[mutter] wayland/dma-buf: Add support for scanout surface feedback
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] wayland/dma-buf: Add support for scanout surface feedback
- Date: Wed, 5 Jan 2022 17:17:48 +0000 (UTC)
commit 64e6bedb6bcd6cedc8439c6848003991906c9c80
Author: Jonas Ã…dahl <jadahl gmail com>
Date: Fri Aug 6 17:04:18 2021 +0200
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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1959>
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 84ef5acfd8..f7e929c5b4 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)
@@ -862,6 +897,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,
@@ -870,8 +1141,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,
@@ -880,10 +1156,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);
}
@@ -1269,6 +1547,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
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]