Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-gl-composite.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 Eric Anholt
4  * Copyright © 2009 Chris Wilson
5  * Copyright © 2005,2010 Red Hat, Inc
6  * Copyright © 2011 Linaro Limited
7  * Copyright © 2011 Samsung Electronics
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it either under the terms of the GNU Lesser General Public
11  * License version 2.1 as published by the Free Software Foundation
12  * (the "LGPL") or, at your option, under the terms of the Mozilla
13  * Public License Version 1.1 (the "MPL"). If you do not alter this
14  * notice, a recipient may use your version of this file under either
15  * the MPL or the LGPL.
16  *
17  * You should have received a copy of the LGPL along with this library
18  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
20  * You should have received a copy of the MPL along with this library
21  * in the file COPYING-MPL-1.1
22  *
23  * The contents of this file are subject to the Mozilla Public License
24  * Version 1.1 (the "License"); you may not use this file except in
25  * compliance with the License. You may obtain a copy of the License at
26  * http://www.mozilla.org/MPL/
27  *
28  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
29  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
30  * the specific language governing rights and limitations.
31  *
32  * The Original Code is the cairo graphics library.
33  *
34  * The Initial Developer of the Original Code is Red Hat, Inc.
35  *
36  * Contributor(s):
37  *      Benjamin Otte <otte@gnome.org>
38  *      Carl Worth <cworth@cworth.org>
39  *      Chris Wilson <chris@chris-wilson.co.uk>
40  *      Eric Anholt <eric@anholt.net>
41  *      Alexandros Frantzis <alexandros.frantzis@linaro.org>
42  *      Henry Song <hsong@sisa.samsung.com>
43  *      Martin Robinson <mrobinson@igalia.com>
44  */
45
46 #include "cairoint.h"
47
48 #include "cairo-gl-private.h"
49
50 #include "cairo-composite-rectangles-private.h"
51 #include "cairo-clip-private.h"
52 #include "cairo-error-private.h"
53 #include "cairo-image-surface-private.h"
54
55 union fi {
56     float f;
57     GLbyte bytes[4];
58 } fi;
59
60 cairo_int_status_t
61 _cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
62                                 const cairo_pattern_t *pattern,
63                                 const cairo_rectangle_int_t *sample,
64                                 const cairo_rectangle_int_t *extents,
65                                 cairo_bool_t use_color_attribute)
66 {
67     _cairo_gl_operand_destroy (&setup->src);
68     return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
69                                    sample, extents, use_color_attribute);
70 }
71
72 void
73 _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
74                                         const cairo_gl_operand_t *source)
75 {
76     _cairo_gl_operand_destroy (&setup->src);
77     _cairo_gl_operand_copy (&setup->src, source);
78 }
79
80 void
81 _cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
82                                       const cairo_color_t *color)
83 {
84     _cairo_gl_operand_destroy (&setup->src);
85     _cairo_gl_solid_operand_init (&setup->src, color);
86 }
87
88 cairo_int_status_t
89 _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
90                               const cairo_pattern_t *pattern,
91                               const cairo_rectangle_int_t *sample,
92                               const cairo_rectangle_int_t *extents)
93 {
94     cairo_int_status_t status;
95
96     _cairo_gl_operand_destroy (&setup->mask);
97     if (pattern == NULL)
98         return CAIRO_STATUS_SUCCESS;
99
100     /* XXX: shoot me - we need to set component_alpha to be true
101        if op is CAIRO_OPERATOR_CLEAR AND pattern is a surface_pattern
102      */
103     status = _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
104                                      sample, extents, FALSE);
105     if (unlikely (status))
106         return status;
107
108     if (setup->op == CAIRO_OPERATOR_CLEAR &&
109         !  _cairo_pattern_is_opaque (pattern, sample))
110         setup->mask.texture.attributes.has_component_alpha = TRUE;
111
112     return status;
113 }
114
115 void
116 _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
117                                       const cairo_gl_operand_t *mask)
118 {
119     _cairo_gl_operand_destroy (&setup->mask);
120     if (mask)
121         _cairo_gl_operand_copy (&setup->mask, mask);
122 }
123
124 void
125 _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
126 {
127     setup->spans = TRUE;
128 }
129
130 void
131 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
132                                      cairo_region_t *clip_region)
133 {
134     setup->clip_region = clip_region;
135 }
136
137 void
138 _cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
139                               cairo_clip_t *clip)
140 {
141     setup->clip = clip;
142 }
143
144 static void
145 _cairo_gl_composite_bind_to_shader (cairo_gl_context_t   *ctx,
146                                     cairo_gl_composite_t *setup)
147 {
148     _cairo_gl_shader_bind_matrix4f(ctx, "ModelViewProjectionMatrix",
149                                    ctx->modelviewprojection_matrix);
150     _cairo_gl_operand_bind_to_shader (ctx, &setup->src,  CAIRO_GL_TEX_SOURCE);
151     _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
152 }
153
154 static void
155 _cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
156                               GLuint              target,
157                               cairo_filter_t      filter)
158 {
159     switch (filter) {
160     case CAIRO_FILTER_FAST:
161     case CAIRO_FILTER_NEAREST:
162         glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
163         glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
164         break;
165     case CAIRO_FILTER_GOOD:
166     case CAIRO_FILTER_BEST:
167     case CAIRO_FILTER_BILINEAR:
168         glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
169         glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
170         break;
171     default:
172     case CAIRO_FILTER_GAUSSIAN:
173         ASSERT_NOT_REACHED;
174     }
175 }
176
177 static void
178 _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
179                               GLuint              target,
180                               cairo_extend_t      extend,
181                               cairo_bool_t            use_atlas)
182 {
183     GLint wrap_mode;
184     assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
185             (extend != CAIRO_EXTEND_REPEAT && extend != CAIRO_EXTEND_REFLECT));
186
187     switch (extend) {
188     case CAIRO_EXTEND_NONE:
189         if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES)
190             wrap_mode = GL_CLAMP_TO_EDGE;
191         else
192             wrap_mode = GL_CLAMP_TO_BORDER;
193         break;
194     case CAIRO_EXTEND_PAD:
195         wrap_mode = GL_CLAMP_TO_EDGE;
196         break;
197     case CAIRO_EXTEND_REPEAT:
198         if (ctx->has_npot_repeat)
199             wrap_mode = GL_REPEAT;
200         else
201             wrap_mode = GL_CLAMP_TO_EDGE;
202         break;
203     case CAIRO_EXTEND_REFLECT:
204         if (ctx->has_npot_repeat)
205             wrap_mode = GL_MIRRORED_REPEAT;
206         else
207             wrap_mode = GL_CLAMP_TO_EDGE;
208         break;
209     default:
210         wrap_mode = 0;
211     }
212
213     if (likely (wrap_mode)) {
214         glTexParameteri (target, GL_TEXTURE_WRAP_S, wrap_mode);
215         glTexParameteri (target, GL_TEXTURE_WRAP_T, wrap_mode);
216     }
217 }
218
219
220 static void
221 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
222                                  cairo_gl_tex_t      tex_unit,
223                                  cairo_gl_operand_t *operand,
224                                  unsigned int        vertex_size,
225                                  unsigned int        vertex_offset)
226 {
227     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
228     cairo_bool_t needs_setup;
229     cairo_bool_t needs_flush = TRUE;
230
231     /* XXX: we need to do setup when switching from shaders
232      * to no shaders (or back) */
233     needs_setup = ctx->vertex_size != vertex_size;
234     needs_setup |= _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
235                                                  operand,
236                                                  vertex_offset,
237                                                  &needs_flush);
238
239     if (needs_setup && needs_flush) {
240         _cairo_gl_composite_flush (ctx);
241         _cairo_gl_context_destroy_operand (ctx, tex_unit);
242     }
243
244     memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
245     ctx->operands[tex_unit].vertex_offset = vertex_offset;
246
247     if (! needs_setup)
248         return;
249
250     switch (operand->type) {
251     default:
252     case CAIRO_GL_OPERAND_COUNT:
253         ASSERT_NOT_REACHED;
254     case CAIRO_GL_OPERAND_NONE:
255         break;
256         /* fall through */
257     case CAIRO_GL_OPERAND_CONSTANT:
258         if (operand->use_color_attribute) {
259             dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
260                                            GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
261                                            ctx->vb + vertex_offset);
262             dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
263         }
264         break;
265     case CAIRO_GL_OPERAND_TEXTURE:
266         if (ctx->states_cache.active_texture != GL_TEXTURE0 + tex_unit) {
267             glActiveTexture (GL_TEXTURE0 + tex_unit);
268             ctx->states_cache.active_texture = GL_TEXTURE0 + tex_unit;
269         }
270         glBindTexture (ctx->tex_target, operand->texture.tex);
271         _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
272                                       operand->texture.attributes.extend,
273                                       operand->texture.use_atlas);
274         _cairo_gl_texture_set_filter (ctx, ctx->tex_target,
275                                       operand->texture.attributes.filter);
276
277         dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
278                                         GL_FLOAT, GL_FALSE, vertex_size,
279                                         ctx->vb + vertex_offset);
280         dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
281
282         if (operand->texture.use_atlas) {
283             dispatch->VertexAttribPointer (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit,
284                                            2, GL_FLOAT, GL_FALSE,
285                                            vertex_size,
286                                            ctx->vb + vertex_offset + 2 * sizeof (float));
287             dispatch->EnableVertexAttribArray (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit);
288             dispatch->VertexAttribPointer (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit,
289                                            2, GL_FLOAT, GL_FALSE,
290                                            vertex_size,
291                                            ctx->vb + vertex_offset + 4 * sizeof (float));
292             dispatch->EnableVertexAttribArray (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit);
293         }
294         break;
295     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
296     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
297     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
298     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
299         if(ctx->states_cache.active_texture != GL_TEXTURE0 + tex_unit) {
300             glActiveTexture (GL_TEXTURE0 + tex_unit);
301             ctx->states_cache.active_texture = GL_TEXTURE0 + tex_unit;
302         }
303         glBindTexture (ctx->tex_target, operand->gradient.gradient->tex);
304         _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
305                                       operand->gradient.extend, FALSE);
306         _cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR);
307
308         dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
309                                        GL_FLOAT, GL_FALSE, vertex_size,
310                                        ctx->vb + vertex_offset);
311         dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
312         break;
313     }
314 }
315
316 static void
317 _cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
318                                unsigned int        vertex_size,
319                                unsigned int        vertex_offset)
320 {
321     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
322
323     dispatch->VertexAttribPointer (CAIRO_GL_COVERAGE_ATTRIB_INDEX, 4,
324                                    GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
325                                    ctx->vb + vertex_offset);
326     dispatch->EnableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX);
327     ctx->spans = TRUE;
328 }
329
330 void
331 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
332                                    cairo_gl_tex_t tex_unit)
333 {
334     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
335
336     if  (!_cairo_gl_context_is_flushed (ctx))
337         _cairo_gl_composite_flush (ctx);
338
339     switch (ctx->operands[tex_unit].type) {
340     default:
341     case CAIRO_GL_OPERAND_COUNT:
342         ASSERT_NOT_REACHED;
343     case CAIRO_GL_OPERAND_NONE:
344         break;
345         /* fall through */
346     case CAIRO_GL_OPERAND_CONSTANT:
347         if (ctx->operands[tex_unit].use_color_attribute)
348             ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
349         break;
350     case CAIRO_GL_OPERAND_TEXTURE:
351         dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
352         if (ctx->operands[tex_unit].texture.use_atlas) {
353             dispatch->DisableVertexAttribArray (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit);
354             dispatch->DisableVertexAttribArray (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit);
355         }
356         break;
357     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
358     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
359     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
360     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
361         dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
362         break;
363     }
364
365     memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
366 }
367
368 static void
369 _cairo_gl_set_operator (cairo_gl_context_t *ctx,
370                         cairo_operator_t    op,
371                         cairo_bool_t        component_alpha)
372 {
373     struct {
374         GLenum src;
375         GLenum dst;
376     } blend_factors[] = {
377         { GL_ZERO, GL_ZERO }, /* Clear */
378         { GL_ONE, GL_ZERO }, /* Source */
379         { GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */
380         { GL_DST_ALPHA, GL_ZERO }, /* In */
381         { GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */
382         { GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */
383
384         { GL_ZERO, GL_ONE }, /* Dest */
385         { GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */
386         { GL_ZERO, GL_SRC_ALPHA }, /* DestIn */
387         { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */
388         { GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */
389
390         { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
391         { GL_ONE, GL_ONE }, /* Add */
392     };
393     GLenum src_factor, dst_factor;
394
395     assert (op < ARRAY_LENGTH (blend_factors));
396     /* different dst and component_alpha changes cause flushes elsewhere */
397     if (ctx->current_operator != op)
398         _cairo_gl_composite_flush (ctx);
399     ctx->current_operator = op;
400
401     src_factor = blend_factors[op].src;
402     dst_factor = blend_factors[op].dst;
403
404     /* Even when the user requests CAIRO_CONTENT_COLOR, we use GL_RGBA
405      * due to texture filtering of GL_CLAMP_TO_BORDER.  So fix those
406      * bits in that case.
407      */
408     if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
409         if (src_factor == GL_ONE_MINUS_DST_ALPHA)
410             src_factor = GL_ZERO;
411         if (src_factor == GL_DST_ALPHA)
412             src_factor = GL_ONE;
413     }
414
415     if (component_alpha) {
416         if (dst_factor == GL_ONE_MINUS_SRC_ALPHA)
417             dst_factor = GL_ONE_MINUS_SRC_COLOR;
418         if (dst_factor == GL_SRC_ALPHA)
419             dst_factor = GL_SRC_COLOR;
420     }
421
422     if (ctx->current_target->base.content == CAIRO_CONTENT_ALPHA) {
423         /* cache glBlendFunc, src factor and dst factor, alpha factor */
424         if (ctx->states_cache.src_color_factor != GL_ZERO ||
425            ctx->states_cache.dst_color_factor != GL_ZERO ||
426            ctx->states_cache.src_alpha_factor != src_factor ||
427            ctx->states_cache.dst_alpha_factor != dst_factor) {
428             glBlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
429             ctx->states_cache.src_color_factor = GL_ZERO;
430             ctx->states_cache.dst_color_factor = GL_ZERO;
431             ctx->states_cache.src_alpha_factor = src_factor;
432             ctx->states_cache.dst_alpha_factor = dst_factor;
433         }
434     } else if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
435         if (ctx->states_cache.src_color_factor != src_factor ||
436             ctx->states_cache.dst_color_factor != dst_factor ||
437             ctx->states_cache.src_alpha_factor != GL_ONE ||
438             ctx->states_cache.dst_alpha_factor != GL_ONE) {
439             glBlendFuncSeparate (src_factor, dst_factor, GL_ONE, GL_ONE);
440             ctx->states_cache.src_color_factor = src_factor;
441             ctx->states_cache.dst_color_factor = dst_factor;
442             ctx->states_cache.src_alpha_factor = GL_ONE;
443             ctx->states_cache.dst_alpha_factor = GL_ONE;
444         }
445     } else {
446         if (ctx->states_cache.src_color_factor != src_factor ||
447             ctx->states_cache.dst_color_factor != dst_factor) {
448             glBlendFunc (src_factor, dst_factor);
449             ctx->states_cache.src_color_factor = src_factor;
450             ctx->states_cache.dst_color_factor = dst_factor;
451         }
452     }
453 }
454
455 static cairo_status_t
456 _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
457                                             cairo_gl_composite_t *setup)
458 {
459     cairo_gl_shader_t *pre_shader = NULL;
460     cairo_status_t status;
461
462     /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
463      * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
464      * is:
465      *     mask IN clip ? src OP dest : dest
466      * or more simply:
467      *     mask IN CLIP ? 0 : dest
468      *
469      * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
470      *
471      * The model we use in _cairo_gl_set_operator() is Render's:
472      *     src IN mask IN clip OP dest
473      * which would boil down to:
474      *     0 (bounded by the extents of the drawing).
475      *
476      * However, we can do a Render operation using an opaque source
477      * and DEST_OUT to produce:
478      *    1 IN mask IN clip DEST_OUT dest
479      * which is
480      *    mask IN clip ? 0 : dest
481      */
482     if (setup->op == CAIRO_OPERATOR_CLEAR) {
483         _cairo_gl_solid_operand_init (&setup->src, CAIRO_COLOR_WHITE);
484         setup->op = CAIRO_OPERATOR_DEST_OUT;
485     }
486
487     /*
488      * implements component-alpha %CAIRO_OPERATOR_OVER using two passes of
489      * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
490      *
491      * From http://anholt.livejournal.com/32058.html:
492      *
493      * The trouble is that component-alpha rendering requires two different sources
494      * for blending: one for the source value to the blender, which is the
495      * per-channel multiplication of source and mask, and one for the source alpha
496      * for multiplying with the destination channels, which is the multiplication
497      * of the source channels by the mask alpha. So the equation for Over is:
498      *
499      * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
500      * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
501      * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
502      * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
503      *
504      * But we can do some simpler operations, right? How about PictOpOutReverse,
505      * which has a source factor of 0 and dest factor of (1 - source alpha). We
506      * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
507      * blenders pretty easily. So we can do a component-alpha OutReverse, which
508      * gets us:
509      *
510      * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
511      * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
512      * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
513      * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
514      *
515      * OK. And if an op doesn't use the source alpha value for the destination
516      * factor, then we can do the channel multiplication in the texture blenders
517      * to get the source value, and ignore the source alpha that we wouldn't use.
518      * We've supported this in the Radeon driver for a long time. An example would
519      * be PictOpAdd, which does:
520      *
521      * dst.A = src.A * mask.A + dst.A
522      * dst.R = src.R * mask.R + dst.R
523      * dst.G = src.G * mask.G + dst.G
524      * dst.B = src.B * mask.B + dst.B
525      *
526      * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
527      * after it, we get:
528      *
529      * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
530      * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
531      * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
532      * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
533      *
534      * This two-pass trickery could be avoided using a new GL extension that
535      * lets two values come out of the shader and into the blend unit.
536      */
537     if (setup->op == CAIRO_OPERATOR_OVER) {
538         setup->op = CAIRO_OPERATOR_ADD;
539         status = _cairo_gl_get_shader_by_type (ctx,
540                                                &setup->src,
541                                                &setup->mask,
542                                                setup->spans,
543                                                CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
544                                                &pre_shader);
545         if (unlikely (status))
546             return status;
547     }
548
549     if (ctx->pre_shader != pre_shader)
550         _cairo_gl_composite_flush (ctx);
551     ctx->pre_shader = pre_shader;
552
553     return CAIRO_STATUS_SUCCESS;
554 }
555
556 static void
557 _scissor_to_doubles (cairo_gl_surface_t *surface,
558                      double x1, double y1,
559                      double x2, double y2)
560 {
561     double height;
562
563     height = y2 - y1;
564     if (_cairo_gl_surface_is_texture (surface) == FALSE)
565         y1 = surface->height - (y1 + height);
566     glScissor (x1, y1, x2 - x1, height);
567     glEnable (GL_SCISSOR_TEST);
568 }
569
570 void
571 _cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
572                        const cairo_rectangle_int_t *r)
573 {
574     _scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
575 }
576
577 static void
578 _scissor_to_box (cairo_gl_surface_t     *surface,
579                  const cairo_box_t      *box)
580 {
581     double x1, y1, x2, y2;
582     _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2);
583     _scissor_to_doubles (surface, x1, y1, x2, y2);
584 }
585
586 static void
587 _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
588                                unsigned int size_per_vertex)
589 {
590     if (ctx->vertex_size != size_per_vertex)
591         _cairo_gl_composite_flush (ctx);
592
593     if (_cairo_gl_context_is_flushed (ctx)) {
594         ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
595                                            GL_FLOAT, GL_FALSE, size_per_vertex,
596                                            ctx->vb);
597         ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
598     }
599     ctx->vertex_size = size_per_vertex;
600 }
601
602 void
603 _disable_stencil_buffer (void)
604 {
605     if (glIsEnabled (GL_STENCIL_TEST))
606         glDisable (GL_STENCIL_TEST);
607 }
608
609 void
610 _disable_scissor_buffer (void)
611 {
612     if (glIsEnabled (GL_SCISSOR_TEST))
613         glDisable (GL_SCISSOR_TEST);
614 }
615
616 static cairo_int_status_t
617 _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
618                                             cairo_gl_context_t *ctx,
619                                             int vertex_size,
620                                             cairo_bool_t equal_clip)
621 {
622     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
623
624     cairo_gl_surface_t *dst = setup->dst;
625     cairo_clip_t *clip = setup->clip;
626     cairo_clip_t *cached_clip = ctx->clip;
627
628     if (_cairo_gl_can_use_scissor_for_clip (clip)) {
629         _scissor_to_box (dst, &clip->boxes[0]);
630         goto disable_stencil_buffer_and_return;
631     }
632
633     if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
634         status = CAIRO_INT_STATUS_UNSUPPORTED;
635         goto disable_stencil_buffer_and_return;
636     }
637
638     /* The clip is not rectangular, so use the stencil buffer. */
639     if (! ctx->states_cache.depth_mask ) {
640         glDepthMask (GL_TRUE);
641         ctx->states_cache.depth_mask = TRUE;
642     }
643     glEnable (GL_STENCIL_TEST);
644
645     if (equal_clip)
646         return CAIRO_INT_STATUS_SUCCESS;
647
648     /* Clear the stencil buffer of previous cached clip */
649     if (cached_clip) {
650         _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (cached_clip));
651         glClearStencil (0);
652         glClear (GL_STENCIL_BUFFER_BIT);
653         _disable_scissor_buffer ();
654     }
655
656     glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
657     glStencilFunc (GL_EQUAL, 1, 0xffffffff);
658     glColorMask (0, 0, 0, 0);
659
660     status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
661
662     if (unlikely (status)) {
663         glColorMask (1, 1, 1, 1);
664         goto disable_stencil_buffer_and_return;
665     }
666
667     /* We want to only render to the stencil buffer, so draw everything now.
668        Flushing also unbinds the VBO, which we want to rebind for regular
669        drawing. */
670     _cairo_gl_composite_flush (ctx);
671     _cairo_gl_composite_setup_vbo (ctx, vertex_size);
672
673     glColorMask (1, 1, 1, 1);
674     glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
675     glStencilFunc (GL_EQUAL, 1, 0xffffffff);
676     return CAIRO_INT_STATUS_SUCCESS;
677
678 disable_stencil_buffer_and_return:
679     _disable_stencil_buffer ();
680     return status;
681 }
682
683 static cairo_int_status_t
684 _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
685                                     cairo_gl_context_t *ctx,
686                                     int vertex_size)
687 {
688     cairo_int_status_t status;
689     cairo_bool_t same_clip;
690
691     if (! ctx->clip && ! setup->clip && ! ctx->clip_region)
692         goto finish;
693
694     same_clip = _cairo_clip_equal (ctx->clip, setup->clip);
695     if (! _cairo_gl_context_is_flushed (ctx) &&
696         (! cairo_region_equal (ctx->clip_region, setup->clip_region) ||
697          ! same_clip))
698         _cairo_gl_composite_flush (ctx);
699
700     cairo_region_destroy (ctx->clip_region);
701     ctx->clip_region = cairo_region_reference (setup->clip_region);
702
703     assert (!setup->clip_region || !setup->clip);
704
705     if (ctx->clip_region) {
706         _disable_stencil_buffer ();
707         glEnable (GL_SCISSOR_TEST);
708         return CAIRO_INT_STATUS_SUCCESS;
709     }
710
711     if (setup->clip) {
712         status = _cairo_gl_composite_setup_painted_clipping (setup,
713                                                               ctx,
714                                                               vertex_size,
715                                                               same_clip);
716         if (! same_clip) {
717         _cairo_clip_destroy (ctx->clip);
718         ctx->clip = _cairo_clip_copy (setup->clip);
719         }
720
721         return status;
722     }
723
724 finish:
725     _disable_stencil_buffer ();
726     _disable_scissor_buffer ();
727     return CAIRO_INT_STATUS_SUCCESS;
728 }
729
730 cairo_status_t
731 _cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
732                                      cairo_gl_context_t *ctx,
733                                      cairo_bool_t multisampling)
734 {
735     unsigned int dst_size, src_size, mask_size, vertex_size;
736     cairo_status_t status;
737     cairo_gl_shader_t *shader;
738     cairo_bool_t component_alpha;
739     cairo_operator_t op = setup->op;
740     cairo_surface_t *mask_surface = NULL;
741
742     component_alpha =
743         setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
744         setup->mask.texture.attributes.has_component_alpha;
745
746     /* Do various magic for component alpha */
747     if (component_alpha) {
748         status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
749         if (unlikely (status))
750             return status;
751      } else {
752         if (ctx->pre_shader) {
753             _cairo_gl_composite_flush (ctx);
754             ctx->pre_shader = NULL;
755         }
756     }
757
758     status = _cairo_gl_get_shader_by_type (ctx,
759                                            &setup->src,
760                                            &setup->mask,
761                                            setup->spans,
762                                            component_alpha ?
763                                            CAIRO_GL_SHADER_IN_CA_SOURCE :
764                                            CAIRO_GL_SHADER_IN_NORMAL,
765                                            &shader);
766     if (unlikely (status)) {
767         ctx->pre_shader = NULL;
768         return status;
769     }
770     if (ctx->current_shader != shader)
771         _cairo_gl_composite_flush (ctx);
772
773     status = CAIRO_STATUS_SUCCESS;
774
775     dst_size = 2 * sizeof (GLfloat);
776     src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
777     mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
778     vertex_size = dst_size + src_size + mask_size;
779
780     if (setup->spans)
781         vertex_size += sizeof (GLfloat);
782
783     _cairo_gl_composite_setup_vbo (ctx, vertex_size);
784
785     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size);
786     _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size);
787     if (setup->spans)
788         _cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size);
789     else {
790         ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX);
791         ctx->spans = FALSE;
792     }
793
794     /* XXX: Shoot me - we have converted CLEAR to DEST_OUT,
795        so the dst_factor would be GL_ONE_MINUS_SRC_ALPHA, if the
796        mask is a surface and mask content not content_alpha, we want to use
797        GL_ONE_MINUS_SRC_COLOR, otherwise, we use GL_ONE_MINUS_SRC_ALPHA
798      */
799     if (setup->mask.type == CAIRO_GL_OPERAND_TEXTURE)
800         mask_surface = &setup->mask.texture.surface->base;
801     if (op == CAIRO_OPERATOR_CLEAR &&
802         component_alpha &&
803         mask_surface != NULL &&
804         cairo_surface_get_content (mask_surface) == CAIRO_CONTENT_ALPHA)
805         component_alpha = FALSE;
806
807     _cairo_gl_set_operator (ctx, setup->op, component_alpha);
808
809     if (_cairo_gl_context_is_flushed (ctx)) {
810         if (ctx->pre_shader) {
811             _cairo_gl_set_shader (ctx, ctx->pre_shader);
812             _cairo_gl_composite_bind_to_shader (ctx, setup);
813         }
814         _cairo_gl_set_shader (ctx, shader);
815         _cairo_gl_composite_bind_to_shader (ctx, setup);
816     }
817
818     return status;
819 }
820
821 cairo_status_t
822 _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
823                                        cairo_gl_context_t **ctx_out,
824                                        cairo_bool_t multisampling)
825 {
826     cairo_gl_context_t *ctx;
827     cairo_status_t status;
828
829     assert (setup->dst);
830
831     status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
832     if (unlikely (status))
833         return status;
834
835     _cairo_gl_context_set_destination (ctx, setup->dst, multisampling);
836     if (ctx->states_cache.blend_enabled == FALSE) {
837         glEnable (GL_BLEND);
838         ctx->states_cache.blend_enabled = TRUE;
839     }
840     _cairo_gl_set_operands_and_operator (setup, ctx, multisampling);
841
842     status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
843     if (unlikely (status))
844         goto FAIL;
845
846     *ctx_out = ctx;
847
848 FAIL:
849     if (unlikely (status))
850         status = _cairo_gl_context_release (ctx, status);
851
852     return status;
853 }
854
855 cairo_status_t
856 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
857                            cairo_gl_context_t **ctx_out)
858 {
859     return _cairo_gl_composite_begin_multisample (setup, ctx_out, FALSE);
860 }
861
862 static inline void
863 _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
864 {
865     cairo_array_t* indices = &ctx->tristrip_indices;
866     const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
867
868     if (ctx->pre_shader) {
869         cairo_gl_shader_t *prev_shader = ctx->current_shader;
870
871         _cairo_gl_set_shader (ctx, ctx->pre_shader);
872         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
873         glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
874
875         _cairo_gl_set_shader (ctx, prev_shader);
876         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
877     }
878
879     glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
880     _cairo_array_truncate (indices, 0);
881 }
882
883 static inline void
884 _cairo_gl_composite_draw_line (cairo_gl_context_t *ctx)
885 {
886     GLenum type = GL_LINE_STRIP;
887     cairo_array_t* indices = &ctx->tristrip_indices;
888     const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
889
890     if (ctx->draw_mode == CAIRO_GL_LINES)
891         type = GL_LINES;
892
893     if (ctx->pre_shader) {
894         cairo_gl_shader_t *prev_shader = ctx->current_shader;
895
896         _cairo_gl_set_shader (ctx, ctx->pre_shader);
897         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
898         glDrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
899
900         _cairo_gl_set_shader (ctx, prev_shader);
901         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
902     }
903
904     glDrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
905     _cairo_array_truncate (indices, 0);
906 }
907
908 static inline void
909 _cairo_gl_composite_draw_triangles (cairo_gl_context_t *ctx,
910                                     unsigned int count)
911 {
912     if (! ctx->pre_shader) {
913         glDrawArrays (GL_TRIANGLES, 0, count);
914     } else {
915         cairo_gl_shader_t *prev_shader = ctx->current_shader;
916
917         _cairo_gl_set_shader (ctx, ctx->pre_shader);
918         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
919         glDrawArrays (GL_TRIANGLES, 0, count);
920
921         _cairo_gl_set_shader (ctx, prev_shader);
922         _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
923         glDrawArrays (GL_TRIANGLES, 0, count);
924     }
925 }
926
927 static void
928 _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
929                                                      unsigned int count)
930 {
931     int i, num_rectangles;
932
933     if (!ctx->clip_region) {
934         _cairo_gl_composite_draw_triangles (ctx, count);
935         return;
936     }
937
938     num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
939     for (i = 0; i < num_rectangles; i++) {
940         cairo_rectangle_int_t rect;
941
942         cairo_region_get_rectangle (ctx->clip_region, i, &rect);
943
944         _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
945         _cairo_gl_composite_draw_triangles (ctx, count);
946     }
947 }
948
949 static void
950 _cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
951 {
952     ctx->vb_offset = 0;
953 }
954
955 void
956 _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
957 {
958     unsigned int count;
959     int i;
960
961     if (_cairo_gl_context_is_flushed (ctx))
962         return;
963
964     count = ctx->vb_offset / ctx->vertex_size;
965     _cairo_gl_composite_unmap_vertex_buffer (ctx);
966
967     if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) {
968         if (ctx->draw_mode == CAIRO_GL_LINE_STRIP ||
969             ctx->draw_mode == CAIRO_GL_LINES)
970             _cairo_gl_composite_draw_line (ctx);
971         else
972             _cairo_gl_composite_draw_tristrip (ctx);
973     } else {
974         assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
975         _cairo_gl_composite_draw_triangles_with_clip_region (ctx, count);
976     }
977
978     for (i = 0; i < ARRAY_LENGTH (&ctx->glyph_cache); i++)
979         _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
980
981     _cairo_gl_image_cache_unlock (ctx);
982 }
983
984 static void
985 _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
986                                     unsigned int n_vertices,
987                                     cairo_gl_primitive_type_t primitive_type)
988 {
989     if (ctx->primitive_type != primitive_type) {
990         _cairo_gl_composite_flush (ctx);
991         ctx->primitive_type = primitive_type;
992     }
993
994     if (ctx->vb_offset + n_vertices * ctx->vertex_size > CAIRO_GL_VBO_SIZE)
995         _cairo_gl_composite_flush (ctx);
996 }
997
998 static inline void
999 _cairo_gl_composite_operand_emit (cairo_gl_operand_t *operand,
1000                         GLfloat ** vb,
1001                         GLfloat x,
1002                         GLfloat y)
1003 {
1004     switch (operand->type) {
1005     default:
1006     case CAIRO_GL_OPERAND_COUNT:
1007         ASSERT_NOT_REACHED;
1008     case CAIRO_GL_OPERAND_NONE:
1009         break;
1010     case CAIRO_GL_OPERAND_CONSTANT:
1011         if (operand->use_color_attribute) {
1012             fi.bytes[0] = operand->constant.color[0] * 255;
1013             fi.bytes[1] = operand->constant.color[1] * 255;
1014             fi.bytes[2] = operand->constant.color[2] * 255;
1015             fi.bytes[3] = operand->constant.color[3] * 255;
1016             *(*vb)++ = fi.f;
1017         }
1018         break;
1019     case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1020     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1021     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1022     case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1023         {
1024             double s = x;
1025             double t = y;
1026
1027             cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
1028
1029             *(*vb)++ = s;
1030             *(*vb)++ = t;
1031         }
1032         break;
1033     case CAIRO_GL_OPERAND_TEXTURE:
1034         {
1035             cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
1036             double s = x;
1037             double t = y;
1038
1039             cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
1040             *(*vb)++ = s;
1041             *(*vb)++ = t;
1042
1043             if (operand->texture.use_atlas) {
1044                 *(*vb)++ = operand->texture.p1.x;
1045                 *(*vb)++ = operand->texture.p1.y;
1046                 *(*vb)++ = operand->texture.p2.x;
1047                 *(*vb)++ = operand->texture.p2.y;
1048             }
1049         }
1050         break;
1051     }
1052 }
1053
1054 static inline void
1055 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
1056                                  GLfloat x,
1057                                  GLfloat y,
1058                                  uint8_t alpha)
1059 {
1060     GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1061
1062     *vb++ = x;
1063     *vb++ = y;
1064
1065     _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1066     _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK  ], &vb, x, y);
1067
1068     if (ctx->spans) {
1069
1070         fi.bytes[0] = 0;
1071         fi.bytes[1] = 0;
1072         fi.bytes[2] = 0;
1073         fi.bytes[3] = alpha;
1074         *vb++ = fi.f;
1075     }
1076
1077     ctx->vb_offset += ctx->vertex_size;
1078 }
1079
1080 static inline void
1081 _cairo_gl_composite_emit_point (cairo_gl_context_t      *ctx,
1082                                 const cairo_point_t     *point,
1083                                 uint8_t alpha)
1084 {
1085     _cairo_gl_composite_emit_vertex (ctx,
1086                                      _cairo_fixed_to_double (point->x),
1087                                      _cairo_fixed_to_double (point->y),
1088                                      alpha);
1089 }
1090
1091 void
1092 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
1093                                GLfloat x1,
1094                                GLfloat y1,
1095                                GLfloat x2,
1096                                GLfloat y2,
1097                                uint8_t alpha)
1098 {
1099     if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1100         _cairo_gl_composite_flush (ctx);
1101         ctx->draw_mode = CAIRO_GL_VERTEX;
1102     }
1103
1104     _cairo_gl_composite_prepare_buffer (ctx, 6,
1105                                         CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1106
1107     _cairo_gl_composite_emit_vertex (ctx, x1, y1, alpha);
1108     _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
1109     _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
1110
1111     _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
1112     _cairo_gl_composite_emit_vertex (ctx, x2, y2, alpha);
1113     _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
1114 }
1115
1116 static inline void
1117 _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
1118                                        GLfloat x,
1119                                        GLfloat y,
1120                                        GLfloat glyph_x,
1121                                        GLfloat glyph_y)
1122 {
1123     GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1124
1125     *vb++ = x;
1126     *vb++ = y;
1127
1128     _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1129
1130     *vb++ = glyph_x;
1131     *vb++ = glyph_y;
1132
1133     ctx->vb_offset += ctx->vertex_size;
1134 }
1135
1136 void
1137 _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
1138                                 GLfloat x1,
1139                                 GLfloat y1,
1140                                 GLfloat x2,
1141                                 GLfloat y2,
1142                                 GLfloat glyph_x1,
1143                                 GLfloat glyph_y1,
1144                                 GLfloat glyph_x2,
1145                                 GLfloat glyph_y2)
1146 {
1147     if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1148         _cairo_gl_composite_flush (ctx);
1149         ctx->draw_mode = CAIRO_GL_VERTEX;
1150     }
1151
1152     _cairo_gl_composite_prepare_buffer (ctx, 6,
1153                                         CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1154
1155     _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
1156     _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1157     _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1158
1159     _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1160     _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
1161     _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1162 }
1163
1164 void
1165 _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
1166 {
1167     _cairo_gl_operand_destroy (&setup->src);
1168     _cairo_gl_operand_destroy (&setup->mask);
1169 }
1170
1171 cairo_status_t
1172 _cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
1173                                   cairo_operator_t op,
1174                                   cairo_bool_t assume_component_alpha)
1175 {
1176     if (assume_component_alpha) {
1177         if (op != CAIRO_OPERATOR_CLEAR &&
1178             op != CAIRO_OPERATOR_OVER &&
1179             op != CAIRO_OPERATOR_ADD)
1180             return UNSUPPORTED ("unsupported component alpha operator");
1181     } else {
1182         if (! _cairo_gl_operator_is_supported (op))
1183             return UNSUPPORTED ("unsupported operator");
1184     }
1185
1186     setup->op = op;
1187     return CAIRO_STATUS_SUCCESS;
1188 }
1189
1190 cairo_status_t
1191 _cairo_gl_composite_init (cairo_gl_composite_t *setup,
1192                           cairo_operator_t op,
1193                           cairo_gl_surface_t *dst,
1194                           cairo_bool_t assume_component_alpha)
1195 {
1196     cairo_status_t status;
1197
1198     memset (setup, 0, sizeof (cairo_gl_composite_t));
1199
1200     status = _cairo_gl_composite_set_operator (setup, op,
1201                                                assume_component_alpha);
1202     if (status)
1203         return status;
1204
1205     setup->dst = dst;
1206     setup->clip_region = dst->clip_region;
1207
1208     return CAIRO_STATUS_SUCCESS;
1209 }
1210
1211 static cairo_int_status_t
1212 _cairo_gl_composite_append_vertex_indices (cairo_gl_context_t   *ctx,
1213                                            int                   number_of_new_indices,
1214                                            cairo_bool_t          is_connected)
1215 {
1216     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1217     cairo_array_t *indices = &ctx->tristrip_indices;
1218     int number_of_indices = _cairo_array_num_elements (indices);
1219     unsigned short current_vertex_index = 0;
1220     int i;
1221
1222     assert (number_of_new_indices > 0);
1223
1224     /* If any preexisting triangle triangle strip indices exist on this
1225        context, we insert a set of degenerate triangles from the last
1226        preexisting vertex to our first one. */
1227     if (number_of_indices > 0 && is_connected) {
1228         const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
1229         current_vertex_index = indices_array[number_of_indices - 1];
1230
1231         status = _cairo_array_append (indices, &current_vertex_index);
1232         if (unlikely (status))
1233             return status;
1234
1235         current_vertex_index++;
1236         status =_cairo_array_append (indices, &current_vertex_index);
1237         if (unlikely (status))
1238             return status;
1239     } else
1240         current_vertex_index = (unsigned short) number_of_indices;
1241
1242     for (i = 0; i < number_of_new_indices; i++) {
1243         status = _cairo_array_append (indices, &current_vertex_index);
1244         current_vertex_index++;
1245         if (unlikely (status))
1246             return status;
1247     }
1248
1249     return CAIRO_STATUS_SUCCESS;
1250 }
1251
1252 cairo_int_status_t
1253 _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t   *ctx,
1254                                            cairo_gl_composite_t *setup,
1255                                            const cairo_point_t  quad[4])
1256 {
1257     if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1258         _cairo_gl_composite_flush (ctx);
1259         ctx->draw_mode = CAIRO_GL_VERTEX;
1260     }
1261
1262     _cairo_gl_composite_prepare_buffer (ctx, 4,
1263                                         CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1264
1265     _cairo_gl_composite_emit_point (ctx, &quad[0], 0);
1266     _cairo_gl_composite_emit_point (ctx, &quad[1], 0);
1267
1268     /* Cairo stores quad vertices in counter-clockwise order, but we need to
1269        emit them from top to bottom in the triangle strip, so we need to reverse
1270        the order of the last two vertices. */
1271     _cairo_gl_composite_emit_point (ctx, &quad[3], 0);
1272     _cairo_gl_composite_emit_point (ctx, &quad[2], 0);
1273
1274     return _cairo_gl_composite_append_vertex_indices (ctx, 4, TRUE);
1275 }
1276
1277 cairo_int_status_t
1278 _cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t       *ctx,
1279                                                cairo_gl_composite_t     *setup,
1280                                                const cairo_point_t       triangle[3])
1281 {
1282     if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1283         _cairo_gl_composite_flush (ctx);
1284         ctx->draw_mode = CAIRO_GL_VERTEX;
1285     }
1286
1287     _cairo_gl_composite_prepare_buffer (ctx, 3,
1288                                         CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1289
1290     _cairo_gl_composite_emit_point (ctx, &triangle[0], 0);
1291     _cairo_gl_composite_emit_point (ctx, &triangle[1], 0);
1292     _cairo_gl_composite_emit_point (ctx, &triangle[2], 0);
1293     return _cairo_gl_composite_append_vertex_indices (ctx, 3, TRUE);
1294 }
1295
1296 cairo_int_status_t
1297 _cairo_gl_composite_emit_point_as_single_line (cairo_gl_context_t  *ctx,
1298                                                const cairo_point_t point[2])
1299 {
1300     int num_indices = 2;
1301     if (ctx->draw_mode != CAIRO_GL_LINES)
1302         _cairo_gl_composite_flush (ctx);
1303
1304     ctx->draw_mode = CAIRO_GL_LINES;
1305
1306     _cairo_gl_composite_prepare_buffer (ctx, 2,
1307                                         CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1308
1309     _cairo_gl_composite_emit_point (ctx, &point[0], 0);
1310     _cairo_gl_composite_emit_point (ctx, &point[1], 0);
1311     return _cairo_gl_composite_append_vertex_indices (ctx, num_indices, FALSE);
1312 }