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.
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>
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"
54 #include "cairo-traps-private.h"
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)
63 _cairo_gl_operand_destroy (&setup->src);
64 return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
65 sample, extents, use_color_attribute);
69 _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
70 const cairo_gl_operand_t *source)
72 _cairo_gl_operand_destroy (&setup->src);
73 _cairo_gl_operand_copy (&setup->src, source);
77 _cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
78 const cairo_color_t *color)
80 _cairo_gl_operand_destroy (&setup->src);
81 _cairo_gl_solid_operand_init (&setup->src, color);
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)
90 cairo_int_status_t status;
92 _cairo_gl_operand_destroy (&setup->mask);
94 return CAIRO_STATUS_SUCCESS;
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
99 status = _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
100 sample, extents, FALSE);
101 if (unlikely (status))
104 if (setup->op == CAIRO_OPERATOR_CLEAR &&
105 ! _cairo_pattern_is_opaque (pattern, sample))
106 setup->mask.texture.attributes.has_component_alpha = TRUE;
112 _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
113 const cairo_gl_operand_t *mask)
115 _cairo_gl_operand_destroy (&setup->mask);
117 _cairo_gl_operand_copy (&setup->mask, mask);
121 _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
127 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
128 cairo_region_t *clip_region)
130 setup->clip_region = clip_region;
134 _cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
141 _cairo_gl_composite_bind_to_shader (cairo_gl_context_t *ctx,
142 cairo_gl_composite_t *setup)
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);
151 _cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
153 cairo_filter_t 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);
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);
168 case CAIRO_FILTER_GAUSSIAN:
174 _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
176 cairo_extend_t extend,
177 cairo_bool_t use_atlas)
180 assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
181 (extend != CAIRO_EXTEND_REPEAT && extend != CAIRO_EXTEND_REFLECT));
184 case CAIRO_EXTEND_NONE:
185 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES)
186 wrap_mode = GL_CLAMP_TO_EDGE;
188 wrap_mode = GL_CLAMP_TO_BORDER;
190 case CAIRO_EXTEND_PAD:
191 wrap_mode = GL_CLAMP_TO_EDGE;
193 case CAIRO_EXTEND_REPEAT:
194 if (ctx->has_npot_repeat)
195 wrap_mode = GL_REPEAT;
197 wrap_mode = GL_CLAMP_TO_EDGE;
199 case CAIRO_EXTEND_REFLECT:
200 if (ctx->has_npot_repeat)
201 wrap_mode = GL_MIRRORED_REPEAT;
203 wrap_mode = GL_CLAMP_TO_EDGE;
209 if (likely (wrap_mode)) {
210 glTexParameteri (target, GL_TEXTURE_WRAP_S, wrap_mode);
211 glTexParameteri (target, GL_TEXTURE_WRAP_T, wrap_mode);
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)
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);
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],
236 if (needs_setup && needs_flush) {
237 _cairo_gl_composite_flush (ctx);
238 _cairo_gl_context_destroy_operand (ctx, tex_unit);
241 memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
242 ctx->operands[tex_unit].vertex_offset = vertex_offset;
247 if (! ctx->has_map_buffer)
248 attrib_location = (void *) (ctx->vb_mem + vertex_offset);
250 switch (operand->type) {
252 case CAIRO_GL_OPERAND_COUNT:
254 case CAIRO_GL_OPERAND_NONE:
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,
262 dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
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);
274 dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
275 GL_FLOAT, GL_FALSE, vertex_size,
277 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
279 if (operand->texture.use_atlas) {
280 dispatch->VertexAttribPointer (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit,
281 2, GL_FLOAT, GL_FALSE,
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,
288 (char *)attrib_location + 4 * sizeof (float));
289 dispatch->EnableVertexAttribArray (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit);
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);
302 dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
303 GL_FLOAT, GL_FALSE, vertex_size,
305 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
311 _cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
312 unsigned int vertex_size,
313 unsigned int vertex_offset)
315 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
316 void *attrib_location = (void *) ((uintptr_t) vertex_offset);
318 if (! ctx->has_map_buffer)
319 attrib_location = (void *) (ctx->vb_mem + vertex_offset);
321 dispatch->VertexAttribPointer (CAIRO_GL_COVERAGE_ATTRIB_INDEX, 4,
322 GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
324 dispatch->EnableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX);
329 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
330 cairo_gl_tex_t tex_unit)
332 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
334 if (!_cairo_gl_context_is_flushed (ctx))
335 _cairo_gl_composite_flush (ctx);
337 switch (ctx->operands[tex_unit].type) {
339 case CAIRO_GL_OPERAND_COUNT:
341 case CAIRO_GL_OPERAND_NONE:
344 case CAIRO_GL_OPERAND_CONSTANT:
345 if (ctx->operands[tex_unit].use_color_attribute)
346 ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
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);
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);
363 memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
367 _cairo_gl_set_operator (cairo_gl_context_t *ctx,
369 cairo_bool_t component_alpha)
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 */
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 */
388 { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
389 { GL_ONE, GL_ONE }, /* Add */
391 GLenum src_factor, dst_factor;
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;
399 src_factor = blend_factors[op].src;
400 dst_factor = blend_factors[op].dst;
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
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)
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;
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);
425 glBlendFunc (src_factor, dst_factor);
429 static cairo_status_t
430 _cairo_gl_composite_begin_component_alpha (cairo_gl_context_t *ctx,
431 cairo_gl_composite_t *setup)
433 cairo_gl_shader_t *pre_shader = NULL;
434 cairo_status_t status;
436 /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
437 * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
439 * mask IN clip ? src OP dest : dest
441 * mask IN CLIP ? 0 : dest
443 * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
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).
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
454 * mask IN clip ? 0 : dest
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;
462 * implements component-alpha %CAIRO_OPERATOR_OVER using two passes of
463 * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
465 * From http://anholt.livejournal.com/32058.html:
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:
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
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
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
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:
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
500 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
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)
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.
511 if (setup->op == CAIRO_OPERATOR_OVER) {
512 setup->op = CAIRO_OPERATOR_ADD;
513 status = _cairo_gl_get_shader_by_type (ctx,
517 CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
519 if (unlikely (status))
523 if (ctx->pre_shader != pre_shader)
524 _cairo_gl_composite_flush (ctx);
525 ctx->pre_shader = pre_shader;
527 return CAIRO_STATUS_SUCCESS;
531 _cairo_gl_scissor_to_extents (cairo_gl_surface_t *surface,
532 const cairo_rectangle_int_t *extents)
538 height = extents->height;
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);
547 _scissor_to_box (cairo_gl_surface_t *surface,
548 const cairo_box_t *box)
550 double x1, y1, x2, y2, height;
551 _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2);
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);
561 _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
562 unsigned int size_per_vertex)
564 void *attrib_location = NULL;
566 if (! ctx->has_map_buffer)
567 attrib_location = (void *) ctx->vb_mem;
569 if (ctx->vertex_size != size_per_vertex)
570 _cairo_gl_composite_flush (ctx);
572 if (_cairo_gl_context_is_flushed (ctx)) {
573 if (ctx->has_map_buffer)
574 ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo);
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);
580 ctx->vertex_size = size_per_vertex;
584 _disable_stencil_buffer (void)
586 if (glIsEnabled (GL_STENCIL_TEST))
587 glDisable (GL_STENCIL_TEST);
588 glDepthMask (GL_FALSE);
592 _disable_scissor_buffer (void)
594 if (glIsEnabled (GL_SCISSOR_TEST))
595 glDisable (GL_SCISSOR_TEST);
598 static cairo_int_status_t
599 _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
600 cairo_gl_context_t *ctx,
602 cairo_bool_t equal_clip)
604 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
606 cairo_gl_surface_t *dst = setup->dst;
607 cairo_clip_t *clip = setup->clip;
609 const cairo_rectangle_int_t *clip_extents;
611 if (clip->num_boxes == 1 && clip->path == NULL) {
612 _scissor_to_box (dst, &clip->boxes[0]);
613 goto disable_stencil_buffer_and_return;
616 if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
617 status = CAIRO_INT_STATUS_UNSUPPORTED;
618 goto disable_stencil_buffer_and_return;
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);
627 return CAIRO_INT_STATUS_SUCCESS;
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);
635 _cairo_traps_init (&traps);
636 status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip, &traps);
637 _cairo_traps_fini (&traps);
639 if (unlikely (status)) {
640 glColorMask (1, 1, 1, 1);
641 goto disable_stencil_buffer_and_return;
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
647 _cairo_gl_composite_flush (ctx);
648 _cairo_gl_composite_setup_vbo (ctx, vertex_size);
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;
655 disable_stencil_buffer_and_return:
656 _disable_stencil_buffer ();
660 static cairo_int_status_t
661 _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
662 cairo_gl_context_t *ctx,
665 cairo_bool_t same_clip;
667 if (! ctx->clip && ! setup->clip && ! ctx->clip_region)
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) ||
674 _cairo_gl_composite_flush (ctx);
676 cairo_region_destroy (ctx->clip_region);
677 ctx->clip_region = cairo_region_reference (setup->clip_region);
679 assert (!setup->clip_region || !setup->clip);
682 _cairo_clip_destroy (ctx->clip);
683 ctx->clip = _cairo_clip_copy (setup->clip);
686 if (ctx->clip_region) {
687 _disable_stencil_buffer ();
688 glEnable (GL_SCISSOR_TEST);
689 return CAIRO_INT_STATUS_SUCCESS;
693 return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
698 _disable_stencil_buffer ();
699 _disable_scissor_buffer ();
700 return CAIRO_INT_STATUS_SUCCESS;
705 _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
706 cairo_gl_context_t **ctx_out,
707 cairo_bool_t multisampling)
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;
719 status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
720 if (unlikely (status))
723 _cairo_gl_context_set_destination (ctx, setup->dst, multisampling);
728 setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
729 setup->mask.texture.attributes.has_component_alpha;
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))
737 if (ctx->pre_shader) {
738 _cairo_gl_composite_flush (ctx);
739 ctx->pre_shader = NULL;
743 status = _cairo_gl_get_shader_by_type (ctx,
748 CAIRO_GL_SHADER_IN_CA_SOURCE :
749 CAIRO_GL_SHADER_IN_NORMAL,
751 if (unlikely (status)) {
752 ctx->pre_shader = NULL;
755 if (ctx->current_shader != shader)
756 _cairo_gl_composite_flush (ctx);
758 status = CAIRO_STATUS_SUCCESS;
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;
766 vertex_size += sizeof (GLfloat);
768 _cairo_gl_composite_setup_vbo (ctx, vertex_size);
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);
773 _cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size);
775 ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX);
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
784 if (setup->mask.type == CAIRO_GL_OPERAND_TEXTURE)
785 mask_surface = &setup->mask.texture.surface->base;
786 if (op == CAIRO_OPERATOR_CLEAR &&
788 mask_surface != NULL &&
789 cairo_surface_get_content (mask_surface) == CAIRO_CONTENT_ALPHA)
790 component_alpha = FALSE;
792 _cairo_gl_set_operator (ctx, setup->op, component_alpha);
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);
799 _cairo_gl_set_shader (ctx, shader);
800 _cairo_gl_composite_bind_to_shader (ctx, setup);
803 status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size);
804 if (unlikely (status))
810 if (unlikely (status))
811 status = _cairo_gl_context_release (ctx, status);
817 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
818 cairo_gl_context_t **ctx_out)
820 return _cairo_gl_composite_begin_multisample (setup, ctx_out, FALSE);
824 _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
826 cairo_array_t* indices = &ctx->tristrip_indices;
827 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
830 if (ctx->pre_shader) {
831 cairo_gl_shader_t *prev_shader = ctx->current_shader;
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);
837 _cairo_gl_set_shader (ctx, prev_shader);
838 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
841 glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
842 _cairo_array_truncate (indices, 0);
846 _cairo_gl_composite_draw_line (cairo_gl_context_t *ctx)
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);
852 if (ctx->draw_mode == CAIRO_GL_LINES)
855 if (ctx->pre_shader) {
856 cairo_gl_shader_t *prev_shader = ctx->current_shader;
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);
862 _cairo_gl_set_shader (ctx, prev_shader);
863 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
866 glDrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
867 _cairo_array_truncate (indices, 0);
871 _cairo_gl_composite_draw (cairo_gl_context_t *ctx,
874 if (! ctx->pre_shader) {
875 glDrawArrays (GL_TRIANGLES, 0, count);
877 cairo_gl_shader_t *prev_shader = ctx->current_shader;
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);
883 _cairo_gl_set_shader (ctx, prev_shader);
884 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
885 glDrawArrays (GL_TRIANGLES, 0, count);
890 _cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
892 if (ctx->has_map_buffer)
893 ctx->dispatch.UnmapBuffer (GL_ARRAY_BUFFER);
900 _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
905 if (_cairo_gl_context_is_flushed (ctx))
908 count = ctx->vb_offset / ctx->vertex_size;
909 _cairo_gl_composite_unmap_vertex_buffer (ctx);
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);
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);
920 for (i = 0; i < num_rectangles; i++) {
921 cairo_rectangle_int_t rect;
923 cairo_region_get_rectangle (ctx->clip_region, i, &rect);
925 glScissor (rect.x, rect.y, rect.width, rect.height);
926 _cairo_gl_composite_draw (ctx, count);
929 _cairo_gl_composite_draw (ctx, count);
932 for (i = 0; i < ARRAY_LENGTH (&ctx->glyph_cache); i++)
933 _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
935 _cairo_gl_image_cache_unlock (ctx);
938 typedef enum cairo_gl_geometry {
939 CAIRO_GL_GEOMETRY_TYPE_TRIANGLES,
940 CAIRO_GL_GEOMETRY_TYPE_TRISTRIPS
941 } cairo_gl_geometry_t;
944 _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
945 unsigned int n_vertices,
946 cairo_gl_geometry_t geometry_type)
948 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
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);
959 if (ctx->vb_offset + n_vertices * ctx->vertex_size > CAIRO_GL_VBO_SIZE)
960 _cairo_gl_composite_flush (ctx);
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);
969 ctx->vb = ctx->vb_mem;
975 _cairo_gl_composite_operand_emit (cairo_gl_operand_t *operand,
980 switch (operand->type) {
982 case CAIRO_GL_OPERAND_COUNT:
984 case CAIRO_GL_OPERAND_NONE:
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];
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:
1002 cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
1008 case CAIRO_GL_OPERAND_TEXTURE:
1010 cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
1014 cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
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;
1030 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
1035 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
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);
1052 fi.bytes[3] = alpha;
1056 ctx->vb_offset += ctx->vertex_size;
1060 _cairo_gl_composite_emit_point (cairo_gl_context_t *ctx,
1061 const cairo_point_t *point,
1064 _cairo_gl_composite_emit_vertex (ctx,
1065 _cairo_fixed_to_double (point->x),
1066 _cairo_fixed_to_double (point->y),
1071 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
1078 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1079 _cairo_gl_composite_flush (ctx);
1080 ctx->draw_mode = CAIRO_GL_VERTEX;
1083 _cairo_gl_composite_prepare_buffer (ctx, 6,
1084 CAIRO_GL_GEOMETRY_TYPE_TRIANGLES);
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);
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);
1096 _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
1102 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1107 _cairo_gl_composite_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1112 ctx->vb_offset += ctx->vertex_size;
1116 _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
1126 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1127 _cairo_gl_composite_flush (ctx);
1128 ctx->draw_mode = CAIRO_GL_VERTEX;
1131 _cairo_gl_composite_prepare_buffer (ctx, 6,
1132 CAIRO_GL_GEOMETRY_TYPE_TRIANGLES);
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);
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);
1144 _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
1146 _cairo_gl_operand_destroy (&setup->src);
1147 _cairo_gl_operand_destroy (&setup->mask);
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)
1156 memset (setup, 0, sizeof (cairo_gl_composite_t));
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");
1164 if (! _cairo_gl_operator_is_supported (op))
1165 return UNSUPPORTED ("unsupported operator");
1170 setup->clip_region = dst->clip_region;
1172 return CAIRO_STATUS_SUCCESS;
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)
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;
1186 assert (number_of_new_indices > 0);
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];
1195 status = _cairo_array_append (indices, ¤t_vertex_index);
1196 if (unlikely (status))
1199 current_vertex_index++;
1200 status =_cairo_array_append (indices, ¤t_vertex_index);
1201 if (unlikely (status))
1204 current_vertex_index = (unsigned short) number_of_indices;
1206 for (i = 0; i < number_of_new_indices; i++) {
1207 status = _cairo_array_append (indices, ¤t_vertex_index);
1208 current_vertex_index++;
1209 if (unlikely (status))
1213 return CAIRO_STATUS_SUCCESS;
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])
1221 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1222 _cairo_gl_composite_flush (ctx);
1223 ctx->draw_mode = CAIRO_GL_VERTEX;
1226 _cairo_gl_composite_prepare_buffer (ctx, 4,
1227 CAIRO_GL_GEOMETRY_TYPE_TRISTRIPS);
1229 _cairo_gl_composite_emit_point (ctx, &quad[0], 0);
1230 _cairo_gl_composite_emit_point (ctx, &quad[1], 0);
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);
1238 return _cairo_gl_composite_append_vertex_indices (ctx, 4, TRUE);
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])
1246 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1247 _cairo_gl_composite_flush (ctx);
1248 ctx->draw_mode = CAIRO_GL_VERTEX;
1251 _cairo_gl_composite_prepare_buffer (ctx, 3,
1252 CAIRO_GL_GEOMETRY_TYPE_TRISTRIPS);
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);
1261 _cairo_gl_composite_emit_point_as_single_line (cairo_gl_context_t *ctx,
1262 const cairo_point_t point[2])
1264 int num_indices = 2;
1265 if (ctx->draw_mode != CAIRO_GL_LINES)
1266 _cairo_gl_composite_flush (ctx);
1268 ctx->draw_mode = CAIRO_GL_LINES;
1270 _cairo_gl_composite_prepare_buffer (ctx, 2,
1271 CAIRO_GL_GEOMETRY_TYPE_TRISTRIPS);
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);