1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 T. Zachary Laine
4 * Copyright © 2010 Eric Anholt
5 * Copyright © 2010 Red Hat, Inc
6 * Copyright © 2010 Linaro Limited
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is T. Zachary Laine.
36 * Benjamin Otte <otte@gnome.org>
37 * Eric Anholt <eric@anholt.net>
38 * T. Zachary Laine <whatwasthataddress@gmail.com>
39 * Alexandros Frantzis <alexandros.frantzis@linaro.org>
43 #include "cairo-gl-private.h"
44 #include "cairo-error-private.h"
45 #include "cairo-output-stream-private.h"
47 typedef struct cairo_gl_shader_impl {
49 (*compile_shader) (cairo_gl_context_t *ctx, GLuint *shader, GLenum type,
53 (*link_shader) (cairo_gl_context_t *ctx, GLuint *program, GLuint vert, GLuint frag);
56 (*destroy_shader) (cairo_gl_context_t *ctx, GLuint shader);
59 (*destroy_program) (cairo_gl_context_t *ctx, GLuint program);
62 (*bind_float) (cairo_gl_context_t *ctx,
63 cairo_gl_shader_t *shader,
68 (*bind_vec2) (cairo_gl_context_t *ctx,
69 cairo_gl_shader_t *shader,
75 (*bind_vec3) (cairo_gl_context_t *ctx,
76 cairo_gl_shader_t *shader,
83 (*bind_vec4) (cairo_gl_context_t *ctx,
84 cairo_gl_shader_t *shader,
86 float value0, float value1,
87 float value2, float value3);
90 (*bind_matrix) (cairo_gl_context_t *ctx,
91 cairo_gl_shader_t *shader,
96 (*bind_matrix4f) (cairo_gl_context_t *ctx,
97 cairo_gl_shader_t *shader,
102 (*use) (cairo_gl_context_t *ctx,
103 cairo_gl_shader_t *shader);
106 static cairo_status_t
107 _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
108 cairo_gl_shader_t *shader,
109 cairo_gl_operand_t *src,
110 cairo_gl_operand_t *mask,
111 cairo_bool_t use_coverage,
112 const char *fragment_text);
114 /* OpenGL Core 2.0 API. */
116 compile_shader_core_2_0 (cairo_gl_context_t *ctx, GLuint *shader,
117 GLenum type, const char *text)
119 const char* strings[1] = { text };
121 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
123 *shader = dispatch->CreateShader (type);
124 dispatch->ShaderSource (*shader, 1, strings, 0);
125 dispatch->CompileShader (*shader);
126 dispatch->GetShaderiv (*shader, GL_COMPILE_STATUS, &gl_status);
127 if (gl_status == GL_FALSE) {
129 dispatch->GetShaderiv (*shader, GL_INFO_LOG_LENGTH, &log_size);
131 char *log = _cairo_malloc (log_size);
134 log[log_size - 1] = '\0';
135 dispatch->GetShaderInfoLog (*shader, log_size, &chars, log);
136 printf ("OpenGL shader compilation failed. Shader:\n"
138 "OpenGL compilation log:\n"
144 printf ("OpenGL shader compilation failed.\n");
152 link_shader_core_2_0 (cairo_gl_context_t *ctx, GLuint *program,
153 GLuint vert, GLuint frag)
156 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
158 *program = dispatch->CreateProgram ();
159 dispatch->AttachShader (*program, vert);
160 dispatch->AttachShader (*program, frag);
162 dispatch->BindAttribLocation (*program, CAIRO_GL_VERTEX_ATTRIB_INDEX,
164 dispatch->BindAttribLocation (*program, CAIRO_GL_COLOR_ATTRIB_INDEX,
166 dispatch->BindAttribLocation (*program, CAIRO_GL_COVERAGE_ATTRIB_INDEX,
168 dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD0_ATTRIB_INDEX,
170 dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD1_ATTRIB_INDEX,
172 dispatch->BindAttribLocation (*program, CAIRO_GL_START_COORD0_ATTRIB_INDEX,
174 dispatch->BindAttribLocation (*program, CAIRO_GL_START_COORD1_ATTRIB_INDEX,
176 dispatch->BindAttribLocation (*program, CAIRO_GL_STOP_COORD0_ATTRIB_INDEX,
178 dispatch->BindAttribLocation (*program, CAIRO_GL_STOP_COORD1_ATTRIB_INDEX,
181 dispatch->LinkProgram (*program);
182 dispatch->GetProgramiv (*program, GL_LINK_STATUS, &gl_status);
183 if (gl_status == GL_FALSE) {
185 dispatch->GetProgramiv (*program, GL_INFO_LOG_LENGTH, &log_size);
187 char *log = _cairo_malloc (log_size);
190 log[log_size - 1] = '\0';
191 dispatch->GetProgramInfoLog (*program, log_size, &chars, log);
192 printf ("OpenGL shader link failed:\n%s\n", log);
196 printf ("OpenGL shader link failed.\n");
204 destroy_shader_core_2_0 (cairo_gl_context_t *ctx, GLuint shader)
206 ctx->dispatch.DeleteShader (shader);
210 destroy_program_core_2_0 (cairo_gl_context_t *ctx, GLuint shader)
212 ctx->dispatch.DeleteProgram (shader);
215 typedef struct _cairo_gl_uniform_entry {
216 cairo_hash_entry_t base;
219 } cairo_gl_uniform_entry_t;
222 _cairo_gl_uniform_init_key (cairo_gl_uniform_entry_t *key,
225 unsigned long sum = 0;
228 for (i = 0; i < strlen(name); i++)
230 key->base.hash = sum;
231 key->name = strdup(name);
235 static cairo_status_t
236 create_gl_uniform_entry (const char *name,
237 cairo_gl_uniform_entry_t **entry)
239 *entry = malloc (sizeof (cairo_gl_uniform_entry_t));
240 if (unlikely (*entry == NULL))
241 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
243 _cairo_gl_uniform_init_key (*entry, name);
244 return CAIRO_STATUS_SUCCESS;
249 _cairo_gl_uniform_equal (const void *key_a,
252 const cairo_gl_uniform_entry_t *a = key_a;
253 const cairo_gl_uniform_entry_t *b = key_b;
255 return strcmp (a->name, b->name) == 0;
258 static cairo_int_status_t
259 get_uniform_location (cairo_gl_context_t *ctx,
260 cairo_gl_shader_t *shader,
264 cairo_gl_uniform_entry_t *key, *uniform_entry;
265 cairo_int_status_t status;
267 status = create_gl_uniform_entry (name, &key);
271 //_cairo_gl_uniform_init_key (key, name);
272 uniform_entry = _cairo_hash_table_lookup (shader->uniform_cache,
275 *location = uniform_entry->location;
278 return CAIRO_INT_STATUS_SUCCESS;
281 key->location = ctx->dispatch.GetUniformLocation (shader->program, name);
282 status = _cairo_hash_table_insert (shader->uniform_cache, &key->base);
283 *location = key->location;
288 static cairo_int_status_t
289 bind_float_core_2_0 (cairo_gl_context_t *ctx,
290 cairo_gl_shader_t *shader,
294 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
296 cairo_int_status_t status;
298 status = get_uniform_location (ctx, shader, name, &location);
302 assert(location != -1);
303 dispatch->Uniform1f (location, value);
304 return CAIRO_INT_STATUS_SUCCESS;
307 static cairo_int_status_t
308 bind_vec2_core_2_0 (cairo_gl_context_t *ctx,
309 cairo_gl_shader_t *shader,
314 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
316 cairo_int_status_t status;
318 status = get_uniform_location (ctx, shader, name, &location);
322 assert(location != -1);
323 dispatch->Uniform2f (location, value0, value1);
324 return CAIRO_INT_STATUS_SUCCESS;
327 static cairo_int_status_t
328 bind_vec3_core_2_0 (cairo_gl_context_t *ctx,
329 cairo_gl_shader_t *shader,
335 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
337 cairo_int_status_t status;
339 status = get_uniform_location (ctx, shader, name, &location);
343 assert(location != -1);
344 dispatch->Uniform3f (location, value0, value1, value2);
345 return CAIRO_INT_STATUS_SUCCESS;
348 static cairo_int_status_t
349 bind_vec4_core_2_0 (cairo_gl_context_t *ctx,
350 cairo_gl_shader_t *shader,
357 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
359 cairo_int_status_t status;
361 status = get_uniform_location (ctx, shader, name, &location);
365 assert(location != -1);
366 dispatch->Uniform4f (location, value0, value1, value2, value3);
367 return CAIRO_INT_STATUS_SUCCESS;
370 static cairo_int_status_t
371 bind_matrix_core_2_0 (cairo_gl_context_t *ctx,
372 cairo_gl_shader_t *shader,
376 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
378 cairo_int_status_t status;
385 status = get_uniform_location (ctx, shader, name, &location);
389 assert(location != -1);
390 dispatch->UniformMatrix3fv (location, 1, GL_TRUE, gl_m);
391 return CAIRO_INT_STATUS_SUCCESS;
394 static cairo_int_status_t
395 bind_matrix4f_core_2_0 (cairo_gl_context_t *ctx,
396 cairo_gl_shader_t *shader,
400 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
402 cairo_int_status_t status;
404 status = get_uniform_location (ctx, shader, name, &location);
408 assert(location != -1);
409 dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m);
410 return CAIRO_INT_STATUS_SUCCESS;
414 use_program_core_2_0 (cairo_gl_context_t *ctx,
415 cairo_gl_shader_t *shader)
418 ctx->dispatch.UseProgram (shader->program);
420 ctx->dispatch.UseProgram (0);
423 static const cairo_gl_shader_impl_t shader_impl_core_2_0 = {
424 compile_shader_core_2_0,
425 link_shader_core_2_0,
426 destroy_shader_core_2_0,
427 destroy_program_core_2_0,
432 bind_matrix_core_2_0,
433 bind_matrix4f_core_2_0,
434 use_program_core_2_0,
437 typedef struct _cairo_shader_cache_entry {
438 cairo_cache_entry_t base;
440 cairo_gl_operand_type_t src;
441 cairo_gl_operand_type_t mask;
442 cairo_gl_operand_type_t dest;
443 cairo_bool_t use_coverage;
444 cairo_bool_t use_color_attribute;
445 cairo_gl_shader_in_t in;
447 cairo_bool_t src_border_fade;
448 cairo_extend_t src_extend;
449 GLint mask_gl_filter;
450 cairo_bool_t mask_border_fade;
451 cairo_extend_t mask_extend;
453 cairo_bool_t src_use_atlas;
454 cairo_bool_t mask_use_atlas;
456 cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */
457 cairo_gl_shader_t shader;
458 } cairo_shader_cache_entry_t;
461 _cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b)
463 const cairo_shader_cache_entry_t *a = key_a;
464 const cairo_shader_cache_entry_t *b = key_b;
465 cairo_bool_t both_have_npot_repeat =
466 a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
468 return a->src == b->src &&
469 a->mask == b->mask &&
470 a->dest == b->dest &&
471 a->use_coverage == b->use_coverage &&
473 (both_have_npot_repeat || a->src_extend == b->src_extend) &&
474 (both_have_npot_repeat || a->mask_extend == b->mask_extend);
478 * For GLES2 we use more complicated shaders to implement missing GL
479 * features. In this case we need more parameters to uniquely identify
480 * a shader (vs _cairo_gl_shader_cache_equal_desktop()).
483 _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
485 const cairo_shader_cache_entry_t *a = key_a;
486 const cairo_shader_cache_entry_t *b = key_b;
487 cairo_bool_t both_have_npot_repeat =
488 a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
490 return a->src == b->src &&
491 a->mask == b->mask &&
492 a->dest == b->dest &&
493 a->use_coverage == b->use_coverage &&
495 a->src_gl_filter == b->src_gl_filter &&
496 a->src_border_fade == b->src_border_fade &&
497 (both_have_npot_repeat || a->src_extend == b->src_extend) &&
498 a->mask_gl_filter == b->mask_gl_filter &&
499 a->mask_border_fade == b->mask_border_fade &&
500 (both_have_npot_repeat || a->mask_extend == b->mask_extend);
504 _cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry)
506 return (entry->src << 16) | (entry->mask << 13) | (entry->dest << 10) | (entry->in << 8) | (entry->mask_extend << 6) | (entry->src_extend << 4) |(entry->mask_use_atlas << 3) | (entry->src_use_atlas << 2) |(entry->use_color_attribute << 1) | entry->use_coverage;
510 _cairo_gl_shader_cache_destroy (void *data)
512 cairo_shader_cache_entry_t *entry = data;
514 _cairo_gl_shader_fini (entry->ctx, &entry->shader);
515 if (entry->ctx->current_shader == &entry->shader)
516 entry->ctx->current_shader = NULL;
521 _cairo_gl_shader_init (cairo_gl_shader_t *shader)
523 shader->fragment_shader = 0;
525 shader->uniform_cache = _cairo_hash_table_create (_cairo_gl_uniform_equal);
529 _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
531 static const char *fill_fs_source =
533 "precision mediump float;\n"
535 "uniform vec4 color;\n"
538 " gl_FragColor = color;\n"
540 cairo_status_t status;
542 if (_cairo_gl_get_version () >= CAIRO_GL_VERSION_ENCODE (2, 0) ||
543 (_cairo_gl_has_extension ("GL_ARB_shader_objects") &&
544 _cairo_gl_has_extension ("GL_ARB_fragment_shader") &&
545 _cairo_gl_has_extension ("GL_ARB_vertex_shader")))
547 ctx->shader_impl = &shader_impl_core_2_0;
551 ctx->shader_impl = NULL;
552 fprintf (stderr, "Error: The cairo gl backend requires shader support!\n");
553 return CAIRO_STATUS_DEVICE_ERROR;
556 memset (ctx->vertex_shaders, 0, sizeof (ctx->vertex_shaders));
558 status = _cairo_cache_init (&ctx->shaders,
559 ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ?
560 _cairo_gl_shader_cache_equal_desktop :
561 _cairo_gl_shader_cache_equal_gles2,
563 _cairo_gl_shader_cache_destroy,
564 CAIRO_GL_MAX_SHADERS_PER_CONTEXT);
565 if (unlikely (status))
568 _cairo_gl_shader_init (&ctx->fill_rectangles_shader);
569 status = _cairo_gl_shader_compile (ctx,
570 &ctx->fill_rectangles_shader,
575 if (unlikely (status))
578 return CAIRO_STATUS_SUCCESS;
582 _cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx)
586 for (i = 0; i <= CAIRO_GL_VAR_TYPE_MAX; i++) {
587 if (ctx->vertex_shaders[i])
588 ctx->shader_impl->destroy_shader (ctx, ctx->vertex_shaders[i]);
591 _cairo_cache_fini (&ctx->shaders);
592 _cairo_gl_shader_fini (ctx, &ctx->fill_rectangles_shader);
596 destroy_uniform_callback (void *entry, void *closure)
598 cairo_gl_uniform_entry_t *key = entry;
599 _cairo_hash_table_remove ((cairo_hash_table_t *) closure, &key->base);
605 _cairo_gl_shader_fini (cairo_gl_context_t *ctx,
606 cairo_gl_shader_t *shader)
608 if (shader->fragment_shader)
609 ctx->shader_impl->destroy_shader (ctx, shader->fragment_shader);
612 ctx->shader_impl->destroy_program (ctx, shader->program);
614 if (shader->uniform_cache) {
615 _cairo_hash_table_foreach (shader->uniform_cache,
616 destroy_uniform_callback,
617 shader->uniform_cache);
618 _cairo_hash_table_destroy (shader->uniform_cache);
622 static const char *operand_names[] = { "source", "mask", "dest" };
624 static cairo_gl_var_type_t
625 cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type,
626 cairo_bool_t use_color_attribute)
630 case CAIRO_GL_OPERAND_COUNT:
632 case CAIRO_GL_OPERAND_NONE:
633 return CAIRO_GL_VAR_NONE;
634 case CAIRO_GL_OPERAND_CONSTANT:
635 if (use_color_attribute)
636 return CAIRO_GL_VAR_COLOR;
638 return CAIRO_GL_VAR_NONE;
639 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
640 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
641 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
642 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
643 case CAIRO_GL_OPERAND_TEXTURE:
644 return CAIRO_GL_VAR_TEXCOORDS;
649 cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
650 cairo_gl_var_type_t type,
652 cairo_bool_t use_atlas)
657 case CAIRO_GL_VAR_NONE:
659 case CAIRO_GL_VAR_COLOR:
660 _cairo_output_stream_printf (stream,
661 "varying vec4 fragment_color;\n");
663 case CAIRO_GL_VAR_TEXCOORDS:
664 _cairo_output_stream_printf (stream,
665 "varying vec2 %s_texcoords;\n",
666 operand_names[name]);
668 _cairo_output_stream_printf (stream,
669 "varying vec2 %s_start_coords;\n"
670 "varying vec2 %s_stop_coords;\n",
671 operand_names[name], operand_names[name]);
677 cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
678 cairo_gl_var_type_t type,
684 case CAIRO_GL_VAR_NONE:
686 case CAIRO_GL_VAR_COLOR:
687 _cairo_output_stream_printf (stream,
688 " fragment_color = Color;\n");
690 case CAIRO_GL_VAR_TEXCOORDS:
691 _cairo_output_stream_printf (stream,
692 " %s_texcoords = MultiTexCoord%d.xy;\n",
693 operand_names[name], name);
699 cairo_gl_shader_dcl_coverage (cairo_output_stream_t *stream)
701 _cairo_output_stream_printf (stream, "varying float coverage;\n");
705 cairo_gl_shader_def_coverage (cairo_output_stream_t *stream)
707 _cairo_output_stream_printf (stream, " coverage = Coverage.a;\n");
711 cairo_gl_shader_def_use_atlas (cairo_output_stream_t *stream,
712 cairo_gl_var_type_t type,
715 if (type == CAIRO_GL_VAR_TEXCOORDS) {
716 _cairo_output_stream_printf (stream,
717 " %s_start_coords = StartCoords%d.xy;\n"
718 " %s_stop_coords = StopCoords%d.xy;\n",
719 operand_names[name], name,
720 operand_names[name], name);
724 static cairo_status_t
725 cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src_type,
726 cairo_gl_var_type_t mask_type,
727 cairo_bool_t src_use_atlas,
728 cairo_bool_t mask_use_atlas,
729 cairo_bool_t use_coverage,
730 cairo_gl_var_type_t dest,
733 cairo_output_stream_t *stream = _cairo_memory_stream_create ();
734 unsigned char *source;
735 unsigned long length;
736 cairo_status_t status;
738 cairo_gl_shader_emit_variable (stream, src_type, CAIRO_GL_TEX_SOURCE,
740 cairo_gl_shader_emit_variable (stream, mask_type, CAIRO_GL_TEX_MASK,
743 cairo_gl_shader_dcl_coverage (stream);
745 _cairo_output_stream_printf (stream,
746 "attribute vec4 Vertex;\n"
747 "attribute vec4 Color;\n"
748 "attribute vec4 Coverage;\n"
749 "attribute vec4 MultiTexCoord0;\n"
750 "attribute vec4 MultiTexCoord1;\n"
751 "attribute vec2 StartCoords0;\n"
752 "attribute vec2 StartCoords1;\n"
753 "attribute vec2 StopCoords0;\n"
754 "attribute vec2 StopCoords1;\n"
755 "uniform mat4 ModelViewProjectionMatrix;\n"
758 " gl_Position = ModelViewProjectionMatrix * Vertex;\n");
760 cairo_gl_shader_emit_vertex (stream, src_type, CAIRO_GL_TEX_SOURCE);
761 cairo_gl_shader_emit_vertex (stream, mask_type, CAIRO_GL_TEX_MASK);
764 cairo_gl_shader_def_coverage (stream);
767 cairo_gl_shader_def_use_atlas (stream, src_type, CAIRO_GL_TEX_SOURCE);
769 cairo_gl_shader_def_use_atlas (stream, mask_type, CAIRO_GL_TEX_MASK);
771 _cairo_output_stream_write (stream,
774 status = _cairo_memory_stream_destroy (stream, &source, &length);
775 if (unlikely (status))
778 *out = (char *) source;
779 return CAIRO_STATUS_SUCCESS;
783 * Returns whether an operand needs a special border fade fragment shader
784 * to simulate the GL_CLAMP_TO_BORDER wrapping method that is missing in GLES2.
787 _cairo_gl_shader_needs_border_fade (cairo_gl_operand_t *operand)
789 cairo_extend_t extend =_cairo_gl_operand_get_extend (operand);
791 return extend == CAIRO_EXTEND_NONE &&
792 (operand->type == CAIRO_GL_OPERAND_TEXTURE ||
793 operand->type == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
794 operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE ||
795 operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0);
799 cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
800 cairo_gl_context_t *ctx,
801 cairo_gl_operand_t *op,
804 const char *namestr = operand_names[name];
805 const char *rectstr = (ctx->tex_target == GL_TEXTURE_RECTANGLE ? "Rect" : "");
806 cairo_bool_t use_atlas = _cairo_gl_operand_get_use_atlas (op);
809 case CAIRO_GL_OPERAND_COUNT:
813 case CAIRO_GL_OPERAND_NONE:
814 _cairo_output_stream_printf (stream,
817 " return vec4 (0, 0, 0, 1);\n"
821 case CAIRO_GL_OPERAND_CONSTANT:
822 if (op->use_color_attribute)
823 _cairo_output_stream_printf (stream,
824 "varying vec4 fragment_color;\n"
827 " return fragment_color;\n"
831 _cairo_output_stream_printf (stream,
832 "uniform vec4 %s_constant;\n"
835 " return %s_constant;\n"
837 namestr, namestr, namestr);
839 case CAIRO_GL_OPERAND_TEXTURE:
841 _cairo_output_stream_printf (stream,
842 "uniform sampler2D%s %s_sampler;\n"
843 "uniform vec2 %s_texdims;\n"
844 "varying vec2 %s_texcoords;\n"
847 rectstr, namestr, namestr, namestr, namestr);
849 _cairo_output_stream_printf (stream,
850 "uniform sampler2D%s %s_sampler;\n"
851 "uniform vec2 %s_texdims;\n"
852 "varying vec2 %s_texcoords;\n"
853 "varying vec2 %s_start_coords;\n"
854 "varying vec2 %s_stop_coords;\n"
857 rectstr, namestr, namestr, namestr, namestr, namestr, namestr);
860 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
861 _cairo_gl_shader_needs_border_fade (op))
863 _cairo_output_stream_printf (stream,
864 " vec2 border_fade = %s_border_fade (%s_texcoords, %s_texdims);\n"
865 " vec4 texel = texture2D%s (%s_sampler, %s_texcoords);\n"
866 " return texel * border_fade.x * border_fade.y;\n"
868 namestr, namestr, namestr, rectstr, namestr, namestr);
873 _cairo_output_stream_printf (stream,
874 " return texture2D%s (%s_sampler, %s_wrap (%s_texcoords));\n"
876 rectstr, namestr, namestr, namestr);
878 _cairo_output_stream_printf (stream,
879 " return texture2D%s (%s_sampler, %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords));\n"
881 rectstr, namestr, namestr, namestr, namestr, namestr);
885 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
886 _cairo_output_stream_printf (stream,
887 "varying vec2 %s_texcoords;\n"
888 "uniform vec2 %s_texdims;\n"
889 "uniform sampler2D%s %s_sampler;\n"
893 namestr, namestr, rectstr, namestr, namestr);
894 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
895 _cairo_gl_shader_needs_border_fade (op))
897 _cairo_output_stream_printf (stream,
898 " float border_fade = %s_border_fade (%s_texcoords.x, %s_texdims.x);\n"
899 " vec4 texel = texture2D%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n"
900 " return texel * border_fade;\n"
902 namestr, namestr, namestr, rectstr, namestr, namestr);
906 _cairo_output_stream_printf (stream,
907 " return texture2D%s (%s_sampler, %s_wrap (vec2 (%s_texcoords.x, 0.5)));\n"
909 rectstr, namestr, namestr, namestr);
912 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
913 _cairo_output_stream_printf (stream,
914 "varying vec2 %s_texcoords;\n"
915 "uniform vec2 %s_texdims;\n"
916 "uniform sampler2D%s %s_sampler;\n"
917 "uniform vec3 %s_circle_d;\n"
918 "uniform float %s_radius_0;\n"
922 " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
924 " float B = dot (pos, %s_circle_d);\n"
925 " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
927 " float t = 0.5 * C / B;\n"
928 " float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n",
929 namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
930 namestr, namestr, namestr, namestr, namestr);
931 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
932 _cairo_gl_shader_needs_border_fade (op))
934 _cairo_output_stream_printf (stream,
935 " float border_fade = %s_border_fade (t, %s_texdims.x);\n"
936 " vec4 texel = texture2D%s (%s_sampler, vec2 (t, 0.5));\n"
937 " return mix (vec4 (0.0), texel * border_fade, is_valid);\n"
939 namestr, namestr, rectstr, namestr);
943 _cairo_output_stream_printf (stream,
944 " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2 (t, 0.5)));\n"
945 " return mix (vec4 (0.0), texel, is_valid);\n"
947 rectstr, namestr, namestr);
950 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
951 _cairo_output_stream_printf (stream,
952 "varying vec2 %s_texcoords;\n"
953 "uniform vec2 %s_texdims;\n"
954 "uniform sampler2D%s %s_sampler;\n"
955 "uniform vec3 %s_circle_d;\n"
956 "uniform float %s_a;\n"
957 "uniform float %s_radius_0;\n"
961 " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
963 " float B = dot (pos, %s_circle_d);\n"
964 " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
966 " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n"
967 " float sqrtdet = sqrt (abs (det));\n"
968 " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
970 " vec2 is_valid = step (vec2 (0.0), t) * step (t, vec2(1.0));\n"
971 " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
973 " float upper_t = mix (t.y, t.x, is_valid.x);\n",
974 namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
975 namestr, namestr, namestr, namestr, namestr, namestr);
976 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
977 _cairo_gl_shader_needs_border_fade (op))
979 _cairo_output_stream_printf (stream,
980 " float border_fade = %s_border_fade (upper_t, %s_texdims.x);\n"
981 " vec4 texel = texture2D%s (%s_sampler, vec2 (upper_t, 0.5));\n"
982 " return mix (vec4 (0.0), texel * border_fade, has_color);\n"
984 namestr, namestr, rectstr, namestr);
988 _cairo_output_stream_printf (stream,
989 " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
990 " return mix (vec4 (0.0), texel, has_color);\n"
992 rectstr, namestr, namestr);
995 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
996 _cairo_output_stream_printf (stream,
997 "varying vec2 %s_texcoords;\n"
998 "uniform sampler2D%s %s_sampler;\n"
999 "uniform vec3 %s_circle_d;\n"
1000 "uniform float %s_a;\n"
1001 "uniform float %s_radius_0;\n"
1005 " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
1007 " float B = dot (pos, %s_circle_d);\n"
1008 " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
1010 " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n"
1011 " float sqrtdet = sqrt (abs (det));\n"
1012 " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
1014 " vec2 is_valid = step (vec2 (-%s_radius_0), t * %s_circle_d.z);\n"
1015 " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
1017 " float upper_t = mix (t.y, t.x, is_valid.x);\n"
1018 " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
1019 " return mix (vec4 (0.0), texel, has_color);\n"
1021 namestr, rectstr, namestr, namestr, namestr, namestr,
1022 namestr, namestr, namestr, namestr, namestr,
1023 namestr, namestr, namestr, rectstr, namestr, namestr);
1029 * Emits the border fade functions used by an operand.
1031 * If bilinear filtering is used, the emitted function performs a linear
1032 * fade to transparency effect in the intervals [-1/2n, 1/2n] and
1033 * [1 - 1/2n, 1 + 1/2n] (n: texture size).
1035 * If nearest filtering is used, the emitted function just returns
1036 * 0.0 for all values outside [0, 1).
1039 _cairo_gl_shader_emit_border_fade (cairo_output_stream_t *stream,
1040 cairo_gl_operand_t *operand,
1041 cairo_gl_tex_t name)
1043 const char *namestr = operand_names[name];
1044 GLint gl_filter = _cairo_gl_operand_get_gl_filter (operand);
1047 _cairo_output_stream_printf (stream,
1048 "vec2 %s_border_fade (vec2 coords, vec2 dims)\n"
1052 if (gl_filter == GL_LINEAR)
1053 _cairo_output_stream_printf (stream,
1054 " return clamp(-abs(dims * (coords - 0.5)) + (dims + vec2(1.0)) * 0.5, 0.0, 1.0);\n");
1056 _cairo_output_stream_printf (stream,
1057 " bvec2 in_tex1 = greaterThanEqual (coords, vec2 (0.0));\n"
1058 " bvec2 in_tex2 = lessThan (coords, vec2 (1.0));\n"
1059 " return vec2 (float (all (in_tex1) && all (in_tex2)));\n");
1061 _cairo_output_stream_printf (stream, "}\n");
1064 _cairo_output_stream_printf (stream,
1065 "float %s_border_fade (float x, float dim)\n"
1068 if (gl_filter == GL_LINEAR)
1069 _cairo_output_stream_printf (stream,
1070 " return clamp(-abs(dim * (x - 0.5)) + (dim + 1.0) * 0.5, 0.0, 1.0);\n");
1072 _cairo_output_stream_printf (stream,
1073 " bool in_tex = x >= 0.0 && x < 1.0;\n"
1074 " return float (in_tex);\n");
1076 _cairo_output_stream_printf (stream, "}\n");
1080 * Emits the wrap function used by an operand.
1082 * In OpenGL ES 2.0, repeat wrap modes (GL_REPEAT and GL_MIRRORED REPEAT) are
1083 * only available for NPOT textures if the GL_OES_texture_npot is supported.
1084 * If GL_OES_texture_npot is not supported, we need to implement the wrapping
1085 * functionality in the shader.
1088 _cairo_gl_shader_emit_wrap (cairo_gl_context_t *ctx,
1089 cairo_output_stream_t *stream,
1090 cairo_gl_operand_t *operand,
1091 cairo_gl_tex_t name)
1093 const char *namestr = operand_names[name];
1094 cairo_extend_t extend = _cairo_gl_operand_get_extend (operand);
1095 cairo_bool_t use_atlas = _cairo_gl_operand_get_use_atlas (operand);
1098 _cairo_output_stream_printf (stream,
1099 "vec2 %s_wrap (vec2 coords, vec2 start_coords, vec2 stop_coords)\n"
1103 _cairo_output_stream_printf (stream,
1104 "vec2 %s_wrap(vec2 coords)\n"
1109 if (extend == CAIRO_EXTEND_REPEAT) {
1110 _cairo_output_stream_printf (stream,
1111 " vec2 range = stop_coords - start_coords;\n"
1112 " return mod (coords - start_coords, range) + start_coords;\n");
1113 } else if (extend == CAIRO_EXTEND_REFLECT){
1114 _cairo_output_stream_printf (stream,
1115 " vec2 range = stop_coords - start_coords;\n"
1116 " vec2 frac = mod (coords - start_coords, range);\n"
1117 " return mix(frac + start_coords, range - frac + start_coords, mod(floor((coords - start_coords) / range), 2.0));\n");
1119 else if (extend == CAIRO_EXTEND_PAD) {
1120 _cairo_output_stream_printf (stream,
1121 " bvec2 compare_to_start = lessThan (coords, start_coords);\n"
1122 " bvec2 compare_to_stop = greaterThan (coords, stop_coords);\n"
1123 " if (all (compare_to_start))\n"
1124 " return start_coords;\n"
1125 " else if (all (compare_to_stop))\n"
1126 " return stop_coords;\n"
1127 " else if (compare_to_start.x && compare_to_stop.y)\n"
1128 " return vec2 (start_coords.x, stop_coords.y);\n"
1129 " else if (compare_to_start.x && ! compare_to_stop.y)\n"
1130 " return vec2 (start_coords.x, coords.y);\n"
1131 " else if (compare_to_stop.x && compare_to_start.y)\n"
1132 " return vec2 (stop_coords.x, start_coords.y);\n"
1133 " else if (compare_to_stop.x && ! compare_to_stop.y)\n"
1134 " return vec2 (stop_coords.x, coords.y);\n"
1135 " else if (compare_to_start.y && ! compare_to_start.x)\n"
1136 " return vec2 (coords.x, start_coords.y);\n"
1137 " else if (compare_to_stop.y && ! compare_to_start.x)\n"
1138 " return vec2 (coords.x, stop_coords.y);\n"
1140 " return coords;\n");
1143 _cairo_output_stream_printf (stream,
1144 " if (any (lessThan (coords, start_coords)))\n"
1145 " return vec2 (-1.0);\n"
1146 " if (any (greaterThan (coords, stop_coords)))\n"
1147 " return vec2 (-1.0);\n"
1149 " return coords;\n");
1153 if (! ctx->has_npot_repeat &&
1154 (extend == CAIRO_EXTEND_REPEAT ||
1155 extend == CAIRO_EXTEND_REFLECT)) {
1156 if (extend == CAIRO_EXTEND_REPEAT) {
1157 _cairo_output_stream_printf (stream,
1158 " return fract(coords);\n");
1159 } else { /* CAIRO_EXTEND_REFLECT */
1160 _cairo_output_stream_printf (stream,
1161 " return mix(fract(coords), 1.0 - fract(coords), floor(mod(coords, 2.0)));\n");
1166 _cairo_output_stream_printf (stream, " return coords;\n");
1170 _cairo_output_stream_printf (stream, "}\n");
1173 static cairo_status_t
1174 cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
1175 cairo_gl_shader_in_t in,
1176 cairo_gl_operand_t *src,
1177 cairo_gl_operand_t *mask,
1178 cairo_bool_t use_coverage,
1179 cairo_gl_operand_type_t dest_type,
1182 cairo_output_stream_t *stream = _cairo_memory_stream_create ();
1183 unsigned char *source;
1184 unsigned long length;
1185 cairo_status_t status;
1186 const char *coverage_str;
1188 _cairo_output_stream_printf (stream,
1190 "precision mediump float;\n"
1193 _cairo_gl_shader_emit_wrap (ctx, stream, src, CAIRO_GL_TEX_SOURCE);
1194 _cairo_gl_shader_emit_wrap (ctx, stream, mask, CAIRO_GL_TEX_MASK);
1196 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
1197 if (_cairo_gl_shader_needs_border_fade (src))
1198 _cairo_gl_shader_emit_border_fade (stream, src, CAIRO_GL_TEX_SOURCE);
1199 if (_cairo_gl_shader_needs_border_fade (mask))
1200 _cairo_gl_shader_emit_border_fade (stream, mask, CAIRO_GL_TEX_MASK);
1203 cairo_gl_shader_emit_color (stream, ctx, src, CAIRO_GL_TEX_SOURCE);
1204 cairo_gl_shader_emit_color (stream, ctx, mask, CAIRO_GL_TEX_MASK);
1208 _cairo_output_stream_printf (stream, "varying float coverage;\n");
1209 coverage_str = " * coverage";
1212 _cairo_output_stream_printf (stream,
1216 case CAIRO_GL_SHADER_IN_COUNT:
1219 case CAIRO_GL_SHADER_IN_NORMAL:
1220 _cairo_output_stream_printf (stream,
1221 " gl_FragColor = get_source() * get_mask().a%s;\n",
1224 case CAIRO_GL_SHADER_IN_CA_SOURCE:
1225 _cairo_output_stream_printf (stream,
1226 " gl_FragColor = get_source() * get_mask()%s;\n",
1229 case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA:
1230 _cairo_output_stream_printf (stream,
1231 " gl_FragColor = get_source().a * get_mask()%s;\n",
1236 _cairo_output_stream_write (stream,
1239 status = _cairo_memory_stream_destroy (stream, &source, &length);
1240 if (unlikely (status))
1243 *out = (char *) source;
1244 return CAIRO_STATUS_SUCCESS;
1247 static cairo_status_t
1248 _cairo_gl_shader_compile (cairo_gl_context_t *ctx,
1249 cairo_gl_shader_t *shader,
1250 cairo_gl_operand_t *src,
1251 cairo_gl_operand_t *mask,
1252 cairo_bool_t use_coverage,
1253 const char *fragment_text)
1255 unsigned int vertex_shader;
1256 cairo_status_t status;
1257 cairo_gl_var_type_t src_type;
1258 cairo_gl_var_type_t mask_type;
1259 cairo_extend_t src_atlas_extend = CAIRO_EXTEND_NONE;
1260 cairo_extend_t mask_atlas_extend = CAIRO_EXTEND_NONE;
1261 cairo_bool_t src_use_atlas = FALSE;
1262 cairo_bool_t mask_use_atlas = FALSE;
1264 assert (shader->program == 0);
1267 src_type = cairo_gl_operand_get_var_type (src->type,
1268 src->use_color_attribute);
1269 src_atlas_extend = _cairo_gl_operand_get_atlas_extend (src);
1270 src_use_atlas = _cairo_gl_operand_get_use_atlas (src);
1273 src_type = CAIRO_GL_VAR_NONE;
1276 mask_type = cairo_gl_operand_get_var_type (mask->type,
1277 mask->use_color_attribute);
1278 mask_atlas_extend = _cairo_gl_operand_get_atlas_extend (mask);
1279 mask_use_atlas = _cairo_gl_operand_get_use_atlas (mask);
1282 mask_type = CAIRO_GL_VAR_NONE;
1284 vertex_shader = cairo_gl_var_type_hash (src_type, mask_type,
1291 if (ctx->vertex_shaders[vertex_shader] == 0) {
1294 status = cairo_gl_shader_get_vertex_source (src_type,
1301 if (unlikely (status))
1304 ctx->shader_impl->compile_shader (ctx, &ctx->vertex_shaders[vertex_shader],
1310 ctx->shader_impl->compile_shader (ctx, &shader->fragment_shader,
1314 ctx->shader_impl->link_shader (ctx, &shader->program,
1315 ctx->vertex_shaders[vertex_shader],
1316 shader->fragment_shader);
1318 return CAIRO_STATUS_SUCCESS;
1321 _cairo_gl_shader_fini (ctx, shader);
1322 shader->fragment_shader = 0;
1323 shader->program = 0;
1328 /* We always bind the source to texture unit 0 if present, and mask to
1329 * texture unit 1 if present, so we can just initialize these once at
1332 static cairo_int_status_t
1333 _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx,
1334 cairo_gl_shader_t *shader)
1336 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1338 GLint saved_program;
1339 cairo_int_status_t status;
1341 /* We have to save/restore the current program because we might be
1342 * asked for a different program while a shader is bound. This shouldn't
1343 * be a performance issue, since this is only called once per compile.
1345 glGetIntegerv (GL_CURRENT_PROGRAM, &saved_program);
1346 dispatch->UseProgram (shader->program);
1348 status = get_uniform_location (ctx, shader, "source_sampler", &location);
1351 if (location != -1) {
1352 dispatch->Uniform1i (location, CAIRO_GL_TEX_SOURCE);
1355 get_uniform_location (ctx, shader, "mask_sampler", &location);
1358 if (location != -1) {
1359 dispatch->Uniform1i (location, CAIRO_GL_TEX_MASK);
1362 dispatch->UseProgram (saved_program);
1363 return CAIRO_INT_STATUS_SUCCESS;
1367 _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
1371 ctx->shader_impl->bind_float (ctx, ctx->current_shader, name, value);
1375 _cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
1380 ctx->shader_impl->bind_vec2 (ctx, ctx->current_shader, name, value0, value1);
1384 _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
1390 ctx->shader_impl->bind_vec3 (ctx, ctx->current_shader, name, value0, value1, value2);
1394 _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
1396 float value0, float value1,
1397 float value2, float value3)
1399 ctx->shader_impl->bind_vec4 (ctx, ctx->current_shader, name, value0, value1, value2, value3);
1403 _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
1404 const char *name, cairo_matrix_t* m)
1406 ctx->shader_impl->bind_matrix (ctx, ctx->current_shader, name, m);
1410 _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
1411 const char *name, GLfloat* gl_m)
1413 ctx->shader_impl->bind_matrix4f (ctx, ctx->current_shader, name, gl_m);
1417 _cairo_gl_set_shader (cairo_gl_context_t *ctx,
1418 cairo_gl_shader_t *shader)
1420 if (ctx->current_shader == shader)
1423 ctx->shader_impl->use (ctx, shader);
1425 ctx->current_shader = shader;
1429 _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
1430 cairo_gl_operand_t *source,
1431 cairo_gl_operand_t *mask,
1432 cairo_bool_t use_coverage,
1433 cairo_gl_shader_in_t in,
1434 cairo_gl_shader_t **shader)
1436 cairo_shader_cache_entry_t lookup, *entry;
1438 cairo_status_t status;
1441 lookup.src = source->type;
1442 lookup.mask = mask->type;
1443 lookup.dest = CAIRO_GL_OPERAND_NONE;
1444 lookup.use_coverage = use_coverage;
1445 lookup.use_color_attribute = source->use_color_attribute;
1447 lookup.src_gl_filter = _cairo_gl_operand_get_gl_filter (source);
1448 lookup.src_border_fade = _cairo_gl_shader_needs_border_fade (source);
1449 lookup.src_extend = _cairo_gl_operand_get_atlas_extend (source);
1450 lookup.mask_gl_filter = _cairo_gl_operand_get_gl_filter (mask);
1451 lookup.mask_border_fade = _cairo_gl_shader_needs_border_fade (mask);
1452 lookup.mask_extend = _cairo_gl_operand_get_atlas_extend (mask);
1453 lookup.src_use_atlas = _cairo_gl_operand_get_use_atlas (source);
1454 lookup.mask_use_atlas = _cairo_gl_operand_get_use_atlas (mask);
1455 lookup.base.hash = _cairo_gl_shader_cache_hash (&lookup);
1456 lookup.base.size = 1;
1458 entry = _cairo_cache_lookup (&ctx->shaders, &lookup.base);
1460 assert (entry->shader.program);
1461 *shader = &entry->shader;
1462 return CAIRO_STATUS_SUCCESS;
1465 status = cairo_gl_shader_get_fragment_source (ctx,
1470 CAIRO_GL_OPERAND_NONE,
1472 if (unlikely (status))
1475 entry = malloc (sizeof (cairo_shader_cache_entry_t));
1476 if (unlikely (entry == NULL)) {
1478 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1481 memcpy (entry, &lookup, sizeof (cairo_shader_cache_entry_t));
1484 _cairo_gl_shader_init (&entry->shader);
1485 status = _cairo_gl_shader_compile (ctx,
1493 if (unlikely (status))
1496 status = _cairo_gl_shader_set_samplers (ctx, &entry->shader);
1497 if (unlikely (status))
1500 status = _cairo_cache_insert (&ctx->shaders, &entry->base);
1501 if (unlikely (status))
1504 *shader = &entry->shader;
1506 return CAIRO_STATUS_SUCCESS;
1509 _cairo_gl_shader_fini (ctx, &entry->shader);