Mesa (main): egl/wayland: add initial dma-buf feedback support
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Fri Nov 26 20:00:50 UTC 2021
Module: Mesa
Branch: main
Commit: 83916ae0b9b920c521bf9bb3e5f82fb911b3a3cf
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=83916ae0b9b920c521bf9bb3e5f82fb911b3a3cf
Author: Leandro Ribeiro <leandro.ribeiro at collabora.com>
Date: Mon Nov 15 13:51:12 2021 -0300
egl/wayland: add initial dma-buf feedback support
This bumps the supported dma-buf version up to 4 and adds the initial
dma-buf feedback implementation. It follows the changes in the dma-buf
protocol extension [1] to include the dma-buf feedback interface, which
should be incorporated by most Wayland compositors in the future.
>From version 4 onwards, the dma-buf modifier events are not sent by the
compositor anymore, so we use the default feedback to pick the set of
formats/modifiers supported by the compositor. Also, we try to avoid the
wl_drm device event and instead use the dma-buf feedback main device. We
only fallback to wl_drm when the compositor advertises a device that
does not have a render node associated.
In this initial dma-buf feedback implementation we still don't do
anything with the per-surface dma-buf feedback, but in the next commits
we add proper support.
It's important to mention that this also bumps the minimal supported
version of wayland-protocols to 1.24, in order to include [1].
[1] https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/8
This patch is based on previous work of Scott Anderson (@ascent).
Signed-off-by: Scott Anderson <scott.anderson at collabora.com>
Signed-off-by: Leandro Ribeiro <leandro.ribeiro at collabora.com>
Reviewed-by: Daniel Stone <daniels at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11248>
---
meson.build | 2 +-
src/egl/drivers/dri2/egl_dri2.h | 30 +++
src/egl/drivers/dri2/platform_wayland.c | 434 +++++++++++++++++++++++++++++++-
3 files changed, 453 insertions(+), 13 deletions(-)
diff --git a/meson.build b/meson.build
index d249418ea60..f5f0f7125bc 100644
--- a/meson.build
+++ b/meson.build
@@ -1990,7 +1990,7 @@ if with_platform_wayland
else
wl_scanner_arg = 'code'
endif
- dep_wl_protocols = dependency('wayland-protocols', version : '>= 1.8')
+ dep_wl_protocols = dependency('wayland-protocols', version : '>= 1.24')
dep_wayland_client = dependency('wayland-client', version : '>=1.18')
dep_wayland_server = dependency('wayland-server', version : '>=1.18')
if with_egl
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 169ca6fa221..948c9acb89e 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -53,6 +53,7 @@ struct wl_registry;
struct wl_shm;
struct wl_surface;
struct zwp_linux_dmabuf_v1;
+struct zwp_linux_dmabuf_feedback_v1;
#endif
#include <GL/gl.h>
@@ -87,6 +88,7 @@ struct zwp_linux_dmabuf_v1;
#include "eglsync.h"
#include "util/u_vector.h"
+#include "util/u_dynarray.h"
#include "util/bitset.h"
struct wl_buffer;
@@ -181,6 +183,28 @@ struct dri2_wl_formats {
/* Array of vectors. Contains one modifier vector per format */
struct u_vector *modifiers;
};
+
+struct dmabuf_feedback_format_table {
+ unsigned int size;
+ struct {
+ uint32_t format;
+ uint32_t padding; /* unused */
+ uint64_t modifier;
+ } *data;
+};
+
+struct dmabuf_feedback_tranche {
+ dev_t target_device;
+ uint32_t flags;
+ struct dri2_wl_formats formats;
+};
+
+struct dmabuf_feedback {
+ dev_t main_device;
+ struct dmabuf_feedback_format_table format_table;
+ struct util_dynarray tranches;
+ struct dmabuf_feedback_tranche pending_tranche;
+};
#endif
struct dri2_egl_display
@@ -251,10 +275,13 @@ struct dri2_egl_display
struct wl_registry *wl_registry;
struct wl_drm *wl_server_drm;
struct wl_drm *wl_drm;
+ uint32_t wl_drm_version, wl_drm_name;
struct wl_shm *wl_shm;
struct wl_event_queue *wl_queue;
struct zwp_linux_dmabuf_v1 *wl_dmabuf;
struct dri2_wl_formats formats;
+ struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback;
+ struct dmabuf_feedback_format_table format_table;
bool authenticated;
char *device_name;
#endif
@@ -300,6 +327,9 @@ struct dri2_egl_surface
struct wl_display *wl_dpy_wrapper;
struct wl_drm *wl_drm_wrapper;
struct wl_callback *throttle_callback;
+ struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback;
+ struct dmabuf_feedback dmabuf_feedback, pending_dmabuf_feedback;
+ bool compositor_using_another_device;
int format;
bool resized;
#endif
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index 9e05bc4e834..60c6cecbb0d 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -318,6 +318,64 @@ err:
return -1;
}
+static void
+dmabuf_feedback_format_table_fini(struct dmabuf_feedback_format_table *format_table)
+{
+ if (format_table->data && format_table->data != MAP_FAILED)
+ munmap(format_table->data, format_table->size);
+}
+
+static void
+dmabuf_feedback_format_table_init(struct dmabuf_feedback_format_table *format_table)
+{
+ memset(format_table, 0, sizeof(*format_table));
+}
+
+static void
+dmabuf_feedback_tranche_fini(struct dmabuf_feedback_tranche *tranche)
+{
+ dri2_wl_formats_fini(&tranche->formats);
+}
+
+static int
+dmabuf_feedback_tranche_init(struct dmabuf_feedback_tranche *tranche)
+{
+ memset(tranche, 0, sizeof(*tranche));
+
+ if (dri2_wl_formats_init(&tranche->formats) < 0)
+ return -1;
+
+ return 0;
+}
+
+static void
+dmabuf_feedback_fini(struct dmabuf_feedback *dmabuf_feedback)
+{
+ dmabuf_feedback_tranche_fini(&dmabuf_feedback->pending_tranche);
+
+ util_dynarray_foreach(&dmabuf_feedback->tranches,
+ struct dmabuf_feedback_tranche, tranche)
+ dmabuf_feedback_tranche_fini(tranche);
+ util_dynarray_fini(&dmabuf_feedback->tranches);
+
+ dmabuf_feedback_format_table_fini(&dmabuf_feedback->format_table);
+}
+
+static int
+dmabuf_feedback_init(struct dmabuf_feedback *dmabuf_feedback)
+{
+ memset(dmabuf_feedback, 0, sizeof(*dmabuf_feedback));
+
+ if (dmabuf_feedback_tranche_init(&dmabuf_feedback->pending_tranche) < 0)
+ return -1;
+
+ util_dynarray_init(&dmabuf_feedback->tranches, NULL);
+
+ dmabuf_feedback_format_table_init(&dmabuf_feedback->format_table);
+
+ return 0;
+}
+
static void
resize_callback(struct wl_egl_window *wl_win, void *data)
{
@@ -365,6 +423,157 @@ get_wl_surface_proxy(struct wl_egl_window *window)
return wl_proxy_create_wrapper(window->surface);
}
+static void
+surface_dmabuf_feedback_format_table(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
+ int32_t fd, uint32_t size)
+{
+ struct dri2_egl_surface *dri2_surf = data;
+ struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
+
+ feedback->format_table.size = size;
+ feedback->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ close(fd);
+}
+
+static void
+surface_dmabuf_feedback_main_device(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
+ struct wl_array *device)
+{
+ struct dri2_egl_surface *dri2_surf = data;
+ struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
+
+ memcpy(&feedback->main_device, device->data, sizeof(feedback->main_device));
+
+ /* Compositors may support switching render devices and change the main
+ * device of the dma-buf feedback. In this case, when we reallocate the
+ * buffers of the surface we must ensure that it is not allocated in memory
+ * that is only visible to the GPU that EGL is using, as the compositor will
+ * have to import them to the render device it is using.
+ *
+ * TODO: we still don't know how to allocate such buffers.
+ */
+ if (dri2_surf->dmabuf_feedback.main_device != 0 &&
+ (feedback->main_device != dri2_surf->dmabuf_feedback.main_device))
+ dri2_surf->compositor_using_another_device = true;
+ else
+ dri2_surf->compositor_using_another_device = false;
+}
+
+static void
+surface_dmabuf_feedback_tranche_target_device(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
+ struct wl_array *device)
+{
+ struct dri2_egl_surface *dri2_surf = data;
+ struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
+
+ memcpy(&feedback->pending_tranche.target_device, device->data,
+ sizeof(feedback->pending_tranche.target_device));
+}
+
+static void
+surface_dmabuf_feedback_tranche_flags(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
+ uint32_t flags)
+{
+ struct dri2_egl_surface *dri2_surf = data;
+ struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
+
+ feedback->pending_tranche.flags = flags;
+}
+
+static void
+surface_dmabuf_feedback_tranche_formats(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
+ struct wl_array *indices)
+{
+ struct dri2_egl_surface *dri2_surf = data;
+ struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
+ uint64_t *modifier_ptr, modifier;
+ uint32_t format;
+ uint16_t *index;
+ int visual_idx;
+
+ /* Compositor may advertise or not a format table. If it does, we use it.
+ * Otherwise, we steal the most recent advertised format table. If we don't have
+ * a most recent advertised format table, compositor did something wrong. */
+ if (feedback->format_table.data == NULL) {
+ feedback->format_table = dri2_surf->dmabuf_feedback.format_table;
+ dmabuf_feedback_format_table_init(&dri2_surf->dmabuf_feedback.format_table);
+ }
+ if (feedback->format_table.data == MAP_FAILED) {
+ _eglLog(_EGL_WARNING, "wayland-egl: we could not map the format table "
+ "so we won't be able to use this batch of dma-buf "
+ "feedback events.");
+ return;
+ }
+ if (feedback->format_table.data == NULL) {
+ _eglLog(_EGL_WARNING, "wayland-egl: compositor didn't advertise a format "
+ "table, so we won't be able to use this batch of dma-buf "
+ "feedback events.");
+ return;
+ }
+
+ wl_array_for_each(index, indices) {
+ format = feedback->format_table.data[*index].format;
+ modifier = feedback->format_table.data[*index].modifier;
+
+ /* Skip formats that are not the one the surface is already using. We
+ * can't switch to another format. */
+ if (format != dri2_surf->format)
+ continue;
+
+ /* We are sure that the format is supported because of the check above. */
+ visual_idx = dri2_wl_visual_idx_from_fourcc(format);
+ assert(visual_idx != -1);
+
+ BITSET_SET(feedback->pending_tranche.formats.formats_bitmap, visual_idx);
+ modifier_ptr =
+ u_vector_add(&feedback->pending_tranche.formats.modifiers[visual_idx]);
+ if (modifier_ptr)
+ *modifier_ptr = modifier;
+ }
+}
+
+static void
+surface_dmabuf_feedback_tranche_done(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
+{
+ struct dri2_egl_surface *dri2_surf = data;
+ struct dmabuf_feedback *feedback = &dri2_surf->pending_dmabuf_feedback;
+
+ /* Add tranche to array of tranches. */
+ util_dynarray_append(&feedback->tranches, struct dmabuf_feedback_tranche,
+ feedback->pending_tranche);
+
+ dmabuf_feedback_tranche_init(&feedback->pending_tranche);
+}
+
+static void
+surface_dmabuf_feedback_done(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
+{
+ struct dri2_egl_surface *dri2_surf = data;
+
+ dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback);
+ dri2_surf->dmabuf_feedback = dri2_surf->pending_dmabuf_feedback;
+ dmabuf_feedback_init(&dri2_surf->pending_dmabuf_feedback);
+}
+
+static const struct zwp_linux_dmabuf_feedback_v1_listener
+surface_dmabuf_feedback_listener = {
+ .format_table = surface_dmabuf_feedback_format_table,
+ .main_device = surface_dmabuf_feedback_main_device,
+ .tranche_target_device = surface_dmabuf_feedback_tranche_target_device,
+ .tranche_flags = surface_dmabuf_feedback_tranche_flags,
+ .tranche_formats = surface_dmabuf_feedback_tranche_formats,
+ .tranche_done = surface_dmabuf_feedback_tranche_done,
+ .done = surface_dmabuf_feedback_done,
+};
+
/**
* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
*/
@@ -376,6 +585,7 @@ dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
struct wl_egl_window *window = native_window;
struct dri2_egl_surface *dri2_surf;
+ struct zwp_linux_dmabuf_v1 *dmabuf_wrapper;
int visual_idx;
const __DRIconfig *config;
@@ -487,6 +697,33 @@ dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper,
dri2_surf->wl_queue);
+ if (dri2_dpy->wl_dmabuf && zwp_linux_dmabuf_v1_get_version(dri2_dpy->wl_dmabuf) >=
+ ZWP_LINUX_DMABUF_V1_GET_SURFACE_FEEDBACK_SINCE_VERSION) {
+ dmabuf_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dmabuf);
+ if (!dmabuf_wrapper) {
+ _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
+ goto cleanup_surf_wrapper;
+ }
+ wl_proxy_set_queue((struct wl_proxy *)dmabuf_wrapper,
+ dri2_surf->wl_queue);
+ dri2_surf->wl_dmabuf_feedback =
+ zwp_linux_dmabuf_v1_get_surface_feedback(dmabuf_wrapper,
+ dri2_surf->wl_surface_wrapper);
+ wl_proxy_wrapper_destroy(dmabuf_wrapper);
+
+ zwp_linux_dmabuf_feedback_v1_add_listener(dri2_surf->wl_dmabuf_feedback,
+ &surface_dmabuf_feedback_listener,
+ dri2_surf);
+
+ if (dmabuf_feedback_init(&dri2_surf->pending_dmabuf_feedback) < 0)
+ goto cleanup_surf_wrapper;
+ if (dmabuf_feedback_init(&dri2_surf->dmabuf_feedback) < 0)
+ goto cleanup_pending_dmabuf_feedback;
+
+ if (roundtrip(dri2_dpy) < 0)
+ goto cleanup_dmabuf_feedback;
+ }
+
dri2_surf->wl_win = window;
dri2_surf->wl_win->driver_private = dri2_surf;
dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;
@@ -494,12 +731,19 @@ dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
dri2_surf->wl_win->resize_callback = resize_callback;
if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
- goto cleanup_surf_wrapper;
+ goto cleanup_dmabuf_feedback;
dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval;
return &dri2_surf->base;
+ cleanup_dmabuf_feedback:
+ if (dri2_surf->wl_dmabuf_feedback) {
+ zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback);
+ dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback);
+ cleanup_pending_dmabuf_feedback:
+ dmabuf_feedback_fini(&dri2_surf->pending_dmabuf_feedback);
+ }
cleanup_surf_wrapper:
wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
cleanup_dpy_wrapper:
@@ -569,6 +813,11 @@ dri2_wl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
if (dri2_surf->wl_drm_wrapper)
wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
+ if (dri2_surf->wl_dmabuf_feedback) {
+ zwp_linux_dmabuf_feedback_v1_destroy(dri2_surf->wl_dmabuf_feedback);
+ dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback);
+ dmabuf_feedback_fini(&dri2_surf->pending_dmabuf_feedback);
+ }
wl_event_queue_destroy(dri2_surf->wl_queue);
dri2_fini_surface(surf);
@@ -1382,6 +1631,12 @@ dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
int visual_idx = dri2_wl_visual_idx_from_fourcc(format);
uint64_t *mod;
+ /* Ignore this if the compositor advertised dma-buf feedback. From version 4
+ * onwards (when dma-buf feedback was introduced), the compositor should not
+ * advertise this event anymore, but let's keep this for safety. */
+ if (dri2_dpy->wl_dmabuf_feedback)
+ return;
+
if (visual_idx == -1)
return;
@@ -1397,6 +1652,134 @@ static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
.modifier = dmabuf_handle_modifier,
};
+static void
+wl_drm_bind(struct dri2_egl_display *dri2_dpy)
+{
+ dri2_dpy->wl_drm = wl_registry_bind(dri2_dpy->wl_registry, dri2_dpy->wl_drm_name,
+ &wl_drm_interface, dri2_dpy->wl_drm_version);
+ wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
+}
+
+static void
+default_dmabuf_feedback_format_table(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
+ int32_t fd, uint32_t size)
+{
+ struct dri2_egl_display *dri2_dpy = data;
+
+ dri2_dpy->format_table.size = size;
+ dri2_dpy->format_table.data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ close(fd);
+}
+
+static void
+default_dmabuf_feedback_main_device(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
+ struct wl_array *device)
+{
+ struct dri2_egl_display *dri2_dpy = data;
+ char *node;
+ int fd;
+ dev_t dev;
+
+ /* Given the device, look for a render node and try to open it. */
+ memcpy(&dev, device->data, sizeof(dev));
+ node = loader_get_render_node(dev);
+ if (!node)
+ return;
+ fd = loader_open_device(node);
+ if (fd == -1) {
+ free(node);
+ return;
+ }
+
+ dri2_dpy->device_name = node;
+ dri2_dpy->fd = fd;
+ dri2_dpy->authenticated = true;
+}
+
+static void
+default_dmabuf_feedback_tranche_target_device(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
+ struct wl_array *device)
+{
+ /* ignore this event */
+}
+
+static void
+default_dmabuf_feedback_tranche_flags(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
+ uint32_t flags)
+{
+ /* ignore this event */
+}
+
+static void
+default_dmabuf_feedback_tranche_formats(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
+ struct wl_array *indices)
+{
+ struct dri2_egl_display *dri2_dpy = data;
+ uint64_t *modifier_ptr, modifier;
+ uint32_t format;
+ uint16_t *index;
+ int visual_idx;
+
+ if (dri2_dpy->format_table.data == MAP_FAILED) {
+ _eglLog(_EGL_WARNING, "wayland-egl: we could not map the format table "
+ "so we won't be able to use this batch of dma-buf "
+ "feedback events.");
+ return;
+ }
+ if (dri2_dpy->format_table.data == NULL) {
+ _eglLog(_EGL_WARNING, "wayland-egl: compositor didn't advertise a format "
+ "table, so we won't be able to use this batch of dma-buf "
+ "feedback events.");
+ return;
+ }
+
+ wl_array_for_each(index, indices) {
+ format = dri2_dpy->format_table.data[*index].format;
+ modifier = dri2_dpy->format_table.data[*index].modifier;
+
+ /* skip formats that we don't support */
+ visual_idx = dri2_wl_visual_idx_from_fourcc(format);
+ if (visual_idx == -1)
+ continue;
+
+ BITSET_SET(dri2_dpy->formats.formats_bitmap, visual_idx);
+ modifier_ptr = u_vector_add(&dri2_dpy->formats.modifiers[visual_idx]);
+ if (modifier_ptr)
+ *modifier_ptr = modifier;
+ }
+}
+
+static void
+default_dmabuf_feedback_tranche_done(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
+{
+ /* ignore this event */
+}
+
+static void
+default_dmabuf_feedback_done(void *data,
+ struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
+{
+ /* ignore this event */
+}
+
+static const struct zwp_linux_dmabuf_feedback_v1_listener
+dmabuf_feedback_listener = {
+ .format_table = default_dmabuf_feedback_format_table,
+ .main_device = default_dmabuf_feedback_main_device,
+ .tranche_target_device = default_dmabuf_feedback_tranche_target_device,
+ .tranche_flags = default_dmabuf_feedback_tranche_flags,
+ .tranche_formats = default_dmabuf_feedback_tranche_formats,
+ .tranche_done = default_dmabuf_feedback_tranche_done,
+ .done = default_dmabuf_feedback_done,
+};
+
static void
registry_handle_global_drm(void *data, struct wl_registry *registry,
uint32_t name, const char *interface,
@@ -1405,13 +1788,12 @@ registry_handle_global_drm(void *data, struct wl_registry *registry,
struct dri2_egl_display *dri2_dpy = data;
if (strcmp(interface, "wl_drm") == 0) {
- dri2_dpy->wl_drm =
- wl_registry_bind(registry, name, &wl_drm_interface, MIN2(version, 2));
- wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
+ dri2_dpy->wl_drm_version = MIN2(version, 2);
+ dri2_dpy->wl_drm_name = name;
} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
dri2_dpy->wl_dmabuf =
wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,
- MIN2(version, 3));
+ MIN2(version, ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION));
zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener,
dri2_dpy);
}
@@ -1582,19 +1964,47 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp)
dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
wl_registry_add_listener(dri2_dpy->wl_registry,
®istry_listener_drm, dri2_dpy);
- if (roundtrip(dri2_dpy) < 0)
- goto cleanup;
- if (dri2_dpy->wl_drm == NULL || dri2_dpy->wl_dmabuf == NULL)
+ /* The compositor must expose the dma-buf interface. */
+ if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_dmabuf == NULL)
goto cleanup;
- if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
- goto cleanup;
+ /* Get default dma-buf feedback */
+ if (zwp_linux_dmabuf_v1_get_version(dri2_dpy->wl_dmabuf) >=
+ ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) {
+ dmabuf_feedback_format_table_init(&dri2_dpy->format_table);
+ dri2_dpy->wl_dmabuf_feedback =
+ zwp_linux_dmabuf_v1_get_default_feedback(dri2_dpy->wl_dmabuf);
+ zwp_linux_dmabuf_feedback_v1_add_listener(dri2_dpy->wl_dmabuf_feedback,
+ &dmabuf_feedback_listener, dri2_dpy);
+ }
- if (!dri2_dpy->authenticated &&
- (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated))
+ /* Receive events from the interfaces */
+ if (roundtrip(dri2_dpy) < 0)
goto cleanup;
+ /* Destroy the default dma-buf feedback and the format table. */
+ if (dri2_dpy->wl_dmabuf_feedback) {
+ zwp_linux_dmabuf_feedback_v1_destroy(dri2_dpy->wl_dmabuf_feedback);
+ dri2_dpy->wl_dmabuf_feedback = NULL;
+ dmabuf_feedback_format_table_fini(&dri2_dpy->format_table);
+ }
+
+ /* We couldn't retrieve a render node from the dma-buf feedback (or the
+ * feedback was not advertised at all), so we must fallback to wl_drm. */
+ if (dri2_dpy->fd == -1) {
+ wl_drm_bind(dri2_dpy);
+
+ if (dri2_dpy->wl_drm == NULL)
+ goto cleanup;
+ if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
+ goto cleanup;
+
+ if (!dri2_dpy->authenticated &&
+ (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated))
+ goto cleanup;
+ }
+
dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,
&dri2_dpy->is_different_gpu);
dev = _eglAddDevice(dri2_dpy->fd, false);
More information about the mesa-commit
mailing list