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