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"
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);
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);
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);
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);
92 return CAIRO_STATUS_SUCCESS;
94 return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
95 sample, extents, use_texgen);
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);
104 _cairo_gl_operand_copy (&setup->mask, mask);
108 _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
114 _cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
116 setup->multisample = TRUE;
120 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
121 cairo_region_t *clip_region)
123 setup->clip_region = clip_region;
127 _cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
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, "ModelViewProjectionMatrix",
138 ctx->modelviewprojection_matrix);
139 _cairo_gl_operand_bind_to_shader (ctx, &setup->src, CAIRO_GL_TEX_SOURCE);
140 _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
144 _cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
146 cairo_filter_t 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);
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);
161 case CAIRO_FILTER_GAUSSIAN:
167 _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
169 cairo_extend_t extend)
172 assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
173 (extend != CAIRO_EXTEND_REPEAT && extend != CAIRO_EXTEND_REFLECT));
176 case CAIRO_EXTEND_NONE:
177 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES)
178 wrap_mode = GL_CLAMP_TO_EDGE;
180 wrap_mode = GL_CLAMP_TO_BORDER;
182 case CAIRO_EXTEND_PAD:
183 wrap_mode = GL_CLAMP_TO_EDGE;
185 case CAIRO_EXTEND_REPEAT:
186 if (ctx->has_npot_repeat)
187 wrap_mode = GL_REPEAT;
189 wrap_mode = GL_CLAMP_TO_EDGE;
191 case CAIRO_EXTEND_REFLECT:
192 if (ctx->has_npot_repeat)
193 wrap_mode = GL_MIRRORED_REPEAT;
195 wrap_mode = GL_CLAMP_TO_EDGE;
201 if (likely (wrap_mode)) {
202 glTexParameteri (target, GL_TEXTURE_WRAP_S, wrap_mode);
203 glTexParameteri (target, GL_TEXTURE_WRAP_T, wrap_mode);
209 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
210 cairo_gl_tex_t tex_unit,
211 cairo_gl_operand_t *operand,
212 unsigned int vertex_size,
213 unsigned int vertex_offset)
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 = ctx->vertex_size != vertex_size;
221 needs_setup |= _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
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;
236 switch (operand->type) {
238 case CAIRO_GL_OPERAND_COUNT:
240 case CAIRO_GL_OPERAND_NONE:
243 case CAIRO_GL_OPERAND_CONSTANT:
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, vertex_size,
256 ctx->vb + vertex_offset);
257 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
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, vertex_size,
272 ctx->vb + vertex_offset);
273 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
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);
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);
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) {
311 case CAIRO_GL_OPERAND_COUNT:
313 case CAIRO_GL_OPERAND_NONE:
316 case CAIRO_GL_OPERAND_CONSTANT:
318 case CAIRO_GL_OPERAND_TEXTURE:
319 dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
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);
329 memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
333 _cairo_gl_set_operator (cairo_gl_context_t *ctx,
335 cairo_bool_t component_alpha)
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
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)
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);
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)
405 * mask IN clip ? src OP dest : dest
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
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
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
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,
483 CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
485 if (unlikely (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;
497 _scissor_to_doubles (cairo_gl_surface_t *surface,
498 double x1, double y1,
499 double x2, double y2)
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);
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);
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);
527 _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
528 unsigned int size_per_vertex)
530 if (ctx->vertex_size != size_per_vertex)
531 _cairo_gl_composite_flush (ctx);
533 if (_cairo_gl_context_is_flushed (ctx)) {
534 ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
535 GL_FLOAT, GL_FALSE, size_per_vertex,
537 ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
539 ctx->vertex_size = size_per_vertex;
543 _disable_stencil_buffer (void)
545 glDisable (GL_STENCIL_TEST);
546 glDepthMask (GL_FALSE);
549 static cairo_int_status_t
550 _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
551 cairo_gl_context_t *ctx,
554 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
556 cairo_gl_surface_t *dst = setup->dst;
557 cairo_clip_t *clip = setup->clip;
559 if (clip->num_boxes == 1 && clip->path == NULL) {
560 _scissor_to_box (dst, &clip->boxes[0]);
561 goto disable_stencil_buffer_and_return;
564 if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
565 status = CAIRO_INT_STATUS_UNSUPPORTED;
566 goto disable_stencil_buffer_and_return;
569 /* The clip is not rectangular, so use the stencil buffer. */
570 glDepthMask (GL_TRUE);
571 glEnable (GL_STENCIL_TEST);
572 glDisable (GL_SCISSOR_TEST);
574 /* Texture surfaces have private depth/stencil buffers, so we can
575 * rely on any previous clip being cached there. */
576 if (_cairo_gl_surface_is_texture (setup->dst)) {
577 cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
578 if (_cairo_clip_equal (old_clip, setup->clip))
579 goto activate_stencil_buffer_and_return;
581 /* Clear the stencil buffer, but only the areas that we are
582 * going to be drawing to. */
584 _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (old_clip));
585 setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
589 glClear (GL_STENCIL_BUFFER_BIT);
590 glDisable (GL_SCISSOR_TEST);
592 glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
593 glStencilFunc (GL_EQUAL, 1, 0xffffffff);
594 glColorMask (0, 0, 0, 0);
596 status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
598 if (unlikely (status)) {
599 glColorMask (1, 1, 1, 1);
600 goto disable_stencil_buffer_and_return;
603 /* We want to only render to the stencil buffer, so draw everything now.
604 Flushing also unbinds the VBO, which we want to rebind for regular
606 _cairo_gl_composite_flush (ctx);
607 _cairo_gl_composite_setup_vbo (ctx, vertex_size);
609 activate_stencil_buffer_and_return:
610 glColorMask (1, 1, 1, 1);
611 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
612 glStencilFunc (GL_EQUAL, 1, 0xffffffff);
613 return CAIRO_INT_STATUS_SUCCESS;
615 disable_stencil_buffer_and_return:
616 _disable_stencil_buffer ();
620 static cairo_int_status_t
621 _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
622 cairo_gl_context_t *ctx,
625 cairo_bool_t clip_changing = TRUE;
626 cairo_bool_t clip_region_changing = TRUE;
628 if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
629 goto disable_all_clipping;
631 clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
632 clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
633 if (! _cairo_gl_context_is_flushed (ctx) &&
634 (clip_region_changing || clip_changing))
635 _cairo_gl_composite_flush (ctx);
637 assert (!setup->clip_region || !setup->clip);
639 /* setup->clip is only used by the msaa compositor and setup->clip_region
640 * only by the other compositors, so it's safe to wait to clean up obsolete
642 if (clip_region_changing) {
643 cairo_region_destroy (ctx->clip_region);
644 ctx->clip_region = cairo_region_reference (setup->clip_region);
647 _cairo_clip_destroy (ctx->clip);
648 ctx->clip = _cairo_clip_copy (setup->clip);
651 /* For clip regions, we scissor right before drawing. */
652 if (setup->clip_region)
653 goto disable_all_clipping;
656 return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
658 disable_all_clipping:
659 _disable_stencil_buffer ();
660 glDisable (GL_SCISSOR_TEST);
661 return CAIRO_INT_STATUS_SUCCESS;
665 _cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
666 cairo_gl_context_t *ctx)
668 unsigned int dst_size, src_size, mask_size, vertex_size;
669 cairo_status_t status;
670 cairo_gl_shader_t *shader;
671 cairo_bool_t component_alpha;
674 setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
675 setup->mask.texture.attributes.has_component_alpha;
677 /* Do various magic for component alpha */
678 if (component_alpha) {
679 status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
680 if (unlikely (status))
683 if (ctx->pre_shader) {
684 _cairo_gl_composite_flush (ctx);
685 ctx->pre_shader = NULL;
689 status = _cairo_gl_get_shader_by_type (ctx,
694 CAIRO_GL_SHADER_IN_CA_SOURCE :
695 CAIRO_GL_SHADER_IN_NORMAL,
697 if (unlikely (status)) {
698 ctx->pre_shader = NULL;
701 if (ctx->current_shader != shader)
702 _cairo_gl_composite_flush (ctx);
704 status = CAIRO_STATUS_SUCCESS;
706 dst_size = 2 * sizeof (GLfloat);
707 src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
708 mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
709 vertex_size = dst_size + src_size + mask_size;
712 vertex_size += sizeof (GLfloat);
714 _cairo_gl_composite_setup_vbo (ctx, vertex_size);
716 _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size);
717 _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size);
719 _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
720 dst_size + src_size + mask_size);
722 _cairo_gl_set_operator (ctx, setup->op, component_alpha);
724 if (_cairo_gl_context_is_flushed (ctx)) {
725 if (ctx->pre_shader) {
726 _cairo_gl_set_shader (ctx, ctx->pre_shader);
727 _cairo_gl_composite_bind_to_shader (ctx, setup);
729 _cairo_gl_set_shader (ctx, shader);
730 _cairo_gl_composite_bind_to_shader (ctx, setup);
737 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
738 cairo_gl_context_t **ctx_out)
740 cairo_gl_context_t *ctx;
741 cairo_status_t status;
745 status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
746 if (unlikely (status))
749 _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
751 _cairo_gl_set_operands_and_operator (setup, ctx);
753 status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
754 if (unlikely (status))
760 if (unlikely (status))
761 status = _cairo_gl_context_release (ctx, status);
767 _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
769 cairo_array_t* indices = &ctx->tristrip_indices;
770 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
772 if (ctx->pre_shader) {
773 cairo_gl_shader_t *prev_shader = ctx->current_shader;
775 _cairo_gl_set_shader (ctx, ctx->pre_shader);
776 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
777 glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
779 _cairo_gl_set_shader (ctx, prev_shader);
780 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
783 glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
784 _cairo_array_truncate (indices, 0);
788 _cairo_gl_composite_draw_triangles (cairo_gl_context_t *ctx,
791 if (! ctx->pre_shader) {
792 glDrawArrays (GL_TRIANGLES, 0, count);
794 cairo_gl_shader_t *prev_shader = ctx->current_shader;
796 _cairo_gl_set_shader (ctx, ctx->pre_shader);
797 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
798 glDrawArrays (GL_TRIANGLES, 0, count);
800 _cairo_gl_set_shader (ctx, prev_shader);
801 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
802 glDrawArrays (GL_TRIANGLES, 0, count);
807 _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
810 int i, num_rectangles;
812 if (!ctx->clip_region) {
813 _cairo_gl_composite_draw_triangles (ctx, count);
817 num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
818 for (i = 0; i < num_rectangles; i++) {
819 cairo_rectangle_int_t rect;
821 cairo_region_get_rectangle (ctx->clip_region, i, &rect);
823 _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
824 _cairo_gl_composite_draw_triangles (ctx, count);
829 _cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
835 _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
840 if (_cairo_gl_context_is_flushed (ctx))
843 count = ctx->vb_offset / ctx->vertex_size;
844 _cairo_gl_composite_unmap_vertex_buffer (ctx);
846 if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) {
847 _cairo_gl_composite_draw_tristrip (ctx);
849 assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
850 _cairo_gl_composite_draw_triangles_with_clip_region (ctx, count);
853 for (i = 0; i < ARRAY_LENGTH (&ctx->glyph_cache); i++)
854 _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
858 _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
859 unsigned int n_vertices,
860 cairo_gl_primitive_type_t primitive_type)
862 if (ctx->primitive_type != primitive_type) {
863 _cairo_gl_composite_flush (ctx);
864 ctx->primitive_type = primitive_type;
867 if (ctx->vb_offset + n_vertices * ctx->vertex_size > CAIRO_GL_VBO_SIZE)
868 _cairo_gl_composite_flush (ctx);
872 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
873 GLfloat x, GLfloat y)
875 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
880 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
881 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
883 ctx->vb_offset += ctx->vertex_size;
887 _cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
888 GLfloat x, GLfloat y, uint8_t alpha)
890 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
899 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
900 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
908 ctx->vb_offset += ctx->vertex_size;
912 _cairo_gl_composite_emit_point (cairo_gl_context_t *ctx,
913 const cairo_point_t *point)
915 _cairo_gl_composite_emit_vertex (ctx,
916 _cairo_fixed_to_double (point->x),
917 _cairo_fixed_to_double (point->y));
921 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
922 GLfloat x1, GLfloat y1,
923 GLfloat x2, GLfloat y2)
925 _cairo_gl_composite_prepare_buffer (ctx, 6,
926 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
928 _cairo_gl_composite_emit_vertex (ctx, x1, y1);
929 _cairo_gl_composite_emit_vertex (ctx, x2, y1);
930 _cairo_gl_composite_emit_vertex (ctx, x1, y2);
932 _cairo_gl_composite_emit_vertex (ctx, x2, y1);
933 _cairo_gl_composite_emit_vertex (ctx, x2, y2);
934 _cairo_gl_composite_emit_vertex (ctx, x1, y2);
938 _cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
940 return _cairo_gl_composite_emit_rect;
944 _cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
945 GLfloat x1, GLfloat y1,
946 GLfloat x2, GLfloat y2)
948 _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
952 _cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
953 GLfloat x1, GLfloat y1,
954 GLfloat x2, GLfloat y2,
957 _cairo_gl_composite_prepare_buffer (ctx, 6,
958 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
960 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
961 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
962 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
964 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
965 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
966 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
970 _cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
971 GLfloat x1, GLfloat y1,
972 GLfloat x2, GLfloat y2,
981 _cairo_gl_composite_prepare_buffer (ctx, 6,
982 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
983 v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
985 v[15] = v[ 6] = v[0] = x1;
986 v[10] = v[ 4] = v[1] = y1;
987 v[12] = v[ 9] = v[3] = x2;
988 v[16] = v[13] = v[7] = y2;
994 v[17] =v[14] = v[11] = v[8] = v[5] = v[2] = fi.f;
996 ctx->vb_offset += 6*3 * sizeof(GLfloat);
1000 _cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
1002 if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE) {
1003 switch (ctx->operands[CAIRO_GL_TEX_MASK].type) {
1005 case CAIRO_GL_OPERAND_COUNT:
1007 case CAIRO_GL_OPERAND_NONE:
1008 case CAIRO_GL_OPERAND_CONSTANT:
1011 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1012 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1013 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1014 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1015 if (!ctx->operands[CAIRO_GL_TEX_MASK].gradient.texgen)
1016 return _cairo_gl_composite_emit_span;
1019 case CAIRO_GL_OPERAND_TEXTURE:
1020 if (!ctx->operands[CAIRO_GL_TEX_MASK].texture.texgen)
1021 return _cairo_gl_composite_emit_span;
1026 switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1028 case CAIRO_GL_OPERAND_COUNT:
1030 case CAIRO_GL_OPERAND_NONE:
1031 case CAIRO_GL_OPERAND_CONSTANT:
1034 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1035 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1036 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1037 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1038 if (!ctx->operands[CAIRO_GL_TEX_SOURCE].gradient.texgen)
1039 return _cairo_gl_composite_emit_span;
1042 case CAIRO_GL_OPERAND_TEXTURE:
1043 if (!ctx->operands[CAIRO_GL_TEX_SOURCE].texture.texgen)
1044 return _cairo_gl_composite_emit_span;
1047 return _cairo_gl_composite_emit_solid_span;
1051 _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
1052 GLfloat x, GLfloat y,
1053 GLfloat glyph_x, GLfloat glyph_y)
1055 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1060 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1065 ctx->vb_offset += ctx->vertex_size;
1069 _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
1070 GLfloat x1, GLfloat y1,
1071 GLfloat x2, GLfloat y2,
1072 GLfloat glyph_x1, GLfloat glyph_y1,
1073 GLfloat glyph_x2, GLfloat glyph_y2)
1075 _cairo_gl_composite_prepare_buffer (ctx, 6,
1076 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1078 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
1079 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1080 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1082 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1083 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
1084 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1088 _cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
1089 GLfloat x1, GLfloat y1,
1090 GLfloat x2, GLfloat y2,
1091 GLfloat glyph_x1, GLfloat glyph_y1,
1092 GLfloat glyph_x2, GLfloat glyph_y2)
1096 _cairo_gl_composite_prepare_buffer (ctx, 6,
1097 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1099 v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1101 v[20] = v[ 8] = v[0] = x1;
1102 v[13] = v[ 5] = v[1] = y1;
1103 v[22] = v[10] = v[2] = glyph_x1;
1104 v[15] = v[ 7] = v[3] = glyph_y1;
1106 v[16] = v[12] = v[4] = x2;
1107 v[18] = v[14] = v[6] = glyph_x2;
1109 v[21] = v[17] = v[ 9] = y2;
1110 v[23] = v[19] = v[11] = glyph_y2;
1112 ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
1115 cairo_gl_emit_glyph_t
1116 _cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx)
1118 switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1120 case CAIRO_GL_OPERAND_COUNT:
1122 case CAIRO_GL_OPERAND_NONE:
1123 case CAIRO_GL_OPERAND_CONSTANT:
1124 return _cairo_gl_composite_emit_solid_glyph;
1126 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1127 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1128 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1129 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1130 case CAIRO_GL_OPERAND_TEXTURE:
1131 return _cairo_gl_composite_emit_glyph;
1136 _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
1138 _cairo_gl_operand_destroy (&setup->src);
1139 _cairo_gl_operand_destroy (&setup->mask);
1143 _cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
1144 cairo_operator_t op,
1145 cairo_bool_t assume_component_alpha)
1147 if (assume_component_alpha) {
1148 if (op != CAIRO_OPERATOR_CLEAR &&
1149 op != CAIRO_OPERATOR_OVER &&
1150 op != CAIRO_OPERATOR_ADD)
1151 return UNSUPPORTED ("unsupported component alpha operator");
1153 if (! _cairo_gl_operator_is_supported (op))
1154 return UNSUPPORTED ("unsupported operator");
1158 return CAIRO_STATUS_SUCCESS;
1162 _cairo_gl_composite_init (cairo_gl_composite_t *setup,
1163 cairo_operator_t op,
1164 cairo_gl_surface_t *dst,
1165 cairo_bool_t assume_component_alpha)
1167 cairo_status_t status;
1169 memset (setup, 0, sizeof (cairo_gl_composite_t));
1171 status = _cairo_gl_composite_set_operator (setup, op,
1172 assume_component_alpha);
1177 setup->clip_region = dst->clip_region;
1179 return CAIRO_STATUS_SUCCESS;
1182 static cairo_int_status_t
1183 _cairo_gl_composite_append_vertex_indices (cairo_gl_context_t *ctx,
1184 int number_of_new_indices)
1186 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1187 cairo_array_t *indices = &ctx->tristrip_indices;
1188 int number_of_indices = _cairo_array_num_elements (indices);
1189 unsigned short current_vertex_index = 0;
1192 assert (number_of_new_indices > 0);
1194 /* If any preexisting triangle triangle strip indices exist on this
1195 context, we insert a set of degenerate triangles from the last
1196 preexisting vertex to our first one. */
1197 if (number_of_indices > 0) {
1198 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
1199 current_vertex_index = indices_array[number_of_indices - 1];
1201 status = _cairo_array_append (indices, ¤t_vertex_index);
1202 if (unlikely (status))
1205 current_vertex_index++;
1206 status =_cairo_array_append (indices, ¤t_vertex_index);
1207 if (unlikely (status))
1211 for (i = 0; i < number_of_new_indices; i++) {
1212 status = _cairo_array_append (indices, ¤t_vertex_index);
1213 current_vertex_index++;
1214 if (unlikely (status))
1218 return CAIRO_STATUS_SUCCESS;
1222 _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t *ctx,
1223 cairo_gl_composite_t *setup,
1224 const cairo_point_t quad[4])
1226 _cairo_gl_composite_prepare_buffer (ctx, 4,
1227 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1229 _cairo_gl_composite_emit_point (ctx, &quad[0]);
1230 _cairo_gl_composite_emit_point (ctx, &quad[1]);
1232 /* Cairo stores quad vertices in counter-clockwise order, but we need to
1233 emit them from top to bottom in the triangle strip, so we need to reverse
1234 the order of the last two vertices. */
1235 _cairo_gl_composite_emit_point (ctx, &quad[3]);
1236 _cairo_gl_composite_emit_point (ctx, &quad[2]);
1238 return _cairo_gl_composite_append_vertex_indices (ctx, 4);
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 _cairo_gl_composite_prepare_buffer (ctx, 3,
1247 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1249 _cairo_gl_composite_emit_point (ctx, &triangle[0]);
1250 _cairo_gl_composite_emit_point (ctx, &triangle[1]);
1251 _cairo_gl_composite_emit_point (ctx, &triangle[2]);
1252 return _cairo_gl_composite_append_vertex_indices (ctx, 3);