beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-gl-composite.c
blob5b1411472d09405d0bb86d94ea5f6009e0a75e3c
1 /* cairo - a vector graphics library with display and print output
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
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.
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
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/
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.
32 * The Original Code is the cairo graphics library.
34 * The Initial Developer of the Original Code is Red Hat, Inc.
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>
46 #include "cairoint.h"
48 #include "cairo-gl-private.h"
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"
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)
62 _cairo_gl_operand_destroy (&setup->src);
63 return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
64 sample, extents, use_texgen);
67 void
68 _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
69 const cairo_gl_operand_t *source)
71 _cairo_gl_operand_destroy (&setup->src);
72 _cairo_gl_operand_copy (&setup->src, source);
75 void
76 _cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
77 const cairo_color_t *color)
79 _cairo_gl_operand_destroy (&setup->src);
80 _cairo_gl_solid_operand_init (&setup->src, color);
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)
90 _cairo_gl_operand_destroy (&setup->mask);
91 if (pattern == NULL)
92 return CAIRO_STATUS_SUCCESS;
94 return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
95 sample, extents, use_texgen);
98 void
99 _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
100 const cairo_gl_operand_t *mask)
102 _cairo_gl_operand_destroy (&setup->mask);
103 if (mask)
104 _cairo_gl_operand_copy (&setup->mask, mask);
107 void
108 _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
110 setup->spans = TRUE;
113 void
114 _cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
116 setup->multisample = TRUE;
119 void
120 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
121 cairo_region_t *clip_region)
123 setup->clip_region = clip_region;
126 void
127 _cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
128 cairo_clip_t *clip)
130 setup->clip = clip;
133 static void
134 _cairo_gl_composite_bind_to_shader (cairo_gl_context_t *ctx,
135 cairo_gl_composite_t *setup)
137 _cairo_gl_shader_bind_matrix4f(ctx, ctx->current_shader->mvp_location,
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);
143 static void
144 _cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
145 GLuint target,
146 cairo_filter_t filter)
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;
166 static void
167 _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
168 GLuint target,
169 cairo_extend_t extend)
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));
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;
201 if (likely (wrap_mode)) {
202 glTexParameteri (target, GL_TEXTURE_WRAP_S, wrap_mode);
203 glTexParameteri (target, GL_TEXTURE_WRAP_T, wrap_mode);
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_offset,
213 cairo_bool_t vertex_size_changed)
215 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
216 cairo_bool_t needs_setup;
218 /* XXX: we need to do setup when switching from shaders
219 * to no shaders (or back) */
220 needs_setup = vertex_size_changed;
221 needs_setup |= _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
222 operand,
223 vertex_offset);
225 if (needs_setup) {
226 _cairo_gl_composite_flush (ctx);
227 _cairo_gl_context_destroy_operand (ctx, tex_unit);
230 memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
231 ctx->operands[tex_unit].vertex_offset = vertex_offset;
233 if (! needs_setup)
234 return;
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);
253 if (! operand->texture.texgen) {
254 dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
255 GL_FLOAT, GL_FALSE, ctx->vertex_size,
256 ctx->vb + vertex_offset);
257 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
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);
269 if (! operand->gradient.texgen) {
270 dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
271 GL_FLOAT, GL_FALSE, ctx->vertex_size,
272 ctx->vb + vertex_offset);
273 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
275 break;
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)
285 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
287 if (! spans_enabled) {
288 dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
289 ctx->spans = FALSE;
290 return;
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;
300 void
301 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
302 cairo_gl_tex_t tex_unit)
304 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
306 if (!_cairo_gl_context_is_flushed (ctx))
307 _cairo_gl_composite_flush (ctx);
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;
329 memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
332 static void
333 _cairo_gl_set_operator (cairo_gl_context_t *ctx,
334 cairo_operator_t op,
335 cairo_bool_t component_alpha)
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 */
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 */
354 { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
355 { GL_ONE, GL_ONE }, /* Add */
357 GLenum src_factor, dst_factor;
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;
365 src_factor = blend_factors[op].src;
366 dst_factor = blend_factors[op].dst;
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.
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;
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;
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);
395 static cairo_status_t
396 _cairo_gl_composite_begin_component_alpha (cairo_gl_context_t *ctx,
397 cairo_gl_composite_t *setup)
399 cairo_gl_shader_t *pre_shader = NULL;
400 cairo_status_t status;
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
409 * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
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).
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
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;
428 * implements component-alpha %CAIRO_OPERATOR_OVER using two passes of
429 * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
431 * From http://anholt.livejournal.com/32058.html:
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:
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
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:
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
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:
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
466 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
467 * after it, we get:
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)
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.
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;
489 if (ctx->pre_shader != pre_shader)
490 _cairo_gl_composite_flush (ctx);
491 ctx->pre_shader = pre_shader;
493 return CAIRO_STATUS_SUCCESS;
496 static void
497 _scissor_to_doubles (cairo_gl_surface_t *surface,
498 double x1, double y1,
499 double x2, double y2)
501 double height;
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);
510 void
511 _cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
512 const cairo_rectangle_int_t *r)
514 _scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
517 static void
518 _scissor_to_box (cairo_gl_surface_t *surface,
519 const cairo_box_t *box)
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);
526 static cairo_bool_t
527 _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
528 unsigned int size_per_vertex)
530 cairo_bool_t vertex_size_changed = ctx->vertex_size != size_per_vertex;
531 if (vertex_size_changed) {
532 ctx->vertex_size = size_per_vertex;
533 _cairo_gl_composite_flush (ctx);
536 if (_cairo_gl_context_is_flushed (ctx)) {
537 ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
538 GL_FLOAT, GL_FALSE, size_per_vertex,
539 ctx->vb);
540 ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
543 return vertex_size_changed;
546 static void
547 _disable_stencil_buffer (void)
549 glDisable (GL_STENCIL_TEST);
550 glDepthMask (GL_FALSE);
553 static cairo_int_status_t
554 _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
555 cairo_gl_context_t *ctx,
556 int vertex_size)
558 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
560 cairo_gl_surface_t *dst = setup->dst;
561 cairo_clip_t *clip = setup->clip;
563 if (clip->num_boxes == 1 && clip->path == NULL) {
564 _scissor_to_box (dst, &clip->boxes[0]);
565 goto disable_stencil_buffer_and_return;
568 if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
569 status = CAIRO_INT_STATUS_UNSUPPORTED;
570 goto disable_stencil_buffer_and_return;
573 /* We only want to clear the part of the stencil buffer
574 * that we are about to use. It also does not hurt to
575 * scissor around the painted clip. */
576 _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip));
578 /* The clip is not rectangular, so use the stencil buffer. */
579 glDepthMask (GL_TRUE);
580 glEnable (GL_STENCIL_TEST);
582 /* Texture surfaces have private depth/stencil buffers, so we can
583 * rely on any previous clip being cached there. */
584 if (_cairo_gl_surface_is_texture (setup->dst)) {
585 cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
586 if (_cairo_clip_equal (old_clip, setup->clip))
587 goto activate_stencil_buffer_and_return;
589 if (old_clip) {
590 _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
593 setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
596 glClearStencil (0);
597 glClear (GL_STENCIL_BUFFER_BIT);
599 glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
600 glStencilFunc (GL_EQUAL, 1, 0xffffffff);
601 glColorMask (0, 0, 0, 0);
603 status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
605 if (unlikely (status)) {
606 glColorMask (1, 1, 1, 1);
607 goto disable_stencil_buffer_and_return;
610 /* We want to only render to the stencil buffer, so draw everything now.
611 Flushing also unbinds the VBO, which we want to rebind for regular
612 drawing. */
613 _cairo_gl_composite_flush (ctx);
614 _cairo_gl_composite_setup_vbo (ctx, vertex_size);
616 activate_stencil_buffer_and_return:
617 glColorMask (1, 1, 1, 1);
618 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
619 glStencilFunc (GL_EQUAL, 1, 0xffffffff);
620 return CAIRO_INT_STATUS_SUCCESS;
622 disable_stencil_buffer_and_return:
623 _disable_stencil_buffer ();
624 return status;
627 static cairo_int_status_t
628 _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
629 cairo_gl_context_t *ctx,
630 int vertex_size)
632 cairo_bool_t clip_changing = TRUE;
633 cairo_bool_t clip_region_changing = TRUE;
635 if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
636 goto disable_all_clipping;
638 clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
639 clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
640 if (! _cairo_gl_context_is_flushed (ctx) &&
641 (clip_region_changing || clip_changing))
642 _cairo_gl_composite_flush (ctx);
644 assert (!setup->clip_region || !setup->clip);
646 /* setup->clip is only used by the msaa compositor and setup->clip_region
647 * only by the other compositors, so it's safe to wait to clean up obsolete
648 * clips. */
649 if (clip_region_changing) {
650 cairo_region_destroy (ctx->clip_region);
651 ctx->clip_region = cairo_region_reference (setup->clip_region);
653 if (clip_changing) {
654 _cairo_clip_destroy (ctx->clip);
655 ctx->clip = _cairo_clip_copy (setup->clip);
658 /* For clip regions, we scissor right before drawing. */
659 if (setup->clip_region)
660 goto disable_all_clipping;
662 if (setup->clip)
663 return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
664 vertex_size);
665 disable_all_clipping:
666 _disable_stencil_buffer ();
667 glDisable (GL_SCISSOR_TEST);
668 return CAIRO_INT_STATUS_SUCCESS;
671 cairo_status_t
672 _cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
673 cairo_gl_context_t *ctx)
675 unsigned int dst_size, src_size, mask_size, vertex_size;
676 cairo_status_t status;
677 cairo_gl_shader_t *shader;
678 cairo_bool_t component_alpha;
679 cairo_bool_t vertex_size_changed;
681 component_alpha =
682 setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
683 setup->mask.texture.attributes.has_component_alpha;
685 /* Do various magic for component alpha */
686 if (component_alpha) {
687 status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
688 if (unlikely (status))
689 return status;
690 } else {
691 if (ctx->pre_shader) {
692 _cairo_gl_composite_flush (ctx);
693 ctx->pre_shader = NULL;
697 status = _cairo_gl_get_shader_by_type (ctx,
698 &setup->src,
699 &setup->mask,
700 setup->spans,
701 component_alpha ?
702 CAIRO_GL_SHADER_IN_CA_SOURCE :
703 CAIRO_GL_SHADER_IN_NORMAL,
704 &shader);
705 if (unlikely (status)) {
706 ctx->pre_shader = NULL;
707 return status;
709 if (ctx->current_shader != shader)
710 _cairo_gl_composite_flush (ctx);
712 status = CAIRO_STATUS_SUCCESS;
714 dst_size = 2 * sizeof (GLfloat);
715 src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
716 mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
717 vertex_size = dst_size + src_size + mask_size;
719 if (setup->spans)
720 vertex_size += sizeof (GLfloat);
722 vertex_size_changed = _cairo_gl_composite_setup_vbo (ctx, vertex_size);
724 _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size, vertex_size_changed);
725 _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size, vertex_size_changed);
727 _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
728 dst_size + src_size + mask_size);
730 _cairo_gl_set_operator (ctx, setup->op, component_alpha);
732 if (_cairo_gl_context_is_flushed (ctx)) {
733 if (ctx->pre_shader) {
734 _cairo_gl_set_shader (ctx, ctx->pre_shader);
735 _cairo_gl_composite_bind_to_shader (ctx, setup);
737 _cairo_gl_set_shader (ctx, shader);
738 _cairo_gl_composite_bind_to_shader (ctx, setup);
741 return status;
744 cairo_status_t
745 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
746 cairo_gl_context_t **ctx_out)
748 cairo_gl_context_t *ctx;
749 cairo_status_t status;
751 assert (setup->dst);
753 status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
754 if (unlikely (status))
755 return status;
757 _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
758 glEnable (GL_BLEND);
760 status = _cairo_gl_set_operands_and_operator (setup, ctx);
761 if (unlikely (status))
762 goto FAIL;
764 status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
765 if (unlikely (status))
766 goto FAIL;
768 *ctx_out = ctx;
770 FAIL:
771 if (unlikely (status))
772 status = _cairo_gl_context_release (ctx, status);
774 return status;
777 static inline void
778 _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
780 cairo_array_t* indices = &ctx->tristrip_indices;
781 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
783 if (ctx->pre_shader) {
784 cairo_gl_shader_t *prev_shader = ctx->current_shader;
786 _cairo_gl_set_shader (ctx, ctx->pre_shader);
787 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
788 glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
790 _cairo_gl_set_shader (ctx, prev_shader);
791 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
794 glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
795 _cairo_array_truncate (indices, 0);
798 static inline void
799 _cairo_gl_composite_draw_triangles (cairo_gl_context_t *ctx,
800 unsigned int count)
802 if (! ctx->pre_shader) {
803 glDrawArrays (GL_TRIANGLES, 0, count);
804 } else {
805 cairo_gl_shader_t *prev_shader = ctx->current_shader;
807 _cairo_gl_set_shader (ctx, ctx->pre_shader);
808 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
809 glDrawArrays (GL_TRIANGLES, 0, count);
811 _cairo_gl_set_shader (ctx, prev_shader);
812 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
813 glDrawArrays (GL_TRIANGLES, 0, count);
817 static void
818 _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
819 unsigned int count)
821 int i, num_rectangles;
823 if (!ctx->clip_region) {
824 _cairo_gl_composite_draw_triangles (ctx, count);
825 return;
828 num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
829 for (i = 0; i < num_rectangles; i++) {
830 cairo_rectangle_int_t rect;
832 cairo_region_get_rectangle (ctx->clip_region, i, &rect);
834 _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
835 _cairo_gl_composite_draw_triangles (ctx, count);
839 static void
840 _cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
842 ctx->vb_offset = 0;
845 void
846 _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
848 unsigned int count;
849 int i;
851 if (_cairo_gl_context_is_flushed (ctx))
852 return;
854 count = ctx->vb_offset / ctx->vertex_size;
855 _cairo_gl_composite_unmap_vertex_buffer (ctx);
857 if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) {
858 _cairo_gl_composite_draw_tristrip (ctx);
859 } else {
860 assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
861 _cairo_gl_composite_draw_triangles_with_clip_region (ctx, count);
864 for (i = 0; i < ARRAY_LENGTH (ctx->glyph_cache); i++)
865 _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
868 static void
869 _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
870 unsigned int n_vertices,
871 cairo_gl_primitive_type_t primitive_type)
873 if (ctx->primitive_type != primitive_type) {
874 _cairo_gl_composite_flush (ctx);
875 ctx->primitive_type = primitive_type;
878 assert(ctx->vbo_size > 0);
879 if (ctx->vb_offset + n_vertices * ctx->vertex_size > ctx->vbo_size)
880 _cairo_gl_composite_flush (ctx);
883 static inline void
884 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
885 GLfloat x, GLfloat y)
887 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
889 *vb++ = x;
890 *vb++ = y;
892 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
893 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
895 ctx->vb_offset += ctx->vertex_size;
898 static inline void
899 _cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
900 GLfloat x, GLfloat y, uint8_t alpha)
902 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
903 union fi {
904 float f;
905 GLbyte bytes[4];
906 } fi;
908 *vb++ = x;
909 *vb++ = y;
911 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
912 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
914 fi.bytes[0] = 0;
915 fi.bytes[1] = 0;
916 fi.bytes[2] = 0;
917 fi.bytes[3] = alpha;
918 *vb++ = fi.f;
920 ctx->vb_offset += ctx->vertex_size;
923 static void
924 _cairo_gl_composite_emit_point (cairo_gl_context_t *ctx,
925 const cairo_point_t *point)
927 _cairo_gl_composite_emit_vertex (ctx,
928 _cairo_fixed_to_double (point->x),
929 _cairo_fixed_to_double (point->y));
932 static void
933 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
934 GLfloat x1, GLfloat y1,
935 GLfloat x2, GLfloat y2)
937 _cairo_gl_composite_prepare_buffer (ctx, 6,
938 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
940 _cairo_gl_composite_emit_vertex (ctx, x1, y1);
941 _cairo_gl_composite_emit_vertex (ctx, x2, y1);
942 _cairo_gl_composite_emit_vertex (ctx, x1, y2);
944 _cairo_gl_composite_emit_vertex (ctx, x2, y1);
945 _cairo_gl_composite_emit_vertex (ctx, x2, y2);
946 _cairo_gl_composite_emit_vertex (ctx, x1, y2);
949 cairo_gl_emit_rect_t
950 _cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
952 return _cairo_gl_composite_emit_rect;
955 void
956 _cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
957 GLfloat x1, GLfloat y1,
958 GLfloat x2, GLfloat y2)
960 _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
963 static void
964 _cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
965 GLfloat x1, GLfloat y1,
966 GLfloat x2, GLfloat y2,
967 uint8_t alpha)
969 _cairo_gl_composite_prepare_buffer (ctx, 6,
970 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
972 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
973 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
974 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
976 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
977 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
978 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
981 static void
982 _cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
983 GLfloat x1, GLfloat y1,
984 GLfloat x2, GLfloat y2,
985 uint8_t alpha)
987 GLfloat *v;
988 union fi {
989 float f;
990 GLbyte bytes[4];
991 } fi;
993 _cairo_gl_composite_prepare_buffer (ctx, 6,
994 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
995 v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
997 v[15] = v[ 6] = v[0] = x1;
998 v[10] = v[ 4] = v[1] = y1;
999 v[12] = v[ 9] = v[3] = x2;
1000 v[16] = v[13] = v[7] = y2;
1002 fi.bytes[0] = 0;
1003 fi.bytes[1] = 0;
1004 fi.bytes[2] = 0;
1005 fi.bytes[3] = alpha;
1006 v[17] =v[14] = v[11] = v[8] = v[5] = v[2] = fi.f;
1008 ctx->vb_offset += 6*3 * sizeof(GLfloat);
1011 cairo_gl_emit_span_t
1012 _cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
1014 if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE) {
1015 switch (ctx->operands[CAIRO_GL_TEX_MASK].type) {
1016 default:
1017 case CAIRO_GL_OPERAND_COUNT:
1018 ASSERT_NOT_REACHED;
1019 case CAIRO_GL_OPERAND_NONE:
1020 case CAIRO_GL_OPERAND_CONSTANT:
1021 break;
1023 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1024 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1025 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1026 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1027 if (!ctx->operands[CAIRO_GL_TEX_MASK].gradient.texgen)
1028 return _cairo_gl_composite_emit_span;
1029 break;
1031 case CAIRO_GL_OPERAND_TEXTURE:
1032 if (!ctx->operands[CAIRO_GL_TEX_MASK].texture.texgen)
1033 return _cairo_gl_composite_emit_span;
1034 break;
1038 switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1039 default:
1040 case CAIRO_GL_OPERAND_COUNT:
1041 ASSERT_NOT_REACHED;
1042 case CAIRO_GL_OPERAND_NONE:
1043 case CAIRO_GL_OPERAND_CONSTANT:
1044 break;
1046 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1047 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1048 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1049 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1050 if (!ctx->operands[CAIRO_GL_TEX_SOURCE].gradient.texgen)
1051 return _cairo_gl_composite_emit_span;
1052 break;
1054 case CAIRO_GL_OPERAND_TEXTURE:
1055 if (!ctx->operands[CAIRO_GL_TEX_SOURCE].texture.texgen)
1056 return _cairo_gl_composite_emit_span;
1059 return _cairo_gl_composite_emit_solid_span;
1062 static inline void
1063 _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
1064 GLfloat x, GLfloat y,
1065 GLfloat glyph_x, GLfloat glyph_y)
1067 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1069 *vb++ = x;
1070 *vb++ = y;
1072 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1074 *vb++ = glyph_x;
1075 *vb++ = glyph_y;
1077 ctx->vb_offset += ctx->vertex_size;
1080 static void
1081 _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
1082 GLfloat x1, GLfloat y1,
1083 GLfloat x2, GLfloat y2,
1084 GLfloat glyph_x1, GLfloat glyph_y1,
1085 GLfloat glyph_x2, GLfloat glyph_y2)
1087 _cairo_gl_composite_prepare_buffer (ctx, 6,
1088 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1090 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
1091 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1092 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1094 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1095 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
1096 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1099 static void
1100 _cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
1101 GLfloat x1, GLfloat y1,
1102 GLfloat x2, GLfloat y2,
1103 GLfloat glyph_x1, GLfloat glyph_y1,
1104 GLfloat glyph_x2, GLfloat glyph_y2)
1106 GLfloat *v;
1108 _cairo_gl_composite_prepare_buffer (ctx, 6,
1109 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1111 v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1113 v[20] = v[ 8] = v[0] = x1;
1114 v[13] = v[ 5] = v[1] = y1;
1115 v[22] = v[10] = v[2] = glyph_x1;
1116 v[15] = v[ 7] = v[3] = glyph_y1;
1118 v[16] = v[12] = v[4] = x2;
1119 v[18] = v[14] = v[6] = glyph_x2;
1121 v[21] = v[17] = v[ 9] = y2;
1122 v[23] = v[19] = v[11] = glyph_y2;
1124 ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
1127 cairo_gl_emit_glyph_t
1128 _cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx)
1130 switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1131 default:
1132 case CAIRO_GL_OPERAND_COUNT:
1133 ASSERT_NOT_REACHED;
1134 case CAIRO_GL_OPERAND_NONE:
1135 case CAIRO_GL_OPERAND_CONSTANT:
1136 return _cairo_gl_composite_emit_solid_glyph;
1138 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1139 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1140 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1141 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1142 case CAIRO_GL_OPERAND_TEXTURE:
1143 return _cairo_gl_composite_emit_glyph;
1147 void
1148 _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
1150 _cairo_gl_operand_destroy (&setup->src);
1151 _cairo_gl_operand_destroy (&setup->mask);
1154 cairo_status_t
1155 _cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
1156 cairo_operator_t op,
1157 cairo_bool_t assume_component_alpha)
1159 if (assume_component_alpha) {
1160 if (op != CAIRO_OPERATOR_CLEAR &&
1161 op != CAIRO_OPERATOR_OVER &&
1162 op != CAIRO_OPERATOR_ADD)
1163 return UNSUPPORTED ("unsupported component alpha operator");
1164 } else {
1165 if (! _cairo_gl_operator_is_supported (op))
1166 return UNSUPPORTED ("unsupported operator");
1169 setup->op = op;
1170 return CAIRO_STATUS_SUCCESS;
1173 cairo_status_t
1174 _cairo_gl_composite_init (cairo_gl_composite_t *setup,
1175 cairo_operator_t op,
1176 cairo_gl_surface_t *dst,
1177 cairo_bool_t assume_component_alpha)
1179 cairo_status_t status;
1181 memset (setup, 0, sizeof (cairo_gl_composite_t));
1183 status = _cairo_gl_composite_set_operator (setup, op,
1184 assume_component_alpha);
1185 if (status)
1186 return status;
1188 setup->dst = dst;
1189 setup->clip_region = dst->clip_region;
1191 return CAIRO_STATUS_SUCCESS;
1194 static cairo_int_status_t
1195 _cairo_gl_composite_append_vertex_indices (cairo_gl_context_t *ctx,
1196 int number_of_new_indices)
1198 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1199 cairo_array_t *indices = &ctx->tristrip_indices;
1200 int number_of_indices = _cairo_array_num_elements (indices);
1201 unsigned short current_vertex_index = 0;
1202 int i;
1204 assert (number_of_new_indices > 0);
1206 /* If any preexisting triangle triangle strip indices exist on this
1207 context, we insert a set of degenerate triangles from the last
1208 preexisting vertex to our first one. */
1209 if (number_of_indices > 0) {
1210 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
1211 current_vertex_index = indices_array[number_of_indices - 1];
1213 status = _cairo_array_append (indices, &current_vertex_index);
1214 if (unlikely (status))
1215 return status;
1217 current_vertex_index++;
1218 status =_cairo_array_append (indices, &current_vertex_index);
1219 if (unlikely (status))
1220 return status;
1223 for (i = 0; i < number_of_new_indices; i++) {
1224 status = _cairo_array_append (indices, &current_vertex_index);
1225 current_vertex_index++;
1226 if (unlikely (status))
1227 return status;
1230 return CAIRO_STATUS_SUCCESS;
1233 cairo_int_status_t
1234 _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t *ctx,
1235 cairo_gl_composite_t *setup,
1236 const cairo_point_t quad[4])
1238 _cairo_gl_composite_prepare_buffer (ctx, 4,
1239 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1241 _cairo_gl_composite_emit_point (ctx, &quad[0]);
1242 _cairo_gl_composite_emit_point (ctx, &quad[1]);
1244 /* Cairo stores quad vertices in counter-clockwise order, but we need to
1245 emit them from top to bottom in the triangle strip, so we need to reverse
1246 the order of the last two vertices. */
1247 _cairo_gl_composite_emit_point (ctx, &quad[3]);
1248 _cairo_gl_composite_emit_point (ctx, &quad[2]);
1250 return _cairo_gl_composite_append_vertex_indices (ctx, 4);
1253 cairo_int_status_t
1254 _cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t *ctx,
1255 cairo_gl_composite_t *setup,
1256 const cairo_point_t triangle[3])
1258 _cairo_gl_composite_prepare_buffer (ctx, 3,
1259 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1261 _cairo_gl_composite_emit_point (ctx, &triangle[0]);
1262 _cairo_gl_composite_emit_point (ctx, &triangle[1]);
1263 _cairo_gl_composite_emit_point (ctx, &triangle[2]);
1264 return _cairo_gl_composite_append_vertex_indices (ctx, 3);