From 72e9f30937df9bf845e658d114121037a691e22a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 6 Apr 2024 20:06:25 +0200 Subject: [PATCH 1/7] subsurface: Add transforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow to specify a Dâ‚‚ transform when attaching a texture to a subsurface, to handle flipped and rotated content. The Wayland implementation handles these transforms by setting a buffer transform on the subsurface. All callers have been updated to pass GDK_TEXTURE_TRANSFORM_NORMAL. --- gdk/gdksubsurface.c | 12 +++++++++- gdk/gdksubsurfaceprivate.h | 17 ++++++++++++++ gdk/wayland/gdksubsurface-wayland-private.h | 2 ++ gdk/wayland/gdksubsurface-wayland.c | 25 +++++++++++++++++++++ gsk/gskoffload.c | 2 ++ testsuite/gdk/subsurface.c | 10 ++++----- 6 files changed, 62 insertions(+), 6 deletions(-) diff --git a/gdk/gdksubsurface.c b/gdk/gdksubsurface.c index 13776a0bfa..5f0a26f62e 100644 --- a/gdk/gdksubsurface.c +++ b/gdk/gdksubsurface.c @@ -113,6 +113,7 @@ gdk_subsurface_attach (GdkSubsurface *subsurface, GdkTexture *texture, const graphene_rect_t *source, const graphene_rect_t *dest, + GdkTextureTransform transform, gboolean above, GdkSubsurface *sibling) { @@ -155,7 +156,7 @@ gdk_subsurface_attach (GdkSubsurface *subsurface, } } - return GDK_SUBSURFACE_GET_CLASS (subsurface)->attach (subsurface, texture, source, dest, above, sibling); + return GDK_SUBSURFACE_GET_CLASS (subsurface)->attach (subsurface, texture, source, dest, transform, above, sibling); } void @@ -203,3 +204,12 @@ gdk_subsurface_is_above_parent (GdkSubsurface *subsurface) return subsurface->above_parent; } + +GdkTextureTransform +gdk_subsurface_get_transform (GdkSubsurface *subsurface) +{ + g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), GDK_TEXTURE_TRANSFORM_NORMAL); + + return GDK_SUBSURFACE_GET_CLASS (subsurface)->get_transform (subsurface); +} + diff --git a/gdk/gdksubsurfaceprivate.h b/gdk/gdksubsurfaceprivate.h index 2ffe394e5b..ea36af1bf5 100644 --- a/gdk/gdksubsurfaceprivate.h +++ b/gdk/gdksubsurfaceprivate.h @@ -47,6 +47,16 @@ struct _GdkSubsurface GdkSubsurface *sibling_below; }; +typedef enum { + GDK_TEXTURE_TRANSFORM_NORMAL, + GDK_TEXTURE_TRANSFORM_90, + GDK_TEXTURE_TRANSFORM_180, + GDK_TEXTURE_TRANSFORM_270, + GDK_TEXTURE_TRANSFORM_FLIPPED, + GDK_TEXTURE_TRANSFORM_FLIPPED_90, + GDK_TEXTURE_TRANSFORM_FLIPPED_180, + GDK_TEXTURE_TRANSFORM_FLIPPED_270, +} GdkTextureTransform; struct _GdkSubsurfaceClass { @@ -56,6 +66,7 @@ struct _GdkSubsurfaceClass GdkTexture *texture, const graphene_rect_t *source, const graphene_rect_t *dest, + GdkTextureTransform transform, gboolean above, GdkSubsurface *sibling); void (* detach) (GdkSubsurface *subsurface); @@ -64,15 +75,19 @@ struct _GdkSubsurfaceClass graphene_rect_t *source); void (* get_dest) (GdkSubsurface *subsurface, graphene_rect_t *dest); + GdkTextureTransform + (* get_transform) (GdkSubsurface *subsurface); }; GType gdk_subsurface_get_type (void) G_GNUC_CONST; GdkSurface * gdk_subsurface_get_parent (GdkSubsurface *subsurface); + gboolean gdk_subsurface_attach (GdkSubsurface *subsurface, GdkTexture *texture, const graphene_rect_t *source, const graphene_rect_t *dest, + GdkTextureTransform transform, gboolean above, GdkSubsurface *sibling); void gdk_subsurface_detach (GdkSubsurface *subsurface); @@ -82,6 +97,8 @@ void gdk_subsurface_get_source (GdkSubsurface *subsurfac void gdk_subsurface_get_dest (GdkSubsurface *subsurface, graphene_rect_t *dest); gboolean gdk_subsurface_is_above_parent (GdkSubsurface *subsurface); +GdkTextureTransform + gdk_subsurface_get_transform (GdkSubsurface *subsurface); G_END_DECLS diff --git a/gdk/wayland/gdksubsurface-wayland-private.h b/gdk/wayland/gdksubsurface-wayland-private.h index 42f357e89f..fb5c98a85a 100644 --- a/gdk/wayland/gdksubsurface-wayland-private.h +++ b/gdk/wayland/gdksubsurface-wayland-private.h @@ -2,6 +2,7 @@ #include "gdksubsurfaceprivate.h" +#include "wayland-client-protocol.h" typedef struct _GdkWaylandSubsurface GdkWaylandSubsurface; typedef struct _GdkWaylandSubsurfaceClass GdkWaylandSubsurfaceClass; @@ -23,6 +24,7 @@ struct _GdkWaylandSubsurface GdkTexture *texture; cairo_rectangle_int_t dest; graphene_rect_t source; + enum wl_output_transform transform; struct wl_region *opaque_region; diff --git a/gdk/wayland/gdksubsurface-wayland.c b/gdk/wayland/gdksubsurface-wayland.c index 588974812d..3e72234e85 100644 --- a/gdk/wayland/gdksubsurface-wayland.c +++ b/gdk/wayland/gdksubsurface-wayland.c @@ -149,11 +149,24 @@ get_wl_buffer (GdkWaylandSubsurface *self, return buffer; } +static inline enum wl_output_transform +gdk_texture_transform_to_wl (GdkTextureTransform transform) +{ + return (enum wl_output_transform) transform; +} + +static inline GdkTextureTransform +wl_output_transform_to_gdk (enum wl_output_transform transform) +{ + return (GdkTextureTransform) transform; +} + static gboolean gdk_wayland_subsurface_attach (GdkSubsurface *sub, GdkTexture *texture, const graphene_rect_t *source, const graphene_rect_t *dest, + GdkTextureTransform transform, gboolean above, GdkSubsurface *sibling) { @@ -188,6 +201,8 @@ gdk_wayland_subsurface_attach (GdkSubsurface *sub, self->source.size.width = source->size.width; self->source.size.height = source->size.height; + self->transform = gdk_texture_transform_to_wl (transform); + scale = gdk_fractional_scale_to_double (&parent->scale); device_rect.origin.x = dest->origin.x * scale; @@ -302,6 +317,7 @@ gdk_wayland_subsurface_attach (GdkSubsurface *sub, if (result) { + wl_surface_set_buffer_transform (self->surface, self->transform); wl_subsurface_set_position (self->subsurface, self->dest.x, self->dest.y); wp_viewport_set_destination (self->viewport, self->dest.width, self->dest.height); wp_viewport_set_source (self->viewport, @@ -406,6 +422,14 @@ gdk_wayland_subsurface_get_source (GdkSubsurface *sub, source->size.height = self->source.size.height; } +static GdkTextureTransform +gdk_wayland_subsurface_get_transform (GdkSubsurface *sub) +{ + GdkWaylandSubsurface *self = GDK_WAYLAND_SUBSURFACE (sub); + + return wl_output_transform_to_gdk (self->transform); +} + static void gdk_wayland_subsurface_class_init (GdkWaylandSubsurfaceClass *class) { @@ -419,6 +443,7 @@ gdk_wayland_subsurface_class_init (GdkWaylandSubsurfaceClass *class) subsurface_class->get_texture = gdk_wayland_subsurface_get_texture; subsurface_class->get_source = gdk_wayland_subsurface_get_source; subsurface_class->get_dest = gdk_wayland_subsurface_get_dest; + subsurface_class->get_transform = gdk_wayland_subsurface_get_transform; }; static void diff --git a/gsk/gskoffload.c b/gsk/gskoffload.c index f4fc9558e7..3c3410faad 100644 --- a/gsk/gskoffload.c +++ b/gsk/gskoffload.c @@ -653,12 +653,14 @@ gsk_offload_new (GdkSurface *surface, info->texture, &info->source, &info->dest, + GDK_TEXTURE_TRANSFORM_NORMAL, TRUE, NULL); else info->is_offloaded = gdk_subsurface_attach (info->subsurface, info->texture, &info->source, &info->dest, + GDK_TEXTURE_TRANSFORM_NORMAL, info->place_above != NULL, info->place_above); } diff --git a/testsuite/gdk/subsurface.c b/testsuite/gdk/subsurface.c index a0a0d8251e..37657e8049 100644 --- a/testsuite/gdk/subsurface.c +++ b/testsuite/gdk/subsurface.c @@ -42,9 +42,9 @@ test_subsurface_stacking (void) texture = gdk_texture_new_from_resource ("/org/gtk/libgtk/icons/16x16/actions/media-eject.png"); - gdk_subsurface_attach (sub0, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), TRUE, NULL); - gdk_subsurface_attach (sub1, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), TRUE, NULL); - gdk_subsurface_attach (sub2, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), TRUE, NULL); + gdk_subsurface_attach (sub0, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, TRUE, NULL); + gdk_subsurface_attach (sub1, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, TRUE, NULL); + gdk_subsurface_attach (sub2, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, TRUE, NULL); g_assert_true (surface->subsurfaces_above == sub2); g_assert_true (sub2->sibling_below == NULL); @@ -67,7 +67,7 @@ test_subsurface_stacking (void) g_assert_true (sub0->sibling_above == NULL); g_assert_true (sub0->above_parent); - gdk_subsurface_attach (sub2, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), FALSE, NULL); + gdk_subsurface_attach (sub2, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, FALSE, NULL); g_assert_true (surface->subsurfaces_above == sub0); g_assert_true (sub0->sibling_below == NULL); @@ -79,7 +79,7 @@ test_subsurface_stacking (void) g_assert_true (sub2->sibling_above == NULL); g_assert_false (sub2->above_parent); - gdk_subsurface_attach (sub1, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), TRUE, sub2); + gdk_subsurface_attach (sub1, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, TRUE, sub2); g_assert_true (surface->subsurfaces_below == sub1); g_assert_true (sub1->sibling_above == NULL); From 704ee6a9d0b09a327d29fe622ece27aa117f6b25 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 7 Apr 2024 09:10:47 -0400 Subject: [PATCH 2/7] offload: Determine output transforms When we look for the texture to attach to the subsurface, keep track of transforms we see along the way, and look at their scale component to determine if the texture needs to be flipped. We currently don't allow rotations here. This fixes glarea rendering being upside-down when offloaded. --- gsk/gskoffload.c | 67 ++++++++++++++++++++++++++++++++--------- gsk/gskoffloadprivate.h | 1 + 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/gsk/gskoffload.c b/gsk/gskoffload.c index 3c3410faad..0ef9323a7c 100644 --- a/gsk/gskoffload.c +++ b/gsk/gskoffload.c @@ -55,18 +55,46 @@ struct _GskOffload GskOffloadInfo *last_info; }; +static GdkTextureTransform +find_texture_transform (GskTransform *transform) +{ + float sx, sy, dx, dy; + + g_assert (gsk_transform_get_category (transform) >= GSK_TRANSFORM_CATEGORY_2D_AFFINE); + + gsk_transform_to_affine (transform, &sx, &sy, &dx, &dy); + + if (sx > 0) + { + if (sy > 0) + return GDK_TEXTURE_TRANSFORM_NORMAL; + else + return GDK_TEXTURE_TRANSFORM_FLIPPED_180; + } + else + { + if (sy > 0) + return GDK_TEXTURE_TRANSFORM_FLIPPED; + else + return GDK_TEXTURE_TRANSFORM_180; + } +} + static GdkTexture * find_texture_to_attach (GskOffload *self, GdkSubsurface *subsurface, const GskRenderNode *node, - graphene_rect_t *out_clip) + graphene_rect_t *out_clip, + GdkTextureTransform *out_texture_transform) { gboolean has_clip = FALSE; graphene_rect_t clip; + GskTransform *transform = NULL; + GdkTexture *ret = NULL; for (;;) { - switch ((int)GSK_RENDER_NODE_TYPE (node)) + switch ((int) GSK_RENDER_NODE_TYPE (node)) { case GSK_DEBUG_NODE: node = gsk_debug_node_get_child (node); @@ -78,7 +106,7 @@ find_texture_to_attach (GskOffload *self, GDK_DISPLAY_DEBUG (gdk_surface_get_display (self->surface), OFFLOAD, "Can't offload subsurface %p: too much content, container with %d children", subsurface, gsk_container_node_get_n_children (node)); - return NULL; + goto out; } node = gsk_container_node_get_child (node, 0); break; @@ -94,7 +122,7 @@ find_texture_to_attach (GskOffload *self, "Can't offload subsurface %p: transform %s is not just scale/translate", subsurface, s); g_free (s); - return NULL; + goto out; } if (has_clip) @@ -104,6 +132,8 @@ find_texture_to_attach (GskOffload *self, gsk_transform_unref (inv); } + transform = gsk_transform_transform (transform, gsk_transform_ref (t)); + node = gsk_transform_node_get_child (node); } break; @@ -118,7 +148,7 @@ find_texture_to_attach (GskOffload *self, { GDK_DISPLAY_DEBUG (gdk_surface_get_display (self->surface), OFFLOAD, "Can't offload subsurface %p: empty clip", subsurface); - return NULL; + goto out; } } else @@ -135,6 +165,8 @@ find_texture_to_attach (GskOffload *self, { GdkTexture *texture = gsk_texture_node_get_texture (node); + *out_texture_transform = find_texture_transform (transform); + if (has_clip) { float dx = node->bounds.origin.x; @@ -157,16 +189,22 @@ find_texture_to_attach (GskOffload *self, out_clip->size.height = gdk_texture_get_height (texture); } - return texture; + ret = texture; + goto out; } default: GDK_DISPLAY_DEBUG (gdk_surface_get_display (self->surface), OFFLOAD, "Can't offload subsurface %p: Only textures supported but found %s", subsurface, g_type_name_from_instance ((GTypeInstance *) node)); - return NULL; + goto out; } } + +out: + g_clear_pointer (&transform, gsk_transform_unref); + + return ret; } static void @@ -551,9 +589,12 @@ complex_clip: case GSK_SUBSURFACE_NODE: { GdkSubsurface *subsurface = gsk_subsurface_node_get_subsurface (node); + GskTransform *transform; GskOffloadInfo *info = find_subsurface_info (self, subsurface); + transform = self->transforms ? (GskTransform *) self->transforms->data : NULL; + if (info == NULL) { GDK_DISPLAY_DEBUG (gdk_surface_get_display (self->surface), OFFLOAD, @@ -566,8 +607,7 @@ complex_clip: "Can't offload subsurface %p: clipped", subsurface); } - else if (self->transforms && - gsk_transform_get_category ((GskTransform *)self->transforms->data) < GSK_TRANSFORM_CATEGORY_2D_AFFINE) + else if (gsk_transform_get_category (transform) < GSK_TRANSFORM_CATEGORY_2D_AFFINE) { GDK_DISPLAY_DEBUG (gdk_surface_get_display (self->surface), OFFLOAD, "Can't offload subsurface %p: non-affine transform", @@ -575,14 +615,11 @@ complex_clip: } else { - graphene_rect_t clip; - - info->texture = find_texture_to_attach (self, subsurface, gsk_subsurface_node_get_child (node), &clip); + info->texture = find_texture_to_attach (self, subsurface, gsk_subsurface_node_get_child (node), &info->source, &info->transform); if (info->texture) { info->can_offload = TRUE; info->can_raise = TRUE; - info->source = clip; transform_bounds (self, &node->bounds, &info->dest); info->place_above = self->last_info ? self->last_info->subsurface : NULL; self->last_info = info; @@ -653,14 +690,14 @@ gsk_offload_new (GdkSurface *surface, info->texture, &info->source, &info->dest, - GDK_TEXTURE_TRANSFORM_NORMAL, + info->transform, TRUE, NULL); else info->is_offloaded = gdk_subsurface_attach (info->subsurface, info->texture, &info->source, &info->dest, - GDK_TEXTURE_TRANSFORM_NORMAL, + info->transform, info->place_above != NULL, info->place_above); } diff --git a/gsk/gskoffloadprivate.h b/gsk/gskoffloadprivate.h index 7eb0645cdc..c4c604179a 100644 --- a/gsk/gskoffloadprivate.h +++ b/gsk/gskoffloadprivate.h @@ -33,6 +33,7 @@ typedef struct GdkSubsurface *place_above; graphene_rect_t dest; graphene_rect_t source; + GdkTextureTransform transform; guint was_offloaded : 1; guint can_offload : 1; From 91b98bc9e21e98eef1c86cd861467ace69cf3853 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 5 Apr 2024 17:40:45 +0200 Subject: [PATCH 3/7] Add a private header Just cosmetic reshuffling. --- gdk/gdkdmabuftexture.c | 1 + gdk/gdkdmabuftexturebuilder.c | 1 + gdk/gdkdmabuftexturebuilderprivate.h | 11 +++++++++++ gdk/gdkdmabuftextureprivate.h | 2 -- 4 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 gdk/gdkdmabuftexturebuilderprivate.h diff --git a/gdk/gdkdmabuftexture.c b/gdk/gdkdmabuftexture.c index a13b4077b5..324645b24c 100644 --- a/gdk/gdkdmabuftexture.c +++ b/gdk/gdkdmabuftexture.c @@ -25,6 +25,7 @@ #include "gdkdmabufformatsbuilderprivate.h" #include "gdkdmabuffourccprivate.h" #include "gdkdmabufprivate.h" +#include "gdkdmabuftexturebuilderprivate.h" #include "gdktextureprivate.h" #include #include diff --git a/gdk/gdkdmabuftexturebuilder.c b/gdk/gdkdmabuftexturebuilder.c index 5cb71c71b6..87957f72fc 100644 --- a/gdk/gdkdmabuftexturebuilder.c +++ b/gdk/gdkdmabuftexturebuilder.c @@ -25,6 +25,7 @@ #include "gdkdisplay.h" #include "gdkenumtypes.h" #include "gdkdmabuftextureprivate.h" +#include "gdkdmabuftexturebuilderprivate.h" #include diff --git a/gdk/gdkdmabuftexturebuilderprivate.h b/gdk/gdkdmabuftexturebuilderprivate.h new file mode 100644 index 0000000000..543ae2f542 --- /dev/null +++ b/gdk/gdkdmabuftexturebuilderprivate.h @@ -0,0 +1,11 @@ +#pragma once + +#include "gdkdmabuftexturebuilder.h" +#include "gdkdmabufprivate.h" + +G_BEGIN_DECLS + +const GdkDmabuf * gdk_dmabuf_texture_builder_get_dmabuf (GdkDmabufTextureBuilder *builder); + +G_END_DECLS + diff --git a/gdk/gdkdmabuftextureprivate.h b/gdk/gdkdmabuftextureprivate.h index fb6ebc9916..074066a2af 100644 --- a/gdk/gdkdmabuftextureprivate.h +++ b/gdk/gdkdmabuftextureprivate.h @@ -7,8 +7,6 @@ G_BEGIN_DECLS -const GdkDmabuf * gdk_dmabuf_texture_builder_get_dmabuf (GdkDmabufTextureBuilder *builder); - GdkTexture * gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder, GDestroyNotify destroy, gpointer data, From 85f2e1ccd8b5a7f407fe8215dbb15a1d54e7e460 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 5 Apr 2024 17:37:17 +0200 Subject: [PATCH 4/7] Add gdk_dmabuf_texture_builder_set_dmabuf Private utility api. --- gdk/gdkdmabuftexturebuilder.c | 16 ++++++++++++++++ gdk/gdkdmabuftexturebuilderprivate.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/gdk/gdkdmabuftexturebuilder.c b/gdk/gdkdmabuftexturebuilder.c index 87957f72fc..b895a32dc5 100644 --- a/gdk/gdkdmabuftexturebuilder.c +++ b/gdk/gdkdmabuftexturebuilder.c @@ -1005,3 +1005,19 @@ gdk_dmabuf_texture_builder_get_dmabuf (GdkDmabufTextureBuilder *self) { return &self->dmabuf; } + +void +gdk_dmabuf_texture_builder_set_dmabuf (GdkDmabufTextureBuilder *self, + const GdkDmabuf *dmabuf) +{ + gdk_dmabuf_texture_builder_set_fourcc (self, dmabuf->fourcc); + gdk_dmabuf_texture_builder_set_modifier (self, dmabuf->modifier); + gdk_dmabuf_texture_builder_set_n_planes (self, dmabuf->n_planes); + + for (unsigned int i = 0; i < dmabuf->n_planes; i++) + { + gdk_dmabuf_texture_builder_set_fd (self, i, dmabuf->planes[i].fd); + gdk_dmabuf_texture_builder_set_stride (self, i, dmabuf->planes[i].stride); + gdk_dmabuf_texture_builder_set_offset (self, i, dmabuf->planes[i].offset); + } +} diff --git a/gdk/gdkdmabuftexturebuilderprivate.h b/gdk/gdkdmabuftexturebuilderprivate.h index 543ae2f542..fe725051fc 100644 --- a/gdk/gdkdmabuftexturebuilderprivate.h +++ b/gdk/gdkdmabuftexturebuilderprivate.h @@ -7,5 +7,8 @@ G_BEGIN_DECLS const GdkDmabuf * gdk_dmabuf_texture_builder_get_dmabuf (GdkDmabufTextureBuilder *builder); +void gdk_dmabuf_texture_builder_set_dmabuf (GdkDmabufTextureBuilder *builder, + const GdkDmabuf *dmabuf); + G_END_DECLS From 11d3be278d54b4719c207a20be1255aacf84a078 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 6 Apr 2024 19:12:46 +0200 Subject: [PATCH 5/7] glarea: Return dmabuf textures Export the GL texture as a dmabuf if we can, and provide the texture in that form. --- gtk/gtkglarea.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/gtk/gtkglarea.c b/gtk/gtkglarea.c index 9271768243..9cd9d661cf 100644 --- a/gtk/gtkglarea.c +++ b/gtk/gtkglarea.c @@ -34,6 +34,12 @@ #include "gtkcssnodeprivate.h" #include "gdk/gdkgltextureprivate.h" #include "gdk/gdkglcontextprivate.h" +#include "gdk/gdkdmabuftexturebuilderprivate.h" +#include "gdk/gdkdmabuftextureprivate.h" + +#ifdef HAVE_UNISTD_H +#include +#endif #include @@ -715,6 +721,26 @@ release_texture (gpointer data) texture->holder = NULL; } +static void +release_dmabuf (const GdkDmabuf *dmabuf) +{ +#ifndef G_OS_WIN32 + for (unsigned int i = 0; i < dmabuf->n_planes; i++) + close (dmabuf->planes[i].fd); +#endif +} + +static void +release_dmabuf_texture (gpointer data) +{ + Texture *texture = data; + + release_dmabuf (gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture->holder))); + g_object_set_data (G_OBJECT (texture->holder), "gltexture", NULL); + + texture->holder = NULL; +} + static void gtk_gl_area_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) @@ -758,6 +784,8 @@ gtk_gl_area_snapshot (GtkWidget *widget, { Texture *texture; gpointer sync = NULL; + GdkTexture *gltexture; + GdkDmabuf dmabuf; if (priv->needs_render || priv->auto_render) { @@ -781,9 +809,33 @@ gtk_gl_area_snapshot (GtkWidget *widget, gdk_gl_texture_builder_set_sync (texture->builder, sync); - texture->holder = gdk_gl_texture_builder_build (texture->builder, - release_texture, - texture); + gltexture = gdk_gl_texture_builder_build (texture->builder, + release_texture, + texture); + + if (gdk_gl_context_export_dmabuf (priv->context, + gdk_gl_texture_builder_get_id (texture->builder), + &dmabuf)) + { + GdkDmabufTextureBuilder *builder = gdk_dmabuf_texture_builder_new (); + + gdk_dmabuf_texture_builder_set_display (builder, gdk_gl_context_get_display (priv->context)); + gdk_dmabuf_texture_builder_set_width (builder, gdk_texture_get_width (gltexture)); + gdk_dmabuf_texture_builder_set_height (builder, gdk_texture_get_height (gltexture)); + gdk_dmabuf_texture_builder_set_premultiplied (builder, TRUE); + gdk_dmabuf_texture_builder_set_dmabuf (builder, &dmabuf); + + texture->holder = gdk_dmabuf_texture_builder_build (builder, release_dmabuf_texture, texture, NULL); + + g_object_unref (builder); + + if (texture->holder != NULL) + g_object_set_data_full (G_OBJECT (texture->holder), "gltexture", gltexture, g_object_unref); + else + release_dmabuf (&dmabuf); + } + else + texture->holder = gltexture; /* Our texture is rendered by OpenGL, so it is upside down, * compared to what GSK expects, so flip it back. From f51c82a2aa9e4b7d2691af6e390cc9055e42ccb4 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 6 Apr 2024 19:22:52 +0200 Subject: [PATCH 6/7] gtk-demo: Use offload for shadertoy This is an easy way to verify that GtkGLArea delivers dmabufs now, and it might have some practical uses to offload gl area. --- demos/gtk-demo/shadertoy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/gtk-demo/shadertoy.c b/demos/gtk-demo/shadertoy.c index cc76e80dfe..06417a6a79 100644 --- a/demos/gtk-demo/shadertoy.c +++ b/demos/gtk-demo/shadertoy.c @@ -120,7 +120,7 @@ create_shadertoy_window (GtkWidget *do_widget) gtk_box_append (GTK_BOX (box), aspect); shadertoy = new_shadertoy ("/shadertoy/alienplanet.glsl"); - gtk_aspect_frame_set_child (GTK_ASPECT_FRAME (aspect), shadertoy); + gtk_aspect_frame_set_child (GTK_ASPECT_FRAME (aspect), gtk_graphics_offload_new (shadertoy)); sw = gtk_scrolled_window_new (); gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (sw), 250); From 2b09f5ea1e8ed7b66ce306aac6d64f961249cbf0 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 7 Apr 2024 12:15:01 -0400 Subject: [PATCH 7/7] dmabuf: Reshuffle docs slightly Move related parts together, for easier understanding. --- gdk/gdkdmabuftexturebuilder.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/gdk/gdkdmabuftexturebuilder.c b/gdk/gdkdmabuftexturebuilder.c index b895a32dc5..6508d9c2cf 100644 --- a/gdk/gdkdmabuftexturebuilder.c +++ b/gdk/gdkdmabuftexturebuilder.c @@ -949,22 +949,20 @@ gdk_dmabuf_texture_builder_set_update_region (GdkDmabufTextureBuilder *self, * * Builds a new `GdkTexture` with the values set up in the builder. * - * It is a programming error to call this function if any mandatory - * property has not been set. + * It is a programming error to call this function if any mandatory property has not been set. * - * If the dmabuf is not supported by GTK, %NULL will be returned and @error will be set. + * Not all formats defined in the `drm_fourcc.h` header are supported. You can use + * [method@Gdk.Display.get_dmabuf_formats] to get a list of supported formats. If the + * format is not supported by GTK, %NULL will be returned and @error will be set. * * The `destroy` function gets called when the returned texture gets released. * - * It is possible to call this function multiple times to create multiple textures, - * possibly with changing properties in between. - * * It is the responsibility of the caller to keep the file descriptors for the planes * open until the created texture is no longer used, and close them afterwards (possibly * using the @destroy notify). * - * Not all formats defined in the `drm_fourcc.h` header are supported. You can use - * [method@Gdk.Display.get_dmabuf_formats] to get a list of supported formats. + * It is possible to call this function multiple times to create multiple textures, + * possibly with changing properties in between. * * Returns: (transfer full) (nullable): a newly built `GdkTexture` or `NULL` * if the format is not supported