diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c index 2a2c980ce4..c88b93b52a 100644 --- a/gsk/gl/gskgldriver.c +++ b/gsk/gl/gskgldriver.c @@ -46,6 +46,7 @@ struct _GskGLDriver Fbo default_fbo; GHashTable *textures; + GHashTable *pointer_textures; const Texture *bound_source_texture; const Fbo *bound_fbo; @@ -119,6 +120,7 @@ gsk_gl_driver_finalize (GObject *gobject) gdk_gl_context_make_current (self->gl_context); g_clear_pointer (&self->textures, g_hash_table_unref); + g_clear_pointer (&self->pointer_textures, g_hash_table_unref); g_clear_object (&self->profiler); if (self->gl_context == gdk_gl_context_get_current ()) @@ -263,7 +265,28 @@ gsk_gl_driver_collect_textures (GskGLDriver *self) } } else - g_hash_table_iter_remove (&iter); + { + /* 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); + } } return old_size - g_hash_table_size (self->textures); @@ -307,26 +330,6 @@ gsk_gl_driver_get_fbo (GskGLDriver *self, 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 * create_texture (GskGLDriver *self, float fwidth, @@ -351,21 +354,7 @@ create_texture (GskGLDriver *self, 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); - t = texture_new (); t->texture_id = texture_id; t->width = width; @@ -547,6 +536,31 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self, 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 gsk_gl_driver_create_permanent_texture (GskGLDriver *self, float width, diff --git a/gsk/gl/gskgldriverprivate.h b/gsk/gl/gskgldriverprivate.h index 7d7a41fe28..8ceecb183a 100644 --- a/gsk/gl/gskgldriverprivate.h +++ b/gsk/gl/gskgldriverprivate.h @@ -33,6 +33,11 @@ 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 texture_id); int gsk_gl_driver_create_permanent_texture (GskGLDriver *driver, float width, float height); diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index f8074a4531..a75f8b3823 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -2255,7 +2255,7 @@ add_offscreen_ops (GskGLRenderer *self, float min_y, float max_y, GskRenderNode *child_node, - int *texture_id, + int *texture_id_out, gboolean *is_offscreen, gboolean force_offscreen, gboolean reset_clip) @@ -2271,6 +2271,7 @@ add_offscreen_ops (GskGLRenderer *self, graphene_rect_t prev_viewport; graphene_matrix_t item_proj; 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 * it on a framebuffer of course. */ @@ -2281,18 +2282,31 @@ add_offscreen_ops (GskGLRenderer *self, 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, - gl_min_filter, - gl_mag_filter); + *texture_id_out = gsk_gl_driver_get_texture_for_texture (self->gl_driver, + texture, + gl_min_filter, + gl_mag_filter); *is_offscreen = FALSE; 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); + /* 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 (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, min_x * scale, max_x * scale, @@ -2328,6 +2342,9 @@ add_offscreen_ops (GskGLRenderer *self, ops_set_render_target (builder, prev_render_target); *is_offscreen = TRUE; + *texture_id_out = texture_id; + + gsk_gl_driver_set_texture_for_pointer (self->gl_driver, child_node, texture_id); } static void