Compare commits

...

9 Commits

Author SHA1 Message Date
Matthias Clasen
d0c9c66c38 gsk: Don't notify surface properties during render
The offloading may change subsurface stacking order, and thereby
change the effective dmabuf formats of the surface. But we don't
want to trigger callbacks during frame processing, so delay the
change notification until after we're done with that.
2024-04-27 19:58:19 -04:00
Matthias Clasen
349a29bb49 gstreamer: Use surface dmabuf formats
Use surface formats instead of display formats, for better results.

This does not pay attention to priorities yet, and renegotiation
is still missing.
2024-04-27 19:55:01 -04:00
Matthias Clasen
dbb890240a wayland: Hook up surface dmabuf feedback
Make the surface and subsurface code handle the dmabuf feedback,
and update the :dmabuf-formats property on the surface to reflect
the Wayland dmabuf information.
2024-04-27 19:55:01 -04:00
Matthias Clasen
ad636b2afb wayland: Hook up default dmabuf feedback
Keep the dmabuf formats from the default feedback events around
in the display, instead of just printing out debug spew.

The formats will be used in the future.
2024-04-27 19:55:01 -04:00
Matthias Clasen
66bc0c968f 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.
2024-04-27 19:54:59 -04:00
Matthias Clasen
3674497163 dmabuf: Add Wayland information
Add device and scanout information for dmabuf formats.

While this is not a great API, there is no good alternative to
making this information available to applications that want to
negotiate dmabuf formats suitable for graphics offload.

The getters for Wayland-specific information are kept as
Wayland backend apis.

Tests included.
2024-04-27 19:48:18 -04:00
Matthias Clasen
1217cc91d7 dmabuf: Redo format collection
Arrange for the following tranches to be collected With GL:
 - Regular EGL formats
 - Mmap formats (that aren't included already

And with GLES:
 - Regular EGL formats
 - External EGL formats
 - Mmap formats (that aren't included already

Also, move the debug spew for formats from the downloaders to the
display, so we can print them properly sorted, and in their tranches.
The only thing we don't have anymore here is the downloader name.
2024-04-27 19:13:13 -04:00
Matthias Clasen
4a8ecd4114 dmabuf: Add priorities to formats
This will be used to influence the sorting of formats, so we can
prefer 'native' formats over those that we can't import.

Test included.
2024-04-27 19:13:13 -04:00
Matthias Clasen
8182fb5704 dmabuf: Move a declaration
We will need to access this struct from the Wayland backend.
2024-04-27 19:13:13 -04:00
28 changed files with 844 additions and 119 deletions

View File

@@ -2004,6 +2004,7 @@ gdk_display_init_dmabuf (GdkDisplay *self)
#ifdef HAVE_EGL
gdk_display_add_dmabuf_downloader (self, gdk_dmabuf_get_egl_downloader (self, builder));
gdk_dmabuf_formats_builder_next_priority (builder);
#endif
gdk_dmabuf_formats_builder_add_formats (builder,
@@ -2016,6 +2017,29 @@ gdk_display_init_dmabuf (GdkDisplay *self)
GDK_DISPLAY_DEBUG (self, DMABUF,
"Initialized support for %zu dmabuf formats",
gdk_dmabuf_formats_get_n_formats (self->dmabuf_formats));
#ifdef G_ENABLE_DEBUG
if (GDK_DISPLAY_DEBUG_CHECK (self, DMABUF))
{
for (gsize i = 0; i < gdk_dmabuf_formats_get_n_formats (self->dmabuf_formats); i++)
{
guint32 fourcc;
guint64 modifier;
gdk_dmabuf_formats_get_format (self->dmabuf_formats, i, &fourcc, &modifier);
gdk_debug_message (" %.4s:%#" G_GINT64_MODIFIER "x%s",
(char *) &fourcc,
modifier,
gdk_dmabuf_formats_contains (self->egl_external_formats, fourcc, modifier) ? " (external)" : "");
if (i + 1 < gdk_dmabuf_formats_get_n_formats (self->dmabuf_formats) &&
gdk_dmabuf_formats_next_priority (self->dmabuf_formats, i) == i + 1)
gdk_debug_message ("------");
}
}
#endif
}
/**

View File

@@ -1965,10 +1965,6 @@ gdk_dmabuf_get_mmap_formats (void)
if (!supported_formats[i].download)
continue;
GDK_DEBUG (DMABUF,
"mmap dmabuf format %.4s:%#0" G_GINT64_MODIFIER "x",
(char *) &supported_formats[i].fourcc, (guint64) DRM_FORMAT_MOD_LINEAR);
gdk_dmabuf_formats_builder_add_format (builder,
supported_formats[i].fourcc,
DRM_FORMAT_MOD_LINEAR);

View File

@@ -93,24 +93,17 @@ gdk_dmabuf_egl_downloader_collect_formats (GdkDisplay *display,
for (int j = 0; j < num_modifiers; j++)
{
/* All linear formats we support are already added my the mmap downloader.
* We don't add external formats, unless we can use them (via GLES)
*/
if (modifiers[j] != DRM_FORMAT_MOD_LINEAR &&
(!external_only[j] || gdk_gl_context_get_use_es (context)))
if (!external_only[j])
{
GDK_DISPLAY_DEBUG (display, DMABUF,
"%s EGL dmabuf format %.4s:%#" G_GINT64_MODIFIER "x",
external_only[j] ? "external " : "",
(char *) &fourccs[i],
modifiers[j]);
gdk_dmabuf_formats_builder_add_format (formats, fourccs[i], modifiers[j]);
all_external = FALSE;
}
if (external_only[j])
gdk_dmabuf_formats_builder_add_format (external, fourccs[i], modifiers[j]);
else
all_external = FALSE;
{
if (gdk_gl_context_get_use_es (context))
gdk_dmabuf_formats_builder_add_format (external, fourccs[i], modifiers[j]);
}
}
/* Accept implicit modifiers as long as we accept the format at all.
@@ -120,9 +113,9 @@ gdk_dmabuf_egl_downloader_collect_formats (GdkDisplay *display,
* As an extra wrinkle, treat the implicit modifier as 'external only'
* if all formats with the same fourcc are 'external only'.
*/
if (!all_external || gdk_gl_context_get_use_es (context))
if (!all_external)
gdk_dmabuf_formats_builder_add_format (formats, fourccs[i], DRM_FORMAT_MOD_INVALID);
if (all_external)
else if (gdk_gl_context_get_use_es (context))
gdk_dmabuf_formats_builder_add_format (external, fourccs[i], DRM_FORMAT_MOD_INVALID);
}
@@ -149,6 +142,7 @@ GdkDmabufDownloader *
gdk_dmabuf_get_egl_downloader (GdkDisplay *display,
GdkDmabufFormatsBuilder *builder)
{
GdkGLContext *context;
GdkDmabufFormatsBuilder *formats;
GdkDmabufFormatsBuilder *external;
gboolean retval = FALSE;
@@ -163,6 +157,8 @@ gdk_dmabuf_get_egl_downloader (GdkDisplay *display,
return NULL;
previous = gdk_gl_context_get_current ();
context = gdk_display_get_gl_context (display);
formats = gdk_dmabuf_formats_builder_new ();
external = gdk_dmabuf_formats_builder_new ();
@@ -172,6 +168,11 @@ gdk_dmabuf_get_egl_downloader (GdkDisplay *display,
display->egl_external_formats = gdk_dmabuf_formats_builder_free_to_formats (external);
gdk_dmabuf_formats_builder_add_formats (builder, display->egl_dmabuf_formats);
if (gdk_gl_context_get_use_es (context))
{
gdk_dmabuf_formats_builder_next_priority (builder);
gdk_dmabuf_formats_builder_add_formats (builder, display->egl_external_formats);
}
if (!retval)
{

View File

@@ -49,14 +49,6 @@
* Since: 4.14
*/
struct _GdkDmabufFormats
{
int ref_count;
gsize n_formats;
GdkDmabufFormat *formats;
};
G_DEFINE_BOXED_TYPE (GdkDmabufFormats, gdk_dmabuf_formats, gdk_dmabuf_formats_ref, gdk_dmabuf_formats_unref)
/**
@@ -152,7 +144,36 @@ gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats,
}
/**
* gdk_dmabuf_formats_contains:
* gdk_dmabuf_formats_next_priority:
* @formats: a `GdkDmabufFormats`
* @idx: the index of the format to query
*
* Returns the index of the next-lower-priority format.
*
* The formats in a `GdkDmabufFormats` are sorted by decreasing
* priority. This function lets you identify formats with the
* same priority: all the formats between @idx and the return
* value of this function have the same priority.
*
* Returns: the index of the next lower priority format
*
* Since: 4.16
*/
gsize
gdk_dmabuf_formats_next_priority (GdkDmabufFormats *formats,
gsize idx)
{
GdkDmabufFormat *format;
g_return_val_if_fail (idx < formats->n_formats, G_MAXSIZE);
format = &formats->formats[idx];
return format->next_priority;
}
/**
* gdk_dmabuf_format_contains:
* @formats: a `GdkDmabufFormats`
* @fourcc: a format code
* @modifier: a format modifier
@@ -184,6 +205,8 @@ gdk_dmabuf_formats_contains (GdkDmabufFormats *formats,
* gdk_dmabuf_formats_new:
* @formats: the formats
* @n_formats: the length of @formats
* @device: the DRM device that the compositor uses, or
* 0 if this object doesn't describe compositor formats
*
* Creates a new `GdkDmabufFormats struct for
* the given formats.
@@ -197,7 +220,8 @@ gdk_dmabuf_formats_contains (GdkDmabufFormats *formats,
*/
GdkDmabufFormats *
gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
gsize n_formats)
gsize n_formats,
guint64 device)
{
GdkDmabufFormats *self;
@@ -206,6 +230,7 @@ gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
self->ref_count = 1;
self->n_formats = n_formats;
self->formats = g_new (GdkDmabufFormat, n_formats);
self->device = device;
memcpy (self->formats, formats, n_formats * sizeof (GdkDmabufFormat));
@@ -240,6 +265,9 @@ gdk_dmabuf_formats_equal (const GdkDmabufFormats *formats1,
if (formats1 == NULL || formats2 == NULL)
return FALSE;
if (formats1->device != formats2->device)
return FALSE;
if (formats1->n_formats != formats2->n_formats)
return FALSE;
@@ -249,7 +277,10 @@ gdk_dmabuf_formats_equal (const GdkDmabufFormats *formats1,
GdkDmabufFormat *f2 = &formats2->formats[i];
if (f1->fourcc != f2->fourcc ||
f1->modifier != f2->modifier)
f1->modifier != f2->modifier ||
f1->next_priority != f2->next_priority ||
f1->flags != f2->flags ||
f1->device != f2->device)
return FALSE;
}

View File

@@ -46,6 +46,10 @@ void gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats
guint32 *fourcc,
guint64 *modifier);
GDK_AVAILABLE_IN_4_16
gsize gdk_dmabuf_formats_next_priority (GdkDmabufFormats *formats,
gsize idx);
GDK_AVAILABLE_IN_4_14
gboolean gdk_dmabuf_formats_contains (GdkDmabufFormats *formats,
guint32 fourcc,

View File

@@ -52,7 +52,9 @@ gdk_dmabuf_format_compare (gconstpointer data_a,
const GdkDmabufFormat *a = data_a;
const GdkDmabufFormat *b = data_b;
if (a->fourcc == b->fourcc)
if (a->next_priority != b->next_priority)
return (a->next_priority < b->next_priority) ? -1 : 1;
else if (a->fourcc == b->fourcc)
return (a->modifier - b->modifier) >> 8 * (sizeof (gint64) - sizeof (gint));
else
return a->fourcc - b->fourcc;
@@ -67,7 +69,9 @@ gdk_dmabuf_format_equal (gconstpointer data_a,
const GdkDmabufFormat *b = data_b;
return a->fourcc == b->fourcc &&
a->modifier == b->modifier;
a->flags == b->flags &&
a->modifier == b->modifier &&
a->device == b->device;
}
static void
@@ -79,38 +83,46 @@ gdk_dmabuf_formats_builder_sort (GdkDmabufFormatsBuilder *self)
gdk_dmabuf_format_compare);
}
/* list must be sorted */
static void
gdk_dmabuf_formats_builder_remove_duplicates (GdkDmabufFormatsBuilder *self)
GdkDmabufFormats *
gdk_dmabuf_formats_builder_free_to_formats_for_device (GdkDmabufFormatsBuilder *self,
guint64 device)
{
gsize i, j;
GdkDmabufFormats *formats;
for (i = 1, j = 0; i < gdk_dmabuf_formats_builder_get_size (self); i++)
{
if (gdk_dmabuf_format_equal (gdk_dmabuf_formats_builder_get (self, i),
gdk_dmabuf_formats_builder_get (self, j)))
continue;
gdk_dmabuf_formats_builder_next_priority (self);
gdk_dmabuf_formats_builder_sort (self);
j++;
if (i != j)
*gdk_dmabuf_formats_builder_index (self, j) = *gdk_dmabuf_formats_builder_index (self, i);
}
formats = gdk_dmabuf_formats_new (gdk_dmabuf_formats_builder_get_data (self),
gdk_dmabuf_formats_builder_get_size (self),
device);
gdk_dmabuf_formats_builder_clear (self);
g_free (self);
return formats;
}
GdkDmabufFormats *
gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self)
{
GdkDmabufFormats *formats;
return gdk_dmabuf_formats_builder_free_to_formats_for_device (self, 0);
}
gdk_dmabuf_formats_builder_sort (self);
gdk_dmabuf_formats_builder_remove_duplicates (self);
void
gdk_dmabuf_formats_builder_add_format_for_device (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint32 flags,
guint64 modifier,
guint64 device)
{
GdkDmabufFormat format = { fourcc, flags, modifier, device, G_MAXSIZE };
formats = gdk_dmabuf_formats_new (gdk_dmabuf_formats_builder_get_data (self),
gdk_dmabuf_formats_builder_get_size (self));
gdk_dmabuf_formats_builder_clear (self);
g_free (self);
for (gsize i = 0; i < gdk_dmabuf_formats_builder_get_size (self); i++)
{
if (gdk_dmabuf_format_equal (gdk_dmabuf_formats_builder_get (self, i), &format))
return;
}
return formats;
gdk_dmabuf_formats_builder_append (self, &format);
}
void
@@ -118,17 +130,33 @@ gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint64 modifier)
{
gdk_dmabuf_formats_builder_append (self, &(GdkDmabufFormat) { fourcc, modifier });
gdk_dmabuf_formats_builder_add_format_for_device (self, fourcc, 0, modifier, 0);
}
void
gdk_dmabuf_formats_builder_next_priority (GdkDmabufFormatsBuilder *self)
{
for (gsize i = gdk_dmabuf_formats_builder_get_size (self); i > 0; i--)
{
GdkDmabufFormat *format = gdk_dmabuf_formats_builder_get (self, i - 1);
if (format->next_priority != G_MAXSIZE)
break;
format->next_priority = gdk_dmabuf_formats_builder_get_size (self);
}
}
void
gdk_dmabuf_formats_builder_add_formats (GdkDmabufFormatsBuilder *self,
GdkDmabufFormats *formats)
{
gdk_dmabuf_formats_builder_splice (self,
gdk_dmabuf_formats_builder_get_size (self),
0,
FALSE,
gdk_dmabuf_formats_peek_formats (formats),
gdk_dmabuf_formats_get_n_formats (formats));
for (gsize i = 0; i < gdk_dmabuf_formats_get_n_formats (formats); i++)
{
guint32 fourcc;
guint64 modifier;
gdk_dmabuf_formats_get_format (formats, i, &fourcc, &modifier);
gdk_dmabuf_formats_builder_add_format (self, fourcc, modifier);
}
}

View File

@@ -4,11 +4,21 @@
typedef struct GdkDmabufFormatsBuilder GdkDmabufFormatsBuilder;
GdkDmabufFormatsBuilder * gdk_dmabuf_formats_builder_new (void);
GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self);
GdkDmabufFormatsBuilder *gdk_dmabuf_formats_builder_new (void);
GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self);
void gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint64 modifier);
void gdk_dmabuf_formats_builder_add_formats (GdkDmabufFormatsBuilder *self,
GdkDmabufFormats *formats);
void gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint64 modifier);
GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats_for_device (GdkDmabufFormatsBuilder *self,
guint64 device);
void gdk_dmabuf_formats_builder_add_format_for_device (GdkDmabufFormatsBuilder *self,
guint32 fourcc,
guint32 flags,
guint64 modifier,
guint64 device);
void gdk_dmabuf_formats_builder_next_priority (GdkDmabufFormatsBuilder *self);
void gdk_dmabuf_formats_builder_add_formats (GdkDmabufFormatsBuilder *self,
GdkDmabufFormats *formats);

View File

@@ -6,10 +6,23 @@ typedef struct _GdkDmabufFormat GdkDmabufFormat;
struct _GdkDmabufFormat
{
guint32 fourcc;
guint32 flags;
guint64 modifier;
guint64 device;
gsize next_priority;
};
struct _GdkDmabufFormats
{
int ref_count;
gsize n_formats;
GdkDmabufFormat *formats;
guint64 device;
};
GdkDmabufFormats * gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
gsize n_formats);
gsize n_formats,
guint64 device);
const GdkDmabufFormat * gdk_dmabuf_formats_peek_formats (GdkDmabufFormats *self);

View File

@@ -21,6 +21,7 @@
#include "gdksurfaceprivate.h"
#include "gdktexture.h"
#include "gsk/gskrectprivate.h"
#include "gdkdebugprivate.h"
G_DEFINE_TYPE (GdkSubsurface, gdk_subsurface, G_TYPE_OBJECT)
@@ -36,6 +37,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);
}
@@ -116,6 +118,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;
}
/*< private >
* gdk_subsurface_attach:
* @subsurface: the `GdkSubsurface`
@@ -150,7 +174,7 @@ gdk_subsurface_attach (GdkSubsurface *subsurface,
GdkSubsurface *sibling)
{
GdkSurface *parent = subsurface->parent;
gboolean result;
gboolean was_topmost, is_topmost, result;
g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), FALSE);
g_return_val_if_fail (GDK_IS_TEXTURE (texture), FALSE);
@@ -164,6 +188,8 @@ gdk_subsurface_attach (GdkSubsurface *subsurface,
g_return_val_if_fail (sibling == NULL || GDK_IS_SUBSURFACE (sibling), FALSE);
g_return_val_if_fail (sibling == NULL || sibling->parent == subsurface->parent, FALSE);
was_topmost = is_topmost_subsurface (subsurface);
result = GDK_SUBSURFACE_GET_CLASS (subsurface)->attach (subsurface,
texture,
source,
@@ -198,6 +224,29 @@ 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 result;
}
@@ -212,10 +261,25 @@ gdk_subsurface_attach (GdkSubsurface *subsurface,
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);
}
@@ -370,3 +434,17 @@ gdk_subsurface_get_bounds (GdkSubsurface *subsurface,
if (gdk_subsurface_get_background_rect (subsurface, &background))
graphene_rect_union (bounds, &background, bounds);
}
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 (subsurface->parent && 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;
};
typedef enum {
@@ -109,6 +112,8 @@ gboolean gdk_subsurface_get_background_rect (GdkSubsurface *subsu
graphene_rect_t *rect);
void gdk_subsurface_get_bounds (GdkSubsurface *subsurface,
graphene_rect_t *bounds);
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 its subsurfaces, 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.16
*/
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,10 @@ GdkVulkanContext *
gdk_surface_create_vulkan_context(GdkSurface *surface,
GError **error);
GDK_AVAILABLE_IN_4_16
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

View File

@@ -337,6 +337,16 @@ static void gdk_wayland_display_remove_output (GdkWaylandDisplay *display_wa
static void gdk_wayland_display_init_xdg_output (GdkWaylandDisplay *display_wayland);
static void gdk_wayland_display_get_xdg_output (GdkWaylandMonitor *monitor);
static void
dmabuf_formats_callback (gpointer data,
DmabufFormatsInfo *info)
{
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (data);
g_clear_pointer (&display_wayland->wayland_dmabuf_formats, gdk_dmabuf_formats_unref);
display_wayland->wayland_dmabuf_formats = gdk_dmabuf_formats_ref (info->formats);
}
static void
gdk_registry_handle_global (void *data,
struct wl_registry *registry,
@@ -370,7 +380,10 @@ gdk_registry_handle_global (void *data,
feedback = zwp_linux_dmabuf_v1_get_default_feedback (display_wayland->linux_dmabuf);
display_wayland->dmabuf_formats_info = dmabuf_formats_info_new (GDK_DISPLAY (display_wayland),
"default",
feedback);
NULL,
feedback,
dmabuf_formats_callback,
display_wayland);
_gdk_wayland_display_async_roundtrip (display_wayland);
}
else if (strcmp (interface, "xdg_wm_base") == 0)
@@ -744,6 +757,7 @@ gdk_wayland_display_dispose (GObject *object)
g_clear_pointer (&display_wayland->single_pixel_buffer, wp_single_pixel_buffer_manager_v1_destroy);
g_clear_pointer (&display_wayland->linux_dmabuf, zwp_linux_dmabuf_v1_destroy);
g_clear_pointer (&display_wayland->dmabuf_formats_info, dmabuf_formats_info_free);
g_clear_pointer (&display_wayland->wayland_dmabuf_formats, gdk_dmabuf_formats_unref);
g_clear_pointer (&display_wayland->shm, wl_shm_destroy);
g_clear_pointer (&display_wayland->wl_registry, wl_registry_destroy);

View File

@@ -100,6 +100,7 @@ struct _GdkWaylandDisplay
struct wl_shm *shm;
struct zwp_linux_dmabuf_v1 *linux_dmabuf;
DmabufFormatsInfo *dmabuf_formats_info;
GdkDmabufFormats *wayland_dmabuf_formats;
struct xdg_wm_base *xdg_wm_base;
struct zxdg_shell_v6 *zxdg_shell_v6;
struct gtk_shell1 *gtk_shell;

View File

@@ -54,24 +54,40 @@ typedef struct
typedef struct DmabufFormatsInfo DmabufFormatsInfo;
typedef void (* DmabufFormatsUpdateCallback) (gpointer data,
DmabufFormatsInfo *formats);
struct DmabufFormatsInfo
{
GdkDisplay *display;
char *name;
struct zwp_linux_dmabuf_feedback_v1 *feedback;
DmabufFormatsUpdateCallback callback;
gpointer data;
gsize n_dmabuf_formats;
DmabufFormat *dmabuf_format_table;
DmabufFormats *dmabuf_formats;
DmabufFormats *pending_dmabuf_formats;
DmabufTranche *pending_tranche;
GdkDmabufFormats *egl_formats;
GdkDmabufFormats *formats;
};
DmabufFormatsInfo * dmabuf_formats_info_new (GdkDisplay *display,
const char *name,
struct zwp_linux_dmabuf_feedback_v1 *feedback);
GdkDmabufFormats *egl_formats,
struct zwp_linux_dmabuf_feedback_v1 *feedback,
DmabufFormatsUpdateCallback callback,
gpointer data);
void dmabuf_formats_info_free (DmabufFormatsInfo *info);
void dmabuf_formats_info_set_egl_formats
(DmabufFormatsInfo *info,
GdkDmabufFormats *egl_formats);
G_END_DECLS

View File

@@ -1,6 +1,7 @@
#include "config.h"
#include "gdkdmabuf-wayland-private.h"
#include "gdkwaylanddmabufformats.h"
#include "gdkdebugprivate.h"
#include "gdkdmabufformatsprivate.h"
@@ -45,44 +46,116 @@ dmabuf_formats_free (DmabufFormats *formats)
g_free (formats);
}
static void
update_dmabuf_formats (DmabufFormatsInfo *info)
static gboolean
is_in_tranche (GdkDmabufFormats *formats,
gsize idx,
guint32 fourcc,
guint64 modifier)
{
DmabufFormats *formats = info->dmabuf_formats;
gsize end;
guint32 f;
guint64 m;
GDK_DISPLAY_DEBUG (info->display, MISC,
"dmabuf format table (%lu entries)", info->n_dmabuf_formats);
GDK_DISPLAY_DEBUG (info->display, MISC,
"dmabuf main device: %u %u",
major (formats->main_device),
minor (formats->main_device));
for (gsize i = 0; i < formats->tranches->len; i++)
end = gdk_dmabuf_formats_next_priority (formats, idx);
for (gsize i = idx; i < end; i++)
{
DmabufTranche *tranche = g_ptr_array_index (formats->tranches, i);
gdk_dmabuf_formats_get_format (formats, i, &f, &m);
if (f == fourcc && m == modifier)
return TRUE;
}
GDK_DISPLAY_DEBUG (info->display, MISC,
"dmabuf tranche target device: %u %u",
major (tranche->target_device),
minor (tranche->target_device));
return FALSE;
}
GDK_DISPLAY_DEBUG (info->display, MISC,
"dmabuf%s tranche (%lu entries):",
tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT ? " scanout" : "",
tranche->n_formats);
static void
gdk_wayland_dmabuf_formats_dump (GdkDmabufFormats *formats,
const char *name)
{
gdk_debug_message ("Wayland %s dmabuf formats: (%lu entries)", name, formats->n_formats);
gdk_debug_message ("Main device: %u %u",
major (formats->device),
minor (formats->device));
for (gsize j = 0; j < tranche->n_formats; j++)
gsize i = 0;
while (i < formats->n_formats)
{
GdkDmabufFormat *format = &formats->formats[i];
gsize next_priority = format->next_priority;
if (i > 0)
gdk_debug_message ("------");
gdk_debug_message ("Tranche target device: %u %u",
major (format->device),
minor (format->device));
if (format->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT)
gdk_debug_message ("Tranche is scanout");
gdk_debug_message ("Tranche formats (%lu entries)", next_priority - i);
for (; i < next_priority; i++)
{
GDK_DISPLAY_DEBUG (info->display, MISC,
" %.4s:%#" G_GINT64_MODIFIER "x",
(char *) &(tranche->formats[j].fourcc),
tranche->formats[j].modifier);
format = &formats->formats[i];
gdk_debug_message (" %.4s:%#" G_GINT64_MODIFIER "x", (char *) &format->fourcc, format->modifier);
}
}
}
static void
linux_dmabuf_done (void *data,
update_dmabuf_formats (DmabufFormatsInfo *info)
{
GdkDmabufFormatsBuilder *builder;
GdkDmabufFormats *egl_formats = info->egl_formats;
DmabufFormats *formats = info->dmabuf_formats;
builder = gdk_dmabuf_formats_builder_new ();
for (gsize i = 0; i < formats->tranches->len; i++)
{
DmabufTranche *tranche = g_ptr_array_index (formats->tranches, i);
if (egl_formats)
{
for (gsize k = 0; k < gdk_dmabuf_formats_get_n_formats (egl_formats); k = gdk_dmabuf_formats_next_priority (egl_formats, k))
{
for (gsize j = 0; j < tranche->n_formats; j++)
{
if (is_in_tranche (egl_formats, k,
tranche->formats[j].fourcc,
tranche->formats[j].modifier))
gdk_dmabuf_formats_builder_add_format_for_device (builder,
tranche->formats[j].fourcc,
tranche->flags,
tranche->formats[j].modifier,
tranche->target_device);
}
gdk_dmabuf_formats_builder_next_priority (builder);
}
}
else
{
for (gsize j = 0; j < tranche->n_formats; j++)
{
gdk_dmabuf_formats_builder_add_format_for_device (builder,
tranche->formats[j].fourcc,
tranche->flags,
tranche->formats[j].modifier,
tranche->target_device);
}
gdk_dmabuf_formats_builder_next_priority (builder);
}
}
g_clear_pointer (&info->formats, gdk_dmabuf_formats_unref);
info->formats = gdk_dmabuf_formats_builder_free_to_formats_for_device (builder, formats->main_device);
if (GDK_DISPLAY_DEBUG_CHECK (info->display, DMABUF))
gdk_wayland_dmabuf_formats_dump (info->formats, info->name);
info->callback (info->data, info);
}
static void
linux_dmabuf_done (void *data,
struct zwp_linux_dmabuf_feedback_v1 *feedback)
{
DmabufFormatsInfo *info = data;
@@ -96,10 +169,10 @@ linux_dmabuf_done (void *data,
}
static void
linux_dmabuf_format_table (void *data,
linux_dmabuf_format_table (void *data,
struct zwp_linux_dmabuf_feedback_v1 *feedback,
int32_t fd,
uint32_t size)
int32_t fd,
uint32_t size)
{
DmabufFormatsInfo *info = data;
@@ -111,9 +184,9 @@ linux_dmabuf_format_table (void *data,
}
static void
linux_dmabuf_main_device (void *data,
linux_dmabuf_main_device (void *data,
struct zwp_linux_dmabuf_feedback_v1 *feedback,
struct wl_array *device)
struct wl_array *device)
{
DmabufFormatsInfo *info = data;
dev_t dev;
@@ -127,7 +200,7 @@ linux_dmabuf_main_device (void *data,
}
static void
linux_dmabuf_tranche_done (void *data,
linux_dmabuf_tranche_done (void *data,
struct zwp_linux_dmabuf_feedback_v1 *feedback)
{
DmabufFormatsInfo *info = data;
@@ -139,9 +212,9 @@ linux_dmabuf_tranche_done (void *data,
}
static void
linux_dmabuf_tranche_target_device (void *data,
linux_dmabuf_tranche_target_device (void *data,
struct zwp_linux_dmabuf_feedback_v1 *feedback,
struct wl_array *device)
struct wl_array *device)
{
DmabufFormatsInfo *info = data;
dev_t dev;
@@ -158,9 +231,9 @@ linux_dmabuf_tranche_target_device (void *data,
}
static void
linux_dmabuf_tranche_formats (void *data,
linux_dmabuf_tranche_formats (void *data,
struct zwp_linux_dmabuf_feedback_v1 *feedback,
struct wl_array *indices)
struct wl_array *indices)
{
DmabufFormatsInfo *info = data;
DmabufTranche *tranche;
@@ -181,9 +254,9 @@ linux_dmabuf_tranche_formats (void *data,
}
static void
linux_dmabuf_tranche_flags (void *data,
linux_dmabuf_tranche_flags (void *data,
struct zwp_linux_dmabuf_feedback_v1 *feedback,
uint32_t flags)
uint32_t flags)
{
DmabufFormatsInfo *info = data;
DmabufTranche *tranche;
@@ -206,7 +279,10 @@ static const struct zwp_linux_dmabuf_feedback_v1_listener feedback_listener = {
DmabufFormatsInfo *
dmabuf_formats_info_new (GdkDisplay *display,
const char *name,
struct zwp_linux_dmabuf_feedback_v1 *feedback)
GdkDmabufFormats *egl_formats,
struct zwp_linux_dmabuf_feedback_v1 *feedback,
DmabufFormatsUpdateCallback callback,
gpointer data)
{
DmabufFormatsInfo *info;
@@ -214,11 +290,21 @@ dmabuf_formats_info_new (GdkDisplay *display,
info->display = display;
info->name = g_strdup (name);
if (egl_formats)
{
info->egl_formats = gdk_dmabuf_formats_ref (egl_formats);
info->formats = gdk_dmabuf_formats_ref (egl_formats);
}
info->feedback = feedback;
info->callback = callback;
info->data = data;
if (info->feedback)
zwp_linux_dmabuf_feedback_v1_add_listener (info->feedback,
&feedback_listener, info);
else
info->callback (info->data, info);
return info;
}
@@ -227,6 +313,8 @@ void
dmabuf_formats_info_free (DmabufFormatsInfo *info)
{
g_free (info->name);
g_clear_pointer (&info->formats, gdk_dmabuf_formats_unref);
g_clear_pointer (&info->egl_formats, gdk_dmabuf_formats_unref);
g_clear_pointer (&info->feedback, zwp_linux_dmabuf_feedback_v1_destroy);
if (info->dmabuf_format_table)
{
@@ -239,3 +327,91 @@ dmabuf_formats_info_free (DmabufFormatsInfo *info)
g_free (info);
}
void
dmabuf_formats_info_set_egl_formats (DmabufFormatsInfo *info,
GdkDmabufFormats *egl_formats)
{
if (info->egl_formats)
return;
info->egl_formats = gdk_dmabuf_formats_ref (egl_formats);
if (info->dmabuf_formats)
update_dmabuf_formats (info);
}
/**
* gdk_wayland_dmabuf_formats_get_main_device:
* @formats: a `GdkDmabufFormats`
*
* Returns the DRM device that the compositor uses for compositing.
*
* If this information isn't available (e.g. because @formats wasn't
* obtained from the compositor), then 0 is returned.
*
* Returns: the main DRM device that the compositor prefers
*
* Since: 4.16
*/
dev_t
gdk_wayland_dmabuf_formats_get_main_device (GdkDmabufFormats *formats)
{
return formats->device;
}
/**
* gdk_wayland_dmabuf_formats_get_target_device:
* @formats: a `GdkDmabufFormats`
* @idx: the index of the format to return
*
* Returns the target DRM device that should be used for creating buffers
* with this format.
*
* If this information isn't available (e.g. because @formats wasn't
* obtained from the compositor), then 0 is returned.
*
* Returns: the target DRM device for this format
*
* Since: 4.16
*/
dev_t
gdk_wayland_dmabuf_formats_get_target_device (GdkDmabufFormats *formats,
gsize idx)
{
GdkDmabufFormat *format;
g_return_val_if_fail (idx < formats->n_formats, 0);
format = &formats->formats[idx];
return format->device;
}
/**
* gdk_wayland_dmabuf_formats_is_scanout:
* @formats: a `GdkDmabufFormats`
* @idx: the index of the format to return
*
* Returns whether the compositor may use buffers with this
* format for scanout.
*
* If this information isn't available (e.g. because @formats wasn't
* obtained from the compositor), then `FALSE` is returned.
*
* Returns: whether the format will be used for scanout
*
* Since: 4.16
*/
gboolean
gdk_wayland_dmabuf_formats_is_scanout (GdkDmabufFormats *formats,
gsize idx)
{
GdkDmabufFormat *format;
g_return_val_if_fail (idx < formats->n_formats, FALSE);
format = &formats->formats[idx];
return (format->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT) != 0;
}

View File

@@ -1,6 +1,8 @@
#pragma once
#include "gdk/gdkdmabufformats.h"
#include "gdksubsurfaceprivate.h"
#include "gdkdmabuf-wayland-private.h"
#include "wayland-client-protocol.h"
@@ -35,6 +37,8 @@ struct _GdkWaylandSubsurface
struct wp_viewport *bg_viewport;
cairo_rectangle_int_t bg_rect;
gboolean bg_attached;
DmabufFormatsInfo *formats;
};
struct _GdkWaylandSubsurfaceClass
@@ -48,4 +52,3 @@ void gdk_wayland_subsurface_request_frame (GdkSubsurface *subsurface);
void gdk_wayland_subsurface_clear_frame_callback (GdkSubsurface *subsurface);
GdkSubsurface * gdk_wayland_surface_create_subsurface (GdkSurface *surface);

View File

@@ -27,6 +27,7 @@
#include "gdksubsurfaceprivate.h"
#include "gdkdebugprivate.h"
#include "gsk/gskrectprivate.h"
#include "gdkprivate.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
@@ -51,6 +52,7 @@ gdk_wayland_subsurface_finalize (GObject *object)
g_clear_pointer (&self->bg_viewport, wp_viewport_destroy);
g_clear_pointer (&self->bg_subsurface, wl_subsurface_destroy);
g_clear_pointer (&self->bg_surface, wl_surface_destroy);
g_clear_pointer (&self->formats, dmabuf_formats_info_free);
G_OBJECT_CLASS (gdk_wayland_subsurface_parent_class)->finalize (object);
}
@@ -790,6 +792,15 @@ gdk_wayland_subsurface_clear_frame_callback (GdkSubsurface *sub)
g_clear_pointer (&self->frame_callback, wl_callback_destroy);
}
static void
dmabuf_formats_callback (gpointer data,
DmabufFormatsInfo *info)
{
GdkSubsurface *sub = data;
gdk_subsurface_set_dmabuf_formats (sub, info->formats);
}
GdkSubsurface *
gdk_wayland_surface_create_subsurface (GdkSurface *surface)
{
@@ -798,6 +809,8 @@ gdk_wayland_surface_create_subsurface (GdkSurface *surface)
GdkWaylandDisplay *disp = GDK_WAYLAND_DISPLAY (display);
GdkWaylandSubsurface *sub;
struct wl_region *region;
struct zwp_linux_dmabuf_feedback_v1 *feedback;
char *name;
if (disp->subcompositor == NULL || disp->viewporter == NULL)
{
@@ -825,8 +838,28 @@ gdk_wayland_surface_create_subsurface (GdkSurface *surface)
wl_region_add (sub->opaque_region, 0, 0, G_MAXINT, G_MAXINT);
wl_surface_set_opaque_region (sub->surface, sub->opaque_region);
gdk_display_init_dmabuf (display);
if (disp->linux_dmabuf)
{
dmabuf_formats_info_set_egl_formats (disp->dmabuf_formats_info, display->dmabuf_formats);
feedback = zwp_linux_dmabuf_v1_get_surface_feedback (disp->linux_dmabuf, sub->surface);
}
else
{
feedback = NULL;
}
name = g_strdup_printf ("subsurface %p", sub);
sub->formats = dmabuf_formats_info_new (display,
name,
display->dmabuf_formats,
feedback,
dmabuf_formats_callback,
sub);
g_free (name);
GDK_DISPLAY_DEBUG (display, OFFLOAD, "Subsurface %p of surface %p created", sub, impl);
return GDK_SUBSURFACE (sub);
}

View File

@@ -89,6 +89,8 @@ struct _GdkWaylandSurface
uint32_t last_configure_serial;
int state_freeze_count;
DmabufFormatsInfo *formats;
};
typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass;

View File

@@ -936,6 +936,15 @@ gdk_wayland_surface_create_wl_surface (GdkSurface *surface)
self->display_server.wl_surface = wl_surface;
}
static void
dmabuf_formats_callback (gpointer data,
DmabufFormatsInfo *info)
{
GdkSurface *surface = data;
gdk_surface_set_dmabuf_formats (surface, info->formats);
}
static void
gdk_wayland_surface_constructed (GObject *object)
{
@@ -944,6 +953,8 @@ gdk_wayland_surface_constructed (GObject *object)
GdkDisplay *display = gdk_surface_get_display (surface);
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (surface);
struct zwp_linux_dmabuf_feedback_v1 *feedback;
char *name;
self->event_queue = wl_display_create_queue (display_wayland->wl_display);
display_wayland->event_queues = g_list_prepend (display_wayland->event_queues,
@@ -969,6 +980,29 @@ gdk_wayland_surface_constructed (GObject *object)
gdk_wayland_surface_create_wl_surface (surface);
gdk_display_init_dmabuf (display);
if (display_wayland->linux_dmabuf)
{
dmabuf_formats_info_set_egl_formats (display_wayland->dmabuf_formats_info,
display->dmabuf_formats);
feedback = zwp_linux_dmabuf_v1_get_surface_feedback (display_wayland->linux_dmabuf,
self->display_server.wl_surface);
}
else
{
feedback = NULL;
}
name = g_strdup_printf ("surface %p", surface);
self->formats = dmabuf_formats_info_new (display,
name,
display->dmabuf_formats,
feedback,
dmabuf_formats_callback,
surface);
g_free (name);
g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface);
g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), surface);

View File

@@ -30,6 +30,7 @@
#include <gdk/wayland/gdkwaylanddevice.h>
#include <gdk/wayland/gdkwaylanddisplay.h>
#include <gdk/wayland/gdkwaylanddmabufformats.h>
#include <gdk/wayland/gdkwaylandglcontext.h>
#include <gdk/wayland/gdkwaylandmonitor.h>
#include <gdk/wayland/gdkwaylandpopup.h>

View File

@@ -0,0 +1,40 @@
/* gdkwaylanddmabufformats.h
*
* Copyright 2023 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GDKWAYLAND_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/wayland/gdkwayland.h> can be included directly."
#endif
#include <gdk/gdkdmabufformats.h>
G_BEGIN_DECLS
GDK_AVAILABLE_IN_4_16
dev_t gdk_wayland_dmabuf_formats_get_main_device (GdkDmabufFormats *formats);
GDK_AVAILABLE_IN_4_16
dev_t gdk_wayland_dmabuf_formats_get_target_device (GdkDmabufFormats *formats,
gsize idx);
GDK_AVAILABLE_IN_4_16
gboolean gdk_wayland_dmabuf_formats_is_scanout (GdkDmabufFormats *formats,
gsize idx);
G_END_DECLS

View File

@@ -30,6 +30,7 @@ gdk_wayland_sources = files([
gdk_wayland_public_headers = files([
'gdkwaylanddevice.h',
'gdkwaylanddisplay.h',
'gdkwaylanddmabufformats.h',
'gdkwaylandglcontext.h',
'gdkwaylandmonitor.h',
'gdkwaylandpopup.h',

View File

@@ -483,6 +483,12 @@ gsk_renderer_render (GskRenderer *renderer,
if (priv->surface == NULL)
return;
/* Offloading can change subsurface stacking, which may trigger
* surface property changes. We don't want them to take effect
* during frame processing.
*/
g_object_freeze_notify (G_OBJECT (priv->surface));
renderer_class = GSK_RENDERER_GET_CLASS (renderer);
clip = cairo_region_copy (region);
@@ -528,6 +534,8 @@ gsk_renderer_render (GskRenderer *renderer,
cairo_region_destroy (clip);
g_clear_pointer (&offload, gsk_offload_free);
priv->prev_node = gsk_render_node_ref (root);
g_object_thaw_notify (G_OBJECT (priv->surface));
}
/*< private >

View File

@@ -132,12 +132,15 @@ gtk_gst_paintable_video_renderer_create_video_sink (GstPlayerVideoRenderer *rend
GstPlayer *player)
{
GtkGstPaintable *self = GTK_GST_PAINTABLE (renderer);
GdkDmabufFormats *dmabuf_formats;
GstElement *sink;
GdkGLContext *ctx;
dmabuf_formats = gdk_display_get_dmabuf_formats (gdk_display_get_default ());
sink = g_object_new (GTK_TYPE_GST_SINK,
"paintable", self,
"gl-context", self->context,
"dmabuf-formats", dmabuf_formats,
NULL);
if (self->context != NULL)

View File

@@ -178,13 +178,12 @@ gtk_gst_sink_get_caps (GstBaseSink *bsink,
{
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
#ifdef HAVE_GSTREAMER_DRM
{
GdkDisplay *display = gdk_gl_context_get_display (self->gdk_context);
GdkDmabufFormats *formats = gdk_display_get_dmabuf_formats (display);
GdkSurface *surface;
tmp = gst_caps_make_writable (tmp);
add_drm_formats_and_modifiers (tmp, formats);
}
tmp = gst_caps_make_writable (tmp);
surface = gdk_gl_context_get_surface (self->gdk_context);
add_drm_formats_and_modifiers (tmp, gdk_surface_get_dmabuf_formats (surface));
#endif
}
else

View File

@@ -5,6 +5,12 @@
#include <gdk/gdkglcontextprivate.h>
#include <gdk/gdkdmabuffourccprivate.h>
#include <gdk/gdkdmabuftextureprivate.h>
#include <gdk/gdkdmabufformatsprivate.h>
#include <gdk/gdkdmabufformatsbuilderprivate.h>
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/wayland/gdkwayland.h>
#endif
static void
test_dmabuf_formats_basic (void)
@@ -82,6 +88,102 @@ test_dmabuf_formats_builder (void)
gdk_dmabuf_formats_unref (formats1);
}
#define AAAA fourcc_code ('A', 'A', 'A', 'A')
#define BBBB fourcc_code ('B', 'B', 'B', 'B')
#define CCCC fourcc_code ('C', 'C', 'C', 'C')
#define DDDD fourcc_code ('D', 'D', 'D', 'D')
static gboolean
dmabuf_format_matches (const GdkDmabufFormat *f1, guint32 fourcc, guint64 modifier, gsize next_priority)
{
return f1->fourcc == fourcc &&
f1->modifier == modifier &&
f1->next_priority == next_priority;
}
/* Test that sorting respects priorities, and the highest priority instance
* of duplicates is kept.
*/
static void
test_priorities (void)
{
GdkDmabufFormatsBuilder *builder;
GdkDmabufFormats *formats;
const GdkDmabufFormat *f;
builder = gdk_dmabuf_formats_builder_new ();
gdk_dmabuf_formats_builder_add_format (builder, AAAA, DRM_FORMAT_MOD_LINEAR);
gdk_dmabuf_formats_builder_add_format (builder, BBBB, DRM_FORMAT_MOD_LINEAR);
gdk_dmabuf_formats_builder_add_format (builder, AAAA, I915_FORMAT_MOD_X_TILED);
gdk_dmabuf_formats_builder_next_priority (builder);
gdk_dmabuf_formats_builder_add_format (builder, DDDD, I915_FORMAT_MOD_X_TILED);
gdk_dmabuf_formats_builder_add_format (builder, BBBB, I915_FORMAT_MOD_X_TILED);
gdk_dmabuf_formats_builder_add_format (builder, CCCC, DRM_FORMAT_MOD_LINEAR);
gdk_dmabuf_formats_builder_add_format (builder, BBBB, DRM_FORMAT_MOD_LINEAR); // a duplicate
formats = gdk_dmabuf_formats_builder_free_to_formats (builder);
g_assert_true (gdk_dmabuf_formats_get_n_formats (formats) == 6);
f = gdk_dmabuf_formats_peek_formats (formats);
g_assert_true (dmabuf_format_matches (&f[0], AAAA, DRM_FORMAT_MOD_LINEAR, 3));
g_assert_true (dmabuf_format_matches (&f[1], AAAA, I915_FORMAT_MOD_X_TILED, 3));
g_assert_true (dmabuf_format_matches (&f[2], BBBB, DRM_FORMAT_MOD_LINEAR, 3));
g_assert_true (dmabuf_format_matches (&f[3], BBBB, I915_FORMAT_MOD_X_TILED, 6));
g_assert_true (dmabuf_format_matches (&f[4], CCCC, DRM_FORMAT_MOD_LINEAR, 6));
g_assert_true (dmabuf_format_matches (&f[5], DDDD, I915_FORMAT_MOD_X_TILED, 6));
gdk_dmabuf_formats_unref (formats);
}
static void
test_wayland (void)
{
GdkDmabufFormatsBuilder *builder;
GdkDmabufFormats *formats1, *formats2;
builder = gdk_dmabuf_formats_builder_new ();
gdk_dmabuf_formats_builder_add_format_for_device (builder,
DRM_FORMAT_RGBA8888,
0,
DRM_FORMAT_MOD_LINEAR,
0);
gdk_dmabuf_formats_builder_add_format_for_device (builder,
DRM_FORMAT_ARGB8888,
0,
DRM_FORMAT_MOD_LINEAR,
1);
formats1 = gdk_dmabuf_formats_builder_free_to_formats_for_device (builder, 2);
#ifdef GDK_WINDOWING_WAYLAND
g_assert_true (gdk_wayland_dmabuf_formats_get_main_device (formats1) == 2);
g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats1, 0) == 0);
g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats1, 1) == 1);
g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats1, 0));
g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats1, 1));
#endif
builder = gdk_dmabuf_formats_builder_new ();
gdk_dmabuf_formats_builder_add_format (builder, DRM_FORMAT_ARGB8888, DRM_FORMAT_MOD_LINEAR);
gdk_dmabuf_formats_builder_add_format (builder, DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_LINEAR);
formats2 = gdk_dmabuf_formats_builder_free_to_formats (builder);
#ifdef GDK_WINDOWING_WAYLAND
g_assert_true (gdk_wayland_dmabuf_formats_get_main_device (formats2) == 0);
g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats2, 0) == 0);
g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats2, 1) == 0);
g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats2, 0));
g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats2, 1));
#endif
g_assert_false (gdk_dmabuf_formats_equal (formats1, formats2));
gdk_dmabuf_formats_unref (formats1);
gdk_dmabuf_formats_unref (formats2);
}
int
main (int argc, char *argv[])
{
@@ -89,6 +191,8 @@ main (int argc, char *argv[])
g_test_add_func ("/dmabuf/formats/basic", test_dmabuf_formats_basic);
g_test_add_func ("/dmabuf/formats/builder", test_dmabuf_formats_builder);
g_test_add_func ("/dmabuf/formats/priorities", test_priorities);
g_test_add_func ("/dmabuf/formats/wayland", test_wayland);
return g_test_run ();
}