gsk: Fix the gl texture cache

We need to include both the scale and the filtering
in the key for the texture cache, since those affect
the texture.

This fixes misrendering in the recorder in the inspector
whenever transforms are involved. An example where this
was showing up is testrevealer's swing transition.
This commit is contained in:
Matthias Clasen 2020-09-09 13:55:09 -04:00
parent 9a927176df
commit 1057588a8f
3 changed files with 84 additions and 36 deletions

View File

@ -541,16 +541,37 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
return t->texture_id;
}
static guint
texture_key_hash (gconstpointer v)
{
const GskTextureKey *k = (GskTextureKey *)v;
return GPOINTER_TO_UINT (k->pointer)
+ (guint)(k->scale*100)
+ (guint)k->filter;
}
static gboolean
texture_key_equal (gconstpointer v1, gconstpointer v2)
{
const GskTextureKey *k1 = (GskTextureKey *)v1;
const GskTextureKey *k2 = (GskTextureKey *)v2;
return k1->pointer == k2->pointer &&
k1->scale == k2->scale &&
k1->filter == k2->filter;
}
int
gsk_gl_driver_get_texture_for_pointer (GskGLDriver *self,
gpointer pointer)
gsk_gl_driver_get_texture_for_key (GskGLDriver *self,
GskTextureKey *key)
{
int id = 0;
if (G_UNLIKELY (self->pointer_textures == NULL))
self->pointer_textures = g_hash_table_new (NULL, NULL);
self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, pointer));
id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, key));
if (id != 0)
{
@ -566,14 +587,19 @@ gsk_gl_driver_get_texture_for_pointer (GskGLDriver *self,
}
void
gsk_gl_driver_set_texture_for_pointer (GskGLDriver *self,
gpointer pointer,
int texture_id)
gsk_gl_driver_set_texture_for_key (GskGLDriver *self,
GskTextureKey *key,
int texture_id)
{
if (G_UNLIKELY (self->pointer_textures == NULL))
self->pointer_textures = g_hash_table_new (NULL, NULL);
GskTextureKey *k;
g_hash_table_insert (self->pointer_textures, pointer, GINT_TO_POINTER (texture_id));
if (G_UNLIKELY (self->pointer_textures == NULL))
self->pointer_textures = g_hash_table_new_full (texture_key_hash, texture_key_equal, g_free, NULL);
k = g_new (GskTextureKey, 1);
*k = *key;
g_hash_table_insert (self->pointer_textures, k, GINT_TO_POINTER (texture_id));
}
int

View File

@ -21,6 +21,11 @@ typedef struct {
guint texture_id;
} TextureSlice;
typedef struct {
gpointer pointer;
float scale;
int filter;
} GskTextureKey;
GskGLDriver * gsk_gl_driver_new (GdkGLContext *context);
GdkGLContext *gsk_gl_driver_get_gl_context (GskGLDriver *driver);
@ -34,10 +39,10 @@ int gsk_gl_driver_get_texture_for_texture (GskGLDriver *driver
GdkTexture *texture,
int min_filter,
int mag_filter);
int gsk_gl_driver_get_texture_for_pointer (GskGLDriver *driver,
gpointer pointer);
void gsk_gl_driver_set_texture_for_pointer (GskGLDriver *driver,
gpointer pointer,
int gsk_gl_driver_get_texture_for_key (GskGLDriver *driver,
GskTextureKey *key);
void gsk_gl_driver_set_texture_for_key (GskGLDriver *driver,
GskTextureKey *key,
int texture_id);
int gsk_gl_driver_create_texture (GskGLDriver *driver,
float width,

View File

@ -572,12 +572,17 @@ render_fallback_node (GskGLRenderer *self,
cairo_t *cr;
int cached_id;
int texture_id;
GskTextureKey key;
if (surface_width <= 0 ||
surface_height <= 0)
return;
cached_id = gsk_gl_driver_get_texture_for_pointer (self->gl_driver, node);
key.pointer = node;
key.scale = scale;
key.filter = GL_NEAREST;
cached_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
if (cached_id != 0)
{
@ -659,7 +664,7 @@ render_fallback_node (GskGLRenderer *self,
cairo_surface_destroy (surface);
cairo_surface_destroy (rendered_surface);
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, node, texture_id);
gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, texture_id);
ops_set_program (builder, &self->programs->blit_program);
ops_set_texture (builder, texture_id);
@ -1638,6 +1643,7 @@ render_blur_node (GskGLRenderer *self,
const float blur_radius = gsk_blur_node_get_radius (node);
GskRenderNode *child = gsk_blur_node_get_child (node);
TextureRegion blurred_region;
GskTextureKey key;
if (node_is_invisible (child))
return;
@ -1648,7 +1654,10 @@ render_blur_node (GskGLRenderer *self,
return;
}
blurred_region.texture_id = gsk_gl_driver_get_texture_for_pointer (self->gl_driver, node);
key.pointer = node;
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);
if (blurred_region.texture_id == 0)
blur_node (self, child, builder, blur_radius, 0, &blurred_region, NULL);
@ -1660,7 +1669,7 @@ render_blur_node (GskGLRenderer *self,
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); /* Render result to screen */
/* Add to cache for the blur node */
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, node, blurred_region.texture_id);
gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, blurred_region.texture_id);
}
static inline void
@ -1698,13 +1707,17 @@ render_inset_shadow_node (GskGLRenderer *self,
float texture_width;
float texture_height;
int blurred_texture_id;
GskTextureKey key;
g_assert (blur_radius > 0);
texture_width = ceilf ((node_outline->bounds.size.width + blur_extra) * scale);
texture_height = ceilf ((node_outline->bounds.size.height + blur_extra) * scale);
blurred_texture_id = gsk_gl_driver_get_texture_for_pointer (self->gl_driver, node);
key.pointer = node;
key.scale = scale;
key.filter = GL_NEAREST;
blurred_texture_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
if (blurred_texture_id == 0)
{
const float spread = gsk_inset_shadow_node_get_spread (node) + (blur_extra / 2.0);
@ -1800,7 +1813,7 @@ render_inset_shadow_node (GskGLRenderer *self,
const float ty1 = blur_extra / 2.0 * scale / texture_height;
const float ty2 = 1.0 - ty1;
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, node, blurred_texture_id);
gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, blurred_texture_id);
if (needs_clip)
{
@ -3400,6 +3413,8 @@ add_offscreen_ops (GskGLRenderer *self,
int texture_id = 0;
int max_texture_size;
int filter;
GskTextureKey key;
int cached_id;
if (node_is_invisible (child_node))
{
@ -3421,18 +3436,24 @@ add_offscreen_ops (GskGLRenderer *self,
return TRUE;
}
/* Check if we've already cached the drawn texture. */
{
const int cached_id = gsk_gl_driver_get_texture_for_pointer (self->gl_driver, child_node);
if (flags & LINEAR_FILTER)
filter = GL_LINEAR;
else
filter = GL_NEAREST;
if (cached_id != 0)
{
init_full_texture_region (texture_region_out, cached_id);
/* We didn't render it offscreen, but hand out an offscreen texture id */
*is_offscreen = TRUE;
return TRUE;
}
}
/* Check if we've already cached the drawn texture. */
key.pointer = child_node;
key.scale = ops_get_scale (builder);
key.filter = filter;
cached_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key);
if (cached_id != 0)
{
init_full_texture_region (texture_region_out, cached_id);
/* We didn't render it offscreen, but hand out an offscreen texture id */
*is_offscreen = TRUE;
return TRUE;
}
scale = ops_get_scale (builder);
width = bounds->size.width;
@ -3452,10 +3473,6 @@ add_offscreen_ops (GskGLRenderer *self,
width = ceilf (width * scale);
height = ceilf (height * scale);
if (flags & LINEAR_FILTER)
filter = GL_LINEAR;
else
filter = GL_NEAREST;
gsk_gl_driver_create_render_target (self->gl_driver,
width, height,
filter, filter,
@ -3534,7 +3551,7 @@ add_offscreen_ops (GskGLRenderer *self,
init_full_texture_region (texture_region_out, texture_id);
if ((flags & NO_CACHE_PLZ) == 0)
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, child_node, texture_id);
gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, texture_id);
return TRUE;
}