From e14d2be1e833c75aa48ba056464d4e23950864a9 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 30 Sep 2020 14:53:13 +0200 Subject: [PATCH] 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. --- gsk/gl/gskgldriver.c | 7 +++++-- gsk/gl/gskgldriverprivate.h | 2 ++ gsk/gl/gskglrenderer.c | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c index b1f8d6ea0e..6305add62c 100644 --- a/gsk/gl/gskgldriver.c +++ b/gsk/gl/gskgldriver.c @@ -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 diff --git a/gsk/gl/gskgldriverprivate.h b/gsk/gl/gskgldriverprivate.h index 0bf9ca89d2..7adf320057 100644 --- a/gsk/gl/gskgldriverprivate.h +++ b/gsk/gl/gskgldriverprivate.h @@ -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); diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 6efe62bca7..4cfe31535c 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -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);