[cairo] [path] cache uniforms

Henry (Yu) Song - SISA henry.song at samsung.com
Thu Jun 13 14:52:25 PDT 2013


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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cairographics.org/archives/cairo/attachments/20130613/e71eb151/attachment-0001.html>


More information about the cairo mailing list