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,
61 cairo_bool_t encode_color_as_attribute)
63 _cairo_gl_operand_destroy (&setup->src);
64 return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
65 sample, extents, use_texgen,
66 encode_color_as_attribute);
70 _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
71 const cairo_gl_operand_t *source)
73 cairo_int_status_t status;
75 _cairo_gl_operand_destroy (&setup->src);
76 _cairo_gl_operand_copy (&setup->src, source);
77 if (source->type == CAIRO_GL_OPERAND_TEXTURE ||
78 source->type == CAIRO_GL_OPERAND_GAUSSIAN)
79 status = _cairo_gl_surface_resolve_multisampling (source->texture.surface);
83 _cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
84 const cairo_color_t *color)
86 _cairo_gl_operand_destroy (&setup->src);
87 _cairo_gl_solid_operand_init (&setup->src, color);
91 _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
92 const cairo_pattern_t *pattern,
93 const cairo_rectangle_int_t *sample,
94 const cairo_rectangle_int_t *extents,
95 cairo_bool_t use_texgen)
97 _cairo_gl_operand_destroy (&setup->mask);
99 return CAIRO_STATUS_SUCCESS;
101 return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
102 sample, extents, use_texgen, FALSE);
106 _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
107 const cairo_gl_operand_t *mask)
109 cairo_int_status_t status;
110 _cairo_gl_operand_destroy (&setup->mask);
112 _cairo_gl_operand_copy (&setup->mask, mask);
113 if (mask->type == CAIRO_GL_OPERAND_TEXTURE ||
114 mask->type == CAIRO_GL_OPERAND_GAUSSIAN)
115 status = _cairo_gl_surface_resolve_multisampling (mask->texture.surface);
120 _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
126 _cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
128 setup->multisample = TRUE;
132 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
133 cairo_region_t *clip_region)
135 setup->clip_region = clip_region;
139 _cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
146 _cairo_gl_composite_bind_to_shader (cairo_gl_context_t *ctx,
147 cairo_gl_composite_t *setup)
149 _cairo_gl_shader_bind_matrix4f(ctx, CAIRO_GL_UNIFORM_PROJECTION_MATRIX,
150 ctx->modelviewprojection_matrix);
151 _cairo_gl_operand_bind_to_shader (ctx, &setup->src, CAIRO_GL_TEX_SOURCE);
152 _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
156 _cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
158 cairo_filter_t filter)
161 case CAIRO_FILTER_FAST:
162 case CAIRO_FILTER_NEAREST:
163 ctx->dispatch.TexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
164 ctx->dispatch.TexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
166 case CAIRO_FILTER_GOOD:
167 case CAIRO_FILTER_BEST:
168 case CAIRO_FILTER_BILINEAR:
169 case CAIRO_FILTER_GAUSSIAN:
170 ctx->dispatch.TexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
171 ctx->dispatch.TexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
179 _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
181 cairo_extend_t extend,
182 cairo_bool_t use_atlas)
185 assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
186 (extend != CAIRO_EXTEND_REPEAT && extend != CAIRO_EXTEND_REFLECT));
189 case CAIRO_EXTEND_NONE:
190 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
191 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
192 wrap_mode = GL_CLAMP_TO_EDGE;
194 wrap_mode = GL_CLAMP_TO_BORDER;
196 case CAIRO_EXTEND_PAD:
197 wrap_mode = GL_CLAMP_TO_EDGE;
199 case CAIRO_EXTEND_REPEAT:
200 if (ctx->has_npot_repeat)
201 wrap_mode = GL_REPEAT;
203 wrap_mode = GL_CLAMP_TO_EDGE;
205 case CAIRO_EXTEND_REFLECT:
206 if (ctx->has_npot_repeat)
207 wrap_mode = GL_MIRRORED_REPEAT;
209 wrap_mode = GL_CLAMP_TO_EDGE;
215 if (likely (wrap_mode)) {
216 ctx->dispatch.TexParameteri (target, GL_TEXTURE_WRAP_S, wrap_mode);
217 ctx->dispatch.TexParameteri (target, GL_TEXTURE_WRAP_T, wrap_mode);
223 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
224 cairo_gl_tex_t tex_unit,
225 cairo_gl_operand_t *operand,
226 unsigned int vertex_offset,
227 cairo_bool_t vertex_size_changed)
229 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
230 cairo_bool_t needs_setup;
231 unsigned int offset = vertex_offset;
233 /* XXX: we need to do setup when switching from shaders
234 * to no shaders (or back) */
235 needs_setup = vertex_size_changed;
236 needs_setup |= _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
241 _cairo_gl_composite_flush (ctx);
242 _cairo_gl_context_destroy_operand (ctx, tex_unit);
245 memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
246 ctx->operands[tex_unit].vertex_offset = vertex_offset;
251 switch (operand->type) {
253 case CAIRO_GL_OPERAND_COUNT:
255 case CAIRO_GL_OPERAND_NONE:
258 case CAIRO_GL_OPERAND_CONSTANT:
259 if (operand->constant.encode_as_attribute) {
260 dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
261 GL_FLOAT, GL_FALSE, ctx->vertex_size,
262 ctx->vb + vertex_offset);
263 dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
266 case CAIRO_GL_OPERAND_TEXTURE:
267 case CAIRO_GL_OPERAND_GAUSSIAN:
268 if (ctx->states_cache.active_texture != GL_TEXTURE0 + tex_unit) {
269 dispatch->ActiveTexture (GL_TEXTURE0 + tex_unit);
270 ctx->states_cache.active_texture = GL_TEXTURE0 + tex_unit;
272 dispatch->BindTexture (ctx->tex_target, operand->texture.tex);
273 _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
274 operand->texture.attributes.extend,
275 operand->texture.use_atlas);
276 _cairo_gl_texture_set_filter (ctx, ctx->tex_target,
277 operand->texture.attributes.filter);
278 if (! operand->texture.texgen) {
279 dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
280 GL_FLOAT, GL_FALSE, ctx->vertex_size,
282 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
283 offset += 2 * sizeof (GLfloat);
286 if (operand->texture.use_atlas) {
287 dispatch->VertexAttribPointer (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit,
288 2, GL_FLOAT, GL_FALSE,
291 dispatch->EnableVertexAttribArray (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit);
292 dispatch->VertexAttribPointer (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit,
293 2, GL_FLOAT, GL_FALSE,
295 ctx->vb + offset + 2 * sizeof (float));
296 dispatch->EnableVertexAttribArray (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit);
299 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
300 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
301 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
302 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
303 if(ctx->states_cache.active_texture != GL_TEXTURE0 + tex_unit) {
304 dispatch->ActiveTexture (GL_TEXTURE0 + tex_unit);
305 ctx->states_cache.active_texture = GL_TEXTURE0 + tex_unit;
307 dispatch->BindTexture (ctx->tex_target, operand->gradient.gradient->tex);
308 _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
309 operand->gradient.extend, FALSE);
310 _cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR);
312 if (! operand->gradient.texgen) {
313 dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
314 GL_FLOAT, GL_FALSE, ctx->vertex_size,
315 ctx->vb + vertex_offset);
316 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
323 _cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
324 cairo_bool_t encode_src_as_attribute,
325 cairo_bool_t spans_enabled,
326 unsigned int vertex_size,
327 unsigned int vertex_offset)
329 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
331 if (! spans_enabled) {
334 /* If we are going to encode the source as an attribute, we don't want
335 * to disable the attribute array here only to enable it again later. */
336 if (! encode_src_as_attribute)
337 dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
342 dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
343 GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
344 ctx->vb + vertex_offset);
345 dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
350 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
351 cairo_gl_tex_t tex_unit)
353 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
355 if (!_cairo_gl_context_is_flushed (ctx))
356 _cairo_gl_composite_flush (ctx);
358 switch (ctx->operands[tex_unit].type) {
360 case CAIRO_GL_OPERAND_COUNT:
362 case CAIRO_GL_OPERAND_NONE:
365 case CAIRO_GL_OPERAND_CONSTANT:
366 if (ctx->operands[tex_unit].constant.encode_as_attribute)
367 dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
369 case CAIRO_GL_OPERAND_TEXTURE:
370 case CAIRO_GL_OPERAND_GAUSSIAN:
371 dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
372 if (ctx->operands[tex_unit].texture.use_atlas) {
373 dispatch->DisableVertexAttribArray (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit);
374 dispatch->DisableVertexAttribArray (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit);
377 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
378 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
379 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
380 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
381 dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
385 memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
389 _cairo_gl_set_operator (cairo_gl_context_t *ctx,
391 cairo_bool_t component_alpha)
396 } blend_factors[] = {
397 { GL_ZERO, GL_ZERO }, /* Clear */
398 { GL_ONE, GL_ZERO }, /* Source */
399 { GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */
400 { GL_DST_ALPHA, GL_ZERO }, /* In */
401 { GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */
402 { GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */
404 { GL_ZERO, GL_ONE }, /* Dest */
405 { GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */
406 { GL_ZERO, GL_SRC_ALPHA }, /* DestIn */
407 { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */
408 { GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */
410 { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
411 { GL_ONE, GL_ONE }, /* Add */
413 GLenum src_factor, dst_factor;
415 assert (op < ARRAY_LENGTH (blend_factors));
416 /* different dst and component_alpha changes cause flushes elsewhere */
417 if (ctx->current_operator != op)
418 _cairo_gl_composite_flush (ctx);
419 ctx->current_operator = op;
421 src_factor = blend_factors[op].src;
422 dst_factor = blend_factors[op].dst;
424 /* Even when the user requests CAIRO_CONTENT_COLOR, we use GL_RGBA
425 * due to texture filtering of GL_CLAMP_TO_BORDER. So fix those
428 if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
429 if (src_factor == GL_ONE_MINUS_DST_ALPHA)
430 src_factor = GL_ZERO;
431 if (src_factor == GL_DST_ALPHA)
435 if (component_alpha) {
436 if (dst_factor == GL_ONE_MINUS_SRC_ALPHA)
437 dst_factor = GL_ONE_MINUS_SRC_COLOR;
438 if (dst_factor == GL_SRC_ALPHA)
439 dst_factor = GL_SRC_COLOR;
442 if (ctx->current_target->base.content == CAIRO_CONTENT_ALPHA) {
443 /* cache BlendFunc, src factor and dst factor, alpha factor */
444 if (ctx->states_cache.src_color_factor != GL_ZERO ||
445 ctx->states_cache.dst_color_factor != GL_ZERO ||
446 ctx->states_cache.src_alpha_factor != src_factor ||
447 ctx->states_cache.dst_alpha_factor != dst_factor) {
448 ctx->dispatch.BlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
449 ctx->states_cache.src_color_factor = GL_ZERO;
450 ctx->states_cache.dst_color_factor = GL_ZERO;
451 ctx->states_cache.src_alpha_factor = src_factor;
452 ctx->states_cache.dst_alpha_factor = dst_factor;
454 } else if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
455 if (ctx->states_cache.src_color_factor != src_factor ||
456 ctx->states_cache.dst_color_factor != dst_factor ||
457 ctx->states_cache.src_alpha_factor != GL_ONE ||
458 ctx->states_cache.dst_alpha_factor != GL_ONE) {
459 ctx->dispatch.BlendFuncSeparate (src_factor, dst_factor, GL_ONE, GL_ONE);
460 ctx->states_cache.src_color_factor = src_factor;
461 ctx->states_cache.dst_color_factor = dst_factor;
462 ctx->states_cache.src_alpha_factor = GL_ONE;
463 ctx->states_cache.dst_alpha_factor = GL_ONE;
466 if (ctx->states_cache.src_color_factor != src_factor ||
467 ctx->states_cache.dst_color_factor != dst_factor) {
468 ctx->dispatch.BlendFunc (src_factor, dst_factor);
469 ctx->states_cache.src_color_factor = src_factor;
470 ctx->states_cache.dst_color_factor = dst_factor;
475 static cairo_status_t
476 _cairo_gl_composite_begin_component_alpha (cairo_gl_context_t *ctx,
477 cairo_gl_composite_t *setup)
479 cairo_gl_shader_t *pre_shader = NULL;
480 cairo_status_t status;
482 /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
483 * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
485 * mask IN clip ? src OP dest : dest
487 * mask IN CLIP ? 0 : dest
489 * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
491 * The model we use in _cairo_gl_set_operator() is Render's:
492 * src IN mask IN clip OP dest
493 * which would boil down to:
494 * 0 (bounded by the extents of the drawing).
496 * However, we can do a Render operation using an opaque source
497 * and DEST_OUT to produce:
498 * 1 IN mask IN clip DEST_OUT dest
500 * mask IN clip ? 0 : dest
502 if (setup->op == CAIRO_OPERATOR_CLEAR) {
503 _cairo_gl_solid_operand_init (&setup->src, CAIRO_COLOR_WHITE);
504 setup->op = CAIRO_OPERATOR_DEST_OUT;
508 * implements component-alpha %CAIRO_OPERATOR_OVER using two passes of
509 * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
511 * From http://anholt.livejournal.com/32058.html:
513 * The trouble is that component-alpha rendering requires two different sources
514 * for blending: one for the source value to the blender, which is the
515 * per-channel multiplication of source and mask, and one for the source alpha
516 * for multiplying with the destination channels, which is the multiplication
517 * of the source channels by the mask alpha. So the equation for Over is:
519 * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
520 * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
521 * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
522 * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
524 * But we can do some simpler operations, right? How about PictOpOutReverse,
525 * which has a source factor of 0 and dest factor of (1 - source alpha). We
526 * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
527 * blenders pretty easily. So we can do a component-alpha OutReverse, which
530 * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
531 * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
532 * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
533 * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
535 * OK. And if an op doesn't use the source alpha value for the destination
536 * factor, then we can do the channel multiplication in the texture blenders
537 * to get the source value, and ignore the source alpha that we wouldn't use.
538 * We've supported this in the Radeon driver for a long time. An example would
539 * be PictOpAdd, which does:
541 * dst.A = src.A * mask.A + dst.A
542 * dst.R = src.R * mask.R + dst.R
543 * dst.G = src.G * mask.G + dst.G
544 * dst.B = src.B * mask.B + dst.B
546 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
549 * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
550 * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
551 * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
552 * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
554 * This two-pass trickery could be avoided using a new GL extension that
555 * lets two values come out of the shader and into the blend unit.
557 if (setup->op == CAIRO_OPERATOR_OVER) {
558 setup->op = CAIRO_OPERATOR_ADD;
559 status = _cairo_gl_get_shader_by_type (ctx,
563 CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
565 if (unlikely (status))
569 if (ctx->pre_shader != pre_shader)
570 _cairo_gl_composite_flush (ctx);
571 ctx->pre_shader = pre_shader;
573 return CAIRO_STATUS_SUCCESS;
577 _scissor_to_doubles (cairo_gl_surface_t *surface,
578 double x1, double y1,
579 double x2, double y2)
583 cairo_gl_context_t *ctx = (cairo_gl_context_t *) cairo_surface_get_device ((cairo_surface_t *) surface);
586 if (_cairo_gl_surface_is_texture (surface) == FALSE)
587 y1 = surface->height - (y1 + height);
588 ctx->dispatch.Scissor (x1, y1, x2 - x1, height);
592 _cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
593 const cairo_rectangle_int_t *r)
595 _scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
599 _scissor_to_box (cairo_gl_surface_t *surface,
600 const cairo_box_t *box)
602 double x1, y1, x2, y2;
603 _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2);
604 _scissor_to_doubles (surface, x1, y1, x2, y2);
608 _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
609 unsigned int size_per_vertex)
611 cairo_bool_t vertex_size_changed = ctx->vertex_size != size_per_vertex;
612 if (vertex_size_changed) {
613 ctx->vertex_size = size_per_vertex;
614 _cairo_gl_composite_flush (ctx);
617 if (_cairo_gl_context_is_flushed (ctx)) {
618 ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
619 GL_FLOAT, GL_FALSE, size_per_vertex,
621 ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
624 return vertex_size_changed;
627 static cairo_int_status_t
628 _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
629 cairo_gl_context_t *ctx,
631 cairo_bool_t clip_is_equal)
633 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
635 cairo_gl_surface_t *dst = setup->dst;
636 cairo_clip_t *clip = setup->clip;
637 cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
639 if (clip->num_boxes == 1 && clip->path == NULL) {
640 _scissor_to_box (dst, &clip->boxes[0]);
641 _enable_scissor_buffer (ctx);
642 goto disable_stencil_buffer_and_return;
645 if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
646 status = CAIRO_INT_STATUS_UNSUPPORTED;
647 goto disable_stencil_buffer_and_return;
650 /* The clip is not rectangular, so use the stencil buffer. */
651 if (! ctx->states_cache.depth_mask ) {
652 ctx->dispatch.DepthMask (GL_TRUE);
653 ctx->states_cache.depth_mask = TRUE;
656 _enable_stencil_buffer (ctx);
657 _enable_scissor_buffer (ctx);
658 _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip));
661 goto activate_stencil_buffer_and_return;
663 /* Clear the stencil buffer, but only the areas that we are
664 * going to be drawing to. */
666 _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
669 setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
671 ctx->dispatch.ClearStencil (0);
672 ctx->dispatch.Clear (GL_STENCIL_BUFFER_BIT);
674 ctx->dispatch.StencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
675 ctx->dispatch.StencilFunc (GL_EQUAL, 1, 0xffffffff);
676 ctx->dispatch.ColorMask (0, 0, 0, 0);
678 status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
680 if (unlikely (status)) {
681 ctx->dispatch.ColorMask (1, 1, 1, 1);
682 goto disable_stencil_buffer_and_return;
685 /* We want to only render to the stencil buffer, so draw everything now.
686 Flushing also unbinds the VBO, which we want to rebind for regular
688 _cairo_gl_composite_flush (ctx);
689 _cairo_gl_composite_setup_vbo (ctx, vertex_size);
691 activate_stencil_buffer_and_return:
692 ctx->dispatch.ColorMask (1, 1, 1, 1);
694 ctx->dispatch.StencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
695 ctx->dispatch.StencilFunc (GL_EQUAL, 1, 0xffffffff);
696 return CAIRO_INT_STATUS_SUCCESS;
698 disable_stencil_buffer_and_return:
699 _disable_stencil_buffer (ctx);
703 static cairo_int_status_t
704 _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
705 cairo_gl_context_t *ctx,
708 cairo_bool_t clip_region_changing = TRUE;
709 cairo_bool_t clip_is_equal = TRUE;
711 if (! _cairo_clip_equal (setup->dst->clip_on_stencil_buffer, setup->clip)) {
712 _cairo_gl_composite_flush (ctx);
713 clip_is_equal = FALSE;
716 if (! setup->clip && ! setup->clip_region && ! ctx->clip_region)
717 goto disable_all_clipping;
719 clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
720 if (! _cairo_gl_context_is_flushed (ctx) &&
721 clip_region_changing)
722 _cairo_gl_composite_flush (ctx);
724 assert (!setup->clip_region || !setup->clip);
726 /* setup->clip is only used by the msaa compositor and setup->clip_region
727 * only by the other compositors, so it's safe to wait to clean up obsolete
729 if (clip_region_changing) {
730 cairo_region_destroy (ctx->clip_region);
731 ctx->clip_region = cairo_region_reference (setup->clip_region);
734 /* For clip regions, we scissor right before drawing. */
735 if (setup->clip_region)
736 goto disable_all_clipping;
739 return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
742 disable_all_clipping:
743 _disable_stencil_buffer (ctx);
744 _disable_scissor_buffer (ctx);
745 return CAIRO_INT_STATUS_SUCCESS;
749 _cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
750 cairo_gl_context_t *ctx)
752 unsigned int dst_size, src_size, mask_size, vertex_size;
753 cairo_status_t status;
754 cairo_gl_shader_t *shader;
755 cairo_bool_t component_alpha;
756 cairo_bool_t vertex_size_changed;
759 setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
760 setup->mask.texture.attributes.has_component_alpha;
762 /* Do various magic for component alpha */
763 if (component_alpha) {
764 status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
765 if (unlikely (status))
768 if (ctx->pre_shader) {
769 _cairo_gl_composite_flush (ctx);
770 ctx->pre_shader = NULL;
774 status = _cairo_gl_get_shader_by_type (ctx,
779 CAIRO_GL_SHADER_IN_CA_SOURCE :
780 CAIRO_GL_SHADER_IN_NORMAL,
782 if (unlikely (status)) {
783 ctx->pre_shader = NULL;
786 if (ctx->current_shader != shader)
787 _cairo_gl_composite_flush (ctx);
789 status = CAIRO_STATUS_SUCCESS;
791 dst_size = 2 * sizeof (GLfloat);
792 src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
793 mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
794 vertex_size = dst_size + src_size + mask_size;
797 vertex_size += sizeof (GLfloat);
799 if (setup->src.type != CAIRO_GL_OPERAND_CONSTANT ||
800 ! setup->src.constant.encode_as_attribute)
801 _cairo_gl_context_setup_spans (ctx,
803 setup->src.type == CAIRO_GL_OPERAND_CONSTANT ||
804 ! setup->src.constant.encode_as_attribute,
806 dst_size + src_size + mask_size);
808 vertex_size_changed = _cairo_gl_composite_setup_vbo (ctx, vertex_size);
810 _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src,
811 dst_size, vertex_size_changed);
812 _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask,
813 dst_size + src_size, vertex_size_changed);
815 _cairo_gl_set_operator (ctx, setup->op, component_alpha);
817 if (_cairo_gl_context_is_flushed (ctx)) {
818 if (ctx->pre_shader) {
819 _cairo_gl_set_shader (ctx, ctx->pre_shader);
820 _cairo_gl_composite_bind_to_shader (ctx, setup);
822 _cairo_gl_set_shader (ctx, shader);
823 _cairo_gl_composite_bind_to_shader (ctx, setup);
830 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
831 cairo_gl_context_t **ctx_out)
833 cairo_gl_context_t *ctx;
834 cairo_status_t status;
838 status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
839 if (unlikely (status))
842 setup->dst->content_cleared = FALSE;
844 _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
845 if (ctx->states_cache.blend_enabled == FALSE) {
846 ctx->dispatch.Enable (GL_BLEND);
847 ctx->states_cache.blend_enabled = TRUE;
849 status = _cairo_gl_set_operands_and_operator (setup, ctx);
850 if (unlikely (status))
853 status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
854 if (unlikely (status))
860 if (unlikely (status))
861 status = _cairo_gl_context_release (ctx, status);
867 _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
869 cairo_array_t* indices = &ctx->tristrip_indices;
870 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
872 if (ctx->pre_shader) {
873 cairo_gl_shader_t *prev_shader = ctx->current_shader;
875 _cairo_gl_set_shader (ctx, ctx->pre_shader);
876 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
877 ctx->dispatch.DrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
879 _cairo_gl_set_shader (ctx, prev_shader);
880 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
883 ctx->dispatch.DrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
884 _cairo_array_truncate (indices, 0);
888 _cairo_gl_composite_draw_line (cairo_gl_context_t *ctx)
890 GLenum type = GL_LINE_STRIP;
891 cairo_array_t* indices = &ctx->tristrip_indices;
892 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
894 if (ctx->draw_mode == CAIRO_GL_LINES)
897 if (ctx->pre_shader) {
898 cairo_gl_shader_t *prev_shader = ctx->current_shader;
900 _cairo_gl_set_shader (ctx, ctx->pre_shader);
901 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
902 ctx->dispatch.DrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
904 _cairo_gl_set_shader (ctx, prev_shader);
905 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
908 ctx->dispatch.DrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
909 _cairo_array_truncate (indices, 0);
913 _cairo_gl_composite_draw_triangles (cairo_gl_context_t *ctx,
916 if (! ctx->pre_shader) {
917 ctx->dispatch.DrawArrays (GL_TRIANGLES, 0, count);
919 cairo_gl_shader_t *prev_shader = ctx->current_shader;
921 _cairo_gl_set_shader (ctx, ctx->pre_shader);
922 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
923 ctx->dispatch.DrawArrays (GL_TRIANGLES, 0, count);
925 _cairo_gl_set_shader (ctx, prev_shader);
926 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
927 ctx->dispatch.DrawArrays (GL_TRIANGLES, 0, count);
932 _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
935 int i, num_rectangles;
937 if (!ctx->clip_region) {
938 _cairo_gl_composite_draw_triangles (ctx, count);
942 num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
943 for (i = 0; i < num_rectangles; i++) {
944 cairo_rectangle_int_t rect;
946 cairo_region_get_rectangle (ctx->clip_region, i, &rect);
948 _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
949 _enable_scissor_buffer (ctx);
950 _cairo_gl_composite_draw_triangles (ctx, count);
955 _cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
961 _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
966 if (_cairo_gl_context_is_flushed (ctx))
969 count = ctx->vb_offset / ctx->vertex_size;
970 _cairo_gl_composite_unmap_vertex_buffer (ctx);
972 if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) {
973 if (ctx->draw_mode == CAIRO_GL_LINE_STRIP ||
974 ctx->draw_mode == CAIRO_GL_LINES)
975 _cairo_gl_composite_draw_line (ctx);
977 _cairo_gl_composite_draw_tristrip (ctx);
979 assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
980 _cairo_gl_composite_draw_triangles_with_clip_region (ctx, count);
983 for (i = 0; i < ARRAY_LENGTH (ctx->glyph_cache); i++)
984 _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
986 _cairo_gl_image_cache_unlock (ctx);
990 _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
991 unsigned int n_vertices,
992 cairo_gl_primitive_type_t primitive_type)
994 if (ctx->primitive_type != primitive_type) {
995 _cairo_gl_composite_flush (ctx);
996 ctx->primitive_type = primitive_type;
999 if (ctx->vb_offset + n_vertices * ctx->vertex_size > CAIRO_GL_VBO_SIZE)
1000 _cairo_gl_composite_flush (ctx);
1004 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
1005 GLfloat x, GLfloat y)
1007 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1012 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1013 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
1015 ctx->vb_offset += ctx->vertex_size;
1019 _cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
1020 GLfloat x, GLfloat y, uint8_t alpha)
1022 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1031 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1032 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
1037 fi.bytes[3] = alpha;
1040 ctx->vb_offset += ctx->vertex_size;
1044 _cairo_gl_composite_emit_point (cairo_gl_context_t *ctx,
1045 const cairo_point_t *point)
1047 _cairo_gl_composite_emit_vertex (ctx,
1048 _cairo_fixed_to_double (point->x),
1049 _cairo_fixed_to_double (point->y));
1053 _cairo_gl_composite_emit_int (cairo_gl_context_t *ctx,
1059 _cairo_gl_composite_emit_vertex (ctx, fx, fy);
1063 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
1064 GLfloat x1, GLfloat y1,
1065 GLfloat x2, GLfloat y2)
1067 _cairo_gl_composite_prepare_buffer (ctx, 6,
1068 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1070 _cairo_gl_composite_emit_vertex (ctx, x1, y1);
1071 _cairo_gl_composite_emit_vertex (ctx, x2, y1);
1072 _cairo_gl_composite_emit_vertex (ctx, x1, y2);
1074 _cairo_gl_composite_emit_vertex (ctx, x2, y1);
1075 _cairo_gl_composite_emit_vertex (ctx, x2, y2);
1076 _cairo_gl_composite_emit_vertex (ctx, x1, y2);
1079 cairo_gl_emit_rect_t
1080 _cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
1082 return _cairo_gl_composite_emit_rect;
1086 _cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
1087 GLfloat x1, GLfloat y1,
1088 GLfloat x2, GLfloat y2)
1090 _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
1094 _cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
1095 GLfloat x1, GLfloat y1,
1096 GLfloat x2, GLfloat y2,
1099 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1100 _cairo_gl_composite_flush (ctx);
1101 ctx->draw_mode = CAIRO_GL_VERTEX;
1104 _cairo_gl_composite_prepare_buffer (ctx, 6,
1105 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1107 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
1108 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
1109 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
1111 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
1112 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
1113 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
1117 _cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
1118 GLfloat x1, GLfloat y1,
1119 GLfloat x2, GLfloat y2,
1123 int src_use_atlas = 0;
1124 int mask_use_atlas = 0;
1130 _cairo_gl_composite_prepare_buffer (ctx, 6,
1131 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1133 if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE ||
1134 ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_GAUSSIAN) &&
1135 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.use_atlas)
1136 src_use_atlas = TRUE;
1137 if ((ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE ||
1138 ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_GAUSSIAN) &&
1139 ctx->operands[CAIRO_GL_TEX_MASK].texture.use_atlas)
1140 mask_use_atlas = TRUE;
1142 v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1144 v[15 + 20*src_use_atlas + 20*mask_use_atlas] =
1145 v[ 6 + 8*src_use_atlas + 8*mask_use_atlas] =
1147 v[10 + 12*src_use_atlas + 12*mask_use_atlas] =
1148 v[ 4 + 4*src_use_atlas + 4*mask_use_atlas] =
1150 v[12 + 16*src_use_atlas + 16*mask_use_atlas] =
1151 v[ 9 + 12*src_use_atlas + 12*mask_use_atlas] =
1152 v[ 3 + 4*src_use_atlas + 4*mask_use_atlas] = x2;
1153 v[16 + 20*src_use_atlas + 20*mask_use_atlas] =
1154 v[13 + 16*src_use_atlas + 16*mask_use_atlas] =
1155 v[ 7 + 8*src_use_atlas + 8*mask_use_atlas] = y2;
1160 fi.bytes[3] = alpha;
1161 v[17 + 24*src_use_atlas + 24*mask_use_atlas] =
1162 v[14 + 20*src_use_atlas + 20*mask_use_atlas] =
1163 v[11 + 16*src_use_atlas + 16*mask_use_atlas] =
1164 v[ 8 + 12*src_use_atlas + 12*mask_use_atlas] =
1165 v[ 5 + 8*src_use_atlas + 8*mask_use_atlas] =
1166 v[ 2 + 4*src_use_atlas + 4*mask_use_atlas ] = fi.f;
1168 if (src_use_atlas) {
1170 v[ 5 + 4*src_use_atlas + 4*mask_use_atlas] =
1171 v[ 8 + 8*src_use_atlas + 8*mask_use_atlas] =
1172 v[11 + 12*src_use_atlas + 12*mask_use_atlas] =
1173 v[14 + 16*src_use_atlas + 16*mask_use_atlas] =
1174 v[17 + 20*src_use_atlas + 20*mask_use_atlas] =
1175 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p1.x;
1178 v[ 6 + 4*src_use_atlas + 4*mask_use_atlas] =
1179 v[ 9 + 8*src_use_atlas + 8*mask_use_atlas] =
1180 v[12 + 12*src_use_atlas + 12*mask_use_atlas] =
1181 v[15 + 16*src_use_atlas + 16*mask_use_atlas] =
1182 v[18 + 20*src_use_atlas + 20*mask_use_atlas] =
1183 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p1.y;
1186 v[ 7 + 4*src_use_atlas + 4*mask_use_atlas] =
1187 v[10 + 8*src_use_atlas + 8*mask_use_atlas] =
1188 v[13 + 12*src_use_atlas + 12*mask_use_atlas] =
1189 v[16 + 16*src_use_atlas + 16*mask_use_atlas] =
1190 v[19 + 20*src_use_atlas + 20*mask_use_atlas] =
1191 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p2.x;
1194 v[ 8 + 4*src_use_atlas + 4*mask_use_atlas] =
1195 v[11 + 8*src_use_atlas + 8*mask_use_atlas] =
1196 v[14 + 12*src_use_atlas + 12*mask_use_atlas] =
1197 v[17 + 16*src_use_atlas + 16*mask_use_atlas] =
1198 v[20 + 20*src_use_atlas + 20*mask_use_atlas] =
1199 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p2.y;
1202 if (mask_use_atlas) {
1203 v[ 2 + 4*src_use_atlas ] =
1204 v[ 5 + 8*src_use_atlas + 4*mask_use_atlas] =
1205 v[ 8 + 12*src_use_atlas + 8*mask_use_atlas] =
1206 v[11 + 16*src_use_atlas + 12*mask_use_atlas] =
1207 v[14 + 20*src_use_atlas + 16*mask_use_atlas] =
1208 v[17 + 24*src_use_atlas + 20*mask_use_atlas] =
1209 ctx->operands[CAIRO_GL_TEX_MASK].texture.p1.x;
1211 v[ 3 + 4*src_use_atlas ] =
1212 v[ 6 + 4*src_use_atlas + 4*mask_use_atlas] =
1213 v[ 9 + 8*src_use_atlas + 8*mask_use_atlas] =
1214 v[12 + 12*src_use_atlas + 12*mask_use_atlas] =
1215 v[15 + 16*src_use_atlas + 16*mask_use_atlas] =
1216 v[18 + 20*src_use_atlas + 20*mask_use_atlas] =
1217 ctx->operands[CAIRO_GL_TEX_MASK].texture.p1.y;
1219 v[ 4 + 4*src_use_atlas ] =
1220 v[ 7 + 4*src_use_atlas + 4*mask_use_atlas] =
1221 v[10 + 8*src_use_atlas + 8*mask_use_atlas] =
1222 v[13 + 12*src_use_atlas + 12*mask_use_atlas] =
1223 v[16 + 16*src_use_atlas + 16*mask_use_atlas] =
1224 v[19 + 20*src_use_atlas + 20*mask_use_atlas] =
1225 ctx->operands[CAIRO_GL_TEX_MASK].texture.p2.x;
1227 v[ 5 + 4*src_use_atlas ] =
1228 v[ 8 + 4*src_use_atlas + 4*mask_use_atlas] =
1229 v[11 + 8*src_use_atlas + 8*mask_use_atlas] =
1230 v[14 + 12*src_use_atlas + 12*mask_use_atlas] =
1231 v[17 + 16*src_use_atlas + 16*mask_use_atlas] =
1232 v[20 + 20*src_use_atlas + 20*mask_use_atlas] =
1233 ctx->operands[CAIRO_GL_TEX_MASK].texture.p2.y;
1236 ctx->vb_offset += 6*(3 + 4*src_use_atlas + 4*mask_use_atlas) * sizeof(GLfloat);
1239 cairo_gl_emit_span_t
1240 _cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
1242 if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE) {
1243 switch (ctx->operands[CAIRO_GL_TEX_MASK].type) {
1245 case CAIRO_GL_OPERAND_COUNT:
1247 case CAIRO_GL_OPERAND_NONE:
1248 case CAIRO_GL_OPERAND_CONSTANT:
1251 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1252 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1253 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1254 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1255 if (!ctx->operands[CAIRO_GL_TEX_MASK].gradient.texgen)
1256 return _cairo_gl_composite_emit_span;
1259 case CAIRO_GL_OPERAND_TEXTURE:
1260 case CAIRO_GL_OPERAND_GAUSSIAN:
1261 if (!ctx->operands[CAIRO_GL_TEX_MASK].texture.texgen)
1262 return _cairo_gl_composite_emit_span;
1267 switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1269 case CAIRO_GL_OPERAND_COUNT:
1271 case CAIRO_GL_OPERAND_NONE:
1272 case CAIRO_GL_OPERAND_CONSTANT:
1275 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1276 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1277 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1278 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1279 if (!ctx->operands[CAIRO_GL_TEX_SOURCE].gradient.texgen)
1280 return _cairo_gl_composite_emit_span;
1283 case CAIRO_GL_OPERAND_TEXTURE:
1284 case CAIRO_GL_OPERAND_GAUSSIAN:
1285 if (!ctx->operands[CAIRO_GL_TEX_SOURCE].texture.texgen)
1286 return _cairo_gl_composite_emit_span;
1289 return _cairo_gl_composite_emit_solid_span;
1293 _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
1294 GLfloat x, GLfloat y,
1295 GLfloat glyph_x, GLfloat glyph_y)
1297 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1302 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1307 ctx->vb_offset += ctx->vertex_size;
1311 _cairo_gl_composite_emit_color_glyph_vertex (cairo_gl_context_t *ctx,
1312 GLfloat x, GLfloat y,
1313 GLfloat glyph_x, GLfloat glyph_y)
1315 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1322 ctx->vb_offset += ctx->vertex_size;
1326 _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
1327 GLfloat x1, GLfloat y1,
1328 GLfloat x2, GLfloat y2,
1329 GLfloat glyph_x1, GLfloat glyph_y1,
1330 GLfloat glyph_x2, GLfloat glyph_y2)
1332 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1333 _cairo_gl_composite_flush (ctx);
1334 ctx->draw_mode = CAIRO_GL_VERTEX;
1337 _cairo_gl_composite_prepare_buffer (ctx, 6,
1338 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1340 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
1341 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1342 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1344 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1345 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
1346 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1350 _cairo_gl_composite_emit_color_glyph (cairo_gl_context_t *ctx,
1351 GLfloat x1, GLfloat y1,
1352 GLfloat x2, GLfloat y2,
1353 GLfloat glyph_x1, GLfloat glyph_y1,
1354 GLfloat glyph_x2, GLfloat glyph_y2)
1356 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1357 _cairo_gl_composite_flush (ctx);
1358 ctx->draw_mode = CAIRO_GL_VERTEX;
1361 _cairo_gl_composite_prepare_buffer (ctx, 6,
1362 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1364 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
1365 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1366 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1368 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1369 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
1370 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1374 _cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
1375 GLfloat x1, GLfloat y1,
1376 GLfloat x2, GLfloat y2,
1377 GLfloat glyph_x1, GLfloat glyph_y1,
1378 GLfloat glyph_x2, GLfloat glyph_y2)
1382 _cairo_gl_composite_prepare_buffer (ctx, 6,
1383 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1385 v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1387 v[20] = v[ 8] = v[0] = x1;
1388 v[13] = v[ 5] = v[1] = y1;
1389 v[22] = v[10] = v[2] = glyph_x1;
1390 v[15] = v[ 7] = v[3] = glyph_y1;
1392 v[16] = v[12] = v[4] = x2;
1393 v[18] = v[14] = v[6] = glyph_x2;
1395 v[21] = v[17] = v[ 9] = y2;
1396 v[23] = v[19] = v[11] = glyph_y2;
1398 ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
1401 cairo_gl_emit_glyph_t
1402 _cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx,
1403 const cairo_bool_t is_color_glyph)
1406 if ( is_color_glyph) {
1407 /* color glyph ignore all source and mask */
1408 return _cairo_gl_composite_emit_color_glyph;
1411 switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1413 case CAIRO_GL_OPERAND_COUNT:
1415 case CAIRO_GL_OPERAND_NONE:
1416 case CAIRO_GL_OPERAND_CONSTANT:
1417 if (! ctx->operands[CAIRO_GL_TEX_SOURCE].constant.encode_as_attribute)
1418 return _cairo_gl_composite_emit_solid_glyph;
1420 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1421 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1422 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1423 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1424 case CAIRO_GL_OPERAND_TEXTURE:
1425 case CAIRO_GL_OPERAND_GAUSSIAN:
1426 return _cairo_gl_composite_emit_glyph;
1431 _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
1433 _cairo_gl_operand_destroy (&setup->src);
1434 _cairo_gl_operand_destroy (&setup->mask);
1438 _cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
1439 cairo_operator_t op,
1440 cairo_bool_t assume_component_alpha)
1442 if (assume_component_alpha) {
1443 if (op != CAIRO_OPERATOR_CLEAR &&
1444 op != CAIRO_OPERATOR_OVER &&
1445 op != CAIRO_OPERATOR_ADD)
1446 return UNSUPPORTED ("unsupported component alpha operator");
1448 if (! _cairo_gl_operator_is_supported (op))
1449 return UNSUPPORTED ("unsupported operator");
1453 return CAIRO_STATUS_SUCCESS;
1457 _cairo_gl_composite_init (cairo_gl_composite_t *setup,
1458 cairo_operator_t op,
1459 cairo_gl_surface_t *dst,
1460 cairo_bool_t assume_component_alpha)
1462 cairo_status_t status;
1464 memset (setup, 0, sizeof (cairo_gl_composite_t));
1466 status = _cairo_gl_composite_set_operator (setup, op,
1467 assume_component_alpha);
1472 setup->clip_region = dst->clip_region;
1474 return CAIRO_STATUS_SUCCESS;
1477 static cairo_int_status_t
1478 _cairo_gl_composite_append_vertex_indices (cairo_gl_context_t *ctx,
1479 int number_of_new_indices,
1480 cairo_bool_t is_connected)
1482 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1483 cairo_array_t *indices = &ctx->tristrip_indices;
1484 int number_of_indices = _cairo_array_num_elements (indices);
1485 unsigned short current_vertex_index = 0;
1488 assert (number_of_new_indices > 0);
1490 /* If any preexisting triangle triangle strip indices exist on this
1491 context, we insert a set of degenerate triangles from the last
1492 preexisting vertex to our first one. */
1493 if (number_of_indices > 0 && is_connected) {
1494 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
1495 if (indices_array == NULL)
1496 return CAIRO_STATUS_NULL_POINTER;
1497 current_vertex_index = indices_array[number_of_indices - 1];
1499 status = _cairo_array_append (indices, ¤t_vertex_index);
1500 if (unlikely (status))
1503 current_vertex_index++;
1504 status =_cairo_array_append (indices, ¤t_vertex_index);
1505 if (unlikely (status))
1508 current_vertex_index = (unsigned short) number_of_indices;
1510 for (i = 0; i < number_of_new_indices; i++) {
1511 status = _cairo_array_append (indices, ¤t_vertex_index);
1512 current_vertex_index++;
1513 if (unlikely (status))
1517 return CAIRO_STATUS_SUCCESS;
1521 _cairo_gl_composite_emit_int_quad_as_tristrip (cairo_gl_context_t *ctx,
1522 cairo_gl_composite_t *setup,
1525 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1526 _cairo_gl_composite_flush (ctx);
1527 ctx->draw_mode = CAIRO_GL_VERTEX;
1530 _cairo_gl_composite_prepare_buffer (ctx, 4,
1531 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1533 _cairo_gl_composite_emit_int (ctx, quad[0], quad[1]);
1534 _cairo_gl_composite_emit_int (ctx, quad[2], quad[3]);
1536 /* Cairo stores quad vertices in counter-clockwise order, but we need to
1537 emit them from top to bottom in the triangle strip, so we need to reverse
1538 the order of the last two vertices. */
1539 _cairo_gl_composite_emit_int (ctx, quad[6], quad[7]);
1540 _cairo_gl_composite_emit_int (ctx, quad[4], quad[5]);
1542 return _cairo_gl_composite_append_vertex_indices (ctx, 4, TRUE);
1546 _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t *ctx,
1547 cairo_gl_composite_t *setup,
1548 const cairo_point_t quad[4])
1550 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1551 _cairo_gl_composite_flush (ctx);
1552 ctx->draw_mode = CAIRO_GL_VERTEX;
1555 _cairo_gl_composite_prepare_buffer (ctx, 4,
1556 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1558 _cairo_gl_composite_emit_point (ctx, &quad[0]);
1559 _cairo_gl_composite_emit_point (ctx, &quad[1]);
1561 /* Cairo stores quad vertices in counter-clockwise order, but we need to
1562 emit them from top to bottom in the triangle strip, so we need to reverse
1563 the order of the last two vertices. */
1564 _cairo_gl_composite_emit_point (ctx, &quad[3]);
1565 _cairo_gl_composite_emit_point (ctx, &quad[2]);
1567 return _cairo_gl_composite_append_vertex_indices (ctx, 4, TRUE);
1571 _cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t *ctx,
1572 cairo_gl_composite_t *setup,
1573 const cairo_point_t triangle[3])
1575 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1576 _cairo_gl_composite_flush (ctx);
1577 ctx->draw_mode = CAIRO_GL_VERTEX;
1580 _cairo_gl_composite_prepare_buffer (ctx, 3,
1581 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1583 _cairo_gl_composite_emit_point (ctx, &triangle[0]);
1584 _cairo_gl_composite_emit_point (ctx, &triangle[1]);
1585 _cairo_gl_composite_emit_point (ctx, &triangle[2]);
1586 return _cairo_gl_composite_append_vertex_indices (ctx, 3, TRUE);
1590 _cairo_gl_composite_emit_point_as_single_line (cairo_gl_context_t *ctx,
1591 const cairo_point_t point[2])
1593 int num_indices = 2;
1594 if (ctx->draw_mode != CAIRO_GL_LINES)
1595 _cairo_gl_composite_flush (ctx);
1597 ctx->draw_mode = CAIRO_GL_LINES;
1599 _cairo_gl_composite_prepare_buffer (ctx, 2,
1600 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1602 _cairo_gl_composite_emit_point (ctx, &point[0]);
1603 _cairo_gl_composite_emit_point (ctx, &point[1]);
1604 return _cairo_gl_composite_append_vertex_indices (ctx, num_indices, FALSE);