tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-gl-shaders.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 T. Zachary Laine
4  * Copyright © 2010 Eric Anholt
5  * Copyright © 2010 Red Hat, Inc
6  * Copyright © 2010 Linaro Limited
7  *
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.
15  *
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
21  *
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/
26  *
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.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is T. Zachary Laine.
34  *
35  * Contributor(s):
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>
40  */
41
42 #include "cairoint.h"
43 #include "cairo-gl-private.h"
44 #include "cairo-error-private.h"
45 #include "cairo-output-stream-private.h"
46
47 static GLint
48 _cairo_gl_shader_get_uniform_location (cairo_gl_context_t *ctx,
49                                        cairo_gl_shader_t *shader,
50                                        cairo_gl_uniform_t uniform)
51 {
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] = {
55         "source_texdims",
56         "source_texgen",
57         "source_constant",
58         "source_sampler",
59         "source_a",
60         "source_circle_d",
61         "source_radius_0",
62         "source_blur_radius",
63         "source_blurs",
64         "source_blur_step",
65         "source_blur_x_axis",
66         "source_blur_y_axis",
67         "source_alpha",
68         "mask_texdims",
69         "mask_texgen",
70         "mask_constant",
71         "mask_sampler",
72         "mask_a",
73         "mask_circle_d",
74         "mask_radius_0",
75         "mask_blur_radius",
76         "mask_blurs",
77         "mask_blur_step",
78         "mask_blur_x_axis",
79         "mask_blur_y_axis",
80         "mask_alpha",
81         "ModelViewProjectionMatrix"
82     };
83
84     if (shader->uniforms[uniform] != -1)
85         return shader->uniforms[uniform];
86
87     shader->uniforms[uniform] =
88         ctx->dispatch.GetUniformLocation (shader->program,
89                                           names[uniform]);
90     return shader->uniforms[uniform];
91 }
92
93 cairo_gl_uniform_t
94 _cairo_gl_shader_uniform_for_texunit (cairo_gl_uniform_t uniform,
95                                       cairo_gl_tex_t tex_unit)
96 {
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)
100         return uniform;
101     else
102         return uniform + CAIRO_GL_UNIFORM_MASK_TEXDIMS;
103 }
104
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);
116
117 typedef struct _cairo_shader_cache_entry {
118     cairo_cache_entry_t base;
119
120     unsigned vertex;
121
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;
126
127     cairo_gl_shader_in_t in;
128     GLint src_gl_filter;
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;
134
135     cairo_bool_t src_use_atlas;
136     cairo_bool_t mask_use_atlas;
137
138     cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */
139     cairo_gl_shader_t shader;
140 } cairo_shader_cache_entry_t;
141
142 static cairo_bool_t
143 _cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b)
144 {
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;
149
150     return (a->vertex == b->vertex &&
151             a->src  == b->src  &&
152             a->mask == b->mask &&
153             a->dest == b->dest &&
154             a->use_coverage == b->use_coverage &&
155             a->in   == b->in &&
156             (both_have_npot_repeat || a->src_extend == b->src_extend) &&
157             (both_have_npot_repeat || a->mask_extend == b->mask_extend));
158 }
159
160 /*
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()).
164  */
165 static cairo_bool_t
166 _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
167 {
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;
172
173     return (a->vertex == b->vertex &&
174             a->src  == b->src  &&
175             a->mask == b->mask &&
176             a->dest == b->dest &&
177             a->use_coverage == b->use_coverage &&
178             a->in   == b->in   &&
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));
185 }
186
187 static unsigned long
188 _cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry)
189 {
190     return ((entry->src << 15) |
191             (entry->mask << 12) |
192             (entry->dest << 9) |
193             (entry->in << 7) |
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;
199 }
200
201 static void
202 _cairo_gl_shader_cache_destroy (void *data)
203 {
204     cairo_shader_cache_entry_t *entry = data;
205
206     _cairo_gl_shader_fini (entry->ctx, &entry->shader);
207     if (entry->ctx->current_shader == &entry->shader)
208         entry->ctx->current_shader = NULL;
209     free (entry);
210 }
211
212 static void
213 _cairo_gl_shader_init (cairo_gl_shader_t *shader)
214 {
215     int i;
216     shader->fragment_shader = 0;
217     shader->program = 0;
218
219     for (i = 0; i < CAIRO_GL_UNIFORM_MAX; i++)
220         shader->uniforms[i] = -1;
221 }
222
223 cairo_status_t
224 _cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
225 {
226     static const char *fill_fs_source =
227         "#ifdef GL_ES\n"
228         "precision mediump float;\n"
229         "#endif\n"
230         "uniform vec4 color;\n"
231         "void main()\n"
232         "{\n"
233         "       gl_FragColor = color;\n"
234         "}\n";
235     cairo_status_t status;
236
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;
242     } else {
243         ctx->has_shader_support = FALSE;
244         fprintf (stderr, "Error: The cairo gl backend requires shader support!\n");
245         return CAIRO_STATUS_DEVICE_ERROR;
246     }
247
248     memset (ctx->vertex_shaders, 0, sizeof (ctx->vertex_shaders));
249
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,
254                                 NULL,
255                                 _cairo_gl_shader_cache_destroy,
256                                 CAIRO_GL_MAX_SHADERS_PER_CONTEXT);
257     if (unlikely (status))
258         return status;
259
260     _cairo_gl_shader_init (&ctx->fill_rectangles_shader);
261     status = _cairo_gl_shader_compile_and_link (ctx,
262                                                 &ctx->fill_rectangles_shader,
263                                                 CAIRO_GL_VAR_NONE,
264                                                 CAIRO_GL_VAR_NONE,
265                                                 FALSE,
266                                                 fill_fs_source,
267                                                 CAIRO_EXTEND_NONE, CAIRO_EXTEND_NONE,
268                                                 FALSE, FALSE);
269     if (unlikely (status))
270         return status;
271
272     return CAIRO_STATUS_SUCCESS;
273 }
274
275 void
276 _cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx)
277 {
278     int i;
279
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]);
283     }
284
285     _cairo_cache_fini (&ctx->shaders);
286 }
287
288 void
289 _cairo_gl_shader_fini (cairo_gl_context_t *ctx,
290                        cairo_gl_shader_t *shader)
291 {
292     if (shader->fragment_shader)
293         ctx->dispatch.DeleteShader (shader->fragment_shader);
294
295     if (shader->program)
296         ctx->dispatch.DeleteProgram (shader->program);
297 }
298
299 static const char *operand_names[] = { "source", "mask", "dest" };
300
301 static cairo_gl_var_type_t
302 cairo_gl_operand_get_var_type (cairo_gl_operand_t *operand)
303 {
304     switch (operand->type) {
305     default:
306     case CAIRO_GL_OPERAND_COUNT:
307         ASSERT_NOT_REACHED;
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;
312         else
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;
322     }
323 }
324
325 static void
326 cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
327                                cairo_gl_var_type_t type,
328                                cairo_gl_tex_t name,
329                                cairo_bool_t use_atlas)
330 {
331     switch (type) {
332     default:
333         ASSERT_NOT_REACHED;
334     case CAIRO_GL_VAR_NONE:
335         break;
336     case CAIRO_GL_VAR_TEXCOORDS:
337         _cairo_output_stream_printf (stream,
338                                      "attribute vec4 MultiTexCoord%d;\n"
339                                      "varying vec2 %s_texcoords;\n",
340                                      name,
341                                      operand_names[name]);
342         if (use_atlas)
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]);
347         break;
348     case CAIRO_GL_VAR_TEXGEN:
349         _cairo_output_stream_printf (stream,
350                                      "uniform mat3 %s_texgen;\n"
351                                      "varying vec2 %s_texcoords;\n",
352                                      operand_names[name],
353                                      operand_names[name]);
354         /*if (use_atlas)
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]);
359 */
360         break;
361     case CAIRO_GL_VAR_COLOR:
362         _cairo_output_stream_printf (stream,
363                                      "varying vec4 fragment_color;\n");
364         break;
365     }
366 }
367
368 static void
369 cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
370                              cairo_gl_var_type_t type,
371                              cairo_gl_tex_t name)
372 {
373     switch (type) {
374     default:
375         ASSERT_NOT_REACHED;
376     case CAIRO_GL_VAR_NONE:
377         break;
378     case CAIRO_GL_VAR_TEXCOORDS:
379         _cairo_output_stream_printf (stream,
380                                      "    %s_texcoords = MultiTexCoord%d.xy;\n",
381                                      operand_names[name], name);
382         break;
383
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]);
388         break;
389     case CAIRO_GL_VAR_COLOR:
390         _cairo_output_stream_printf (stream, "    fragment_color = Color;\n");
391         break;
392     }
393 }
394
395 static void
396 cairo_gl_shader_dcl_coverage (cairo_output_stream_t *stream)
397 {
398     _cairo_output_stream_printf (stream, "varying float coverage;\n");
399 }
400
401 static void
402 cairo_gl_shader_def_coverage (cairo_output_stream_t *stream)
403 {
404     _cairo_output_stream_printf (stream, "    coverage = Color.a;\n");
405 }
406
407 static void
408 cairo_gl_shader_def_use_atlas (cairo_output_stream_t *stream,
409                                cairo_gl_var_type_t type,
410                                cairo_gl_tex_t name)
411 {
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);
417 }
418
419 static void
420 cairo_gl_shader_emit_varying (cairo_output_stream_t *stream,
421                               cairo_gl_tex_t name)
422 {
423     const char *namestr = operand_names[name];
424
425     _cairo_output_stream_printf (stream,
426         "varying vec2 %s_start_coords;\n"
427         "varying vec2 %s_stop_coords;\n",
428         namestr, namestr);
429 }
430
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,
438                                    char **out)
439 {
440     cairo_output_stream_t *stream = _cairo_memory_stream_create ();
441     unsigned char *source;
442     unsigned long length;
443     cairo_status_t status;
444
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);
447     if (use_coverage)
448         cairo_gl_shader_dcl_coverage (stream);
449
450     if (src_use_atlas && src == CAIRO_GL_VAR_TEXGEN)
451         cairo_gl_shader_emit_varying (stream, CAIRO_GL_TEX_SOURCE);
452
453     if (mask_use_atlas && mask == CAIRO_GL_VAR_TEXGEN)
454         cairo_gl_shader_emit_varying (stream, CAIRO_GL_TEX_MASK);
455
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"
464                                  "void main()\n"
465                                  "{\n"
466                                  "    gl_Position = ModelViewProjectionMatrix * Vertex;\n");
467
468     cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE);
469     cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK);
470     if (use_coverage)
471         cairo_gl_shader_def_coverage (stream);
472
473     if (src_use_atlas)
474         cairo_gl_shader_def_use_atlas (stream, src, CAIRO_GL_TEX_SOURCE);
475     if (mask_use_atlas)
476         cairo_gl_shader_def_use_atlas (stream, mask, CAIRO_GL_TEX_MASK);
477
478     _cairo_output_stream_write (stream,
479                                 "}\n\0", 3);
480
481     status = _cairo_memory_stream_destroy (stream, &source, &length);
482     if (unlikely (status)) {
483         free (source);
484         return status;
485     }
486
487     *out = (char *) source;
488     return CAIRO_STATUS_SUCCESS;
489 }
490
491 /*
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.
494  */
495 static cairo_bool_t
496 _cairo_gl_shader_needs_border_fade (cairo_gl_operand_t *operand)
497 {
498     cairo_extend_t extend =_cairo_gl_operand_get_extend (operand);
499
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);
506 }
507
508 static void
509 cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
510                             cairo_gl_context_t *ctx,
511                             cairo_gl_operand_t *op,
512                             cairo_gl_tex_t name)
513 {
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);
517
518     switch (op->type) {
519     case CAIRO_GL_OPERAND_COUNT:
520     default:
521         ASSERT_NOT_REACHED;
522         break;
523     case CAIRO_GL_OPERAND_NONE:
524         _cairo_output_stream_printf (stream,
525             "vec4 get_%s()\n"
526             "{\n"
527             "    return vec4 (0, 0, 0, 1);\n"
528             "}\n",
529             namestr);
530         break;
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"
535                 "vec4 get_%s()\n"
536                 "{\n"
537                 "    return fragment_color;\n"
538                 "}\n",
539                 namestr);
540         } else {
541             _cairo_output_stream_printf (stream,
542                 "uniform vec4 %s_constant;\n"
543                 "vec4 get_%s()\n"
544                 "{\n"
545                 "    return %s_constant;\n"
546                 "}\n",
547                 namestr, namestr, namestr);
548         }
549             break;
550     case CAIRO_GL_OPERAND_TEXTURE:
551     case CAIRO_GL_OPERAND_GAUSSIAN:
552         if (! use_atlas) {
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);
558         } else {
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);
566         }
567
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);
577         }
578
579         _cairo_output_stream_printf (stream,
580             "vec4 get_%s()\n"
581             "{\n",
582             namestr);
583
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))
588             {
589                 if (! use_atlas) {
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"
594                         "}\n",
595                         namestr, namestr, namestr, rectstr, namestr, namestr);
596                 }
597                 else {
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"
605                         "}\n",
606                         namestr, namestr, namestr, namestr,
607                         namestr, namestr, namestr, rectstr, namestr);
608                 }
609             }
610             else
611             {
612                 if (! use_atlas) {
613                     _cairo_output_stream_printf (stream,
614                         "    return texture2D%s (%s_sampler, %s_wrap (%s_texcoords));\n"
615                         "}\n",
616                         rectstr, namestr, namestr, namestr);
617                 } else {
618                     _cairo_output_stream_printf (stream,
619                         "    return texture2D%s (%s_sampler, %s_wrap (%s_texcoords, %s_start_coords, %s_stop_coords));\n"
620                         "}\n",
621                         rectstr, namestr, namestr, namestr, namestr, namestr);
622                 }
623             }
624         }
625         else if (op->type == CAIRO_GL_OPERAND_GAUSSIAN) {
626             _cairo_output_stream_printf (stream,
627                 "    int i;\n"
628                 "    vec2 texcoords;\n"
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"
633                 "        return texel;\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"
637                 "        if (i == 0)\n"
638                 "            continue;\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"
640
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"
644                 "        else\n"
645                 "            texel += texture2D%s (%s_sampler, wrapped_coords) * %s_blurs[i+%s_blur_radius];\n"
646                 "    }\n"
647                 "    return texel;\n"
648                 "}\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);
655         }
656         break;
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"
662             "\n"
663             "vec4 get_%s()\n"
664             "{\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))
669         {
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"
674                 "}\n",
675                 namestr, namestr, namestr, rectstr, namestr, namestr);
676         }
677         else
678         {
679             _cairo_output_stream_printf (stream,
680                 "    return texture2D%s (%s_sampler, %s_wrap (vec2 (%s_texcoords.x, 0.5)));\n"
681                 "}\n",
682                 rectstr, namestr, namestr, namestr);
683         }
684         break;
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"
692             "\n"
693             "vec4 get_%s()\n"
694             "{\n"
695             "    vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
696             "    \n"
697             "    float B = dot (pos, %s_circle_d);\n"
698             "    float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
699             "    \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))
707         {
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"
712                 "}\n",
713                 namestr, namestr, rectstr, namestr);
714         }
715         else
716         {
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"
720                 "}\n",
721                 rectstr, namestr, namestr);
722         }
723         break;
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"
732             "\n"
733             "vec4 get_%s()\n"
734             "{\n"
735             "    vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
736             "    \n"
737             "    float B = dot (pos, %s_circle_d);\n"
738             "    float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
739             "    \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"
743             "    \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"
746             "    \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))
753         {
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"
758                 "}\n",
759                 namestr, namestr, rectstr, namestr);
760         }
761         else
762         {
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"
766                 "}\n",
767                 rectstr, namestr, namestr);
768         }
769         break;
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"
777             "\n"
778             "vec4 get_%s()\n"
779             "{\n"
780             "    vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
781             "    \n"
782             "    float B = dot (pos, %s_circle_d);\n"
783             "    float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
784             "    \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"
788             "    \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"
791             "    \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"
795             "}\n",
796             namestr, rectstr, namestr, namestr, namestr, namestr,
797             namestr, namestr, namestr, namestr, namestr,
798             namestr, namestr, namestr, rectstr, namestr, namestr);
799         break;
800     }
801 }
802
803 /*
804  * Emits the border fade functions used by an operand.
805  *
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).
809  *
810  * If nearest filtering is used, the emitted function just returns
811  * 0.0 for all values outside [0, 1).
812  */
813 static void
814 _cairo_gl_shader_emit_border_fade (cairo_output_stream_t *stream,
815                                    cairo_gl_operand_t *operand,
816                                    cairo_gl_tex_t name)
817 {
818     const char *namestr = operand_names[name];
819     GLint gl_filter = _cairo_gl_operand_get_gl_filter (operand);
820
821     /* 2D version */
822     _cairo_output_stream_printf (stream,
823         "vec2 %s_border_fade (vec2 coords, vec2 dims)\n"
824         "{\n",
825         namestr);
826
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");
830     else
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");
835
836     _cairo_output_stream_printf (stream, "}\n");
837
838     /* 1D version */
839     _cairo_output_stream_printf (stream,
840         "float %s_border_fade (float x, float dim)\n"
841         "{\n",
842         namestr);
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");
846     else
847         _cairo_output_stream_printf (stream,
848             "    bool in_tex = x >= 0.0 && x < 1.0;\n"
849             "    return float (in_tex);\n");
850
851     _cairo_output_stream_printf (stream, "}\n");
852 }
853
854 /*
855  * Emits the wrap function used by an operand.
856  *
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.
861  */
862 static void
863 _cairo_gl_shader_emit_wrap (cairo_gl_context_t *ctx,
864                             cairo_output_stream_t *stream,
865                             cairo_gl_operand_t *operand,
866                             cairo_gl_tex_t name)
867 {
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);
871
872     if (use_atlas)
873         _cairo_output_stream_printf (stream,
874             "vec2 %s_wrap (vec2 coords, vec2 start_coords, vec2 stop_coords)\n"
875             "{\n",
876             namestr);
877     else
878         _cairo_output_stream_printf (stream,
879             "vec2 %s_wrap(vec2 coords)\n"
880             "{\n",
881             namestr);
882
883     if (use_atlas) {
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");
893         }
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"
914                 "    else\n"
915                 "        return coords;\n");
916         }
917         else {
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"
925                 "    else\n"
926                 "        return coords;\n");
927         }
928     }
929     else {
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");
939             }
940         }
941         else
942         {
943             _cairo_output_stream_printf (stream, "    return coords;\n");
944         }
945     }
946
947     _cairo_output_stream_printf (stream, "}\n");
948 }
949
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,
957                                      char **out)
958 {
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;
964
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,
972         "#ifdef GL_ES\n"
973         "precision highp float;\n"
974         "#endif\n");
975     else
976         _cairo_output_stream_printf (stream,
977         "#ifdef GL_ES\n"
978         "precision mediump float;\n"
979         "#endif\n");
980
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);
983
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);
990     }
991
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);
994
995     coverage_str = "";
996     if (use_coverage) {
997         _cairo_output_stream_printf (stream, "varying float coverage;\n");
998         coverage_str = " * coverage";
999     }
1000
1001     _cairo_output_stream_printf (stream,
1002         "void main()\n"
1003         "{\n");
1004     switch (in) {
1005     case CAIRO_GL_SHADER_IN_COUNT:
1006     default:
1007         ASSERT_NOT_REACHED;
1008     case CAIRO_GL_SHADER_IN_NORMAL:
1009         _cairo_output_stream_printf (stream,
1010             "    gl_FragColor = get_source() * get_mask().a%s;\n",
1011             coverage_str);
1012         break;
1013     case CAIRO_GL_SHADER_IN_CA_SOURCE:
1014         _cairo_output_stream_printf (stream,
1015             "    gl_FragColor = get_source() * get_mask()%s;\n",
1016             coverage_str);
1017         break;
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",
1021             coverage_str);
1022         break;
1023     }
1024
1025     _cairo_output_stream_write (stream,
1026                                 "}\n\0", 3);
1027
1028     status = _cairo_memory_stream_destroy (stream, &source, &length);
1029     if (unlikely (status)) {
1030         free (source);
1031         return status;
1032     }
1033
1034     *out = (char *) source;
1035     return CAIRO_STATUS_SUCCESS;
1036 }
1037
1038 static void
1039 compile_shader (cairo_gl_context_t *ctx,
1040                 GLuint *shader,
1041                 GLenum type,
1042                 const char *source)
1043 {
1044     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1045     GLint success, log_size, num_chars;
1046     char *log;
1047
1048     *shader = dispatch->CreateShader (type);
1049     dispatch->ShaderSource (*shader, 1, &source, 0);
1050     dispatch->CompileShader (*shader);
1051     dispatch->GetShaderiv (*shader, GL_COMPILE_STATUS, &success);
1052
1053     if (success)
1054         return;
1055
1056     dispatch->GetShaderiv (*shader, GL_INFO_LOG_LENGTH, &log_size);
1057     if (log_size < 0) {
1058         printf ("OpenGL shader compilation failed.\n");
1059         ASSERT_NOT_REACHED;
1060         return;
1061     }
1062
1063     log = _cairo_malloc (log_size + 1);
1064     if (log == NULL) {
1065         printf ("OpenGL shader compilation failed.\n");
1066         ASSERT_NOT_REACHED;
1067     }
1068
1069     dispatch->GetShaderInfoLog (*shader, log_size, &num_chars, log);
1070     log[num_chars] = '\0';
1071
1072     printf ("OpenGL shader compilation failed.  Shader:\n%s\n", source);
1073     printf ("OpenGL compilation log:\n%s\n", log);
1074
1075     free (log);
1076     ASSERT_NOT_REACHED;
1077 }
1078
1079 static void
1080 link_shader_program (cairo_gl_context_t *ctx,
1081                      GLuint *program,
1082                      GLuint vert,
1083                      GLuint frag)
1084 {
1085     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1086     GLint success, log_size, num_chars;
1087     char *log;
1088
1089     *program = dispatch->CreateProgram ();
1090     dispatch->AttachShader (*program, vert);
1091     dispatch->AttachShader (*program, frag);
1092
1093     dispatch->BindAttribLocation (*program, CAIRO_GL_VERTEX_ATTRIB_INDEX,
1094                                   "Vertex");
1095     dispatch->BindAttribLocation (*program, CAIRO_GL_COLOR_ATTRIB_INDEX,
1096                                   "Color");
1097     dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD0_ATTRIB_INDEX,
1098                                   "MultiTexCoord0");
1099     dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD1_ATTRIB_INDEX,
1100                                   "MultiTexCoord1");
1101     dispatch->BindAttribLocation (*program, CAIRO_GL_START_COORD0_ATTRIB_INDEX,
1102                                   "StartCoords0");
1103     dispatch->BindAttribLocation (*program, CAIRO_GL_START_COORD1_ATTRIB_INDEX,
1104                                   "StartCoords1");
1105     dispatch->BindAttribLocation (*program, CAIRO_GL_STOP_COORD0_ATTRIB_INDEX,
1106                                   "StopCoords0");
1107     dispatch->BindAttribLocation (*program, CAIRO_GL_STOP_COORD1_ATTRIB_INDEX,
1108                                   "StopCoords1");
1109
1110     dispatch->LinkProgram (*program);
1111     dispatch->GetProgramiv (*program, GL_LINK_STATUS, &success);
1112     if (success)
1113         return;
1114
1115     dispatch->GetProgramiv (*program, GL_INFO_LOG_LENGTH, &log_size);
1116     if (log_size < 0) {
1117         printf ("OpenGL shader link failed.\n");
1118         ASSERT_NOT_REACHED;
1119         return;
1120     }
1121
1122     log = _cairo_malloc (log_size + 1);
1123     if (log == NULL) {
1124         printf ("OpenGL shader link failed.\n");
1125         ASSERT_NOT_REACHED;
1126     }
1127
1128     dispatch->GetProgramInfoLog (*program, log_size, &num_chars, log);
1129     log[num_chars] = '\0';
1130
1131     printf ("OpenGL shader link failed:\n%s\n", log);
1132     free (log);
1133     ASSERT_NOT_REACHED;
1134 }
1135
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)
1147 {
1148     unsigned int vertex_shader;
1149     cairo_status_t status;
1150
1151     assert (shader->program == 0);
1152
1153     vertex_shader = cairo_gl_var_type_hash (src, mask,
1154                                             src_atlas_extend,
1155                                             mask_atlas_extend,
1156                                             src_use_atlas,
1157                                             mask_use_atlas,
1158                                             use_coverage,
1159                                             CAIRO_GL_VAR_NONE);
1160     if (ctx->vertex_shaders[vertex_shader] == 0) {
1161         char *source;
1162
1163         status = cairo_gl_shader_get_vertex_source (src,
1164                                                     mask,
1165                                                     src_use_atlas,
1166                                                     mask_use_atlas,
1167                                                     use_coverage,
1168                                                     CAIRO_GL_VAR_NONE,
1169                                                     &source);
1170         if (unlikely (status))
1171             goto FAILURE;
1172
1173         compile_shader (ctx, &ctx->vertex_shaders[vertex_shader],
1174                         GL_VERTEX_SHADER, source);
1175         free (source);
1176     }
1177
1178     compile_shader (ctx, &shader->fragment_shader,
1179                     GL_FRAGMENT_SHADER, fragment_text);
1180
1181     link_shader_program (ctx, &shader->program,
1182                          ctx->vertex_shaders[vertex_shader],
1183                          shader->fragment_shader);
1184
1185     return CAIRO_STATUS_SUCCESS;
1186
1187  FAILURE:
1188     _cairo_gl_shader_fini (ctx, shader);
1189     shader->fragment_shader = 0;
1190     shader->program = 0;
1191
1192     return status;
1193 }
1194
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
1197  * compile time.
1198  */
1199 static void
1200 _cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx,
1201                                cairo_gl_shader_t *shader)
1202 {
1203     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1204     GLint location;
1205     GLint saved_program;
1206
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.
1210      */
1211     dispatch->GetIntegerv (GL_CURRENT_PROGRAM, &saved_program);
1212     dispatch->UseProgram (shader->program);
1213
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);
1218     }
1219
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);
1224     }
1225
1226     dispatch->UseProgram (saved_program);
1227 }
1228
1229 void
1230 _cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
1231                              cairo_gl_uniform_t uniform,
1232                              float value)
1233 {
1234     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1235     GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1236                                                             ctx->current_shader,
1237                                                             uniform);
1238     assert (location != -1);
1239     dispatch->Uniform1f (location, value);
1240 }
1241
1242 void
1243 _cairo_gl_shader_bind_int (cairo_gl_context_t *ctx,
1244                              cairo_gl_uniform_t uniform,
1245                              int value)
1246 {
1247     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1248     GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1249                                                             ctx->current_shader,
1250                                                             uniform);
1251     assert (location != -1);
1252     dispatch->Uniform1i (location, value);
1253 }
1254
1255 void
1256 _cairo_gl_shader_bind_float_array (cairo_gl_context_t *ctx,
1257                                    cairo_gl_uniform_t uniform,
1258                                    int num, float *values)
1259 {
1260     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1261     GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1262                                                             ctx->current_shader,
1263                                                             uniform);
1264     assert (location != -1);
1265     dispatch->Uniform1fv (location, num, values);
1266 }
1267
1268 void
1269 _cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
1270                             cairo_gl_uniform_t uniform,
1271                             float value0,
1272                             float value1)
1273 {
1274     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1275     GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1276                                                             ctx->current_shader,
1277                                                             uniform);
1278     assert (location != -1);
1279     dispatch->Uniform2f (location, value0, value1);
1280 }
1281
1282 void
1283 _cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
1284                             cairo_gl_uniform_t uniform,
1285                             float value0,
1286                             float value1,
1287                             float value2)
1288 {
1289     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1290     GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1291                                                             ctx->current_shader,
1292                                                             uniform);
1293     assert (location != -1);
1294     dispatch->Uniform3f (location, value0, value1, value2);
1295 }
1296
1297 void
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)
1302 {
1303     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1304     GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1305                                                             ctx->current_shader,
1306                                                             uniform);
1307     assert (location != -1);
1308     dispatch->Uniform4f (location, value0, value1, value2, value3);
1309 }
1310
1311 void
1312 _cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
1313                               cairo_gl_uniform_t uniform,
1314                               const cairo_matrix_t* m)
1315 {
1316     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1317     GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1318                                                             ctx->current_shader,
1319                                                             uniform);
1320
1321     float gl_m[9] = {
1322         m->xx, m->yx, 0,
1323         m->xy, m->yy, 0,
1324         m->x0, m->y0, 1
1325     };
1326     assert (location != -1);
1327     dispatch->UniformMatrix3fv (location, 1, GL_FALSE, gl_m);
1328 }
1329
1330 void
1331 _cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
1332                                 cairo_gl_uniform_t uniform,
1333                                 GLfloat* gl_m)
1334 {
1335     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
1336     GLint location = _cairo_gl_shader_get_uniform_location (ctx,
1337                                                             ctx->current_shader,
1338                                                             uniform);
1339     assert (location != -1);
1340     dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m);
1341 }
1342
1343 void
1344 _cairo_gl_set_shader (cairo_gl_context_t *ctx,
1345                       cairo_gl_shader_t *shader)
1346 {
1347     if (ctx->current_shader == shader)
1348         return;
1349
1350     if (shader)
1351         ctx->dispatch.UseProgram (shader->program);
1352     else
1353         ctx->dispatch.UseProgram (0);
1354
1355     ctx->current_shader = shader;
1356 }
1357
1358 cairo_status_t
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)
1365 {
1366     cairo_shader_cache_entry_t lookup, *entry;
1367     char *fs_source;
1368     cairo_status_t status;
1369
1370     lookup.ctx = ctx;
1371
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),
1378                                             use_coverage,
1379                                             CAIRO_GL_VAR_NONE);
1380
1381     lookup.src = source->type;
1382     lookup.mask = mask->type;
1383     lookup.dest = CAIRO_GL_OPERAND_NONE;
1384     lookup.use_coverage = use_coverage;
1385     lookup.in = in;
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;
1396
1397     entry = _cairo_cache_lookup (&ctx->shaders, &lookup.base);
1398     if (entry) {
1399         assert (entry->shader.program);
1400         *shader = &entry->shader;
1401         return CAIRO_STATUS_SUCCESS;
1402     }
1403
1404     status = cairo_gl_shader_get_fragment_source (ctx,
1405                                                   in,
1406                                                   source,
1407                                                   mask,
1408                                                   use_coverage,
1409                                                   CAIRO_GL_OPERAND_NONE,
1410                                                   &fs_source);
1411     if (unlikely (status))
1412         return status;
1413
1414     entry = malloc (sizeof (cairo_shader_cache_entry_t));
1415     if (unlikely (entry == NULL)) {
1416         free (fs_source);
1417         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1418     }
1419
1420     memcpy (entry, &lookup, sizeof (cairo_shader_cache_entry_t));
1421
1422     entry->ctx = ctx;
1423     _cairo_gl_shader_init (&entry->shader);
1424     status = _cairo_gl_shader_compile_and_link (ctx,
1425                                                 &entry->shader,
1426                                                 cairo_gl_operand_get_var_type (source),
1427                                                 cairo_gl_operand_get_var_type (mask),
1428                                                 use_coverage,
1429                                                 fs_source,
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));
1434     free (fs_source);
1435
1436     if (unlikely (status)) {
1437         free (entry);
1438         return status;
1439     }
1440
1441     _cairo_gl_shader_set_samplers (ctx, &entry->shader);
1442
1443     status = _cairo_cache_insert (&ctx->shaders, &entry->base);
1444     if (unlikely (status)) {
1445         _cairo_gl_shader_fini (ctx, &entry->shader);
1446         free (entry);
1447         return status;
1448     }
1449
1450     *shader = &entry->shader;
1451
1452     return CAIRO_STATUS_SUCCESS;
1453 }