gl renderer: Fix render node texture cache

We're caching two things, either a node itself being rendered, or a
parent storing a cached version of a child as rendered to an offscreen
the size and location of the parent.

If both the parent and child uses the cache this will cause a conflict in
the cache as it is currently use keying of a node pointer which will have
the same value for the node-as-itself and the child-node-of-the-parent.

We fix this by adding another part to the key "pointer_is_child" which means
we can have the same node pointer twice in the cache.

Additionally, in the child-is-rendered-offscreen case the offscreen
result actually depends on the position and size of the parent viewport,
so we need to store the parent bounds in that case.
This commit is contained in:
Alexander Larsson 2020-09-30 14:53:13 +02:00
parent e9885f9cde
commit e14d2be1e8
3 changed files with 11 additions and 3 deletions

View File

@ -587,7 +587,8 @@ texture_key_hash (gconstpointer v)
return GPOINTER_TO_UINT (k->pointer)
+ (guint)(k->scale*100)
+ (guint)k->filter;
+ (guint)k->filter * 2 +
+ (guint)k->pointer_is_child;
}
static gboolean
@ -598,7 +599,9 @@ texture_key_equal (gconstpointer v1, gconstpointer v2)
return k1->pointer == k2->pointer &&
k1->scale == k2->scale &&
k1->filter == k2->filter;
k1->filter == k2->filter &&
k1->pointer_is_child == k2->pointer_is_child &&
(!k1->pointer_is_child || graphene_rect_equal (&k1->parent_rect, &k2->parent_rect));
}
int

View File

@ -25,6 +25,8 @@ typedef struct {
gpointer pointer;
float scale;
int filter;
int pointer_is_child;
graphene_rect_t parent_rect; /* Only set if pointer_is_child */
} GskTextureKey;
GskGLDriver * gsk_gl_driver_new (GdkGLContext *context);

View File

@ -626,6 +626,7 @@ render_fallback_node (GskGLRenderer *self,
return;
key.pointer = node;
key.pointer_is_child = FALSE;
key.scale = scale;
key.filter = GL_NEAREST;
@ -1922,6 +1923,7 @@ render_blur_node (GskGLRenderer *self,
}
key.pointer = node;
key.pointer_is_child = FALSE;
key.scale = ops_get_scale (builder);
key.filter = GL_NEAREST;
blurred_region.texture_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
@ -1982,6 +1984,7 @@ render_inset_shadow_node (GskGLRenderer *self,
texture_height = ceilf ((node_outline->bounds.size.height + blur_extra) * scale);
key.pointer = node;
key.pointer_is_child = FALSE;
key.scale = scale;
key.filter = GL_NEAREST;
blurred_texture_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
@ -3812,7 +3815,6 @@ add_offscreen_ops (GskGLRenderer *self,
(flags & FORCE_OFFSCREEN) == 0)
{
GdkTexture *texture = gsk_texture_node_get_texture (child_node);
upload_texture (self, texture, texture_region_out);
*is_offscreen = FALSE;
return TRUE;
@ -3825,6 +3827,7 @@ add_offscreen_ops (GskGLRenderer *self,
/* Check if we've already cached the drawn texture. */
key.pointer = child_node;
key.pointer_is_child = TRUE; /* Don't conflict with the child using the cache too */
key.scale = ops_get_scale (builder);
key.filter = filter;
cached_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);