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-ttrace.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_texgen,
62 cairo_bool_t encode_color_as_attribute)
64 _cairo_gl_operand_destroy (&setup->src);
65 return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
66 sample, extents, use_texgen,
67 encode_color_as_attribute);
71 _cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
72 const cairo_gl_operand_t *source)
74 cairo_int_status_t status;
76 _cairo_gl_operand_destroy (&setup->src);
77 _cairo_gl_operand_copy (&setup->src, source);
78 if (source->type == CAIRO_GL_OPERAND_TEXTURE ||
79 source->type == CAIRO_GL_OPERAND_GAUSSIAN)
80 status = _cairo_gl_surface_resolve_multisampling (source->texture.surface);
84 _cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
85 const cairo_color_t *color)
87 _cairo_gl_operand_destroy (&setup->src);
88 _cairo_gl_solid_operand_init (&setup->src, color);
92 _cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
93 const cairo_pattern_t *pattern,
94 const cairo_rectangle_int_t *sample,
95 const cairo_rectangle_int_t *extents,
96 cairo_bool_t use_texgen)
98 _cairo_gl_operand_destroy (&setup->mask);
100 return CAIRO_INT_STATUS_SUCCESS;
102 return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
103 sample, extents, use_texgen, FALSE);
107 _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
108 const cairo_gl_operand_t *mask)
110 cairo_int_status_t status;
111 _cairo_gl_operand_destroy (&setup->mask);
113 _cairo_gl_operand_copy (&setup->mask, mask);
114 if (mask->type == CAIRO_GL_OPERAND_TEXTURE ||
115 mask->type == CAIRO_GL_OPERAND_GAUSSIAN)
116 status = _cairo_gl_surface_resolve_multisampling (mask->texture.surface);
121 _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
127 _cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
129 setup->multisample = TRUE;
133 _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
134 cairo_region_t *clip_region)
136 setup->clip_region = clip_region;
140 _cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
147 _cairo_gl_composite_bind_to_shader (cairo_gl_context_t *ctx,
148 cairo_gl_composite_t *setup)
150 _cairo_gl_shader_bind_matrix4f(ctx, ctx->current_shader->mvp_location,
151 ctx->modelviewprojection_matrix);
152 _cairo_gl_operand_bind_to_shader (ctx, &setup->src, CAIRO_GL_TEX_SOURCE);
153 _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
157 _cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
159 cairo_filter_t filter)
162 case CAIRO_FILTER_FAST:
163 case CAIRO_FILTER_NEAREST:
164 ctx->dispatch.TexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
165 ctx->dispatch.TexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
167 case CAIRO_FILTER_GOOD:
168 case CAIRO_FILTER_BEST:
169 case CAIRO_FILTER_BILINEAR:
170 case CAIRO_FILTER_GAUSSIAN:
171 ctx->dispatch.TexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
172 ctx->dispatch.TexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
180 _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
182 cairo_extend_t extend,
183 cairo_bool_t use_atlas)
186 assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
187 (extend != CAIRO_EXTEND_REPEAT && extend != CAIRO_EXTEND_REFLECT));
190 case CAIRO_EXTEND_NONE:
191 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
192 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
193 wrap_mode = GL_CLAMP_TO_EDGE;
195 wrap_mode = GL_CLAMP_TO_BORDER;
197 case CAIRO_EXTEND_PAD:
198 wrap_mode = GL_CLAMP_TO_EDGE;
200 case CAIRO_EXTEND_REPEAT:
201 if (ctx->has_npot_repeat)
202 wrap_mode = GL_REPEAT;
204 wrap_mode = GL_CLAMP_TO_EDGE;
206 case CAIRO_EXTEND_REFLECT:
207 if (ctx->has_npot_repeat)
208 wrap_mode = GL_MIRRORED_REPEAT;
210 wrap_mode = GL_CLAMP_TO_EDGE;
216 if (likely (wrap_mode)) {
217 ctx->dispatch.TexParameteri (target, GL_TEXTURE_WRAP_S, wrap_mode);
218 ctx->dispatch.TexParameteri (target, GL_TEXTURE_WRAP_T, wrap_mode);
224 _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
225 cairo_gl_tex_t tex_unit,
226 cairo_gl_operand_t *operand,
227 unsigned int vertex_offset,
228 cairo_bool_t vertex_size_changed)
230 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
231 cairo_bool_t needs_setup;
232 unsigned int offset = vertex_offset;
234 /* XXX: we need to do setup when switching from shaders
235 * to no shaders (or back) */
236 needs_setup = vertex_size_changed;
237 needs_setup |= _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
242 _cairo_gl_composite_flush (ctx);
243 _cairo_gl_context_destroy_operand (ctx, tex_unit);
246 memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
247 ctx->operands[tex_unit].vertex_offset = vertex_offset;
252 switch (operand->type) {
254 case CAIRO_GL_OPERAND_COUNT:
256 case CAIRO_GL_OPERAND_NONE:
259 case CAIRO_GL_OPERAND_CONSTANT:
260 if (operand->constant.encode_as_attribute) {
261 dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
262 GL_FLOAT, GL_FALSE, ctx->vertex_size,
263 ctx->vbo ? (GLvoid *)vertex_offset : (GLvoid *)(ctx->vb + vertex_offset));
264 dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
267 case CAIRO_GL_OPERAND_TEXTURE:
268 case CAIRO_GL_OPERAND_GAUSSIAN:
269 if (ctx->states_cache.active_texture != GL_TEXTURE0 + tex_unit) {
270 dispatch->ActiveTexture (GL_TEXTURE0 + tex_unit);
271 ctx->states_cache.active_texture = GL_TEXTURE0 + tex_unit;
273 dispatch->BindTexture (ctx->tex_target, operand->texture.tex);
274 _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
275 operand->texture.attributes.extend,
276 operand->texture.use_atlas);
277 _cairo_gl_texture_set_filter (ctx, ctx->tex_target,
278 operand->texture.attributes.filter);
279 if (! operand->texture.texgen) {
280 dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
281 GL_FLOAT, GL_FALSE, ctx->vertex_size,
282 ctx->vbo ? (GLvoid *)offset : (GLvoid *)(ctx->vb + offset));
283 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
284 offset += 2 * sizeof (GLfloat);
287 if (operand->texture.use_atlas) {
288 dispatch->VertexAttribPointer (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit,
289 2, GL_FLOAT, GL_FALSE,
291 ctx->vbo ? (GLvoid *)offset : (GLvoid *)(ctx->vb + offset));
292 dispatch->EnableVertexAttribArray (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit);
293 dispatch->VertexAttribPointer (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit,
294 2, GL_FLOAT, GL_FALSE,
296 ctx->vbo ? (GLvoid *)(offset + 2 * sizeof (float)) : (GLvoid *)(ctx->vb + offset + 2 * sizeof (float)));
297 dispatch->EnableVertexAttribArray (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit);
300 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
301 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
302 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
303 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
304 if(ctx->states_cache.active_texture != GL_TEXTURE0 + tex_unit) {
305 dispatch->ActiveTexture (GL_TEXTURE0 + tex_unit);
306 ctx->states_cache.active_texture = GL_TEXTURE0 + tex_unit;
308 dispatch->BindTexture (ctx->tex_target, operand->gradient.gradient->tex);
309 _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
310 operand->gradient.extend, FALSE);
311 _cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR);
313 if (! operand->gradient.texgen) {
314 dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
315 GL_FLOAT, GL_FALSE, ctx->vertex_size,
316 ctx->vbo ? (GLvoid *)vertex_offset : (GLvoid *)(ctx->vb + vertex_offset));
317 dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
324 _cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
325 cairo_bool_t spans_enabled,
326 cairo_bool_t encode_src_as_attribute,
327 unsigned int vertex_size,
328 unsigned int vertex_offset)
330 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
332 if (! spans_enabled) {
335 /* If we are going to encode the source as an attribute, we don't want
336 * to disable the attribute array here only to enable it again later. */
337 if (! encode_src_as_attribute)
338 dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
343 dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
344 GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
345 ctx->vbo ? (GLvoid *)vertex_offset : (GLvoid *)(ctx->vb + vertex_offset));
346 dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
351 _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
352 cairo_gl_tex_t tex_unit)
354 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
356 if (!_cairo_gl_context_is_flushed (ctx))
357 _cairo_gl_composite_flush (ctx);
359 switch (ctx->operands[tex_unit].type) {
361 case CAIRO_GL_OPERAND_COUNT:
363 case CAIRO_GL_OPERAND_NONE:
366 case CAIRO_GL_OPERAND_CONSTANT:
367 if (ctx->operands[tex_unit].constant.encode_as_attribute)
368 dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
370 case CAIRO_GL_OPERAND_TEXTURE:
371 case CAIRO_GL_OPERAND_GAUSSIAN:
372 dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
373 if (ctx->operands[tex_unit].texture.use_atlas) {
374 dispatch->DisableVertexAttribArray (CAIRO_GL_START_COORD0_ATTRIB_INDEX + tex_unit);
375 dispatch->DisableVertexAttribArray (CAIRO_GL_STOP_COORD0_ATTRIB_INDEX + tex_unit);
378 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
379 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
380 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
381 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
382 dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
386 memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
390 _cairo_gl_set_operator (cairo_gl_context_t *ctx,
392 cairo_bool_t component_alpha)
397 } blend_factors[] = {
398 { GL_ZERO, GL_ZERO }, /* Clear */
399 { GL_ONE, GL_ZERO }, /* Source */
400 { GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */
401 { GL_DST_ALPHA, GL_ZERO }, /* In */
402 { GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */
403 { GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */
405 { GL_ZERO, GL_ONE }, /* Dest */
406 { GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */
407 { GL_ZERO, GL_SRC_ALPHA }, /* DestIn */
408 { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */
409 { GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */
411 { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
412 { GL_ONE, GL_ONE }, /* Add */
414 GLenum src_factor, dst_factor;
416 assert (op < ARRAY_LENGTH (blend_factors));
417 /* different dst and component_alpha changes cause flushes elsewhere */
418 if (ctx->current_operator != op)
419 _cairo_gl_composite_flush (ctx);
420 ctx->current_operator = op;
422 src_factor = blend_factors[op].src;
423 dst_factor = blend_factors[op].dst;
425 /* Even when the user requests CAIRO_CONTENT_COLOR, we use GL_RGBA
426 * due to texture filtering of GL_CLAMP_TO_BORDER. So fix those
429 if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
430 if (src_factor == GL_ONE_MINUS_DST_ALPHA)
431 src_factor = GL_ZERO;
432 if (src_factor == GL_DST_ALPHA)
436 if (component_alpha) {
437 if (dst_factor == GL_ONE_MINUS_SRC_ALPHA)
438 dst_factor = GL_ONE_MINUS_SRC_COLOR;
439 if (dst_factor == GL_SRC_ALPHA)
440 dst_factor = GL_SRC_COLOR;
443 if (ctx->current_target->base.content == CAIRO_CONTENT_ALPHA) {
444 /* cache BlendFunc, src factor and dst factor, alpha factor */
445 if (ctx->states_cache.src_color_factor != GL_ZERO ||
446 ctx->states_cache.dst_color_factor != GL_ZERO ||
447 ctx->states_cache.src_alpha_factor != src_factor ||
448 ctx->states_cache.dst_alpha_factor != dst_factor) {
449 ctx->dispatch.BlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
450 ctx->states_cache.src_color_factor = GL_ZERO;
451 ctx->states_cache.dst_color_factor = GL_ZERO;
452 ctx->states_cache.src_alpha_factor = src_factor;
453 ctx->states_cache.dst_alpha_factor = dst_factor;
455 } else if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
456 if (ctx->states_cache.src_color_factor != src_factor ||
457 ctx->states_cache.dst_color_factor != dst_factor ||
458 ctx->states_cache.src_alpha_factor != GL_ONE ||
459 ctx->states_cache.dst_alpha_factor != GL_ONE) {
460 ctx->dispatch.BlendFuncSeparate (src_factor, dst_factor, GL_ONE, GL_ONE);
461 ctx->states_cache.src_color_factor = src_factor;
462 ctx->states_cache.dst_color_factor = dst_factor;
463 ctx->states_cache.src_alpha_factor = GL_ONE;
464 ctx->states_cache.dst_alpha_factor = GL_ONE;
467 if (ctx->states_cache.src_color_factor != src_factor ||
468 ctx->states_cache.dst_color_factor != dst_factor) {
469 ctx->dispatch.BlendFunc (src_factor, dst_factor);
470 ctx->states_cache.src_color_factor = src_factor;
471 ctx->states_cache.dst_color_factor = dst_factor;
476 static cairo_status_t
477 _cairo_gl_composite_begin_component_alpha (cairo_gl_context_t *ctx,
478 cairo_gl_composite_t *setup)
480 cairo_gl_shader_t *pre_shader = NULL;
481 cairo_status_t status;
483 /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
484 * http://lists.cairographics.org/archives/cairo/2005-August/004992.html)
486 * mask IN clip ? src OP dest : dest
488 * mask IN CLIP ? 0 : dest
490 * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
492 * The model we use in _cairo_gl_set_operator() is Render's:
493 * src IN mask IN clip OP dest
494 * which would boil down to:
495 * 0 (bounded by the extents of the drawing).
497 * However, we can do a Render operation using an opaque source
498 * and DEST_OUT to produce:
499 * 1 IN mask IN clip DEST_OUT dest
501 * mask IN clip ? 0 : dest
503 if (setup->op == CAIRO_OPERATOR_CLEAR) {
504 _cairo_gl_solid_operand_init (&setup->src, CAIRO_COLOR_WHITE);
505 setup->op = CAIRO_OPERATOR_DEST_OUT;
509 * implements component-alpha %CAIRO_OPERATOR_OVER using two passes of
510 * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
512 * From http://anholt.livejournal.com/32058.html:
514 * The trouble is that component-alpha rendering requires two different sources
515 * for blending: one for the source value to the blender, which is the
516 * per-channel multiplication of source and mask, and one for the source alpha
517 * for multiplying with the destination channels, which is the multiplication
518 * of the source channels by the mask alpha. So the equation for Over is:
520 * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
521 * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
522 * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
523 * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
525 * But we can do some simpler operations, right? How about PictOpOutReverse,
526 * which has a source factor of 0 and dest factor of (1 - source alpha). We
527 * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
528 * blenders pretty easily. So we can do a component-alpha OutReverse, which
531 * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
532 * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
533 * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
534 * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
536 * OK. And if an op doesn't use the source alpha value for the destination
537 * factor, then we can do the channel multiplication in the texture blenders
538 * to get the source value, and ignore the source alpha that we wouldn't use.
539 * We've supported this in the Radeon driver for a long time. An example would
540 * be PictOpAdd, which does:
542 * dst.A = src.A * mask.A + dst.A
543 * dst.R = src.R * mask.R + dst.R
544 * dst.G = src.G * mask.G + dst.G
545 * dst.B = src.B * mask.B + dst.B
547 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
550 * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
551 * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
552 * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
553 * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
555 * This two-pass trickery could be avoided using a new GL extension that
556 * lets two values come out of the shader and into the blend unit.
558 if (setup->op == CAIRO_OPERATOR_OVER) {
559 setup->op = CAIRO_OPERATOR_ADD;
560 status = _cairo_gl_get_shader_by_type (ctx,
564 CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
566 if (unlikely (status))
570 if (ctx->pre_shader != pre_shader)
571 _cairo_gl_composite_flush (ctx);
572 ctx->pre_shader = pre_shader;
574 return CAIRO_STATUS_SUCCESS;
578 _scissor_to_doubles (cairo_gl_surface_t *surface,
579 double x1, double y1,
580 double x2, double y2)
584 cairo_gl_context_t *ctx = (cairo_gl_context_t *) cairo_surface_get_device ((cairo_surface_t *) surface);
587 if (_cairo_gl_surface_is_texture (surface) == FALSE)
588 y1 = surface->height - (y1 + height);
589 ctx->dispatch.Scissor (x1, y1, x2 - x1, height);
593 _cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
594 const cairo_rectangle_int_t *r)
596 _scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
600 _scissor_to_box (cairo_gl_surface_t *surface,
601 const cairo_box_t *box)
603 double x1, y1, x2, y2;
604 _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2);
605 _scissor_to_doubles (surface, x1, y1, x2, y2);
609 _cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
610 unsigned int size_per_vertex)
612 cairo_bool_t vertex_size_changed = ctx->vertex_size != size_per_vertex;
613 if (vertex_size_changed) {
614 ctx->vertex_size = size_per_vertex;
615 _cairo_gl_composite_flush (ctx);
618 if (_cairo_gl_context_is_flushed (ctx)) {
619 ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
620 GL_FLOAT, GL_FALSE, size_per_vertex,
621 ctx->vbo ? 0 : ctx->vb);
622 ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
625 return vertex_size_changed;
628 static cairo_int_status_t
629 _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
630 cairo_gl_context_t *ctx,
632 cairo_bool_t clip_is_equal)
634 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
636 cairo_gl_surface_t *dst = setup->dst;
637 cairo_clip_t *clip = setup->clip;
638 cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
640 if (clip->num_boxes == 1 && clip->path == NULL) {
641 _scissor_to_box (dst, &clip->boxes[0]);
642 _enable_scissor_buffer (ctx);
643 goto disable_stencil_buffer_and_return;
646 if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
647 status = CAIRO_INT_STATUS_UNSUPPORTED;
648 goto disable_stencil_buffer_and_return;
651 /* The clip is not rectangular, so use the stencil buffer. */
652 if (! ctx->states_cache.depth_mask ) {
653 ctx->dispatch.DepthMask (GL_TRUE);
654 ctx->states_cache.depth_mask = TRUE;
657 _enable_stencil_buffer (ctx);
658 _enable_scissor_buffer (ctx);
660 /* We only want to clear the part of the stencil buffer
661 * that we are about to use. It also does not hurt to
662 * scissor around the painted clip. */
663 _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip));
666 goto activate_stencil_buffer_and_return;
669 _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
671 setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
673 ctx->dispatch.ClearStencil (0);
674 ctx->dispatch.Clear (GL_STENCIL_BUFFER_BIT);
676 ctx->dispatch.StencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
677 ctx->dispatch.StencilFunc (GL_EQUAL, 1, 0xffffffff);
678 ctx->dispatch.ColorMask (0, 0, 0, 0);
680 status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
682 if (unlikely (status)) {
683 ctx->dispatch.ColorMask (1, 1, 1, 1);
684 goto disable_stencil_buffer_and_return;
687 /* We want to only render to the stencil buffer, so draw everything now.
688 Flushing also unbinds the VBO, which we want to rebind for regular
690 _cairo_gl_composite_flush (ctx);
691 _cairo_gl_composite_setup_vbo (ctx, vertex_size);
693 activate_stencil_buffer_and_return:
694 ctx->dispatch.ColorMask (1, 1, 1, 1);
696 ctx->dispatch.StencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
697 ctx->dispatch.StencilFunc (GL_EQUAL, 1, 0xffffffff);
698 return CAIRO_INT_STATUS_SUCCESS;
700 disable_stencil_buffer_and_return:
701 _disable_stencil_buffer (ctx);
705 static cairo_int_status_t
706 _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
707 cairo_gl_context_t *ctx,
710 cairo_bool_t clip_region_changing = TRUE;
711 cairo_bool_t clip_is_equal = TRUE;
713 if (! _cairo_clip_equal (setup->dst->clip_on_stencil_buffer, setup->clip)) {
714 _cairo_gl_composite_flush (ctx);
715 clip_is_equal = FALSE;
718 if (! setup->clip && ! setup->clip_region && ! ctx->clip_region)
719 goto disable_all_clipping;
721 clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
722 if (! _cairo_gl_context_is_flushed (ctx) &&
723 clip_region_changing)
724 _cairo_gl_composite_flush (ctx);
726 assert (!setup->clip_region || !setup->clip);
728 /* setup->clip is only used by the msaa compositor and setup->clip_region
729 * only by the other compositors, so it's safe to wait to clean up obsolete
731 if (clip_region_changing) {
732 cairo_region_destroy (ctx->clip_region);
733 ctx->clip_region = cairo_region_reference (setup->clip_region);
736 /* For clip regions, we scissor right before drawing. */
737 if (setup->clip_region)
738 goto disable_all_clipping;
741 return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
744 disable_all_clipping:
745 _disable_stencil_buffer (ctx);
746 _disable_scissor_buffer (ctx);
747 return CAIRO_INT_STATUS_SUCCESS;
751 _cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
752 cairo_gl_context_t *ctx)
754 unsigned int dst_size, src_size, mask_size, vertex_size;
755 cairo_status_t status;
756 cairo_gl_shader_t *shader;
757 cairo_bool_t component_alpha;
758 cairo_bool_t vertex_size_changed;
761 setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
762 setup->mask.texture.attributes.has_component_alpha;
764 /* Do various magic for component alpha */
765 if (component_alpha) {
766 status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
767 if (unlikely (status))
770 if (ctx->pre_shader) {
771 _cairo_gl_composite_flush (ctx);
772 ctx->pre_shader = NULL;
776 status = _cairo_gl_get_shader_by_type (ctx,
781 CAIRO_GL_SHADER_IN_CA_SOURCE :
782 CAIRO_GL_SHADER_IN_NORMAL,
784 if (unlikely (status)) {
785 ctx->pre_shader = NULL;
789 if (ctx->current_shader != shader)
790 _cairo_gl_composite_flush (ctx);
792 status = CAIRO_STATUS_SUCCESS;
794 dst_size = 2 * sizeof (GLfloat);
795 src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
796 mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
797 vertex_size = dst_size + src_size + mask_size;
800 vertex_size += sizeof (GLfloat);
802 if (setup->src.type == CAIRO_GL_OPERAND_CONSTANT)
803 _cairo_gl_context_setup_spans (ctx,
805 setup->src.constant.encode_as_attribute,
807 dst_size + src_size + mask_size);
809 vertex_size_changed = _cairo_gl_composite_setup_vbo (ctx, vertex_size);
811 _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src,
812 dst_size, vertex_size_changed);
813 _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask,
814 dst_size + src_size, vertex_size_changed);
816 _cairo_gl_set_operator (ctx, setup->op, component_alpha);
818 if (_cairo_gl_context_is_flushed (ctx)) {
819 if (ctx->pre_shader) {
820 _cairo_gl_set_shader (ctx, ctx->pre_shader);
821 _cairo_gl_composite_bind_to_shader (ctx, setup);
823 _cairo_gl_set_shader (ctx, shader);
824 _cairo_gl_composite_bind_to_shader (ctx, setup);
831 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
832 cairo_gl_context_t **ctx_out)
834 CAIRO_TRACE_BEGIN (__func__);
835 cairo_gl_context_t *ctx;
836 cairo_status_t status;
840 status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
841 if (unlikely (status)) {
842 CAIRO_TRACE_END (__func__);
846 setup->dst->content_cleared = FALSE;
848 _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
850 if (ctx->states_cache.blend_enabled == FALSE) {
851 ctx->dispatch.Enable (GL_BLEND);
852 ctx->states_cache.blend_enabled = TRUE;
855 status = _cairo_gl_set_operands_and_operator (setup, ctx);
856 if (unlikely (status))
859 status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
860 if (unlikely (status))
866 if (unlikely (status))
867 status = _cairo_gl_context_release (ctx, status);
869 CAIRO_TRACE_END (__func__);
874 _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
876 CAIRO_TRACE_BEGIN (__func__);
877 cairo_array_t* indices = &ctx->tristrip_indices;
878 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
881 ctx->dispatch.BufferSubData (GL_ELEMENT_ARRAY_BUFFER, 0,
882 _cairo_array_num_elements (indices) * sizeof (unsigned short),
883 (GLvoid *) indices_array);
886 if (ctx->pre_shader) {
887 cairo_gl_shader_t *prev_shader = ctx->current_shader;
889 _cairo_gl_set_shader (ctx, ctx->pre_shader);
890 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
891 ctx->dispatch.DrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, ctx->ibo ? 0 : indices_array);
893 _cairo_gl_set_shader (ctx, prev_shader);
894 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
897 ctx->dispatch.DrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, ctx->ibo ? 0 :indices_array);
898 _cairo_array_truncate (indices, 0);
899 CAIRO_TRACE_END (__func__);
903 _cairo_gl_composite_draw_line (cairo_gl_context_t *ctx)
905 CAIRO_TRACE_BEGIN (__func__);
906 GLenum type = GL_LINE_STRIP;
907 cairo_array_t* indices = &ctx->tristrip_indices;
908 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
910 if (ctx->draw_mode == CAIRO_GL_LINES)
914 ctx->dispatch.BufferSubData (GL_ELEMENT_ARRAY_BUFFER, 0,
915 _cairo_array_num_elements (indices) * sizeof (unsigned short),
916 (GLvoid *) indices_array);
919 if (ctx->pre_shader) {
920 cairo_gl_shader_t *prev_shader = ctx->current_shader;
922 _cairo_gl_set_shader (ctx, ctx->pre_shader);
923 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
924 ctx->dispatch.DrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, ctx->ibo ? 0 : indices_array);
926 _cairo_gl_set_shader (ctx, prev_shader);
927 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
930 ctx->dispatch.DrawElements (type, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, ctx->ibo ? 0 : indices_array);
931 _cairo_array_truncate (indices, 0);
932 CAIRO_TRACE_END (__func__);
936 _cairo_gl_composite_draw_triangles (cairo_gl_context_t *ctx,
939 CAIRO_TRACE_BEGIN (__func__);
940 if (! ctx->pre_shader) {
941 ctx->dispatch.DrawArrays (GL_TRIANGLES, 0, count);
943 cairo_gl_shader_t *prev_shader = ctx->current_shader;
945 _cairo_gl_set_shader (ctx, ctx->pre_shader);
946 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
947 ctx->dispatch.DrawArrays (GL_TRIANGLES, 0, count);
949 _cairo_gl_set_shader (ctx, prev_shader);
950 _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
951 ctx->dispatch.DrawArrays (GL_TRIANGLES, 0, count);
953 CAIRO_TRACE_END (__func__);
957 _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
960 CAIRO_TRACE_BEGIN (__func__);
961 int i, num_rectangles;
963 if (!ctx->clip_region) {
964 _cairo_gl_composite_draw_triangles (ctx, count);
965 CAIRO_TRACE_END (__func__);
969 num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
970 for (i = 0; i < num_rectangles; i++) {
971 cairo_rectangle_int_t rect;
973 cairo_region_get_rectangle (ctx->clip_region, i, &rect);
975 _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
976 _enable_scissor_buffer (ctx);
977 _cairo_gl_composite_draw_triangles (ctx, count);
979 CAIRO_TRACE_END (__func__);
983 _cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
986 ctx->dispatch.BufferSubData (GL_ARRAY_BUFFER, 0,
988 (const GLvoid *)ctx->vb);
994 _cairo_gl_composite_flush (cairo_gl_context_t *ctx)
996 CAIRO_TRACE_BEGIN (__func__);
1000 if (_cairo_gl_context_is_flushed (ctx)) {
1001 CAIRO_TRACE_END (__func__);
1005 count = ctx->vb_offset / ctx->vertex_size;
1007 _cairo_gl_composite_unmap_vertex_buffer (ctx);
1009 if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) {
1010 if (ctx->draw_mode == CAIRO_GL_LINE_STRIP ||
1011 ctx->draw_mode == CAIRO_GL_LINES)
1012 _cairo_gl_composite_draw_line (ctx);
1014 _cairo_gl_composite_draw_tristrip (ctx);
1016 assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1017 _cairo_gl_composite_draw_triangles_with_clip_region (ctx, count);
1020 for (i = 0; i < ARRAY_LENGTH (ctx->glyph_cache); i++)
1021 _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
1023 _cairo_gl_image_cache_unlock (ctx);
1024 CAIRO_TRACE_END (__func__);
1028 _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
1029 unsigned int n_vertices,
1030 cairo_gl_primitive_type_t primitive_type)
1032 if (ctx->primitive_type != primitive_type) {
1033 _cairo_gl_composite_flush (ctx);
1034 ctx->primitive_type = primitive_type;
1037 assert(ctx->vbo_size > 0);
1038 if (ctx->vb_offset + n_vertices * ctx->vertex_size > ctx->vbo_size)
1039 _cairo_gl_composite_flush (ctx);
1043 _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
1044 GLfloat x, GLfloat y)
1046 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1051 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1052 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
1054 ctx->vb_offset += ctx->vertex_size;
1058 _cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
1059 GLfloat x, GLfloat y, uint8_t alpha)
1061 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1070 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1071 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
1076 fi.bytes[3] = alpha;
1079 ctx->vb_offset += ctx->vertex_size;
1083 _cairo_gl_composite_emit_point (cairo_gl_context_t *ctx,
1084 const cairo_point_t *point)
1086 _cairo_gl_composite_emit_vertex (ctx,
1087 _cairo_fixed_to_double (point->x),
1088 _cairo_fixed_to_double (point->y));
1092 _cairo_gl_composite_emit_int (cairo_gl_context_t *ctx,
1098 _cairo_gl_composite_emit_vertex (ctx, fx, fy);
1102 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
1103 GLfloat x1, GLfloat y1,
1104 GLfloat x2, GLfloat y2)
1106 _cairo_gl_composite_prepare_buffer (ctx, 6,
1107 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1109 _cairo_gl_composite_emit_vertex (ctx, x1, y1);
1110 _cairo_gl_composite_emit_vertex (ctx, x2, y1);
1111 _cairo_gl_composite_emit_vertex (ctx, x1, y2);
1113 _cairo_gl_composite_emit_vertex (ctx, x2, y1);
1114 _cairo_gl_composite_emit_vertex (ctx, x2, y2);
1115 _cairo_gl_composite_emit_vertex (ctx, x1, y2);
1118 cairo_gl_emit_rect_t
1119 _cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
1121 return _cairo_gl_composite_emit_rect;
1125 _cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
1126 GLfloat x1, GLfloat y1,
1127 GLfloat x2, GLfloat y2)
1129 _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
1133 _cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
1134 GLfloat x1, GLfloat y1,
1135 GLfloat x2, GLfloat y2,
1138 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1139 _cairo_gl_composite_flush (ctx);
1140 ctx->draw_mode = CAIRO_GL_VERTEX;
1143 _cairo_gl_composite_prepare_buffer (ctx, 6,
1144 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1146 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
1147 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
1148 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
1150 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
1151 _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
1152 _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
1156 _cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
1157 GLfloat x1, GLfloat y1,
1158 GLfloat x2, GLfloat y2,
1162 int src_use_atlas = 0;
1163 int mask_use_atlas = 0;
1169 _cairo_gl_composite_prepare_buffer (ctx, 6,
1170 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1172 if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE ||
1173 ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_GAUSSIAN) &&
1174 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.use_atlas)
1175 src_use_atlas = TRUE;
1176 if ((ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE ||
1177 ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_GAUSSIAN) &&
1178 ctx->operands[CAIRO_GL_TEX_MASK].texture.use_atlas)
1179 mask_use_atlas = TRUE;
1181 v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1183 v[15 + 20*src_use_atlas + 20*mask_use_atlas] =
1184 v[ 6 + 8*src_use_atlas + 8*mask_use_atlas] =
1186 v[10 + 12*src_use_atlas + 12*mask_use_atlas] =
1187 v[ 4 + 4*src_use_atlas + 4*mask_use_atlas] =
1189 v[12 + 16*src_use_atlas + 16*mask_use_atlas] =
1190 v[ 9 + 12*src_use_atlas + 12*mask_use_atlas] =
1191 v[ 3 + 4*src_use_atlas + 4*mask_use_atlas] = x2;
1192 v[16 + 20*src_use_atlas + 20*mask_use_atlas] =
1193 v[13 + 16*src_use_atlas + 16*mask_use_atlas] =
1194 v[ 7 + 8*src_use_atlas + 8*mask_use_atlas] = y2;
1199 fi.bytes[3] = alpha;
1200 v[17 + 24*src_use_atlas + 24*mask_use_atlas] =
1201 v[14 + 20*src_use_atlas + 20*mask_use_atlas] =
1202 v[11 + 16*src_use_atlas + 16*mask_use_atlas] =
1203 v[ 8 + 12*src_use_atlas + 12*mask_use_atlas] =
1204 v[ 5 + 8*src_use_atlas + 8*mask_use_atlas] =
1205 v[ 2 + 4*src_use_atlas + 4*mask_use_atlas ] = fi.f;
1207 if (src_use_atlas) {
1209 v[ 5 + 4*src_use_atlas + 4*mask_use_atlas] =
1210 v[ 8 + 8*src_use_atlas + 8*mask_use_atlas] =
1211 v[11 + 12*src_use_atlas + 12*mask_use_atlas] =
1212 v[14 + 16*src_use_atlas + 16*mask_use_atlas] =
1213 v[17 + 20*src_use_atlas + 20*mask_use_atlas] =
1214 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p1.x;
1217 v[ 6 + 4*src_use_atlas + 4*mask_use_atlas] =
1218 v[ 9 + 8*src_use_atlas + 8*mask_use_atlas] =
1219 v[12 + 12*src_use_atlas + 12*mask_use_atlas] =
1220 v[15 + 16*src_use_atlas + 16*mask_use_atlas] =
1221 v[18 + 20*src_use_atlas + 20*mask_use_atlas] =
1222 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p1.y;
1225 v[ 7 + 4*src_use_atlas + 4*mask_use_atlas] =
1226 v[10 + 8*src_use_atlas + 8*mask_use_atlas] =
1227 v[13 + 12*src_use_atlas + 12*mask_use_atlas] =
1228 v[16 + 16*src_use_atlas + 16*mask_use_atlas] =
1229 v[19 + 20*src_use_atlas + 20*mask_use_atlas] =
1230 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p2.x;
1233 v[ 8 + 4*src_use_atlas + 4*mask_use_atlas] =
1234 v[11 + 8*src_use_atlas + 8*mask_use_atlas] =
1235 v[14 + 12*src_use_atlas + 12*mask_use_atlas] =
1236 v[17 + 16*src_use_atlas + 16*mask_use_atlas] =
1237 v[20 + 20*src_use_atlas + 20*mask_use_atlas] =
1238 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.p2.y;
1241 if (mask_use_atlas) {
1242 v[ 2 + 4*src_use_atlas ] =
1243 v[ 5 + 8*src_use_atlas + 4*mask_use_atlas] =
1244 v[ 8 + 12*src_use_atlas + 8*mask_use_atlas] =
1245 v[11 + 16*src_use_atlas + 12*mask_use_atlas] =
1246 v[14 + 20*src_use_atlas + 16*mask_use_atlas] =
1247 v[17 + 24*src_use_atlas + 20*mask_use_atlas] =
1248 ctx->operands[CAIRO_GL_TEX_MASK].texture.p1.x;
1250 v[ 3 + 4*src_use_atlas ] =
1251 v[ 6 + 4*src_use_atlas + 4*mask_use_atlas] =
1252 v[ 9 + 8*src_use_atlas + 8*mask_use_atlas] =
1253 v[12 + 12*src_use_atlas + 12*mask_use_atlas] =
1254 v[15 + 16*src_use_atlas + 16*mask_use_atlas] =
1255 v[18 + 20*src_use_atlas + 20*mask_use_atlas] =
1256 ctx->operands[CAIRO_GL_TEX_MASK].texture.p1.y;
1258 v[ 4 + 4*src_use_atlas ] =
1259 v[ 7 + 4*src_use_atlas + 4*mask_use_atlas] =
1260 v[10 + 8*src_use_atlas + 8*mask_use_atlas] =
1261 v[13 + 12*src_use_atlas + 12*mask_use_atlas] =
1262 v[16 + 16*src_use_atlas + 16*mask_use_atlas] =
1263 v[19 + 20*src_use_atlas + 20*mask_use_atlas] =
1264 ctx->operands[CAIRO_GL_TEX_MASK].texture.p2.x;
1266 v[ 5 + 4*src_use_atlas ] =
1267 v[ 8 + 4*src_use_atlas + 4*mask_use_atlas] =
1268 v[11 + 8*src_use_atlas + 8*mask_use_atlas] =
1269 v[14 + 12*src_use_atlas + 12*mask_use_atlas] =
1270 v[17 + 16*src_use_atlas + 16*mask_use_atlas] =
1271 v[20 + 20*src_use_atlas + 20*mask_use_atlas] =
1272 ctx->operands[CAIRO_GL_TEX_MASK].texture.p2.y;
1275 ctx->vb_offset += 6*(3 + 4*src_use_atlas + 4*mask_use_atlas) * sizeof(GLfloat);
1278 cairo_gl_emit_span_t
1279 _cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
1281 if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE) {
1282 switch (ctx->operands[CAIRO_GL_TEX_MASK].type) {
1284 case CAIRO_GL_OPERAND_COUNT:
1286 case CAIRO_GL_OPERAND_NONE:
1287 case CAIRO_GL_OPERAND_CONSTANT:
1290 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1291 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1292 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1293 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1294 if (!ctx->operands[CAIRO_GL_TEX_MASK].gradient.texgen)
1295 return _cairo_gl_composite_emit_span;
1298 case CAIRO_GL_OPERAND_TEXTURE:
1299 case CAIRO_GL_OPERAND_GAUSSIAN:
1300 if (!ctx->operands[CAIRO_GL_TEX_MASK].texture.texgen)
1301 return _cairo_gl_composite_emit_span;
1306 switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1308 case CAIRO_GL_OPERAND_COUNT:
1310 case CAIRO_GL_OPERAND_NONE:
1311 case CAIRO_GL_OPERAND_CONSTANT:
1314 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1315 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1316 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1317 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1318 if (!ctx->operands[CAIRO_GL_TEX_SOURCE].gradient.texgen)
1319 return _cairo_gl_composite_emit_span;
1322 case CAIRO_GL_OPERAND_TEXTURE:
1323 case CAIRO_GL_OPERAND_GAUSSIAN:
1324 if (!ctx->operands[CAIRO_GL_TEX_SOURCE].texture.texgen)
1325 return _cairo_gl_composite_emit_span;
1328 return _cairo_gl_composite_emit_solid_span;
1332 _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
1333 GLfloat x, GLfloat y,
1334 GLfloat glyph_x, GLfloat glyph_y)
1336 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1341 _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
1346 ctx->vb_offset += ctx->vertex_size;
1350 _cairo_gl_composite_emit_color_glyph_vertex (cairo_gl_context_t *ctx,
1351 GLfloat x, GLfloat y,
1352 GLfloat glyph_x, GLfloat glyph_y)
1354 GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1361 ctx->vb_offset += ctx->vertex_size;
1365 _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
1366 GLfloat x1, GLfloat y1,
1367 GLfloat x2, GLfloat y2,
1368 GLfloat glyph_x1, GLfloat glyph_y1,
1369 GLfloat glyph_x2, GLfloat glyph_y2)
1371 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1372 _cairo_gl_composite_flush (ctx);
1373 ctx->draw_mode = CAIRO_GL_VERTEX;
1376 _cairo_gl_composite_prepare_buffer (ctx, 6,
1377 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1379 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
1380 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1381 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1383 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1384 _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
1385 _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1389 _cairo_gl_composite_emit_color_glyph (cairo_gl_context_t *ctx,
1390 GLfloat x1, GLfloat y1,
1391 GLfloat x2, GLfloat y2,
1392 GLfloat glyph_x1, GLfloat glyph_y1,
1393 GLfloat glyph_x2, GLfloat glyph_y2)
1395 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1396 _cairo_gl_composite_flush (ctx);
1397 ctx->draw_mode = CAIRO_GL_VERTEX;
1400 _cairo_gl_composite_prepare_buffer (ctx, 6,
1401 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1403 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
1404 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1405 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1407 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
1408 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
1409 _cairo_gl_composite_emit_color_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
1413 _cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
1414 GLfloat x1, GLfloat y1,
1415 GLfloat x2, GLfloat y2,
1416 GLfloat glyph_x1, GLfloat glyph_y1,
1417 GLfloat glyph_x2, GLfloat glyph_y2)
1421 _cairo_gl_composite_prepare_buffer (ctx, 6,
1422 CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
1424 v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
1426 v[20] = v[ 8] = v[0] = x1;
1427 v[13] = v[ 5] = v[1] = y1;
1428 v[22] = v[10] = v[2] = glyph_x1;
1429 v[15] = v[ 7] = v[3] = glyph_y1;
1431 v[16] = v[12] = v[4] = x2;
1432 v[18] = v[14] = v[6] = glyph_x2;
1434 v[21] = v[17] = v[ 9] = y2;
1435 v[23] = v[19] = v[11] = glyph_y2;
1437 ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
1440 cairo_gl_emit_glyph_t
1441 _cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx,
1442 const cairo_bool_t is_color_glyph)
1444 if ( is_color_glyph) {
1445 /* color glyph ignore all source and mask */
1446 return _cairo_gl_composite_emit_color_glyph;
1449 switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
1451 case CAIRO_GL_OPERAND_COUNT:
1453 case CAIRO_GL_OPERAND_NONE:
1454 case CAIRO_GL_OPERAND_CONSTANT:
1455 if (! ctx->operands[CAIRO_GL_TEX_SOURCE].constant.encode_as_attribute)
1456 return _cairo_gl_composite_emit_solid_glyph;
1458 case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
1459 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
1460 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
1461 case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
1462 case CAIRO_GL_OPERAND_TEXTURE:
1463 case CAIRO_GL_OPERAND_GAUSSIAN:
1464 return _cairo_gl_composite_emit_glyph;
1469 _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
1471 _cairo_gl_operand_destroy (&setup->src);
1472 _cairo_gl_operand_destroy (&setup->mask);
1476 _cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
1477 cairo_operator_t op,
1478 cairo_bool_t assume_component_alpha)
1480 if (assume_component_alpha) {
1481 if (op != CAIRO_OPERATOR_CLEAR &&
1482 op != CAIRO_OPERATOR_OVER &&
1483 op != CAIRO_OPERATOR_ADD)
1484 return UNSUPPORTED ("unsupported component alpha operator");
1486 if (! _cairo_gl_operator_is_supported (op))
1487 return UNSUPPORTED ("unsupported operator");
1491 return CAIRO_STATUS_SUCCESS;
1495 _cairo_gl_composite_init (cairo_gl_composite_t *setup,
1496 cairo_operator_t op,
1497 cairo_gl_surface_t *dst,
1498 cairo_bool_t assume_component_alpha)
1500 CAIRO_TRACE_BEGIN (__func__);
1501 cairo_status_t status;
1503 memset (setup, 0, sizeof (cairo_gl_composite_t));
1505 status = _cairo_gl_composite_set_operator (setup, op,
1506 assume_component_alpha);
1508 CAIRO_TRACE_END (__func__);
1513 setup->clip_region = dst->clip_region;
1515 CAIRO_TRACE_END (__func__);
1516 return CAIRO_STATUS_SUCCESS;
1519 static cairo_int_status_t
1520 _cairo_gl_composite_append_vertex_indices (cairo_gl_context_t *ctx,
1521 int number_of_new_indices,
1522 cairo_bool_t is_connected)
1524 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1525 cairo_array_t *indices = &ctx->tristrip_indices;
1526 int number_of_indices = _cairo_array_num_elements (indices);
1527 unsigned short current_vertex_index = 0;
1530 assert (number_of_new_indices > 0);
1532 /* If any preexisting triangle triangle strip indices exist on this
1533 context, we insert a set of degenerate triangles from the last
1534 preexisting vertex to our first one. */
1535 if (number_of_indices > 0 && is_connected) {
1536 const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
1537 if (indices_array == NULL)
1538 return CAIRO_STATUS_NULL_POINTER;
1539 current_vertex_index = indices_array[number_of_indices - 1];
1541 status = _cairo_array_append (indices, ¤t_vertex_index);
1542 if (unlikely (status))
1545 current_vertex_index++;
1546 status =_cairo_array_append (indices, ¤t_vertex_index);
1547 if (unlikely (status))
1550 current_vertex_index = (unsigned short) number_of_indices;
1552 for (i = 0; i < number_of_new_indices; i++) {
1553 status = _cairo_array_append (indices, ¤t_vertex_index);
1554 current_vertex_index++;
1555 if (unlikely (status))
1559 return CAIRO_STATUS_SUCCESS;
1563 _cairo_gl_composite_emit_int_quad_as_tristrip (cairo_gl_context_t *ctx,
1564 cairo_gl_composite_t *setup,
1567 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1568 _cairo_gl_composite_flush (ctx);
1569 ctx->draw_mode = CAIRO_GL_VERTEX;
1572 _cairo_gl_composite_prepare_buffer (ctx, 4,
1573 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1575 _cairo_gl_composite_emit_int (ctx, quad[0], quad[1]);
1576 _cairo_gl_composite_emit_int (ctx, quad[2], quad[3]);
1578 /* Cairo stores quad vertices in counter-clockwise order, but we need to
1579 emit them from top to bottom in the triangle strip, so we need to reverse
1580 the order of the last two vertices. */
1581 _cairo_gl_composite_emit_int (ctx, quad[6], quad[7]);
1582 _cairo_gl_composite_emit_int (ctx, quad[4], quad[5]);
1584 return _cairo_gl_composite_append_vertex_indices (ctx, 4, TRUE);
1588 _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t *ctx,
1589 cairo_gl_composite_t *setup,
1590 const cairo_point_t quad[4])
1592 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1593 _cairo_gl_composite_flush (ctx);
1594 ctx->draw_mode = CAIRO_GL_VERTEX;
1597 _cairo_gl_composite_prepare_buffer (ctx, 4,
1598 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1600 _cairo_gl_composite_emit_point (ctx, &quad[0]);
1601 _cairo_gl_composite_emit_point (ctx, &quad[1]);
1603 /* Cairo stores quad vertices in counter-clockwise order, but we need to
1604 emit them from top to bottom in the triangle strip, so we need to reverse
1605 the order of the last two vertices. */
1606 _cairo_gl_composite_emit_point (ctx, &quad[3]);
1607 _cairo_gl_composite_emit_point (ctx, &quad[2]);
1609 return _cairo_gl_composite_append_vertex_indices (ctx, 4, TRUE);
1613 _cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t *ctx,
1614 cairo_gl_composite_t *setup,
1615 const cairo_point_t triangle[3])
1617 if (ctx->draw_mode != CAIRO_GL_VERTEX) {
1618 _cairo_gl_composite_flush (ctx);
1619 ctx->draw_mode = CAIRO_GL_VERTEX;
1622 _cairo_gl_composite_prepare_buffer (ctx, 3,
1623 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1625 _cairo_gl_composite_emit_point (ctx, &triangle[0]);
1626 _cairo_gl_composite_emit_point (ctx, &triangle[1]);
1627 _cairo_gl_composite_emit_point (ctx, &triangle[2]);
1628 return _cairo_gl_composite_append_vertex_indices (ctx, 3, TRUE);
1632 _cairo_gl_composite_emit_point_as_single_line (cairo_gl_context_t *ctx,
1633 const cairo_point_t point[2])
1635 int num_indices = 2;
1636 if (ctx->draw_mode != CAIRO_GL_LINES)
1637 _cairo_gl_composite_flush (ctx);
1639 ctx->draw_mode = CAIRO_GL_LINES;
1641 _cairo_gl_composite_prepare_buffer (ctx, 2,
1642 CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
1644 _cairo_gl_composite_emit_point (ctx, &point[0]);
1645 _cairo_gl_composite_emit_point (ctx, &point[1]);
1646 return _cairo_gl_composite_append_vertex_indices (ctx, num_indices, FALSE);