[cairo] [PATCH] gl: Remove the shader language version abstraction

Martin Robinson mrobinson at igalia.com
Fri Aug 17 12:44:16 PDT 2012


Cairo only needs to support one version of the shader language API,
thanks to the dispatch table. This seems unlikely to change any time
soon. This makes the addition of new features, such as a uniform
location cache, simpler.
---
 src/cairo-gl-private.h |    6 +-
 src/cairo-gl-shaders.c |  464 ++++++++++++++++--------------------------------
 2 files changed, 159 insertions(+), 311 deletions(-)

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 97abaf0..48087ec 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -193,8 +193,6 @@ typedef enum cairo_gl_tex {
     CAIRO_GL_TEX_TEMP = 2
 } cairo_gl_tex_t;
 
-typedef struct cairo_gl_shader_impl cairo_gl_shader_impl_t;
-
 typedef struct cairo_gl_shader {
     GLuint fragment_shader;
     GLuint program;
@@ -316,7 +314,7 @@ struct _cairo_gl_context {
     cairo_bool_t supports_msaa;
     char *vb;
 
-    const cairo_gl_shader_impl_t *shader_impl;
+    cairo_bool_t has_shader_support;
 
     GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1];
     cairo_gl_shader_t fill_rectangles_shader;
@@ -419,7 +417,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 static cairo_always_inline cairo_bool_t
 _cairo_gl_device_has_glsl (cairo_device_t *device)
 {
-    return ((cairo_gl_context_t *) device)->shader_impl != NULL;
+    return ((cairo_gl_context_t *) device)->has_shader_support;
 }
 
 static cairo_always_inline cairo_bool_t
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index ea57efa..9e84ee5 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -44,270 +44,13 @@
 #include "cairo-error-private.h"
 #include "cairo-output-stream-private.h"
 
-typedef struct cairo_gl_shader_impl {
-    void
-    (*compile_shader) (cairo_gl_context_t *ctx, GLuint *shader, GLenum type,
-		       const char *text);
-
-    void
-    (*link_shader) (cairo_gl_context_t *ctx, GLuint *program, GLuint vert, GLuint frag);
-
-    void
-    (*destroy_shader) (cairo_gl_context_t *ctx, GLuint shader);
-
-    void
-    (*destroy_program) (cairo_gl_context_t *ctx, GLuint program);
-
-    void
-    (*bind_float) (cairo_gl_context_t *ctx,
-		   cairo_gl_shader_t *shader,
-		   const char *name,
-		   float value);
-
-    void
-    (*bind_vec2) (cairo_gl_context_t *ctx,
-		  cairo_gl_shader_t *shader,
-		  const char *name,
-		  float value0,
-		  float value1);
-
-    void
-    (*bind_vec3) (cairo_gl_context_t *ctx,
-		  cairo_gl_shader_t *shader,
-		  const char *name,
-		  float value0,
-		  float value1,
-		  float value2);
-
-    void
-    (*bind_vec4) (cairo_gl_context_t *ctx,
-		  cairo_gl_shader_t *shader,
-		  const char *name,
-		  float value0, float value1,
-		  float value2, float value3);
-
-    void
-    (*bind_matrix) (cairo_gl_context_t *ctx,
-		    cairo_gl_shader_t *shader,
-		    const char *name,
-		    cairo_matrix_t* m);
-
-    void
-    (*bind_matrix4f) (cairo_gl_context_t *ctx,
-		      cairo_gl_shader_t *shader,
-		      const char *name,
-		      GLfloat* gl_m);
-
-    void
-    (*use) (cairo_gl_context_t *ctx,
-	    cairo_gl_shader_t *shader);
-} shader_impl_t;
-
 static cairo_status_t
-_cairo_gl_shader_compile (cairo_gl_context_t *ctx,
-			  cairo_gl_shader_t *shader,
-			  cairo_gl_var_type_t src,
-			  cairo_gl_var_type_t mask,
-			  cairo_bool_t use_coverage,
-			  const char *fragment_text);
-
-/* OpenGL Core 2.0 API. */
-static void
-compile_shader_core_2_0 (cairo_gl_context_t *ctx, GLuint *shader,
-			 GLenum type, const char *text)
-{
-    const char* strings[1] = { text };
-    GLint gl_status;
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
-    *shader = dispatch->CreateShader (type);
-    dispatch->ShaderSource (*shader, 1, strings, 0);
-    dispatch->CompileShader (*shader);
-    dispatch->GetShaderiv (*shader, GL_COMPILE_STATUS, &gl_status);
-    if (gl_status == GL_FALSE) {
-        GLint log_size;
-        dispatch->GetShaderiv (*shader, GL_INFO_LOG_LENGTH, &log_size);
-        if (0 < log_size) {
-            char *log = _cairo_malloc (log_size);
-            GLint chars;
-
-            log[log_size - 1] = '\0';
-            dispatch->GetShaderInfoLog (*shader, log_size, &chars, log);
-            printf ("OpenGL shader compilation failed.  Shader:\n"
-                    "%s\n"
-                    "OpenGL compilation log:\n"
-                    "%s\n",
-                    text, log);
-
-            free (log);
-        } else {
-            printf ("OpenGL shader compilation failed.\n");
-        }
-
-	ASSERT_NOT_REACHED;
-    }
-}
-
-static void
-link_shader_core_2_0 (cairo_gl_context_t *ctx, GLuint *program,
-		      GLuint vert, GLuint frag)
-{
-    GLint gl_status;
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
-    *program = dispatch->CreateProgram ();
-    dispatch->AttachShader (*program, vert);
-    dispatch->AttachShader (*program, frag);
-
-    dispatch->BindAttribLocation (*program, CAIRO_GL_VERTEX_ATTRIB_INDEX,
-				  "Vertex");
-    dispatch->BindAttribLocation (*program, CAIRO_GL_COLOR_ATTRIB_INDEX,
-				  "Color");
-    dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD0_ATTRIB_INDEX,
-				  "MultiTexCoord0");
-    dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD1_ATTRIB_INDEX,
-				  "MultiTexCoord1");
-
-    dispatch->LinkProgram (*program);
-    dispatch->GetProgramiv (*program, GL_LINK_STATUS, &gl_status);
-    if (gl_status == GL_FALSE) {
-        GLint log_size;
-        dispatch->GetProgramiv (*program, GL_INFO_LOG_LENGTH, &log_size);
-        if (0 < log_size) {
-            char *log = _cairo_malloc (log_size);
-            GLint chars;
-
-            log[log_size - 1] = '\0';
-            dispatch->GetProgramInfoLog (*program, log_size, &chars, log);
-            printf ("OpenGL shader link failed:\n%s\n", log);
-
-            free (log);
-        } else {
-            printf ("OpenGL shader link failed.\n");
-        }
-
-	ASSERT_NOT_REACHED;
-    }
-}
-
-static void
-destroy_shader_core_2_0 (cairo_gl_context_t *ctx, GLuint shader)
-{
-    ctx->dispatch.DeleteShader (shader);
-}
-
-static void
-destroy_program_core_2_0 (cairo_gl_context_t *ctx, GLuint shader)
-{
-    ctx->dispatch.DeleteProgram (shader);
-}
-
-static void
-bind_float_core_2_0 (cairo_gl_context_t *ctx,
-		     cairo_gl_shader_t *shader,
-		     const char *name,
-		     float value)
-{
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (shader->program, name);
-    assert (location != -1);
-    dispatch->Uniform1f (location, value);
-}
-
-static void
-bind_vec2_core_2_0 (cairo_gl_context_t *ctx,
-		    cairo_gl_shader_t *shader,
-		    const char *name,
-		    float value0,
-		    float value1)
-{
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (shader->program, name);
-    assert (location != -1);
-    dispatch->Uniform2f (location, value0, value1);
-}
-
-static void
-bind_vec3_core_2_0 (cairo_gl_context_t *ctx,
-		    cairo_gl_shader_t *shader,
-		    const char *name,
-		    float value0,
-		    float value1,
-		    float value2)
-{
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (shader->program, name);
-    assert (location != -1);
-    dispatch->Uniform3f (location, value0, value1, value2);
-}
-
-static void
-bind_vec4_core_2_0 (cairo_gl_context_t *ctx,
-		    cairo_gl_shader_t *shader,
-		    const char *name,
-		    float value0,
-		    float value1,
-		    float value2,
-		    float value3)
-{
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (shader->program, name);
-    assert (location != -1);
-    dispatch->Uniform4f (location, value0, value1, value2, value3);
-}
-
-static void
-bind_matrix_core_2_0 (cairo_gl_context_t *ctx,
-		      cairo_gl_shader_t *shader,
-		      const char *name,
-		      cairo_matrix_t* m)
-{
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (shader->program, name);
-    float gl_m[16] = {
-        m->xx, m->xy, m->x0,
-        m->yx, m->yy, m->y0,
-        0,     0,     1
-    };
-    assert (location != -1);
-    dispatch->UniformMatrix3fv (location, 1, GL_TRUE, gl_m);
-}
-
-static void
-bind_matrix4f_core_2_0 (cairo_gl_context_t *ctx,
-		        cairo_gl_shader_t *shader,
-		        const char *name,
-		        GLfloat* gl_m)
-{
-    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-    GLint location = dispatch->GetUniformLocation (shader->program, name);
-    assert (location != -1);
-    dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m);
-}
-
-static void
-use_program_core_2_0 (cairo_gl_context_t *ctx,
-		      cairo_gl_shader_t *shader)
-{
-    if (shader)
-	ctx->dispatch.UseProgram (shader->program);
-    else
-	ctx->dispatch.UseProgram (0);
-}
-
-static const cairo_gl_shader_impl_t shader_impl_core_2_0 = {
-    compile_shader_core_2_0,
-    link_shader_core_2_0,
-    destroy_shader_core_2_0,
-    destroy_program_core_2_0,
-    bind_float_core_2_0,
-    bind_vec2_core_2_0,
-    bind_vec3_core_2_0,
-    bind_vec4_core_2_0,
-    bind_matrix_core_2_0,
-    bind_matrix4f_core_2_0,
-    use_program_core_2_0,
-};
+_cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
+				   cairo_gl_shader_t *shader,
+				   cairo_gl_var_type_t src,
+				   cairo_gl_var_type_t mask,
+				   cairo_bool_t use_coverage,
+				   const char *fragment_text);
 
 typedef struct _cairo_shader_cache_entry {
     cairo_cache_entry_t base;
@@ -412,13 +155,10 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
     if (_cairo_gl_get_version () >= CAIRO_GL_VERSION_ENCODE (2, 0) ||
 	(_cairo_gl_has_extension ("GL_ARB_shader_objects") &&
 	 _cairo_gl_has_extension ("GL_ARB_fragment_shader") &&
-	 _cairo_gl_has_extension ("GL_ARB_vertex_shader")))
-    {
-	ctx->shader_impl = &shader_impl_core_2_0;
-    }
-    else
-    {
-	ctx->shader_impl = NULL;
+	 _cairo_gl_has_extension ("GL_ARB_vertex_shader"))) {
+	ctx->has_shader_support = TRUE;
+    } else {
+	ctx->has_shader_support = FALSE;
 	fprintf (stderr, "Error: The cairo gl backend requires shader support!\n");
 	return CAIRO_STATUS_DEVICE_ERROR;
     }
@@ -436,12 +176,12 @@ _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
 	return status;
 
     _cairo_gl_shader_init (&ctx->fill_rectangles_shader);
-    status = _cairo_gl_shader_compile (ctx,
-				       &ctx->fill_rectangles_shader,
-				       CAIRO_GL_VAR_NONE,
-				       CAIRO_GL_VAR_NONE,
-				       FALSE,
-				       fill_fs_source);
+    status = _cairo_gl_shader_compile_and_link (ctx,
+						&ctx->fill_rectangles_shader,
+						CAIRO_GL_VAR_NONE,
+						CAIRO_GL_VAR_NONE,
+						FALSE,
+						fill_fs_source);
     if (unlikely (status))
 	return status;
 
@@ -455,7 +195,7 @@ _cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx)
 
     for (i = 0; i <= CAIRO_GL_VAR_TYPE_MAX; i++) {
 	if (ctx->vertex_shaders[i])
-	    ctx->shader_impl->destroy_shader (ctx, ctx->vertex_shaders[i]);
+	    ctx->dispatch.DeleteShader (ctx->vertex_shaders[i]);
     }
 
     _cairo_cache_fini (&ctx->shaders);
@@ -466,10 +206,10 @@ _cairo_gl_shader_fini (cairo_gl_context_t *ctx,
 		       cairo_gl_shader_t *shader)
 {
     if (shader->fragment_shader)
-        ctx->shader_impl->destroy_shader (ctx, shader->fragment_shader);
+	ctx->dispatch.DeleteShader (shader->fragment_shader);
 
     if (shader->program)
-        ctx->shader_impl->destroy_program (ctx, shader->program);
+	ctx->dispatch.DeleteProgram (shader->program);
 }
 
 static const char *operand_names[] = { "source", "mask", "dest" };
@@ -966,13 +706,93 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void
+compile_shader (cairo_gl_context_t *ctx,
+		GLuint *shader,
+		GLenum type,
+		const char *source)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint success, log_size, num_chars;
+    char *log;
+
+    *shader = dispatch->CreateShader (type);
+    dispatch->ShaderSource (*shader, 1, &source, 0);
+    dispatch->CompileShader (*shader);
+    dispatch->GetShaderiv (*shader, GL_COMPILE_STATUS, &success);
+
+    if (success)
+	return;
+
+    dispatch->GetShaderiv (*shader, GL_INFO_LOG_LENGTH, &log_size);
+    if (log_size < 0) {
+	printf ("OpenGL shader compilation failed.\n");
+	ASSERT_NOT_REACHED;
+	return;
+    }
+
+    log = _cairo_malloc (log_size + 1);
+    dispatch->GetShaderInfoLog (*shader, log_size, &num_chars, log);
+    log[num_chars] = '\0';
+
+    printf ("OpenGL shader compilation failed.  Shader:\n%s\n", source);
+    printf ("OpenGL compilation log:\n%s\n", log);
+
+    free (log);
+    ASSERT_NOT_REACHED;
+}
+
+static void
+link_shader_program (cairo_gl_context_t *ctx,
+		     GLuint *program,
+		     GLuint vert,
+		     GLuint frag)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint success, log_size, num_chars;
+    char *log;
+
+    *program = dispatch->CreateProgram ();
+    dispatch->AttachShader (*program, vert);
+    dispatch->AttachShader (*program, frag);
+
+    dispatch->BindAttribLocation (*program, CAIRO_GL_VERTEX_ATTRIB_INDEX,
+				  "Vertex");
+    dispatch->BindAttribLocation (*program, CAIRO_GL_COLOR_ATTRIB_INDEX,
+				  "Color");
+    dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD0_ATTRIB_INDEX,
+				  "MultiTexCoord0");
+    dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD1_ATTRIB_INDEX,
+				  "MultiTexCoord1");
+
+    dispatch->LinkProgram (*program);
+    dispatch->GetProgramiv (*program, GL_LINK_STATUS, &success);
+    if (success)
+	return;
+
+    dispatch->GetProgramiv (*program, GL_INFO_LOG_LENGTH, &log_size);
+    if (log_size < 0) {
+	printf ("OpenGL shader link failed.\n");
+	ASSERT_NOT_REACHED;
+	return;
+    }
+
+    log = _cairo_malloc (log_size + 1);
+    dispatch->GetProgramInfoLog (*program, log_size, &num_chars, log);
+    log[num_chars] = '\0';
+
+    printf ("OpenGL shader link failed:\n%s\n", log);
+    free (log);
+    ASSERT_NOT_REACHED;
+}
+
 static cairo_status_t
-_cairo_gl_shader_compile (cairo_gl_context_t *ctx,
-			  cairo_gl_shader_t *shader,
-			  cairo_gl_var_type_t src,
-			  cairo_gl_var_type_t mask,
-			  cairo_bool_t use_coverage,
-			  const char *fragment_text)
+_cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
+				   cairo_gl_shader_t *shader,
+				   cairo_gl_var_type_t src,
+				   cairo_gl_var_type_t mask,
+				   cairo_bool_t use_coverage,
+				   const char *fragment_text)
 {
     unsigned int vertex_shader;
     cairo_status_t status;
@@ -992,19 +812,17 @@ _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
         if (unlikely (status))
             goto FAILURE;
 
-	ctx->shader_impl->compile_shader (ctx, &ctx->vertex_shaders[vertex_shader],
-					  GL_VERTEX_SHADER,
-					  source);
+	compile_shader (ctx, &ctx->vertex_shaders[vertex_shader],
+			GL_VERTEX_SHADER, source);
         free (source);
     }
 
-    ctx->shader_impl->compile_shader (ctx, &shader->fragment_shader,
-				      GL_FRAGMENT_SHADER,
-				      fragment_text);
+    compile_shader (ctx, &shader->fragment_shader,
+		    GL_FRAGMENT_SHADER, fragment_text);
 
-    ctx->shader_impl->link_shader (ctx, &shader->program,
-				   ctx->vertex_shaders[vertex_shader],
-				   shader->fragment_shader);
+    link_shader_program (ctx, &shader->program,
+			 ctx->vertex_shaders[vertex_shader],
+			 shader->fragment_shader);
 
     return CAIRO_STATUS_SUCCESS;
 
@@ -1053,7 +871,11 @@ _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
 			     const char *name,
 			     float value)
 {
-    ctx->shader_impl->bind_float (ctx, ctx->current_shader, name, value);
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
+						   name);
+    assert (location != -1);
+    dispatch->Uniform1f (location, value);
 }
 
 void
@@ -1062,7 +884,11 @@ _cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
 			    float value0,
 			    float value1)
 {
-    ctx->shader_impl->bind_vec2 (ctx, ctx->current_shader, name, value0, value1);
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
+						   name);
+    assert (location != -1);
+    dispatch->Uniform2f (location, value0, value1);
 }
 
 void
@@ -1072,7 +898,11 @@ _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
 			    float value1,
 			    float value2)
 {
-    ctx->shader_impl->bind_vec3 (ctx, ctx->current_shader, name, value0, value1, value2);
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
+						   name);
+    assert (location != -1);
+    dispatch->Uniform3f (location, value0, value1, value2);
 }
 
 void
@@ -1081,21 +911,38 @@ _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
 			    float value0, float value1,
 			    float value2, float value3)
 {
-    ctx->shader_impl->bind_vec4 (ctx, ctx->current_shader, name, value0, value1, value2, value3);
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
+						   name);
+    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_matrix_t* m)
 {
-    ctx->shader_impl->bind_matrix (ctx, ctx->current_shader, name, m);
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
+						   name);
+    float gl_m[16] = {
+	m->xx, m->xy, m->x0,
+	m->yx, m->yy, m->y0,
+	0,     0,     1
+    };
+    assert (location != -1);
+    dispatch->UniformMatrix3fv (location, 1, GL_TRUE, gl_m);
 }
 
 void
 _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
 				const char *name, GLfloat* gl_m)
 {
-    ctx->shader_impl->bind_matrix4f (ctx, ctx->current_shader, name, gl_m);
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
+						   name);
+    assert (location != -1);
+    dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m);
 }
 
 void
@@ -1105,7 +952,10 @@ _cairo_gl_set_shader (cairo_gl_context_t *ctx,
     if (ctx->current_shader == shader)
         return;
 
-    ctx->shader_impl->use (ctx, shader);
+    if (shader)
+	ctx->dispatch.UseProgram (shader->program);
+    else
+	ctx->dispatch.UseProgram (0);
 
     ctx->current_shader = shader;
 }
@@ -1164,12 +1014,12 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
 
     entry->ctx = ctx;
     _cairo_gl_shader_init (&entry->shader);
-    status = _cairo_gl_shader_compile (ctx,
-				       &entry->shader,
-				       cairo_gl_operand_get_var_type (source->type),
-				       cairo_gl_operand_get_var_type (mask->type),
-				       use_coverage,
-				       fs_source);
+    status = _cairo_gl_shader_compile_and_link (ctx,
+						&entry->shader,
+						cairo_gl_operand_get_var_type (source->type),
+						cairo_gl_operand_get_var_type (mask->type),
+						use_coverage,
+						fs_source);
     free (fs_source);
 
     if (unlikely (status)) {
-- 
1.7.5.4



More information about the cairo mailing list