... and use it in rendernodes.
Setting up textures for diffing is done via gdk_texture_set_diff() which
should only be used during texture construction.
Note that the pointers to next/previous are allowed to dangle if one of
the textures is finalized, but that's fine because we always check both
textures' links to each other before we consider the pointer valid.
{
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);
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 *
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 {
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,
{
GskTextureNode *self1 = (GskTextureNode *) node1;
GskTextureNode *self2 = (GskTextureNode *) node2;
+ cairo_region_t *sub;
- if (graphene_rect_equal (&node1->bounds, &node2->bounds) &&
- self1->texture == self2->texture)
+ if (!graphene_rect_equal (&node1->bounds, &node2->bounds) ||
+ gdk_texture_get_width (self1->texture) != gdk_texture_get_width (self2->texture) ||
+ gdk_texture_get_height (self1->texture) != gdk_texture_get_height (self2->texture))
+ {
+ gsk_render_node_diff_impossible (node1, node2, region);
+ return;
+ }
+
+ if (self1->texture == self2->texture)
return;
- gsk_render_node_diff_impossible (node1, node2, region);
+ sub = cairo_region_create ();
+ gdk_texture_diff (self1->texture, self2->texture, sub);
+ region_union_region_affine (region,
+ sub,
+ node1->bounds.size.width / gdk_texture_get_width (self1->texture),
+ node1->bounds.size.height / gdk_texture_get_height (self1->texture),
+ node1->bounds.origin.x,
+ node1->bounds.origin.y);
+ cairo_region_destroy (sub);
}
static void