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