diff --git a/docs/reference/gtk/running.md b/docs/reference/gtk/running.md index 879e23d2e9..3ddae2cc36 100644 --- a/docs/reference/gtk/running.md +++ b/docs/reference/gtk/running.md @@ -217,6 +217,10 @@ A number of options affect behavior instead of logging: `no-portals` : Disable use of [portals](https://docs.flatpak.org/en/latest/portals.html) +`force-offload` +: Force graphics offload for all textures, even when slower. This allows + to debug offloading in the absence of dmabufs. + `gl-disable` : Disable OpenGL support diff --git a/gdk/gdk.c b/gdk/gdk.c index 9787b437b8..95521522f2 100644 --- a/gdk/gdk.c +++ b/gdk/gdk.c @@ -122,6 +122,7 @@ static const GdkDebugKey gdk_debug_keys[] = { { "portals", GDK_DEBUG_PORTALS, "Force use of portals" }, { "no-portals", GDK_DEBUG_NO_PORTALS, "Disable use of portals" }, + { "force-offload", GDK_DEBUG_FORCE_OFFLOAD, "Force graphics offload for all textures" }, { "gl-disable", GDK_DEBUG_GL_DISABLE, "Disable OpenGL support" }, { "gl-no-fractional", GDK_DEBUG_GL_NO_FRACTIONAL, "Disable fractional scaling for OpenGL" }, { "gl-debug", GDK_DEBUG_GL_DEBUG, "Insert debugging information in OpenGL" }, diff --git a/gdk/gdkdebugprivate.h b/gdk/gdkdebugprivate.h index ba709fb5e9..359f13e6fa 100644 --- a/gdk/gdkdebugprivate.h +++ b/gdk/gdkdebugprivate.h @@ -44,7 +44,7 @@ typedef enum { GDK_DEBUG_NO_PORTALS = 1 << 15, GDK_DEBUG_GL_DISABLE = 1 << 16, GDK_DEBUG_GL_NO_FRACTIONAL= 1 << 17, - + GDK_DEBUG_FORCE_OFFLOAD = 1 << 18, GDK_DEBUG_GL_DISABLE_GL = 1 << 19, GDK_DEBUG_GL_DISABLE_GLES = 1 << 20, GDK_DEBUG_GL_PREFER_GL = 1 << 21, diff --git a/gdk/gdksubsurface.c b/gdk/gdksubsurface.c index 5f0a26f62e..20d4810a4c 100644 --- a/gdk/gdksubsurface.c +++ b/gdk/gdksubsurface.c @@ -48,6 +48,14 @@ gdk_subsurface_class_init (GdkSubsurfaceClass *class) object_class->finalize = gdk_subsurface_finalize; } +/*< private > + * gdk_subsurface_get_parent: + * @subsurface: a `GdkSubsurface` + * + * Returns the parent surface of @subsurface. + * + * Returns: the parent surface + */ GdkSurface * gdk_subsurface_get_parent (GdkSubsurface *subsurface) { @@ -108,16 +116,41 @@ insert_subsurface (GdkSubsurface *subsurface, } } +/*< private > + * gdk_subsurface_attach: + * @subsurface: the `GdkSubsurface` + * @texture: the texture to attach. This typically has to be a `GdkDmabufTexture` + * @source: the source rectangle (i.e. the subset of the texture) to display + * @dest: the dest rectangle, in application pixels, relative to the parent surface. + * It must be integral in application and device pixels, or attaching will fail + * @transform: the transform to apply to the texture contents before displaying + * @background: (nullable): the background rectangle, in application pixels relative + * to the parent surface. This tells GDK to put a black background of this + * size below the subsurface. It must be integral in application and device pixels, + * or attaching will fail + * @above: whether the subsurface should be above its sibling + * @sibling: (nullable): the sibling subsurface to stack relative to, or `NULL` to + * stack relative to the parent surface + * + * Attaches content to a subsurface. + * + * This function takes all the necessary arguments to determine the subsurface + * configuration, including its position, size, content, background and stacking. + * + * Returns: `TRUE` if the attaching succeeded + */ gboolean gdk_subsurface_attach (GdkSubsurface *subsurface, GdkTexture *texture, const graphene_rect_t *source, const graphene_rect_t *dest, GdkTextureTransform transform, + const graphene_rect_t *background, gboolean above, GdkSubsurface *sibling) { GdkSurface *parent = subsurface->parent; + gboolean result; g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), FALSE); g_return_val_if_fail (GDK_IS_TEXTURE (texture), FALSE); @@ -131,6 +164,15 @@ 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); + result = GDK_SUBSURFACE_GET_CLASS (subsurface)->attach (subsurface, + texture, + source, + dest, + transform, + background, + above, + sibling); + remove_subsurface (subsurface); if (sibling) @@ -156,9 +198,17 @@ gdk_subsurface_attach (GdkSubsurface *subsurface, } } - return GDK_SUBSURFACE_GET_CLASS (subsurface)->attach (subsurface, texture, source, dest, transform, above, sibling); + return result; } +/*< private > + * gdk_subsurface_detach: + * @subsurface: a `GdkSubsurface` + * + * Hides the subsurface. + * + * To show it again, you need to call gdk_subsurface_attach(). + */ void gdk_subsurface_detach (GdkSubsurface *subsurface) { @@ -169,6 +219,14 @@ gdk_subsurface_detach (GdkSubsurface *subsurface) GDK_SUBSURFACE_GET_CLASS (subsurface)->detach (subsurface); } +/*< private > + * gdk_subsurface_get_texture: + * @subsurface: a `GdkSubsurface` + * + * Gets the texture that is currently displayed by the subsurface. + * + * Returns: (nullable): the texture that is displayed + */ GdkTexture * gdk_subsurface_get_texture (GdkSubsurface *subsurface) { @@ -177,34 +235,91 @@ gdk_subsurface_get_texture (GdkSubsurface *subsurface) return GDK_SUBSURFACE_GET_CLASS (subsurface)->get_texture (subsurface); } +/*< private > + * gdk_subsurface_get_source_rect: + * @subsurface: a `GdkSubsurface` + * @rect: (out caller-allocates): return location for the rectangle + * + * Returns the source rect that was specified in the most recent + * gdk_subsurface_attach() call for @subsurface. + */ void -gdk_subsurface_get_source (GdkSubsurface *subsurface, - graphene_rect_t *source) +gdk_subsurface_get_source_rect (GdkSubsurface *subsurface, + graphene_rect_t *rect) { g_return_if_fail (GDK_IS_SUBSURFACE (subsurface)); - g_return_if_fail (source != NULL); + g_return_if_fail (rect != NULL); - GDK_SUBSURFACE_GET_CLASS (subsurface)->get_source (subsurface, source); + GDK_SUBSURFACE_GET_CLASS (subsurface)->get_source_rect (subsurface, rect); } +/*< private > + * gdk_subsurface_get_texture_rect: + * @subsurface: a `GdkSubsurface` + * @rect: (out caller-allocates): return location for the rectangle + * + * Returns the texture rect that was specified in the most recent + * gdk_subsurface_attach() call for @subsurface. + */ void -gdk_subsurface_get_dest (GdkSubsurface *subsurface, - graphene_rect_t *dest) +gdk_subsurface_get_texture_rect (GdkSubsurface *subsurface, + graphene_rect_t *rect) { g_return_if_fail (GDK_IS_SUBSURFACE (subsurface)); - g_return_if_fail (dest != NULL); + g_return_if_fail (rect != NULL); - GDK_SUBSURFACE_GET_CLASS (subsurface)->get_dest (subsurface, dest); + GDK_SUBSURFACE_GET_CLASS (subsurface)->get_texture_rect (subsurface, rect); } +/*< private > + * gdk_subsurface_is_above_parent: + * @subsurface: a `GdkSubsurface` + * + * Returns whether the subsurface is above the parent surface + * or below. Note that a subsurface can be above its parent + * surface, and still be covered by sibling subsurfaces. + * + * Returns: `TRUE` if @subsurface is above its parent + */ gboolean gdk_subsurface_is_above_parent (GdkSubsurface *subsurface) { - g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), TRUE); + g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), FALSE); return subsurface->above_parent; } +/*< private> + * gdk_subsurface_get_sibling: + * @subsurface: the `GdkSubsurface` + * @above: whether to get the subsurface above + * + * Returns the subsurface above (or below) @subsurface in + * the stacking order. + * + * Returns: the sibling, or `NULL` if there is none. + */ +GdkSubsurface * +gdk_subsurface_get_sibling (GdkSubsurface *subsurface, + gboolean above) +{ + g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), NULL); + + if (above) + return subsurface->sibling_above; + else + return subsurface->sibling_below; +} + +/*< private > + * gdk_subsurface_get_transform: + * @subsurface: a `GdkSubsurface` + * + * Returns the transform that was specified in the most recent call to + * gdk_subsurface_attach() call for @subsurface. + * + * Returns: the transform + */ GdkTextureTransform gdk_subsurface_get_transform (GdkSubsurface *subsurface) { @@ -213,3 +328,45 @@ gdk_subsurface_get_transform (GdkSubsurface *subsurface) return GDK_SUBSURFACE_GET_CLASS (subsurface)->get_transform (subsurface); } +/*< private > + * gdk_subsurface_get_background_rect: + * @subsurface: a `GdkSubsurface` + * @rect: (out caller-allocates): return location for the rectangle + * + * Obtains the background rect that was specified in the most recent + * gdk_subsurface_attach() call for @subsurface. + * + * Returns: `TRUE` if @subsurface has a background + */ +gboolean +gdk_subsurface_get_background_rect (GdkSubsurface *subsurface, + graphene_rect_t *rect) +{ + g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), FALSE); + g_return_val_if_fail (rect != NULL, FALSE); + + return GDK_SUBSURFACE_GET_CLASS (subsurface)->get_background_rect (subsurface, rect); +} + +/*< private > + * gdk_subsurface_get_bounds: + * @subsurface: a `GdkSubsurface` + * @bounds: (out caller-allocates): return location for the bounds + * + * Returns the bounds of the subsurface. + * + * The bounds are the union of the texture and background rects. + */ +void +gdk_subsurface_get_bounds (GdkSubsurface *subsurface, + graphene_rect_t *bounds) +{ + graphene_rect_t background; + + g_return_if_fail (GDK_IS_SUBSURFACE (subsurface)); + g_return_if_fail (bounds != NULL); + + gdk_subsurface_get_texture_rect (subsurface, bounds); + if (gdk_subsurface_get_background_rect (subsurface, &background)) + graphene_rect_union (bounds, &background, bounds); +} diff --git a/gdk/gdksubsurface.c.orig b/gdk/gdksubsurface.c.orig new file mode 100644 index 0000000000..3c0e303977 --- /dev/null +++ b/gdk/gdksubsurface.c.orig @@ -0,0 +1,222 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 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 . + */ + +#include "config.h" + +#include "gdksubsurfaceprivate.h" +#include "gdksurfaceprivate.h" +#include "gdktexture.h" +#include "gsk/gskrectprivate.h" + +G_DEFINE_TYPE (GdkSubsurface, gdk_subsurface, G_TYPE_OBJECT) + +static void +gdk_subsurface_init (GdkSubsurface *self) +{ +} + +static void +gdk_subsurface_finalize (GObject *object) +{ + GdkSubsurface *subsurface = GDK_SUBSURFACE (object); + + g_ptr_array_remove (subsurface->parent->subsurfaces, subsurface); + g_clear_object (&subsurface->parent); + + G_OBJECT_CLASS (gdk_subsurface_parent_class)->finalize (object); +} + +static void +gdk_subsurface_class_init (GdkSubsurfaceClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = gdk_subsurface_finalize; +} + +GdkSurface * +gdk_subsurface_get_parent (GdkSubsurface *subsurface) +{ + g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), NULL); + + return subsurface->parent; +} + +static void +remove_subsurface (GdkSubsurface *subsurface) +{ + GdkSurface *parent = subsurface->parent; + + if (parent->subsurfaces_above == subsurface) + parent->subsurfaces_above = subsurface->sibling_above; + if (parent->subsurfaces_below == subsurface) + parent->subsurfaces_below = subsurface->sibling_below; + + if (subsurface->sibling_above) + subsurface->sibling_above->sibling_below = subsurface->sibling_below; + if (subsurface->sibling_below) + subsurface->sibling_below->sibling_above = subsurface->sibling_above; + + subsurface->sibling_above = NULL; + subsurface->sibling_below = NULL; +} + +static void +insert_subsurface (GdkSubsurface *subsurface, + gboolean above, + GdkSubsurface *sibling) +{ + GdkSurface *parent = subsurface->parent; + + subsurface->above_parent = sibling->above_parent; + + if (above) + { + subsurface->sibling_above = sibling->sibling_above; + sibling->sibling_above = subsurface; + subsurface->sibling_below = sibling; + if (subsurface->sibling_above) + subsurface->sibling_above->sibling_below = subsurface; + + if (parent->subsurfaces_below == sibling) + parent->subsurfaces_below = subsurface; + } + else + { + subsurface->sibling_below = sibling->sibling_below; + sibling->sibling_below = subsurface; + subsurface->sibling_above = sibling; + if (subsurface->sibling_below) + subsurface->sibling_below->sibling_above = subsurface; + + if (parent->subsurfaces_above == sibling) + parent->subsurfaces_above = subsurface; + } +} + +gboolean +gdk_subsurface_attach (GdkSubsurface *subsurface, + GdkTexture *texture, + const graphene_rect_t *source, + const graphene_rect_t *dest, + GdkTextureTransform transform, + const graphene_rect_t *background, + gboolean above, + GdkSubsurface *sibling) +{ + GdkSurface *parent = subsurface->parent; + + g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), FALSE); + g_return_val_if_fail (GDK_IS_TEXTURE (texture), FALSE); + g_return_val_if_fail (source != NULL && + gsk_rect_contains_rect (&GRAPHENE_RECT_INIT (0, 0, + gdk_texture_get_width (texture), + gdk_texture_get_height (texture)), + source), FALSE); + g_return_val_if_fail (dest != NULL, FALSE); + g_return_val_if_fail (sibling != subsurface, FALSE); + g_return_val_if_fail (sibling == NULL || GDK_IS_SUBSURFACE (sibling), FALSE); + g_return_val_if_fail (sibling == NULL || sibling->parent == subsurface->parent, FALSE); + + remove_subsurface (subsurface); + + if (sibling) + { + insert_subsurface (subsurface, above, sibling); + } + else + { + sibling = above ? parent->subsurfaces_above : parent->subsurfaces_below; + + if (sibling) + { + insert_subsurface (subsurface, !above, sibling); + } + else + { + subsurface->above_parent = above; + + if (above) + parent->subsurfaces_above = subsurface; + else + parent->subsurfaces_below = subsurface; + } + } + + return GDK_SUBSURFACE_GET_CLASS (subsurface)->attach (subsurface, + texture, + source, + dest, + transform, + background, + above, + sibling); +} + +void +gdk_subsurface_detach (GdkSubsurface *subsurface) +{ + g_return_if_fail (GDK_IS_SUBSURFACE (subsurface)); + + remove_subsurface (subsurface); + + GDK_SUBSURFACE_GET_CLASS (subsurface)->detach (subsurface); +} + +GdkTexture * +gdk_subsurface_get_texture (GdkSubsurface *subsurface) +{ + g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), NULL); + + return GDK_SUBSURFACE_GET_CLASS (subsurface)->get_texture (subsurface); +} + +void +gdk_subsurface_get_source (GdkSubsurface *subsurface, + graphene_rect_t *source) +{ + g_return_if_fail (GDK_IS_SUBSURFACE (subsurface)); + g_return_if_fail (source != NULL); + + GDK_SUBSURFACE_GET_CLASS (subsurface)->get_source (subsurface, source); +} + +void +gdk_subsurface_get_dest (GdkSubsurface *subsurface, + graphene_rect_t *dest) +{ + g_return_if_fail (GDK_IS_SUBSURFACE (subsurface)); + g_return_if_fail (dest != NULL); + + GDK_SUBSURFACE_GET_CLASS (subsurface)->get_dest (subsurface, dest); +} + +gboolean +gdk_subsurface_is_above_parent (GdkSubsurface *subsurface) +{ + g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), TRUE); + + 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/gdksubsurface.c.rej b/gdk/gdksubsurface.c.rej new file mode 100644 index 0000000000..b68e718211 --- /dev/null +++ b/gdk/gdksubsurface.c.rej @@ -0,0 +1,16 @@ +--- gdk/gdksubsurface.c ++++ gdk/gdksubsurface.c +@@ -213,3 +213,13 @@ gdk_subsurface_get_transform (GdkSubsurface *subsurface) + return GDK_SUBSURFACE_GET_CLASS (subsurface)->get_transform (subsurface); + } + ++void ++gdk_subsurface_get_background (GdkSubsurface *subsurface, ++ graphene_rect_t *background) ++{ ++ g_return_if_fail (GDK_IS_SUBSURFACE (subsurface)); ++ g_return_if_fail (background != NULL); ++ ++ GDK_SUBSURFACE_GET_CLASS (subsurface)->get_background (subsurface, background); ++} ++ diff --git a/gdk/gdksubsurfaceprivate.h b/gdk/gdksubsurfaceprivate.h index ea36af1bf5..6a28ac3f1d 100644 --- a/gdk/gdksubsurfaceprivate.h +++ b/gdk/gdksubsurfaceprivate.h @@ -62,44 +62,53 @@ struct _GdkSubsurfaceClass { GObjectClass parent_class; - gboolean (* attach) (GdkSubsurface *subsurface, - GdkTexture *texture, - const graphene_rect_t *source, - const graphene_rect_t *dest, - GdkTextureTransform transform, - gboolean above, - GdkSubsurface *sibling); - void (* detach) (GdkSubsurface *subsurface); - GdkTexture * (* get_texture) (GdkSubsurface *subsurface); - void (* get_source) (GdkSubsurface *subsurface, - graphene_rect_t *source); - void (* get_dest) (GdkSubsurface *subsurface, - graphene_rect_t *dest); + gboolean (* attach) (GdkSubsurface *subsurface, + GdkTexture *texture, + const graphene_rect_t *source, + const graphene_rect_t *dest, + GdkTextureTransform transform, + const graphene_rect_t *bg, + gboolean above, + GdkSubsurface *sibling); + void (* detach) (GdkSubsurface *subsurface); + GdkTexture * (* get_texture) (GdkSubsurface *subsurface); + void (* get_source_rect) (GdkSubsurface *subsurface, + graphene_rect_t *rect); + void (* get_texture_rect) (GdkSubsurface *subsurface, + graphene_rect_t *rect); GdkTextureTransform - (* get_transform) (GdkSubsurface *subsurface); + (* get_transform) (GdkSubsurface *subsurface); + gboolean (* get_background_rect) (GdkSubsurface *subsurface, + graphene_rect_t *rect); }; -GType gdk_subsurface_get_type (void) G_GNUC_CONST; +GType gdk_subsurface_get_type (void) G_GNUC_CONST; -GdkSurface * gdk_subsurface_get_parent (GdkSubsurface *subsurface); +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); -GdkTexture * gdk_subsurface_get_texture (GdkSubsurface *subsurface); -void gdk_subsurface_get_source (GdkSubsurface *subsurface, - graphene_rect_t *source); -void gdk_subsurface_get_dest (GdkSubsurface *subsurface, - graphene_rect_t *dest); -gboolean gdk_subsurface_is_above_parent (GdkSubsurface *subsurface); +gboolean gdk_subsurface_attach (GdkSubsurface *subsurface, + GdkTexture *texture, + const graphene_rect_t *source, + const graphene_rect_t *dest, + GdkTextureTransform transform, + const graphene_rect_t *background, + gboolean above, + GdkSubsurface *sibling); +void gdk_subsurface_detach (GdkSubsurface *subsurface); +GdkTexture * gdk_subsurface_get_texture (GdkSubsurface *subsurface); +void gdk_subsurface_get_source_rect (GdkSubsurface *subsurface, + graphene_rect_t *rect); +void gdk_subsurface_get_texture_rect (GdkSubsurface *subsurface, + graphene_rect_t *rect); +gboolean gdk_subsurface_is_above_parent (GdkSubsurface *subsurface); +GdkSubsurface * gdk_subsurface_get_sibling (GdkSubsurface *subsurface, + gboolean above); GdkTextureTransform - gdk_subsurface_get_transform (GdkSubsurface *subsurface); - + gdk_subsurface_get_transform (GdkSubsurface *subsurface); +gboolean gdk_subsurface_get_background_rect (GdkSubsurface *subsurface, + graphene_rect_t *rect); +void gdk_subsurface_get_bounds (GdkSubsurface *subsurface, + graphene_rect_t *bounds); G_END_DECLS diff --git a/gdk/gdksubsurfaceprivate.h.orig b/gdk/gdksubsurfaceprivate.h.orig new file mode 100644 index 0000000000..ad4204f542 --- /dev/null +++ b/gdk/gdksubsurfaceprivate.h.orig @@ -0,0 +1,107 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 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 . + */ + +/* Uninstalled header defining types and functions internal to GDK */ + +#pragma once + +#include "gdkenumtypes.h" +#include "gdksurface.h" +#include + +G_BEGIN_DECLS + +typedef struct _GdkSubsurface GdkSubsurface; +typedef struct _GdkSubsurfaceClass GdkSubsurfaceClass; + +#define GDK_TYPE_SUBSURFACE (gdk_subsurface_get_type ()) +#define GDK_SUBSURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SUBSURFACE, GdkSubsurface)) +#define GDK_SUBSURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SUBSURFACE, GdkSubsurfaceClass)) +#define GDK_IS_SUBSURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SUBSURFACE)) +#define GDK_SUBSURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SUBSURFACE, GdkSubsurfaceClass)) + +struct _GdkSubsurface +{ + GObject parent_instance; + + GdkSurface *parent; + + int ref_count; + + gboolean above_parent; + GdkSubsurface *sibling_above; + 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 +{ + GObjectClass parent_class; + + gboolean (* attach) (GdkSubsurface *subsurface, + GdkTexture *texture, + const graphene_rect_t *source, + const graphene_rect_t *dest, + GdkTextureTransform transform, + const graphene_rect_t *bg, + gboolean above, + GdkSubsurface *sibling); + void (* detach) (GdkSubsurface *subsurface); + GdkTexture * (* get_texture) (GdkSubsurface *subsurface); + void (* get_source) (GdkSubsurface *subsurface, + 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, + const graphene_rect_t *background, + gboolean above, + GdkSubsurface *sibling); +void gdk_subsurface_detach (GdkSubsurface *subsurface); +GdkTexture * gdk_subsurface_get_texture (GdkSubsurface *subsurface); +void gdk_subsurface_get_source (GdkSubsurface *subsurface, + graphene_rect_t *source); +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/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index cc2c51dfa6..46af453bd3 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -606,7 +606,13 @@ gdk_registry_handle_global (void *data, &wp_presentation_interface, MIN (version, 1)); } - + else if (strcmp (interface, wp_single_pixel_buffer_manager_v1_interface.name) == 0) + { + display_wayland->single_pixel_buffer = + wl_registry_bind (display_wayland->wl_registry, id, + &wp_single_pixel_buffer_manager_v1_interface, + MIN (version, 1)); + } g_hash_table_insert (display_wayland->known_globals, GUINT_TO_POINTER (id), g_strdup (interface)); @@ -817,6 +823,7 @@ gdk_wayland_display_dispose (GObject *object) g_clear_pointer (&display_wayland->fractional_scale, wp_fractional_scale_manager_v1_destroy); g_clear_pointer (&display_wayland->viewporter, wp_viewporter_destroy); g_clear_pointer (&display_wayland->presentation, wp_presentation_destroy); + 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->linux_dmabuf_feedback, zwp_linux_dmabuf_feedback_v1_destroy); if (display_wayland->linux_dmabuf_formats) diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index f08323ee3e..b2a5f84509 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -127,6 +128,7 @@ struct _GdkWaylandDisplay struct wp_fractional_scale_manager_v1 *fractional_scale; struct wp_viewporter *viewporter; struct wp_presentation *presentation; + struct wp_single_pixel_buffer_manager_v1 *single_pixel_buffer; GList *async_roundtrips; diff --git a/gdk/wayland/gdksubsurface-wayland-private.h b/gdk/wayland/gdksubsurface-wayland-private.h index fb5c98a85a..9b8378ccc2 100644 --- a/gdk/wayland/gdksubsurface-wayland-private.h +++ b/gdk/wayland/gdksubsurface-wayland-private.h @@ -29,6 +29,12 @@ struct _GdkWaylandSubsurface struct wl_region *opaque_region; struct wl_callback *frame_callback; + + struct wl_surface *bg_surface; + struct wl_subsurface *bg_subsurface; + struct wp_viewport *bg_viewport; + cairo_rectangle_int_t bg_rect; + gboolean bg_attached; }; struct _GdkWaylandSubsurfaceClass diff --git a/gdk/wayland/gdksubsurface-wayland.c b/gdk/wayland/gdksubsurface-wayland.c index cecd10cb28..eaf5b72e8b 100644 --- a/gdk/wayland/gdksubsurface-wayland.c +++ b/gdk/wayland/gdksubsurface-wayland.c @@ -25,6 +25,8 @@ #include "gdkdmabuftextureprivate.h" #include "gdksurface-wayland-private.h" #include "gdksubsurfaceprivate.h" +#include "gdkdebugprivate.h" +#include "gsk/gskrectprivate.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" @@ -46,10 +48,55 @@ gdk_wayland_subsurface_finalize (GObject *object) g_clear_pointer (&self->viewport, wp_viewport_destroy); g_clear_pointer (&self->subsurface, wl_subsurface_destroy); g_clear_pointer (&self->surface, wl_surface_destroy); + 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_OBJECT_CLASS (gdk_wayland_subsurface_parent_class)->finalize (object); } +static void +shm_buffer_release (void *data, + struct wl_buffer *buffer) +{ + cairo_surface_t *surface = data; + + /* Note: the wl_buffer is destroyed as cairo user data */ + cairo_surface_destroy (surface); +} + +static const struct wl_buffer_listener shm_buffer_listener = { + shm_buffer_release, +}; + +static struct wl_buffer * +get_shm_wl_buffer (GdkWaylandSubsurface *self, + GdkTexture *texture) +{ + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SUBSURFACE (self)->parent)); + int width, height; + cairo_surface_t *surface; + GdkTextureDownloader *downloader; + struct wl_buffer *buffer; + + width = gdk_texture_get_width (texture); + height = gdk_texture_get_height (texture); + surface = gdk_wayland_display_create_shm_surface (display, width, height, &GDK_FRACTIONAL_SCALE_INIT_INT (1)); + + downloader = gdk_texture_downloader_new (texture); + + gdk_texture_downloader_download_into (downloader, + cairo_image_surface_get_data (surface), + cairo_image_surface_get_stride (surface)); + + gdk_texture_downloader_free (downloader); + + buffer = _gdk_wayland_shm_surface_get_wl_buffer (surface); + wl_buffer_add_listener (buffer, &shm_buffer_listener, surface); + + return buffer; +} + static void dmabuf_buffer_release (void *data, struct wl_buffer *buffer) @@ -96,8 +143,8 @@ static const struct zwp_linux_buffer_params_v1_listener params_listener = { }; static struct wl_buffer * -get_wl_buffer (GdkWaylandSubsurface *self, - GdkTexture *texture) +get_dmabuf_wl_buffer (GdkWaylandSubsurface *self, + GdkTexture *texture) { GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SUBSURFACE (self)->parent)); const GdkDmabuf *dmabuf; @@ -148,6 +195,52 @@ get_wl_buffer (GdkWaylandSubsurface *self, return buffer; } +static struct wl_buffer * +get_wl_buffer (GdkWaylandSubsurface *self, + GdkTexture *texture) +{ + GdkDisplay *display = gdk_surface_get_display (GDK_SUBSURFACE (self)->parent); + struct wl_buffer *buffer = NULL; + + if (GDK_IS_DMABUF_TEXTURE (texture)) + buffer = get_dmabuf_wl_buffer (self, texture); + + if (GDK_DISPLAY_DEBUG_CHECK (display, FORCE_OFFLOAD)) + { + if (!buffer) + buffer = get_shm_wl_buffer (self, texture); + } + + return buffer; +} + +static void +sp_buffer_release (void *data, + struct wl_buffer *buffer) +{ + wl_buffer_destroy (buffer); +} + +static const struct wl_buffer_listener sp_buffer_listener = { + sp_buffer_release, +}; + +static struct wl_buffer * +get_sp_buffer (GdkWaylandSubsurface *self) +{ + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SUBSURFACE (self)->parent)); + struct wl_buffer *buffer = NULL; + + if (display->single_pixel_buffer) + buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer (display->single_pixel_buffer, + 0, 0, 0, 0xffffffffU); + + if (buffer) + wl_buffer_add_listener (buffer, &sp_buffer_listener, self); + + return buffer; +} + static inline enum wl_output_transform gdk_texture_transform_to_wl (GdkTextureTransform transform) { @@ -160,24 +253,80 @@ wl_output_transform_to_gdk (enum wl_output_transform transform) return (GdkTextureTransform) transform; } +static void +ensure_bg_surface (GdkWaylandSubsurface *self) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (GDK_SUBSURFACE (self)->parent); + GdkDisplay *display = gdk_surface_get_display (GDK_SUBSURFACE (self)->parent); + GdkWaylandDisplay *disp = GDK_WAYLAND_DISPLAY (display); + struct wl_region *region; + + if (self->bg_surface) + return; + + self->bg_surface = wl_compositor_create_surface (disp->compositor); + self->bg_subsurface = wl_subcompositor_get_subsurface (disp->subcompositor, + self->bg_surface, + impl->display_server.wl_surface); + self->bg_viewport = wp_viewporter_get_viewport (disp->viewporter, self->bg_surface); + + /* We are opaque */ + wl_surface_set_opaque_region (self->bg_surface, self->opaque_region); + + /* No input, please */ + region = wl_compositor_create_region (disp->compositor); + wl_surface_set_input_region (self->bg_surface, region); + wl_region_destroy (region); +} + +static inline gboolean +scaled_rect_is_integral (const graphene_rect_t *rect, + float scale, + graphene_rect_t *device_rect) +{ + cairo_rectangle_int_t device_int; + + gsk_rect_scale (rect, scale, scale, device_rect); + + device_int.x = device_rect->origin.x; + device_int.y = device_rect->origin.y; + device_int.width = device_rect->size.width; + device_int.height = device_rect->size.height; + + return device_int.x == device_rect->origin.x && + device_int.y == device_rect->origin.y && + device_int.width == device_rect->size.width && + device_int.height == device_rect->size.height; +} + static gboolean gdk_wayland_subsurface_attach (GdkSubsurface *sub, GdkTexture *texture, const graphene_rect_t *source, const graphene_rect_t *dest, GdkTextureTransform transform, + const graphene_rect_t *background, gboolean above, GdkSubsurface *sibling) { GdkWaylandSubsurface *self = GDK_WAYLAND_SUBSURFACE (sub); GdkWaylandSurface *parent = GDK_WAYLAND_SURFACE (sub->parent); + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (sub->parent)); struct wl_buffer *buffer = NULL; gboolean result = FALSE; GdkWaylandSubsurface *sib = sibling ? GDK_WAYLAND_SUBSURFACE (sibling) : NULL; gboolean will_be_above; double scale; graphene_rect_t device_rect; - cairo_rectangle_int_t device_dest; + gboolean has_background; + enum wl_output_transform tf; + gboolean dest_changed = FALSE; + gboolean source_changed = FALSE; + gboolean transform_changed = FALSE; + gboolean stacking_changed = FALSE; + gboolean needs_commit = FALSE; + gboolean background_changed = FALSE; + gboolean needs_bg_commit = FALSE; if (sibling) will_be_above = sibling->above_parent; @@ -190,29 +339,74 @@ gdk_wayland_subsurface_attach (GdkSubsurface *sub, return FALSE; } - self->dest.x = dest->origin.x; - self->dest.y = dest->origin.y; - self->dest.width = dest->size.width; - self->dest.height = dest->size.height; + if (self->dest.x != dest->origin.x || + self->dest.y != dest->origin.y || + self->dest.width != dest->size.width || + self->dest.height != dest->size.height) + { + self->dest.x = dest->origin.x; + self->dest.y = dest->origin.y; + self->dest.width = dest->size.width; + self->dest.height = dest->size.height; + dest_changed = TRUE; + } - self->source.origin.x = source->origin.x; - self->source.origin.y = source->origin.y; - self->source.size.width = source->size.width; - self->source.size.height = source->size.height; + if (!gsk_rect_equal (&self->source, source)) + { + self->source.origin.x = source->origin.x; + self->source.origin.y = source->origin.y; + self->source.size.width = source->size.width; + self->source.size.height = source->size.height; + source_changed = TRUE; + } - self->transform = gdk_texture_transform_to_wl (transform); + tf = gdk_texture_transform_to_wl (transform); + if (self->transform != tf) + { + self->transform = tf; + transform_changed = TRUE; + } + + if (sibling != gdk_subsurface_get_sibling (sub, above) || + will_be_above != gdk_subsurface_is_above_parent (sub)) + stacking_changed = TRUE; + + if (self->texture == NULL) + { + dest_changed = TRUE; + source_changed = TRUE; + transform_changed = TRUE; + stacking_changed = TRUE; + } scale = gdk_fractional_scale_to_double (&parent->scale); - device_rect.origin.x = dest->origin.x * scale; - device_rect.origin.y = dest->origin.y * scale; - device_rect.size.width = dest->size.width * scale; - device_rect.size.height = dest->size.height * scale; + if (background) + { + background_changed = + !self->bg_attached || + self->bg_rect.x != background->origin.x || + self->bg_rect.y != background->origin.y || + self->bg_rect.width != background->size.width || + self->bg_rect.height != background->size.height; + self->bg_rect.x = background->origin.x; + self->bg_rect.y = background->origin.y; + self->bg_rect.width = background->size.width; + self->bg_rect.height = background->size.height; + } + else + { + background_changed = self->bg_attached; + self->bg_rect.x = 0; + self->bg_rect.y = 0; + self->bg_rect.width = 0; + self->bg_rect.height = 0; + } - device_dest.x = device_rect.origin.x; - device_dest.y = device_rect.origin.y; - device_dest.width = device_rect.size.width; - device_dest.height = device_rect.size.height; + has_background = self->bg_rect.width > 0 && self->bg_rect.height > 0; + + if (has_background) + ensure_bg_surface (self); if (self->dest.x != dest->origin.x || self->dest.y != dest->origin.y || @@ -227,19 +421,26 @@ gdk_wayland_subsurface_attach (GdkSubsurface *sub, gdk_texture_get_height (texture), self); } - else if (device_dest.x != device_rect.origin.x || - device_dest.y != device_rect.origin.y || - device_dest.width != device_rect.size.width || - device_dest.height != device_rect.size.height) + else if (!scaled_rect_is_integral (dest, scale, &device_rect)) { GDK_DISPLAY_DEBUG (gdk_surface_get_display (sub->parent), OFFLOAD, "Non-integral device coordinates %g %g %g %g (fractional scale %.2f), hiding subsurface %p", device_rect.origin.x, device_rect.origin.y, - device_rect.size.width, device_rect.size.width, + device_rect.size.width, device_rect.size.height, scale, self); } - else if (!GDK_IS_DMABUF_TEXTURE (texture)) + else if (background && !scaled_rect_is_integral (background, scale, &device_rect)) + { + GDK_DISPLAY_DEBUG (gdk_surface_get_display (sub->parent), OFFLOAD, + "Non-integral background device coordinates %g %g %g %g (fractional scale %.2f), hiding background of subsurface %p", + device_rect.origin.x, device_rect.origin.y, + device_rect.size.width, device_rect.size.height, + scale, + self); + } + else if (!GDK_IS_DMABUF_TEXTURE (texture) && + !GDK_DISPLAY_DEBUG_CHECK (gdk_surface_get_display (sub->parent), FORCE_OFFLOAD)) { GDK_DISPLAY_DEBUG (gdk_surface_get_display (sub->parent), OFFLOAD, "%dx%d %s is not a GdkDmabufTexture, hiding subsurface %p", @@ -257,6 +458,12 @@ gdk_wayland_subsurface_attach (GdkSubsurface *sub, gdk_texture_get_height (texture), self); } + else if (has_background && !display->single_pixel_buffer) + { + GDK_DISPLAY_DEBUG (gdk_surface_get_display (sub->parent), OFFLOAD, + "Cannot offload subsurface %p with background, no single-pixel buffer support", + self); + } else { gboolean was_transparent; @@ -316,14 +523,28 @@ 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, - wl_fixed_from_double (self->source.origin.x), - wl_fixed_from_double (self->source.origin.y), - wl_fixed_from_double (self->source.size.width), - wl_fixed_from_double (self->source.size.height)); + if (transform_changed) + { + wl_surface_set_buffer_transform (self->surface, self->transform); + needs_commit = TRUE; + } + + if (dest_changed) + { + wl_subsurface_set_position (self->subsurface, self->dest.x, self->dest.y); + wp_viewport_set_destination (self->viewport, self->dest.width, self->dest.height); + needs_commit = TRUE; + } + + if (source_changed) + { + wp_viewport_set_source (self->viewport, + wl_fixed_from_double (self->source.origin.x), + wl_fixed_from_double (self->source.origin.y), + wl_fixed_from_double (self->source.size.width), + wl_fixed_from_double (self->source.size.height)); + needs_commit = TRUE; + } if (buffer) { @@ -332,39 +553,95 @@ gdk_wayland_subsurface_attach (GdkSubsurface *sub, 0, 0, gdk_texture_get_width (texture), gdk_texture_get_height (texture)); + needs_commit = TRUE; + } + if (has_background) + { + if (background_changed) + { + wl_subsurface_set_position (self->bg_subsurface, self->bg_rect.x, self->bg_rect.y); + wp_viewport_set_destination (self->bg_viewport, self->bg_rect.width, self->bg_rect.height); + needs_bg_commit = TRUE; + } + + if (!self->bg_attached) + { + self->bg_attached = TRUE; + + wp_viewport_set_source (self->bg_viewport, + wl_fixed_from_int (0), + wl_fixed_from_int (0), + wl_fixed_from_int (1), + wl_fixed_from_int (1)); + wl_surface_attach (self->bg_surface, get_sp_buffer (self), 0, 0); + wl_surface_damage_buffer (self->bg_surface, 0, 0, 1, 1); + needs_bg_commit = TRUE; + } + } + else + { + if (self->bg_attached) + { + self->bg_attached = FALSE; + wl_surface_attach (self->bg_surface, NULL, 0, 0); + needs_bg_commit = TRUE; + } } result = TRUE; } else { - g_set_object (&self->texture, NULL); + if (g_set_object (&self->texture, NULL)) + { + wl_surface_attach (self->surface, NULL, 0, 0); + needs_commit = TRUE; + } - wl_surface_attach (self->surface, NULL, 0, 0); + if (self->bg_attached) + { + self->bg_attached = FALSE; + wl_surface_attach (self->bg_surface, NULL, 0, 0); + needs_bg_commit = TRUE; + } } - if (sib) + if (stacking_changed) { - if (above) - wl_subsurface_place_above (self->subsurface, sib->surface); + if (sib) + { + if (above) + wl_subsurface_place_above (self->subsurface, sib->surface); + else + wl_subsurface_place_below (self->subsurface, sib->surface); + } else - wl_subsurface_place_below (self->subsurface, sib->surface); - } - else - { - if (above) - wl_subsurface_place_above (self->subsurface, - GDK_WAYLAND_SURFACE (sub->parent)->display_server.wl_surface); - else - wl_subsurface_place_below (self->subsurface, - GDK_WAYLAND_SURFACE (sub->parent)->display_server.wl_surface); + { + if (above) + wl_subsurface_place_above (self->subsurface, + GDK_WAYLAND_SURFACE (sub->parent)->display_server.wl_surface); + else + wl_subsurface_place_below (self->subsurface, + GDK_WAYLAND_SURFACE (sub->parent)->display_server.wl_surface); + } + needs_commit = TRUE; + + if (self->bg_attached) + { + wl_subsurface_place_below (self->bg_subsurface, self->surface); + needs_bg_commit = TRUE; + } } - wl_surface_commit (self->surface); + if (needs_commit) + wl_surface_commit (self->surface); - ((GdkWaylandSurface *)sub->parent)->has_pending_subsurface_commits = TRUE; - GDK_WAYLAND_SURFACE (sub->parent)->opaque_region_dirty = TRUE; + if (needs_bg_commit) + wl_surface_commit (self->bg_surface); + + ((GdkWaylandSurface *)sub->parent)->has_pending_subsurface_commits = needs_commit || needs_bg_commit; + GDK_WAYLAND_SURFACE (sub->parent)->opaque_region_dirty = stacking_changed || dest_changed || background_changed; return result; } @@ -385,6 +662,13 @@ gdk_wayland_subsurface_detach (GdkSubsurface *sub) wl_surface_set_opaque_region (self->surface, self->opaque_region); wl_surface_commit (self->surface); + if (self->bg_attached) + { + wl_surface_attach (self->bg_surface, NULL, 0, 0); + wl_surface_commit (self->bg_surface); + self->bg_attached = FALSE; + } + ((GdkWaylandSurface *)sub->parent)->has_pending_subsurface_commits = TRUE; GDK_WAYLAND_SURFACE (sub->parent)->opaque_region_dirty = TRUE; } @@ -398,27 +682,27 @@ gdk_wayland_subsurface_get_texture (GdkSubsurface *sub) } static void -gdk_wayland_subsurface_get_dest (GdkSubsurface *sub, - graphene_rect_t *dest) +gdk_wayland_subsurface_get_texture_rect (GdkSubsurface *sub, + graphene_rect_t *rect) { GdkWaylandSubsurface *self = GDK_WAYLAND_SUBSURFACE (sub); - dest->origin.x = self->dest.x; - dest->origin.y = self->dest.y; - dest->size.width = self->dest.width; - dest->size.height = self->dest.height; + rect->origin.x = self->dest.x; + rect->origin.y = self->dest.y; + rect->size.width = self->dest.width; + rect->size.height = self->dest.height; } static void -gdk_wayland_subsurface_get_source (GdkSubsurface *sub, - graphene_rect_t *source) +gdk_wayland_subsurface_get_source_rect (GdkSubsurface *sub, + graphene_rect_t *rect) { GdkWaylandSubsurface *self = GDK_WAYLAND_SUBSURFACE (sub); - source->origin.x = self->source.origin.x; - source->origin.y = self->source.origin.y; - source->size.width = self->source.size.width; - source->size.height = self->source.size.height; + rect->origin.x = self->source.origin.x; + rect->origin.y = self->source.origin.y; + rect->size.width = self->source.size.width; + rect->size.height = self->source.size.height; } static GdkTextureTransform @@ -429,6 +713,20 @@ gdk_wayland_subsurface_get_transform (GdkSubsurface *sub) return wl_output_transform_to_gdk (self->transform); } +static gboolean +gdk_wayland_subsurface_get_background_rect (GdkSubsurface *sub, + graphene_rect_t *rect) +{ + GdkWaylandSubsurface *self = GDK_WAYLAND_SUBSURFACE (sub); + + rect->origin.x = self->bg_rect.x; + rect->origin.y = self->bg_rect.y; + rect->size.width = self->bg_rect.width; + rect->size.height = self->bg_rect.height; + + return rect->size.width > 0 && rect->size.height > 0; +} + static void gdk_wayland_subsurface_class_init (GdkWaylandSubsurfaceClass *class) { @@ -440,9 +738,10 @@ gdk_wayland_subsurface_class_init (GdkWaylandSubsurfaceClass *class) subsurface_class->attach = gdk_wayland_subsurface_attach; subsurface_class->detach = gdk_wayland_subsurface_detach; 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_source_rect = gdk_wayland_subsurface_get_source_rect; + subsurface_class->get_texture_rect = gdk_wayland_subsurface_get_texture_rect; subsurface_class->get_transform = gdk_wayland_subsurface_get_transform; + subsurface_class->get_background_rect = gdk_wayland_subsurface_get_background_rect; }; static void diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index ce5f0558f8..2792cb9762 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -54,6 +54,8 @@ #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "presentation-time-client-protocol.h" +#include "gsk/gskrectprivate.h" + /** * GdkWaylandSurface: @@ -657,6 +659,7 @@ static void gdk_wayland_surface_sync_opaque_region (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); struct wl_region *wl_region = NULL; if (!impl->display_server.wl_surface) @@ -679,16 +682,21 @@ gdk_wayland_surface_sync_opaque_region (GdkSurface *surface) continue; if (sub->texture != NULL) - cairo_region_subtract_rectangle (region, &sub->dest); + { + graphene_rect_t bounds; + cairo_rectangle_int_t rect; + + gdk_subsurface_get_bounds (subsurface, &bounds); + gsk_rect_to_cairo_grow (&bounds, &rect); + cairo_region_subtract_rectangle (region, &rect); + } } - wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)), - region); + wl_region = wl_region_from_cairo_region (display, region); cairo_region_destroy (region); } else - wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)), - impl->opaque_region); + wl_region = wl_region_from_cairo_region (display, impl->opaque_region); } wl_surface_set_opaque_region (impl->display_server.wl_surface, wl_region); diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build index 16e5e0a6a0..0ed74bb80b 100644 --- a/gdk/wayland/meson.build +++ b/gdk/wayland/meson.build @@ -66,6 +66,7 @@ proto_sources = [ wlmod.find_protocol('fractional-scale', state: 'staging', version: 1), wlmod.find_protocol('linux-dmabuf', state: 'unstable', version: 1), wlmod.find_protocol('presentation-time', state: 'stable'), + wlmod.find_protocol('single-pixel-buffer', state: 'staging', version: 1), ] gdk_wayland_gen_headers = [] diff --git a/gsk/gskoffload.c b/gsk/gskoffload.c index 0ef9323a7c..79966d2179 100644 --- a/gsk/gskoffload.c +++ b/gsk/gskoffload.c @@ -81,17 +81,26 @@ find_texture_transform (GskTransform *transform) } static GdkTexture * -find_texture_to_attach (GskOffload *self, - GdkSubsurface *subsurface, - const GskRenderNode *node, - graphene_rect_t *out_clip, - GdkTextureTransform *out_texture_transform) +find_texture_to_attach (GskOffload *self, + const GskRenderNode *subsurface_node, + graphene_rect_t *out_texture_rect, + graphene_rect_t *out_source_rect, + gboolean *has_background, + GdkTextureTransform *out_texture_transform) { + GdkSubsurface *subsurface; + const GskRenderNode *node; gboolean has_clip = FALSE; graphene_rect_t clip; GskTransform *transform = NULL; GdkTexture *ret = NULL; + *has_background = FALSE; + *out_texture_transform = GDK_TEXTURE_TRANSFORM_NORMAL; + + subsurface = gsk_subsurface_node_get_subsurface (subsurface_node); + node = subsurface_node; + for (;;) { switch ((int) GSK_RENDER_NODE_TYPE (node)) @@ -100,17 +109,41 @@ find_texture_to_attach (GskOffload *self, node = gsk_debug_node_get_child (node); break; - case GSK_CONTAINER_NODE: - if (gsk_container_node_get_n_children (node) != 1) - { - 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)); - goto out; - } - node = gsk_container_node_get_child (node, 0); + case GSK_SUBSURFACE_NODE: + node = gsk_subsurface_node_get_child (node); break; + case GSK_CONTAINER_NODE: + if (gsk_container_node_get_n_children (node) == 1) + { + node = gsk_container_node_get_child (node, 0); + break; + } + else if (gsk_container_node_get_n_children (node) == 2) + { + GskRenderNode *child = gsk_container_node_get_child (node, 0); + graphene_rect_t bounds; + + gsk_transform_transform_bounds (transform, &child->bounds, &bounds); + if (GSK_RENDER_NODE_TYPE (child) == GSK_COLOR_NODE && + gsk_rect_equal (&bounds, &subsurface_node->bounds) && + gdk_rgba_equal (gsk_color_node_get_color (child), &(GdkRGBA) { 0, 0, 0, 1 })) + { + GDK_DISPLAY_DEBUG (gdk_surface_get_display (self->surface), OFFLOAD, + "Offloading subsurface %p with background", + subsurface); + *has_background = TRUE; + + node = gsk_container_node_get_child (node, 1); + break; + } + } + + 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)); + goto out; + case GSK_TRANSFORM_NODE: { GskTransform *t = gsk_transform_node_get_transform (node); @@ -153,6 +186,7 @@ find_texture_to_attach (GskOffload *self, } else { + gsk_transform_transform_bounds (transform, &node->bounds, out_texture_rect); clip = *c; has_clip = TRUE; } @@ -176,17 +210,18 @@ find_texture_to_attach (GskOffload *self, gsk_rect_intersection (&node->bounds, &clip, &clip); - out_clip->origin.x = (clip.origin.x - dx) * sx; - out_clip->origin.y = (clip.origin.y - dy) * sy; - out_clip->size.width = clip.size.width * sx; - out_clip->size.height = clip.size.height * sy; + out_source_rect->origin.x = (clip.origin.x - dx) * sx; + out_source_rect->origin.y = (clip.origin.y - dy) * sy; + out_source_rect->size.width = clip.size.width * sx; + out_source_rect->size.height = clip.size.height * sy; } else { - out_clip->origin.x = 0; - out_clip->origin.y = 0; - out_clip->size.width = gdk_texture_get_width (texture); - out_clip->size.height = gdk_texture_get_height (texture); + gsk_transform_transform_bounds (transform, &node->bounds, out_texture_rect); + out_source_rect->origin.x = 0; + out_source_rect->origin.y = 0; + out_source_rect->size.width = gdk_texture_get_width (texture); + out_source_rect->size.height = gdk_texture_get_height (texture); } ret = texture; @@ -444,7 +479,8 @@ visit_node (GskOffload *self, if (info->can_raise) { - if (gsk_rect_intersects (&transformed_bounds, &info->dest)) + if (gsk_rect_intersects (&transformed_bounds, &info->texture_rect) || + gsk_rect_intersects (&transformed_bounds, &info->background_rect)) { GskRenderNodeType type = GSK_RENDER_NODE_TYPE (node); @@ -469,7 +505,6 @@ visit_node (GskOffload *self, switch (GSK_RENDER_NODE_TYPE (node)) { case GSK_BORDER_NODE: - case GSK_COLOR_NODE: case GSK_CONIC_GRADIENT_NODE: case GSK_LINEAR_GRADIENT_NODE: case GSK_REPEATING_LINEAR_GRADIENT_NODE: @@ -479,6 +514,7 @@ visit_node (GskOffload *self, case GSK_TEXTURE_NODE: case GSK_TEXTURE_SCALE_NODE: case GSK_CAIRO_NODE: + case GSK_COLOR_NODE: case GSK_INSET_SHADOW_NODE: case GSK_OUTSET_SHADOW_NODE: case GSK_GL_SHADER_NODE: @@ -492,7 +528,7 @@ visit_node (GskOffload *self, case GSK_MASK_NODE: case GSK_FILL_NODE: case GSK_STROKE_NODE: - break; + break; case GSK_CLIP_NODE: { @@ -615,12 +651,16 @@ complex_clip: } else { - info->texture = find_texture_to_attach (self, subsurface, gsk_subsurface_node_get_child (node), &info->source, &info->transform); + gboolean has_background; + + info->texture = find_texture_to_attach (self, node, &info->texture_rect, &info->source_rect, &has_background, &info->transform); if (info->texture) { info->can_offload = TRUE; info->can_raise = TRUE; - transform_bounds (self, &node->bounds, &info->dest); + transform_bounds (self, &info->texture_rect, &info->texture_rect); + info->has_background = has_background; + transform_bounds (self, &node->bounds, &info->background_rect); info->place_above = self->last_info ? self->last_info->subsurface : NULL; self->last_info = info; } @@ -660,9 +700,12 @@ gsk_offload_new (GdkSurface *surface, for (gsize i = 0; i < self->n_subsurfaces; i++) { GskOffloadInfo *info = &self->subsurfaces[i]; + graphene_rect_t rect; + info->subsurface = gdk_surface_get_subsurface (self->surface, i); info->was_offloaded = gdk_subsurface_get_texture (info->subsurface) != NULL; info->was_above = gdk_subsurface_is_above_parent (info->subsurface); + info->had_background = gdk_subsurface_get_background_rect (info->subsurface, &rect); } if (self->n_subsurfaces > 0) @@ -679,25 +722,28 @@ gsk_offload_new (GdkSurface *surface, for (gsize i = 0; i < self->n_subsurfaces; i++) { GskOffloadInfo *info = &self->subsurfaces[i]; - graphene_rect_t old_dest; + graphene_rect_t old_bounds; + graphene_rect_t bounds; - gdk_subsurface_get_dest (info->subsurface, &old_dest); + gdk_subsurface_get_bounds (info->subsurface, &old_bounds); if (info->can_offload) { if (info->can_raise) info->is_offloaded = gdk_subsurface_attach (info->subsurface, info->texture, - &info->source, - &info->dest, + &info->source_rect, + &info->texture_rect, info->transform, + info->has_background ? &info->background_rect : NULL, TRUE, NULL); else info->is_offloaded = gdk_subsurface_attach (info->subsurface, info->texture, - &info->source, - &info->dest, + &info->source_rect, + &info->texture_rect, info->transform, + info->has_background ? &info->background_rect : NULL, info->place_above != NULL, info->place_above); } @@ -717,22 +763,24 @@ gsk_offload_new (GdkSurface *surface, info->is_above = TRUE; } + gdk_subsurface_get_bounds (info->subsurface, &bounds); + if (info->is_offloaded != info->was_offloaded || info->is_above != info->was_above || - (info->is_offloaded && !gsk_rect_equal (&info->dest, &old_dest))) + (info->is_offloaded && !gsk_rect_equal (&bounds, &old_bounds))) { /* We changed things, need to invalidate everything */ - cairo_rectangle_int_t int_dest; + cairo_rectangle_int_t rect; if (info->is_offloaded) { - gsk_rect_to_cairo_grow (&info->dest, &int_dest); - cairo_region_union_rectangle (diff, &int_dest); + gsk_rect_to_cairo_grow (&bounds, &rect); + cairo_region_union_rectangle (diff, &rect); } if (info->was_offloaded) { - gsk_rect_to_cairo_grow (&old_dest, &int_dest); - cairo_region_union_rectangle (diff, &int_dest); + gsk_rect_to_cairo_grow (&old_bounds, &rect); + cairo_region_union_rectangle (diff, &rect); } } diff --git a/gsk/gskoffloadprivate.h b/gsk/gskoffloadprivate.h index c4c604179a..6848d83436 100644 --- a/gsk/gskoffloadprivate.h +++ b/gsk/gskoffloadprivate.h @@ -31,9 +31,10 @@ typedef struct GdkSubsurface *subsurface; GdkTexture *texture; GdkSubsurface *place_above; - graphene_rect_t dest; - graphene_rect_t source; + graphene_rect_t texture_rect; + graphene_rect_t source_rect; GdkTextureTransform transform; + graphene_rect_t background_rect; guint was_offloaded : 1; guint can_offload : 1; @@ -42,6 +43,9 @@ typedef struct guint was_above : 1; guint can_raise : 1; guint is_above : 1; + + guint had_background : 1; + guint has_background : 1; } GskOffloadInfo; GskOffload * gsk_offload_new (GdkSurface *surface, diff --git a/gtk/inspector/general.c b/gtk/inspector/general.c index 027eb0ad72..e025557e59 100644 --- a/gtk/inspector/general.c +++ b/gtk/inspector/general.c @@ -694,6 +694,7 @@ add_wayland_protocols (GdkDisplay *display, append_wayland_protocol_row (gen, (struct wl_proxy *)d->fractional_scale); append_wayland_protocol_row (gen, (struct wl_proxy *)d->viewporter); append_wayland_protocol_row (gen, (struct wl_proxy *)d->presentation); + append_wayland_protocol_row (gen, (struct wl_proxy *)d->single_pixel_buffer); } } #endif diff --git a/gtk/inspector/subsurfaceoverlay.c b/gtk/inspector/subsurfaceoverlay.c index 8e5a203365..7701ebcff3 100644 --- a/gtk/inspector/subsurfaceoverlay.c +++ b/gtk/inspector/subsurfaceoverlay.c @@ -50,7 +50,7 @@ gtk_subsurface_overlay_snapshot (GtkInspectorOverlay *overlay, else gdk_rgba_parse (&color, "magenta"); - gdk_subsurface_get_dest (subsurface, &dest); + gdk_subsurface_get_texture_rect (subsurface, &dest); /* Use 4 color nodes since a border node overlaps and prevents * the subsurface from being raised. diff --git a/gtk/theme/Default/_common.scss b/gtk/theme/Default/_common.scss index 5197eeb84a..883e37fe8c 100644 --- a/gtk/theme/Default/_common.scss +++ b/gtk/theme/Default/_common.scss @@ -3940,7 +3940,9 @@ video { min-height: 64px; border-radius: 32px; } - background: black; + & graphicsoffload > picture { + background: black; + } } /************ diff --git a/testsuite/gdk/subsurface.c b/testsuite/gdk/subsurface.c index 37657e8049..3a63fe44b9 100644 --- a/testsuite/gdk/subsurface.c +++ b/testsuite/gdk/subsurface.c @@ -1,6 +1,7 @@ #include #include "gdk/gdksurfaceprivate.h" #include "gdk/gdksubsurfaceprivate.h" +#include "gdk/gdkdebugprivate.h" #ifdef GDK_WINDOWING_WAYLAND #include "gdk/wayland/gdkwayland.h" @@ -11,6 +12,53 @@ gdk_texture_get_width (t), \ gdk_texture_get_height (t)) +static void +test_subsurface_basics (void) +{ + GdkSurface *surface; + GdkSubsurface *sub; + GdkTexture *texture; + graphene_rect_t rect; + +#ifdef GDK_WINDOWING_WAYLAND + if (!GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) +#endif + { + g_test_skip ("No subsurface support"); + return; + } + + surface = gdk_surface_new_toplevel (gdk_display_get_default ()); + + g_assert_true (surface->subsurfaces_below == NULL); + g_assert_true (surface->subsurfaces_above == NULL); + + sub = gdk_surface_create_subsurface (surface); + + g_assert_true (gdk_subsurface_get_parent (sub) == surface); + + g_assert_null (gdk_subsurface_get_texture (sub)); + g_assert_false (gdk_subsurface_is_above_parent (sub)); + g_assert_true (gdk_subsurface_get_transform (sub) == GDK_TEXTURE_TRANSFORM_NORMAL); + + texture = gdk_texture_new_from_resource ("/org/gtk/libgtk/icons/16x16/actions/media-eject.png"); + gdk_subsurface_attach (sub, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_90, &GRAPHENE_RECT_INIT (0, 0, 20, 20), TRUE, NULL); + + g_assert_true (gdk_subsurface_get_texture (sub) == texture); + g_assert_true (gdk_subsurface_is_above_parent (sub)); + g_assert_true (gdk_subsurface_get_transform (sub) == GDK_TEXTURE_TRANSFORM_90); + gdk_subsurface_get_source_rect (sub, &rect); + g_assert_true (graphene_rect_equal (&rect, &TEXTURE_RECT (texture))); + gdk_subsurface_get_texture_rect (sub, &rect); + g_assert_true (graphene_rect_equal (&rect, &GRAPHENE_RECT_INIT (0, 0, 10, 10))); + gdk_subsurface_get_background_rect (sub, &rect); + g_assert_true (graphene_rect_equal (&rect, &GRAPHENE_RECT_INIT (0, 0, 20, 20))); + + g_object_unref (sub); + g_object_unref (texture); + gdk_surface_destroy (surface); +} + static void test_subsurface_stacking (void) { @@ -42,9 +90,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), 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); + gdk_subsurface_attach (sub0, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, NULL, TRUE, NULL); + gdk_subsurface_attach (sub1, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, NULL, TRUE, NULL); + gdk_subsurface_attach (sub2, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, NULL, TRUE, NULL); g_assert_true (surface->subsurfaces_above == sub2); g_assert_true (sub2->sibling_below == NULL); @@ -67,7 +115,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), GDK_TEXTURE_TRANSFORM_NORMAL, FALSE, NULL); + gdk_subsurface_attach (sub2, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, NULL, FALSE, NULL); g_assert_true (surface->subsurfaces_above == sub0); g_assert_true (sub0->sibling_below == NULL); @@ -79,7 +127,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), GDK_TEXTURE_TRANSFORM_NORMAL, TRUE, sub2); + gdk_subsurface_attach (sub1, texture, &TEXTURE_RECT (texture), &GRAPHENE_RECT_INIT (0, 0, 10, 10), GDK_TEXTURE_TRANSFORM_NORMAL, NULL, TRUE, sub2); g_assert_true (surface->subsurfaces_below == sub1); g_assert_true (sub1->sibling_above == NULL); @@ -103,6 +151,9 @@ main (int argc, char *argv[]) { gtk_test_init (&argc, &argv, NULL); + gdk_display_set_debug_flags (gdk_display_get_default (), GDK_DEBUG_FORCE_OFFLOAD); + + g_test_add_func ("/subsurface/basics", test_subsurface_basics); g_test_add_func ("/subsurface/stacking", test_subsurface_stacking); return g_test_run (); diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index d8776c451a..a7289b6e64 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -478,6 +478,8 @@ if os_linux 'clipped.node', 'not-clipped.node', 'complex-clip.node', + 'background.node', + 'background2.node', ] foreach test : offload_tests @@ -487,10 +489,10 @@ if os_linux join_paths(meson.current_source_dir(), 'offload', test) ], env: [ - 'GSK_RENDERER=opengl', 'GTK_A11Y=test', 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), - 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()) + 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()), + 'GDK_DEBUG=force-offload', ], protocol: 'exitcode', suite: ['gsk', 'offload'], diff --git a/testsuite/gsk/offload.c b/testsuite/gsk/offload.c index 3e2b186411..03c9611d70 100644 --- a/testsuite/gsk/offload.c +++ b/testsuite/gsk/offload.c @@ -210,11 +210,16 @@ collect_offload_info (GdkSurface *surface, gdk_texture_get_width (info->texture), gdk_texture_get_height (info->texture)); g_string_append_printf (s, "source: %g %g %g %g, ", - info->source.origin.x, info->source.origin.y, - info->source.size.width, info->source.size.height); - g_string_append_printf (s, "dest: %g %g %g %g\n", - info->dest.origin.x, info->dest.origin.y, - info->dest.size.width, info->dest.size.height); + info->source_rect.origin.x, info->source_rect.origin.y, + info->source_rect.size.width, info->source_rect.size.height); + g_string_append_printf (s, "dest: %g %g %g %g", + info->texture_rect.origin.x, info->texture_rect.origin.y, + info->texture_rect.size.width, info->texture_rect.size.height); + if (info->has_background) + g_string_append_printf (s, ", background: %g %g %g %g", + info->background_rect.origin.x, info->background_rect.origin.y, + info->background_rect.size.width, info->background_rect.size.height); + g_string_append (s, "\n"); } else g_string_append_printf (s, "%u: %snot offloaded\n", @@ -416,8 +421,11 @@ parse_node_file (GFile *file, const char *generate) g_assert_no_error (error); if (diff && g_bytes_get_size (diff) > 0) { - g_print ("Resulting .offload file doesn't match reference:\n%s\n", + char *basename = g_path_get_basename (reference_file); + g_print ("Resulting file doesn't match reference (%s):\n%s\n", + basename, (const char *) g_bytes_get_data (diff, NULL)); + g_free (basename); result = FALSE; } @@ -452,8 +460,11 @@ parse_node_file (GFile *file, const char *generate) g_assert_no_error (error); if (diff && g_bytes_get_size (diff) > 0) { - g_print ("Resulting .offload2 file doesn't match reference:\n%s\n", + char *basename = g_path_get_basename (reference_file); + g_print ("Resulting file doesn't match reference (%s):\n%s\n", + basename, (const char *) g_bytes_get_data (diff, NULL)); + g_free (basename); result = FALSE; } diff --git a/testsuite/gsk/offload/background.node b/testsuite/gsk/offload/background.node new file mode 100644 index 0000000000..b3078ab81d --- /dev/null +++ b/testsuite/gsk/offload/background.node @@ -0,0 +1,71 @@ +container { + + transform { + child: subsurface { + child: container { + color { + bounds: 0 0 100 100; + color: black; + } + texture { + texture: url('data:image/svg+xml;utf-8,'); + } + } + } + } + + debug { + message: "Non-black background doesn't work"; + child: subsurface { + child: container { + color { + bounds: 0 0 100 100; + color: red; + } + texture { + texture: url('data:image/svg+xml;utf-8,'); + } + } + } + } + + debug { + message: "Can't have too much content"; + child: subsurface { + child: container { + color { + bounds: 0 0 100 100; + color: black; + } + color { + bounds: 0 0 20 20; + color: red; + } + texture { + texture: url('data:image/svg+xml;utf-8,'); + } + } + } + } + + debug { + message: "Texture can be deeper in"; + child: subsurface { + child: container { + color { + bounds: 0 0 100 100; + color: black; + } + container { + debug { + message: "bla"; + child: texture { + texture: url('data:image/svg+xml;utf-8,'); + } + } + } + } + } + } + +} diff --git a/testsuite/gsk/offload/background.offload b/testsuite/gsk/offload/background.offload new file mode 100644 index 0000000000..e6bedfa12a --- /dev/null +++ b/testsuite/gsk/offload/background.offload @@ -0,0 +1,4 @@ +0: offloaded, above: -, texture: 13x17, source: 0 0 13 17, dest: 0 0 50 50, background: 0 0 100 100 +1: not offloaded +2: not offloaded +3: offloaded, raised, above: 0, texture: 13x17, source: 0 0 13 17, dest: 0 0 50 50, background: 0 0 100 100 diff --git a/testsuite/gsk/offload/background2.diff b/testsuite/gsk/offload/background2.diff new file mode 100644 index 0000000000..542ff51bdc --- /dev/null +++ b/testsuite/gsk/offload/background2.diff @@ -0,0 +1 @@ +0 0 50 50 diff --git a/testsuite/gsk/offload/background2.node b/testsuite/gsk/offload/background2.node new file mode 100644 index 0000000000..a6d9d0d547 --- /dev/null +++ b/testsuite/gsk/offload/background2.node @@ -0,0 +1,15 @@ +container { + + subsurface { + child: container { + color { + bounds: 0 0 100 100; + color: black; + } + texture { + texture: url('data:image/svg+xml;utf-8,'); + } + } + } + +} diff --git a/testsuite/gsk/offload/background2.node2 b/testsuite/gsk/offload/background2.node2 new file mode 100644 index 0000000000..bb670adcfc --- /dev/null +++ b/testsuite/gsk/offload/background2.node2 @@ -0,0 +1,22 @@ +container { + + subsurface { + child: container { + color { + bounds: 0 0 100 100; + color: black; + } + texture { + texture: url('data:image/svg+xml;utf-8,'); + } + } + } + + debug { + message: "Put something on top, so we switch from above to below"; + child: color { + bounds: 0 0 10 10; + color: red; + } + } +} diff --git a/testsuite/gsk/offload/background2.offload b/testsuite/gsk/offload/background2.offload new file mode 100644 index 0000000000..d100720f95 --- /dev/null +++ b/testsuite/gsk/offload/background2.offload @@ -0,0 +1 @@ +0: offloaded, raised, above: -, texture: 13x17, source: 0 0 13 17, dest: 0 0 50 50, background: 0 0 100 100 diff --git a/testsuite/gsk/offload/background2.offload2 b/testsuite/gsk/offload/background2.offload2 new file mode 100644 index 0000000000..e128259b60 --- /dev/null +++ b/testsuite/gsk/offload/background2.offload2 @@ -0,0 +1 @@ +0: offloaded, was offloaded, above: -, texture: 13x17, source: 0 0 13 17, dest: 0 0 50 50, background: 0 0 100 100 diff --git a/testsuite/gsk/offload/deep.node b/testsuite/gsk/offload/deep.node index 459094bf3d..d553c8445d 100644 --- a/testsuite/gsk/offload/deep.node +++ b/testsuite/gsk/offload/deep.node @@ -43,7 +43,7 @@ subsurface { } subsurface { child: debug { - message: "Clips (regardless how large) are not ok"; + message: "Clips are ok"; child: clip { clip: 0 0 400 400; child: texture { } diff --git a/testsuite/gsk/offload/move.offload2 b/testsuite/gsk/offload/move.offload2 index b656abf6a1..65d6b78c5f 100644 --- a/testsuite/gsk/offload/move.offload2 +++ b/testsuite/gsk/offload/move.offload2 @@ -1 +1 @@ -0: offloaded, raised, above: -, texture: 16x16, source: 0 0 16 16, dest: 40 40 20 20 +0: offloaded, was offloaded, raised, above: -, texture: 16x16, source: 0 0 16 16, dest: 40 40 20 20 diff --git a/testsuite/gsk/offload/start_offloading.diff b/testsuite/gsk/offload/start_offloading.diff index 039342357c..08f07ec9af 100644 --- a/testsuite/gsk/offload/start_offloading.diff +++ b/testsuite/gsk/offload/start_offloading.diff @@ -1,2 +1 @@ -0 0 16 16 16 16 16 16 diff --git a/testsuite/gsk/offload/stop_offloading.offload2 b/testsuite/gsk/offload/stop_offloading.offload2 index 94737aed76..cd6081cb46 100644 --- a/testsuite/gsk/offload/stop_offloading.offload2 +++ b/testsuite/gsk/offload/stop_offloading.offload2 @@ -1 +1 @@ -0: not offloaded +0: was offloaded, not offloaded