diff options
author | Carl Worth <cworth@cworth.org> | 2009-10-20 14:01:32 -0700 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2009-10-20 14:01:32 -0700 |
commit | ef74dd0668e5cc3df5e62ec56955ad96c4ff159a (patch) | |
tree | d786761136c4adb3932022f2658877ac8f88e2c0 | |
parent | 3f091e92e528a6137267b21f948b416fa0fe0aa4 (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.sources | 4 | ||||
-rw-r--r-- | src/cairo-gl-private.h | 3 | ||||
-rw-r--r-- | src/cairo-gl-surface.c | 24 | ||||
-rw-r--r-- | src/cairo-glsl-private.h | 70 | ||||
-rw-r--r-- | src/cairo-glsl.c | 257 | ||||
-rw-r--r-- | src/cairo.h | 2 |
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; |