1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-27 01:22:30 +00:00

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.
This commit is contained in:
Aaron Boxer 2022-05-18 10:35:53 -04:00 committed by Dudemanguy
parent 9022b1b51d
commit defb02daa4
12 changed files with 992 additions and 4 deletions

View File

@ -1249,7 +1249,7 @@ Video
:videotoolbox: requires ``--vo=gpu`` (macOS 10.8 and up),
or ``--vo=libmpv`` (iOS 9.0 and up)
:videotoolbox-copy: copies video back into system RAM (macOS 10.8 or iOS 9.0 and up)
:vaapi: requires ``--vo=gpu`` or ``--vo=vaapi`` (Linux only)
:vaapi: requires ``--vo=gpu``, ``--vo=vaapi`` or ``--vo=vaapi-wayland`` (Linux only)
:vaapi-copy: copies video back into system RAM (Linux with some GPUs only)
:nvdec: requires ``--vo=gpu`` (Any platform CUDA is available)
:nvdec-copy: copies video back to system RAM (Any platform CUDA is available)

View File

@ -286,6 +286,14 @@ Available video output drivers are:
``--sdl-switch-mode``
Instruct SDL to switch the monitor video mode when going fullscreen.
``vaapi-wayland``
Experimental Wayland output driver designed for use with VA API hardware decoding.
The driver is designed to avoid any GPU to CPU copies, and to perform scaling and
color space conversion using fixed-function hardware, if available,
rather than GPU shaders. This frees up GPU resources for other tasks.
Currently this driver is experimental and only works with the ``--hwdec=vaapi`` driver;
OSD is also not supported. Supported compositors : Weston and Sway.
``vaapi``
Intel VA API video output driver with support for hardware decoding. Note
that there is absolutely no reason to use this, other than compatibility.

View File

@ -1,7 +1,9 @@
wl_protocol_dir = wayland['deps'][2].get_variable(pkgconfig: 'pkgdatadir')
protocols = [[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'],
protocols = [[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'],
[wl_protocol_dir, 'stable/viewporter/viewporter.xml'],
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml']]
wl_protocols_source = []
wl_protocols_headers = []

View File

@ -1432,10 +1432,16 @@ vaapi_wayland = {
'deps': dependency('libva-wayland', version: '>= 1.1.0', required: get_option('vaapi-wayland')),
}
vaapi_wayland += {'use': vaapi['use'] and egl_wayland['use'] and vaapi_wayland['deps'].found()}
if vaapi_wayland['use']
features += vaapi_wayland['name']
endif
if vaapi_wayland['use'] and memfd_create
features += 'vaapi-wayland-memfd'
sources += files('video/out/vo_vaapi_wayland.c')
endif
vaapi_x11 = {
'name': 'vaapi-x11',
'deps': dependency('libva-x11', version: '>= 1.1.0', required: get_option('vaapi-x11')),

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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)
};

View File

@ -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) && found++) {
wl->dmabuf = wl_registry_bind (reg, id, &zwp_linux_dmabuf_v1_interface, 2);
zwp_linux_dmabuf_v1_add_listener (wl->dmabuf, &dmabuf_listener, wl);
wl->drm_format_ct_max = 64;
wl->drm_formats = talloc_array(NULL,uint,wl->drm_format_ct_max);
}
if (!strcmp (interface, wp_viewporter_interface.name) && (ver >= 1) && found++) {
wl->viewporter = wl_registry_bind (reg, id, &wp_viewporter_interface, 1);
wl->viewport = wp_viewporter_get_viewport (wl->viewporter, wl->surface);
wl->video_viewport = wp_viewporter_get_viewport (wl->viewporter,wl->video_surface);
}
if (!strcmp(interface, wl_data_device_manager_interface.name) && (ver >= 3) && found++) {
wl->dnd_devman = wl_registry_bind(reg, id, &wl_data_device_manager_interface, 3);
}
@ -1938,6 +2001,9 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->compositor)
wl_compositor_destroy(wl->compositor);
if (wl->subcompositor)
wl_subcompositor_destroy(wl->subcompositor);
if (wl->current_output && wl->current_output->output)
wl_output_destroy(wl->current_output->output);
@ -1980,6 +2046,18 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->registry)
wl_registry_destroy(wl->registry);
if (wl->viewporter)
wp_viewporter_destroy (wl->viewporter);
if (wl->viewport)
wp_viewport_destroy (wl->viewport);
if (wl->video_viewport)
wp_viewport_destroy (wl->video_viewport);
if (wl->dmabuf)
zwp_linux_dmabuf_v1_destroy (wl->dmabuf);
if (wl->seat)
wl_seat_destroy(wl->seat);
@ -1989,6 +2067,12 @@ void vo_wayland_uninit(struct vo *vo)
if (wl->surface)
wl_surface_destroy(wl->surface);
if (wl->video_surface)
wl_surface_destroy(wl->video_surface);
if (wl->video_subsurface)
wl_subsurface_destroy(wl->video_subsurface);
if (wl->wm_base)
xdg_wm_base_destroy(wl->wm_base);
@ -2022,6 +2106,8 @@ void vo_wayland_uninit(struct vo *vo)
wl_list_for_each_safe(output, tmp, &wl->output_list, link)
remove_output(output);
talloc_free(wl->drm_formats);
talloc_free(wl->dnd_mime_type);
for (int n = 0; n < 2; n++)

View File

@ -36,10 +36,20 @@ struct vo_wayland_state {
struct wayland_opts *opts;
struct wl_callback *frame_callback;
struct wl_compositor *compositor;
struct wl_subcompositor *subcompositor;
struct wl_display *display;
struct wl_registry *registry;
struct wp_viewporter *viewporter;
struct wp_viewport *viewport;
struct zwp_linux_dmabuf_v1 *dmabuf;
uint *drm_formats;
uint drm_format_ct;
uint drm_format_ct_max;
struct wl_shm *shm;
struct wl_surface *surface;
struct wl_surface *video_surface;
struct wl_subsurface *video_subsurface;
struct wp_viewport *video_viewport;
/* Geometry */
struct mp_rect geometry;
@ -137,5 +147,6 @@ void vo_wayland_uninit(struct vo *vo);
void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us);
void vo_wayland_wait_frame(struct vo_wayland_state *wl);
void vo_wayland_wakeup(struct vo *vo);
bool vo_wayland_supported_format(struct vo *vo,uint format);
#endif /* MPLAYER_WAYLAND_COMMON_H */

View File

@ -649,6 +649,11 @@ video_output_features = [
'desc': 'VAAPI (Wayland support)',
'deps': 'vaapi && gl-wayland',
'func': check_pkg_config('libva-wayland', '>= 1.1.0'),
}, {
'name': 'vaapi-wayland-memfd',
'desc': 'VAAPI (Wayland support)',
'deps': 'vaapi-wayland && memfd_create',
'func': check_true,
}, {
'name': '--vaapi-drm',
'desc': 'VAAPI (DRM/EGL support)',

View File

@ -127,6 +127,18 @@ def build(ctx):
ctx.wayland_protocol_header(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "unstable/xdg-decoration/xdg-decoration-unstable-v1",
target = "generated/wayland/xdg-decoration-unstable-v1.h")
ctx.wayland_protocol_code(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "unstable/linux-dmabuf/linux-dmabuf-unstable-v1",
target = "generated/wayland/linux-dmabuf-unstable-v1.c")
ctx.wayland_protocol_header(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "unstable/linux-dmabuf/linux-dmabuf-unstable-v1",
target = "generated/wayland/linux-dmabuf-unstable-v1.h")
ctx.wayland_protocol_code(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "stable/viewporter/viewporter",
target = "generated/wayland/viewporter.c")
ctx.wayland_protocol_header(proto_dir = ctx.env.WL_PROTO_DIR,
protocol = "stable/viewporter/viewporter",
target = "generated/wayland/viewporter.h")
ctx(features = "ebml_header", target = "generated/ebml_types.h")
ctx(features = "ebml_definitions", target = "generated/ebml_defs.inc")
@ -506,6 +518,7 @@ def build(ctx):
( "video/out/vo_sixel.c", "sixel" ),
( "video/out/vo_tct.c" ),
( "video/out/vo_vaapi.c", "vaapi-x11 && gpl" ),
( "video/out/vo_vaapi_wayland.c", "vaapi-wayland-memfd" ),
( "video/out/vo_vdpau.c", "vdpau" ),
( "video/out/vo_wlshm.c", "wayland && memfd_create" ),
( "video/out/vo_x11.c" , "x11" ),
@ -522,6 +535,8 @@ def build(ctx):
( "generated/wayland/presentation-time.c", "wayland" ),
( "generated/wayland/xdg-decoration-unstable-v1.c", "wayland" ),
( "generated/wayland/xdg-shell.c", "wayland" ),
( "generated/wayland/linux-dmabuf-unstable-v1.c", "wayland" ),
( "generated/wayland/viewporter.c", "wayland" ),
( "video/out/wayland_common.c", "wayland" ),
( "video/out/win32/displayconfig.c", "win32-desktop" ),
( "video/out/win32/droptarget.c", "win32-desktop" ),