[cairo] [patch] gl: cache uniform location

Henry (Yu) Song - SISA hsong at sisa.samsung.com
Wed Aug 22 15:04:44 PDT 2012


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 <henry.song at samsung.com>
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");


More information about the cairo mailing list