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>
This commit is contained in:
parent
4c54b36126
commit
64e6bedb6b
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user