summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2009-10-20 14:01:32 -0700
committerCarl Worth <cworth@cworth.org>2009-10-20 14:01:32 -0700
commitef74dd0668e5cc3df5e62ec56955ad96c4ff159a (patch)
treed786761136c4adb3932022f2658877ac8f88e2c0
parent3f091e92e528a6137267b21f948b416fa0fe0aa4 (diff)
cairo-gl: Add first baby step toward using GLSL in cairo-gl backend.glsl
This implements only the fill_rectangles call so far, and introduces tons of new fallbacks with warnings printed on stderr. Thanks to Eric Anholt and his work on Glamor in the X server for the code here.
-rw-r--r--src/Makefile.sources4
-rw-r--r--src/cairo-gl-private.h3
-rw-r--r--src/cairo-gl-surface.c24
-rw-r--r--src/cairo-glsl-private.h70
-rw-r--r--src/cairo-glsl.c257
-rw-r--r--src/cairo.h2
6 files changed, 358 insertions, 2 deletions
diff --git a/src/Makefile.sources b/src/Makefile.sources
index df958881..abe32628 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -278,8 +278,8 @@ cairo_beos_headers = cairo-beos.h
#cairo_beos_sources = cairo-beos-surface.cpp
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_private = cairo-gl-private.h cairo-glsl-private.h
+cairo_gl_sources = cairo-gl-surface.c cairo-gl-glyphs.c cairo-glsl.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 9c8f901b..876b6fbf 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -45,6 +45,7 @@
#include <GL/glew.h>
#include "cairo-gl.h"
+#include "cairo-glsl-private.h"
#include <GL/gl.h>
#define GL_GLEXT_PROTOTYPES
@@ -92,6 +93,8 @@ struct _cairo_gl_context {
cairo_gl_surface_t *current_target;
cairo_gl_glyph_cache_t glyph_cache[2];
+ cairo_glsl_shaders_t shaders;
+
void (*make_current)(void *ctx, cairo_gl_surface_t *surface);
void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface);
void (*destroy) (void *ctx);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index ec8a1521..35c44933 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -123,6 +123,8 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
_cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
+ _cairo_glsl_shaders_init (&ctx->shaders);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -304,6 +306,10 @@ _cairo_gl_context_release (cairo_gl_context_t *ctx)
CAIRO_MUTEX_UNLOCK (ctx->mutex);
}
+/* XXX: glamor's set_destination_pixmap does no more than
+ * glBindFramebufferEXT and glViewport here. Why do we do more?
+ * Is it because glamor has a separate glamor_set_transform_for_pixmap?
+ */
void
_cairo_gl_set_destination (cairo_gl_surface_t *surface)
{
@@ -1122,6 +1128,15 @@ _cairo_gl_operand_init (cairo_gl_composite_operand_t *operand,
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_gl_solid_operand_init (operand,
&((cairo_solid_pattern_t *) pattern)->color);
+ /* GLSL-only */
+ CAIRO_PATTERN_TYPE_SURFACE:
+ CAIRO_PATTERN_TYPE_LINEAR:
+ CAIRO_PATTERN_TYPE_RADIAL:
+ default:
+ fprintf (stderr, "WARNING: cairo-glsl doesn't support non-solid patterns yet. Falling back.\n");
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+#if 0
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
{
@@ -1170,6 +1185,7 @@ _cairo_gl_operand_init (cairo_gl_composite_operand_t *operand,
dst_x, dst_y,
width, height);
}
+#endif
}
void
@@ -1306,6 +1322,12 @@ _cairo_gl_surface_composite (cairo_operator_t op,
return status;
src_attributes = &setup.src.operand.texture.attributes;
+ /* GLSL-only */
+ if (mask != NULL) {
+ fprintf (stderr, "Warning: cairo-glsl doesn't support composite with a mask yet. Falling back.\n");
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
if (mask != NULL && _cairo_pattern_is_opaque (mask))
mask = NULL;
@@ -1538,6 +1560,8 @@ _cairo_gl_surface_fill_rectangles (void *abstract_surface,
GLfloat *vertices;
GLfloat *colors;
+ return _cairo_glsl_fill_rectangles (abstract_surface, op, color, rects, num_rects);
+
if (! _cairo_gl_operator_is_supported (op))
return CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/cairo-glsl-private.h b/src/cairo-glsl-private.h
new file mode 100644
index 00000000..9f80cc2a
--- /dev/null
+++ b/src/cairo-glsl-private.h
@@ -0,0 +1,70 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Intel corporation
+ *
+ * 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 Intel corporation.
+ *
+ * Contributor(s):
+ * Carl Worth <cworth@cworth.org>
+ */
+
+#ifndef CAIRO_GLSL_PRIVATE_H
+#define CAIRO_GLSL_PRIVATE_H
+
+#include "cairoint.h"
+
+#include <GL/glew.h>
+
+typedef struct _cairo_glsl_transform_uniforms {
+ GLint x_bias;
+ GLint x_scale;
+ GLint y_bias;
+ GLint y_scale;
+} cairo_glsl_transform_uniforms_t;
+
+typedef struct _cairo_glsl_shader_solid {
+ GLint prog;
+ GLint color_uniform_location;
+ cairo_glsl_transform_uniforms_t uniforms;
+} cairo_glsl_shader_solid_t;
+
+typedef struct _cairo_glsl_shaders {
+ cairo_glsl_shader_solid_t solid;
+} cairo_glsl_shaders_t;
+
+void
+_cairo_glsl_shaders_init (cairo_glsl_shaders_t *shaders);
+
+cairo_int_status_t
+_cairo_glsl_fill_rectangles (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_color_t *cairo_color,
+ cairo_rectangle_int_t *rects,
+ int num_rects);
+
+#endif /* CAIRO_GLSL_PRIVATE_H */
diff --git a/src/cairo-glsl.c b/src/cairo-glsl.c
new file mode 100644
index 00000000..49ff01dc
--- /dev/null
+++ b/src/cairo-glsl.c
@@ -0,0 +1,257 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008,2009 Intel Corporation
+ *
+ * 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 Intel Corporation.
+ *
+ * Contributor(s):
+ * Eric Anholt <eric@anholt.net>
+ * Carl Worth <cworth@cworth.org>
+ */
+
+#include "cairo-glsl-private.h"
+#include "cairo-gl-private.h"
+
+static void
+_cairo_glsl_transform_uniforms_init (cairo_glsl_transform_uniforms_t *uniforms,
+ GLint prog)
+{
+ uniforms->x_bias = glGetUniformLocationARB (prog, "x_bias");
+ uniforms->x_scale = glGetUniformLocationARB (prog, "x_scale");
+ uniforms->y_bias = glGetUniformLocationARB (prog, "y_bias");
+ uniforms->y_scale = glGetUniformLocationARB (prog, "y_scale");
+}
+
+/* We don't use a full matrix for our transformations because it's
+ * wasteful when all we want is to rescale to NDC and possibly do a flip
+ * if it's the front buffer.
+ */
+static void
+_cairo_glsl_transform_uniforms_set_for_surface (cairo_glsl_transform_uniforms_t *uniforms,
+ cairo_gl_surface_t *surface)
+{
+ int onscreen = (surface->fb == 0);
+
+ glUniform1fARB (uniforms->x_bias, -surface->width / 2.0f);
+ glUniform1fARB (uniforms->x_scale, 2.0f / surface->width);
+ glUniform1fARB (uniforms->y_bias, -surface->height / 2.0f);
+
+ if (onscreen)
+ glUniform1fARB(uniforms->y_scale,
+ -2.0f / surface->height);
+ else
+ glUniform1fARB(uniforms->y_scale,
+ 2.0f / surface->height);
+}
+
+static cairo_status_t
+_cairo_glsl_link (GLint prog)
+{
+ GLint ok;
+
+ glLinkProgram (prog);
+
+ glGetObjectParameterivARB (prog, GL_OBJECT_LINK_STATUS_ARB, &ok);
+ if (!ok) {
+#if CAIRO_DEBUG_GLSL
+ GLchar *info;
+ GLint size;
+
+ glGetObjectParameterivARB (prog, GL_OBJECT_INFO_LOG_LENGTH_ARB, &size);
+ info = malloc (size);
+
+ glGetInfoLogARB (prog, size, NULL, info);
+ fprintf (stderr, "Failed to link: %s\n", info);
+#endif
+ return CAIRO_STATUS_GLSL_PROGRAM_ERROR;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_glsl_compile (GLenum type, const char *source, GLint *prog_ret)
+{
+ GLint ok;
+ GLint prog;
+
+ prog = glCreateShaderObjectARB (type);
+ glShaderSourceARB (prog, 1, (const GLchar **)&source, NULL);
+ glCompileShaderARB (prog);
+
+ glGetObjectParameterivARB (prog, GL_OBJECT_COMPILE_STATUS_ARB, &ok);
+ if (!ok) {
+#if CAIRO_DEBUG_GLSL
+ GLchar *info;
+ GLint size;
+
+ glGetObjectParameterivARB (prog, GL_OBJECT_INFO_LOG_LENGTH_ARB, &size);
+ info = malloc (size);
+
+ glGetInfoLogARB (prog, size, NULL, info);
+ fprintf (stderr, "Failed to compile %s: %s\n",
+ type == GL_FRAGMENT_SHADER ? "FS" : "VS",
+ info);
+ fprintf (stderr, "Program source:\n%s", source);
+#endif
+ return CAIRO_STATUS_GLSL_PROGRAM_ERROR;
+ }
+
+ *prog_ret = prog;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_glsl_shader_solid_init (cairo_glsl_shader_solid_t *solid)
+{
+ cairo_status_t status;
+
+ const char *solid_vs_only =
+ "uniform vec4 color;\n"
+ "uniform float x_bias;\n"
+ "uniform float x_scale;\n"
+ "uniform float y_bias;\n"
+ "uniform float y_scale;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4((gl_Vertex.x + x_bias) * x_scale,\n"
+ " (gl_Vertex.y + y_bias) * y_scale,\n"
+ " 0,\n"
+ " 1);\n"
+ " gl_Color = color;\n"
+ "}\n";
+ const char *solid_vs =
+ "uniform float x_bias;\n"
+ "uniform float x_scale;\n"
+ "uniform float y_bias;\n"
+ "uniform float y_scale;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4((gl_Vertex.x + x_bias) * x_scale,\n"
+ " (gl_Vertex.y + y_bias) * y_scale,\n"
+ " 0,\n"
+ " 1);\n"
+ "}\n";
+ const char *solid_fs =
+ "uniform vec4 color;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+ GLint fs_prog, vs_prog;
+
+ solid->prog = glCreateProgramObjectARB ();
+ if (GLEW_ARB_fragment_shader) {
+ status = _cairo_glsl_compile (GL_VERTEX_SHADER_ARB,
+ solid_vs, &vs_prog);
+ if (status)
+ return status;
+
+ status = _cairo_glsl_compile (GL_FRAGMENT_SHADER_ARB,
+ solid_fs, &fs_prog);
+ if (status)
+ return status;
+
+ glAttachObjectARB (solid->prog, vs_prog);
+ glAttachObjectARB (solid->prog, fs_prog);
+ } else {
+ status = _cairo_glsl_compile (GL_VERTEX_SHADER_ARB,
+ solid_vs_only, &vs_prog);
+ if (status)
+ return status;
+
+ glAttachObjectARB (solid->prog, vs_prog);
+ }
+ status = _cairo_glsl_link (solid->prog);
+ if (status)
+ return status;
+
+ solid->color_uniform_location =
+ glGetUniformLocationARB (solid->prog, "color");
+ _cairo_glsl_transform_uniforms_init (&solid->uniforms, solid->prog);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_glsl_shaders_init (cairo_glsl_shaders_t *shaders)
+{
+ _cairo_glsl_shader_solid_init (&shaders->solid);
+}
+
+cairo_int_status_t
+_cairo_glsl_fill_rectangles (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_color_t *cairo_color,
+ cairo_rectangle_int_t *rects,
+ int num_rects)
+{
+ cairo_gl_surface_t *surface = abstract_surface;
+ cairo_gl_context_t *ctx;
+ cairo_glsl_shader_solid_t *solid;
+ GLfloat gl_color[4];
+ int i;
+
+ if (! _cairo_gl_operator_is_supported (op))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ ctx = _cairo_gl_context_acquire (surface->ctx);
+ solid = &ctx->shaders.solid;
+
+ _cairo_gl_set_destination (surface);
+ _cairo_gl_set_operator (surface, op);
+
+ glUseProgramObjectARB (solid->prog);
+
+ gl_color[0] = cairo_color->red * cairo_color->alpha;
+ gl_color[1] = cairo_color->green * cairo_color->alpha;
+ gl_color[2] = cairo_color->blue * cairo_color->alpha;
+ gl_color[3] = cairo_color->alpha;
+
+ glUniform4fvARB (solid->color_uniform_location, 1, gl_color);
+
+ _cairo_glsl_transform_uniforms_set_for_surface (&solid->uniforms,
+ surface);
+
+ glBegin (GL_TRIANGLES);
+ for (i = 0; i < num_rects; i++) {
+ glVertex2f (rects[i].x, rects[i].y);
+ glVertex2f (rects[i].x + rects[i].width, rects[i].y);
+ glVertex2f (rects[i].x + rects[i].width, rects[i].y + rects[i].height);
+ glVertex2f (rects[i].x, rects[i].y);
+ glVertex2f (rects[i].x, rects[i].y + rects[i].height);
+ glVertex2f (rects[i].x + rects[i].width, rects[i].y + rects[i].height);
+ }
+ glEnd();
+
+ glUseProgramObjectARB (0);
+
+ _cairo_gl_context_release (ctx);
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo.h b/src/cairo.h
index 3b5eb36e..aa6fb401 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -241,6 +241,7 @@ typedef struct _cairo_user_data_key {
* @CAIRO_STATUS_INVALID_WEIGHT: invalid value for an input #cairo_font_weight_t (Since 1.8)
* @CAIRO_STATUS_INVALID_SIZE: invalid value (typically too big) for the size of the input (surface, pattern, etc.) (Since 1.10)
* @CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: user-font method not implemented (Since 1.10)
+ * @CAIRO_STATUS_GLSL_PROGRAM_ERROR: a GLSL shader failed to compile link (Since 1.10)
* @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of
* status values defined in this enumeration. When using this value, note
* that the version of cairo at run-time may have additional status values
@@ -290,6 +291,7 @@ typedef enum _cairo_status {
CAIRO_STATUS_INVALID_WEIGHT,
CAIRO_STATUS_INVALID_SIZE,
CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED,
+ CAIRO_STATUS_GLSL_PROGRAM_ERROR,
CAIRO_STATUS_LAST_STATUS
} cairo_status_t;