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"
48 _cairo_gl_shader_get_uniform_location (cairo_gl_context_t *ctx,
49 cairo_gl_shader_t *shader,
50 cairo_gl_uniform_t uniform)
52 /* This should be kept in sync with the enum
53 * definition in cairo-gl-private.h. */
54 const char *names[CAIRO_GL_UNIFORM_MAX] = {
81 "ModelViewProjectionMatrix"
84 if (shader->uniforms[uniform] != -1)
85 return shader->uniforms[uniform];
87 shader->uniforms[uniform] =
88 ctx->dispatch.GetUniformLocation (shader->program,
90 return shader->uniforms[uniform];
94 _cairo_gl_shader_uniform_for_texunit (cairo_gl_uniform_t uniform,
95 cairo_gl_tex_t tex_unit)
97 assert (uniform < CAIRO_GL_UNIFORM_MASK_TEXDIMS);
98 assert (tex_unit == CAIRO_GL_TEX_SOURCE || tex_unit == CAIRO_GL_TEX_MASK);
99 if (tex_unit == CAIRO_GL_TEX_SOURCE)
102 return uniform + CAIRO_GL_UNIFORM_MASK_TEXDIMS;
105 static cairo_status_t
106 _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
107 cairo_gl_shader_t *shader,
108 cairo_gl_var_type_t src,
109 cairo_gl_var_type_t mask,
110 cairo_bool_t use_coverage,
111 const char *fragment_text,
112 cairo_extend_t src_atlas_extend,
113 cairo_extend_t mask_atlas_extend,
114 cairo_bool_t src_use_atlas,
115 cairo_bool_t mask_use_atlas);
117 typedef struct _cairo_shader_cache_entry {
118 cairo_cache_entry_t base;
122 cairo_gl_operand_type_t src;
123 cairo_gl_operand_type_t mask;
124 cairo_gl_operand_type_t dest;
125 cairo_bool_t use_coverage;
127 cairo_gl_shader_in_t in;
129 cairo_bool_t src_border_fade;
130 cairo_extend_t src_extend;
131 GLint mask_gl_filter;
132 cairo_bool_t mask_border_fade;
133 cairo_extend_t mask_extend;
135 cairo_bool_t src_use_atlas;
136 cairo_bool_t mask_use_atlas;
138 cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */
139 cairo_gl_shader_t shader;
140 } cairo_shader_cache_entry_t;
143 _cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b)
145 const cairo_shader_cache_entry_t *a = key_a;
146 const cairo_shader_cache_entry_t *b = key_b;
147 cairo_bool_t both_have_npot_repeat =
148 a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
150 return (a->vertex == b->vertex &&
152 a->mask == b->mask &&
153 a->dest == b->dest &&
154 a->use_coverage == b->use_coverage &&
156 (both_have_npot_repeat || a->src_extend == b->src_extend) &&
157 (both_have_npot_repeat || a->mask_extend == b->mask_extend));
161 * For GLES2 we use more complicated shaders to implement missing GL
162 * features. In this case we need more parameters to uniquely identify
163 * a shader (vs _cairo_gl_shader_cache_equal_desktop()).
166 _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
168 const cairo_shader_cache_entry_t *a = key_a;
169 const cairo_shader_cache_entry_t *b = key_b;
170 cairo_bool_t both_have_npot_repeat =
171 a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
173 return (a->vertex == b->vertex &&
175 a->mask == b->mask &&
176 a->dest == b->dest &&
177 a->use_coverage == b->use_coverage &&
179 a->src_gl_filter == b->src_gl_filter &&
180 a->src_border_fade == b->src_border_fade &&
181 (both_have_npot_repeat || a->src_extend == b->src_extend) &&
182 a->mask_gl_filter == b->mask_gl_filter &&
183 a->mask_border_fade == b->mask_border_fade &&
184 (both_have_npot_repeat || a->mask_extend == b->mask_extend));
188 _cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry)
190 return ((entry->src << 15) |
191 (entry->mask << 12) |
194 (entry->mask_extend << 5) |
195 (entry->src_extend << 3) |
196 (entry->mask_use_atlas << 2) |
197 (entry->src_use_atlas << 1) |
198 entry->use_coverage) ^ entry->vertex;
202 _cairo_gl_shader_cache_destroy (void *data)
204 cairo_shader_cache_entry_t *entry = data;
206 _cairo_gl_shader_fini (entry->ctx, &entry->shader);
207 if (entry->ctx->current_shader == &entry->shader)
208 entry->ctx->current_shader = NULL;
213 _cairo_gl_shader_init (cairo_gl_shader_t *shader)
216 shader->fragment_shader = 0;
219 for (i = 0; i < CAIRO_GL_UNIFORM_MAX; i++)
220 shader->uniforms[i] = -1;
224 _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
226 static const char *fill_fs_source =
228 "precision mediump float;\n"
230 "uniform vec4 color;\n"
233 " gl_FragColor = color;\n"
235 cairo_status_t status;
237 if (_cairo_gl_get_version (&ctx->dispatch) >= CAIRO_GL_VERSION_ENCODE (2, 0) ||
238 (_cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_shader_objects") &&
239 _cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_fragment_shader") &&
240 _cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_vertex_shader"))) {
241 ctx->has_shader_support = TRUE;
243 ctx->has_shader_support = FALSE;
244 fprintf (stderr, "Error: The cairo gl backend requires shader support!\n");
245 return CAIRO_STATUS_DEVICE_ERROR;
248 memset (ctx->vertex_shaders, 0, sizeof (ctx->vertex_shaders));
250 status = _cairo_cache_init (&ctx->shaders,
251 ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ?
252 _cairo_gl_shader_cache_equal_desktop :
253 _cairo_gl_shader_cache_equal_gles2,
255 _cairo_gl_shader_cache_destroy,
256 CAIRO_GL_MAX_SHADERS_PER_CONTEXT);
257 if (unlikely (status))
260 _cairo_gl_shader_init (&ctx->fill_rectangles_shader);
261 status = _cairo_gl_shader_compile_and_link (ctx,
262 &ctx->fill_rectangles_shader,
267 CAIRO_EXTEND_NONE, CAIRO_EXTEND_NONE,
269 if (unlikely (status))
272 return CAIRO_STATUS_SUCCESS;
276 _cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx)
280 for (i = 0; i < CAIRO_GL_VAR_TYPE_MAX; i++) {
281 if (ctx->vertex_shaders[i])
282 ctx->dispatch.DeleteShader (ctx->vertex_shaders[i]);
285 _cairo_cache_fini (&ctx->shaders);
289 _cairo_gl_shader_fini (cairo_gl_context_t *ctx,
290 cairo_gl_shader_t *shader)
292 if (shader->fragment_shader)
293 ctx->dispatch.DeleteShader (shader->fragment_shader);
296 ctx->dispatch.DeleteProgram (shader->program);
299 static const char *operand_names[] = { "source", "mask", "dest" };
301 static cairo_gl_var_type_t
302 cairo_gl_operand_get_var_type (cairo_gl_operand_t *operand)
304 switch (operand->type) {
306 case CAIRO_GL_OPERAND_COUNT:
308 case CAIRO_GL_OPERAND_NONE:
309 case CAIRO_GL_OPERAND_CONSTANT:
310 if (operand->constant.encode_as_attribute)
311 return CAIRO_GL_VAR_COLOR;
313 return CAIRO_GL_VAR_NONE;
314 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
315 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
316 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
317 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
318 return operand->gradient.texgen ? CAIRO_GL_VAR_TEXGEN : CAIRO_GL_VAR_TEXCOORDS;
319 case CAIRO_GL_OPERAND_TEXTURE:
320 case CAIRO_GL_OPERAND_GAUSSIAN:
321 return operand->texture.texgen ? CAIRO_GL_VAR_TEXGEN : CAIRO_GL_VAR_TEXCOORDS;
326 cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
327 cairo_gl_var_type_t type,
329 cairo_bool_t use_atlas)
334 case CAIRO_GL_VAR_NONE:
336 case CAIRO_GL_VAR_TEXCOORDS:
337 _cairo_output_stream_printf (stream,
338 "attribute vec4 MultiTexCoord%d;\n"
339 "varying vec2 %s_texcoords;\n",
341 operand_names[name]);
343 _cairo_output_stream_printf (stream,
344 "varying vec2 %s_start_coords;\n"
345 "varying vec2 %s_stop_coords;\n",
346 operand_names[name], operand_names[name]);
348 case CAIRO_GL_VAR_TEXGEN:
349 _cairo_output_stream_printf (stream,
350 "uniform mat3 %s_texgen;\n"
351 "varying vec2 %s_texcoords;\n",
353 operand_names[name]);
355 _cairo_output_stream_printf (stream,
356 "varying vec2 %s_start_coords;\n"
357 "varying vec2 %s_stop_coords;\n",
358 operand_names[name], operand_names[name]);
361 case CAIRO_GL_VAR_COLOR:
362 _cairo_output_stream_printf (stream,
363 "varying vec4 fragment_color;\n");
369 cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
370 cairo_gl_var_type_t type,
376 case CAIRO_GL_VAR_NONE:
378 case CAIRO_GL_VAR_TEXCOORDS:
379 _cairo_output_stream_printf (stream,
380 " %s_texcoords = MultiTexCoord%d.xy;\n",
381 operand_names[name], name);
384 case CAIRO_GL_VAR_TEXGEN:
385 _cairo_output_stream_printf (stream,
386 " %s_texcoords = (%s_texgen * Vertex.xyw).xy;\n",
387 operand_names[name], operand_names[name]);
389 case CAIRO_GL_VAR_COLOR:
390 _cairo_output_stream_printf (stream, " fragment_color = Color;\n");
396 cairo_gl_shader_dcl_coverage (cairo_output_stream_t *stream)
398 _cairo_output_stream_printf (stream, "varying float coverage;\n");
402 cairo_gl_shader_def_coverage (cairo_output_stream_t *stream)
404 _cairo_output_stream_printf (stream, " coverage = Color.a;\n");
408 cairo_gl_shader_def_use_atlas (cairo_output_stream_t *stream,
409 cairo_gl_var_type_t type,
412 _cairo_output_stream_printf (stream,
413 " %s_start_coords = StartCoords%d.xy;\n"
414 " %s_stop_coords = StopCoords%d.xy;\n",
415 operand_names[name], name,
416 operand_names[name], name);
420 cairo_gl_shader_emit_varying (cairo_output_stream_t *stream,
423 const char *namestr = operand_names[name];
425 _cairo_output_stream_printf (stream,
426 "varying vec2 %s_start_coords;\n"
427 "varying vec2 %s_stop_coords;\n",
431 static cairo_status_t
432 cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
433 cairo_gl_var_type_t mask,
434 cairo_bool_t src_use_atlas,
435 cairo_bool_t mask_use_atlas,
436 cairo_bool_t use_coverage,
437 cairo_gl_var_type_t dest,
440 cairo_output_stream_t *stream = _cairo_memory_stream_create ();
441 unsigned char *source;
442 unsigned long length;
443 cairo_status_t status;
445 cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_TEX_SOURCE, src_use_atlas);
446 cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_TEX_MASK, mask_use_atlas);
448 cairo_gl_shader_dcl_coverage (stream);
450 if (src_use_atlas && src == CAIRO_GL_VAR_TEXGEN)
451 cairo_gl_shader_emit_varying (stream, CAIRO_GL_TEX_SOURCE);
453 if (mask_use_atlas && mask == CAIRO_GL_VAR_TEXGEN)
454 cairo_gl_shader_emit_varying (stream, CAIRO_GL_TEX_MASK);
456 _cairo_output_stream_printf (stream,
457 "attribute vec4 Vertex;\n"
458 "attribute vec4 Color;\n"
459 "attribute vec2 StartCoords0;\n"
460 "attribute vec2 StartCoords1;\n"
461 "attribute vec2 StopCoords0;\n"
462 "attribute vec2 StopCoords1;\n"
463 "uniform mat4 ModelViewProjectionMatrix;\n"
466 " gl_Position = ModelViewProjectionMatrix * Vertex;\n");
468 cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE);
469 cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK);
471 cairo_gl_shader_def_coverage (stream);
474 cairo_gl_shader_def_use_atlas (stream, src, CAIRO_GL_TEX_SOURCE);
476 cairo_gl_shader_def_use_atlas (stream, mask, CAIRO_GL_TEX_MASK);
478 _cairo_output_stream_write (stream,
481 status = _cairo_memory_stream_destroy (stream, &source, &length);
482 if (unlikely (status)) {
487 *out = (char *) source;
488 return CAIRO_STATUS_SUCCESS;
492 * Returns whether an operand needs a special border fade fragment shader
493 * to simulate the GL_CLAMP_TO_BORDER wrapping method that is missing in GLES2.
496 _cairo_gl_shader_needs_border_fade (cairo_gl_operand_t *operand)
498 cairo_extend_t extend =_cairo_gl_operand_get_extend (operand);
500 return extend == CAIRO_EXTEND_NONE &&
501 (operand->type == CAIRO_GL_OPERAND_TEXTURE ||
502 operand->type == CAIRO_GL_OPERAND_GAUSSIAN ||
503 operand->type == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
504 operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE ||
505 operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0);
509 cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
510 cairo_gl_context_t *ctx,
511 cairo_gl_operand_t *op,
514 const char *namestr = operand_names[name];
515 const char *rectstr = (ctx->tex_target == GL_TEXTURE_RECTANGLE ? "Rect" : "");
516 cairo_bool_t use_atlas = _cairo_gl_operand_get_use_atlas (op);
519 case CAIRO_GL_OPERAND_COUNT:
523 case CAIRO_GL_OPERAND_NONE:
524 _cairo_output_stream_printf (stream,
527 " return vec4 (0, 0, 0, 1);\n"
531 case CAIRO_GL_OPERAND_CONSTANT:
532 if (op->constant.encode_as_attribute) {
533 _cairo_output_stream_printf (stream,
534 "varying vec4 fragment_color;\n"
537 " return fragment_color;\n"
541 _cairo_output_stream_printf (stream,
542 "uniform vec4 %s_constant;\n"
545 " return %s_constant;\n"
547 namestr, namestr, namestr);
550 case CAIRO_GL_OPERAND_TEXTURE:
551 case CAIRO_GL_OPERAND_GAUSSIAN:
553 _cairo_output_stream_printf (stream,
554 "uniform sampler2D%s %s_sampler;\n"
555 "uniform vec2 %s_texdims;\n"
556 "varying vec2 %s_texcoords;\n",
557 rectstr, namestr, namestr, namestr);
559 _cairo_output_stream_printf (stream,
560 "uniform sampler2D%s %s_sampler;\n"
561 "uniform vec2 %s_texdims;\n"
562 "varying vec2 %s_texcoords;\n"
563 "varying vec2 %s_start_coords;\n"
564 "varying vec2 %s_stop_coords;\n",
565 rectstr, namestr, namestr, namestr, namestr, namestr);
568 if (op->type != CAIRO_GL_OPERAND_TEXTURE) {
569 _cairo_output_stream_printf (stream,
570 "uniform int %s_blur_radius;\n"
571 "uniform float %s_blur_step;\n"
572 "uniform float %s_blurs[17];\n"
573 "uniform float %s_blur_x_axis;\n"
574 "uniform float %s_blur_y_axis;\n"
575 "uniform float %s_alpha;\n",
576 namestr, namestr, namestr, namestr, namestr, namestr);
579 _cairo_output_stream_printf (stream,
584 if (op->type == CAIRO_GL_OPERAND_TEXTURE) {
585 if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
586 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
587 _cairo_gl_shader_needs_border_fade (op))
590 _cairo_output_stream_printf (stream,
591 " vec2 border_fade = %s_border_fade (%s_texcoords, %s_texdims);\n"
592 " vec4 texel = texture2D%s (%s_sampler, %s_texcoords);\n"
593 " return texel * border_fade.x * border_fade.y;\n"
595 namestr, namestr, namestr, rectstr, namestr, namestr);
598 _cairo_output_stream_printf (stream,
599 " vec2 border_fade = %s_border_fade (%s_texcoords, %s_texdims);\n"
600 " vec2 co = %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords);\n"
601 " if (co.x == -1.0 && co.y == -1.0)\n"
602 " return vec4(0.0, 0.0, 0.0, 0.0);\n"
603 " vec4 texel = texture2D%s (%s_sampler, co);\n"
604 " return texel * border_fade.x * border_fade.y;\n"
606 namestr, namestr, namestr, namestr,
607 namestr, namestr, namestr, rectstr, namestr);
613 _cairo_output_stream_printf (stream,
614 " return texture2D%s (%s_sampler, %s_wrap (%s_texcoords));\n"
616 rectstr, namestr, namestr, namestr);
618 _cairo_output_stream_printf (stream,
619 " return texture2D%s (%s_sampler, %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords));\n"
621 rectstr, namestr, namestr, namestr, namestr, namestr);
625 else if (op->type == CAIRO_GL_OPERAND_GAUSSIAN) {
626 _cairo_output_stream_printf (stream,
629 " float alpha = %s_alpha;\n"
630 " vec4 texel = vec4 (0.0, 0.0, 0.0, 0.0);\n"
631 " vec2 wrapped_coords = %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords);\n"
632 " if (wrapped_coords == vec2 (-1.0, -1.0))\n"
634 " texel += texture2D%s (%s_sampler, wrapped_coords);\n"
635 " texel = texel * %s_blurs[%s_blur_radius];\n"
636 " for (i = -%s_blur_radius; i <= %s_blur_radius; i++) {\n"
639 " texcoords = %s_texcoords + vec2 (%s_blur_step * float(i) * %s_blur_x_axis, %s_blur_step * float(i) * %s_blur_y_axis);\n"
641 " wrapped_coords = %s_wrap (texcoords, %s_start_coords, %s_stop_coords);\n"
642 " if (wrapped_coords == vec2 (-1.0, -1.0))\n"
643 " texel += vec4 (0.0, 0.0, 0.0, alpha) * %s_blurs[i+%s_blur_radius];\n"
645 " texel += texture2D%s (%s_sampler, wrapped_coords) * %s_blurs[i+%s_blur_radius];\n"
649 namestr, namestr, namestr, namestr, namestr,
650 rectstr, namestr, namestr, namestr,
651 namestr, namestr, namestr, namestr,
652 namestr, namestr, namestr, namestr,
653 namestr, namestr, namestr, namestr,
654 rectstr, namestr, namestr, namestr);
657 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
658 _cairo_output_stream_printf (stream,
659 "varying vec2 %s_texcoords;\n"
660 "uniform vec2 %s_texdims;\n"
661 "uniform sampler2D%s %s_sampler;\n"
665 namestr, namestr, rectstr, namestr, namestr);
666 if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
667 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
668 _cairo_gl_shader_needs_border_fade (op))
670 _cairo_output_stream_printf (stream,
671 " float border_fade = %s_border_fade (%s_texcoords.x, %s_texdims.x);\n"
672 " vec4 texel = texture2D%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n"
673 " return texel * border_fade;\n"
675 namestr, namestr, namestr, rectstr, namestr, namestr);
679 _cairo_output_stream_printf (stream,
680 " return texture2D%s (%s_sampler, %s_wrap (vec2 (%s_texcoords.x, 0.5)));\n"
682 rectstr, namestr, namestr, namestr);
685 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
686 _cairo_output_stream_printf (stream,
687 "varying vec2 %s_texcoords;\n"
688 "uniform vec2 %s_texdims;\n"
689 "uniform sampler2D%s %s_sampler;\n"
690 "uniform vec3 %s_circle_d;\n"
691 "uniform float %s_radius_0;\n"
695 " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
697 " float B = dot (pos, %s_circle_d);\n"
698 " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
700 " float t = 0.5 * C / B;\n"
701 " float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n",
702 namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
703 namestr, namestr, namestr, namestr, namestr);
704 if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
705 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
706 _cairo_gl_shader_needs_border_fade (op))
708 _cairo_output_stream_printf (stream,
709 " float border_fade = %s_border_fade (t, %s_texdims.x);\n"
710 " vec4 texel = texture2D%s (%s_sampler, vec2 (t, 0.5));\n"
711 " return mix (vec4 (0.0), texel * border_fade, is_valid);\n"
713 namestr, namestr, rectstr, namestr);
717 _cairo_output_stream_printf (stream,
718 " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2 (t, 0.5)));\n"
719 " return mix (vec4 (0.0), texel, is_valid);\n"
721 rectstr, namestr, namestr);
724 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
725 _cairo_output_stream_printf (stream,
726 "varying vec2 %s_texcoords;\n"
727 "uniform vec2 %s_texdims;\n"
728 "uniform sampler2D%s %s_sampler;\n"
729 "uniform vec3 %s_circle_d;\n"
730 "uniform float %s_a;\n"
731 "uniform float %s_radius_0;\n"
735 " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
737 " float B = dot (pos, %s_circle_d);\n"
738 " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
740 " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n"
741 " float sqrtdet = sqrt (abs (det));\n"
742 " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
744 " vec2 is_valid = step (vec2 (0.0), t) * step (t, vec2(1.0));\n"
745 " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
747 " float upper_t = mix (t.y, t.x, is_valid.x);\n",
748 namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
749 namestr, namestr, namestr, namestr, namestr, namestr);
750 if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
751 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) &&
752 _cairo_gl_shader_needs_border_fade (op))
754 _cairo_output_stream_printf (stream,
755 " float border_fade = %s_border_fade (upper_t, %s_texdims.x);\n"
756 " vec4 texel = texture2D%s (%s_sampler, vec2 (upper_t, 0.5));\n"
757 " return mix (vec4 (0.0), texel * border_fade, has_color);\n"
759 namestr, namestr, rectstr, namestr);
763 _cairo_output_stream_printf (stream,
764 " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
765 " return mix (vec4 (0.0), texel, has_color);\n"
767 rectstr, namestr, namestr);
770 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
771 _cairo_output_stream_printf (stream,
772 "varying vec2 %s_texcoords;\n"
773 "uniform sampler2D%s %s_sampler;\n"
774 "uniform vec3 %s_circle_d;\n"
775 "uniform float %s_a;\n"
776 "uniform float %s_radius_0;\n"
780 " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
782 " float B = dot (pos, %s_circle_d);\n"
783 " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
785 " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n"
786 " float sqrtdet = sqrt (abs (det));\n"
787 " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
789 " vec2 is_valid = step (vec2 (-%s_radius_0), t * %s_circle_d.z);\n"
790 " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
792 " float upper_t = mix (t.y, t.x, is_valid.x);\n"
793 " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
794 " return mix (vec4 (0.0), texel, has_color);\n"
796 namestr, rectstr, namestr, namestr, namestr, namestr,
797 namestr, namestr, namestr, namestr, namestr,
798 namestr, namestr, namestr, rectstr, namestr, namestr);
804 * Emits the border fade functions used by an operand.
806 * If bilinear filtering is used, the emitted function performs a linear
807 * fade to transparency effect in the intervals [-1/2n, 1/2n] and
808 * [1 - 1/2n, 1 + 1/2n] (n: texture size).
810 * If nearest filtering is used, the emitted function just returns
811 * 0.0 for all values outside [0, 1).
814 _cairo_gl_shader_emit_border_fade (cairo_output_stream_t *stream,
815 cairo_gl_operand_t *operand,
818 const char *namestr = operand_names[name];
819 GLint gl_filter = _cairo_gl_operand_get_gl_filter (operand);
822 _cairo_output_stream_printf (stream,
823 "vec2 %s_border_fade (vec2 coords, vec2 dims)\n"
827 if (gl_filter == GL_LINEAR)
828 _cairo_output_stream_printf (stream,
829 " return clamp(-abs(dims * (coords - 0.5)) + (dims + vec2(1.0)) * 0.5, 0.0, 1.0);\n");
831 _cairo_output_stream_printf (stream,
832 " bvec2 in_tex1 = greaterThanEqual (coords, vec2 (0.0));\n"
833 " bvec2 in_tex2 = lessThan (coords, vec2 (1.0));\n"
834 " return vec2 (float (all (in_tex1) && all (in_tex2)));\n");
836 _cairo_output_stream_printf (stream, "}\n");
839 _cairo_output_stream_printf (stream,
840 "float %s_border_fade (float x, float dim)\n"
843 if (gl_filter == GL_LINEAR)
844 _cairo_output_stream_printf (stream,
845 " return clamp(-abs(dim * (x - 0.5)) + (dim + 1.0) * 0.5, 0.0, 1.0);\n");
847 _cairo_output_stream_printf (stream,
848 " bool in_tex = x >= 0.0 && x < 1.0;\n"
849 " return float (in_tex);\n");
851 _cairo_output_stream_printf (stream, "}\n");
855 * Emits the wrap function used by an operand.
857 * In OpenGL ES 2.0, repeat wrap modes (GL_REPEAT and GL_MIRRORED REPEAT) are
858 * only available for NPOT textures if the GL_OES_texture_npot is supported.
859 * If GL_OES_texture_npot is not supported, we need to implement the wrapping
860 * functionality in the shader.
863 _cairo_gl_shader_emit_wrap (cairo_gl_context_t *ctx,
864 cairo_output_stream_t *stream,
865 cairo_gl_operand_t *operand,
868 const char *namestr = operand_names[name];
869 cairo_extend_t extend = _cairo_gl_operand_get_extend (operand);
870 cairo_bool_t use_atlas = _cairo_gl_operand_get_use_atlas (operand);
873 _cairo_output_stream_printf (stream,
874 "vec2 %s_wrap (vec2 coords, vec2 start_coords, vec2 stop_coords)\n"
878 _cairo_output_stream_printf (stream,
879 "vec2 %s_wrap(vec2 coords)\n"
884 if (extend == CAIRO_EXTEND_REPEAT) {
885 _cairo_output_stream_printf (stream,
886 " vec2 range = stop_coords - start_coords;\n"
887 " return mod (coords - start_coords, range) + start_coords;\n");
888 } else if (extend == CAIRO_EXTEND_REFLECT){
889 _cairo_output_stream_printf (stream,
890 " vec2 range = stop_coords - start_coords;\n"
891 " vec2 frac = mod (coords - start_coords, range);\n"
892 " return mix(frac + start_coords, range - frac + start_coords, mod(floor((coords - start_coords) / range), 2.0));\n");
894 else if (extend == CAIRO_EXTEND_PAD) {
895 _cairo_output_stream_printf (stream,
896 " bvec2 compare_to_start = lessThan (coords, start_coords);\n"
897 " bvec2 compare_to_stop = greaterThan (coords, stop_coords);\n"
898 " if (all (compare_to_start))\n"
899 " return start_coords;\n"
900 " else if (all (compare_to_stop))\n"
901 " return stop_coords;\n"
902 " else if (compare_to_start.x && compare_to_stop.y)\n"
903 " return vec2 (start_coords.x, stop_coords.y);\n"
904 " else if (compare_to_start.x && ! compare_to_stop.y)\n"
905 " return vec2 (start_coords.x, coords.y);\n"
906 " else if (compare_to_stop.x && compare_to_start.y)\n"
907 " return vec2 (stop_coords.x, start_coords.y);\n"
908 " else if (compare_to_stop.x && ! compare_to_stop.y)\n"
909 " return vec2 (stop_coords.x, coords.y);\n"
910 " else if (compare_to_start.y && ! compare_to_start.x)\n"
911 " return vec2 (coords.x, start_coords.y);\n"
912 " else if (compare_to_stop.y && ! compare_to_start.x)\n"
913 " return vec2 (coords.x, stop_coords.y);\n"
915 " return coords;\n");
918 _cairo_output_stream_printf (stream,
919 " if (any (lessThan (coords, start_coords)))\n"
920 //" return vec2 (coords - start_coords);\n"
921 " return vec2 (-1.0);\n"
922 " if (any (greaterThan (coords, stop_coords)))\n"
923 //" return vec2 (coords - stop_coords + vec2 (1.0, 1.0));\n"
924 " return vec2 (-1.0);\n"
926 " return coords;\n");
930 if (! ctx->has_npot_repeat &&
931 (extend == CAIRO_EXTEND_REPEAT ||
932 extend == CAIRO_EXTEND_REFLECT)) {
933 if (extend == CAIRO_EXTEND_REPEAT) {
934 _cairo_output_stream_printf (stream,
935 " return fract(coords);\n");
936 } else { /* CAIRO_EXTEND_REFLECT */
937 _cairo_output_stream_printf (stream,
938 " return mix(fract(coords), 1.0 - fract(coords), floor(mod(coords, 2.0)));\n");
943 _cairo_output_stream_printf (stream, " return coords;\n");
947 _cairo_output_stream_printf (stream, "}\n");
950 static cairo_status_t
951 cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
952 cairo_gl_shader_in_t in,
953 cairo_gl_operand_t *src,
954 cairo_gl_operand_t *mask,
955 cairo_bool_t use_coverage,
956 cairo_gl_operand_type_t dest_type,
959 cairo_output_stream_t *stream = _cairo_memory_stream_create ();
960 unsigned char *source;
961 unsigned long length;
962 cairo_status_t status;
963 const char *coverage_str;
965 // dy5.kim: Use highp only for gradients to handle the following test case
966 // http://w3c-test.org/html/tests/approved/canvas/2d.gradient.radial.touch1.html
967 if (src->type == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
968 src->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0 ||
969 src->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE ||
970 src->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT)
971 _cairo_output_stream_printf (stream,
973 "precision highp float;\n"
976 _cairo_output_stream_printf (stream,
978 "precision mediump float;\n"
981 _cairo_gl_shader_emit_wrap (ctx, stream, src, CAIRO_GL_TEX_SOURCE);
982 _cairo_gl_shader_emit_wrap (ctx, stream, mask, CAIRO_GL_TEX_MASK);
984 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
985 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) {
986 if (_cairo_gl_shader_needs_border_fade (src))
987 _cairo_gl_shader_emit_border_fade (stream, src, CAIRO_GL_TEX_SOURCE);
988 if (_cairo_gl_shader_needs_border_fade (mask))
989 _cairo_gl_shader_emit_border_fade (stream, mask, CAIRO_GL_TEX_MASK);
992 cairo_gl_shader_emit_color (stream, ctx, src, CAIRO_GL_TEX_SOURCE);
993 cairo_gl_shader_emit_color (stream, ctx, mask, CAIRO_GL_TEX_MASK);
997 _cairo_output_stream_printf (stream, "varying float coverage;\n");
998 coverage_str = " * coverage";
1001 _cairo_output_stream_printf (stream,
1005 case CAIRO_GL_SHADER_IN_COUNT:
1008 case CAIRO_GL_SHADER_IN_NORMAL:
1009 _cairo_output_stream_printf (stream,
1010 " gl_FragColor = get_source() * get_mask().a%s;\n",
1013 case CAIRO_GL_SHADER_IN_CA_SOURCE:
1014 _cairo_output_stream_printf (stream,
1015 " gl_FragColor = get_source() * get_mask()%s;\n",
1018 case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA:
1019 _cairo_output_stream_printf (stream,
1020 " gl_FragColor = get_source().a * get_mask()%s;\n",
1025 _cairo_output_stream_write (stream,
1028 status = _cairo_memory_stream_destroy (stream, &source, &length);
1029 if (unlikely (status)) {
1034 *out = (char *) source;
1035 return CAIRO_STATUS_SUCCESS;
1039 compile_shader (cairo_gl_context_t *ctx,
1044 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1045 GLint success, log_size, num_chars;
1048 *shader = dispatch->CreateShader (type);
1049 dispatch->ShaderSource (*shader, 1, &source, 0);
1050 dispatch->CompileShader (*shader);
1051 dispatch->GetShaderiv (*shader, GL_COMPILE_STATUS, &success);
1056 dispatch->GetShaderiv (*shader, GL_INFO_LOG_LENGTH, &log_size);
1058 printf ("OpenGL shader compilation failed.\n");
1063 log = _cairo_malloc (log_size + 1);
1065 printf ("OpenGL shader compilation failed.\n");
1069 dispatch->GetShaderInfoLog (*shader, log_size, &num_chars, log);
1070 log[num_chars] = '\0';
1072 printf ("OpenGL shader compilation failed. Shader:\n%s\n", source);
1073 printf ("OpenGL compilation log:\n%s\n", log);
1080 link_shader_program (cairo_gl_context_t *ctx,
1085 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1086 GLint success, log_size, num_chars;
1089 *program = dispatch->CreateProgram ();
1090 dispatch->AttachShader (*program, vert);
1091 dispatch->AttachShader (*program, frag);
1093 dispatch->BindAttribLocation (*program, CAIRO_GL_VERTEX_ATTRIB_INDEX,
1095 dispatch->BindAttribLocation (*program, CAIRO_GL_COLOR_ATTRIB_INDEX,
1097 dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD0_ATTRIB_INDEX,
1099 dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD1_ATTRIB_INDEX,
1101 dispatch->BindAttribLocation (*program, CAIRO_GL_START_COORD0_ATTRIB_INDEX,
1103 dispatch->BindAttribLocation (*program, CAIRO_GL_START_COORD1_ATTRIB_INDEX,
1105 dispatch->BindAttribLocation (*program, CAIRO_GL_STOP_COORD0_ATTRIB_INDEX,
1107 dispatch->BindAttribLocation (*program, CAIRO_GL_STOP_COORD1_ATTRIB_INDEX,
1110 dispatch->LinkProgram (*program);
1111 dispatch->GetProgramiv (*program, GL_LINK_STATUS, &success);
1115 dispatch->GetProgramiv (*program, GL_INFO_LOG_LENGTH, &log_size);
1117 printf ("OpenGL shader link failed.\n");
1122 log = _cairo_malloc (log_size + 1);
1124 printf ("OpenGL shader link failed.\n");
1128 dispatch->GetProgramInfoLog (*program, log_size, &num_chars, log);
1129 log[num_chars] = '\0';
1131 printf ("OpenGL shader link failed:\n%s\n", log);
1136 static cairo_status_t
1137 _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
1138 cairo_gl_shader_t *shader,
1139 cairo_gl_var_type_t src,
1140 cairo_gl_var_type_t mask,
1141 cairo_bool_t use_coverage,
1142 const char *fragment_text,
1143 cairo_extend_t src_atlas_extend,
1144 cairo_extend_t mask_atlas_extend,
1145 cairo_bool_t src_use_atlas,
1146 cairo_bool_t mask_use_atlas)
1148 unsigned int vertex_shader;
1149 cairo_status_t status;
1151 assert (shader->program == 0);
1153 vertex_shader = cairo_gl_var_type_hash (src, mask,
1160 if (ctx->vertex_shaders[vertex_shader] == 0) {
1163 status = cairo_gl_shader_get_vertex_source (src,
1170 if (unlikely (status))
1173 compile_shader (ctx, &ctx->vertex_shaders[vertex_shader],
1174 GL_VERTEX_SHADER, source);
1178 compile_shader (ctx, &shader->fragment_shader,
1179 GL_FRAGMENT_SHADER, fragment_text);
1181 link_shader_program (ctx, &shader->program,
1182 ctx->vertex_shaders[vertex_shader],
1183 shader->fragment_shader);
1185 return CAIRO_STATUS_SUCCESS;
1188 _cairo_gl_shader_fini (ctx, shader);
1189 shader->fragment_shader = 0;
1190 shader->program = 0;
1195 /* We always bind the source to texture unit 0 if present, and mask to
1196 * texture unit 1 if present, so we can just initialize these once at
1200 _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx,
1201 cairo_gl_shader_t *shader)
1203 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1205 GLint saved_program;
1207 /* We have to save/restore the current program because we might be
1208 * asked for a different program while a shader is bound. This shouldn't
1209 * be a performance issue, since this is only called once per compile.
1211 dispatch->GetIntegerv (GL_CURRENT_PROGRAM, &saved_program);
1212 dispatch->UseProgram (shader->program);
1214 location = _cairo_gl_shader_get_uniform_location (ctx, shader,
1215 CAIRO_GL_UNIFORM_SAMPLER);
1216 if (location != -1) {
1217 dispatch->Uniform1i (location, CAIRO_GL_TEX_SOURCE);
1220 location = _cairo_gl_shader_get_uniform_location (ctx, shader,
1221 CAIRO_GL_UNIFORM_MASK_SAMPLER);
1222 if (location != -1) {
1223 dispatch->Uniform1i (location, CAIRO_GL_TEX_MASK);
1226 dispatch->UseProgram (saved_program);
1230 _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
1231 cairo_gl_uniform_t uniform,
1234 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1235 GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1236 ctx->current_shader,
1238 assert (location != -1);
1239 dispatch->Uniform1f (location, value);
1243 _cairo_gl_shader_bind_int (cairo_gl_context_t *ctx,
1244 cairo_gl_uniform_t uniform,
1247 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1248 GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1249 ctx->current_shader,
1251 assert (location != -1);
1252 dispatch->Uniform1i (location, value);
1256 _cairo_gl_shader_bind_float_array (cairo_gl_context_t *ctx,
1257 cairo_gl_uniform_t uniform,
1258 int num, float *values)
1260 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1261 GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1262 ctx->current_shader,
1264 assert (location != -1);
1265 dispatch->Uniform1fv (location, num, values);
1269 _cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
1270 cairo_gl_uniform_t uniform,
1274 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1275 GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1276 ctx->current_shader,
1278 assert (location != -1);
1279 dispatch->Uniform2f (location, value0, value1);
1283 _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
1284 cairo_gl_uniform_t uniform,
1289 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1290 GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1291 ctx->current_shader,
1293 assert (location != -1);
1294 dispatch->Uniform3f (location, value0, value1, value2);
1298 _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
1299 cairo_gl_uniform_t uniform,
1300 float value0, float value1,
1301 float value2, float value3)
1303 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1304 GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1305 ctx->current_shader,
1307 assert (location != -1);
1308 dispatch->Uniform4f (location, value0, value1, value2, value3);
1312 _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
1313 cairo_gl_uniform_t uniform,
1314 const cairo_matrix_t* m)
1316 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1317 GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1318 ctx->current_shader,
1326 assert (location != -1);
1327 dispatch->UniformMatrix3fv (location, 1, GL_FALSE, gl_m);
1331 _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
1332 cairo_gl_uniform_t uniform,
1335 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1336 GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1337 ctx->current_shader,
1339 assert (location != -1);
1340 dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m);
1344 _cairo_gl_set_shader (cairo_gl_context_t *ctx,
1345 cairo_gl_shader_t *shader)
1347 if (ctx->current_shader == shader)
1351 ctx->dispatch.UseProgram (shader->program);
1353 ctx->dispatch.UseProgram (0);
1355 ctx->current_shader = shader;
1359 _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
1360 cairo_gl_operand_t *source,
1361 cairo_gl_operand_t *mask,
1362 cairo_bool_t use_coverage,
1363 cairo_gl_shader_in_t in,
1364 cairo_gl_shader_t **shader)
1366 cairo_shader_cache_entry_t lookup, *entry;
1368 cairo_status_t status;
1372 lookup.vertex = cairo_gl_var_type_hash (cairo_gl_operand_get_var_type (source),
1373 cairo_gl_operand_get_var_type (mask),
1374 _cairo_gl_operand_get_atlas_extend (source),
1375 _cairo_gl_operand_get_atlas_extend (mask),
1376 _cairo_gl_operand_get_use_atlas (source),
1377 _cairo_gl_operand_get_use_atlas (mask),
1381 lookup.src = source->type;
1382 lookup.mask = mask->type;
1383 lookup.dest = CAIRO_GL_OPERAND_NONE;
1384 lookup.use_coverage = use_coverage;
1386 lookup.src_gl_filter = _cairo_gl_operand_get_gl_filter (source);
1387 lookup.src_border_fade = _cairo_gl_shader_needs_border_fade (source);
1388 lookup.src_extend = _cairo_gl_operand_get_atlas_extend (source);
1389 lookup.mask_gl_filter = _cairo_gl_operand_get_gl_filter (mask);
1390 lookup.mask_border_fade = _cairo_gl_shader_needs_border_fade (mask);
1391 lookup.mask_extend = _cairo_gl_operand_get_atlas_extend (mask);
1392 lookup.src_use_atlas = _cairo_gl_operand_get_use_atlas (source);
1393 lookup.mask_use_atlas = _cairo_gl_operand_get_use_atlas (mask);
1394 lookup.base.hash = _cairo_gl_shader_cache_hash (&lookup);
1395 lookup.base.size = 1;
1397 entry = _cairo_cache_lookup (&ctx->shaders, &lookup.base);
1399 assert (entry->shader.program);
1400 *shader = &entry->shader;
1401 return CAIRO_STATUS_SUCCESS;
1404 status = cairo_gl_shader_get_fragment_source (ctx,
1409 CAIRO_GL_OPERAND_NONE,
1411 if (unlikely (status))
1414 entry = malloc (sizeof (cairo_shader_cache_entry_t));
1415 if (unlikely (entry == NULL)) {
1417 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1420 memcpy (entry, &lookup, sizeof (cairo_shader_cache_entry_t));
1423 _cairo_gl_shader_init (&entry->shader);
1424 status = _cairo_gl_shader_compile_and_link (ctx,
1426 cairo_gl_operand_get_var_type (source),
1427 cairo_gl_operand_get_var_type (mask),
1430 _cairo_gl_operand_get_atlas_extend (source),
1431 _cairo_gl_operand_get_atlas_extend (mask),
1432 _cairo_gl_operand_get_use_atlas (source),
1433 _cairo_gl_operand_get_use_atlas (mask));
1436 if (unlikely (status)) {
1441 _cairo_gl_shader_set_samplers (ctx, &entry->shader);
1443 status = _cairo_cache_insert (&ctx->shaders, &entry->base);
1444 if (unlikely (status)) {
1445 _cairo_gl_shader_fini (ctx, &entry->shader);
1450 *shader = &entry->shader;
1452 return CAIRO_STATUS_SUCCESS;