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_compile_and_link (cairo_gl_context_t
*ctx
,
49 cairo_gl_shader_t
*shader
,
50 cairo_gl_var_type_t src
,
51 cairo_gl_var_type_t mask
,
52 cairo_bool_t use_coverage
,
53 const char *fragment_text
);
55 typedef struct _cairo_shader_cache_entry
{
56 cairo_cache_entry_t base
;
60 cairo_gl_operand_type_t src
;
61 cairo_gl_operand_type_t mask
;
62 cairo_gl_operand_type_t dest
;
63 cairo_bool_t use_coverage
;
65 cairo_gl_shader_in_t in
;
67 cairo_bool_t src_border_fade
;
68 cairo_extend_t src_extend
;
70 cairo_bool_t mask_border_fade
;
71 cairo_extend_t mask_extend
;
73 cairo_gl_context_t
*ctx
; /* XXX: needed to destroy the program */
74 cairo_gl_shader_t shader
;
75 } cairo_shader_cache_entry_t
;
78 _cairo_gl_shader_cache_equal_desktop (const void *key_a
, const void *key_b
)
80 const cairo_shader_cache_entry_t
*a
= key_a
;
81 const cairo_shader_cache_entry_t
*b
= key_b
;
82 cairo_bool_t both_have_npot_repeat
=
83 a
->ctx
->has_npot_repeat
&& b
->ctx
->has_npot_repeat
;
85 return (a
->vertex
== b
->vertex
&&
89 a
->use_coverage
== b
->use_coverage
&&
91 (both_have_npot_repeat
|| a
->src_extend
== b
->src_extend
) &&
92 (both_have_npot_repeat
|| a
->mask_extend
== b
->mask_extend
));
96 * For GLES2 we use more complicated shaders to implement missing GL
97 * features. In this case we need more parameters to uniquely identify
98 * a shader (vs _cairo_gl_shader_cache_equal_desktop()).
101 _cairo_gl_shader_cache_equal_gles2 (const void *key_a
, const void *key_b
)
103 const cairo_shader_cache_entry_t
*a
= key_a
;
104 const cairo_shader_cache_entry_t
*b
= key_b
;
105 cairo_bool_t both_have_npot_repeat
=
106 a
->ctx
->has_npot_repeat
&& b
->ctx
->has_npot_repeat
;
108 return (a
->vertex
== b
->vertex
&&
110 a
->mask
== b
->mask
&&
111 a
->dest
== b
->dest
&&
112 a
->use_coverage
== b
->use_coverage
&&
114 a
->src_gl_filter
== b
->src_gl_filter
&&
115 a
->src_border_fade
== b
->src_border_fade
&&
116 (both_have_npot_repeat
|| a
->src_extend
== b
->src_extend
) &&
117 a
->mask_gl_filter
== b
->mask_gl_filter
&&
118 a
->mask_border_fade
== b
->mask_border_fade
&&
119 (both_have_npot_repeat
|| a
->mask_extend
== b
->mask_extend
));
123 _cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t
*entry
)
125 return ((entry
->src
<< 24) | (entry
->mask
<< 16) | (entry
->dest
<< 8) | (entry
->in
<< 1) | entry
->use_coverage
) ^ entry
->vertex
;
129 _cairo_gl_shader_cache_destroy (void *data
)
131 cairo_shader_cache_entry_t
*entry
= data
;
133 _cairo_gl_shader_fini (entry
->ctx
, &entry
->shader
);
134 if (entry
->ctx
->current_shader
== &entry
->shader
)
135 entry
->ctx
->current_shader
= NULL
;
140 _cairo_gl_shader_init (cairo_gl_shader_t
*shader
)
142 shader
->fragment_shader
= 0;
147 _cairo_gl_context_init_shaders (cairo_gl_context_t
*ctx
)
149 static const char *fill_fs_source
=
151 "precision mediump float;\n"
153 "uniform vec4 color;\n"
156 " gl_FragColor = color;\n"
158 cairo_status_t status
;
160 if (_cairo_gl_get_version () >= CAIRO_GL_VERSION_ENCODE (2, 0) ||
161 (_cairo_gl_has_extension ("GL_ARB_shader_objects") &&
162 _cairo_gl_has_extension ("GL_ARB_fragment_shader") &&
163 _cairo_gl_has_extension ("GL_ARB_vertex_shader"))) {
164 ctx
->has_shader_support
= TRUE
;
166 ctx
->has_shader_support
= FALSE
;
167 fprintf (stderr
, "Error: The cairo gl backend requires shader support!\n");
168 return CAIRO_STATUS_DEVICE_ERROR
;
171 memset (ctx
->vertex_shaders
, 0, sizeof (ctx
->vertex_shaders
));
173 status
= _cairo_cache_init (&ctx
->shaders
,
174 ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
?
175 _cairo_gl_shader_cache_equal_desktop
:
176 _cairo_gl_shader_cache_equal_gles2
,
178 _cairo_gl_shader_cache_destroy
,
179 CAIRO_GL_MAX_SHADERS_PER_CONTEXT
);
180 if (unlikely (status
))
183 _cairo_gl_shader_init (&ctx
->fill_rectangles_shader
);
184 status
= _cairo_gl_shader_compile_and_link (ctx
,
185 &ctx
->fill_rectangles_shader
,
190 if (unlikely (status
))
193 return CAIRO_STATUS_SUCCESS
;
197 _cairo_gl_context_fini_shaders (cairo_gl_context_t
*ctx
)
201 for (i
= 0; i
< CAIRO_GL_VAR_TYPE_MAX
; i
++) {
202 if (ctx
->vertex_shaders
[i
])
203 ctx
->dispatch
.DeleteShader (ctx
->vertex_shaders
[i
]);
206 _cairo_cache_fini (&ctx
->shaders
);
210 _cairo_gl_shader_fini (cairo_gl_context_t
*ctx
,
211 cairo_gl_shader_t
*shader
)
213 if (shader
->fragment_shader
)
214 ctx
->dispatch
.DeleteShader (shader
->fragment_shader
);
217 ctx
->dispatch
.DeleteProgram (shader
->program
);
220 static const char *operand_names
[] = { "source", "mask", "dest" };
222 static cairo_gl_var_type_t
223 cairo_gl_operand_get_var_type (cairo_gl_operand_t
*operand
)
225 switch (operand
->type
) {
227 case CAIRO_GL_OPERAND_COUNT
:
229 case CAIRO_GL_OPERAND_NONE
:
230 case CAIRO_GL_OPERAND_CONSTANT
:
231 return CAIRO_GL_VAR_NONE
;
232 case CAIRO_GL_OPERAND_LINEAR_GRADIENT
:
233 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0
:
234 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE
:
235 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT
:
236 return operand
->gradient
.texgen
? CAIRO_GL_VAR_TEXGEN
: CAIRO_GL_VAR_TEXCOORDS
;
237 case CAIRO_GL_OPERAND_TEXTURE
:
238 return operand
->texture
.texgen
? CAIRO_GL_VAR_TEXGEN
: CAIRO_GL_VAR_TEXCOORDS
;
243 cairo_gl_shader_emit_variable (cairo_output_stream_t
*stream
,
244 cairo_gl_var_type_t type
,
250 case CAIRO_GL_VAR_NONE
:
252 case CAIRO_GL_VAR_TEXCOORDS
:
253 _cairo_output_stream_printf (stream
,
254 "attribute vec4 MultiTexCoord%d;\n"
255 "varying vec2 %s_texcoords;\n",
257 operand_names
[name
]);
259 case CAIRO_GL_VAR_TEXGEN
:
260 _cairo_output_stream_printf (stream
,
261 "uniform mat3 %s_texgen;\n"
262 "varying vec2 %s_texcoords;\n",
264 operand_names
[name
]);
270 cairo_gl_shader_emit_vertex (cairo_output_stream_t
*stream
,
271 cairo_gl_var_type_t type
,
277 case CAIRO_GL_VAR_NONE
:
279 case CAIRO_GL_VAR_TEXCOORDS
:
280 _cairo_output_stream_printf (stream
,
281 " %s_texcoords = MultiTexCoord%d.xy;\n",
282 operand_names
[name
], name
);
285 case CAIRO_GL_VAR_TEXGEN
:
286 _cairo_output_stream_printf (stream
,
287 " %s_texcoords = (%s_texgen * Vertex.xyw).xy;\n",
288 operand_names
[name
], operand_names
[name
]);
294 cairo_gl_shader_dcl_coverage (cairo_output_stream_t
*stream
)
296 _cairo_output_stream_printf (stream
, "varying float coverage;\n");
300 cairo_gl_shader_def_coverage (cairo_output_stream_t
*stream
)
302 _cairo_output_stream_printf (stream
, " coverage = Color.a;\n");
305 static cairo_status_t
306 cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src
,
307 cairo_gl_var_type_t mask
,
308 cairo_bool_t use_coverage
,
309 cairo_gl_var_type_t dest
,
312 cairo_output_stream_t
*stream
= _cairo_memory_stream_create ();
313 unsigned char *source
;
314 unsigned long length
;
315 cairo_status_t status
;
317 cairo_gl_shader_emit_variable (stream
, src
, CAIRO_GL_TEX_SOURCE
);
318 cairo_gl_shader_emit_variable (stream
, mask
, CAIRO_GL_TEX_MASK
);
320 cairo_gl_shader_dcl_coverage (stream
);
322 _cairo_output_stream_printf (stream
,
323 "attribute vec4 Vertex;\n"
324 "attribute vec4 Color;\n"
325 "uniform mat4 ModelViewProjectionMatrix;\n"
328 " gl_Position = ModelViewProjectionMatrix * Vertex;\n");
330 cairo_gl_shader_emit_vertex (stream
, src
, CAIRO_GL_TEX_SOURCE
);
331 cairo_gl_shader_emit_vertex (stream
, mask
, CAIRO_GL_TEX_MASK
);
333 cairo_gl_shader_def_coverage (stream
);
335 _cairo_output_stream_write (stream
,
338 status
= _cairo_memory_stream_destroy (stream
, &source
, &length
);
339 if (unlikely (status
))
342 *out
= (char *) source
;
343 return CAIRO_STATUS_SUCCESS
;
347 * Returns whether an operand needs a special border fade fragment shader
348 * to simulate the GL_CLAMP_TO_BORDER wrapping method that is missing in GLES2.
351 _cairo_gl_shader_needs_border_fade (cairo_gl_operand_t
*operand
)
353 cairo_extend_t extend
=_cairo_gl_operand_get_extend (operand
);
355 return extend
== CAIRO_EXTEND_NONE
&&
356 (operand
->type
== CAIRO_GL_OPERAND_TEXTURE
||
357 operand
->type
== CAIRO_GL_OPERAND_LINEAR_GRADIENT
||
358 operand
->type
== CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE
||
359 operand
->type
== CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0
);
363 cairo_gl_shader_emit_color (cairo_output_stream_t
*stream
,
364 cairo_gl_context_t
*ctx
,
365 cairo_gl_operand_t
*op
,
368 const char *namestr
= operand_names
[name
];
369 const char *rectstr
= (ctx
->tex_target
== GL_TEXTURE_RECTANGLE
? "Rect" : "");
372 case CAIRO_GL_OPERAND_COUNT
:
376 case CAIRO_GL_OPERAND_NONE
:
377 _cairo_output_stream_printf (stream
,
380 " return vec4 (0, 0, 0, 1);\n"
384 case CAIRO_GL_OPERAND_CONSTANT
:
385 _cairo_output_stream_printf (stream
,
386 "uniform vec4 %s_constant;\n"
389 " return %s_constant;\n"
391 namestr
, namestr
, namestr
);
393 case CAIRO_GL_OPERAND_TEXTURE
:
394 _cairo_output_stream_printf (stream
,
395 "uniform sampler2D%s %s_sampler;\n"
396 "uniform vec2 %s_texdims;\n"
397 "varying vec2 %s_texcoords;\n"
400 rectstr
, namestr
, namestr
, namestr
, namestr
);
401 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
&&
402 _cairo_gl_shader_needs_border_fade (op
))
404 _cairo_output_stream_printf (stream
,
405 " vec2 border_fade = %s_border_fade (%s_texcoords, %s_texdims);\n"
406 " vec4 texel = texture2D%s (%s_sampler, %s_texcoords);\n"
407 " return texel * border_fade.x * border_fade.y;\n"
409 namestr
, namestr
, namestr
, rectstr
, namestr
, namestr
);
413 _cairo_output_stream_printf (stream
,
414 " return texture2D%s (%s_sampler, %s_wrap (%s_texcoords));\n"
416 rectstr
, namestr
, namestr
, namestr
);
419 case CAIRO_GL_OPERAND_LINEAR_GRADIENT
:
420 _cairo_output_stream_printf (stream
,
421 "varying vec2 %s_texcoords;\n"
422 "uniform vec2 %s_texdims;\n"
423 "uniform sampler2D%s %s_sampler;\n"
427 namestr
, namestr
, rectstr
, namestr
, namestr
);
428 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
&&
429 _cairo_gl_shader_needs_border_fade (op
))
431 _cairo_output_stream_printf (stream
,
432 " float border_fade = %s_border_fade (%s_texcoords.x, %s_texdims.x);\n"
433 " vec4 texel = texture2D%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n"
434 " return texel * border_fade;\n"
436 namestr
, namestr
, namestr
, rectstr
, namestr
, namestr
);
440 _cairo_output_stream_printf (stream
,
441 " return texture2D%s (%s_sampler, %s_wrap (vec2 (%s_texcoords.x, 0.5)));\n"
443 rectstr
, namestr
, namestr
, namestr
);
446 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0
:
447 _cairo_output_stream_printf (stream
,
448 "varying vec2 %s_texcoords;\n"
449 "uniform vec2 %s_texdims;\n"
450 "uniform sampler2D%s %s_sampler;\n"
451 "uniform vec3 %s_circle_d;\n"
452 "uniform float %s_radius_0;\n"
456 " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
458 " float B = dot (pos, %s_circle_d);\n"
459 " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
461 " float t = 0.5 * C / B;\n"
462 " float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n",
463 namestr
, namestr
, rectstr
, namestr
, namestr
, namestr
, namestr
,
464 namestr
, namestr
, namestr
, namestr
, namestr
);
465 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
&&
466 _cairo_gl_shader_needs_border_fade (op
))
468 _cairo_output_stream_printf (stream
,
469 " float border_fade = %s_border_fade (t, %s_texdims.x);\n"
470 " vec4 texel = texture2D%s (%s_sampler, vec2 (t, 0.5));\n"
471 " return mix (vec4 (0.0), texel * border_fade, is_valid);\n"
473 namestr
, namestr
, rectstr
, namestr
);
477 _cairo_output_stream_printf (stream
,
478 " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2 (t, 0.5)));\n"
479 " return mix (vec4 (0.0), texel, is_valid);\n"
481 rectstr
, namestr
, namestr
);
484 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE
:
485 _cairo_output_stream_printf (stream
,
486 "varying vec2 %s_texcoords;\n"
487 "uniform vec2 %s_texdims;\n"
488 "uniform sampler2D%s %s_sampler;\n"
489 "uniform vec3 %s_circle_d;\n"
490 "uniform float %s_a;\n"
491 "uniform float %s_radius_0;\n"
495 " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
497 " float B = dot (pos, %s_circle_d);\n"
498 " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
500 " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n"
501 " float sqrtdet = sqrt (abs (det));\n"
502 " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
504 " vec2 is_valid = step (vec2 (0.0), t) * step (t, vec2(1.0));\n"
505 " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
507 " float upper_t = mix (t.y, t.x, is_valid.x);\n",
508 namestr
, namestr
, rectstr
, namestr
, namestr
, namestr
, namestr
,
509 namestr
, namestr
, namestr
, namestr
, namestr
, namestr
);
510 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
&&
511 _cairo_gl_shader_needs_border_fade (op
))
513 _cairo_output_stream_printf (stream
,
514 " float border_fade = %s_border_fade (upper_t, %s_texdims.x);\n"
515 " vec4 texel = texture2D%s (%s_sampler, vec2 (upper_t, 0.5));\n"
516 " return mix (vec4 (0.0), texel * border_fade, has_color);\n"
518 namestr
, namestr
, rectstr
, namestr
);
522 _cairo_output_stream_printf (stream
,
523 " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
524 " return mix (vec4 (0.0), texel, has_color);\n"
526 rectstr
, namestr
, namestr
);
529 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT
:
530 _cairo_output_stream_printf (stream
,
531 "varying vec2 %s_texcoords;\n"
532 "uniform sampler2D%s %s_sampler;\n"
533 "uniform vec3 %s_circle_d;\n"
534 "uniform float %s_a;\n"
535 "uniform float %s_radius_0;\n"
539 " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
541 " float B = dot (pos, %s_circle_d);\n"
542 " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
544 " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n"
545 " float sqrtdet = sqrt (abs (det));\n"
546 " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
548 " vec2 is_valid = step (vec2 (-%s_radius_0), t * %s_circle_d.z);\n"
549 " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
551 " float upper_t = mix (t.y, t.x, is_valid.x);\n"
552 " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
553 " return mix (vec4 (0.0), texel, has_color);\n"
555 namestr
, rectstr
, namestr
, namestr
, namestr
, namestr
,
556 namestr
, namestr
, namestr
, namestr
, namestr
,
557 namestr
, namestr
, namestr
, rectstr
, namestr
, namestr
);
563 * Emits the border fade functions used by an operand.
565 * If bilinear filtering is used, the emitted function performs a linear
566 * fade to transparency effect in the intervals [-1/2n, 1/2n] and
567 * [1 - 1/2n, 1 + 1/2n] (n: texture size).
569 * If nearest filtering is used, the emitted function just returns
570 * 0.0 for all values outside [0, 1).
573 _cairo_gl_shader_emit_border_fade (cairo_output_stream_t
*stream
,
574 cairo_gl_operand_t
*operand
,
577 const char *namestr
= operand_names
[name
];
578 GLint gl_filter
= _cairo_gl_operand_get_gl_filter (operand
);
581 _cairo_output_stream_printf (stream
,
582 "vec2 %s_border_fade (vec2 coords, vec2 dims)\n"
586 if (gl_filter
== GL_LINEAR
)
587 _cairo_output_stream_printf (stream
,
588 " return clamp(-abs(dims * (coords - 0.5)) + (dims + vec2(1.0)) * 0.5, 0.0, 1.0);\n");
590 _cairo_output_stream_printf (stream
,
591 " bvec2 in_tex1 = greaterThanEqual (coords, vec2 (0.0));\n"
592 " bvec2 in_tex2 = lessThan (coords, vec2 (1.0));\n"
593 " return vec2 (float (all (in_tex1) && all (in_tex2)));\n");
595 _cairo_output_stream_printf (stream
, "}\n");
598 _cairo_output_stream_printf (stream
,
599 "float %s_border_fade (float x, float dim)\n"
602 if (gl_filter
== GL_LINEAR
)
603 _cairo_output_stream_printf (stream
,
604 " return clamp(-abs(dim * (x - 0.5)) + (dim + 1.0) * 0.5, 0.0, 1.0);\n");
606 _cairo_output_stream_printf (stream
,
607 " bool in_tex = x >= 0.0 && x < 1.0;\n"
608 " return float (in_tex);\n");
610 _cairo_output_stream_printf (stream
, "}\n");
614 * Emits the wrap function used by an operand.
616 * In OpenGL ES 2.0, repeat wrap modes (GL_REPEAT and GL_MIRRORED REPEAT) are
617 * only available for NPOT textures if the GL_OES_texture_npot is supported.
618 * If GL_OES_texture_npot is not supported, we need to implement the wrapping
619 * functionality in the shader.
622 _cairo_gl_shader_emit_wrap (cairo_gl_context_t
*ctx
,
623 cairo_output_stream_t
*stream
,
624 cairo_gl_operand_t
*operand
,
627 const char *namestr
= operand_names
[name
];
628 cairo_extend_t extend
= _cairo_gl_operand_get_extend (operand
);
630 _cairo_output_stream_printf (stream
,
631 "vec2 %s_wrap(vec2 coords)\n"
635 if (! ctx
->has_npot_repeat
&&
636 (extend
== CAIRO_EXTEND_REPEAT
|| extend
== CAIRO_EXTEND_REFLECT
))
638 if (extend
== CAIRO_EXTEND_REPEAT
) {
639 _cairo_output_stream_printf (stream
,
640 " return fract(coords);\n");
641 } else { /* CAIRO_EXTEND_REFLECT */
642 _cairo_output_stream_printf (stream
,
643 " return mix(fract(coords), 1.0 - fract(coords), floor(mod(coords, 2.0)));\n");
648 _cairo_output_stream_printf (stream
, " return coords;\n");
651 _cairo_output_stream_printf (stream
, "}\n");
654 static cairo_status_t
655 cairo_gl_shader_get_fragment_source (cairo_gl_context_t
*ctx
,
656 cairo_gl_shader_in_t in
,
657 cairo_gl_operand_t
*src
,
658 cairo_gl_operand_t
*mask
,
659 cairo_bool_t use_coverage
,
660 cairo_gl_operand_type_t dest_type
,
663 cairo_output_stream_t
*stream
= _cairo_memory_stream_create ();
664 unsigned char *source
;
665 unsigned long length
;
666 cairo_status_t status
;
667 const char *coverage_str
;
669 _cairo_output_stream_printf (stream
,
671 "precision mediump float;\n"
674 _cairo_gl_shader_emit_wrap (ctx
, stream
, src
, CAIRO_GL_TEX_SOURCE
);
675 _cairo_gl_shader_emit_wrap (ctx
, stream
, mask
, CAIRO_GL_TEX_MASK
);
677 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
) {
678 if (_cairo_gl_shader_needs_border_fade (src
))
679 _cairo_gl_shader_emit_border_fade (stream
, src
, CAIRO_GL_TEX_SOURCE
);
680 if (_cairo_gl_shader_needs_border_fade (mask
))
681 _cairo_gl_shader_emit_border_fade (stream
, mask
, CAIRO_GL_TEX_MASK
);
684 cairo_gl_shader_emit_color (stream
, ctx
, src
, CAIRO_GL_TEX_SOURCE
);
685 cairo_gl_shader_emit_color (stream
, ctx
, mask
, CAIRO_GL_TEX_MASK
);
689 _cairo_output_stream_printf (stream
, "varying float coverage;\n");
690 coverage_str
= " * coverage";
693 _cairo_output_stream_printf (stream
,
697 case CAIRO_GL_SHADER_IN_COUNT
:
700 case CAIRO_GL_SHADER_IN_NORMAL
:
701 _cairo_output_stream_printf (stream
,
702 " gl_FragColor = get_source() * get_mask().a%s;\n",
705 case CAIRO_GL_SHADER_IN_CA_SOURCE
:
706 _cairo_output_stream_printf (stream
,
707 " gl_FragColor = get_source() * get_mask()%s;\n",
710 case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA
:
711 _cairo_output_stream_printf (stream
,
712 " gl_FragColor = get_source().a * get_mask()%s;\n",
717 _cairo_output_stream_write (stream
,
720 status
= _cairo_memory_stream_destroy (stream
, &source
, &length
);
721 if (unlikely (status
))
724 *out
= (char *) source
;
725 return CAIRO_STATUS_SUCCESS
;
729 compile_shader (cairo_gl_context_t
*ctx
,
734 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
735 GLint success
, log_size
, num_chars
;
738 *shader
= dispatch
->CreateShader (type
);
739 dispatch
->ShaderSource (*shader
, 1, &source
, 0);
740 dispatch
->CompileShader (*shader
);
741 dispatch
->GetShaderiv (*shader
, GL_COMPILE_STATUS
, &success
);
746 dispatch
->GetShaderiv (*shader
, GL_INFO_LOG_LENGTH
, &log_size
);
748 printf ("OpenGL shader compilation failed.\n");
753 log
= _cairo_malloc (log_size
+ 1);
754 dispatch
->GetShaderInfoLog (*shader
, log_size
, &num_chars
, log
);
755 log
[num_chars
] = '\0';
757 printf ("OpenGL shader compilation failed. Shader:\n%s\n", source
);
758 printf ("OpenGL compilation log:\n%s\n", log
);
765 link_shader_program (cairo_gl_context_t
*ctx
,
770 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
771 GLint success
, log_size
, num_chars
;
774 *program
= dispatch
->CreateProgram ();
775 dispatch
->AttachShader (*program
, vert
);
776 dispatch
->AttachShader (*program
, frag
);
778 dispatch
->BindAttribLocation (*program
, CAIRO_GL_VERTEX_ATTRIB_INDEX
,
780 dispatch
->BindAttribLocation (*program
, CAIRO_GL_COLOR_ATTRIB_INDEX
,
782 dispatch
->BindAttribLocation (*program
, CAIRO_GL_TEXCOORD0_ATTRIB_INDEX
,
784 dispatch
->BindAttribLocation (*program
, CAIRO_GL_TEXCOORD1_ATTRIB_INDEX
,
787 dispatch
->LinkProgram (*program
);
788 dispatch
->GetProgramiv (*program
, GL_LINK_STATUS
, &success
);
792 dispatch
->GetProgramiv (*program
, GL_INFO_LOG_LENGTH
, &log_size
);
794 printf ("OpenGL shader link failed.\n");
799 log
= _cairo_malloc (log_size
+ 1);
800 dispatch
->GetProgramInfoLog (*program
, log_size
, &num_chars
, log
);
801 log
[num_chars
] = '\0';
803 printf ("OpenGL shader link failed:\n%s\n", log
);
809 _cairo_gl_get_op_uniform_location(cairo_gl_context_t
*ctx
,
810 cairo_gl_shader_t
*shader
,
811 cairo_gl_tex_t tex_unit
,
814 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
815 char uniform_name
[100];
816 const char *unit_name
[2] = { "source", "mask" };
818 snprintf (uniform_name
, sizeof (uniform_name
), "%s_%s",
819 unit_name
[tex_unit
], suffix
);
821 return dispatch
->GetUniformLocation (shader
->program
, uniform_name
);
824 static cairo_status_t
825 _cairo_gl_shader_compile_and_link (cairo_gl_context_t
*ctx
,
826 cairo_gl_shader_t
*shader
,
827 cairo_gl_var_type_t src
,
828 cairo_gl_var_type_t mask
,
829 cairo_bool_t use_coverage
,
830 const char *fragment_text
)
832 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
833 unsigned int vertex_shader
;
834 cairo_status_t status
;
837 assert (shader
->program
== 0);
839 vertex_shader
= cairo_gl_var_type_hash (src
, mask
, use_coverage
,
841 if (ctx
->vertex_shaders
[vertex_shader
] == 0) {
844 status
= cairo_gl_shader_get_vertex_source (src
,
849 if (unlikely (status
))
852 compile_shader (ctx
, &ctx
->vertex_shaders
[vertex_shader
],
853 GL_VERTEX_SHADER
, source
);
857 compile_shader (ctx
, &shader
->fragment_shader
,
858 GL_FRAGMENT_SHADER
, fragment_text
);
860 link_shader_program (ctx
, &shader
->program
,
861 ctx
->vertex_shaders
[vertex_shader
],
862 shader
->fragment_shader
);
864 shader
->mvp_location
=
865 dispatch
->GetUniformLocation (shader
->program
,
866 "ModelViewProjectionMatrix");
868 for (i
= 0; i
< 2; i
++) {
869 shader
->constant_location
[i
] =
870 _cairo_gl_get_op_uniform_location (ctx
, shader
, i
, "constant");
871 shader
->a_location
[i
] =
872 _cairo_gl_get_op_uniform_location (ctx
, shader
, i
, "a");
873 shader
->circle_d_location
[i
] =
874 _cairo_gl_get_op_uniform_location (ctx
, shader
, i
, "circle_d");
875 shader
->radius_0_location
[i
] =
876 _cairo_gl_get_op_uniform_location (ctx
, shader
, i
, "radius_0");
877 shader
->texdims_location
[i
] =
878 _cairo_gl_get_op_uniform_location (ctx
, shader
, i
, "texdims");
879 shader
->texgen_location
[i
] =
880 _cairo_gl_get_op_uniform_location (ctx
, shader
, i
, "texgen");
883 return CAIRO_STATUS_SUCCESS
;
886 _cairo_gl_shader_fini (ctx
, shader
);
887 shader
->fragment_shader
= 0;
893 /* We always bind the source to texture unit 0 if present, and mask to
894 * texture unit 1 if present, so we can just initialize these once at
898 _cairo_gl_shader_set_samplers (cairo_gl_context_t
*ctx
,
899 cairo_gl_shader_t
*shader
)
901 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
905 /* We have to save/restore the current program because we might be
906 * asked for a different program while a shader is bound. This shouldn't
907 * be a performance issue, since this is only called once per compile.
909 glGetIntegerv (GL_CURRENT_PROGRAM
, &saved_program
);
910 dispatch
->UseProgram (shader
->program
);
912 location
= dispatch
->GetUniformLocation (shader
->program
, "source_sampler");
913 if (location
!= -1) {
914 dispatch
->Uniform1i (location
, CAIRO_GL_TEX_SOURCE
);
917 location
= dispatch
->GetUniformLocation (shader
->program
, "mask_sampler");
918 if (location
!= -1) {
919 dispatch
->Uniform1i (location
, CAIRO_GL_TEX_MASK
);
922 dispatch
->UseProgram (saved_program
);
926 _cairo_gl_shader_bind_float (cairo_gl_context_t
*ctx
,
930 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
931 assert (location
!= -1);
932 dispatch
->Uniform1f (location
, value
);
936 _cairo_gl_shader_bind_vec2 (cairo_gl_context_t
*ctx
,
941 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
942 assert (location
!= -1);
943 dispatch
->Uniform2f (location
, value0
, value1
);
947 _cairo_gl_shader_bind_vec3 (cairo_gl_context_t
*ctx
,
953 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
954 assert (location
!= -1);
955 dispatch
->Uniform3f (location
, value0
, value1
, value2
);
959 _cairo_gl_shader_bind_vec4 (cairo_gl_context_t
*ctx
,
961 float value0
, float value1
,
962 float value2
, float value3
)
964 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
965 assert (location
!= -1);
966 dispatch
->Uniform4f (location
, value0
, value1
, value2
, value3
);
970 _cairo_gl_shader_bind_matrix (cairo_gl_context_t
*ctx
,
972 const cairo_matrix_t
* m
)
974 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
980 assert (location
!= -1);
981 dispatch
->UniformMatrix3fv (location
, 1, GL_FALSE
, gl_m
);
985 _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t
*ctx
,
986 GLint location
, GLfloat
* gl_m
)
988 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
989 assert (location
!= -1);
990 dispatch
->UniformMatrix4fv (location
, 1, GL_FALSE
, gl_m
);
994 _cairo_gl_set_shader (cairo_gl_context_t
*ctx
,
995 cairo_gl_shader_t
*shader
)
997 if (ctx
->current_shader
== shader
)
1001 ctx
->dispatch
.UseProgram (shader
->program
);
1003 ctx
->dispatch
.UseProgram (0);
1005 ctx
->current_shader
= shader
;
1009 _cairo_gl_get_shader_by_type (cairo_gl_context_t
*ctx
,
1010 cairo_gl_operand_t
*source
,
1011 cairo_gl_operand_t
*mask
,
1012 cairo_bool_t use_coverage
,
1013 cairo_gl_shader_in_t in
,
1014 cairo_gl_shader_t
**shader
)
1016 cairo_shader_cache_entry_t lookup
, *entry
;
1018 cairo_status_t status
;
1022 lookup
.vertex
= cairo_gl_var_type_hash (cairo_gl_operand_get_var_type (source
),
1023 cairo_gl_operand_get_var_type (mask
),
1027 lookup
.src
= source
->type
;
1028 lookup
.mask
= mask
->type
;
1029 lookup
.dest
= CAIRO_GL_OPERAND_NONE
;
1030 lookup
.use_coverage
= use_coverage
;
1032 lookup
.src_gl_filter
= _cairo_gl_operand_get_gl_filter (source
);
1033 lookup
.src_border_fade
= _cairo_gl_shader_needs_border_fade (source
);
1034 lookup
.src_extend
= _cairo_gl_operand_get_extend (source
);
1035 lookup
.mask_gl_filter
= _cairo_gl_operand_get_gl_filter (mask
);
1036 lookup
.mask_border_fade
= _cairo_gl_shader_needs_border_fade (mask
);
1037 lookup
.mask_extend
= _cairo_gl_operand_get_extend (mask
);
1038 lookup
.base
.hash
= _cairo_gl_shader_cache_hash (&lookup
);
1039 lookup
.base
.size
= 1;
1041 entry
= _cairo_cache_lookup (&ctx
->shaders
, &lookup
.base
);
1043 assert (entry
->shader
.program
);
1044 *shader
= &entry
->shader
;
1045 return CAIRO_STATUS_SUCCESS
;
1048 status
= cairo_gl_shader_get_fragment_source (ctx
,
1053 CAIRO_GL_OPERAND_NONE
,
1055 if (unlikely (status
))
1058 entry
= malloc (sizeof (cairo_shader_cache_entry_t
));
1059 if (unlikely (entry
== NULL
)) {
1061 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1064 memcpy (entry
, &lookup
, sizeof (cairo_shader_cache_entry_t
));
1067 _cairo_gl_shader_init (&entry
->shader
);
1068 status
= _cairo_gl_shader_compile_and_link (ctx
,
1070 cairo_gl_operand_get_var_type (source
),
1071 cairo_gl_operand_get_var_type (mask
),
1076 if (unlikely (status
)) {
1081 _cairo_gl_shader_set_samplers (ctx
, &entry
->shader
);
1083 status
= _cairo_cache_insert (&ctx
->shaders
, &entry
->base
);
1084 if (unlikely (status
)) {
1085 _cairo_gl_shader_fini (ctx
, &entry
->shader
);
1090 *shader
= &entry
->shader
;
1092 return CAIRO_STATUS_SUCCESS
;