[cairo] [PATCH] [gl] Add shader support code for GL versions < 3.0.

Zach Laine whatwasthataddress at gmail.com
Thu Jan 14 09:49:04 PST 2010


On Wed, Jan 13, 2010 at 6:08 PM, Eric Anholt <eric at anholt.net> wrote:
> Ultimately, we want all of our paths to use shaders when they are
> exposed -- it brings us closer to GL 3.0 compatibility and it should
> reduce the work that GL drivers have to do per operation to compute
> the required hardware state.

[snip]

I had just finished working on this before I saw Eric's patch above,
so there are conflicts with it.  If people like it in principle, I can
easily modify Eric's patch to work with it.
=============
Adds cairo_gl_shader_program_t, and functions to manipulate same.  Multiple GL
entry points for shaders are provided -- one for the pre-GL 2.0 extenstions
entry points, and one for GL 2.0.  This code is well tested, but currently
unused in the GL backend.
---
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 1e04ed2..b94516f 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -279,7 +279,7 @@ cairo_beos_headers = cairo-beos.h

 cairo_gl_headers = cairo-gl.h
 cairo_gl_private = cairo-gl-private.h
-cairo_gl_sources = cairo-gl-surface.c cairo-gl-glyphs.c
+cairo_gl_sources = cairo-gl-surface.c cairo-gl-glyphs.c cairo-gl-shader.c
 cairo_glx_sources += cairo-glx-context.c
 cairo_eagle_sources += cairo-eagle-context.c

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 79145cf..c9fd5cf 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -34,6 +34,7 @@
  * Contributor(s):
  *	Carl Worth <cworth at cworth.org>
  *	Chris Wilson <chris at chris-wilson.co.uk>
+ *      T. Zachary Laine <whatwasthataddress at gmail.com>
  */

 #ifndef CAIRO_GL_PRIVATE_H
@@ -79,6 +80,13 @@ typedef struct cairo_gl_glyph_cache {
     unsigned int width, height;
 } cairo_gl_glyph_cache_t;

+typedef struct cairo_gl_shader_program {
+    GLuint vertex_shader;
+    GLuint fragment_shader;
+    GLuint program;
+    cairo_bool_t build_failure;
+} cairo_gl_shader_program_t;
+
 struct _cairo_gl_context {
     cairo_reference_count_t ref_count;
     cairo_status_t status;
@@ -211,6 +219,47 @@ _cairo_gl_y_flip (cairo_gl_surface_t *surface, int y)
 	return (surface->height - 1) - y;
 }

+void
+init_shader_program (cairo_gl_shader_program_t *program);
+
+void
+destroy_shader_program (cairo_gl_shader_program_t *program);
+
+cairo_status_t
+create_shader_program (cairo_gl_shader_program_t *program,
+                       const char *vertex_text,
+                       const char *fragment_text);
+
+cairo_status_t
+create_linear_gradient_shader_program (cairo_gl_shader_program_t *program);
+
+cairo_status_t
+create_radial_gradient_shader_program (cairo_gl_shader_program_t *program);
+
+cairo_status_t
+bind_float_to_shader (GLuint program, const char *name,
+                      float value);
+
+cairo_status_t
+bind_vec2_to_shader (GLuint program, const char *name,
+                     float value0, float value1);
+
+cairo_status_t
+bind_vec3_to_shader (GLuint program, const char *name,
+                     float value0, float value1,
+                     float value2);
+
+cairo_status_t
+bind_vec4_to_shader (GLuint program, const char *name,
+                     float value0, float value1,
+                     float value2, float value3);
+
+cairo_status_t
+bind_matrix_to_shader (GLuint program, const char *name, cairo_matrix_t* m);
+
+cairo_status_t
+bind_texture_to_shader (GLuint program, const char *name, GLuint tex_unit);
+
 slim_hidden_proto (cairo_gl_surface_create);

 #endif /* CAIRO_GL_PRIVATE_H */
diff --git a/src/cairo-gl-shader.c b/src/cairo-gl-shader.c
new file mode 100644
index 0000000..52f43f3
--- /dev/null
+++ b/src/cairo-gl-shader.c
@@ -0,0 +1,653 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 T. Zachary Laine
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is T. Zachary Laine.
+ */
+
+#include "cairo-gl-private.h"
+
+typedef struct _shader_impl {
+    cairo_status_t
+    (*compile_shader) (GLuint *shader, GLenum type, const char *text);
+
+    cairo_status_t
+    (*link_shader) (GLuint *program, GLuint vert, GLuint frag);
+
+    void
+    (*destroy_shader_program) (cairo_gl_shader_program_t *program);
+
+    cairo_status_t
+    (*create_linear_gradient_shader_program)
(cairo_gl_shader_program_t *program);
+
+    cairo_status_t
+    (*create_radial_gradient_shader_program)
(cairo_gl_shader_program_t *program);
+
+    cairo_status_t
+    (*bind_float_to_shader) (GLuint program, const char *name,
+                             float value);
+
+    cairo_status_t
+    (*bind_vec2_to_shader) (GLuint program, const char *name,
+                            float value0, float value1);
+
+    cairo_status_t
+    (*bind_vec3_to_shader) (GLuint program, const char *name,
+                            float value0, float value1,
+                            float value2);
+
+    cairo_status_t
+    (*bind_vec4_to_shader) (GLuint program, const char *name,
+                            float value0, float value1,
+                            float value2, float value3);
+
+    cairo_status_t
+    (*bind_matrix_to_shader) (GLuint program, const char *name,
cairo_matrix_t* m);
+
+    cairo_status_t
+    (*bind_texture_to_shader) (GLuint program, const char *name,
GLuint tex_unit);
+
+    GLenum
+    (*vertex_enumerator) (void);
+
+    GLenum
+    (*fragment_enumerator) (void);
+} shader_impl_t;
+
+static const shader_impl_t*
+get_impl (void);
+
+static const char * const minimal_vert_text_110 =
+    "#version 110\n"
+    "\n"
+    "void main ()\n"
+    "{ gl_Position = ftransform(); }\n";
+
+/* This fragment shader was adapted from Argiris Kirtzidis' cairo-gral
+ * library, found at git://github.com/akyrtzi/cairo-gral.git.  Argiris' shader
+ * was adapted from the original algorithm in pixman.
+ */
+static const char * const radial_gradient_frag_text_110 =
+    "#version 110\n"
+    "\n"
+    "uniform sampler1D tex;\n"
+    "uniform mat4 matrix;\n"
+    "uniform vec2 circle_1;\n"
+    "uniform float radius_0;\n"
+    "uniform float radius_1;\n"
+    "uniform float first_offset;\n"
+    "uniform float last_offset;\n"
+    "\n"
+    "void main ()\n"
+    "{\n"
+    "    vec2 pos = (matrix * vec4 (gl_FragCoord.xy, 0.0, 1.0)).xy;\n"
+    "    \n"
+    "    float dr = radius_1 - radius_0;\n"
+    "    float dot_circle_1 = dot (circle_1, circle_1);\n"
+    "    float dot_pos_circle_1 = dot (pos, circle_1);\n"
+    "    \n"
+    "    float A = dot_circle_1 - dr * dr;\n"
+    "    float B = -2.0 * (dot_pos_circle_1 + radius_0 * dr);\n"
+    "    float C = dot (pos, pos) - radius_0 * radius_0;\n"
+    "    float det = B * B - 4.0 * A * C;\n"
+    "    det = max (det, 0.0);\n"
+    "    \n"
+    "    float sqrt_det = sqrt (det);\n"
+    "    /* This complicated bit of logic acts as\n"
+    "     * \"if (A < 0.0) sqrt_det = -sqrt_det\", without the branch.\n"
+    "     */\n"
+    "    sqrt_det *= 1.0 + 2.0 * sign (min (A, 0.0));\n"
+    "    \n"
+    "    float t = (-B + sqrt_det) / (2.0 * A);\n"
+    "    t = (t - first_offset) / (last_offset - first_offset);\n"
+    "    gl_FragColor = texture1D (tex, t);\n"
+    "}\n";
+
+static const char * const linear_gradient_frag_text_110 =
+    "#version 110\n"
+    "\n"
+    "uniform sampler1D tex;\n"
+    "uniform mat4 matrix;\n"
+    "uniform vec2 segment;\n"
+    "uniform float first_offset;\n"
+    "uniform float last_offset;\n"
+    "\n"
+    "void main ()\n"
+    "{\n"
+    "    vec2 pos = (matrix * vec4 (gl_FragCoord.xy, 0.0, 1.0)).xy;\n"
+    "    float t = dot (pos, segment) / dot (segment, segment);\n"
+    "    t = (t - first_offset) / (last_offset - first_offset);\n"
+    "    gl_FragColor = texture1D (tex, t);\n"
+    "}\n";
+
+/* ARB_shader_objects / ARB_vertex_shader / ARB_fragment_shader extensions
+   API. */
+static cairo_status_t
+compile_shader_arb (GLuint *shader, GLenum type, const char *text)
+{
+    const char* strings[1] = { text };
+    GLint gl_status;
+
+    *shader = glCreateShaderObjectARB (type);
+    glShaderSourceARB (*shader, 1, strings, 0);
+    glCompileShaderARB (*shader);
+    glGetObjectParameterivARB (*shader, GL_OBJECT_COMPILE_STATUS_ARB,
&gl_status);
+    if (gl_status == GL_FALSE) {
+        GLint log_size;
+        glGetObjectParameterivARB (*shader,
GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_size);
+        if (0 < log_size) {
+            char *log = _cairo_malloc (log_size);
+            GLint chars;
+
+            log[log_size - 1] = '\0';
+            glGetInfoLogARB (*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");
+        }
+
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+link_shader_arb (GLuint *program, GLuint vert, GLuint frag)
+{
+    GLint gl_status;
+
+    *program = glCreateProgramObjectARB ();
+    glAttachObjectARB (*program, vert);
+    glAttachObjectARB (*program, frag);
+    glLinkProgramARB (*program);
+    glGetObjectParameterivARB (*program, GL_OBJECT_LINK_STATUS_ARB,
&gl_status);
+    if (gl_status == GL_FALSE) {
+        GLint log_size;
+        glGetObjectParameterivARB (*program,
GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_size);
+        if (0 < log_size) {
+            char *log = _cairo_malloc (log_size);
+            GLint chars;
+
+            log[log_size - 1] = '\0';
+            glGetInfoLogARB (*program, log_size, &chars, log);
+            printf ("OpenGL shader link failed:\n%s\n", log);
+
+            free (log);
+        } else {
+            printf ("OpenGL shader link failed.\n");
+        }
+
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+destroy_shader_program_arb (cairo_gl_shader_program_t *program)
+{
+    if (program->vertex_shader)
+        glDeleteObjectARB (program->vertex_shader);
+    if (program->fragment_shader)
+        glDeleteObjectARB (program->fragment_shader);
+    if (program->program)
+        glDeleteObjectARB (program->program);
+}
+
+static cairo_status_t
+create_linear_gradient_shader_program_arb (cairo_gl_shader_program_t *program)
+{
+    return create_shader_program (program,
+                                  minimal_vert_text_110,
+                                  linear_gradient_frag_text_110);
+}
+
+static cairo_status_t
+create_radial_gradient_shader_program_arb (cairo_gl_shader_program_t *program)
+{
+    return create_shader_program (program,
+                                  minimal_vert_text_110,
+                                  radial_gradient_frag_text_110);
+}
+
+static cairo_status_t
+bind_float_to_shader_arb (GLuint program, const char *name,
+                               float value)
+{
+    GLint location = glGetUniformLocationARB (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform1fARB (location, value);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_vec2_to_shader_arb (GLuint program, const char *name,
+                              float value0, float value1)
+{
+    GLint location = glGetUniformLocationARB (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform2fARB (location, value0, value1);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_vec3_to_shader_arb (GLuint program, const char *name,
+                              float value0, float value1,
+                              float value2)
+{
+    GLint location = glGetUniformLocationARB (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform3fARB (location, value0, value1, value2);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_vec4_to_shader_arb (GLuint program, const char *name,
+                              float value0, float value1,
+                              float value2, float value3)
+{
+    GLint location = glGetUniformLocationARB (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform4fARB (location, value0, value1, value2, value3);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_matrix_to_shader_arb (GLuint program, const char *name, cairo_matrix_t* m)
+{
+    GLint location = glGetUniformLocationARB (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    float gl_m[16] = {
+        m->xx, m->xy, 0,     m->x0,
+        m->yx, m->yy, 0,     m->y0,
+        0,     0,     1,     0,
+        0,     0,     0,     1
+    };
+    glUniformMatrix4fvARB (location, 1, GL_TRUE, gl_m);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_texture_to_shader_arb (GLuint program, const char *name, GLuint tex_unit)
+{
+    GLint location = glGetUniformLocationARB (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform1iARB (location, tex_unit);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static GLenum
+vertex_enumerator_arb (void)
+{
+    return GL_VERTEX_SHADER_ARB;
+}
+
+static GLenum
+fragment_enumerator_arb (void)
+{
+    return GL_FRAGMENT_SHADER_ARB;
+}
+
+/* OpenGL Core 2.0 API. */
+static cairo_status_t
+compile_shader_core_2_0 (GLuint *shader, GLenum type, const char *text)
+{
+    const char* strings[1] = { text };
+    GLint gl_status;
+
+    *shader = glCreateShader (type);
+    glShaderSource (*shader, 1, strings, 0);
+    glCompileShader (*shader);
+    glGetShaderiv (*shader, GL_COMPILE_STATUS, &gl_status);
+    if (gl_status == GL_FALSE) {
+        GLint log_size;
+        glGetShaderiv (*shader, GL_INFO_LOG_LENGTH, &log_size);
+        if (0 < log_size) {
+            char *log = _cairo_malloc (log_size);
+            GLint chars;
+
+            log[log_size - 1] = '\0';
+            glGetShaderInfoLog (*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");
+        }
+
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+link_shader_core_2_0 (GLuint *program, GLuint vert, GLuint frag)
+{
+    GLint gl_status;
+
+    *program = glCreateProgram ();
+    glAttachShader (*program, vert);
+    glAttachShader (*program, frag);
+    glLinkProgram (*program);
+    glGetProgramiv (*program, GL_LINK_STATUS, &gl_status);
+    if (gl_status == GL_FALSE) {
+        GLint log_size;
+        glGetProgramiv (*program, GL_INFO_LOG_LENGTH, &log_size);
+        if (0 < log_size) {
+            char *log = _cairo_malloc (log_size);
+            GLint chars;
+
+            log[log_size - 1] = '\0';
+            glGetProgramInfoLog (*program, log_size, &chars, log);
+            printf ("OpenGL shader link failed:\n%s\n", log);
+
+            free (log);
+        } else {
+            printf ("OpenGL shader link failed.\n");
+        }
+
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+destroy_shader_program_core_2_0 (cairo_gl_shader_program_t *program)
+{
+    glDeleteShader (program->vertex_shader);
+    glDeleteShader (program->fragment_shader);
+    glDeleteProgram (program->program);
+}
+
+static cairo_status_t
+create_linear_gradient_shader_program_core_2_0
(cairo_gl_shader_program_t *program)
+{
+    return create_shader_program (program,
+                                  minimal_vert_text_110,
+                                  linear_gradient_frag_text_110);
+}
+
+static cairo_status_t
+create_radial_gradient_shader_program_core_2_0
(cairo_gl_shader_program_t *program)
+{
+    return create_shader_program (program,
+                                  minimal_vert_text_110,
+                                  radial_gradient_frag_text_110);
+}
+
+static cairo_status_t
+bind_float_to_shader_core_2_0 (GLuint program, const char *name,
+                               float value)
+{
+    GLint location = glGetUniformLocation (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform1f (location, value);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_vec2_to_shader_core_2_0 (GLuint program, const char *name,
+                              float value0, float value1)
+{
+    GLint location = glGetUniformLocation (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform2f (location, value0, value1);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_vec3_to_shader_core_2_0 (GLuint program, const char *name,
+                              float value0, float value1,
+                              float value2)
+{
+    GLint location = glGetUniformLocation (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform3f (location, value0, value1, value2);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_vec4_to_shader_core_2_0 (GLuint program, const char *name,
+                              float value0, float value1,
+                              float value2, float value3)
+{
+    GLint location = glGetUniformLocation (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform4f (location, value0, value1, value2, value3);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_matrix_to_shader_core_2_0 (GLuint program, const char *name,
cairo_matrix_t* m)
+{
+    GLint location = glGetUniformLocation (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    float gl_m[16] = {
+        m->xx, m->xy, 0,     m->x0,
+        m->yx, m->yy, 0,     m->y0,
+        0,     0,     1,     0,
+        0,     0,     0,     1
+    };
+    glUniformMatrix4fv (location, 1, GL_TRUE, gl_m);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+bind_texture_to_shader_core_2_0 (GLuint program, const char *name,
GLuint tex_unit)
+{
+    GLint location = glGetUniformLocation (program, name);
+    if (location == -1)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    glUniform1i (location, tex_unit);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static GLenum
+vertex_enumerator_core_2_0 (void)
+{
+    return GL_VERTEX_SHADER;
+}
+
+static GLenum
+fragment_enumerator_core_2_0 (void)
+{
+    return GL_FRAGMENT_SHADER;
+}
+
+#define SHADER_IMPL_DECL(x)                                             \
+    static const shader_impl_t shader_impl_ ## x = {                    \
+        compile_shader_ ## x,                                           \
+        link_shader_ ## x,                                              \
+        destroy_shader_program_ ## x,                                   \
+        create_linear_gradient_shader_program_ ## x,                    \
+        create_radial_gradient_shader_program_ ## x,                    \
+        bind_float_to_shader_ ## x,                                     \
+        bind_vec2_to_shader_ ## x,                                      \
+        bind_vec3_to_shader_ ## x,                                      \
+        bind_vec4_to_shader_ ## x,                                      \
+        bind_matrix_to_shader_ ## x,                                    \
+        bind_texture_to_shader_ ## x,                                   \
+        vertex_enumerator_ ## x,                                        \
+        fragment_enumerator_ ## x                                       \
+    }
+
+SHADER_IMPL_DECL(core_2_0);
+SHADER_IMPL_DECL(arb);
+
+#undef SHADER_IMPL_DECL
+
+static const shader_impl_t*
+get_impl (void)
+{
+    if (GLEW_VERSION_2_0) {
+        return &shader_impl_core_2_0;
+    } else if (GLEW_ARB_shader_objects &&
+               GLEW_ARB_fragment_shader &&
+               GLEW_ARB_vertex_program) {
+        return &shader_impl_arb;
+    }
+
+    ASSERT_NOT_REACHED;
+    return NULL;
+}
+
+void
+init_shader_program (cairo_gl_shader_program_t *program)
+{
+    program->vertex_shader = 0;
+    program->fragment_shader = 0;
+    program->program = 0;
+    program->build_failure = FALSE;
+}
+
+void
+destroy_shader_program (cairo_gl_shader_program_t *program)
+{
+    return get_impl()->destroy_shader_program(program);
+}
+
+cairo_status_t
+create_shader_program (cairo_gl_shader_program_t *program,
+                       const char *vertex_text,
+                       const char *fragment_text)
+{
+    cairo_status_t status;
+
+    if (program->program != 0)
+        return CAIRO_STATUS_SUCCESS;
+
+    if (program->build_failure)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = get_impl()->compile_shader (&program->vertex_shader,
+                                         get_impl()->vertex_enumerator(),
+                                         vertex_text);
+    if (unlikely (status))
+        goto FAILURE;
+
+    status = get_impl()->compile_shader (&program->fragment_shader,
+                                         get_impl()->fragment_enumerator(),
+                                         fragment_text);
+    if (unlikely (status))
+        goto FAILURE;
+
+    status = get_impl()->link_shader (&program->program,
+                                      program->vertex_shader,
+                                      program->fragment_shader);
+    if (unlikely (status))
+        goto FAILURE;
+
+    return CAIRO_STATUS_SUCCESS;
+
+ FAILURE:
+    destroy_shader_program (program);
+    program->vertex_shader = 0;
+    program->fragment_shader = 0;
+    program->program = 0;
+    program->build_failure = TRUE;
+
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_status_t
+create_linear_gradient_shader_program (cairo_gl_shader_program_t *program)
+{
+    return get_impl()->create_linear_gradient_shader_program(program);
+}
+
+cairo_status_t
+create_radial_gradient_shader_program (cairo_gl_shader_program_t *program)
+{
+    return get_impl()->create_radial_gradient_shader_program(program);
+}
+
+cairo_status_t
+bind_float_to_shader (GLuint program, const char *name,
+                      float value)
+{
+    return get_impl()->bind_float_to_shader(program, name, value);
+}
+
+cairo_status_t
+bind_vec2_to_shader (GLuint program, const char *name,
+                     float value0, float value1)
+{
+    return get_impl()->bind_vec2_to_shader(program, name, value0, value1);
+}
+
+cairo_status_t
+bind_vec3_to_shader (GLuint program, const char *name,
+                     float value0, float value1,
+                     float value2)
+{
+    return get_impl()->bind_vec3_to_shader(program, name, value0,
value1, value2);
+}
+
+cairo_status_t
+bind_vec4_to_shader (GLuint program, const char *name,
+                     float value0, float value1,
+                     float value2, float value3)
+{
+    return get_impl()->bind_vec4_to_shader(program, name, value0,
value1, value2, value3);
+}
+
+cairo_status_t
+bind_matrix_to_shader (GLuint program, const char *name, cairo_matrix_t* m)
+{
+    return get_impl()->bind_matrix_to_shader(program, name, m);
+}
+
+cairo_status_t
+bind_texture_to_shader (GLuint program, const char *name, GLuint tex_unit)
+{
+    return get_impl()->bind_texture_to_shader(program, name, tex_unit);
+}


More information about the cairo mailing list