[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