[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