summaryrefslogtreecommitdiff
path: root/gdk
diff options
context:
space:
mode:
authorBenjamin Otte <otte.benjamin@googlemail.com>2023-05-06 00:59:25 +0000
committerBenjamin Otte <otte.benjamin@googlemail.com>2023-05-06 00:59:25 +0000
commit2a950dec71ce9b572ef6666430536ec3931b0188 (patch)
tree44758c2cef496d33faf532ed0e4ebfc6fdbb7e94 /gdk
parentd6c80d4f35aa73624028d4e4af95d61e856901c1 (diff)
parent97aff588d553b147220a1af8eb0d5fad08fefcf3 (diff)
downloadgtk+-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.c17
-rw-r--r--gdk/gdkgltexturebuilder.c147
-rw-r--r--gdk/gdkgltexturebuilder.h12
-rw-r--r--gdk/gdktexture.c44
-rw-r--r--gdk/gdktextureprivate.h14
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,