diff --git a/0001-egl-Add-eglQueryDisplayAttribEXT-helper.patch b/0001-egl-Add-eglQueryDisplayAttribEXT-helper.patch new file mode 100644 index 0000000..61f659b --- /dev/null +++ b/0001-egl-Add-eglQueryDisplayAttribEXT-helper.patch @@ -0,0 +1,80 @@ +From 0e6889f3ad3e417b29c5ea29fe6dfe485e5f6218 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 4 Aug 2021 09:59:50 +0200 +Subject: [PATCH 01/18] egl: Add eglQueryDisplayAttribEXT() helper + +To be used to fetch the EGLDevice used for an EGL display. + +Part-of: +(cherry picked from commit 7ce481bf6996b2d99314311bf68afc6bd703c480) +--- + src/backends/meta-egl.c | 23 +++++++++++++++++++++++ + src/backends/meta-egl.h | 6 ++++++ + 2 files changed, 29 insertions(+) + +diff --git a/src/backends/meta-egl.c b/src/backends/meta-egl.c +index fdeff4f779..c2777271ff 100644 +--- a/src/backends/meta-egl.c ++++ b/src/backends/meta-egl.c +@@ -71,6 +71,8 @@ struct _MetaEgl + + PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT; + PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT; ++ ++ PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT; + }; + + G_DEFINE_TYPE (MetaEgl, meta_egl, G_TYPE_OBJECT) +@@ -1064,6 +1066,25 @@ meta_egl_query_dma_buf_modifiers (MetaEgl *egl, + return TRUE; + } + ++gboolean ++meta_egl_query_display_attrib (MetaEgl *egl, ++ EGLDisplay display, ++ EGLint attribute, ++ EGLAttrib *value, ++ GError **error) ++{ ++ if (!is_egl_proc_valid (egl->eglQueryDisplayAttribEXT, error)) ++ return FALSE; ++ ++ if (!egl->eglQueryDisplayAttribEXT (display, attribute, value)) ++ { ++ set_egl_error (error); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ + #define GET_EGL_PROC_ADDR(proc) \ + egl->proc = (void *) eglGetProcAddress (#proc); + +@@ -1102,6 +1123,8 @@ meta_egl_constructed (GObject *object) + + GET_EGL_PROC_ADDR (eglQueryDmaBufFormatsEXT); + GET_EGL_PROC_ADDR (eglQueryDmaBufModifiersEXT); ++ ++ GET_EGL_PROC_ADDR (eglQueryDisplayAttribEXT); + } + + #undef GET_EGL_PROC_ADDR +diff --git a/src/backends/meta-egl.h b/src/backends/meta-egl.h +index 4591e7d853..5c0aacd520 100644 +--- a/src/backends/meta-egl.h ++++ b/src/backends/meta-egl.h +@@ -260,4 +260,10 @@ gboolean meta_egl_query_dma_buf_modifiers (MetaEgl *egl, + EGLint *num_formats, + GError **error); + ++gboolean meta_egl_query_display_attrib (MetaEgl *egl, ++ EGLDisplay display, ++ EGLint attribute, ++ EGLAttrib *value, ++ GError **error); ++ + #endif /* META_EGL_H */ +-- +2.51.1 + diff --git a/0002-wayland-dma-buf-Add-manager-struct.patch b/0002-wayland-dma-buf-Add-manager-struct.patch new file mode 100644 index 0000000..c6974e3 --- /dev/null +++ b/0002-wayland-dma-buf-Add-manager-struct.patch @@ -0,0 +1,217 @@ +From bc73828642ed3ba6e7bee5ee8e8c83f8f15b1e14 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 4 Aug 2021 10:12:33 +0200 +Subject: [PATCH 02/18] wayland/dma-buf: Add manager struct + +It'll be used to store state related to DMA buffer Wayland support. + +Part-of: +(cherry picked from commit 51308a9d78ba712a9a25438e257c430d517f35ac) +--- + src/wayland/meta-wayland-dma-buf.c | 49 ++++++++++++++++++++++-------- + src/wayland/meta-wayland-dma-buf.h | 5 ++- + src/wayland/meta-wayland-private.h | 1 + + src/wayland/meta-wayland-types.h | 2 ++ + src/wayland/meta-wayland.c | 28 ++++++++++++++++- + 5 files changed, 71 insertions(+), 14 deletions(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index 230b13bc8a..0803a942db 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -66,6 +66,11 @@ + + #define META_WAYLAND_DMA_BUF_MAX_FDS 4 + ++struct _MetaWaylandDmaBufManager ++{ ++ MetaWaylandCompositor *compositor; ++}; ++ + struct _MetaWaylandDmaBufBuffer + { + GObject parent; +@@ -696,17 +701,17 @@ send_modifiers (struct wl_resource *resource, + + static void + dma_buf_bind (struct wl_client *client, +- void *data, ++ void *user_data, + uint32_t version, + uint32_t id) + { +- MetaWaylandCompositor *compositor = data; ++ MetaWaylandDmaBufManager *dma_buf_manager = user_data; + struct wl_resource *resource; + + resource = wl_resource_create (client, &zwp_linux_dmabuf_v1_interface, + version, id); + wl_resource_set_implementation (resource, &dma_buf_implementation, +- compositor, NULL); ++ dma_buf_manager, NULL); + send_modifiers (resource, DRM_FORMAT_ARGB8888); + send_modifiers (resource, DRM_FORMAT_ABGR8888); + send_modifiers (resource, DRM_FORMAT_XRGB8888); +@@ -722,38 +727,58 @@ dma_buf_bind (struct wl_client *client, + } + + /** +- * meta_wayland_dma_buf_init: ++ * meta_wayland_dma_buf_manager_new: + * @compositor: The #MetaWaylandCompositor + * + * Creates the global Wayland object that exposes the linux-dmabuf protocol. + * +- * Returns: Whether the initialization was successful. If this is %FALSE, +- * clients won't be able to use the linux-dmabuf protocol to pass buffers. ++ * Returns: (transfer full): The MetaWaylandDmaBufManager instance. + */ +-gboolean +-meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor) ++MetaWaylandDmaBufManager * ++meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, ++ GError **error) + { + MetaBackend *backend = meta_get_backend (); + MetaEgl *egl = meta_backend_get_egl (backend); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); + EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); ++ g_autoptr (GError) local_error = NULL; ++ g_autofree MetaWaylandDmaBufManager *dma_buf_manager = NULL; + + g_assert (backend && egl && clutter_backend && cogl_context && egl_display); + + if (!meta_egl_has_extensions (egl, egl_display, NULL, + "EGL_EXT_image_dma_buf_import_modifiers", + NULL)) +- return FALSE; ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, ++ "Missing 'EGL_EXT_image_dma_buf_import_modifiers'"); ++ return NULL; ++ } ++ ++ dma_buf_manager = g_new0 (MetaWaylandDmaBufManager, 1); + + if (!wl_global_create (compositor->wayland_display, + &zwp_linux_dmabuf_v1_interface, + META_ZWP_LINUX_DMABUF_V1_VERSION, +- compositor, ++ dma_buf_manager, + dma_buf_bind)) +- return FALSE; ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "Failed to create zwp_linux_dmabuf_v1 global"); ++ return NULL; ++ } + +- return TRUE; ++ dma_buf_manager->compositor = compositor; ++ ++ return g_steal_pointer (&dma_buf_manager); ++} ++ ++void ++meta_wayland_dma_buf_manager_free (MetaWaylandDmaBufManager *dma_buf_manager) ++{ ++ g_free (dma_buf_manager); + } + + static void +diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h +index cdc65aeb5b..72fd0b16a0 100644 +--- a/src/wayland/meta-wayland-dma-buf.h ++++ b/src/wayland/meta-wayland-dma-buf.h +@@ -39,7 +39,10 @@ G_DECLARE_FINAL_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, + + typedef struct _MetaWaylandDmaBufBuffer MetaWaylandDmaBufBuffer; + +-gboolean meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor); ++MetaWaylandDmaBufManager * meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, ++ GError **error); ++ ++void meta_wayland_dma_buf_manager_free (MetaWaylandDmaBufManager *dma_buf_manager); + + gboolean + meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, +diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h +index 3306c192c9..3a2724256f 100644 +--- a/src/wayland/meta-wayland-private.h ++++ b/src/wayland/meta-wayland-private.h +@@ -97,6 +97,7 @@ struct _MetaWaylandCompositor + GHashTable *scheduled_surface_associations; + + MetaWaylandPresentationTime presentation_time; ++ MetaWaylandDmaBufManager *dma_buf_manager; + }; + + #define META_TYPE_WAYLAND_COMPOSITOR (meta_wayland_compositor_get_type ()) +diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h +index 00712ad1f1..8ad9084827 100644 +--- a/src/wayland/meta-wayland-types.h ++++ b/src/wayland/meta-wayland-types.h +@@ -61,4 +61,6 @@ typedef struct _MetaWaylandWindowConfiguration MetaWaylandWindowConfiguration; + + typedef struct _MetaWaylandPointerClient MetaWaylandPointerClient; + ++typedef struct _MetaWaylandDmaBufManager MetaWaylandDmaBufManager; ++ + #endif +diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c +index 8f16aa429d..a566a35449 100644 +--- a/src/wayland/meta-wayland.c ++++ b/src/wayland/meta-wayland.c +@@ -454,6 +454,29 @@ meta_wayland_get_xwayland_auth_file (MetaWaylandCompositor *compositor) + return compositor->xwayland_manager.auth_file; + } + ++static void ++init_dma_buf_support (MetaWaylandCompositor *compositor) ++{ ++ g_autoptr (GError) error = NULL; ++ ++ compositor->dma_buf_manager = meta_wayland_dma_buf_manager_new (compositor, ++ &error); ++ if (!compositor->dma_buf_manager) ++ { ++ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) ++ { ++ meta_topic (META_DEBUG_WAYLAND, ++ "Wayland DMA buffer protocol support not enabled: %s", ++ error->message); ++ } ++ else ++ { ++ g_warning ("Wayland DMA buffer protocol support not enabled: %s", ++ error->message); ++ } ++ } ++} ++ + MetaWaylandCompositor * + meta_wayland_compositor_new (MetaBackend *backend) + { +@@ -507,7 +530,7 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *compositor) + meta_wayland_relative_pointer_init (compositor); + meta_wayland_pointer_constraints_init (compositor); + meta_wayland_xdg_foreign_init (compositor); +- meta_wayland_dma_buf_init (compositor); ++ init_dma_buf_support (compositor); + meta_wayland_keyboard_shortcuts_inhibit_init (compositor); + meta_wayland_surface_inhibit_shortcuts_dialog_init (); + meta_wayland_text_input_init (compositor); +@@ -595,6 +618,9 @@ meta_wayland_finalize (void) + if (compositor->wayland_display) + wl_display_destroy_clients (compositor->wayland_display); + ++ g_clear_pointer (&compositor->dma_buf_manager, ++ meta_wayland_dma_buf_manager_free); ++ + g_clear_pointer (&compositor->seat, meta_wayland_seat_free); + + g_clear_pointer (&compositor->display_name, g_free); +-- +2.51.1 + diff --git a/0003-wayland-dma-buf-Prepare-format-modifier-map-up-front.patch b/0003-wayland-dma-buf-Prepare-format-modifier-map-up-front.patch new file mode 100644 index 0000000..617acc2 --- /dev/null +++ b/0003-wayland-dma-buf-Prepare-format-modifier-map-up-front.patch @@ -0,0 +1,261 @@ +From cf495636abdee738c59aa854cd16c172048bbf72 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 4 Aug 2021 10:17:15 +0200 +Subject: [PATCH 03/18] wayland/dma-buf: Prepare format/modifier map up front + +As the format table is setup up front, it doesn't change when this +experimental feature setting change. Make the settings documentation +reflect that. + +Part-of: +(cherry picked from commit 1978e93f285222e10ac6d5a25de5f90d061ec228) +--- + data/org.gnome.mutter.gschema.xml.in | 5 + + src/wayland/meta-wayland-dma-buf.c | 166 ++++++++++++++++----------- + 2 files changed, 106 insertions(+), 65 deletions(-) + +diff --git a/data/org.gnome.mutter.gschema.xml.in b/data/org.gnome.mutter.gschema.xml.in +index 23fa9f3ad3..4955f8d383 100644 +--- a/data/org.gnome.mutter.gschema.xml.in ++++ b/data/org.gnome.mutter.gschema.xml.in +@@ -121,6 +121,11 @@ + to manage HiDPI monitors. Does not + require a restart. + ++ • “kms-modifiers” — makes mutter always advertise valid ++ buffer modifiers on Wayland. This is ++ currently not the case when using the ++ i915 driver. Requires a restart. ++ + • “rt-scheduler” — makes mutter request a low priority + real-time scheduling. The executable + or user must have CAP_SYS_NICE. +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index 0803a942db..d9338ae474 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -66,9 +66,17 @@ + + #define META_WAYLAND_DMA_BUF_MAX_FDS 4 + ++typedef struct _MetaWaylandDmaBufFormat ++{ ++ uint32_t drm_format; ++ uint64_t drm_modifier; ++} MetaWaylandDmaBufFormat; ++ + struct _MetaWaylandDmaBufManager + { + MetaWaylandCompositor *compositor; ++ ++ GArray *formats; + }; + + struct _MetaWaylandDmaBufBuffer +@@ -633,97 +641,122 @@ should_send_modifiers (MetaBackend *backend) + } + + static void +-send_modifiers (struct wl_resource *resource, +- uint32_t format) ++send_modifiers (struct wl_resource *resource, ++ MetaWaylandDmaBufFormat *format) ++{ ++ zwp_linux_dmabuf_v1_send_format (resource, format->drm_format); ++ ++ if (wl_resource_get_version (resource) < ++ ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) ++ return; ++ ++ zwp_linux_dmabuf_v1_send_modifier (resource, ++ format->drm_format, ++ format->drm_modifier >> 32, ++ format->drm_modifier & 0xffffffff); ++} ++ ++static void ++dma_buf_bind (struct wl_client *client, ++ void *user_data, ++ uint32_t version, ++ uint32_t id) ++{ ++ MetaWaylandDmaBufManager *dma_buf_manager = user_data; ++ struct wl_resource *resource; ++ unsigned int i; ++ ++ resource = wl_resource_create (client, &zwp_linux_dmabuf_v1_interface, ++ version, id); ++ wl_resource_set_implementation (resource, &dma_buf_implementation, ++ dma_buf_manager, NULL); ++ ++ ++ for (i = 0; i < dma_buf_manager->formats->len; i++) ++ { ++ MetaWaylandDmaBufFormat *format = ++ &g_array_index (dma_buf_manager->formats, ++ MetaWaylandDmaBufFormat, ++ i); ++ ++ send_modifiers (resource, format); ++ } ++} ++ ++static void ++add_format (MetaWaylandDmaBufManager *dma_buf_manager, ++ EGLDisplay egl_display, ++ uint32_t drm_format) + { + MetaBackend *backend = meta_get_backend (); + MetaEgl *egl = meta_backend_get_egl (backend); +- ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); +- CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); +- EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); + EGLint num_modifiers; +- EGLuint64KHR *modifiers; +- GError *error = NULL; +- gboolean ret; ++ g_autofree EGLuint64KHR *modifiers = NULL; ++ g_autoptr (GError) error = NULL; + int i; +- +- zwp_linux_dmabuf_v1_send_format (resource, format); +- +- /* The modifier event was only added in v3; v1 and v2 only have the format +- * event. */ +- if (wl_resource_get_version (resource) < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) +- return; ++ MetaWaylandDmaBufFormat format; + + if (!should_send_modifiers (backend)) +- { +- zwp_linux_dmabuf_v1_send_modifier (resource, format, +- DRM_FORMAT_MOD_INVALID >> 32, +- DRM_FORMAT_MOD_INVALID & 0xffffffff); +- return; +- } ++ goto add_fallback; + + /* First query the number of available modifiers, then allocate an array, + * then fill the array. */ +- ret = meta_egl_query_dma_buf_modifiers (egl, egl_display, format, 0, NULL, +- NULL, &num_modifiers, NULL); +- if (!ret) +- return; ++ if (!meta_egl_query_dma_buf_modifiers (egl, egl_display, drm_format, 0, NULL, ++ NULL, &num_modifiers, NULL)) ++ goto add_fallback; + + if (num_modifiers == 0) +- { +- zwp_linux_dmabuf_v1_send_modifier (resource, format, +- DRM_FORMAT_MOD_INVALID >> 32, +- DRM_FORMAT_MOD_INVALID & 0xffffffff); +- return; +- } ++ goto add_fallback; + + modifiers = g_new0 (uint64_t, num_modifiers); +- ret = meta_egl_query_dma_buf_modifiers (egl, egl_display, format, +- num_modifiers, modifiers, NULL, +- &num_modifiers, &error); +- if (!ret) ++ if (!meta_egl_query_dma_buf_modifiers (egl, egl_display, drm_format, ++ num_modifiers, modifiers, NULL, ++ &num_modifiers, &error)) + { + g_warning ("Failed to query modifiers for format 0x%" PRIu32 ": %s", +- format, error ? error->message : "unknown error"); +- g_free (modifiers); +- return; ++ drm_format, error ? error->message : "unknown error"); ++ goto add_fallback; + } + + for (i = 0; i < num_modifiers; i++) + { +- zwp_linux_dmabuf_v1_send_modifier (resource, format, +- modifiers[i] >> 32, +- modifiers[i] & 0xffffffff); ++ format = (MetaWaylandDmaBufFormat) { ++ .drm_format = drm_format, ++ .drm_modifier = modifiers[i], ++ }; ++ g_array_append_val (dma_buf_manager->formats, format); + } + +- g_free (modifiers); ++ return; ++ ++add_fallback: ++ format = (MetaWaylandDmaBufFormat) { ++ .drm_format = drm_format, ++ .drm_modifier = DRM_FORMAT_MOD_INVALID, ++ }; ++ g_array_append_val (dma_buf_manager->formats, format); + } + + static void +-dma_buf_bind (struct wl_client *client, +- void *user_data, +- uint32_t version, +- uint32_t id) ++init_formats (MetaWaylandDmaBufManager *dma_buf_manager, ++ EGLDisplay egl_display) + { +- MetaWaylandDmaBufManager *dma_buf_manager = user_data; +- struct wl_resource *resource; +- +- resource = wl_resource_create (client, &zwp_linux_dmabuf_v1_interface, +- version, id); +- wl_resource_set_implementation (resource, &dma_buf_implementation, +- dma_buf_manager, NULL); +- send_modifiers (resource, DRM_FORMAT_ARGB8888); +- send_modifiers (resource, DRM_FORMAT_ABGR8888); +- send_modifiers (resource, DRM_FORMAT_XRGB8888); +- send_modifiers (resource, DRM_FORMAT_XBGR8888); +- send_modifiers (resource, DRM_FORMAT_ARGB2101010); +- send_modifiers (resource, DRM_FORMAT_ABGR2101010); +- send_modifiers (resource, DRM_FORMAT_XRGB2101010); +- send_modifiers (resource, DRM_FORMAT_RGB565); +- send_modifiers (resource, DRM_FORMAT_ABGR16161616F); +- send_modifiers (resource, DRM_FORMAT_XBGR16161616F); +- send_modifiers (resource, DRM_FORMAT_XRGB16161616F); +- send_modifiers (resource, DRM_FORMAT_ARGB16161616F); ++ dma_buf_manager->formats = g_array_new (FALSE, FALSE, ++ sizeof (MetaWaylandDmaBufFormat)); ++ ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_ARGB8888); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_ABGR8888); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_XRGB8888); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_XBGR8888); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_ARGB2101010); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_ABGR2101010); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_XRGB2101010); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_XBGR2101010); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_RGB565); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_ABGR16161616F); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_XBGR16161616F); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_XRGB16161616F); ++ add_format (dma_buf_manager, egl_display, DRM_FORMAT_ARGB16161616F); + } + + /** +@@ -772,12 +805,15 @@ meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, + + dma_buf_manager->compositor = compositor; + ++ init_formats (dma_buf_manager, egl_display); ++ + return g_steal_pointer (&dma_buf_manager); + } + + void + meta_wayland_dma_buf_manager_free (MetaWaylandDmaBufManager *dma_buf_manager) + { ++ g_clear_pointer (&dma_buf_manager->formats, g_array_unref); + g_free (dma_buf_manager); + } + +-- +2.51.1 + diff --git a/0004-wayland-dma-buf-Add-basic-support-for-DMA-buffer-fee.patch b/0004-wayland-dma-buf-Add-basic-support-for-DMA-buffer-fee.patch new file mode 100644 index 0000000..7303d7b --- /dev/null +++ b/0004-wayland-dma-buf-Add-basic-support-for-DMA-buffer-fee.patch @@ -0,0 +1,545 @@ +From ed3c27feeb3b745d04ec462e82d8ae58e041338e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Thu, 5 Aug 2021 15:10:47 +0200 +Subject: [PATCH 04/18] wayland/dma-buf: Add basic support for DMA buffer + feedback + +This includes sending the default tranche, but so far only sends the +same for every surface feedback requested. Scanout tranche will be added +later. + +Part-of: +(cherry picked from commit 7acecb1c7233dad0b9b314f59121882a518901d7) +--- + meson.build | 2 +- + src/wayland/meta-wayland-dma-buf.c | 368 +++++++++++++++++++++++++++- + src/wayland/meta-wayland-versions.h | 1 - + 3 files changed, 360 insertions(+), 11 deletions(-) + +diff --git a/meson.build b/meson.build +index f6f3872394..2dbee750c3 100644 +--- a/meson.build ++++ b/meson.build +@@ -41,7 +41,7 @@ gudev_req = '>= 232' + + # wayland version requirements + wayland_server_req = '>= 1.18' +-wayland_protocols_req = '>= 1.19' ++wayland_protocols_req = '>= 1.24' + + # native backend version requirements + libinput_req = '>= 1.15.0' +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index d9338ae474..7155d07dcf 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -40,6 +40,9 @@ + #include "wayland/meta-wayland-dma-buf.h" + + #include ++#include ++#include ++#include + + #include "backends/meta-backend-private.h" + #include "backends/meta-egl-ext.h" +@@ -66,17 +69,41 @@ + + #define META_WAYLAND_DMA_BUF_MAX_FDS 4 + ++/* Compatible with zwp_linux_dmabuf_feedback_v1.tranche_flags */ ++typedef enum _MetaWaylandDmaBufTrancheFlags ++{ ++ META_WAYLAND_DMA_BUF_TRANCHE_FLAG_NONE = 0, ++ META_WAYLAND_DMA_BUF_TRANCHE_FLAG_SCANOUT = 1, ++} MetaWaylandDmaBufTrancheFlags; ++ + typedef struct _MetaWaylandDmaBufFormat + { + uint32_t drm_format; + uint64_t drm_modifier; ++ uint16_t table_index; + } MetaWaylandDmaBufFormat; + ++typedef struct _MetaWaylandDmaBufTranche ++{ ++ dev_t target_device_id; ++ GArray *formats; ++ MetaWaylandDmaBufTrancheFlags flags; ++} MetaWaylandDmaBufTranche; ++ ++typedef struct _MetaWaylandDmaBufFeedback ++{ ++ dev_t main_device_id; ++ GList *tranches; ++} MetaWaylandDmaBufFeedback; ++ + struct _MetaWaylandDmaBufManager + { + MetaWaylandCompositor *compositor; ++ dev_t main_device_id; + + GArray *formats; ++ MetaAnonymousFile *format_table_file; ++ MetaWaylandDmaBufFeedback *default_feedback; + }; + + struct _MetaWaylandDmaBufBuffer +@@ -95,6 +122,118 @@ struct _MetaWaylandDmaBufBuffer + + G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJECT); + ++static MetaWaylandDmaBufTranche * ++meta_wayland_dma_buf_tranche_new (dev_t device_id, ++ GArray *formats, ++ MetaWaylandDmaBufTrancheFlags flags) ++{ ++ MetaWaylandDmaBufTranche *tranche; ++ ++ tranche = g_new0 (MetaWaylandDmaBufTranche, 1); ++ tranche->target_device_id = device_id; ++ tranche->formats = g_array_copy (formats); ++ tranche->flags = flags; ++ ++ return tranche; ++} ++ ++static void ++meta_wayland_dma_buf_tranche_free (MetaWaylandDmaBufTranche *tranche) ++{ ++ g_clear_pointer (&tranche->formats, g_array_unref); ++ g_free (tranche); ++} ++ ++static void ++meta_wayland_dma_buf_tranche_send (MetaWaylandDmaBufTranche *tranche, ++ struct wl_resource *resource) ++{ ++ struct wl_array target_device_buf; ++ dev_t *device_id_ptr; ++ struct wl_array formats_array; ++ unsigned int i; ++ ++ wl_array_init (&target_device_buf); ++ device_id_ptr = wl_array_add (&target_device_buf, sizeof (*device_id_ptr)); ++ *device_id_ptr = tranche->target_device_id; ++ zwp_linux_dmabuf_feedback_v1_send_tranche_target_device (resource, ++ &target_device_buf); ++ wl_array_release (&target_device_buf); ++ zwp_linux_dmabuf_feedback_v1_send_tranche_flags (resource, tranche->flags); ++ ++ wl_array_init (&formats_array); ++ for (i = 0; i < tranche->formats->len; i++) ++ { ++ MetaWaylandDmaBufFormat *format = ++ &g_array_index (tranche->formats, ++ MetaWaylandDmaBufFormat, ++ i); ++ uint16_t *format_index_ptr; ++ ++ format_index_ptr = wl_array_add (&formats_array, ++ sizeof (*format_index_ptr)); ++ *format_index_ptr = format->table_index; ++ } ++ zwp_linux_dmabuf_feedback_v1_send_tranche_formats (resource, &formats_array); ++ wl_array_release (&formats_array); ++ ++ zwp_linux_dmabuf_feedback_v1_send_tranche_done (resource); ++} ++ ++static void ++meta_wayland_dma_buf_feedback_send (MetaWaylandDmaBufFeedback *feedback, ++ MetaWaylandDmaBufManager *dma_buf_manager, ++ struct wl_resource *resource) ++{ ++ size_t size; ++ int fd; ++ struct wl_array main_device_buf; ++ dev_t *device_id_ptr; ++ ++ fd = meta_anonymous_file_open_fd (dma_buf_manager->format_table_file, ++ META_ANONYMOUS_FILE_MAPMODE_PRIVATE); ++ size = meta_anonymous_file_size (dma_buf_manager->format_table_file); ++ zwp_linux_dmabuf_feedback_v1_send_format_table (resource, fd, size); ++ meta_anonymous_file_close_fd (fd); ++ ++ wl_array_init (&main_device_buf); ++ device_id_ptr = wl_array_add (&main_device_buf, sizeof (*device_id_ptr)); ++ *device_id_ptr = feedback->main_device_id; ++ zwp_linux_dmabuf_feedback_v1_send_main_device (resource, &main_device_buf); ++ ++ g_list_foreach (feedback->tranches, ++ (GFunc) meta_wayland_dma_buf_tranche_send, ++ resource); ++ ++ zwp_linux_dmabuf_feedback_v1_send_done (resource); ++} ++ ++static void ++meta_wayland_dma_buf_feedback_add_tranche (MetaWaylandDmaBufFeedback *feedback, ++ MetaWaylandDmaBufTranche *tranche) ++{ ++ feedback->tranches = g_list_append (feedback->tranches, tranche); ++} ++ ++static MetaWaylandDmaBufFeedback * ++meta_wayland_dma_buf_feedback_new (dev_t device_id) ++{ ++ MetaWaylandDmaBufFeedback *feedback; ++ ++ feedback = g_new0 (MetaWaylandDmaBufFeedback, 1); ++ feedback->main_device_id = device_id; ++ ++ return feedback; ++} ++ ++static void ++meta_wayland_dma_buf_feedback_free (MetaWaylandDmaBufFeedback *feedback) ++{ ++ g_clear_list (&feedback->tranches, ++ (GDestroyNotify) meta_wayland_dma_buf_tranche_free); ++ g_free (feedback); ++} ++ + static gboolean + meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, + GError **error) +@@ -616,10 +755,80 @@ dma_buf_handle_create_buffer_params (struct wl_client *client, + buffer_params_destructor); + } + ++static void ++feedback_destroy (struct wl_client *client, ++ struct wl_resource *resource) ++{ ++ wl_resource_destroy (resource); ++} ++ ++static const struct zwp_linux_dmabuf_feedback_v1_interface feedback_implementation = ++{ ++ feedback_destroy, ++}; ++ ++static void ++feedback_destructor (struct wl_resource *resource) ++{ ++} ++ ++static void ++dma_buf_handle_get_default_feedback (struct wl_client *client, ++ struct wl_resource *dma_buf_resource, ++ uint32_t feedback_id) ++{ ++ MetaWaylandDmaBufManager *dma_buf_manager = ++ wl_resource_get_user_data (dma_buf_resource); ++ struct wl_resource *feedback_resource; ++ ++ feedback_resource = ++ wl_resource_create (client, ++ &zwp_linux_dmabuf_feedback_v1_interface, ++ wl_resource_get_version (dma_buf_resource), ++ feedback_id); ++ ++ wl_resource_set_implementation (feedback_resource, ++ &feedback_implementation, ++ NULL, ++ feedback_destructor); ++ ++ meta_wayland_dma_buf_feedback_send (dma_buf_manager->default_feedback, ++ dma_buf_manager, ++ feedback_resource); ++} ++ ++static void ++dma_buf_handle_get_surface_feedback (struct wl_client *client, ++ struct wl_resource *dma_buf_resource, ++ uint32_t feedback_id, ++ struct wl_resource *surface_resource) ++{ ++ MetaWaylandDmaBufManager *dma_buf_manager = ++ wl_resource_get_user_data (dma_buf_resource); ++ struct wl_resource *feedback_resource; ++ ++ feedback_resource = ++ wl_resource_create (client, ++ &zwp_linux_dmabuf_feedback_v1_interface, ++ wl_resource_get_version (dma_buf_resource), ++ feedback_id); ++ ++ wl_resource_set_implementation (feedback_resource, ++ &feedback_implementation, ++ NULL, ++ feedback_destructor); ++ ++ meta_wayland_dma_buf_feedback_send (dma_buf_manager->default_feedback, ++ dma_buf_manager, ++ feedback_resource); ++} ++ + static const struct zwp_linux_dmabuf_v1_interface dma_buf_implementation = + { + dma_buf_handle_destroy, + dma_buf_handle_create_buffer_params, ++ dma_buf_handle_get_default_feedback, ++ dma_buf_handle_get_surface_feedback, + }; + + static gboolean +@@ -644,6 +853,9 @@ static void + send_modifiers (struct wl_resource *resource, + MetaWaylandDmaBufFormat *format) + { ++ g_assert (wl_resource_get_version (resource) < ++ ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION); ++ + zwp_linux_dmabuf_v1_send_format (resource, format->drm_format); + + if (wl_resource_get_version (resource) < +@@ -664,22 +876,25 @@ dma_buf_bind (struct wl_client *client, + { + MetaWaylandDmaBufManager *dma_buf_manager = user_data; + struct wl_resource *resource; +- unsigned int i; + + resource = wl_resource_create (client, &zwp_linux_dmabuf_v1_interface, + version, id); + wl_resource_set_implementation (resource, &dma_buf_implementation, + dma_buf_manager, NULL); + +- +- for (i = 0; i < dma_buf_manager->formats->len; i++) ++ if (version < ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) + { +- MetaWaylandDmaBufFormat *format = +- &g_array_index (dma_buf_manager->formats, +- MetaWaylandDmaBufFormat, +- i); ++ unsigned int i; ++ ++ for (i = 0; i < dma_buf_manager->formats->len; i++) ++ { ++ MetaWaylandDmaBufFormat *format = ++ &g_array_index (dma_buf_manager->formats, ++ MetaWaylandDmaBufFormat, ++ i); + +- send_modifiers (resource, format); ++ send_modifiers (resource, format); ++ } + } + } + +@@ -723,6 +938,7 @@ add_format (MetaWaylandDmaBufManager *dma_buf_manager, + format = (MetaWaylandDmaBufFormat) { + .drm_format = drm_format, + .drm_modifier = modifiers[i], ++ .table_index = dma_buf_manager->formats->len, + }; + g_array_append_val (dma_buf_manager->formats, format); + } +@@ -733,10 +949,53 @@ add_fallback: + format = (MetaWaylandDmaBufFormat) { + .drm_format = drm_format, + .drm_modifier = DRM_FORMAT_MOD_INVALID, ++ .table_index = dma_buf_manager->formats->len, + }; + g_array_append_val (dma_buf_manager->formats, format); + } + ++/* ++ * This is the structure the data is expected to have in the shared memory file ++ * shared with clients, according to the Wayland Linux DMA buffer protocol. ++ * It's structured as 16 bytes (128 bits) per entry, where each entry consists ++ * of the following: ++ * ++ * [ 32 bit format ][ 32 bit padding ][ 64 bit modifier ] ++ */ ++typedef struct _MetaMetaWaylanDmaBdufFormatEntry ++{ ++ uint32_t drm_format; ++ uint32_t unused_padding; ++ uint64_t drm_modifier; ++} MetaWaylandDmaBufFormatEntry; ++ ++G_STATIC_ASSERT (sizeof (MetaWaylandDmaBufFormatEntry) == 16); ++G_STATIC_ASSERT (offsetof (MetaWaylandDmaBufFormatEntry, drm_format) == 0); ++G_STATIC_ASSERT (offsetof (MetaWaylandDmaBufFormatEntry, drm_modifier) == 8); ++ ++static void ++init_format_table (MetaWaylandDmaBufManager *dma_buf_manager) ++{ ++ g_autofree MetaWaylandDmaBufFormatEntry *format_table = NULL; ++ size_t size; ++ int i; ++ ++ size = sizeof (MetaWaylandDmaBufFormatEntry) * dma_buf_manager->formats->len; ++ format_table = g_malloc0 (size); ++ ++ for (i = 0; i < dma_buf_manager->formats->len; i++) ++ { ++ MetaWaylandDmaBufFormat *format = ++ &g_array_index (dma_buf_manager->formats, MetaWaylandDmaBufFormat, i); ++ ++ format_table[i].drm_format = format->drm_format; ++ format_table[i].drm_modifier = format->drm_modifier; ++ } ++ ++ dma_buf_manager->format_table_file = ++ meta_anonymous_file_new (size, (uint8_t *) format_table); ++} ++ + static void + init_formats (MetaWaylandDmaBufManager *dma_buf_manager, + EGLDisplay egl_display) +@@ -757,6 +1016,25 @@ init_formats (MetaWaylandDmaBufManager *dma_buf_manager, + add_format (dma_buf_manager, egl_display, DRM_FORMAT_XBGR16161616F); + add_format (dma_buf_manager, egl_display, DRM_FORMAT_XRGB16161616F); + add_format (dma_buf_manager, egl_display, DRM_FORMAT_ARGB16161616F); ++ ++ init_format_table (dma_buf_manager); ++} ++ ++static void ++init_default_feedback (MetaWaylandDmaBufManager *dma_buf_manager) ++{ ++ MetaWaylandDmaBufTrancheFlags flags; ++ MetaWaylandDmaBufTranche *tranche; ++ ++ dma_buf_manager->default_feedback = ++ meta_wayland_dma_buf_feedback_new (dma_buf_manager->main_device_id); ++ ++ flags = META_WAYLAND_DMA_BUF_TRANCHE_FLAG_NONE; ++ tranche = meta_wayland_dma_buf_tranche_new (dma_buf_manager->main_device_id, ++ dma_buf_manager->formats, ++ flags); ++ meta_wayland_dma_buf_feedback_add_tranche (dma_buf_manager->default_feedback, ++ tranche); + } + + /** +@@ -776,8 +1054,14 @@ meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); + EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); ++ dev_t device_id = 0; ++ int protocol_version; ++ EGLDeviceEXT egl_device; ++ EGLAttrib attrib; + g_autoptr (GError) local_error = NULL; + g_autofree MetaWaylandDmaBufManager *dma_buf_manager = NULL; ++ const char *device_path = NULL; ++ struct stat device_stat; + + g_assert (backend && egl && clutter_backend && cogl_context && egl_display); + +@@ -790,11 +1074,71 @@ meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, + return NULL; + } + ++ if (!meta_egl_query_display_attrib (egl, egl_display, ++ EGL_DEVICE_EXT, &attrib, ++ &local_error)) ++ { ++ g_warning ("Failed to query EGL device from primary EGL display: %s", ++ local_error->message); ++ protocol_version = 3; ++ goto initialize; ++ } ++ egl_device = (EGLDeviceEXT) attrib; ++ ++ if (meta_egl_egl_device_has_extensions (egl, egl_device, NULL, ++ "EGL_EXT_device_drm_render_node", ++ NULL)) ++ { ++ device_path = meta_egl_query_device_string (egl, egl_device, ++ EGL_DRM_RENDER_NODE_FILE_EXT, ++ &local_error); ++ } ++ else if (meta_egl_egl_device_has_extensions (egl, egl_device, NULL, ++ "EGL_EXT_device_drm", ++ NULL)) ++ { ++ device_path = meta_egl_query_device_string (egl, egl_device, ++ EGL_DRM_DEVICE_FILE_EXT, ++ &local_error); ++ } ++ else ++ { ++ meta_topic (META_DEBUG_WAYLAND, ++ "Only advertising zwp_linux_dmabuf_v1 interface version 3 " ++ "support, missing 'EGL_EXT_device_drm' and " ++ "'EGL_EXT_device_drm_render_node'"); ++ protocol_version = 3; ++ goto initialize; ++ } ++ ++ if (!device_path) ++ { ++ g_warning ("Failed to query EGL device path: %s", ++ local_error->message); ++ protocol_version = 3; ++ goto initialize; ++ } ++ ++ if (stat (device_path, &device_stat) != 0) ++ { ++ g_warning ("Failed to fetch device file ID for '%s': %s", ++ device_path, ++ g_strerror (errno)); ++ protocol_version = 3; ++ goto initialize; ++ } ++ ++ device_id = device_stat.st_rdev; ++ ++ protocol_version = 4; ++ ++initialize: ++ + dma_buf_manager = g_new0 (MetaWaylandDmaBufManager, 1); + + if (!wl_global_create (compositor->wayland_display, + &zwp_linux_dmabuf_v1_interface, +- META_ZWP_LINUX_DMABUF_V1_VERSION, ++ protocol_version, + dma_buf_manager, + dma_buf_bind)) + { +@@ -804,8 +1148,10 @@ meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, + } + + dma_buf_manager->compositor = compositor; ++ dma_buf_manager->main_device_id = device_id; + + init_formats (dma_buf_manager, egl_display); ++ init_default_feedback (dma_buf_manager); + + return g_steal_pointer (&dma_buf_manager); + } +@@ -813,7 +1159,11 @@ meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, + void + meta_wayland_dma_buf_manager_free (MetaWaylandDmaBufManager *dma_buf_manager) + { ++ g_clear_pointer (&dma_buf_manager->format_table_file, ++ meta_anonymous_file_free); + g_clear_pointer (&dma_buf_manager->formats, g_array_unref); ++ g_clear_pointer (&dma_buf_manager->default_feedback, ++ meta_wayland_dma_buf_feedback_free); + g_free (dma_buf_manager); + } + +diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h +index 8f71c19dce..78e4e6127a 100644 +--- a/src/wayland/meta-wayland-versions.h ++++ b/src/wayland/meta-wayland-versions.h +@@ -48,7 +48,6 @@ + #define META_ZWP_POINTER_GESTURES_V1_VERSION 1 + #define META_ZXDG_EXPORTER_V1_VERSION 1 + #define META_ZXDG_IMPORTER_V1_VERSION 1 +-#define META_ZWP_LINUX_DMABUF_V1_VERSION 3 + #define META_ZWP_KEYBOARD_SHORTCUTS_INHIBIT_V1_VERSION 1 + #define META_ZXDG_OUTPUT_V1_VERSION 3 + #define META_ZWP_XWAYLAND_KEYBOARD_GRAB_V1_VERSION 1 +-- +2.51.1 + diff --git a/0005-wayland-dma-buf-Always-advertise-non-modifier-fallba.patch b/0005-wayland-dma-buf-Always-advertise-non-modifier-fallba.patch new file mode 100644 index 0000000..bb32492 --- /dev/null +++ b/0005-wayland-dma-buf-Always-advertise-non-modifier-fallba.patch @@ -0,0 +1,72 @@ +From e4d494916c1045dd24ae44a82c8e398feed2179d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 7 Dec 2021 22:12:57 +0100 +Subject: [PATCH 05/18] wayland/dma-buf: Always advertise non-modifier fallback + +This is done to explicitly tell clients that the compositor supports +implicit modifier paths (i.e. using modifier unaware API). + +Part-of: +(cherry picked from commit 2a16a750c556a916a6792adf10adbe4499d5e092) +--- + src/wayland/meta-wayland-dma-buf.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index 7155d07dcf..ca9be5d601 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -851,12 +851,18 @@ should_send_modifiers (MetaBackend *backend) + + static void + send_modifiers (struct wl_resource *resource, +- MetaWaylandDmaBufFormat *format) ++ MetaWaylandDmaBufFormat *format, ++ GHashTable *sent_formats) + { + g_assert (wl_resource_get_version (resource) < + ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION); + +- zwp_linux_dmabuf_v1_send_format (resource, format->drm_format); ++ if (!g_hash_table_contains (sent_formats, ++ GUINT_TO_POINTER (format->drm_format))) ++ { ++ g_hash_table_add (sent_formats, GUINT_TO_POINTER (format->drm_format)); ++ zwp_linux_dmabuf_v1_send_format (resource, format->drm_format); ++ } + + if (wl_resource_get_version (resource) < + ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) +@@ -884,8 +890,11 @@ dma_buf_bind (struct wl_client *client, + + if (version < ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION) + { ++ g_autoptr (GHashTable) sent_formats = NULL; + unsigned int i; + ++ sent_formats = g_hash_table_new (NULL, NULL); ++ + for (i = 0; i < dma_buf_manager->formats->len; i++) + { + MetaWaylandDmaBufFormat *format = +@@ -893,7 +902,7 @@ dma_buf_bind (struct wl_client *client, + MetaWaylandDmaBufFormat, + i); + +- send_modifiers (resource, format); ++ send_modifiers (resource, format, sent_formats); + } + } + } +@@ -943,8 +952,6 @@ add_format (MetaWaylandDmaBufManager *dma_buf_manager, + g_array_append_val (dma_buf_manager->formats, format); + } + +- return; +- + add_fallback: + format = (MetaWaylandDmaBufFormat) { + .drm_format = drm_format, +-- +2.51.1 + diff --git a/0006-wayland-surface-Remove-unnecessary-NULL-check.patch b/0006-wayland-surface-Remove-unnecessary-NULL-check.patch new file mode 100644 index 0000000..88bf6ce --- /dev/null +++ b/0006-wayland-surface-Remove-unnecessary-NULL-check.patch @@ -0,0 +1,98 @@ +From 15168d00affa1e05fd1307abef196b6e395a14bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Thu, 5 Aug 2021 16:03:26 +0200 +Subject: [PATCH 06/18] wayland/surface: Remove unnecessary NULL check + +This check has caused repeated confusion, as there are no current code +paths where this can ever end up in the true-branch. + +Part-of: +(cherry picked from commit 90076cf268bde6c18e49908514d7dc7af4b3a92e) +--- + src/wayland/meta-wayland-surface.c | 28 ---------------------------- + 1 file changed, 28 deletions(-) + +diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c +index 6e6457b249..e033b7b911 100644 +--- a/src/wayland/meta-wayland-surface.c ++++ b/src/wayland/meta-wayland-surface.c +@@ -1027,10 +1027,6 @@ wl_surface_attach (struct wl_client *client, + MetaWaylandSurfaceState *pending = surface->pending_state; + MetaWaylandBuffer *buffer; + +- /* X11 unmanaged window */ +- if (!surface) +- return; +- + if (buffer_resource) + buffer = meta_wayland_buffer_from_resource (buffer_resource); + else +@@ -1068,10 +1064,6 @@ wl_surface_damage (struct wl_client *client, + MetaWaylandSurfaceState *pending = surface->pending_state; + cairo_rectangle_int_t rectangle; + +- /* X11 unmanaged window */ +- if (!surface) +- return; +- + rectangle = (cairo_rectangle_int_t) { + .x = x, + .y = y, +@@ -1100,10 +1092,6 @@ wl_surface_frame (struct wl_client *client, + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSurfaceState *pending = surface->pending_state; + +- /* X11 unmanaged window */ +- if (!surface) +- return; +- + callback = g_new0 (MetaWaylandFrameCallback, 1); + callback->surface = surface; + callback->resource = wl_resource_create (client, +@@ -1124,10 +1112,6 @@ wl_surface_set_opaque_region (struct wl_client *client, + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSurfaceState *pending = surface->pending_state; + +- /* X11 unmanaged window */ +- if (!surface) +- return; +- + g_clear_pointer (&pending->opaque_region, cairo_region_destroy); + if (region_resource) + { +@@ -1146,10 +1130,6 @@ wl_surface_set_input_region (struct wl_client *client, + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandSurfaceState *pending = surface->pending_state; + +- /* X11 unmanaged window */ +- if (!surface) +- return; +- + g_clear_pointer (&pending->input_region, cairo_region_destroy); + if (region_resource) + { +@@ -1166,10 +1146,6 @@ wl_surface_commit (struct wl_client *client, + { + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + +- /* X11 unmanaged window */ +- if (!surface) +- return; +- + meta_wayland_surface_commit (surface); + } + +@@ -1257,10 +1233,6 @@ wl_surface_damage_buffer (struct wl_client *client, + MetaWaylandSurfaceState *pending = surface->pending_state; + cairo_rectangle_int_t rectangle; + +- /* X11 unmanaged window */ +- if (!surface) +- return; +- + rectangle = (cairo_rectangle_int_t) { + .x = x, + .y = y, +-- +2.51.1 + diff --git a/0007-wayland-dma-buf-Make-manager-object-a-GObject.patch b/0007-wayland-dma-buf-Make-manager-object-a-GObject.patch new file mode 100644 index 0000000..964ab8b --- /dev/null +++ b/0007-wayland-dma-buf-Make-manager-object-a-GObject.patch @@ -0,0 +1,145 @@ +From ba03e83acc2157fa96bb06784ca43d0da7e942ab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Fri, 6 Aug 2021 15:23:15 +0200 +Subject: [PATCH 07/18] wayland/dma-buf: Make manager object a GObject + +Will make certain operations easier, i.e. setting up a GQuark. + +Part-of: +(cherry picked from commit 9c942a43d6c49a728ab472d08640cef929cc94b0) +--- + src/wayland/meta-wayland-dma-buf.c | 48 ++++++++++++++++++++++-------- + src/wayland/meta-wayland-dma-buf.h | 6 ++-- + src/wayland/meta-wayland.c | 3 +- + 3 files changed, 40 insertions(+), 17 deletions(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index ca9be5d601..6b798ec2dd 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -98,6 +98,8 @@ typedef struct _MetaWaylandDmaBufFeedback + + struct _MetaWaylandDmaBufManager + { ++ GObject parent; ++ + MetaWaylandCompositor *compositor; + dev_t main_device_id; + +@@ -122,6 +124,9 @@ struct _MetaWaylandDmaBufBuffer + + G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJECT); + ++G_DEFINE_TYPE (MetaWaylandDmaBufManager, meta_wayland_dma_buf_manager, ++ G_TYPE_OBJECT) ++ + static MetaWaylandDmaBufTranche * + meta_wayland_dma_buf_tranche_new (dev_t device_id, + GArray *formats, +@@ -1066,7 +1071,7 @@ meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, + EGLDeviceEXT egl_device; + EGLAttrib attrib; + g_autoptr (GError) local_error = NULL; +- g_autofree MetaWaylandDmaBufManager *dma_buf_manager = NULL; ++ g_autoptr (MetaWaylandDmaBufManager) dma_buf_manager = NULL; + const char *device_path = NULL; + struct stat device_stat; + +@@ -1141,7 +1146,7 @@ meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, + + initialize: + +- dma_buf_manager = g_new0 (MetaWaylandDmaBufManager, 1); ++ dma_buf_manager = g_object_new (META_TYPE_WAYLAND_DMA_BUF_MANAGER, NULL); + + if (!wl_global_create (compositor->wayland_display, + &zwp_linux_dmabuf_v1_interface, +@@ -1163,17 +1168,6 @@ initialize: + return g_steal_pointer (&dma_buf_manager); + } + +-void +-meta_wayland_dma_buf_manager_free (MetaWaylandDmaBufManager *dma_buf_manager) +-{ +- g_clear_pointer (&dma_buf_manager->format_table_file, +- meta_anonymous_file_free); +- g_clear_pointer (&dma_buf_manager->formats, g_array_unref); +- g_clear_pointer (&dma_buf_manager->default_feedback, +- meta_wayland_dma_buf_feedback_free); +- g_free (dma_buf_manager); +-} +- + static void + meta_wayland_dma_buf_buffer_finalize (GObject *object) + { +@@ -1207,3 +1201,31 @@ meta_wayland_dma_buf_buffer_class_init (MetaWaylandDmaBufBufferClass *klass) + + object_class->finalize = meta_wayland_dma_buf_buffer_finalize; + } ++ ++static void ++meta_wayland_dma_buf_manager_finalize (GObject *object) ++{ ++ MetaWaylandDmaBufManager *dma_buf_manager = ++ META_WAYLAND_DMA_BUF_MANAGER (object); ++ ++ g_clear_pointer (&dma_buf_manager->format_table_file, ++ meta_anonymous_file_free); ++ g_clear_pointer (&dma_buf_manager->formats, g_array_unref); ++ g_clear_pointer (&dma_buf_manager->default_feedback, ++ meta_wayland_dma_buf_feedback_free); ++ ++ G_OBJECT_CLASS (meta_wayland_dma_buf_manager_parent_class)->finalize (object); ++} ++ ++static void ++meta_wayland_dma_buf_manager_class_init (MetaWaylandDmaBufManagerClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ ++ object_class->finalize = meta_wayland_dma_buf_manager_finalize; ++} ++ ++static void ++meta_wayland_dma_buf_manager_init (MetaWaylandDmaBufManager *dma_buf) ++{ ++} +diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h +index 72fd0b16a0..dc1231560b 100644 +--- a/src/wayland/meta-wayland-dma-buf.h ++++ b/src/wayland/meta-wayland-dma-buf.h +@@ -37,13 +37,15 @@ + G_DECLARE_FINAL_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, + META, WAYLAND_DMA_BUF_BUFFER, GObject); + ++#define META_TYPE_WAYLAND_DMA_BUF_MANAGER (meta_wayland_dma_buf_manager_get_type ()) ++G_DECLARE_FINAL_TYPE (MetaWaylandDmaBufManager, meta_wayland_dma_buf_manager, ++ META, WAYLAND_DMA_BUF_MANAGER, GObject) ++ + typedef struct _MetaWaylandDmaBufBuffer MetaWaylandDmaBufBuffer; + + MetaWaylandDmaBufManager * meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, + GError **error); + +-void meta_wayland_dma_buf_manager_free (MetaWaylandDmaBufManager *dma_buf_manager); +- + gboolean + meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, + CoglTexture **texture, +diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c +index a566a35449..28af6ae196 100644 +--- a/src/wayland/meta-wayland.c ++++ b/src/wayland/meta-wayland.c +@@ -618,8 +618,7 @@ meta_wayland_finalize (void) + if (compositor->wayland_display) + wl_display_destroy_clients (compositor->wayland_display); + +- g_clear_pointer (&compositor->dma_buf_manager, +- meta_wayland_dma_buf_manager_free); ++ g_clear_object (&compositor->dma_buf_manager); + + g_clear_pointer (&compositor->seat, meta_wayland_seat_free); + +-- +2.51.1 + diff --git a/0008-wayland-dma-buf-Add-tranche-priorities.patch b/0008-wayland-dma-buf-Add-tranche-priorities.patch new file mode 100644 index 0000000..ebe93a9 --- /dev/null +++ b/0008-wayland-dma-buf-Add-tranche-priorities.patch @@ -0,0 +1,108 @@ +From c5f6a8435d526438c722f6b13869d177bcc31855 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Fri, 6 Aug 2021 16:20:14 +0200 +Subject: [PATCH 08/18] wayland/dma-buf: Add tranche priorities + +Unused for now, but will be added to prioritize scanout tranches higher +than render only ones. + +Part-of: +(cherry picked from commit 9a47766a9627e75fffb7c5a20c0e3d63aae38539) +--- + src/wayland/meta-wayland-dma-buf.c | 36 ++++++++++++++++++++++++++---- + 1 file changed, 32 insertions(+), 4 deletions(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index 6b798ec2dd..a255158993 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -76,6 +76,12 @@ typedef enum _MetaWaylandDmaBufTrancheFlags + META_WAYLAND_DMA_BUF_TRANCHE_FLAG_SCANOUT = 1, + } MetaWaylandDmaBufTrancheFlags; + ++typedef enum _MetaWaylandDmaBufTranchePriority ++{ ++ META_WAYLAND_DMA_BUF_TRANCHE_PRIORITY_HIGH = 0, ++ META_WAYLAND_DMA_BUF_TRANCHE_PRIORITY_DEFAULT = 10, ++} MetaWaylandDmaBufTranchePriority; ++ + typedef struct _MetaWaylandDmaBufFormat + { + uint32_t drm_format; +@@ -85,6 +91,7 @@ typedef struct _MetaWaylandDmaBufFormat + + typedef struct _MetaWaylandDmaBufTranche + { ++ MetaWaylandDmaBufTranchePriority priority; + dev_t target_device_id; + GArray *formats; + MetaWaylandDmaBufTrancheFlags flags; +@@ -127,16 +134,33 @@ G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJE + G_DEFINE_TYPE (MetaWaylandDmaBufManager, meta_wayland_dma_buf_manager, + G_TYPE_OBJECT) + ++static gint ++compare_tranches (gconstpointer a, ++ gconstpointer b) ++{ ++ const MetaWaylandDmaBufTranche *tranche_a = a; ++ const MetaWaylandDmaBufTranche *tranche_b = b; ++ ++ if (tranche_a->priority > tranche_b->priority) ++ return 1; ++ if (tranche_a->priority < tranche_b->priority) ++ return -1; ++ else ++ return 0; ++} ++ + static MetaWaylandDmaBufTranche * +-meta_wayland_dma_buf_tranche_new (dev_t device_id, +- GArray *formats, +- MetaWaylandDmaBufTrancheFlags flags) ++meta_wayland_dma_buf_tranche_new (dev_t device_id, ++ GArray *formats, ++ MetaWaylandDmaBufTranchePriority priority, ++ MetaWaylandDmaBufTrancheFlags flags) + { + MetaWaylandDmaBufTranche *tranche; + + tranche = g_new0 (MetaWaylandDmaBufTranche, 1); + tranche->target_device_id = device_id; + tranche->formats = g_array_copy (formats); ++ tranche->priority = priority; + tranche->flags = flags; + + return tranche; +@@ -217,7 +241,8 @@ static void + meta_wayland_dma_buf_feedback_add_tranche (MetaWaylandDmaBufFeedback *feedback, + MetaWaylandDmaBufTranche *tranche) + { +- feedback->tranches = g_list_append (feedback->tranches, tranche); ++ feedback->tranches = g_list_insert_sorted (feedback->tranches, tranche, ++ compare_tranches); + } + + static MetaWaylandDmaBufFeedback * +@@ -1035,15 +1060,18 @@ init_formats (MetaWaylandDmaBufManager *dma_buf_manager, + static void + init_default_feedback (MetaWaylandDmaBufManager *dma_buf_manager) + { ++ MetaWaylandDmaBufTranchePriority priority; + MetaWaylandDmaBufTrancheFlags flags; + MetaWaylandDmaBufTranche *tranche; + + dma_buf_manager->default_feedback = + meta_wayland_dma_buf_feedback_new (dma_buf_manager->main_device_id); + ++ priority = META_WAYLAND_DMA_BUF_TRANCHE_PRIORITY_DEFAULT; + flags = META_WAYLAND_DMA_BUF_TRANCHE_FLAG_NONE; + tranche = meta_wayland_dma_buf_tranche_new (dma_buf_manager->main_device_id, + dma_buf_manager->formats, ++ priority, + flags); + meta_wayland_dma_buf_feedback_add_tranche (dma_buf_manager->default_feedback, + tranche); +-- +2.51.1 + diff --git a/0009-compositor-native-Track-what-Wayland-surface-is-a-sc.patch b/0009-compositor-native-Track-what-Wayland-surface-is-a-sc.patch new file mode 100644 index 0000000..f0590cd --- /dev/null +++ b/0009-compositor-native-Track-what-Wayland-surface-is-a-sc.patch @@ -0,0 +1,302 @@ +From f928306ebbec7bcbdb80a456b07e7db0219da36c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Fri, 6 Aug 2021 17:00:19 +0200 +Subject: [PATCH 09/18] compositor/native: Track what Wayland surface is a + scanout candidate + +For the current candidate, set the candidate CRTC on that surface. This +will later be used to send DMA buffer feedback for direct scanout purposes. + +Part-of: +(cherry picked from commit 43161c66602febd5bf635f8dea927da1b282c757) +--- + src/compositor/meta-compositor-native.c | 69 +++++++++++++++++---- + src/compositor/meta-surface-actor-wayland.c | 3 +- + src/wayland/meta-wayland-surface.c | 60 ++++++++++++++++++ + src/wayland/meta-wayland-surface.h | 8 +++ + 4 files changed, 127 insertions(+), 13 deletions(-) + +diff --git a/src/compositor/meta-compositor-native.c b/src/compositor/meta-compositor-native.c +index 00f66b70d4..7822789a3e 100644 +--- a/src/compositor/meta-compositor-native.c ++++ b/src/compositor/meta-compositor-native.c +@@ -23,11 +23,14 @@ + #include "compositor/meta-compositor-native.h" + + #include "backends/meta-logical-monitor.h" ++#include "backends/native/meta-crtc-kms.h" + #include "compositor/meta-surface-actor-wayland.h" + + struct _MetaCompositorNative + { + MetaCompositorServer parent; ++ ++ MetaWaylandSurface *current_scanout_candidate; + }; + + G_DEFINE_TYPE (MetaCompositorNative, meta_compositor_native, +@@ -62,57 +65,88 @@ get_window_view (MetaRenderer *renderer, + static void + maybe_assign_primary_plane (MetaCompositor *compositor) + { ++ MetaCompositorNative *compositor_native = META_COMPOSITOR_NATIVE (compositor); + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaWindowActor *window_actor; + MetaWindow *window; + MetaRendererView *view; ++ MetaCrtc *crtc; + CoglFramebuffer *framebuffer; + CoglOnscreen *onscreen; + MetaSurfaceActor *surface_actor; + MetaSurfaceActorWayland *surface_actor_wayland; ++ MetaWaylandSurface *surface; ++ MetaWaylandSurface *old_candidate = ++ compositor_native->current_scanout_candidate; ++ MetaWaylandSurface *new_candidate = NULL; + g_autoptr (CoglScanout) scanout = NULL; + + if (meta_compositor_is_unredirect_inhibited (compositor)) +- return; ++ goto done; + + window_actor = meta_compositor_get_top_window_actor (compositor); + if (!window_actor) +- return; ++ goto done; + + if (meta_window_actor_effect_in_progress (window_actor)) +- return; ++ goto done; + + if (clutter_actor_has_transitions (CLUTTER_ACTOR (window_actor))) +- return; ++ goto done; + + if (clutter_actor_get_n_children (CLUTTER_ACTOR (window_actor)) != 1) +- return; ++ goto done; + + window = meta_window_actor_get_meta_window (window_actor); + if (!window) +- return; ++ goto done; + + view = get_window_view (renderer, window); + if (!view) +- return; ++ goto done; ++ ++ crtc = meta_renderer_view_get_crtc (META_RENDERER_VIEW (view)); ++ if (!META_IS_CRTC_KMS (crtc)) ++ goto done; + + framebuffer = clutter_stage_view_get_framebuffer (CLUTTER_STAGE_VIEW (view)); + if (!COGL_IS_ONSCREEN (framebuffer)) +- return; ++ goto done; + + surface_actor = meta_window_actor_get_surface (window_actor); + if (!META_IS_SURFACE_ACTOR_WAYLAND (surface_actor)) +- return; +- ++ goto done; + surface_actor_wayland = META_SURFACE_ACTOR_WAYLAND (surface_actor); ++ ++ surface = meta_surface_actor_wayland_get_surface (surface_actor_wayland); ++ if (!surface) ++ goto done; ++ ++ new_candidate = surface; ++ + onscreen = COGL_ONSCREEN (framebuffer); + scanout = meta_surface_actor_wayland_try_acquire_scanout (surface_actor_wayland, + onscreen); + if (!scanout) +- return; ++ goto done; + + clutter_stage_view_assign_next_scanout (CLUTTER_STAGE_VIEW (view), scanout); ++ ++done: ++ ++ if (old_candidate && old_candidate != new_candidate) ++ { ++ meta_wayland_surface_set_scanout_candidate (old_candidate, NULL); ++ g_clear_weak_pointer (&compositor_native->current_scanout_candidate); ++ } ++ ++ if (new_candidate) ++ { ++ meta_wayland_surface_set_scanout_candidate (surface, crtc); ++ g_set_weak_pointer (&compositor_native->current_scanout_candidate, ++ surface); ++ } + } + + static void +@@ -137,6 +171,16 @@ meta_compositor_native_new (MetaDisplay *display, + NULL); + } + ++static void ++meta_compositor_native_finalize (GObject *object) ++{ ++ MetaCompositorNative *compositor_native = META_COMPOSITOR_NATIVE (object); ++ ++ g_clear_weak_pointer (&compositor_native->current_scanout_candidate); ++ ++ G_OBJECT_CLASS (meta_compositor_native_parent_class)->finalize (object); ++} ++ + static void + meta_compositor_native_init (MetaCompositorNative *compositor_native) + { +@@ -145,7 +189,10 @@ meta_compositor_native_init (MetaCompositorNative *compositor_native) + static void + meta_compositor_native_class_init (MetaCompositorNativeClass *klass) + { ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaCompositorClass *compositor_class = META_COMPOSITOR_CLASS (klass); + ++ object_class->finalize = meta_compositor_native_finalize; ++ + compositor_class->before_paint = meta_compositor_native_before_paint; + } +diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c +index 8c2a93da1e..4e131b0ba6 100644 +--- a/src/compositor/meta-surface-actor-wayland.c ++++ b/src/compositor/meta-surface-actor-wayland.c +@@ -80,8 +80,7 @@ meta_surface_actor_wayland_try_acquire_scanout (MetaSurfaceActorWayland *self, + return NULL; + + surface = meta_surface_actor_wayland_get_surface (self); +- if (!surface) +- return NULL; ++ g_return_val_if_fail (surface, NULL); + + scanout = meta_wayland_surface_try_acquire_scanout (surface, onscreen); + if (!scanout) +diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c +index e033b7b911..c69433352e 100644 +--- a/src/wayland/meta-wayland-surface.c ++++ b/src/wayland/meta-wayland-surface.c +@@ -79,6 +79,17 @@ typedef struct _MetaWaylandSurfaceRolePrivate + MetaWaylandSurface *surface; + } MetaWaylandSurfaceRolePrivate; + ++enum ++{ ++ PROP_0, ++ ++ PROP_SCANOUT_CANDIDATE, ++ ++ N_PROPS ++}; ++ ++static GParamSpec *obj_props[N_PROPS]; ++ + G_DEFINE_TYPE (MetaWaylandSurface, meta_wayland_surface, G_TYPE_OBJECT); + + G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRole, +@@ -1413,6 +1424,7 @@ wl_surface_destructor (struct wl_resource *resource) + + g_signal_emit (surface, surface_signals[SURFACE_DESTROY], 0); + ++ g_clear_object (&surface->scanout_candidate); + g_clear_object (&surface->role); + + if (surface->unassigned.buffer) +@@ -1697,11 +1709,41 @@ meta_wayland_surface_init (MetaWaylandSurface *surface) + g_node_prepend_data (surface->subsurface_branch_node, surface); + } + ++static void ++meta_wayland_surface_get_property (GObject *object, ++ guint prop_id, ++ GValue *value, ++ GParamSpec *pspec) ++{ ++ MetaWaylandSurface *surface = META_WAYLAND_SURFACE (object); ++ ++ switch (prop_id) ++ { ++ case PROP_SCANOUT_CANDIDATE: ++ g_value_set_object (value, surface->scanout_candidate); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ + static void + meta_wayland_surface_class_init (MetaWaylandSurfaceClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ++ object_class->get_property = meta_wayland_surface_get_property; ++ ++ obj_props[PROP_SCANOUT_CANDIDATE] = ++ g_param_spec_object ("scanout-candidate", ++ "scanout-candidate", ++ "Scanout candidate for given CRTC", ++ META_TYPE_CRTC, ++ G_PARAM_READABLE | ++ G_PARAM_STATIC_STRINGS); ++ g_object_class_install_properties (object_class, N_PROPS, obj_props); ++ + surface_signals[SURFACE_DESTROY] = + g_signal_new ("destroy", + G_TYPE_FROM_CLASS (object_class), +@@ -2104,3 +2146,21 @@ meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, + + return scanout; + } ++ ++MetaCrtc * ++meta_wayland_surface_get_scanout_candidate (MetaWaylandSurface *surface) ++{ ++ return surface->scanout_candidate; ++} ++ ++void ++meta_wayland_surface_set_scanout_candidate (MetaWaylandSurface *surface, ++ MetaCrtc *crtc) ++{ ++ if (surface->scanout_candidate == crtc) ++ return; ++ ++ g_set_object (&surface->scanout_candidate, crtc); ++ g_object_notify_by_pspec (G_OBJECT (surface), ++ obj_props[PROP_SCANOUT_CANDIDATE]); ++} +diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h +index f0153b23b9..7e90cf095c 100644 +--- a/src/wayland/meta-wayland-surface.h ++++ b/src/wayland/meta-wayland-surface.h +@@ -247,6 +247,9 @@ struct _MetaWaylandSurface + */ + uint64_t sequence; + } presentation_time; ++ ++ /* dma-buf feedback */ ++ MetaCrtc *scanout_candidate; + }; + + void meta_wayland_shell_init (MetaWaylandCompositor *compositor); +@@ -362,6 +365,11 @@ int meta_wayland_surface_get_height (MetaWaylandSurface *surface + CoglScanout * meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, + CoglOnscreen *onscreen); + ++MetaCrtc * meta_wayland_surface_get_scanout_candidate (MetaWaylandSurface *surface); ++ ++void meta_wayland_surface_set_scanout_candidate (MetaWaylandSurface *surface, ++ MetaCrtc *crtc); ++ + static inline GNode * + meta_get_next_subsurface_sibling (GNode *n) + { +-- +2.51.1 + diff --git a/0010-wayland-dma-buf-Move-should_send_modifiers-to-the-to.patch b/0010-wayland-dma-buf-Move-should_send_modifiers-to-the-to.patch new file mode 100644 index 0000000..63b78d5 --- /dev/null +++ b/0010-wayland-dma-buf-Move-should_send_modifiers-to-the-to.patch @@ -0,0 +1,75 @@ +From 2890b4a152f1efbc1492626a4ee055083cc40159 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Fri, 6 Aug 2021 17:07:21 +0200 +Subject: [PATCH 10/18] wayland/dma-buf: Move should_send_modifiers() to the + top + +It's very much an auxiliary method; lets move it to where it belongs, +according to HACKING.md. + +Part-of: +(cherry picked from commit 4c54b36126a610c43b05f36f4aab33f302fdc021) +--- + src/wayland/meta-wayland-dma-buf.c | 39 ++++++++++++++++-------------- + 1 file changed, 21 insertions(+), 18 deletions(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index a255158993..c9e4671074 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -134,6 +134,27 @@ G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJE + G_DEFINE_TYPE (MetaWaylandDmaBufManager, meta_wayland_dma_buf_manager, + G_TYPE_OBJECT) + ++static gboolean ++should_send_modifiers (MetaBackend *backend) ++{ ++ MetaSettings *settings = meta_backend_get_settings (backend); ++ ++ if (meta_settings_is_experimental_feature_enabled ( ++ settings, META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS)) ++ return TRUE; ++ ++#ifdef HAVE_NATIVE_BACKEND ++ if (META_IS_BACKEND_NATIVE (backend)) ++ { ++ MetaRenderer *renderer = meta_backend_get_renderer (backend); ++ MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); ++ return meta_renderer_native_use_modifiers (renderer_native); ++ } ++#endif ++ ++ return FALSE; ++} ++ + static gint + compare_tranches (gconstpointer a, + gconstpointer b) +@@ -861,24 +882,6 @@ static const struct zwp_linux_dmabuf_v1_interface dma_buf_implementation = + dma_buf_handle_get_surface_feedback, + }; + +-static gboolean +-should_send_modifiers (MetaBackend *backend) +-{ +- MetaSettings *settings = meta_backend_get_settings (backend); +- +-#ifdef HAVE_NATIVE_BACKEND +- if (META_IS_BACKEND_NATIVE (backend)) +- { +- MetaRenderer *renderer = meta_backend_get_renderer (backend); +- MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); +- return meta_renderer_native_use_modifiers (renderer_native); +- } +-#endif +- +- return meta_settings_is_experimental_feature_enabled ( +- settings, META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS); +-} +- + static void + send_modifiers (struct wl_resource *resource, + MetaWaylandDmaBufFormat *format, +-- +2.51.1 + diff --git a/0011-wayland-dma-buf-Add-support-for-scanout-surface-feed.patch b/0011-wayland-dma-buf-Add-support-for-scanout-surface-feed.patch new file mode 100644 index 0000000..318c10d --- /dev/null +++ b/0011-wayland-dma-buf-Add-support-for-scanout-surface-feed.patch @@ -0,0 +1,378 @@ +From 6bb16eb5ac7f70b42533b189a4928f29d0fbc768 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Fri, 6 Aug 2021 17:04:18 +0200 +Subject: [PATCH 11/18] wayland/dma-buf: Add support for scanout surface + feedback + +Whenever a surface is promoted as a scanout candidate by +MetaCompositorNative, it'll get a CRTC set as the candidate CRTC. + +When a client asks for DMA buffer surface feedback, use this property to +determine whether we should send a scanout feedback tranche. + +Part-of: +(cherry picked from commit 64e6bedb6bcd6cedc8439c6848003991906c9c80) +--- + src/wayland/meta-wayland-dma-buf.c | 287 ++++++++++++++++++++++++++++- + 1 file changed, 284 insertions(+), 3 deletions(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index c9e4671074..385012f1ab 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -95,6 +95,7 @@ typedef struct _MetaWaylandDmaBufTranche + dev_t target_device_id; + GArray *formats; + MetaWaylandDmaBufTrancheFlags flags; ++ uint64_t scanout_crtc_id; + } MetaWaylandDmaBufTranche; + + typedef struct _MetaWaylandDmaBufFeedback +@@ -103,6 +104,15 @@ typedef struct _MetaWaylandDmaBufFeedback + GList *tranches; + } MetaWaylandDmaBufFeedback; + ++typedef struct _MetaWaylandDmaBufSurfaceFeedback ++{ ++ MetaWaylandDmaBufManager *dma_buf_manager; ++ MetaWaylandSurface *surface; ++ MetaWaylandDmaBufFeedback *feedback; ++ GList *resources; ++ gulong scanout_candidate_changed_id; ++} MetaWaylandDmaBufSurfaceFeedback; ++ + struct _MetaWaylandDmaBufManager + { + GObject parent; +@@ -134,6 +144,8 @@ G_DEFINE_TYPE (MetaWaylandDmaBufBuffer, meta_wayland_dma_buf_buffer, G_TYPE_OBJE + G_DEFINE_TYPE (MetaWaylandDmaBufManager, meta_wayland_dma_buf_manager, + G_TYPE_OBJECT) + ++static GQuark quark_dma_buf_surface_feedback; ++ + static gboolean + should_send_modifiers (MetaBackend *backend) + { +@@ -194,6 +206,15 @@ meta_wayland_dma_buf_tranche_free (MetaWaylandDmaBufTranche *tranche) + g_free (tranche); + } + ++static MetaWaylandDmaBufTranche * ++meta_wayland_dma_buf_tranche_copy (MetaWaylandDmaBufTranche *tranche) ++{ ++ return meta_wayland_dma_buf_tranche_new (tranche->target_device_id, ++ tranche->formats, ++ tranche->priority, ++ tranche->flags); ++} ++ + static void + meta_wayland_dma_buf_tranche_send (MetaWaylandDmaBufTranche *tranche, + struct wl_resource *resource) +@@ -285,6 +306,20 @@ meta_wayland_dma_buf_feedback_free (MetaWaylandDmaBufFeedback *feedback) + g_free (feedback); + } + ++static MetaWaylandDmaBufFeedback * ++meta_wayland_dma_buf_feedback_copy (MetaWaylandDmaBufFeedback *feedback) ++{ ++ MetaWaylandDmaBufFeedback *new_feedback; ++ ++ new_feedback = meta_wayland_dma_buf_feedback_new (feedback->main_device_id); ++ new_feedback->tranches = ++ g_list_copy_deep (feedback->tranches, ++ (GCopyFunc) meta_wayland_dma_buf_tranche_copy, ++ NULL); ++ ++ return new_feedback; ++} ++ + static gboolean + meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, + GError **error) +@@ -848,6 +883,242 @@ dma_buf_handle_get_default_feedback (struct wl_client *client, + feedback_resource); + } + ++#ifdef HAVE_NATIVE_BACKEND ++static int ++find_scanout_tranche_func (gconstpointer a, ++ gconstpointer b) ++{ ++ const MetaWaylandDmaBufTranche *tranche = a; ++ ++ if (tranche->scanout_crtc_id) ++ return 0; ++ else ++ return -1; ++} ++ ++static gboolean ++has_modifier (GArray *modifiers, ++ uint64_t drm_modifier) ++{ ++ int i; ++ ++ for (i = 0; i < modifiers->len; i++) ++ { ++ if (drm_modifier == g_array_index (modifiers, uint64_t, i)) ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++static gboolean ++crtc_supports_modifier (MetaCrtcKms *crtc_kms, ++ uint32_t drm_format, ++ uint64_t drm_modifier) ++{ ++ GArray *crtc_modifiers; ++ ++ crtc_modifiers = meta_crtc_kms_get_modifiers (crtc_kms, drm_format); ++ if (!crtc_modifiers) ++ return FALSE; ++ ++ return has_modifier (crtc_modifiers, drm_modifier); ++} ++ ++static void ++ensure_scanout_tranche (MetaWaylandDmaBufSurfaceFeedback *surface_feedback, ++ MetaCrtc *crtc) ++{ ++ MetaWaylandDmaBufManager *dma_buf_manager = surface_feedback->dma_buf_manager; ++ MetaWaylandDmaBufFeedback *feedback = surface_feedback->feedback; ++ MetaCrtcKms *crtc_kms; ++ MetaWaylandDmaBufTranche *tranche; ++ GList *el; ++ int i; ++ g_autoptr (GArray) formats = NULL; ++ MetaWaylandDmaBufTranchePriority priority; ++ MetaWaylandDmaBufTrancheFlags flags; ++ ++ g_return_if_fail (META_IS_CRTC_KMS (crtc)); ++ crtc_kms = META_CRTC_KMS (crtc); ++ ++ el = g_list_find_custom (feedback->tranches, NULL, find_scanout_tranche_func); ++ if (el) ++ { ++ tranche = el->data; ++ ++ if (tranche->scanout_crtc_id == meta_crtc_get_id (crtc)) ++ return; ++ ++ meta_wayland_dma_buf_tranche_free (tranche); ++ feedback->tranches = g_list_delete_link (feedback->tranches, el); ++ } ++ ++ formats = g_array_new (FALSE, FALSE, sizeof (MetaWaylandDmaBufFormat)); ++ if (should_send_modifiers (meta_get_backend ())) ++ { ++ for (i = 0; i < dma_buf_manager->formats->len; i++) ++ { ++ MetaWaylandDmaBufFormat format = ++ g_array_index (dma_buf_manager->formats, ++ MetaWaylandDmaBufFormat, ++ i); ++ ++ if (!crtc_supports_modifier (crtc_kms, ++ format.drm_format, ++ format.drm_modifier)) ++ continue; ++ ++ g_array_append_val (formats, format); ++ } ++ ++ if (formats->len == 0) ++ return; ++ } ++ else ++ { ++ for (i = 0; i < dma_buf_manager->formats->len; i++) ++ { ++ MetaWaylandDmaBufFormat format = ++ g_array_index (dma_buf_manager->formats, ++ MetaWaylandDmaBufFormat, ++ i); ++ ++ if (format.drm_modifier != DRM_FORMAT_MOD_INVALID) ++ continue; ++ ++ if (!meta_crtc_kms_get_modifiers (crtc_kms, format.drm_format)) ++ continue; ++ ++ g_array_append_val (formats, format); ++ } ++ ++ if (formats->len == 0) ++ return; ++ } ++ ++ priority = META_WAYLAND_DMA_BUF_TRANCHE_PRIORITY_HIGH; ++ flags = META_WAYLAND_DMA_BUF_TRANCHE_FLAG_SCANOUT; ++ tranche = meta_wayland_dma_buf_tranche_new (feedback->main_device_id, ++ formats, ++ priority, ++ flags); ++ tranche->scanout_crtc_id = meta_crtc_get_id (crtc); ++ meta_wayland_dma_buf_feedback_add_tranche (feedback, tranche); ++} ++ ++static void ++clear_scanout_tranche (MetaWaylandDmaBufSurfaceFeedback *surface_feedback) ++{ ++ MetaWaylandDmaBufFeedback *feedback = surface_feedback->feedback; ++ MetaWaylandDmaBufTranche *tranche; ++ GList *el; ++ ++ el = g_list_find_custom (feedback->tranches, NULL, find_scanout_tranche_func); ++ if (!el) ++ return; ++ ++ tranche = el->data; ++ meta_wayland_dma_buf_tranche_free (tranche); ++ feedback->tranches = g_list_delete_link (feedback->tranches, el); ++} ++#endif /* HAVE_NATIVE_BACKEND */ ++ ++static void ++update_surface_feedback_tranches (MetaWaylandDmaBufSurfaceFeedback *surface_feedback) ++{ ++#ifdef HAVE_NATIVE_BACKEND ++ MetaCrtc *crtc; ++ ++ crtc = meta_wayland_surface_get_scanout_candidate (surface_feedback->surface); ++ if (crtc) ++ ensure_scanout_tranche (surface_feedback, crtc); ++ else ++ clear_scanout_tranche (surface_feedback); ++#endif /* HAVE_NATIVE_BACKEND */ ++} ++ ++static void ++on_scanout_candidate_changed (MetaWaylandSurface *surface, ++ GParamSpec *pspec, ++ MetaWaylandDmaBufSurfaceFeedback *surface_feedback) ++{ ++ GList *l; ++ ++ update_surface_feedback_tranches (surface_feedback); ++ ++ for (l = surface_feedback->resources; l; l = l->next) ++ { ++ struct wl_resource *resource = l->data; ++ ++ meta_wayland_dma_buf_feedback_send (surface_feedback->feedback, ++ surface_feedback->dma_buf_manager, ++ resource); ++ } ++} ++ ++static void ++surface_feedback_surface_destroyed_cb (gpointer user_data) ++{ ++ MetaWaylandDmaBufSurfaceFeedback *surface_feedback = user_data; ++ ++ g_list_foreach (surface_feedback->resources, ++ (GFunc) wl_resource_set_user_data, ++ NULL); ++ g_list_free (surface_feedback->resources); ++ ++ g_free (surface_feedback); ++} ++ ++static MetaWaylandDmaBufSurfaceFeedback * ++ensure_surface_feedback (MetaWaylandDmaBufManager *dma_buf_manager, ++ MetaWaylandSurface *surface) ++{ ++ MetaWaylandDmaBufSurfaceFeedback *surface_feedback; ++ ++ surface_feedback = g_object_get_qdata (G_OBJECT (surface), ++ quark_dma_buf_surface_feedback); ++ if (surface_feedback) ++ return surface_feedback; ++ ++ surface_feedback = g_new0 (MetaWaylandDmaBufSurfaceFeedback, 1); ++ surface_feedback->dma_buf_manager = dma_buf_manager; ++ surface_feedback->surface = surface; ++ surface_feedback->feedback = ++ meta_wayland_dma_buf_feedback_copy (dma_buf_manager->default_feedback); ++ ++ surface_feedback->scanout_candidate_changed_id = ++ g_signal_connect (surface, "notify::scanout-candidate", ++ G_CALLBACK (on_scanout_candidate_changed), ++ surface_feedback); ++ ++ g_object_set_qdata_full (G_OBJECT (surface), ++ quark_dma_buf_surface_feedback, ++ surface_feedback, ++ surface_feedback_surface_destroyed_cb); ++ ++ return surface_feedback; ++} ++ ++static void ++surface_feedback_destructor (struct wl_resource *resource) ++{ ++ MetaWaylandDmaBufSurfaceFeedback *surface_feedback = ++ ++ surface_feedback = wl_resource_get_user_data (resource); ++ if (!surface_feedback) ++ return; ++ ++ surface_feedback->resources = g_list_remove (surface_feedback->resources, ++ resource); ++ if (!surface_feedback->resources) ++ { ++ g_clear_signal_handler (&surface_feedback->scanout_candidate_changed_id, ++ surface_feedback->surface); ++ g_object_set_qdata (G_OBJECT (surface_feedback->surface), ++ quark_dma_buf_surface_feedback, NULL); ++ } ++} ++ + static void + dma_buf_handle_get_surface_feedback (struct wl_client *client, + struct wl_resource *dma_buf_resource, +@@ -856,8 +1127,13 @@ dma_buf_handle_get_surface_feedback (struct wl_client *client, + { + MetaWaylandDmaBufManager *dma_buf_manager = + wl_resource_get_user_data (dma_buf_resource); ++ MetaWaylandSurface *surface = ++ wl_resource_get_user_data (surface_resource); ++ MetaWaylandDmaBufSurfaceFeedback *surface_feedback; + struct wl_resource *feedback_resource; + ++ surface_feedback = ensure_surface_feedback (dma_buf_manager, surface); ++ + feedback_resource = + wl_resource_create (client, + &zwp_linux_dmabuf_feedback_v1_interface, +@@ -866,10 +1142,12 @@ dma_buf_handle_get_surface_feedback (struct wl_client *client, + + wl_resource_set_implementation (feedback_resource, + &feedback_implementation, +- NULL, +- feedback_destructor); ++ surface_feedback, ++ surface_feedback_destructor); ++ surface_feedback->resources = g_list_prepend (surface_feedback->resources, ++ feedback_resource); + +- meta_wayland_dma_buf_feedback_send (dma_buf_manager->default_feedback, ++ meta_wayland_dma_buf_feedback_send (surface_feedback->feedback, + dma_buf_manager, + feedback_resource); + } +@@ -1254,6 +1532,9 @@ meta_wayland_dma_buf_manager_class_init (MetaWaylandDmaBufManagerClass *klass) + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_wayland_dma_buf_manager_finalize; ++ ++ quark_dma_buf_surface_feedback = ++ g_quark_from_static_string ("-meta-wayland-dma-buf-surface-feedback"); + } + + static void +-- +2.51.1 + diff --git a/0012-wayland-dma-buf-Add-missing-wl_array_release.patch b/0012-wayland-dma-buf-Add-missing-wl_array_release.patch new file mode 100644 index 0000000..f30e8d9 --- /dev/null +++ b/0012-wayland-dma-buf-Add-missing-wl_array_release.patch @@ -0,0 +1,30 @@ +From 405673317976d578d7b228f4ab5ceea0e1366d99 Mon Sep 17 00:00:00 2001 +From: Robert Mader +Date: Tue, 15 Feb 2022 20:56:27 +0100 +Subject: [PATCH 12/18] wayland/dma-buf: Add missing wl_array_release() + +So we don't leak the array. + +Fixes 7acecb1c7233dad0b9b314f59121882a518901d7 + +Part-of: +(cherry picked from commit 5b9abecc1bbe6acf8f65f976c660d5eefead16d8) +--- + src/wayland/meta-wayland-dma-buf.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index 385012f1ab..4e21632159 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -271,6 +271,7 @@ meta_wayland_dma_buf_feedback_send (MetaWaylandDmaBufFeedback *feedback, + device_id_ptr = wl_array_add (&main_device_buf, sizeof (*device_id_ptr)); + *device_id_ptr = feedback->main_device_id; + zwp_linux_dmabuf_feedback_v1_send_main_device (resource, &main_device_buf); ++ wl_array_release (&main_device_buf); + + g_list_foreach (feedback->tranches, + (GFunc) meta_wayland_dma_buf_tranche_send, +-- +2.51.1 + diff --git a/0013-wayland-dma-buf-Fix-typos-in-struct-name.patch b/0013-wayland-dma-buf-Fix-typos-in-struct-name.patch new file mode 100644 index 0000000..b8fbc98 --- /dev/null +++ b/0013-wayland-dma-buf-Fix-typos-in-struct-name.patch @@ -0,0 +1,29 @@ +From 70ff9d15f67dc88b6d81f794e8bb35820c23dfc2 Mon Sep 17 00:00:00 2001 +From: Robert Mader +Date: Tue, 15 Feb 2022 21:31:06 +0100 +Subject: [PATCH 13/18] wayland/dma-buf: Fix typos in struct name + +Fixes 7acecb1c7233dad0b9b314f59121882a518901d7 + +Part-of: +(cherry picked from commit 8f91d831ee20b9c73036561ee1b57bf9f5efef65) +--- + src/wayland/meta-wayland-dma-buf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index 4e21632159..f28070da80 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -1281,7 +1281,7 @@ add_fallback: + * + * [ 32 bit format ][ 32 bit padding ][ 64 bit modifier ] + */ +-typedef struct _MetaMetaWaylanDmaBdufFormatEntry ++typedef struct _MetaWaylandDmaBufFormatEntry + { + uint32_t drm_format; + uint32_t unused_padding; +-- +2.51.1 + diff --git a/0014-wayland-dma-buf-Free-feedback-in-surface_feedback_su.patch b/0014-wayland-dma-buf-Free-feedback-in-surface_feedback_su.patch new file mode 100644 index 0000000..c04c2e0 --- /dev/null +++ b/0014-wayland-dma-buf-Free-feedback-in-surface_feedback_su.patch @@ -0,0 +1,45 @@ +From ba94be928ecf77bd202bd57bbcc5dc5dffb4aee5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michel=20D=C3=A4nzer?= +Date: Thu, 16 Jun 2022 12:17:36 +0200 +Subject: [PATCH 14/18] wayland/dma-buf: Free feedback in + surface_feedback_surface_destroyed_cb + +Fixes leak: + +==14889== 2,168 (16 direct, 2,152 indirect) bytes in 1 blocks are definitely lost in loss record 15,308 of 15,584 +==14889== at 0x48445EF: calloc (vg_replace_malloc.c:1328) +==14889== by 0x4BAC1D0: g_malloc0 (gmem.c:155) +==14889== by 0x4AAFF60: meta_wayland_dma_buf_feedback_new (meta-wayland-dma-buf.c:298) +==14889== by 0x4AAFFE0: meta_wayland_dma_buf_feedback_copy (meta-wayland-dma-buf.c:317) +==14889== by 0x4AB16B6: ensure_surface_feedback (meta-wayland-dma-buf.c:1121) +==14889== by 0x4AB1848: dma_buf_handle_get_surface_feedback (meta-wayland-dma-buf.c:1169) +==14889== by 0x66F77E9: ??? (in /usr/lib/x86_64-linux-gnu/libffi.so.8.1.0) +==14889== by 0x66F6922: ??? (in /usr/lib/x86_64-linux-gnu/libffi.so.8.1.0) +==14889== by 0x5318750: ??? (in /usr/lib/x86_64-linux-gnu/libwayland-server.so.0.20.0) +==14889== by 0x5313B99: ??? (in /usr/lib/x86_64-linux-gnu/libwayland-server.so.0.20.0) +==14889== by 0x5316649: wl_event_loop_dispatch (in /usr/lib/x86_64-linux-gnu/libwayland-server.so.0.20.0) +==14889== by 0x4AA7C19: wayland_event_source_dispatch (meta-wayland.c:110) + +Fixes: 64e6bedb6bcd ("wayland/dma-buf: Add support for scanout surface feedback") +Part-of: +(cherry picked from commit 4af54225de3a653e7b44ab1905b64ebddf57da4a) +--- + src/wayland/meta-wayland-dma-buf.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index f28070da80..3a1d92ecf6 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -1067,6 +1067,8 @@ surface_feedback_surface_destroyed_cb (gpointer user_data) + NULL); + g_list_free (surface_feedback->resources); + ++ meta_wayland_dma_buf_feedback_free (surface_feedback->feedback); ++ + g_free (surface_feedback); + } + +-- +2.51.1 + diff --git a/0015-wayland-dma-buf-Only-advertise-supported-formats.patch b/0015-wayland-dma-buf-Only-advertise-supported-formats.patch new file mode 100644 index 0000000..5c09fce --- /dev/null +++ b/0015-wayland-dma-buf-Only-advertise-supported-formats.patch @@ -0,0 +1,144 @@ +From 43feafa1c2c061acb226a8df0a6b6a1f5a9b1ba0 Mon Sep 17 00:00:00 2001 +From: Robert Mader +Date: Mon, 25 Apr 2022 18:00:50 +0200 +Subject: [PATCH 15/18] wayland/dma-buf: Only advertise supported formats + +Analogous to how we use `eglQueryDmaBufModifiersEXT()` to query +supported modifiers, use `eglQueryDmaBufFormatsEXT()` to ensure +we only advertise formats supported by both the compositor and the +driver. + +If there is no overlap, don't advertise `zwp_linux_dmabuf_v1` at +all. + +Closes https://gitlab.gnome.org/GNOME/mutter/-/issues/2238 + +Part-of: +(cherry picked from commit c8095b430689365c5cdd4646c54de4b07a0da7ee) +--- + src/wayland/meta-wayland-dma-buf.c | 89 +++++++++++++++++++++++------- + 1 file changed, 69 insertions(+), 20 deletions(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index 3a1d92ecf6..145fd0cdab 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -1317,28 +1317,71 @@ init_format_table (MetaWaylandDmaBufManager *dma_buf_manager) + meta_anonymous_file_new (size, (uint8_t *) format_table); + } + +-static void +-init_formats (MetaWaylandDmaBufManager *dma_buf_manager, +- EGLDisplay egl_display) ++static EGLint supported_formats[] = { ++ DRM_FORMAT_ARGB8888, ++ DRM_FORMAT_ABGR8888, ++ DRM_FORMAT_XRGB8888, ++ DRM_FORMAT_XBGR8888, ++ DRM_FORMAT_ARGB2101010, ++ DRM_FORMAT_ABGR2101010, ++ DRM_FORMAT_XRGB2101010, ++ DRM_FORMAT_XBGR2101010, ++ DRM_FORMAT_RGB565, ++ DRM_FORMAT_ABGR16161616F, ++ DRM_FORMAT_XBGR16161616F, ++ DRM_FORMAT_XRGB16161616F, ++ DRM_FORMAT_ARGB16161616F ++}; ++ ++static gboolean ++init_formats (MetaWaylandDmaBufManager *dma_buf_manager, ++ EGLDisplay egl_display, ++ GError **error) + { ++ MetaBackend *backend = meta_get_backend (); ++ MetaEgl *egl = meta_backend_get_egl (backend); ++ EGLint num_formats; ++ g_autofree EGLint *driver_formats = NULL; ++ int i, j; ++ + dma_buf_manager->formats = g_array_new (FALSE, FALSE, + sizeof (MetaWaylandDmaBufFormat)); + +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_ARGB8888); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_ABGR8888); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_XRGB8888); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_XBGR8888); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_ARGB2101010); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_ABGR2101010); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_XRGB2101010); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_XBGR2101010); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_RGB565); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_ABGR16161616F); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_XBGR16161616F); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_XRGB16161616F); +- add_format (dma_buf_manager, egl_display, DRM_FORMAT_ARGB16161616F); ++ if (!meta_egl_query_dma_buf_formats (egl, egl_display, 0, NULL, &num_formats, ++ error)) ++ return FALSE; ++ ++ if (num_formats == 0) ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "EGL doesn't support any DRM formats"); ++ return FALSE; ++ } ++ ++ driver_formats = g_new0 (EGLint, num_formats); ++ if (!meta_egl_query_dma_buf_formats (egl, egl_display, num_formats, ++ driver_formats, &num_formats, error)) ++ return FALSE; ++ ++ for (i = 0; i < G_N_ELEMENTS (supported_formats); i++) ++ { ++ for (j = 0; j < num_formats; j++) ++ { ++ if (supported_formats[i] == driver_formats[j]) ++ add_format (dma_buf_manager, egl_display, supported_formats[i]); ++ } ++ } ++ ++ if (dma_buf_manager->formats->len == 0) ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "EGL doesn't support any DRM formats supported by the " ++ "compositor"); ++ return FALSE; ++ } + + init_format_table (dma_buf_manager); ++ return TRUE; + } + + static void +@@ -1460,6 +1503,16 @@ initialize: + + dma_buf_manager = g_object_new (META_TYPE_WAYLAND_DMA_BUF_MANAGER, NULL); + ++ dma_buf_manager->compositor = compositor; ++ dma_buf_manager->main_device_id = device_id; ++ ++ if (!init_formats (dma_buf_manager, egl_display, &local_error)) ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "No supported formats detected: %s", local_error->message); ++ return NULL; ++ } ++ + if (!wl_global_create (compositor->wayland_display, + &zwp_linux_dmabuf_v1_interface, + protocol_version, +@@ -1471,10 +1524,6 @@ initialize: + return NULL; + } + +- dma_buf_manager->compositor = compositor; +- dma_buf_manager->main_device_id = device_id; +- +- init_formats (dma_buf_manager, egl_display); + init_default_feedback (dma_buf_manager); + + return g_steal_pointer (&dma_buf_manager); +-- +2.51.1 + diff --git a/0016-wayland-dma-buf-Remove-redundant-error-check.patch b/0016-wayland-dma-buf-Remove-redundant-error-check.patch new file mode 100644 index 0000000..60631ee --- /dev/null +++ b/0016-wayland-dma-buf-Remove-redundant-error-check.patch @@ -0,0 +1,29 @@ +From d7bf34fc6d9b9dd876c665c9e8b84270de86e34e Mon Sep 17 00:00:00 2001 +From: Robert Mader +Date: Tue, 26 Apr 2022 20:27:57 +0200 +Subject: [PATCH 16/18] wayland/dma-buf: Remove redundant error check + +`meta_egl_*` functions are assumed to set an error on failure. + +Part-of: +(cherry picked from commit aa8d2d6fffbcb4ccf16ff527311e101fa75d4d3c) +--- + src/wayland/meta-wayland-dma-buf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index 145fd0cdab..c59b767b4c 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -1252,7 +1252,7 @@ add_format (MetaWaylandDmaBufManager *dma_buf_manager, + &num_modifiers, &error)) + { + g_warning ("Failed to query modifiers for format 0x%" PRIu32 ": %s", +- drm_format, error ? error->message : "unknown error"); ++ drm_format, error->message); + goto add_fallback; + } + +-- +2.51.1 + diff --git a/0017-egl-Don-t-set-an-error-when-there-is-none.patch b/0017-egl-Don-t-set-an-error-when-there-is-none.patch new file mode 100644 index 0000000..1eda665 --- /dev/null +++ b/0017-egl-Don-t-set-an-error-when-there-is-none.patch @@ -0,0 +1,34 @@ +From 6e6a88f95e6fae313601fc83e3f3b7e61628e4e0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 12 Jan 2022 14:02:25 +0100 +Subject: [PATCH 17/18] egl: Don't set an error when there is none + +Some API will return NULL or the equivalent; sometimes it's an error, +and sometimes it's not, and the way to check that is by looking at the +return value of eglGetError(). When we check this, don't set the GError +if it returned EGL_SUCCESS, as that indicates that the return value is +expected behavior, and not an error. + +Part-of: +(cherry picked from commit 719a6c0006ed5e982b283c9a616973600db8c7f7) +--- + src/backends/meta-egl.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/backends/meta-egl.c b/src/backends/meta-egl.c +index c2777271ff..3b6e4b399e 100644 +--- a/src/backends/meta-egl.c ++++ b/src/backends/meta-egl.c +@@ -158,6 +158,9 @@ set_egl_error (GError **error) + return; + + error_number = eglGetError (); ++ if (error_number == EGL_SUCCESS) ++ return; ++ + error_str = get_egl_error_str (error_number); + g_set_error_literal (error, META_EGL_ERROR, + error_number, +-- +2.51.1 + diff --git a/0018-wayland-dma-buf-Don-t-warn-if-there-was-no-render-no.patch b/0018-wayland-dma-buf-Don-t-warn-if-there-was-no-render-no.patch new file mode 100644 index 0000000..6aa1bf4 --- /dev/null +++ b/0018-wayland-dma-buf-Don-t-warn-if-there-was-no-render-no.patch @@ -0,0 +1,72 @@ +From b61fc8eb57186dd4fb2f83383f69673a06b0104c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 12 Jan 2022 12:11:01 +0100 +Subject: [PATCH 18/18] wayland/dma-buf: Don't warn if there was no render node + +When running in KVM, the EGL driver supports querying the render node +path, but it returns NULL. Handle that better by falling back to +querying the device main device file, instead of falling back on v3 of +the protocol and logging a warning. + +Part-of: +(cherry picked from commit a2382f325117dbfc4dede55f72fc5b9942c3ffb9) +--- + src/wayland/meta-wayland-dma-buf.c | 33 +++++++++++++++++------------- + 1 file changed, 19 insertions(+), 14 deletions(-) + +diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c +index c59b767b4c..75b0bbe858 100644 +--- a/src/wayland/meta-wayland-dma-buf.c ++++ b/src/wayland/meta-wayland-dma-buf.c +@@ -1459,29 +1459,34 @@ meta_wayland_dma_buf_manager_new (MetaWaylandCompositor *compositor, + device_path = meta_egl_query_device_string (egl, egl_device, + EGL_DRM_RENDER_NODE_FILE_EXT, + &local_error); ++ if (local_error) ++ { ++ g_warning ("Failed to query EGL render node path: %s", ++ local_error->message); ++ g_clear_error (&local_error); ++ } + } +- else if (meta_egl_egl_device_has_extensions (egl, egl_device, NULL, +- "EGL_EXT_device_drm", +- NULL)) ++ ++ if (!device_path && ++ meta_egl_egl_device_has_extensions (egl, egl_device, NULL, ++ "EGL_EXT_device_drm", ++ NULL)) + { + device_path = meta_egl_query_device_string (egl, egl_device, + EGL_DRM_DEVICE_FILE_EXT, + &local_error); +- } +- else +- { +- meta_topic (META_DEBUG_WAYLAND, +- "Only advertising zwp_linux_dmabuf_v1 interface version 3 " +- "support, missing 'EGL_EXT_device_drm' and " +- "'EGL_EXT_device_drm_render_node'"); +- protocol_version = 3; +- goto initialize; ++ if (local_error) ++ { ++ g_warning ("Failed to query EGL render node path: %s", ++ local_error->message); ++ } + } + + if (!device_path) + { +- g_warning ("Failed to query EGL device path: %s", +- local_error->message); ++ meta_topic (META_DEBUG_WAYLAND, ++ "Only advertising zwp_linux_dmabuf_v1 interface version 3 " ++ "support, no suitable device path could be found"); + protocol_version = 3; + goto initialize; + } +-- +2.51.1 + diff --git a/mutter.spec b/mutter.spec index ef8a88f..4317d8e 100644 --- a/mutter.spec +++ b/mutter.spec @@ -10,7 +10,7 @@ Name: mutter Version: 40.9 -Release: 30%{?dist} +Release: 31%{?dist} Summary: Window and compositing manager based on Clutter License: GPLv2+ @@ -170,6 +170,26 @@ Patch73: 0001-compositor-x11-sync-again-at-the-end-of-before_paint.patch # RHEL-113246 Patch74: 0001-compositor-sync-ring-Allow-the-gpu_fence-to-be-moved.patch +# RHEL-129832 - linux_dmabuf v4 support. +Patch75: 0001-egl-Add-eglQueryDisplayAttribEXT-helper.patch +Patch76: 0002-wayland-dma-buf-Add-manager-struct.patch +Patch77: 0003-wayland-dma-buf-Prepare-format-modifier-map-up-front.patch +Patch78: 0004-wayland-dma-buf-Add-basic-support-for-DMA-buffer-fee.patch +Patch79: 0005-wayland-dma-buf-Always-advertise-non-modifier-fallba.patch +Patch80: 0006-wayland-surface-Remove-unnecessary-NULL-check.patch +Patch81: 0007-wayland-dma-buf-Make-manager-object-a-GObject.patch +Patch82: 0008-wayland-dma-buf-Add-tranche-priorities.patch +Patch83: 0009-compositor-native-Track-what-Wayland-surface-is-a-sc.patch +Patch84: 0010-wayland-dma-buf-Move-should_send_modifiers-to-the-to.patch +Patch85: 0011-wayland-dma-buf-Add-support-for-scanout-surface-feed.patch +Patch86: 0012-wayland-dma-buf-Add-missing-wl_array_release.patch +Patch87: 0013-wayland-dma-buf-Fix-typos-in-struct-name.patch +Patch88: 0014-wayland-dma-buf-Free-feedback-in-surface_feedback_su.patch +Patch89: 0015-wayland-dma-buf-Only-advertise-supported-formats.patch +Patch90: 0016-wayland-dma-buf-Remove-redundant-error-check.patch +Patch91: 0017-egl-Don-t-set-an-error-when-there-is-none.patch +Patch92: 0018-wayland-dma-buf-Don-t-warn-if-there-was-no-render-no.patch + # RHEL-70872 Patch533: 0001-x11-iconcache-Turn-icons-from-WM_HINTS-pixmaps-to-ca.patch @@ -224,7 +244,7 @@ BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(gbm) BuildRequires: pkgconfig(wayland-server) BuildRequires: pkgconfig(wayland-eglstream) -BuildRequires: pkgconfig(wayland-protocols) +BuildRequires: pkgconfig(wayland-protocols) >= 1.24 BuildRequires: json-glib-devel >= %{json_glib_version} BuildRequires: libgudev1-devel @@ -320,6 +340,11 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop %{_datadir}/mutter-%{mutter_api_version}/tests %changelog +* Thu Nov 20 2025 Olivier Fourdan - 40.9-31 +- Backport linux-dmabuf v4 support to restore hardware acceleration + in Xwayland 24.1 with Mesa 25.2 + Resolves: RHEL-129832 + * Mon Nov 10 2025 Jonas Ådahl - 40.9-30 - Fix handling of more WM_HINTS window icon types Resolves: RHEL-70872