summaryrefslogtreecommitdiffstats
path: root/video/out
diff options
context:
space:
mode:
authorAaron Boxer <boxerab@protonmail.com>2022-05-18 10:35:53 -0400
committerDudemanguy <random342@airmail.cc>2022-05-24 21:39:34 +0000
commitdefb02daa461200f4de972c57c4ac8dc108feb5f (patch)
tree0f6725f695b3d8be240c71bc1c5e35aacc3fdb8c /video/out
parent9022b1b51dc1204760f9d495e7b3b5550f501bf3 (diff)
downloadmpv-defb02daa461200f4de972c57c4ac8dc108feb5f.tar.bz2
mpv-defb02daa461200f4de972c57c4ac8dc108feb5f.tar.xz
vo: add new vaapi-wayland driver
This driver makes use of dmabuffer and viewporter interfaces to enable efficient display of vaapi surfaces, avoiding any unnecessary colour space conversion, and avoiding scaling or colour conversion using GPU shader resources.
Diffstat (limited to 'video/out')
-rw-r--r--video/out/drm_common.c449
-rw-r--r--video/out/drm_common.h2
-rw-r--r--video/out/vo.c5
-rw-r--r--video/out/vo_vaapi_wayland.c401
-rw-r--r--video/out/wayland_common.c86
-rw-r--r--video/out/wayland_common.h11
6 files changed, 953 insertions, 1 deletions
diff --git a/video/out/drm_common.c b/video/out/drm_common.c
index dad9aaf2fb..cd79f3ee42 100644
--- a/video/out/drm_common.c
+++ b/video/out/drm_common.c
@@ -25,6 +25,7 @@
#include <limits.h>
#include <math.h>
#include <time.h>
+#include <drm_fourcc.h>
#include "config.h"
@@ -1099,3 +1100,451 @@ fail:
*closure->waiting_for_flip = false;
talloc_free(closure);
}
+
+const char* drm_format_string(uint drm_format) {
+
+ switch (drm_format) {
+ /* Reserve 0 for the invalid format specifier */
+ case DRM_FORMAT_INVALID:
+ return "DRM_FORMAT_INVALID";
+ break;
+ /* color index */
+ case DRM_FORMAT_C8:
+ return "DRM_FORMAT_C8";
+ break;
+ /* 8 bpp Red */
+ case DRM_FORMAT_R8:
+ return "DRM_FORMAT_R8";
+ break;
+ /* these formats are not in the header for some reason */
+#if 0
+ /* 10 bpp Red */
+ case DRM_FORMAT_R10:
+ return "DRM_FORMAT_R10";
+ break;
+ /* 12 bpp Red */
+ case DRM_FORMAT_R12:
+ return "DRM_FORMAT_R12";
+ break;
+#endif
+ /* 16 bpp Red */
+ case DRM_FORMAT_R16:
+ return "DRM_FORMAT_R16";
+ break;
+ /* 16 bpp RG */
+ case DRM_FORMAT_RG88:
+ return "DRM_FORMAT_RG88";
+ break;
+ case DRM_FORMAT_GR88:
+ return "DRM_FORMAT_GR88";
+ break;
+ /* 32 bpp RG */
+ case DRM_FORMAT_RG1616:
+ return "DRM_FORMAT_RG1616";
+ break;
+ case DRM_FORMAT_GR1616:
+ return "DRM_FORMAT_GR1616";
+ break;
+ /* 8 bpp RGB */
+ case DRM_FORMAT_RGB332:
+ return "DRM_FORMAT_RGB332";
+ break;
+ case DRM_FORMAT_BGR233:
+ return "DRM_FORMAT_BGR233";
+ break;
+ /* 16 bpp RGB */
+ case DRM_FORMAT_XRGB4444:
+ return "DRM_FORMAT_XRGB4444";
+ break;
+ case DRM_FORMAT_XBGR4444:
+ return "DRM_FORMAT_XBGR4444";
+ break;
+ case DRM_FORMAT_RGBX4444:
+ return "DRM_FORMAT_RGBX4444";
+ break;
+ case DRM_FORMAT_BGRX4444:
+ return "DRM_FORMAT_BGRX4444";
+ break;
+ case DRM_FORMAT_ARGB4444:
+ return "DRM_FORMAT_ARGB4444";
+ break;
+ case DRM_FORMAT_ABGR4444:
+ return "DRM_FORMAT_ABGR4444";
+ break;
+ case DRM_FORMAT_RGBA4444:
+ return "DRM_FORMAT_RGBA4444";
+ break;
+ case DRM_FORMAT_BGRA4444:
+ return "DRM_FORMAT_BGRA4444";
+ break;
+ case DRM_FORMAT_XRGB1555:
+ return "DRM_FORMAT_XRGB1555";
+ break;
+ case DRM_FORMAT_XBGR1555:
+ return "DRM_FORMAT_XBGR1555";
+ break;
+ case DRM_FORMAT_RGBX5551:
+ return "DRM_FORMAT_RGBX5551";
+ break;
+ case DRM_FORMAT_BGRX5551:
+ return "DRM_FORMAT_BGRX5551";
+ break;
+ case DRM_FORMAT_ARGB1555:
+ return "DRM_FORMAT_ARGB1555";
+ break;
+ case DRM_FORMAT_ABGR1555:
+ return "DRM_FORMAT_ABGR1555";
+ break;
+ case DRM_FORMAT_RGBA5551:
+ return "DRM_FORMAT_RGBA5551";
+ break;
+ case DRM_FORMAT_BGRA5551:
+ return "DRM_FORMAT_BGRA5551";
+ break;
+ case DRM_FORMAT_RGB565:
+ return "DRM_FORMAT_RGB565";
+ break;
+ case DRM_FORMAT_BGR565:
+ return "DRM_FORMAT_BGR565";
+ break;
+ /* 24 bpp RGB */
+ case DRM_FORMAT_RGB888:
+ return "DRM_FORMAT_RGB888";
+ break;
+ case DRM_FORMAT_BGR888:
+ return "DRM_FORMAT_BGR888";
+ break;
+ /* 32 bpp RGB */
+ case DRM_FORMAT_XRGB8888:
+ return "DRM_FORMAT_XRGB8888";
+ break;
+ case DRM_FORMAT_XBGR8888:
+ return "DRM_FORMAT_XBGR8888";
+ break;
+ case DRM_FORMAT_RGBX8888:
+ return "DRM_FORMAT_RGBX8888";
+ break;
+ case DRM_FORMAT_BGRX8888:
+ return "DRM_FORMAT_BGRX8888";
+ break;
+ case DRM_FORMAT_ARGB8888:
+ return "DRM_FORMAT_ARGB8888";
+ break;
+ case DRM_FORMAT_ABGR8888:
+ return "DRM_FORMAT_ABGR8888";
+ break;
+ case DRM_FORMAT_RGBA8888:
+ return "DRM_FORMAT_RGBA8888";
+ break;
+ case DRM_FORMAT_BGRA8888:
+ return "DRM_FORMAT_BGRA8888";
+ break;
+ case DRM_FORMAT_XRGB2101010:
+ return "DRM_FORMAT_XRGB2101010";
+ break;
+ case DRM_FORMAT_XBGR2101010:
+ return "DRM_FORMAT_XBGR2101010";
+ break;
+ case DRM_FORMAT_RGBX1010102:
+ return "DRM_FORMAT_RGBX1010102";
+ break;
+ case DRM_FORMAT_BGRX1010102:
+ return "DRM_FORMAT_BGRX1010102";
+ break;
+ case DRM_FORMAT_ARGB2101010:
+ return "DRM_FORMAT_ARGB2101010";
+ break;
+ case DRM_FORMAT_ABGR2101010:
+ return "DRM_FORMAT_ABGR2101010";
+ break;
+ case DRM_FORMAT_RGBA1010102:
+ return "DRM_FORMAT_RGBA1010102";
+ break;
+ case DRM_FORMAT_BGRA1010102:
+ return "DRM_FORMAT_BGRA1010102";
+ break;
+ /* 64 bpp RGB */
+ case DRM_FORMAT_XRGB16161616:
+ return "DRM_FORMAT_XRGB16161616";
+ break;
+ case DRM_FORMAT_XBGR16161616:
+ return "DRM_FORMAT_XBGR16161616";
+ break;
+ case DRM_FORMAT_ARGB16161616:
+ return "DRM_FORMAT_ARGB16161616";
+ break;
+ case DRM_FORMAT_ABGR16161616:
+ return "DRM_FORMAT_ABGR16161616";
+ break;
+ /*
+ * Floating point 64bpp RGB
+ * IEEE 754-2008 binary16 half-precision float
+ * [15:0] sign:exponent:mantissa 1:5:10
+ */
+ case DRM_FORMAT_XRGB16161616F:
+ return "DRM_FORMAT_XRGB16161616F";
+ break;
+ case DRM_FORMAT_XBGR16161616F:
+ return "DRM_FORMAT_XBGR16161616F";
+ break;
+ case DRM_FORMAT_ARGB16161616F:
+ return "DRM_FORMAT_ARGB16161616F";
+ break;
+ case DRM_FORMAT_ABGR16161616F:
+ return "DRM_FORMAT_ABGR16161616F";
+ break;
+ /*
+ * RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits
+ * of unused padding per component:
+ */
+ case DRM_FORMAT_AXBXGXRX106106106106:
+ return "DRM_FORMAT_AXBXGXRX106106106106";
+ break;
+ /* packed YCbCr */
+ case DRM_FORMAT_YUYV:
+ return "DRM_FORMAT_YUYV";
+ break;
+ case DRM_FORMAT_YVYU:
+ return "DRM_FORMAT_YVYU";
+ break;
+ case DRM_FORMAT_UYVY:
+ return "DRM_FORMAT_UYVY";
+ break;
+ case DRM_FORMAT_VYUY:
+ return "DRM_FORMAT_VYUY";
+ break;
+ case DRM_FORMAT_AYUV:
+ return "DRM_FORMAT_AYUV";
+ break;
+ case DRM_FORMAT_XYUV8888:
+ return "DRM_FORMAT_XYUV8888";
+ break;
+ case DRM_FORMAT_VUY888:
+ return "DRM_FORMAT_VUY888";
+ break;
+ case DRM_FORMAT_VUY101010:
+ return "DRM_FORMAT_VUY101010";
+ break;
+ /*
+ * packed Y2xx indicate for each component, xx valid data occupy msb
+ * 16-xx padding occupy lsb
+ */
+ case DRM_FORMAT_Y210:
+ return "DRM_FORMAT_Y210";
+ break;
+ case DRM_FORMAT_Y212:
+ return "DRM_FORMAT_Y212";
+ break;
+ case DRM_FORMAT_Y216:
+ return "DRM_FORMAT_Y216";
+ break;
+ /*
+ * packed Y4xx indicate for each component, xx valid data occupy msb
+ * 16-xx padding occupy lsb except Y410
+ */
+ case DRM_FORMAT_Y410:
+ return "DRM_FORMAT_Y410";
+ break;
+ case DRM_FORMAT_Y412:
+ return "DRM_FORMAT_Y412";
+ break;
+ case DRM_FORMAT_Y416:
+ return "DRM_FORMAT_Y416";
+ break;
+ case DRM_FORMAT_XVYU2101010:
+ return "DRM_FORMAT_XVYU2101010";
+ break;
+ case DRM_FORMAT_XVYU12_16161616:
+ return "DRM_FORMAT_XVYU12_16161616";
+ break;
+ case DRM_FORMAT_XVYU16161616:
+ return "DRM_FORMAT_XVYU16161616";
+ break;
+ /*
+ * packed YCbCr420 2x2 tiled formats
+ * first 64 bits will contain Y,Cb,Cr components for a 2x2 tile
+ */
+ /* [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */
+ case DRM_FORMAT_Y0L0:
+ return "DRM_FORMAT_Y0L0";
+ break;
+ /* [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */
+ case DRM_FORMAT_X0L0:
+ return "DRM_FORMAT_X0L0";
+ break;
+ /* [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */
+ case DRM_FORMAT_Y0L2:
+ return "DRM_FORMAT_Y0L2";
+ break;
+ /* [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */
+ case DRM_FORMAT_X0L2:
+ return "DRM_FORMAT_X0L2";
+ break;
+ /*
+ * 1-plane YUV 4:2:0
+ * In these formats, the component ordering is specified (Y, followed by U
+ * then V), but the exact Linear layout is undefined.
+ * These formats can only be used with a non-Linear modifier.
+ */
+ case DRM_FORMAT_YUV420_8BIT:
+ return "DRM_FORMAT_YUV420_8BIT";
+ break;
+ case DRM_FORMAT_YUV420_10BIT:
+ return "DRM_FORMAT_YUV420_10BIT";
+ break;
+ /*
+ * 2 plane RGB + A
+ * index 0 = RGB plane, same format as the corresponding non _A8 format has
+ * index 1 = A plane, [7:0] A
+ */
+ case DRM_FORMAT_XRGB8888_A8:
+ return "DRM_FORMAT_XRGB8888_A8";
+ break;
+ case DRM_FORMAT_XBGR8888_A8:
+ return "DRM_FORMAT_XBGR8888_A8";
+ break;
+ case DRM_FORMAT_RGBX8888_A8:
+ return "DRM_FORMAT_RGBX8888_A8";
+ break;
+ case DRM_FORMAT_BGRX8888_A8:
+ return "DRM_FORMAT_BGRX8888_A8";
+ break;
+ case DRM_FORMAT_RGB888_A8:
+ return "DRM_FORMAT_RGB888_A8";
+ break;
+ case DRM_FORMAT_BGR888_A8:
+ return "DRM_FORMAT_BGR888_A8";
+ break;
+ case DRM_FORMAT_RGB565_A8:
+ return "DRM_FORMAT_RGB565_A8";
+ break;
+ case DRM_FORMAT_BGR565_A8:
+ return "DRM_FORMAT_BGR565_A8";
+ break;
+ /*
+ * 2 plane YCbCr
+ * index 0 = Y plane, [7:0] Y
+ * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
+ * or
+ * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian
+ */
+ case DRM_FORMAT_NV12:
+ return "DRM_FORMAT_NV12";
+ break;
+ case DRM_FORMAT_NV21:
+ return "DRM_FORMAT_NV21";
+ break;
+ case DRM_FORMAT_NV16:
+ return "DRM_FORMAT_NV16";
+ break;
+ case DRM_FORMAT_NV61:
+ return "DRM_FORMAT_NV61";
+ break;
+ case DRM_FORMAT_NV24:
+ return "DRM_FORMAT_NV24";
+ break;
+ case DRM_FORMAT_NV42:
+ return "DRM_FORMAT_NV42";
+ break; /*
+ * 2 plane YCbCr
+ * index 0 = Y plane, [39:0] Y3:Y2:Y1:Y0 little endian
+ * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian
+ */
+ case DRM_FORMAT_NV15:
+ return "DRM_FORMAT_NV15";
+ break;
+ /*
+ * 2 plane YCbCr MSB aligned
+ * index 0 = Y plane, [15:0] Y:x [10:6] little endian
+ * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian
+ */
+ case DRM_FORMAT_P210:
+ return "DRM_FORMAT_P210";
+ break;
+ /*
+ * 2 plane YCbCr MSB aligned
+ * index 0 = Y plane, [15:0] Y:x [10:6] little endian
+ * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian
+ */
+ case DRM_FORMAT_P010:
+ return "DRM_FORMAT_P010";
+ break;
+ /*
+ * 2 plane YCbCr MSB aligned
+ * index 0 = Y plane, [15:0] Y:x [12:4] little endian
+ * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [12:4:12:4] little endian
+ */
+ case DRM_FORMAT_P012:
+ return "DRM_FORMAT_P012";
+ break;
+ /*
+ * 2 plane YCbCr MSB aligned
+ * index 0 = Y plane, [15:0] Y little endian
+ * index 1 = Cr:Cb plane, [31:0] Cr:Cb [16:16] little endian
+ */
+ case DRM_FORMAT_P016:
+ return "DRM_FORMAT_P016";
+ break;
+ /* 3 plane non-subsampled (444) YCbCr
+ * 16 bits per component, but only 10 bits are used and 6 bits are padded
+ * index 0: Y plane, [15:0] Y:x [10:6] little endian
+ * index 1: Cb plane, [15:0] Cb:x [10:6] little endian
+ * index 2: Cr plane, [15:0] Cr:x [10:6] little endian
+ */
+ case DRM_FORMAT_Q410:
+ return "DRM_FORMAT_Q410";
+ break;
+ /* 3 plane non-subsampled (444) YCrCb
+ * 16 bits per component, but only 10 bits are used and 6 bits are padded
+ * index 0: Y plane, [15:0] Y:x [10:6] little endian
+ * index 1: Cr plane, [15:0] Cr:x [10:6] little endian
+ * index 2: Cb plane, [15:0] Cb:x [10:6] little endian
+ */
+ case DRM_FORMAT_Q401:
+ return "DRM_FORMAT_Q401";
+ break;
+ /*
+ * 3 plane YCbCr
+ * index 0: Y plane, [7:0] Y
+ * index 1: Cb plane, [7:0] Cb
+ * index 2: Cr plane, [7:0] Cr
+ * or
+ * index 1: Cr plane, [7:0] Cr
+ * index 2: Cb plane, [7:0] Cb
+ */
+ case DRM_FORMAT_YUV410:
+ return "DRM_FORMAT_YUV410";
+ break;
+ case DRM_FORMAT_YVU410:
+ return "DRM_FORMAT_YVU410";
+ break;
+ case DRM_FORMAT_YUV411:
+ return "DRM_FORMAT_YUV411";
+ break;
+ case DRM_FORMAT_YVU411:
+ return "DRM_FORMAT_YVU411";
+ break;
+ case DRM_FORMAT_YUV420:
+ return "DRM_FORMAT_YUV420";
+ break;
+ case DRM_FORMAT_YVU420:
+ return "DRM_FORMAT_YVU420";
+ break;
+ case DRM_FORMAT_YUV422:
+ return "DRM_FORMAT_YUV422";
+ break;
+ case DRM_FORMAT_YVU422:
+ return "DRM_FORMAT_YVU422";
+ break;
+ case DRM_FORMAT_YUV444:
+ return "DRM_FORMAT_YUV444";
+ break;
+ case DRM_FORMAT_YVU444:
+ return "DRM_FORMAT_YVU444";
+ break;
+ default:
+ return "DRM_FORMAT_UNKNOWN";
+ break;
+ }
+}
+
diff --git a/video/out/drm_common.h b/video/out/drm_common.h
index 5d884e3c80..cd7f87e506 100644
--- a/video/out/drm_common.h
+++ b/video/out/drm_common.h
@@ -97,4 +97,6 @@ double kms_get_display_fps(const struct kms *kms);
void drm_pflip_cb(int fd, unsigned int msc, unsigned int sec,
unsigned int usec, void *data);
+const char* drm_format_string(uint drm_format);
+
#endif
diff --git a/video/out/vo.c b/video/out/vo.c
index 11ef596227..6b38711acf 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -62,6 +62,7 @@ extern const struct vo_driver video_out_drm;
extern const struct vo_driver video_out_direct3d;
extern const struct vo_driver video_out_sdl;
extern const struct vo_driver video_out_vaapi;
+extern const struct vo_driver video_out_vaapi_wayland;
extern const struct vo_driver video_out_wlshm;
extern const struct vo_driver video_out_rpi;
extern const struct vo_driver video_out_tct;
@@ -92,7 +93,9 @@ const struct vo_driver *const video_out_drivers[] =
#if HAVE_SDL2_VIDEO
&video_out_sdl,
#endif
-#if HAVE_VAAPI_X11 && HAVE_GPL
+#if HAVE_VAAPI_WAYLAND
+ &video_out_vaapi_wayland,
+#elif HAVE_VAAPI_X11 && HAVE_GPL
&video_out_vaapi,
#endif
#if HAVE_X11
diff --git a/video/out/vo_vaapi_wayland.c b/video/out/vo_vaapi_wayland.c
new file mode 100644
index 0000000000..931b88229a
--- /dev/null
+++ b/video/out/vo_vaapi_wayland.c
@@ -0,0 +1,401 @@
+/*
+ * This file is part of mpv video player.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <va/va_wayland.h>
+#include <va/va_drmcommon.h>
+
+#include "sub/osd.h"
+#include "video/vaapi.h"
+#include "wayland_common.h"
+#include "drm_common.h"
+#include "generated/wayland/linux-dmabuf-unstable-v1.h"
+#include "generated/wayland/viewporter.h"
+
+#define VA_POOL_NUM_ALLOCATED_INIT 30
+
+struct va_pool_entry {
+ /* key */
+ VASurfaceID surface;
+
+ VADRMPRIMESurfaceDescriptor desc;
+ struct wl_buffer *buffer;
+ struct zwp_linux_buffer_params_v1 *params;
+ uint drm_format;
+};
+struct va_pool {
+ struct vo *vo;
+ struct va_pool_entry **entries;
+ uint num_entries;
+ uint num_allocated;
+};
+
+struct priv {
+ struct vo *vo;
+ struct mp_rect src;
+ struct mp_rect dst;
+ struct mp_osd_res osd;
+ struct mp_log *log;
+
+ VADisplay display;
+ struct mp_vaapi_ctx *mpvaapi;
+ struct va_image_formats *image_formats;
+ struct wl_shm_pool *solid_buffer_pool;
+ struct wl_buffer *solid_buffer;
+ struct va_pool *va_pool;
+};
+
+static void va_close_surface_descriptor(VADRMPRIMESurfaceDescriptor desc) {
+ for (uint i = 0; i < desc.num_objects; i++) {
+ close(desc.objects[i].fd);
+ desc.objects[i].fd = 0;
+ }
+}
+
+static void va_free_entry(struct va_pool_entry *entry) {
+ if (!entry)
+ return;
+ va_close_surface_descriptor(entry->desc);
+ if (entry->buffer)
+ wl_buffer_destroy(entry->buffer);
+ if (entry->params)
+ zwp_linux_buffer_params_v1_destroy(entry->params);
+ talloc_free(entry);
+}
+
+static VAStatus va_export_surface_handle(VADisplay display, VASurfaceID surface,
+ VADRMPRIMESurfaceDescriptor *desc) {
+ return vaExportSurfaceHandle(display, surface,
+ VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
+ VA_EXPORT_SURFACE_COMPOSED_LAYERS | VA_EXPORT_SURFACE_READ_ONLY,
+ desc);
+}
+
+static struct va_pool_entry* va_alloc_entry(struct vo *vo, struct mp_image *src) {
+ struct priv *p = vo->priv;
+ struct vo_wayland_state *wl = vo->wl;
+ VAStatus status;
+ struct va_pool_entry *entry = talloc(NULL, struct va_pool_entry);
+ memset(entry, 0, sizeof(struct va_pool_entry));
+
+ /* extract dmabuf surface descriptor */
+ entry->surface = va_surface_id(src);
+ status = va_export_surface_handle(p->display, entry->surface, &entry->desc);
+ if (status == VA_STATUS_ERROR_INVALID_SURFACE) {
+ MP_VERBOSE(vo, "VA export to composed layers not supported.\n");
+ va_free_entry(entry);
+ return NULL;
+ } else if (!vo_wayland_supported_format(vo,
+ entry->desc.layers[0].drm_format)) {
+ MP_VERBOSE(vo, "%s not supported.\n",
+ drm_format_string(entry->desc.layers[0].drm_format));
+ va_free_entry(entry);
+ return NULL;
+ } else if (!CHECK_VA_STATUS(vo, "vaExportSurfaceHandle()")) {
+ va_free_entry(entry);
+ return NULL;
+ } else {
+ uint i, j, plane = 0;
+
+ entry->params = zwp_linux_dmabuf_v1_create_params(wl->dmabuf);
+ for (i = 0; i < entry->desc.num_layers; i++) {
+ entry->drm_format = entry->desc.layers[i].drm_format;
+ for (j = 0; j < entry->desc.layers[i].num_planes; ++j) {
+ int object = entry->desc.layers[i].object_index[j];
+ uint64_t modifier =
+ entry->desc.objects[object].drm_format_modifier;
+ zwp_linux_buffer_params_v1_add(entry->params,
+ entry->desc.objects[object].fd, plane++,
+ entry->desc.layers[i].offset[j],
+ entry->desc.layers[i].pitch[j], modifier >> 32,
+ modifier & 0xffffffff);
+ }
+ }
+ }
+ entry->buffer = zwp_linux_buffer_params_v1_create_immed(entry->params,
+ src->params.w, src->params.h, entry->drm_format, 0);
+
+ return entry;
+}
+static void va_pool_clean(struct va_pool *pool) {
+ if (!pool)
+ return;
+
+ for (uint i = 0; i < pool->num_entries; ++i)
+ va_free_entry(pool->entries[i]);
+ pool->num_entries = 0;
+}
+
+static void va_pool_free(struct va_pool *pool) {
+ if (!pool)
+ return;
+
+ va_pool_clean(pool);
+ talloc_free(pool->entries);
+ talloc_free(pool);
+}
+static struct va_pool* va_pool_alloc(struct vo *vo) {
+ struct va_pool *pool = talloc(NULL, struct va_pool);
+ memset(pool, 0, sizeof(struct va_pool));
+ pool->num_allocated = VA_POOL_NUM_ALLOCATED_INIT;
+ pool->entries = talloc_array(NULL,struct va_pool_entry*, pool->num_allocated);
+ memset(pool->entries,0,pool->num_allocated * sizeof(struct va_pool_entry*));
+ pool->vo = vo;
+
+ return pool;
+}
+static struct va_pool_entry* va_pool_alloc_entry(struct vo *vo,
+ struct va_pool *pool, struct mp_image *src) {
+ VASurfaceID surface;
+
+ if (!pool)
+ return NULL;
+
+ surface = va_surface_id(src);
+ for (uint i = 0; i < pool->num_entries; ++i) {
+ struct va_pool_entry *item = pool->entries[i];
+ if (item->surface == surface)
+ return pool->entries[i];
+ }
+
+ struct va_pool_entry *entry = va_alloc_entry(pool->vo, src);
+ if (!entry)
+ return NULL;
+
+ if (pool->num_entries == pool->num_allocated) {
+ uint current_num_allocated = pool->num_allocated;
+ pool->num_allocated *= 2;
+ pool->entries = talloc_realloc(NULL,pool->entries,struct va_pool_entry*, pool->num_allocated);
+ for (uint i = current_num_allocated; i < pool->num_allocated; ++i)
+ pool->entries[i] = NULL;
+ }
+ pool->entries[pool->num_entries++] = entry;
+
+ return entry;
+}
+
+struct va_image_formats {
+ VAImageFormat *entries;
+ int num;
+};
+
+static void va_get_formats(struct priv *ctx) {
+ struct va_image_formats *formats = talloc_ptrtype(ctx, formats);
+
+ formats->num = vaMaxNumImageFormats(ctx->display);
+ formats->entries = talloc_array(formats, VAImageFormat, formats->num);
+ VAStatus status = vaQueryImageFormats(ctx->display, formats->entries,
+ &formats->num);
+ if (!CHECK_VA_STATUS(ctx, "vaQueryImageFormats()"))
+ return;
+ MP_VERBOSE(ctx, "%d image formats available:\n", formats->num);
+ for (int i = 0; i < formats->num; i++)
+ MP_VERBOSE(ctx, " %s\n", mp_tag_str(formats->entries[i].fourcc));
+ ctx->image_formats = formats;
+}
+
+static void uninit(struct vo *vo) {
+ struct priv *p = vo->priv;
+
+ va_pool_free(p->va_pool);
+ if (p->solid_buffer_pool)
+ wl_shm_pool_destroy(p->solid_buffer_pool);
+ if (p->solid_buffer)
+ wl_buffer_destroy(p->solid_buffer);
+ vo_wayland_uninit(vo);
+
+ if (vo->hwdec_devs) {
+ hwdec_devices_remove(vo->hwdec_devs, &p->mpvaapi->hwctx);
+ hwdec_devices_destroy(vo->hwdec_devs);
+ }
+ if (p->mpvaapi)
+ va_destroy(p->mpvaapi);
+}
+static int allocate_memfd(size_t size) {
+ int fd = memfd_create("mpv", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (fd < 0)
+ return VO_ERROR;
+
+ fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
+
+ if (posix_fallocate(fd, 0, size) == 0)
+ return fd;
+
+ close(fd);
+ return VO_ERROR;
+}
+
+static int preinit(struct vo *vo) {
+ struct priv *p = vo->priv;
+
+ p->vo = vo;
+ p->log = vo->log;
+ if (!vo_wayland_init(vo))
+ return VO_ERROR;
+ p->display = vaGetDisplayWl(vo->wl->display);
+ if (!p->display)
+ return VO_ERROR;
+ p->mpvaapi = va_initialize(p->display, p->log, false);
+ if (!p->mpvaapi) {
+ vaTerminate(p->display);
+ p->display = NULL;
+ goto fail;
+ }
+ va_get_formats(p);
+ if (!p->image_formats)
+ goto fail;
+
+ vo->hwdec_devs = hwdec_devices_create();
+ hwdec_devices_add(vo->hwdec_devs, &p->mpvaapi->hwctx);
+ p->va_pool = va_pool_alloc(vo);
+
+ return 0;
+
+fail:
+ uninit(vo);
+
+ return VO_ERROR;
+}
+
+static int query_format(struct vo *vo, int format) {
+ return format == IMGFMT_VAAPI;
+}
+
+static int reconfig(struct vo *vo, struct mp_image_params *params) {
+ struct priv *p = vo->priv;
+ struct vo_wayland_state *wl = vo->wl;
+
+ if (!p->solid_buffer_pool) {
+ int width = 1;
+ int height = 1;
+ int stride = MP_ALIGN_UP(width * 4, 16);
+ int fd = allocate_memfd(stride);
+ if (fd < 0)
+ return VO_ERROR;
+ p->solid_buffer_pool = wl_shm_create_pool(wl->shm, fd, height * stride);
+ if (!p->solid_buffer_pool)
+ return VO_ERROR;
+ p->solid_buffer = wl_shm_pool_create_buffer(p->solid_buffer_pool, 0,
+ width, height, stride, WL_SHM_FORMAT_XRGB8888);
+ if (!p->solid_buffer)
+ return VO_ERROR;
+ }
+ if (!vo_wayland_reconfig(vo))
+ return VO_ERROR;
+
+ return 0;
+}
+
+static int resize(struct vo *vo) {
+ struct vo_wayland_state *wl = vo->wl;
+ struct priv *p = vo->priv;
+
+ wl_subsurface_set_sync(wl->video_subsurface);
+ vo_wayland_set_opaque_region(wl, 0);
+ const int32_t width = wl->scaling * mp_rect_w(wl->geometry);
+ const int32_t height = wl->scaling * mp_rect_h(wl->geometry);
+ vo->dwidth = width;
+ vo->dheight = height;
+ vo_get_src_dst_rects(vo, &p->src, &p->dst, &p->osd);
+ wp_viewport_set_destination(wl->viewport,
+ (p->dst.x0 << 1) + mp_rect_w(p->dst),
+ (p->dst.y0 << 1) + mp_rect_h(p->dst));
+ wp_viewport_set_destination(wl->video_viewport, mp_rect_w(p->dst),
+ mp_rect_h(p->dst));
+ wl_subsurface_set_position(wl->video_subsurface, p->dst.x0, p->dst.y0);
+ vo->want_redraw = true;
+ wl_subsurface_set_desync(wl->video_subsurface);
+
+ return VO_TRUE;
+}
+
+static int control(struct vo *vo, uint32_t request, void *data) {
+ struct priv *p = vo->priv;
+ int events = 0;
+ int ret;
+
+ switch (request) {
+ /* need to clean pool after seek to avoid artifacts */
+ case VOCTRL_RESET:
+ va_pool_clean(p->va_pool);
+ break;
+ default:
+ break;
+ }
+ ret = vo_wayland_control(vo, &events, request, data);
+ if (events & VO_EVENT_RESIZE)
+ ret = resize(vo);
+ if (events & VO_EVENT_EXPOSE)
+ vo->want_redraw = true;
+ vo_event(vo, events);
+
+ return ret;
+}
+
+static void draw_frame(struct vo *vo, struct vo_frame *frame) {
+ struct priv *p = vo->priv;
+ struct vo_wayland_state *wl = vo->wl;
+
+ if (!vo_wayland_check_visible(vo))
+ return;
+
+ struct va_pool_entry *entry = va_pool_alloc_entry(vo, p->va_pool,
+ frame->current);
+ if (!entry)
+ return;
+
+ wl_surface_attach(wl->surface, p->solid_buffer, 0, 0);
+ wl_surface_attach(wl->video_surface, entry->buffer, 0, 0);
+ wl_surface_damage_buffer(wl->video_surface, 0, 0, INT32_MAX, INT32_MAX);
+ wl_surface_commit(wl->video_surface);
+ wl_surface_commit(wl->surface);
+
+ if (!wl->opts->disable_vsync)
+ vo_wayland_wait_frame(wl);
+ if (wl->presentation)
+ vo_wayland_sync_swap(wl);
+}
+static void flip_page(struct vo *vo) {
+ /* no-op */
+}
+
+static void get_vsync(struct vo *vo, struct vo_vsync_info *info) {
+ struct vo_wayland_state *wl = vo->wl;
+ if (wl->presentation) {
+ info->vsync_duration = wl->vsync_duration;
+ info->skipped_vsyncs = wl->last_skipped_vsyncs;
+ info->last_queue_display_time = wl->last_queue_display_time;
+ }
+}
+
+const struct vo_driver video_out_vaapi_wayland = { .description =
+ "VA API with Wayland video output",
+ .name = "vaapi-wayland",
+ .preinit = preinit,
+ .query_format = query_format,
+ .reconfig = reconfig,
+ .control = control,
+ .draw_frame = draw_frame,
+ .flip_page = flip_page,
+ .get_vsync = get_vsync,
+ .wakeup = vo_wayland_wakeup,
+ .wait_events = vo_wayland_wait_events,
+ .uninit = uninit,
+ .priv_size = sizeof(struct priv)
+};
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index cd97c77bf6..93a44fde7a 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -32,17 +32,21 @@
#include "osdep/timer.h"
#include "wayland_common.h"
#include "win_state.h"
+#include "drm_common.h"
// Generated from wayland-protocols
#include "generated/wayland/idle-inhibit-unstable-v1.h"
#include "generated/wayland/presentation-time.h"
#include "generated/wayland/xdg-decoration-unstable-v1.h"
#include "generated/wayland/xdg-shell.h"
+#include "generated/wayland/linux-dmabuf-unstable-v1.h"
+#include "generated/wayland/viewporter.h"
#if WAYLAND_VERSION_MAJOR > 1 || WAYLAND_VERSION_MINOR >= 20
#define HAVE_WAYLAND_1_20
#endif
+
static const struct mp_keymap keymap[] = {
/* Special keys */
{XKB_KEY_Pause, MP_KEY_PAUSE}, {XKB_KEY_Escape, MP_KEY_ESC},
@@ -1039,6 +1043,41 @@ static const struct wl_callback_listener frame_listener = {
frame_callback,
};
+static void dmabuf_format(void *data,
+ struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format) {
+ struct vo_wayland_state *wl = data;
+
+ if (wl->drm_format_ct == wl->drm_format_ct_max) {
+ wl->drm_format_ct_max *= 2;
+ wl->drm_formats = talloc_realloc(NULL,wl->drm_formats,uint, wl->drm_format_ct_max);
+ }
+ wl->drm_formats[wl->drm_format_ct++] = format;
+ MP_VERBOSE(wl, "%s available\n", drm_format_string(format));
+}
+
+bool vo_wayland_supported_format(struct vo *vo, uint drm_format) {
+ struct vo_wayland_state *wl = vo->wl;
+
+ for (uint i = 0; i < wl->drm_format_ct; ++i) {
+ if (drm_format == wl->drm_formats[i])
+ return true;
+ }
+
+ return false;
+}
+
+/* currently unused */
+static void dmabuf_modifier(void *data,
+ struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format,
+ uint32_t modifier_hi, uint32_t modifier_lo) {
+
+}
+
+static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
+ dmabuf_format,
+ dmabuf_modifier
+};
+
static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id,
const char *interface, uint32_t ver)
{
@@ -1048,10 +1087,34 @@ static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id
if (!strcmp(interface, wl_compositor_interface.name) && (ver >= 4) && found++) {
wl->compositor = wl_registry_bind(reg, id, &wl_compositor_interface, 4);
wl->surface = wl_compositor_create_surface(wl->compositor);
+ wl->video_surface = wl_compositor_create_surface(wl->compositor);
+ /* never accept input events on the video surface */
+ struct wl_region *region = wl_compositor_create_region (wl->compositor);
+ wl_surface_set_input_region (wl->video_surface, region);
+ wl_region_destroy (region);
wl->cursor_surface = wl_compositor_create_surface(wl->compositor);
wl_surface_add_listener(wl->surface, &surface_listener, wl);
}
+ if (!strcmp(interface, wl_subcompositor_interface.name) && (ver >= 1) && found++) {
+ wl->subcompositor = wl_registry_bind(reg, id, &wl_subcompositor_interface, 1);
+ wl->video_subsurface = wl_subcompositor_get_subsurface(wl->subcompositor, wl->video_surface, wl->surface);
+ wl_subsurface_set_desync (wl->video_subsurface);
+ }
+
+ if (!strcmp (interface, zwp_linux_dmabuf_v1_interface.name) && (ver >= 2) && foun