mirror of https://gitlab.freedesktop.org/mesa/mesa
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@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11248>
This commit is contained in:
parent
a25d4dd276
commit
83916ae0b9
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,18 +1964,46 @@ 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);
|
||||
|
||||
/* The compositor must expose the dma-buf interface. */
|
||||
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_dmabuf == NULL)
|
||||
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);
|
||||
}
|
||||
|
||||
/* Receive events from the interfaces */
|
||||
if (roundtrip(dri2_dpy) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (dri2_dpy->wl_drm == NULL || dri2_dpy->wl_dmabuf == NULL)
|
||||
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);
|
||||
}
|
||||
|
||||
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
|
||||
goto cleanup;
|
||||
/* 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->authenticated &&
|
||||
(roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated))
|
||||
goto cleanup;
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue