[cairo-commit] src/cairo-gl-private.h src/cairo-gl-shaders.c

Martin Robinson mrobinson at kemper.freedesktop.org
Wed Aug 22 10:50:12 PDT 2012


 src/cairo-gl-private.h |    6 
 src/cairo-gl-shaders.c |  464 ++++++++++++++++---------------------------------
 2 files changed, 159 insertions(+), 311 deletions(-)

New commits:
commit 97410990935bb4baacbc1584362a87733c483583
Author: Martin Robinson <mrobinson at igalia.com>
Date:   Fri Aug 17 16:00:51 2012 -0700

    gl: Remove the shader language version abstraction
    
    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.

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..41672d6 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[9] = {
+	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)) {


More information about the cairo-commit mailing list