gl renderer: Cache offscreen textures per node, not size

This commit is contained in:
Timm Bäder 2018-11-28 18:40:48 +01:00
parent 12378f0afa
commit c0cf592336
3 changed files with 80 additions and 44 deletions

View File

@ -46,6 +46,7 @@ struct _GskGLDriver
Fbo default_fbo; Fbo default_fbo;
GHashTable *textures; GHashTable *textures;
GHashTable *pointer_textures;
const Texture *bound_source_texture; const Texture *bound_source_texture;
const Fbo *bound_fbo; const Fbo *bound_fbo;
@ -119,6 +120,7 @@ gsk_gl_driver_finalize (GObject *gobject)
gdk_gl_context_make_current (self->gl_context); gdk_gl_context_make_current (self->gl_context);
g_clear_pointer (&self->textures, g_hash_table_unref); g_clear_pointer (&self->textures, g_hash_table_unref);
g_clear_pointer (&self->pointer_textures, g_hash_table_unref);
g_clear_object (&self->profiler); g_clear_object (&self->profiler);
if (self->gl_context == gdk_gl_context_get_current ()) if (self->gl_context == gdk_gl_context_get_current ())
@ -263,8 +265,29 @@ gsk_gl_driver_collect_textures (GskGLDriver *self)
} }
} }
else else
{
/* Remove from self->pointer_textures. */
/* TODO: Is there a better way for this? */
if (self->pointer_textures)
{
GHashTableIter pointer_iter;
gpointer value;
gpointer p;
g_hash_table_iter_init (&pointer_iter, self->pointer_textures);
while (g_hash_table_iter_next (&pointer_iter, &p, &value))
{
if (GPOINTER_TO_INT (value) == t->texture_id)
{
g_hash_table_iter_remove (&pointer_iter);
break;
}
}
}
g_hash_table_iter_remove (&iter); g_hash_table_iter_remove (&iter);
} }
}
return old_size - g_hash_table_size (self->textures); return old_size - g_hash_table_size (self->textures);
} }
@ -307,26 +330,6 @@ gsk_gl_driver_get_fbo (GskGLDriver *self,
return &t->fbo; return &t->fbo;
} }
static Texture *
find_texture_by_size (GHashTable *textures,
int width,
int height)
{
GHashTableIter iter;
gpointer value_p = NULL;
g_hash_table_iter_init (&iter, textures);
while (g_hash_table_iter_next (&iter, NULL, &value_p))
{
Texture *t = value_p;
if (t->width == width && t->height == height)
return t;
}
return NULL;
}
static Texture * static Texture *
create_texture (GskGLDriver *self, create_texture (GskGLDriver *self,
float fwidth, float fwidth,
@ -351,21 +354,7 @@ create_texture (GskGLDriver *self,
height = MIN (height, self->max_texture_size); height = MIN (height, self->max_texture_size);
} }
t = find_texture_by_size (self->textures, width, height);
if (t != NULL && !t->in_use && t->user == NULL)
{
GSK_NOTE (OPENGL, g_message ("Reusing Texture(%d) for size %dx%d",
t->texture_id, t->width, t->height));
t->in_use = TRUE;
#ifdef G_ENABLE_DEBUG
gsk_profiler_counter_inc (self->profiler, self->counters.reused_textures);
#endif
return t;
}
glGenTextures (1, &texture_id); glGenTextures (1, &texture_id);
t = texture_new (); t = texture_new ();
t->texture_id = texture_id; t->texture_id = texture_id;
t->width = width; t->width = width;
@ -547,6 +536,31 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
return t->texture_id; return t->texture_id;
} }
int
gsk_gl_driver_get_texture_for_pointer (GskGLDriver *self,
gpointer pointer)
{
int id = 0;
if (G_UNLIKELY (self->pointer_textures == NULL))
self->pointer_textures = g_hash_table_new (NULL, NULL);
id = GPOINTER_TO_INT (g_hash_table_lookup (self->pointer_textures, pointer));
return id;
}
void
gsk_gl_driver_set_texture_for_pointer (GskGLDriver *self,
gpointer pointer,
int texture_id)
{
if (G_UNLIKELY (self->pointer_textures == NULL))
self->pointer_textures = g_hash_table_new (NULL, NULL);
g_hash_table_insert (self->pointer_textures, pointer, GINT_TO_POINTER (texture_id));
}
int int
gsk_gl_driver_create_permanent_texture (GskGLDriver *self, gsk_gl_driver_create_permanent_texture (GskGLDriver *self,
float width, float width,

View File

@ -33,6 +33,11 @@ int gsk_gl_driver_get_texture_for_texture (GskGLDriver *driver
GdkTexture *texture, GdkTexture *texture,
int min_filter, int min_filter,
int mag_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 texture_id);
int gsk_gl_driver_create_permanent_texture (GskGLDriver *driver, int gsk_gl_driver_create_permanent_texture (GskGLDriver *driver,
float width, float width,
float height); float height);

View File

@ -2255,7 +2255,7 @@ add_offscreen_ops (GskGLRenderer *self,
float min_y, float min_y,
float max_y, float max_y,
GskRenderNode *child_node, GskRenderNode *child_node,
int *texture_id, int *texture_id_out,
gboolean *is_offscreen, gboolean *is_offscreen,
gboolean force_offscreen, gboolean force_offscreen,
gboolean reset_clip) gboolean reset_clip)
@ -2271,6 +2271,7 @@ add_offscreen_ops (GskGLRenderer *self,
graphene_rect_t prev_viewport; graphene_rect_t prev_viewport;
graphene_matrix_t item_proj; graphene_matrix_t item_proj;
GskRoundedRect prev_clip; GskRoundedRect prev_clip;
int texture_id = 0;
/* We need the child node as a texture. If it already is one, we don't need to draw /* We need the child node as a texture. If it already is one, we don't need to draw
* it on a framebuffer of course. */ * it on a framebuffer of course. */
@ -2281,7 +2282,7 @@ add_offscreen_ops (GskGLRenderer *self,
get_gl_scaling_filters (child_node, &gl_min_filter, &gl_mag_filter); get_gl_scaling_filters (child_node, &gl_min_filter, &gl_mag_filter);
*texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver, *texture_id_out = gsk_gl_driver_get_texture_for_texture (self->gl_driver,
texture, texture,
gl_min_filter, gl_min_filter,
gl_mag_filter); gl_mag_filter);
@ -2289,10 +2290,23 @@ add_offscreen_ops (GskGLRenderer *self,
return; return;
} }
*texture_id = gsk_gl_driver_create_texture (self->gl_driver, width, height); /* Check if we've already cached the drawn texture. */
gsk_gl_driver_bind_source_texture (self->gl_driver, *texture_id); {
gsk_gl_driver_init_texture_empty (self->gl_driver, *texture_id); const int cached_id = gsk_gl_driver_get_texture_for_pointer (self->gl_driver, child_node);
render_target = gsk_gl_driver_create_render_target (self->gl_driver, *texture_id, TRUE, TRUE);
if (cached_id != 0)
{
*texture_id_out = cached_id;
/* We didn't render it offscreen, but hand out an offscreen texture id */
*is_offscreen = TRUE;
return;
}
}
texture_id = gsk_gl_driver_create_texture (self->gl_driver, width, height);
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
gsk_gl_driver_init_texture_empty (self->gl_driver, texture_id);
render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture_id, TRUE, TRUE);
graphene_matrix_init_ortho (&item_proj, graphene_matrix_init_ortho (&item_proj,
min_x * scale, max_x * scale, min_x * scale, max_x * scale,
@ -2328,6 +2342,9 @@ add_offscreen_ops (GskGLRenderer *self,
ops_set_render_target (builder, prev_render_target); ops_set_render_target (builder, prev_render_target);
*is_offscreen = TRUE; *is_offscreen = TRUE;
*texture_id_out = texture_id;
gsk_gl_driver_set_texture_for_pointer (self->gl_driver, child_node, texture_id);
} }
static void static void