0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 20:03:10 +02:00
mpv/video/out/vo_dmabuf_wayland.c
Dudemanguy 0bed2a2263 build: remove outdated generated directory
This only existed as essentially a workaround for meson's behavior and
to maintain compatibility with the waf build. Since waf put everything
in a generated subdirectory, we had to put make a subdirectory called
"generated" in the source for meson so stuff could go to the right
place. Well now we don't need to do that anymore. Move the meson.build
files around so they go in the appropriate place in the subdirectory of
the source tree and change the paths of the headers accordingly. A
couple of important things to note.

1. mpv.com now gets made in build/player/mpv.com (necessary because of
   a meson limitation)
2. The macos icon generation path is shortened to
   TOOLS/osxbundle/icon.icns.inc.
2023-07-31 19:00:06 +00:00

838 lines
24 KiB
C

/*
* This file is part of mpv.
*
* 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 <libavutil/hwcontext_drm.h>
#include <sys/mman.h>
#include <unistd.h>
#include "config.h"
#if HAVE_VAAPI
#include <va/va_drmcommon.h>
#endif
#include "common/global.h"
#include "gpu/hwdec.h"
#include "gpu/video.h"
#include "mpv_talloc.h"
#include "present_sync.h"
#include "sub/draw_bmp.h"
#include "video/fmt-conversion.h"
#include "video/mp_image.h"
#include "vo.h"
#include "wayland_common.h"
#include "wldmabuf/ra_wldmabuf.h"
#if HAVE_VAAPI
#include "video/vaapi.h"
#endif
// Generated from wayland-protocols
#include "linux-dmabuf-unstable-v1.h"
#include "viewporter.h"
#if HAVE_WAYLAND_PROTOCOLS_1_27
#include "single-pixel-buffer-v1.h"
#endif
// We need at least enough buffers to avoid a
// flickering artifact in certain formats.
#define WL_BUFFERS_WANTED 15
enum hwdec_type {
HWDEC_NONE,
HWDEC_VAAPI,
HWDEC_DRMPRIME,
};
struct buffer {
struct vo *vo;
struct wl_buffer *buffer;
struct wl_list link;
struct mp_image *image;
uint32_t drm_format;
uintptr_t id;
};
struct osd_buffer {
struct vo *vo;
struct wl_buffer *buffer;
struct wl_list link;
struct mp_image image;
size_t size;
};
struct priv {
struct mp_log *log;
struct mp_rect src;
struct mpv_global *global;
struct ra_ctx *ctx;
struct ra_hwdec_ctx hwdec_ctx;
struct wl_shm_pool *solid_buffer_pool;
struct wl_buffer *solid_buffer;
struct wl_list buffer_list;
struct wl_list osd_buffer_list;
struct wl_shm_pool *osd_shm_pool;
uint8_t *osd_shm_data;
int osd_shm_width;
int osd_shm_stride;
int osd_shm_height;
struct osd_buffer *osd_buffer;
struct mp_draw_sub_cache *osd_cache;
struct mp_osd_res screen_osd_res;
bool destroy_buffers;
enum hwdec_type hwdec_type;
uint32_t drm_format;
uint64_t drm_modifier;
};
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
{
struct buffer *buf = data;
if (buf->image) {
mp_image_unrefp(&buf->image);
buf->image = NULL;
}
}
static const struct wl_buffer_listener buffer_listener = {
buffer_handle_release,
};
static void osd_buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
{
struct osd_buffer *osd_buf = data;
wl_list_remove(&osd_buf->link);
if (osd_buf->buffer) {
wl_buffer_destroy(osd_buf->buffer);
osd_buf->buffer = NULL;
}
talloc_free(osd_buf);
}
static const struct wl_buffer_listener osd_buffer_listener = {
osd_buffer_handle_release,
};
#if HAVE_VAAPI
static void close_file_descriptors(VADRMPRIMESurfaceDescriptor desc)
{
for (int i = 0; i < desc.num_objects; i++)
close(desc.objects[i].fd);
}
#endif
static uintptr_t vaapi_surface_id(struct mp_image *src)
{
uintptr_t id = 0;
#if HAVE_VAAPI
id = (uintptr_t)va_surface_id(src);
#endif
return id;
}
static bool vaapi_drm_format(struct vo *vo, struct mp_image *src)
{
bool format = false;
#if HAVE_VAAPI
struct priv *p = vo->priv;
VADRMPRIMESurfaceDescriptor desc = {0};
uintptr_t id = vaapi_surface_id(src);
VADisplay display = ra_get_native_resource(p->ctx->ra, "VADisplay");
VAStatus status = vaExportSurfaceHandle(display, id, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
VA_EXPORT_SURFACE_COMPOSED_LAYERS | VA_EXPORT_SURFACE_READ_ONLY, &desc);
if (!CHECK_VA_STATUS(vo, "vaExportSurfaceHandle()")) {
/* invalid surface warning => composed layers not supported */
if (status == VA_STATUS_ERROR_INVALID_SURFACE)
MP_VERBOSE(vo, "vaExportSurfaceHandle: composed layers not supported.\n");
goto done;
}
p->drm_format = desc.layers[0].drm_format;
p->drm_modifier = desc.objects[0].drm_format_modifier;
format = true;
done:
close_file_descriptors(desc);
#endif
return format;
}
static void vaapi_dmabuf_importer(struct buffer *buf, struct mp_image *src,
struct zwp_linux_buffer_params_v1 *params)
{
#if HAVE_VAAPI
struct vo *vo = buf->vo;
struct priv *p = vo->priv;
VADRMPRIMESurfaceDescriptor desc = {0};
VADisplay display = ra_get_native_resource(p->ctx->ra, "VADisplay");
/* composed has single layer */
int layer_no = 0;
buf->id = vaapi_surface_id(src);
VAStatus status = vaExportSurfaceHandle(display, buf->id, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
VA_EXPORT_SURFACE_COMPOSED_LAYERS | VA_EXPORT_SURFACE_READ_ONLY, &desc);
if (!CHECK_VA_STATUS(vo, "vaExportSurfaceHandle()")) {
/* invalid surface warning => composed layers not supported */
if (status == VA_STATUS_ERROR_INVALID_SURFACE)
MP_VERBOSE(vo, "vaExportSurfaceHandle: composed layers not supported.\n");
goto done;
}
buf->drm_format = desc.layers[layer_no].drm_format;
if (!ra_compatible_format(p->ctx->ra, buf->drm_format, desc.objects[0].drm_format_modifier)) {
MP_VERBOSE(vo, "%s(%016lx) is not supported.\n",
mp_tag_str(buf->drm_format), desc.objects[0].drm_format_modifier);
buf->drm_format = 0;
goto done;
}
for (int plane_no = 0; plane_no < desc.layers[layer_no].num_planes; ++plane_no) {
int object = desc.layers[layer_no].object_index[plane_no];
uint64_t modifier = desc.objects[object].drm_format_modifier;
zwp_linux_buffer_params_v1_add(params, desc.objects[object].fd, plane_no, desc.layers[layer_no].offset[plane_no],
desc.layers[layer_no].pitch[plane_no], modifier >> 32, modifier & 0xffffffff);
}
done:
close_file_descriptors(desc);
#endif
}
static uintptr_t drmprime_surface_id(struct mp_image *src)
{
uintptr_t id = 0;
struct AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->planes[0];
AVDRMObjectDescriptor object = desc->objects[0];
id = (uintptr_t)object.fd;
return id;
}
static bool drmprime_drm_format(struct vo *vo, struct mp_image *src)
{
struct priv *p = vo->priv;
struct AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->planes[0];
if (!desc)
return false;
// Just check the very first layer/plane.
p->drm_format = desc->layers[0].format;
int object_index = desc->layers[0].planes[0].object_index;
p->drm_modifier = desc->objects[object_index].format_modifier;
return true;
}
static void drmprime_dmabuf_importer(struct buffer *buf, struct mp_image *src,
struct zwp_linux_buffer_params_v1 *params)
{
int layer_no, plane_no;
int max_planes = 0;
const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->planes[0];
if (!desc)
return;
buf->id = drmprime_surface_id(src);
for (layer_no = 0; layer_no < desc->nb_layers; layer_no++) {
AVDRMLayerDescriptor layer = desc->layers[layer_no];
buf->drm_format = layer.format;
max_planes = MPMAX(max_planes, layer.nb_planes);
for (plane_no = 0; plane_no < layer.nb_planes; ++plane_no) {
AVDRMPlaneDescriptor plane = layer.planes[plane_no];
int object_index = plane.object_index;
AVDRMObjectDescriptor object = desc->objects[object_index];
uint64_t modifier = object.format_modifier;
zwp_linux_buffer_params_v1_add(params, object.fd, plane_no, plane.offset,
plane.pitch, modifier >> 32, modifier & 0xffffffff);
}
}
}
static intptr_t surface_id(struct vo *vo, struct mp_image *src)
{
struct priv *p = vo->priv;
switch(p->hwdec_type) {
case HWDEC_VAAPI:
return vaapi_surface_id(src);
case HWDEC_DRMPRIME:
return drmprime_surface_id(src);
default:
return 0;
}
}
static bool drm_format_check(struct vo *vo, struct mp_image *src)
{
struct priv *p = vo->priv;
switch(p->hwdec_type) {
case HWDEC_VAAPI:
return vaapi_drm_format(vo, src);
case HWDEC_DRMPRIME:
return drmprime_drm_format(vo, src);
}
return false;
}
static struct buffer *buffer_check(struct vo *vo, struct mp_image *src)
{
struct priv *p = vo->priv;
/* Make more buffers if we're not at the desired amount yet. */
if (wl_list_length(&p->buffer_list) < WL_BUFFERS_WANTED)
goto done;
uintptr_t id = surface_id(vo, src);
struct buffer *buf;
wl_list_for_each(buf, &p->buffer_list, link) {
if (buf->id == id) {
if (buf->image)
mp_image_unrefp(&buf->image);
buf->image = src;
return buf;
}
}
done:
return NULL;
}
static struct buffer *buffer_create(struct vo *vo, struct mp_image *src)
{
struct vo_wayland_state *wl = vo->wl;
struct priv *p = vo->priv;
struct buffer *buf = talloc_zero(vo, struct buffer);
buf->vo = vo;
buf->image = src;
struct zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(wl->dmabuf);
switch(p->hwdec_type) {
case HWDEC_VAAPI:
vaapi_dmabuf_importer(buf, src, params);
break;
case HWDEC_DRMPRIME:
drmprime_dmabuf_importer(buf, src, params);
break;
}
if (!buf->drm_format) {
mp_image_unrefp(&buf->image);
talloc_free(buf);
zwp_linux_buffer_params_v1_destroy(params);
return NULL;
}
buf->buffer = zwp_linux_buffer_params_v1_create_immed(params, src->params.w, src->params.h,
buf->drm_format, 0);
zwp_linux_buffer_params_v1_destroy(params);
wl_buffer_add_listener(buf->buffer, &buffer_listener, buf);
wl_list_insert(&p->buffer_list, &buf->link);
return buf;
}
static struct buffer *buffer_get(struct vo *vo, struct mp_image *src)
{
/* Reuse existing buffer if possible. */
struct buffer *buf = buffer_check(vo, src);
if (buf) {
return buf;
} else {
return buffer_create(vo, src);
}
}
static void destroy_buffers(struct vo *vo)
{
struct priv *p = vo->priv;
struct buffer *buf, *tmp;
p->destroy_buffers = false;
wl_list_for_each_safe(buf, tmp, &p->buffer_list, link) {
wl_list_remove(&buf->link);
if (buf->image) {
mp_image_unrefp(&buf->image);
buf->image = NULL;
}
if (buf->buffer) {
wl_buffer_destroy(buf->buffer);
buf->buffer = NULL;
}
talloc_free(buf);
}
}
static void destroy_osd_buffers(struct vo *vo)
{
if (!vo->wl)
return;
// Remove any existing buffer before we destroy them.
wl_surface_attach(vo->wl->osd_surface, NULL, 0, 0);
wl_surface_commit(vo->wl->osd_surface);
struct priv *p = vo->priv;
struct osd_buffer *osd_buf, *tmp;
wl_list_for_each_safe(osd_buf, tmp, &p->osd_buffer_list, link) {
wl_list_remove(&osd_buf->link);
munmap(osd_buf->image.planes[0], osd_buf->size);
if (osd_buf->buffer) {
wl_buffer_destroy(osd_buf->buffer);
osd_buf->buffer = NULL;
}
}
}
static struct osd_buffer *osd_buffer_check(struct vo *vo)
{
struct priv *p = vo->priv;
struct osd_buffer *osd_buf;
wl_list_for_each(osd_buf, &p->osd_buffer_list, link) {
return osd_buf;
}
return NULL;
}
static struct osd_buffer *osd_buffer_create(struct vo *vo)
{
struct priv *p = vo->priv;
struct osd_buffer *osd_buf = talloc_zero(vo, struct osd_buffer);
osd_buf->vo = vo;
osd_buf->size = p->osd_shm_height * p->osd_shm_stride;
mp_image_set_size(&osd_buf->image, p->osd_shm_width, p->osd_shm_height);
osd_buf->image.planes[0] = p->osd_shm_data;
osd_buf->image.stride[0] = p->osd_shm_stride;
osd_buf->buffer = wl_shm_pool_create_buffer(p->osd_shm_pool, 0,
p->osd_shm_width, p->osd_shm_height,
p->osd_shm_stride, WL_SHM_FORMAT_ARGB8888);
if (!osd_buf->buffer) {
talloc_free(osd_buf);
return NULL;
}
wl_list_insert(&p->osd_buffer_list, &osd_buf->link);
wl_buffer_add_listener(osd_buf->buffer, &osd_buffer_listener, osd_buf);
return osd_buf;
}
static struct osd_buffer *osd_buffer_get(struct vo *vo)
{
struct osd_buffer *osd_buf = osd_buffer_check(vo);
if (osd_buf) {
return osd_buf;
} else {
return osd_buffer_create(vo);
}
}
static void create_shm_pool(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wl;
struct priv *p = vo->priv;
int stride = MP_ALIGN_UP(vo->dwidth * 4, 16);
size_t size = vo->dheight * stride;
int fd = vo_wayland_allocate_memfd(vo, size);
if (fd < 0)
return;
uint8_t *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
goto error1;
struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, fd, size);
if (!pool)
goto error2;
close(fd);
destroy_osd_buffers(vo);
if (p->osd_shm_pool)
wl_shm_pool_destroy(p->osd_shm_pool);
p->osd_shm_pool = pool;
p->osd_shm_width = vo->dwidth;
p->osd_shm_height = vo->dheight;
p->osd_shm_stride = stride;
p->osd_shm_data = data;
return;
error2:
munmap(data, size);
error1:
close(fd);
}
static void set_viewport_source(struct vo *vo, struct mp_rect src)
{
struct priv *p = vo->priv;
struct vo_wayland_state *wl = vo->wl;
if (wl->video_viewport && !mp_rect_equals(&p->src, &src)) {
wp_viewport_set_source(wl->video_viewport, src.x0 << 8,
src.y0 << 8, mp_rect_w(src) << 8,
mp_rect_h(src) << 8);
p->src = src;
}
}
static void resize(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wl;
struct priv *p = vo->priv;
struct mp_rect src;
struct mp_rect dst;
struct mp_vo_opts *vo_opts = wl->vo_opts;
const int width = mp_rect_w(wl->geometry);
const int height = mp_rect_h(wl->geometry);
if (width == 0 || height == 0)
return;
vo_wayland_set_opaque_region(wl, false);
vo->dwidth = width;
vo->dheight = height;
create_shm_pool(vo);
// top level viewport is calculated with pan set to zero
vo->opts->pan_x = 0;
vo->opts->pan_y = 0;
vo_get_src_dst_rects(vo, &src, &dst, &p->screen_osd_res);
wp_viewport_set_destination(wl->viewport, 2 * dst.x0 + mp_rect_w(dst), 2 * dst.y0 + mp_rect_h(dst));
//now we restore pan for video viewport calculation
vo->opts->pan_x = vo_opts->pan_x;
vo->opts->pan_y = vo_opts->pan_y;
vo_get_src_dst_rects(vo, &src, &dst, &p->screen_osd_res);
wp_viewport_set_destination(wl->video_viewport, mp_rect_w(dst), mp_rect_h(dst));
wl_subsurface_set_position(wl->video_subsurface, dst.x0, dst.y0);
wp_viewport_set_destination(wl->osd_viewport, vo->dwidth, vo->dheight);
wl_subsurface_set_position(wl->osd_subsurface, 0 - dst.x0, 0 - dst.y0);
set_viewport_source(vo, src);
}
static bool draw_osd(struct vo *vo, struct mp_image *cur, double pts)
{
struct priv *p = vo->priv;
struct mp_osd_res *res = &p->screen_osd_res;
bool draw = false;
struct sub_bitmap_list *sbs = osd_render(vo->osd, *res, pts, 0, mp_draw_sub_formats);
if (!sbs)
return draw;
struct mp_rect act_rc[1], mod_rc[64];
int num_act_rc = 0, num_mod_rc = 0;
if (!p->osd_cache)
p->osd_cache = mp_draw_sub_alloc(p, vo->global);
struct mp_image *osd = mp_draw_sub_overlay(p->osd_cache, sbs, act_rc,
MP_ARRAY_SIZE(act_rc), &num_act_rc,
mod_rc, MP_ARRAY_SIZE(mod_rc), &num_mod_rc);
if (!osd || !num_mod_rc)
goto done;
for (int n = 0; n < num_mod_rc; n++) {
struct mp_rect rc = mod_rc[n];
int rw = mp_rect_w(rc);
int rh = mp_rect_h(rc);
void *src = mp_image_pixel_ptr(osd, 0, rc.x0, rc.y0);
void *dst = cur->planes[0] + rc.x0 * 4 + rc.y0 * cur->stride[0];
memcpy_pic(dst, src, rw * 4, rh, cur->stride[0], osd->stride[0]);
}
draw = true;
done:
talloc_free(sbs);
return draw;
}
static void draw_frame(struct vo *vo, struct vo_frame *frame)
{
struct priv *p = vo->priv;
struct vo_wayland_state *wl = vo->wl;
struct buffer *buf;
struct osd_buffer *osd_buf;
double pts;
if (!vo_wayland_check_visible(vo) || !frame->current)
return;
if (p->destroy_buffers)
destroy_buffers(vo);
pts = frame->current->pts;
struct mp_image *src = mp_image_new_ref(frame->current);
buf = buffer_get(vo, src);
osd_buf = osd_buffer_get(vo);
if (buf && buf->image) {
wl_surface_attach(wl->video_surface, buf->buffer, 0, 0);
wl_surface_damage_buffer(wl->video_surface, 0, 0, buf->image->w,
buf->image->h);
if (osd_buf && osd_buf->buffer) {
if (draw_osd(vo, &osd_buf->image, pts)) {
wl_surface_attach(wl->osd_surface, osd_buf->buffer, 0, 0);
wl_surface_damage_buffer(wl->osd_surface, 0, 0, osd_buf->image.w,
osd_buf->image.h);
}
}
}
}
static void flip_page(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wl;
wl_surface_commit(wl->video_surface);
wl_surface_commit(wl->osd_surface);
wl_surface_commit(wl->surface);
if (!wl->opts->disable_vsync)
vo_wayland_wait_frame(wl);
if (wl->use_present)
present_sync_swap(wl->present);
}
static void get_vsync(struct vo *vo, struct vo_vsync_info *info)
{
struct vo_wayland_state *wl = vo->wl;
if (wl->use_present)
present_sync_get_info(wl->present, info);
}
static bool is_supported_fmt(int fmt)
{
return (fmt == IMGFMT_DRMPRIME || fmt == IMGFMT_VAAPI);
}
static int query_format(struct vo *vo, int format)
{
return is_supported_fmt(format);
}
static int reconfig(struct vo *vo, struct mp_image *img)
{
struct priv *p = vo->priv;
// If we have a supported format but no hw_subfmt, this
// is probably handle_force_window. Consider it valid.
if (is_supported_fmt(img->params.imgfmt) && img->params.hw_subfmt == IMGFMT_NONE)
goto done;
if (!drm_format_check(vo, img)) {
MP_ERR(vo, "Unable to get drm format from hardware decoding!\n");
return VO_ERROR;
}
if (!ra_compatible_format(p->ctx->ra, p->drm_format, p->drm_modifier)) {
MP_ERR(vo, "Format '%s' with modifier '(%016lx)' is not supported by"
" the compositor.\n", mp_tag_str(p->drm_format), p->drm_modifier);
return VO_ERROR;
}
done:
if (!vo_wayland_reconfig(vo))
return VO_ERROR;
// Immediately destroy all buffers if params change.
destroy_buffers(vo);
return 0;
}
static int control(struct vo *vo, uint32_t request, void *data)
{
struct priv *p = vo->priv;
int events = 0;
int ret;
switch (request) {
case VOCTRL_RESET:
p->destroy_buffers = true;
return VO_TRUE;
case VOCTRL_SET_PANSCAN:
resize(vo);
return VO_TRUE;
}
ret = vo_wayland_control(vo, &events, request, data);
if (events & VO_EVENT_RESIZE)
resize(vo);
if (events & VO_EVENT_EXPOSE)
vo->want_redraw = true;
vo_event(vo, events);
return ret;
}
static void uninit(struct vo *vo)
{
struct priv *p = vo->priv;
destroy_buffers(vo);
destroy_osd_buffers(vo);
if (p->osd_shm_pool)
wl_shm_pool_destroy(p->osd_shm_pool);
if (p->solid_buffer_pool)
wl_shm_pool_destroy(p->solid_buffer_pool);
if (p->solid_buffer)
wl_buffer_destroy(p->solid_buffer);
ra_hwdec_ctx_uninit(&p->hwdec_ctx);
if (vo->hwdec_devs) {
hwdec_devices_set_loader(vo->hwdec_devs, NULL, NULL);
hwdec_devices_destroy(vo->hwdec_devs);
}
vo_wayland_uninit(vo);
ra_ctx_destroy(&p->ctx);
}
static int preinit(struct vo *vo)
{
struct priv *p = vo->priv;
p->log = vo->log;
p->global = vo->global;
p->ctx = ra_ctx_create_by_name(vo, "wldmabuf");
wl_list_init(&p->buffer_list);
wl_list_init(&p->osd_buffer_list);
if (!p->ctx)
goto err;
assert(p->ctx->ra);
if (!vo->wl->dmabuf || !vo->wl->dmabuf_feedback) {
MP_FATAL(vo->wl, "Compositor doesn't support the %s (ver. 4) protocol!\n",
zwp_linux_dmabuf_v1_interface.name);
goto err;
}
if (!vo->wl->shm) {
MP_FATAL(vo->wl, "Compositor doesn't support the %s protocol!\n",
wl_shm_interface.name);
goto err;
}
if (!vo->wl->video_subsurface) {
MP_FATAL(vo->wl, "Compositor doesn't support the %s protocol!\n",
wl_subcompositor_interface.name);
goto err;
}
if (!vo->wl->viewport) {
MP_FATAL(vo->wl, "Compositor doesn't support the %s protocol!\n",
wp_viewporter_interface.name);
goto err;
}
if (vo->wl->single_pixel_manager) {
#if HAVE_WAYLAND_PROTOCOLS_1_27
p->solid_buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(
vo->wl->single_pixel_manager, 0, 0, 0, UINT32_MAX); /* R, G, B, A */
#endif
} else {
int width = 1;
int height = 1;
int stride = MP_ALIGN_UP(width * 4, 16);
int fd = vo_wayland_allocate_memfd(vo, stride);
if (fd < 0)
goto err;
p->solid_buffer_pool = wl_shm_create_pool(vo->wl->shm, fd, height * stride);
close(fd);
if (!p->solid_buffer_pool)
goto err;
p->solid_buffer = wl_shm_pool_create_buffer(
p->solid_buffer_pool, 0, width, height, stride, WL_SHM_FORMAT_XRGB8888);
}
if (!p->solid_buffer)
goto err;
wl_surface_attach(vo->wl->surface, p->solid_buffer, 0, 0);
vo->hwdec_devs = hwdec_devices_create();
p->hwdec_ctx = (struct ra_hwdec_ctx) {
.log = p->log,
.global = p->global,
.ra_ctx = p->ctx,
};
ra_hwdec_ctx_init(&p->hwdec_ctx, vo->hwdec_devs, NULL, true);
// Loop through hardware accelerated formats and only request known
// supported formats.
for (int i = IMGFMT_VDPAU_OUTPUT; i < IMGFMT_AVPIXFMT_START; ++i) {
if (is_supported_fmt(i)) {
struct hwdec_imgfmt_request params = {
.imgfmt = i,
.probing = false,
};
ra_hwdec_ctx_load_fmt(&p->hwdec_ctx, vo->hwdec_devs, &params);
}
}
for (int i = 0; i < p->hwdec_ctx.num_hwdecs; i++) {
struct ra_hwdec *hw = p->hwdec_ctx.hwdecs[i];
if (ra_get_native_resource(p->ctx->ra, "VADisplay")) {
p->hwdec_type = HWDEC_VAAPI;
} else if (strcmp(hw->driver->name, "drmprime") == 0) {
p->hwdec_type = HWDEC_DRMPRIME;
}
}
if (p->hwdec_type == HWDEC_NONE) {
MP_ERR(vo, "No valid hardware decoding driver could be loaded!\n");
goto err;
}
p->src = (struct mp_rect){0, 0, 0, 0};
return 0;
err:
uninit(vo);
return -1;
}
const struct vo_driver video_out_dmabuf_wayland = {
.description = "Wayland dmabuf video output",
.name = "dmabuf-wayland",
.preinit = preinit,
.query_format = query_format,
.reconfig2 = 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),
};