[patch] gl: cache uniform location

"Henry (Yu) Song - SISA" <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <3955FA337689574EB32F94B12A7E6E9E246B0CF4@sisaex01sj>
GetUniformLocation is expensive call, especially on embedded device,  we can cache them once obtained.

From c856118e637412a8c5cd7b68cc569f7e1bf4f44c Mon Sep 17 00:00:00 2001
From: Henry Song <[email protected]>
Date: Fri, 6 Jan 2012 16:46:25 -0800
Subject: [PATCH] gl/msaa: Cache shader uniform locations

Instead of continuously fetching the uniform locations from compiled
shaders, cache them.
---
 src/cairo-gl-private.h |    1 +
 src/cairo-gl-shaders.c |  122 +++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 111 insertions(+), 12 deletions(-)

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 48087ec..057b9f3 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -196,6 +196,7 @@ typedef enum cairo_gl_tex {
 typedef struct cairo_gl_shader {
     GLuint fragment_shader;
     GLuint program;
+    cairo_hash_table_t *uniform_cache;
 } cairo_gl_shader_t;
 
 typedef enum cairo_gl_shader_in {
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 41672d6..c07150e 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -52,6 +52,75 @@ _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
 				   cairo_bool_t use_coverage,
 				   const char *fragment_text);
 
+typedef struct _cairo_gl_uniform_entry {
+    cairo_hash_entry_t base;
+    char *name;
+    GLint location;
+} cairo_gl_uniform_entry_t;
+
+static void
+_cairo_gl_uniform_entry_init (cairo_gl_uniform_entry_t *key,
+			      const char *name)
+{
+    unsigned long sum = 0;
+    unsigned int i;
+
+    for (i = 0; i < strlen(name); i++)
+	sum += name[i];
+    key->base.hash = sum;
+    key->name = strdup(name);
+    key->location = -1;
+}
+
+static void
+_cairo_gl_uniform_entry_fini (cairo_gl_uniform_entry_t *entry)
+{
+    free (entry->name);
+    entry->location = -1;
+}
+
+static cairo_bool_t
+_cairo_gl_uniform_equal (const void *key_a,
+			 const void *key_b)
+{
+    const cairo_gl_uniform_entry_t *a = key_a;
+    const cairo_gl_uniform_entry_t *b = key_b;
+
+    return strcmp (a->name, b->name) == 0;
+}
+
+static void
+get_uniform_location (cairo_gl_context_t *ctx,
+		      cairo_gl_shader_t *shader,
+		      const char *name,
+		      GLint *location)
+{
+    cairo_gl_uniform_entry_t key, *uniform_entry;
+
+    _cairo_gl_uniform_entry_init (&key, name);
+
+    uniform_entry = _cairo_hash_table_lookup (shader->uniform_cache, &key.base);
+    if (uniform_entry) {
+	*location = uniform_entry->location;
+	_cairo_gl_uniform_entry_fini (&key);
+	return;
+    }
+
+    *location = ctx->dispatch.GetUniformLocation (shader->program, name);
+
+    uniform_entry = _cairo_malloc (sizeof (cairo_gl_uniform_entry_t));
+    if (unlikely (uniform_entry == NULL))
+	return;
+
+    _cairo_gl_uniform_entry_init (uniform_entry, name);
+    uniform_entry->location = *location;
+    if (_cairo_hash_table_insert (shader->uniform_cache,
+				  &uniform_entry->base)) {
+	_cairo_gl_uniform_entry_fini (uniform_entry);
+	free (uniform_entry);
+    }
+}
+
 typedef struct _cairo_shader_cache_entry {
     cairo_cache_entry_t base;
 
@@ -136,6 +205,7 @@ _cairo_gl_shader_init (cairo_gl_shader_t *shader)
 {
     shader->fragment_shader = 0;
     shader->program = 0;
+    shader->uniform_cache = _cairo_hash_table_create (_cairo_gl_uniform_equal);
 }
 
 cairo_status_t
@@ -199,6 +269,19 @@ _cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx)
     }
 
     _cairo_cache_fini (&ctx->shaders);
+    _cairo_gl_shader_fini (ctx, &ctx->fill_rectangles_shader);
+}
+
+static void
+_cairo_gl_shader_uniform_cache_destroy_entry (void *entry,
+					      void *closure)
+{
+    cairo_gl_uniform_entry_t *uniform_entry = entry;
+
+    _cairo_hash_table_remove ((cairo_hash_table_t *) closure,
+			      &uniform_entry->base);
+    _cairo_gl_uniform_entry_fini (uniform_entry);
+    free (uniform_entry);
 }
 
 void
@@ -210,6 +293,13 @@ _cairo_gl_shader_fini (cairo_gl_context_t *ctx,
 
     if (shader->program)
 	ctx->dispatch.DeleteProgram (shader->program);
+
+    if (shader->uniform_cache) {
+	_cairo_hash_table_foreach (shader->uniform_cache,
+				   _cairo_gl_shader_uniform_cache_destroy_entry,
+				   shader->uniform_cache);
+	_cairo_hash_table_destroy (shader->uniform_cache);
+    }
 }
 
 static const char *operand_names[] = { "source", "mask", "dest" };
@@ -853,12 +943,12 @@ _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx,
     glGetIntegerv (GL_CURRENT_PROGRAM, &saved_program);
     dispatch->UseProgram (shader->program);
 
-    location = dispatch->GetUniformLocation (shader->program, "source_sampler");
-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.