[path] cache uniforms

"Henry (Yu) Song - SISA" <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <3955FA337689574EB32F94B12A7E6E9E438CA335@sisaex01sj>
On mobile drivers, where a typical glGetUniform takes 2 - 3 microseconds.  This is called possibly multiple times for each drawing operation.  Saving uniform locations reduces time.



From d8209e455e1c1b66d4d8ff67c842cfa6bf7e44de Mon Sep 17 00:00:00 2001
From: Henry Song <[email protected]>
Date: Fri, 11 Jan 2013 14:12:12 +0100
Subject: [PATCH] gl: Cache shader uniform locations

Instead of continuously calling glUniformLocation each time we have
flushed, cache the uniform locations in the shader object.
---
src/cairo-gl-composite.c |   2 +-
src/cairo-gl-operand.c   |  50 +++++++++++-------------
src/cairo-gl-private.h   |  41 ++++++++++++++++---
src/cairo-gl-shaders.c   | 100 +++++++++++++++++++++++++++++++++++++----------
4 files changed, 139 insertions(+), 54 deletions(-)

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 1dcc6a1..23db7aa 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -134,7 +134,7 @@ static void
_cairo_gl_composite_bind_to_shader (cairo_gl_context_t   *ctx,
                                                                   cairo_gl_composite_t *setup)
{
-    _cairo_gl_shader_bind_matrix4f(ctx, "ModelViewProjectionMatrix",
+    _cairo_gl_shader_bind_matrix4f(ctx, CAIRO_GL_UNIFORM_PROJECTION_MATRIX,
                                                                  ctx->modelviewprojection_matrix);
     _cairo_gl_operand_bind_to_shader (ctx, &setup->src,  CAIRO_GL_TEX_SOURCE);
     _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
index 7b5b404..5f0f9db 100644
--- a/src/cairo-gl-operand.c
+++ b/src/cairo-gl-operand.c
@@ -613,14 +613,8 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                                   cairo_gl_operand_t *operand,
                                   cairo_gl_tex_t      tex_unit)
{
-    char uniform_name[50];
-    char *custom_part;
-    static const char *names[] = { "source", "mask" };
     const cairo_matrix_t *texgen = NULL;
-    strcpy (uniform_name, names[tex_unit]);
-    custom_part = uniform_name + strlen (names[tex_unit]);
-
     switch (operand->type) {
     default:
     case CAIRO_GL_OPERAND_COUNT:
@@ -629,32 +623,31 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
               return;
     case CAIRO_GL_OPERAND_CONSTANT:
-        strcpy (custom_part, "_constant");
               _cairo_gl_shader_bind_vec4 (ctx,
-                                    uniform_name,
-                                    operand->constant.color[0],
-                                    operand->constant.color[1],
-                                    operand->constant.color[2],
-                                    operand->constant.color[3]);
-              return;
-
+                                                                 _cairo_gl_shader_uniform_for_texunit (
+                                                                             CAIRO_GL_UNIFORM_CONSTANT, tex_unit),
+                                                                 operand->constant.color[0],
+                                                                 operand->constant.color[1],
+                                                                 operand->constant.color[2],
+                                                                 operand->constant.color[3]);
+        return;
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
-              strcpy (custom_part, "_a");
               _cairo_gl_shader_bind_float  (ctx,
-                                                                    uniform_name,
+                                                                   _cairo_gl_shader_uniform_for_texunit (
+                                                                               CAIRO_GL_UNIFORM_A, tex_unit),
                                                                     operand->gradient.a);
               /* fall through */
     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
-              strcpy (custom_part, "_circle_d");
-              _cairo_gl_shader_bind_vec3   (ctx,
-                                                                    uniform_name,
+             _cairo_gl_shader_bind_vec3 (ctx,
+                                                                 _cairo_gl_shader_uniform_for_texunit (
+                                                                             CAIRO_GL_UNIFORM_CIRCLE_D, tex_unit),
                                                                     operand->gradient.circle_d.center.x,
                                                                     operand->gradient.circle_d.center.y,
                                                                     operand->gradient.circle_d.radius);
-              strcpy (custom_part, "_radius_0");
               _cairo_gl_shader_bind_float  (ctx,
-                                                                    uniform_name,
+                                                                   _cairo_gl_shader_uniform_for_texunit (
+                                                                               CAIRO_GL_UNIFORM_RADIUS_0, tex_unit),
                                                                     operand->gradient.radius_0);
         /* fall through */
     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
@@ -677,8 +670,10 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                               width = operand->gradient.gradient->cache_entry.size,
                               height = 1;
                   }
-                  strcpy (custom_part, "_texdims");
-                  _cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
+                 _cairo_gl_shader_bind_vec2 (ctx,
+                                                                             _cairo_gl_shader_uniform_for_texunit (
+                                                                                 CAIRO_GL_UNIFORM_TEXDIMS, tex_unit),
+                                                                             width, height);
               }
               break;
     }
@@ -690,11 +685,12 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                   if (operand->gradient.texgen)
                                   texgen = &operand->gradient.m;
     }
-    if (texgen) {
-                  char name[20];
-                  sprintf (name, "%s_texgen", names[tex_unit]);
-                  _cairo_gl_shader_bind_matrix(ctx, name, texgen);
+    if (texgen) {
+             _cairo_gl_shader_bind_matrix (ctx,
+                                                                   _cairo_gl_shader_uniform_for_texunit (
+                                                                               CAIRO_GL_UNIFORM_TEXGEN, tex_unit),
+                                                                   texgen);
     }
}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index d49e3d9..8985fe1 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -105,6 +105,30 @@ typedef enum cairo_gl_flavor {
     CAIRO_GL_FLAVOR_ES = 2
} cairo_gl_flavor_t;
+/* The order here is sensitive because of the logic of
+ *_cairo_gl_shader_uniform_for_texunit. */
+typedef enum cairo_gl_uniform_t {
+    CAIRO_GL_UNIFORM_TEXDIMS,    /* "source_texdims" */
+    CAIRO_GL_UNIFORM_TEXGEN,     /* "source_texgen" */
+    CAIRO_GL_UNIFORM_CONSTANT,   /* "source_constant" */
+    CAIRO_GL_UNIFORM_SAMPLER,    /* "source_sampler" */
+    CAIRO_GL_UNIFORM_A,          /* "source_a" */
+    CAIRO_GL_UNIFORM_CIRCLE_D,   /* "source_circle_d" */
+    CAIRO_GL_UNIFORM_RADIUS_0,   /* "source_radius_0" */
+
+    CAIRO_GL_UNIFORM_MASK_TEXDIMS,      /* "mask_texdims" */
+    CAIRO_GL_UNIFORM_MASK_TEXGEN,       /* "mask_texgen" */
+    CAIRO_GL_UNIFORM_MASK_CONSTANT,     /* "mask_constant" */
+    CAIRO_GL_UNIFORM_MASK_SAMPLER,      /* "mask_sampler" */
+    CAIRO_GL_UNIFORM_MASK_A,            /* "mask_a" */
+    CAIRO_GL_UNIFORM_MASK_CIRCLE_D,     /* "mask_circle_d" */
+    CAIRO_GL_UNIFORM_MASK_RADIUS_0,     /* "mask_radius_0" */
+
+    CAIRO_GL_UNIFORM_PROJECTION_MATRIX, /* "ModelViewProjectionMatrix" */
+
+    CAIRO_GL_UNIFORM_MAX
+} cairo_gl_uniform_t;
+
/* Indices for vertex attributes used by BindAttribLocation etc */
enum {
     CAIRO_GL_VERTEX_ATTRIB_INDEX = 0,
@@ -201,6 +225,7 @@ typedef enum cairo_gl_tex {
typedef struct cairo_gl_shader {
     GLuint fragment_shader;
     GLuint program;
+    GLint uniforms[CAIRO_GL_UNIFORM_MAX];
} cairo_gl_shader_t;
 typedef enum cairo_gl_shader_in {
@@ -649,37 +674,41 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
                               cairo_gl_shader_in_t in,
                               cairo_gl_shader_t **shader);
+cairo_private cairo_gl_uniform_t
+_cairo_gl_shader_uniform_for_texunit (cairo_gl_uniform_t uniform,
+                                                                   cairo_gl_tex_t tex_unit);
+
cairo_private void
_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
-                                                   const char *name,
+                                                  cairo_gl_uniform_t uniform,
                                                    float value);
 cairo_private void
_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
-                                                  const char *name,
+                                                 cairo_gl_uniform_t uniform,
                                                   float value0, float value1);
 cairo_private void
_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
-                                                  const char *name,
+                                                 cairo_gl_uniform_t uniform,
                                                   float value0,
                                                   float value1,
                                                   float value2);
 cairo_private void
_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
-                                                  const char *name,
+                                                 cairo_gl_uniform_t uniform,
                                                   float value0, float value1,
                                                   float value2, float value3);
 cairo_private void
_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
-                                                    const char *name,
+                                                   cairo_gl_uniform_t uniform,
                                                     const cairo_matrix_t* m);
 cairo_private void
_cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
-                                                              const char *name,
+                                                             cairo_gl_uniform_t uniform,
                                                               GLfloat* gl_m);
 cairo_private void
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index d8de712..b9eb5c7 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -44,6 +44,52 @@
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
+static GLint
+_cairo_gl_shader_get_uniform_location (cairo_gl_context_t *ctx,
+                                                                    cairo_gl_shader_t *shader,
+                                                                    cairo_gl_uniform_t uniform)
+{
+    /* This should be kept in sync with the enum
+     * definition in cairo-gl-private.h. */
+    const char *names[CAIRO_GL_UNIFORM_MAX] = {
+             "source_texdims",
+             "source_texgen",
+             "source_constant",
+             "source_sampler",
+             "source_a",
+             "source_circle_d",
+             "source_radius_0",
+             "mask_texdims",
+             "mask_texgen",
+             "mask_constant",
+             "mask_sampler",
+             "mask_a",
+             "mask_circle_d",
+             "mask_radius_0",
+             "ModelViewProjectionMatrix"
+    };
+
+    if (shader->uniforms[uniform] != -1)
+             return shader->uniforms[uniform];
+
+    shader->uniforms[uniform] =
+             ctx->dispatch.GetUniformLocation (shader->program,
+                                                                               names[uniform]);
+    return shader->uniforms[uniform];
+}
+
+cairo_gl_uniform_t
+_cairo_gl_shader_uniform_for_texunit (cairo_gl_uniform_t uniform,
+                                                                   cairo_gl_tex_t tex_unit)
+{
+    assert (uniform < CAIRO_GL_UNIFORM_MASK_TEXDIMS);
+    assert (tex_unit == CAIRO_GL_TEX_SOURCE || tex_unit == CAIRO_GL_TEX_MASK);
+    if (tex_unit == CAIRO_GL_TEX_SOURCE)
+             return uniform;
+    else
+             return uniform + CAIRO_GL_UNIFORM_MASK_TEXDIMS;
+}
+
static cairo_status_t
_cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
                                                                  cairo_gl_shader_t *shader,
@@ -139,8 +185,12 @@ _cairo_gl_shader_cache_destroy (void *data)
static void
_cairo_gl_shader_init (cairo_gl_shader_t *shader)
{
+    int i;
     shader->fragment_shader = 0;
     shader->program = 0;
+
+    for (i = 0; i < CAIRO_GL_UNIFORM_MAX; i++)
+             shader->uniforms[i] = -1;
}
 cairo_status_t
@@ -872,12 +922,14 @@ _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");
+    location = _cairo_gl_shader_get_uniform_location (ctx, shader,
+                                                                                                   CAIRO_GL_UNIFORM_SAMPLER);
     if (location != -1) {
               dispatch->Uniform1i (location, CAIRO_GL_TEX_SOURCE);
     }
-    location = dispatch->GetUniformLocation (shader->program, "mask_sampler");
+    location = _cairo_gl_shader_get_uniform_location (ctx, shader,
+                                                                                                   CAIRO_GL_UNIFORM_MASK_SAMPLER);
     if (location != -1) {
               dispatch->Uniform1i (location, CAIRO_GL_TEX_MASK);
     }
@@ -887,64 +939,70 @@ _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx,
 void
_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
-                                                   const char *name,
+                                                  cairo_gl_uniform_t uniform,
                                                    float value)
{
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
-                                                                                                 name);
+    GLint location = _cairo_gl_shader_get_uniform_location (ctx,
+                                                                                                                 ctx->current_shader,
+                                                                                                                 uniform);
     assert (location != -1);
     dispatch->Uniform1f (location, value);
}
 void
_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
-                                                  const char *name,
+                                                 cairo_gl_uniform_t uniform,
                                                   float value0,
                                                   float value1)
{
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
-                                                                                                 name);
+    GLint location = _cairo_gl_shader_get_uniform_location (ctx,
+                                                                                                                 ctx->current_shader,
+                                                                                                                 uniform);
     assert (location != -1);
     dispatch->Uniform2f (location, value0, value1);
}
 void
_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
-                                                  const char *name,
+                                                 cairo_gl_uniform_t uniform,
                                                   float value0,
                                                   float value1,
                                                   float value2)
{
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
-                                                                                                 name);
+    GLint location = _cairo_gl_shader_get_uniform_location (ctx,
+                                                                                                                 ctx->current_shader,
+                                                                                                                 uniform);
     assert (location != -1);
     dispatch->Uniform3f (location, value0, value1, value2);
}
 void
_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
-                                                  const char *name,
+                                                 cairo_gl_uniform_t uniform,
                                                   float value0, float value1,
                                                   float value2, float value3)
{
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
-                                                                                                 name);
+    GLint location = _cairo_gl_shader_get_uniform_location (ctx,
+                                                                                                                 ctx->current_shader,
+                                                                                                                 uniform);
     assert (location != -1);
     dispatch->Uniform4f (location, value0, value1, value2, value3);
}
 void
_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
-                                                    const char *name,
+                                                   cairo_gl_uniform_t uniform,
                                                     const cairo_matrix_t* m)
{
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
-                                                                                                 name);
+    GLint location = _cairo_gl_shader_get_uniform_location (ctx,
+                                                                                                                 ctx->current_shader,
+                                                                                                                 uniform);
+
     float gl_m[9] = {
               m->xx, m->xy, m->x0,
               m->yx, m->yy, m->y0,
@@ -956,11 +1014,13 @@ _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
 void
_cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
-                                                              const char *name, GLfloat* gl_m)
+                                                             cairo_gl_uniform_t uniform,
+                                                             GLfloat* gl_m)
{
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
-                                                                                                 name);
+    GLint location = _cairo_gl_shader_get_uniform_location (ctx,
+                                                                                                                 ctx->current_shader,
+                                                                                                                 uniform);
     assert (location != -1);
     dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m);
}
--
1.8.1.2

-- 
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.