[gtk/wip/chergert/glproto: 140/493] cleanup texturing code in driver
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/glproto: 140/493] cleanup texturing code in driver
- Date: Fri, 19 Feb 2021 02:25:07 +0000 (UTC)
commit 806014a34cba0416e03b5f04bb534f1d666e0f76
Author: Christian Hergert <chergert redhat com>
Date: Thu Jan 7 20:30:34 2021 -0800
cleanup texturing code in driver
this code was a source of a lot of indirection in the previous renderer.
this tries to decode that a bit by specifying when we're caching, when
we're creating new, and when we are looking up/releasing textures for
reuse.
it will mean just a slight bit more code in renderjob, but very much work
it for the clarity of troubleshooting.
gsk/next/gskgldriver.c | 250 ++++++++++++++++++++++++++++++------------
gsk/next/gskgldriverprivate.h | 62 ++++++-----
2 files changed, 217 insertions(+), 95 deletions(-)
---
diff --git a/gsk/next/gskgldriver.c b/gsk/next/gskgldriver.c
index 79c931e24f..b5a7a39596 100644
--- a/gsk/next/gskgldriver.c
+++ b/gsk/next/gskgldriver.c
@@ -36,23 +36,12 @@
#include "gskgliconlibraryprivate.h"
#include "gskglprogramprivate.h"
#include "gskglshadowlibraryprivate.h"
+#include "gskgltexturepoolprivate.h"
#define TEXTURES_CACHED_FOR_N_FRAMES 5
G_DEFINE_TYPE (GskNextDriver, gsk_next_driver, G_TYPE_OBJECT)
-typedef struct _GskGLTexture
-{
- int width;
- int height;
- GLuint min_filter;
- GLuint mag_filter;
- gint64 last_used_in_frame;
- GdkTexture *user;
- GLuint texture_id;
- guint permanent : 1;
-} GskGLTexture;
-
static guint
texture_key_hash (gconstpointer v)
{
@@ -107,7 +96,7 @@ remove_texture_key_for_id (GskNextDriver *self,
}
static void
-gsk_next_driver_release_texture (gpointer data)
+gsk_gl_texture_destroyed (gpointer data)
{
((GskGLTexture *)data)->user = NULL;
}
@@ -168,10 +157,8 @@ gsk_next_driver_dispose (GObject *object)
}
g_assert (self->autorelease_framebuffers->len == 0);
- g_assert (self->autorelease_textures->len == 0);
g_clear_pointer (&self->autorelease_framebuffers, g_array_unref);
- g_clear_pointer (&self->autorelease_textures, g_array_unref);
g_clear_pointer (&self->key_to_texture_id, g_hash_table_unref);
g_clear_pointer (&self->textures, g_hash_table_unref);
g_clear_pointer (&self->key_to_texture_id, g_hash_table_unref);
@@ -192,13 +179,13 @@ static void
gsk_next_driver_init (GskNextDriver *self)
{
self->autorelease_framebuffers = g_array_new (FALSE, FALSE, sizeof (guint));
- self->autorelease_textures = g_array_new (FALSE, FALSE, sizeof (guint));
self->textures = g_hash_table_new_full (NULL, NULL, NULL, gsk_gl_texture_free);
self->texture_id_to_key = g_hash_table_new (NULL, NULL);
self->key_to_texture_id = g_hash_table_new_full (texture_key_hash,
texture_key_equal,
g_free,
NULL);
+ gsk_gl_texture_pool_init (&self->texture_pool);
}
static gboolean
@@ -269,6 +256,15 @@ failure:
return ret;
}
+void
+gsk_next_driver_autorelease_framebuffer (GskNextDriver *self,
+ guint framebuffer_id)
+{
+ g_return_if_fail (GSK_IS_NEXT_DRIVER (self));
+
+ g_array_append_val (self->autorelease_framebuffers, framebuffer_id);
+}
+
GskNextDriver *
gsk_next_driver_new (GskGLCommandQueue *command_queue,
gboolean debug,
@@ -336,13 +332,6 @@ gsk_next_driver_end_frame (GskNextDriver *self)
gsk_gl_texture_library_end_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphs));
gsk_gl_texture_library_end_frame (GSK_GL_TEXTURE_LIBRARY (self->shadows));
- if (self->autorelease_textures->len > 0)
- {
- glDeleteTextures (self->autorelease_textures->len,
- (GLuint *)(gpointer)self->autorelease_textures->data);
- self->autorelease_textures->len = 0;
- }
-
if (self->autorelease_framebuffers->len > 0)
{
glDeleteFramebuffers (self->autorelease_framebuffers->len,
@@ -350,6 +339,8 @@ gsk_next_driver_end_frame (GskNextDriver *self)
self->autorelease_framebuffers->len = 0;
}
+ gsk_gl_texture_pool_clear (&self->texture_pool);
+
self->in_frame = FALSE;
}
@@ -362,6 +353,20 @@ gsk_next_driver_get_context (GskNextDriver *self)
return gsk_gl_command_queue_get_context (self->command_queue);
}
+/**
+ * gsk_next_driver_create_render_target:
+ * @self: a #GskNextDriver
+ * @width: the width for the render target
+ * @height: the height for the render target
+ * @out_fbo_id: (out): location for framebuffer id
+ * @out_texture_id: (out): location for texture id
+ *
+ * Creates a new render target where @out_texture_id is bount
+ * to the framebuffer @out_fbo_id using glFramebufferTexture2D().
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @out_fbo_id and
+ * @out_texture_id are undefined.
+ */
gboolean
gsk_next_driver_create_render_target (GskNextDriver *self,
int width,
@@ -370,9 +375,7 @@ gsk_next_driver_create_render_target (GskNextDriver *self,
guint *out_texture_id)
{
g_return_val_if_fail (GSK_IS_NEXT_DRIVER (self), FALSE);
-
- if (self->command_queue == NULL)
- return FALSE;
+ g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self->command_queue), FALSE);
return gsk_gl_command_queue_create_render_target (self->command_queue,
width,
@@ -381,28 +384,20 @@ gsk_next_driver_create_render_target (GskNextDriver *self,
out_texture_id);
}
-void
-gsk_next_driver_autorelease_texture (GskNextDriver *self,
- guint texture_id)
-{
- g_return_if_fail (GSK_IS_NEXT_DRIVER (self));
-
- g_array_append_val (self->autorelease_textures, texture_id);
-}
-
-void
-gsk_next_driver_autorelease_framebuffer (GskNextDriver *self,
- guint framebuffer_id)
-{
- g_return_if_fail (GSK_IS_NEXT_DRIVER (self));
-
- g_array_append_val (self->autorelease_framebuffers, framebuffer_id);
-}
-
-gboolean
+/**
+ * gsk_next_driver_lookup_texture:
+ * @self: a #GskNextDriver
+ * @key: the key for the texture
+ *
+ * Looks up a texture in the texture cache by @key.
+ *
+ * If the texture could not be found, then zero is returned.
+ *
+ * Returns: a positive integer if the texture was found; otherwise 0.
+ */
+guint
gsk_next_driver_lookup_texture (GskNextDriver *self,
- const GskTextureKey *key,
- guint *texture_id)
+ const GskTextureKey *key)
{
gpointer id;
@@ -411,28 +406,35 @@ gsk_next_driver_lookup_texture (GskNextDriver *self,
if (g_hash_table_lookup_extended (self->key_to_texture_id, key, NULL, &id))
{
- GskGLTexture *texture;
-
- g_assert (id != NULL);
-
- if (texture_id != NULL)
- *texture_id = GPOINTER_TO_UINT (id);
-
- texture = g_hash_table_lookup (self->textures, id);
+ GskGLTexture *texture = g_hash_table_lookup (self->textures, id);
if (texture != NULL)
texture->last_used_in_frame = self->current_frame_id;
- return TRUE;
+ return GPOINTER_TO_UINT (id);
}
- return FALSE;
+ return 0;
}
+/**
+ * gsk_next_driver_cache_texture:
+ * @self: a #GskNextDriver
+ * @key: the key for the texture
+ * @texture_id: the id of the texture to be cached
+ *
+ * Inserts @texture_id into the texture cache using @key.
+ *
+ * Textures can be looked up by @key after calling this function using
+ * gsk_next_driver_lookup_texture().
+ *
+ * Textures that have not been used within a number of frames will be
+ * purged from the texture cache automatically.
+ */
void
-gsk_next_driver_insert_texture (GskNextDriver *self,
- const GskTextureKey *key,
- guint texture_id)
+gsk_next_driver_cache_texture (GskNextDriver *self,
+ const GskTextureKey *key,
+ guint texture_id)
{
GskTextureKey *k;
@@ -446,6 +448,29 @@ gsk_next_driver_insert_texture (GskNextDriver *self,
g_hash_table_insert (self->texture_id_to_key, GUINT_TO_POINTER (texture_id), k);
}
+/**
+ * gsk_next_driver_load_texture:
+ * @self: a #GdkTexture
+ * @texture: a #GdkTexture
+ * @min_filter: GL_NEAREST or GL_LINEAR
+ * @mag_filter: GL_NEAREST or GL_LINEAR
+ *
+ * Loads a #GdkTexture by uploading the contents to the GPU when
+ * necessary. If @texture is a #GdkGLTexture, it can be used without
+ * uploading contents to the GPU.
+ *
+ * If the texture has already been uploaded and not yet released
+ * from cache, this function returns that texture id without further
+ * work.
+ *
+ * If the texture has not been used for a number of frames, it will
+ * be removed from cache.
+ *
+ * There is no need to release the resulting texture identifier after
+ * using it. It will be released automatically.
+ *
+ * Returns: a texture identifier
+ */
guint
gsk_next_driver_load_texture (GskNextDriver *self,
GdkTexture *texture,
@@ -495,15 +520,10 @@ gsk_next_driver_load_texture (GskNextDriver *self,
source_texture = downloaded_texture;
}
}
- else
+ else if ((t = gdk_texture_get_render_data (texture, self)))
{
- t = gdk_texture_get_render_data (texture, self);
-
- if (t)
- {
- if (t->min_filter == min_filter && t->mag_filter == mag_filter)
- return t->texture_id;
- }
+ if (t->min_filter == min_filter && t->mag_filter == mag_filter)
+ return t->texture_id;
source_texture = texture;
}
@@ -523,7 +543,7 @@ gsk_next_driver_load_texture (GskNextDriver *self,
t->min_filter,
t->mag_filter);
- if (gdk_texture_set_render_data (texture, self, t, gsk_next_driver_release_texture))
+ if (gdk_texture_set_render_data (texture, self, t, gsk_gl_texture_destroyed))
t->user = texture;
gdk_gl_context_label_object_printf (context, GL_TEXTURE, t->texture_id,
@@ -533,3 +553,95 @@ gsk_next_driver_load_texture (GskNextDriver *self,
return t->texture_id;
}
+
+/**
+ * gsk_next_driver_create_texture:
+ * @self: a #GskNextDriver
+ * @width: the width of the texture
+ * @height: the height of the texture
+ * @min_filter: GL_NEAREST or GL_LINEAR
+ * @mag_filter: GL_NEAREST or GL_FILTER
+ *
+ * Creates a new texture immediately that can be used by the caller
+ * to upload data, map to a framebuffer, or other uses which may
+ * modify the texture immediately.
+ *
+ * Use this instead of gsk_next_driver_acquire_texture() when you need
+ * to be able to modify the texture immediately instead of just when the
+ * pipeline is executing. Otherwise, gsk_next_driver_acquire_texture()
+ * provides more chances for re-use of textures, reducing the VRAM overhead
+ * on the GPU.
+ *
+ * Use gsk_next_driver_release_texture() to release this texture back into
+ * the pool so it may be reused later in the pipeline.
+ *
+ * Returns: a #GskGLTexture which can be returned to the pool with
+ * gsk_next_driver_release_texture().
+ */
+GskGLTexture *
+gsk_next_driver_create_texture (GskNextDriver *self,
+ float width,
+ float height,
+ int min_filter,
+ int mag_filter)
+{
+ g_return_val_if_fail (GSK_IS_NEXT_DRIVER (self), NULL);
+
+ return gsk_gl_texture_pool_get (&self->texture_pool,
+ width, height,
+ min_filter, mag_filter,
+ TRUE);
+}
+
+/**
+ * gsk_next_driver_acquire_texture:
+ * @self: a #GskNextDriver
+ * @width: the min width of the texture necessary
+ * @height: the min height of the texture necessary
+ * @min_filter: GL_NEAREST or GL_LINEAR
+ * @mag_filter: GL_NEAREST or GL_LINEAR
+ *
+ * This function acquires a #GskGLTexture from the texture pool. Doing
+ * so increases the chances for reduced VRAM usage in the GPU by having
+ * fewer textures in use at one time. Batches later in the stream can
+ * use the same texture memory of a previous batch.
+ *
+ * Consumers of this function are not allowed to modify @texture
+ * immediately, it must wait until batches are being processed as
+ * the texture may contain contents used earlier in the pipeline.
+ *
+ * Returns: a #GskGLTexture that may be returned to the pool with
+ * gsk_next_driver_release_texture().
+ */
+GskGLTexture *
+gsk_next_driver_acquire_texture (GskNextDriver *self,
+ float width,
+ float height,
+ int min_filter,
+ int mag_filter)
+{
+ g_return_val_if_fail (GSK_IS_NEXT_DRIVER (self), NULL);
+
+ return gsk_gl_texture_pool_get (&self->texture_pool,
+ width, height,
+ min_filter, mag_filter,
+ FALSE);
+}
+
+/**
+ * gsk_gl_driver_release_texture:
+ * @self: a #GskNextDriver
+ * @texture: a #GskGLTexture
+ *
+ * Releases @texture back into the pool so that it can be used later
+ * in the command stream by future batches. This helps reduce VRAM
+ * usage on the GPU.
+ */
+void
+gsk_next_driver_release_texture (GskNextDriver *self,
+ GskGLTexture *texture)
+{
+ g_return_if_fail (GSK_IS_NEXT_DRIVER (self));
+
+ gsk_gl_texture_pool_put (&self->texture_pool, texture);
+}
diff --git a/gsk/next/gskgldriverprivate.h b/gsk/next/gskgldriverprivate.h
index 4a2b1c63bd..85c4e380ee 100644
--- a/gsk/next/gskgldriverprivate.h
+++ b/gsk/next/gskgldriverprivate.h
@@ -23,6 +23,8 @@
#include "gskgltypes.h"
+#include "gskgltexturepoolprivate.h"
+
G_BEGIN_DECLS
enum {
@@ -63,6 +65,8 @@ struct _GskNextDriver
GskGLCommandQueue *command_queue;
+ GskGLTexturePool texture_pool;
+
GskGLGlyphLibrary *glyphs;
GskGLIconLibrary *icons;
GskGLShadowLibrary *shadows;
@@ -73,7 +77,6 @@ struct _GskNextDriver
GHashTable *texture_id_to_key;
GArray *autorelease_framebuffers;
- GArray *autorelease_textures;
#define GSK_GL_NO_UNIFORMS
#define GSK_GL_ADD_UNIFORM(pos, KEY, name)
@@ -89,31 +92,38 @@ struct _GskNextDriver
guint in_frame : 1;
};
-GskNextDriver *gsk_next_driver_new (GskGLCommandQueue *command_queue,
- gboolean debug,
- GError **error);
-GdkGLContext *gsk_next_driver_get_context (GskNextDriver *self);
-gboolean gsk_next_driver_create_render_target (GskNextDriver *self,
- int width,
- int height,
- guint *out_fbo_id,
- guint *out_texture_id);
-void gsk_next_driver_begin_frame (GskNextDriver *self);
-void gsk_next_driver_end_frame (GskNextDriver *self);
-void gsk_next_driver_autorelease_framebuffer (GskNextDriver *self,
- guint framebuffer_id);
-void gsk_next_driver_autorelease_texture (GskNextDriver *self,
- guint texture_id);
-gboolean gsk_next_driver_lookup_texture (GskNextDriver *self,
- const GskTextureKey *key,
- guint *texture_id);
-void gsk_next_driver_insert_texture (GskNextDriver *self,
- const GskTextureKey *key,
- guint texture_id);
-guint gsk_next_driver_load_texture (GskNextDriver *self,
- GdkTexture *texture,
- int min_filter,
- int mag_filter);
+GskNextDriver *gsk_next_driver_new (GskGLCommandQueue *command_queue,
+ gboolean debug,
+ GError **error);
+GdkGLContext *gsk_next_driver_get_context (GskNextDriver *self);
+gboolean gsk_next_driver_create_render_target (GskNextDriver *self,
+ int width,
+ int height,
+ guint *out_fbo_id,
+ guint *out_texture_id);
+void gsk_next_driver_begin_frame (GskNextDriver *self);
+void gsk_next_driver_end_frame (GskNextDriver *self);
+guint gsk_next_driver_lookup_texture (GskNextDriver *self,
+ const GskTextureKey *key);
+void gsk_next_driver_cache_texture (GskNextDriver *self,
+ const GskTextureKey *key,
+ guint texture_id);
+guint gsk_next_driver_load_texture (GskNextDriver *self,
+ GdkTexture *texture,
+ int min_filter,
+ int mag_filter);
+GskGLTexture *gsk_next_driver_create_texture (GskNextDriver *self,
+ float width,
+ float height,
+ int min_filter,
+ int mag_filter);
+GskGLTexture *gsk_next_driver_acquire_texture (GskNextDriver *self,
+ float width,
+ float height,
+ int min_filter,
+ int mag_filter);
+void gsk_next_driver_release_texture (GskNextDriver *self,
+ GskGLTexture *texture);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]