diff options
author | Benjamin Otte <otte.benjamin@googlemail.com> | 2023-05-06 00:59:25 +0000 |
---|---|---|
committer | Benjamin Otte <otte.benjamin@googlemail.com> | 2023-05-06 00:59:25 +0000 |
commit | 2a950dec71ce9b572ef6666430536ec3931b0188 (patch) | |
tree | 44758c2cef496d33faf532ed0e4ebfc6fdbb7e94 /gdk | |
parent | d6c80d4f35aa73624028d4e4af95d61e856901c1 (diff) | |
parent | 97aff588d553b147220a1af8eb0d5fad08fefcf3 (diff) | |
download | gtk+-2a950dec71ce9b572ef6666430536ec3931b0188.tar.gz |
Merge branch 'wip/otte/update-texture' into 'main'
Add texture update regions
See merge request GNOME/gtk!5880
Diffstat (limited to 'gdk')
-rw-r--r-- | gdk/gdkgltexture.c | 17 | ||||
-rw-r--r-- | gdk/gdkgltexturebuilder.c | 147 | ||||
-rw-r--r-- | gdk/gdkgltexturebuilder.h | 12 | ||||
-rw-r--r-- | gdk/gdktexture.c | 44 | ||||
-rw-r--r-- | gdk/gdktextureprivate.h | 14 |
5 files changed, 233 insertions, 1 deletions
diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index b409ae852d..e08711aaf2 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -338,6 +338,7 @@ gdk_gl_texture_new_from_builder (GdkGLTextureBuilder *builder, gpointer data) { GdkGLTexture *self; + GdkTexture *update_texture; self = g_object_new (GDK_TYPE_GL_TEXTURE, "width", gdk_gl_texture_builder_get_width (builder), @@ -353,6 +354,22 @@ gdk_gl_texture_new_from_builder (GdkGLTextureBuilder *builder, self->destroy = destroy; self->data = data; + update_texture = gdk_gl_texture_builder_get_update_texture (builder); + if (update_texture) + { + cairo_region_t *update_region = gdk_gl_texture_builder_get_update_region (builder); + if (update_region) + { + update_region = cairo_region_copy (update_region); + cairo_region_intersect_rectangle (update_region, + &(cairo_rectangle_int_t) { + 0, 0, + update_texture->width, update_texture->height + }); + gdk_texture_set_diff (GDK_TEXTURE (self), update_texture, update_region); + } + } + return GDK_TEXTURE (self); } diff --git a/gdk/gdkgltexturebuilder.c b/gdk/gdkgltexturebuilder.c index ceaf44a9c8..ec885fea72 100644 --- a/gdk/gdkgltexturebuilder.c +++ b/gdk/gdkgltexturebuilder.c @@ -25,6 +25,8 @@ #include "gdkglcontext.h" #include "gdkgltextureprivate.h" +#include <cairo-gobject.h> + struct _GdkGLTextureBuilder { GObject parent_instance; @@ -36,6 +38,9 @@ struct _GdkGLTextureBuilder GdkMemoryFormat format; gboolean has_mipmap; gpointer sync; + + GdkTexture *update_texture; + cairo_region_t *update_region; }; struct _GdkGLTextureBuilderClass @@ -70,6 +75,8 @@ enum PROP_HEIGHT, PROP_ID, PROP_SYNC, + PROP_UPDATE_REGION, + PROP_UPDATE_TEXTURE, PROP_WIDTH, N_PROPS @@ -86,6 +93,9 @@ gdk_gl_texture_builder_dispose (GObject *object) g_clear_object (&self->context); + g_clear_object (&self->update_texture); + g_clear_pointer (&self->update_region, cairo_region_destroy); + G_OBJECT_CLASS (gdk_gl_texture_builder_parent_class)->dispose (object); } @@ -123,6 +133,14 @@ gdk_gl_texture_builder_get_property (GObject *object, g_value_set_pointer (value, self->sync); break; + case PROP_UPDATE_REGION: + g_value_set_boxed (value, self->update_region); + break; + + case PROP_UPDATE_TEXTURE: + g_value_set_object (value, self->update_texture); + break; + case PROP_WIDTH: g_value_set_int (value, self->width); break; @@ -167,6 +185,14 @@ gdk_gl_texture_builder_set_property (GObject *object, gdk_gl_texture_builder_set_sync (self, g_value_get_pointer (value)); break; + case PROP_UPDATE_REGION: + gdk_gl_texture_builder_set_update_region (self, g_value_get_boxed (value)); + break; + + case PROP_UPDATE_TEXTURE: + gdk_gl_texture_builder_set_update_texture (self, g_value_get_object (value)); + break; + case PROP_WIDTH: gdk_gl_texture_builder_set_width (self, g_value_get_int (value)); break; @@ -261,6 +287,30 @@ gdk_gl_texture_builder_class_init (GdkGLTextureBuilderClass *klass) G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); /** + * GdkGLTextureBuilder:update-region: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_update_region org.gdk.Property.set=gdk_gl_texture_builder_set_update_region) + * + * The update region for [property@Gdk.GLTextureBuilder:update-texture]. + * + * Since: 4.12 + */ + properties[PROP_UPDATE_REGION] = + g_param_spec_boxed ("update-region", NULL, NULL, + CAIRO_GOBJECT_TYPE_REGION, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GdkGLTextureBuilder:update-texture: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_update_texture org.gdk.Property.set=gdk_gl_texture_builder_set_update_texture) + * + * The texture [property@Gdk.GLTextureBuilder:update-region] is an update for. + * + * Since: 4.12 + */ + properties[PROP_UPDATE_TEXTURE] = + g_param_spec_object ("update-texture", NULL, NULL, + GDK_TYPE_TEXTURE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** * GdkGLTextureBuilder:width: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_width org.gdk.Property.set=gdk_gl_texture_builder_set_width) * * The width of the texture. @@ -271,6 +321,7 @@ gdk_gl_texture_builder_class_init (GdkGLTextureBuilderClass *klass) g_param_spec_int ("width", NULL, NULL, G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, N_PROPS, properties); } @@ -614,6 +665,102 @@ gdk_gl_texture_builder_set_format (GdkGLTextureBuilder *self, } /** + * gdk_gl_texture_builder_get_update_texture: (attributes org.gdk.Method.get_property=update_texture) + * @self: a `GdkGLTextureBuilder` + * + * Gets the texture previously set via gdk_gl_texture_builder_set_update_texture() or + * %NULL if none was set. + * + * Returns: (transfer none) (nullable): The texture + * + * Since: 4.12 + */ +GdkTexture * +gdk_gl_texture_builder_get_update_texture (GdkGLTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL); + + return self->update_texture; +} + +/** + * gdk_gl_texture_builder_set_update_texture: (attributes org.gdk.Method.set_property=update_texture) + * @self: a `GdkGLTextureBuilder` + * @texture: (nullable): the texture to update + * + * Sets the texture to be updated by this texture. See + * [method@Gdk.GLTextureBuilder.set_update_region] for an explanation. + * + * Since: 4.12 + */ +void +gdk_gl_texture_builder_set_update_texture (GdkGLTextureBuilder *self, + GdkTexture *texture) +{ + g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self)); + g_return_if_fail (texture == NULL || GDK_IS_TEXTURE (texture)); + + if (!g_set_object (&self->update_texture, texture)) + return; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_TEXTURE]); +} + +/** + * gdk_gl_texture_builder_get_update_region: (attributes org.gdk.Method.get_property=update_region) + * @self: a `GdkGLTextureBuilder` + * + * Gets the region previously set via gdk_gl_texture_builder_set_update_region() or + * %NULL if none was set. + * + * Returns: (transfer none) (nullable): The region + * + * Since: 4.12 + */ +cairo_region_t * +gdk_gl_texture_builder_get_update_region (GdkGLTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL); + + return self->update_region; +} + +/** + * gdk_gl_texture_builder_set_update_region: (attributes org.gdk.Method.set_property=update_region) + * @self: a `GdkGLTextureBuilder` + * @region: (nullable): the region to update + * + * Sets the region to be updated by this texture. Together with + * [property@Gdk.GLTextureBuilder:update-texture] this describes an + * update of a previous texture. + * + * When rendering animations of large textures, it is possible that + * consecutive textures are only updating contents in parts of the texture. + * It is then possible to describe this update via these two properties, + * so that GTK can avoid rerendering parts that did not change. + * + * An example would be a screen recording where only the mouse pointer moves. + * + * Since: 4.12 + */ +void +gdk_gl_texture_builder_set_update_region (GdkGLTextureBuilder *self, + cairo_region_t *region) +{ + g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self)); + + if (self->update_region == region) + return; + + g_clear_pointer (&self->update_region, cairo_region_destroy); + + if (region) + self->update_region = cairo_region_reference (region); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_REGION]); +} + +/** * gdk_gl_texture_builder_build: * @self: a `GdkGLTextureBuilder` * @destroy: (nullable): destroy function to be called when the texture is diff --git a/gdk/gdkgltexturebuilder.h b/gdk/gdkgltexturebuilder.h index 03ee185e0c..042bcc96cb 100644 --- a/gdk/gdkgltexturebuilder.h +++ b/gdk/gdkgltexturebuilder.h @@ -79,6 +79,18 @@ void gdk_gl_texture_builder_set_sync (GdkGLTextureBui gpointer sync); GDK_AVAILABLE_IN_4_12 +GdkTexture * gdk_gl_texture_builder_get_update_texture (GdkGLTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_12 +void gdk_gl_texture_builder_set_update_texture (GdkGLTextureBuilder *self, + GdkTexture *texture); + +GDK_AVAILABLE_IN_4_12 +cairo_region_t * gdk_gl_texture_builder_get_update_region (GdkGLTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_12 +void gdk_gl_texture_builder_set_update_region (GdkGLTextureBuilder *self, + cairo_region_t *region); + +GDK_AVAILABLE_IN_4_12 GdkTexture * gdk_gl_texture_builder_build (GdkGLTextureBuilder *self, GDestroyNotify destroy, gpointer data); diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c index 41cb8ea11a..b392b90222 100644 --- a/gdk/gdktexture.c +++ b/gdk/gdktexture.c @@ -282,6 +282,8 @@ gdk_texture_dispose (GObject *object) { GdkTexture *self = GDK_TEXTURE (object); + g_clear_pointer (&self->diff_to_previous, cairo_region_destroy); + gdk_texture_clear_render_data (self); G_OBJECT_CLASS (gdk_texture_parent_class)->dispose (object); @@ -671,7 +673,47 @@ gdk_texture_do_download (GdkTexture *texture, guchar *data, gsize stride) { - GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, data,stride); + GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, data, stride); +} + +void +gdk_texture_diff (GdkTexture *self, + GdkTexture *other, + cairo_region_t *region) +{ + if (self == other) + return; + + if (self->previous_texture == other && + g_atomic_pointer_get (&other->next_texture) == self) + { + cairo_region_union (region, self->diff_to_previous); + } + else if (other->previous_texture == self && + g_atomic_pointer_get (&self->next_texture) == other) + { + cairo_region_union (region, other->diff_to_previous); + } + else + { + cairo_region_union_rectangle (region, + &(cairo_rectangle_int_t) { + 0, + 0, + MAX (self->width, other->width), + MAX (self->height, other->height) + }); + } +} + +void +gdk_texture_set_diff (GdkTexture *self, + GdkTexture *previous, + cairo_region_t *diff) +{ + self->previous_texture = previous; + self->diff_to_previous = diff; + g_atomic_pointer_set (&previous->next_texture, self); } cairo_surface_t * diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h index fccf380d7c..b0fc2a8785 100644 --- a/gdk/gdktextureprivate.h +++ b/gdk/gdktextureprivate.h @@ -21,6 +21,12 @@ struct _GdkTexture gpointer render_key; gpointer render_data; GDestroyNotify render_notify; + + /* for diffing swapchain-like textures. + * Links are only valid if both textures agree on them */ + gpointer next_texture; /* atomic, no reference, may be invalid pointer */ + gpointer previous_texture; /* no reference, may be invalid pointer */ + cairo_region_t *diff_to_previous; }; struct _GdkTextureClass { @@ -42,6 +48,14 @@ void gdk_texture_do_download (GdkTexture GdkMemoryFormat format, guchar *data, gsize stride); +void gdk_texture_diff (GdkTexture *self, + GdkTexture *other, + cairo_region_t *region); + +void gdk_texture_set_diff (GdkTexture *self, + GdkTexture *previous, + cairo_region_t *diff); + gboolean gdk_texture_set_render_data (GdkTexture *self, gpointer key, gpointer data, |