surface: Add a dmabuf-formats property

Add a property to GdkSurface that carries the effective dmabuf
formats for the surface. This will be either the formats according
to the surfaces own Wayland dmabuf feedback, or the formats of the
topmost subsurface.
This commit is contained in:
Matthias Clasen
2024-02-07 10:29:41 +00:00
parent 8f28b21f2d
commit 05bd3bc05a
5 changed files with 183 additions and 0 deletions

View File

@@ -20,6 +20,7 @@
#include "gdksubsurfaceprivate.h"
#include "gdksurfaceprivate.h"
#include "gdktexture.h"
#include "gdkdebugprivate.h"
G_DEFINE_TYPE (GdkSubsurface, gdk_subsurface, G_TYPE_OBJECT)
@@ -35,6 +36,7 @@ gdk_subsurface_finalize (GObject *object)
g_ptr_array_remove (subsurface->parent->subsurfaces, subsurface);
g_clear_object (&subsurface->parent);
g_clear_pointer (&subsurface->dmabuf_formats, gdk_dmabuf_formats_unref);
G_OBJECT_CLASS (gdk_subsurface_parent_class)->finalize (object);
}
@@ -107,6 +109,28 @@ insert_subsurface (GdkSubsurface *subsurface,
}
}
static inline gboolean
is_topmost_subsurface (GdkSubsurface *subsurface)
{
GdkSurface *parent = subsurface->parent;
return !subsurface->sibling_above && parent->subsurfaces_below != subsurface;
}
static inline GdkSubsurface *
find_topmost_subsurface (GdkSurface *surface)
{
GdkSubsurface *top = surface->subsurfaces_above;
if (top)
{
while (top->sibling_above)
top = top->sibling_above;
}
return top;
}
gboolean
gdk_subsurface_attach (GdkSubsurface *subsurface,
GdkTexture *texture,
@@ -115,6 +139,7 @@ gdk_subsurface_attach (GdkSubsurface *subsurface,
GdkSubsurface *sibling)
{
GdkSurface *parent = subsurface->parent;
gboolean was_topmost, is_topmost;
g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), FALSE);
g_return_val_if_fail (GDK_IS_TEXTURE (texture), FALSE);
@@ -125,6 +150,8 @@ gdk_subsurface_attach (GdkSubsurface *subsurface,
remove_subsurface (subsurface);
was_topmost = is_topmost_subsurface (subsurface);
if (sibling)
{
insert_subsurface (subsurface, above, sibling);
@@ -148,16 +175,54 @@ gdk_subsurface_attach (GdkSubsurface *subsurface,
}
}
is_topmost = is_topmost_subsurface (subsurface);
if (!was_topmost && is_topmost)
{
GDK_DISPLAY_DEBUG (parent->display, DMABUF, "Using formats of topmost subsurface %p", subsurface);
gdk_surface_set_effective_dmabuf_formats (parent, subsurface->dmabuf_formats);
}
else if (was_topmost && !is_topmost)
{
GdkSubsurface *top = find_topmost_subsurface (parent);
if (top)
{
GDK_DISPLAY_DEBUG (parent->display, DMABUF, "Using formats of topmost subsurface %p", top);
gdk_surface_set_effective_dmabuf_formats (parent, top->dmabuf_formats);
}
else
{
GDK_DISPLAY_DEBUG (parent->display, DMABUF, "Using formats of main surface");
gdk_surface_set_effective_dmabuf_formats (parent, parent->dmabuf_formats);
}
}
return GDK_SUBSURFACE_GET_CLASS (subsurface)->attach (subsurface, texture, rect, above, sibling);
}
void
gdk_subsurface_detach (GdkSubsurface *subsurface)
{
gboolean was_topmost;
g_return_if_fail (GDK_IS_SUBSURFACE (subsurface));
was_topmost = is_topmost_subsurface (subsurface);
remove_subsurface (subsurface);
if (was_topmost)
{
GdkSurface *parent = subsurface->parent;
GdkSubsurface *top = find_topmost_subsurface (parent);
if (top)
gdk_surface_set_effective_dmabuf_formats (parent, top->dmabuf_formats);
else
gdk_surface_set_effective_dmabuf_formats (parent, parent->dmabuf_formats);
}
GDK_SUBSURFACE_GET_CLASS (subsurface)->detach (subsurface);
}
@@ -186,3 +251,17 @@ gdk_subsurface_is_above_parent (GdkSubsurface *subsurface)
return subsurface->above_parent;
}
void
gdk_subsurface_set_dmabuf_formats (GdkSubsurface *subsurface,
GdkDmabufFormats *formats)
{
g_return_if_fail (GDK_IS_SUBSURFACE (subsurface));
g_return_if_fail (formats != NULL);
g_clear_pointer (&subsurface->dmabuf_formats, gdk_dmabuf_formats_unref);
subsurface->dmabuf_formats = gdk_dmabuf_formats_ref (formats);
if (is_topmost_subsurface (subsurface))
gdk_surface_set_effective_dmabuf_formats (subsurface->parent, formats);
}

View File

@@ -21,6 +21,7 @@
#include "gdkenumtypes.h"
#include "gdksurface.h"
#include "gdkdmabufformats.h"
#include <graphene.h>
G_BEGIN_DECLS
@@ -45,6 +46,8 @@ struct _GdkSubsurface
gboolean above_parent;
GdkSubsurface *sibling_above;
GdkSubsurface *sibling_below;
GdkDmabufFormats *dmabuf_formats;
};
@@ -77,6 +80,8 @@ void gdk_subsurface_get_rect (GdkSubsurface *subsurfac
graphene_rect_t *rect);
gboolean gdk_subsurface_is_above_parent (GdkSubsurface *subsurface);
void gdk_subsurface_set_dmabuf_formats (GdkSubsurface *subsurface,
GdkDmabufFormats *formats);
G_END_DECLS

View File

@@ -91,6 +91,7 @@ enum {
PROP_0,
PROP_CURSOR,
PROP_DISPLAY,
PROP_DMABUF_FORMATS,
PROP_FRAME_CLOCK,
PROP_MAPPED,
PROP_WIDTH,
@@ -548,6 +549,18 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
GDK_TYPE_DISPLAY,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
/**
* GdkSurface:dmabuf-formats: (attributes org.gtk.Property.get=gdk_surface_get_dmabuf_formats)
*
* The dmabuf formats that can be used with this surface.
*
* Since: 4.14
*/
properties[PROP_DMABUF_FORMATS] =
g_param_spec_boxed ("dmabuf-formats", NULL, NULL,
GDK_TYPE_DMABUF_FORMATS,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
/**
* GdkSurface:frame-clock: (attributes org.gtk.Property.get=gdk_surface_get_frame_clock)
*
@@ -773,6 +786,9 @@ gdk_surface_finalize (GObject *object)
g_ptr_array_unref (surface->subsurfaces);
g_clear_pointer (&surface->dmabuf_formats, gdk_dmabuf_formats_unref);
g_clear_pointer (&surface->effective_dmabuf_formats, gdk_dmabuf_formats_unref);
G_OBJECT_CLASS (gdk_surface_parent_class)->finalize (object);
}
@@ -827,6 +843,10 @@ gdk_surface_get_property (GObject *object,
g_value_set_object (value, surface->display);
break;
case PROP_DMABUF_FORMATS:
g_value_set_boxed (value, surface->effective_dmabuf_formats);
break;
case PROP_FRAME_CLOCK:
g_value_set_object (value, surface->frame_clock);
break;
@@ -3076,3 +3096,70 @@ gdk_surface_get_subsurface (GdkSurface *surface,
{
return g_ptr_array_index (surface->subsurfaces, idx);
}
void
gdk_surface_set_dmabuf_formats (GdkSurface *surface,
GdkDmabufFormats *formats)
{
g_return_if_fail (GDK_IS_SURFACE (surface));
g_return_if_fail (formats != NULL);
g_clear_pointer (&surface->dmabuf_formats, gdk_dmabuf_formats_unref);
surface->dmabuf_formats = gdk_dmabuf_formats_ref (formats);
if (surface->subsurfaces_above == NULL)
{
GDK_DISPLAY_DEBUG (surface->display, DMABUF, "Using main surface formats");
gdk_surface_set_effective_dmabuf_formats (surface, formats);
}
}
void
gdk_surface_set_effective_dmabuf_formats (GdkSurface *surface,
GdkDmabufFormats *formats)
{
g_return_if_fail (GDK_IS_SURFACE (surface));
if (!formats)
return;
if (gdk_dmabuf_formats_equal (surface->effective_dmabuf_formats, formats))
{
GDK_DISPLAY_DEBUG (surface->display, DMABUF, "Formats unchanged");
return;
}
g_clear_pointer (&surface->effective_dmabuf_formats, gdk_dmabuf_formats_unref);
surface->effective_dmabuf_formats = gdk_dmabuf_formats_ref (formats);
g_object_notify_by_pspec (G_OBJECT (surface), properties[PROP_DMABUF_FORMATS]);
}
/**
* gdk_surface_get_dmabuf_formats:
* @surface: a `GdkSurface`
*
* Returns the dma-buf formats that are supported on this surface.
*
* What formats can be used may depend on the geometry and stacking
* order of the surface, and can change over time.
*
* The formats returned by this function can be used for negotiating
* buffer formats with producers such as v4l, pipewire or GStreamer.
*
* To learn more about dma-bufs, see [class@Gdk.DmabufTextureBuilder].
*
* Returns: (transfer none): a `GdkDmabufFormats` object
*
* Since: 4.14
*/
GdkDmabufFormats *
gdk_surface_get_dmabuf_formats (GdkSurface *surface)
{
g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL);
if (surface->effective_dmabuf_formats)
return surface->effective_dmabuf_formats;
else
return gdk_display_get_dmabuf_formats (surface->display);
}

View File

@@ -139,6 +139,9 @@ GdkVulkanContext *
gdk_surface_create_vulkan_context(GdkSurface *surface,
GError **error);
GdkDmabufFormats *
gdk_surface_get_dmabuf_formats (GdkSurface *surface);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GdkSurface, g_object_unref)
G_END_DECLS

View File

@@ -105,6 +105,9 @@ struct _GdkSurface
*/
GdkSubsurface *subsurfaces_above;
GdkSubsurface *subsurfaces_below;
GdkDmabufFormats *dmabuf_formats;
GdkDmabufFormats *effective_dmabuf_formats;
};
struct _GdkSurfaceClass
@@ -355,4 +358,10 @@ gsize gdk_surface_get_n_subsurfaces (GdkSurface *surface);
GdkSubsurface * gdk_surface_get_subsurface (GdkSurface *surface,
gsize idx);
void gdk_surface_set_dmabuf_formats (GdkSurface *surface,
GdkDmabufFormats *formats);
void gdk_surface_set_effective_dmabuf_formats (GdkSurface *surface,
GdkDmabufFormats *formats);
G_END_DECLS