1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
6 * Copyright © 2011 Intel Corporation
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 University of Southern
38 * Henry Song <hsong@sisa.samsung.com>
39 * Martin Robinson <mrobinson@igalia.com>
44 #include "cairo-clip-inline.h"
45 #include "cairo-composite-rectangles-private.h"
46 #include "cairo-compositor-private.h"
47 #include "cairo-gl-private.h"
48 #include "cairo-path-private.h"
49 #include "cairo-traps-private.h"
52 can_use_msaa_compositor (cairo_gl_surface_t *surface,
53 cairo_antialias_t antialias);
56 query_surface_capabilities (cairo_gl_surface_t *surface);
58 struct _tristrip_composite_info {
59 cairo_gl_composite_t setup;
60 cairo_gl_context_t *ctx;
64 _is_continuous_single_line (const cairo_path_fixed_t *path,
65 const cairo_stroke_style_t *style)
67 return (_cairo_path_fixed_is_single_line (path) &&
71 static cairo_int_status_t
72 _draw_trap (cairo_gl_context_t *ctx,
73 cairo_gl_composite_t *setup,
74 cairo_trapezoid_t *trap)
76 cairo_point_t quad[4];
78 if (trap->left.p1.x == trap->left.p2.x) {
79 quad[0].x = trap->left.p1.x;
80 quad[1].x = trap->left.p1.x;
84 dy = trap->left.p2.y - trap->left.p1.y;
86 if (trap->top == trap->left.p1.y)
88 else if (trap->top == trap->left.p2.y)
89 quad[0].x = trap->left.p2.x;
91 quad[0].x = x + _cairo_fixed_mul_div_floor (trap->top - trap->left.p1.y,
92 trap->left.p2.x - trap->left.p1.x, dy);
94 if (trap->bottom == trap->left.p2.y)
95 quad[1].x = trap->left.p2.x;
96 else if (trap->bottom == trap->left.p1.y)
99 quad[1].x = x + _cairo_fixed_mul_div_floor (trap->bottom - trap->left.p1.y,
100 trap->left.p2.x - trap->left.p1.x, dy);
102 quad[0].y = trap->top;
103 quad[1].y = trap->bottom;
105 if (trap->right.p1.x == trap->right.p2.x) {
106 quad[2].x = trap->right.p1.x;
107 quad[3].x = trap->right.p1.x;
110 x = trap->right.p1.x;
111 dy = trap->right.p2.y - trap->right.p1.y;
113 if (trap->bottom == trap->right.p2.y)
114 quad[2].x = trap->right.p2.x;
115 else if (trap->bottom == trap->right.p1.y)
118 quad[2].x = x + _cairo_fixed_mul_div_floor (trap->bottom - trap->right.p1.y,
119 trap->right.p2.x - trap->right.p1.x, dy);
121 if (trap->top == trap->right.p1.y)
123 else if (trap->top == trap->right.p2.y)
124 quad[3].x = trap->right.p2.x;
126 quad[3].x = x + _cairo_fixed_mul_div_floor (trap->top - trap->right.p1.y,
127 trap->right.p2.x - trap->right.p1.x, dy);
129 quad[2].y = trap->bottom;
130 quad[3].y = trap->top;
132 return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
135 static cairo_int_status_t
136 _draw_traps (cairo_gl_context_t *ctx,
137 cairo_gl_composite_t *setup,
138 cairo_traps_t *traps)
140 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
143 for (i = 0; i < traps->num_traps; i++) {
144 cairo_trapezoid_t *trap = traps->traps + i;
145 if (unlikely ((status = _draw_trap (ctx, setup, trap))))
152 static cairo_int_status_t
153 _draw_int_rect (cairo_gl_context_t *ctx,
154 cairo_gl_composite_t *setup,
155 cairo_rectangle_int_t *rect)
159 quad[0] = quad[2] = rect->x;
160 quad[1] = quad[7] = rect->y;
161 quad[3] = quad[5] = rect->y + rect->height;
162 quad[4] = quad[6] = rect->x + rect->width;
164 return _cairo_gl_composite_emit_int_quad_as_tristrip (ctx, setup, quad);
167 static cairo_int_status_t
168 _draw_triangle_fan (cairo_gl_context_t *ctx,
169 cairo_gl_composite_t *setup,
170 const cairo_point_t *midpt,
171 const cairo_point_t *points,
176 /* Our strategy here is to not even try to build a triangle fan, but to
177 draw each triangle as if it was an unconnected member of a triangle strip. */
178 for (i = 1; i < npoints; i++) {
179 cairo_int_status_t status;
180 cairo_point_t triangle[3];
182 triangle[0] = *midpt;
183 triangle[1] = points[i - 1];
184 triangle[2] = points[i];
186 status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
187 if (unlikely (status))
191 return CAIRO_STATUS_SUCCESS;
194 static cairo_int_status_t
195 _clip_to_traps (cairo_clip_t *clip,
196 cairo_traps_t *traps)
198 cairo_int_status_t status;
199 cairo_polygon_t polygon;
200 cairo_antialias_t antialias;
201 cairo_fill_rule_t fill_rule;
203 _cairo_traps_init (traps);
205 if (clip->num_boxes == 1 && clip->path == NULL) {
207 _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
208 return _cairo_traps_init_boxes (traps, &boxes);
211 status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
212 if (unlikely (status))
215 /* We ignore the antialias mode of the clip here, since the user requested
216 * unantialiased rendering of their path and we expect that this stencil
217 * based rendering of the clip to be a reasonable approximation to
218 * the intersection between that clip and the path.
220 * In other words, what the user expects when they try to perform
221 * a geometric intersection between an unantialiased polygon and an
222 * antialiased polygon is open to interpretation. And we choose the fast
226 _cairo_traps_init (traps);
227 status = _cairo_bentley_ottmann_tessellate_polygon (traps,
230 _cairo_polygon_fini (&polygon);
236 _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
237 cairo_gl_composite_t *setup,
240 cairo_int_status_t status;
243 status = _clip_to_traps (clip, &traps);
244 if (unlikely (status))
246 status = _draw_traps (ctx, setup, &traps);
248 _cairo_traps_fini (&traps);
252 static cairo_int_status_t
253 _blit_texture_to_renderbuffer (cairo_gl_surface_t *surface)
255 cairo_gl_context_t *ctx = NULL;
256 cairo_gl_composite_t setup;
257 cairo_surface_pattern_t pattern;
258 cairo_rectangle_int_t extents;
259 cairo_int_status_t status;
260 cairo_gl_flavor_t gl_flavor = ((cairo_gl_context_t *) surface->base.device)->gl_flavor;
262 if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
263 return CAIRO_INT_STATUS_SUCCESS;
264 else if (! _cairo_gl_surface_is_texture (surface))
265 return CAIRO_INT_STATUS_SUCCESS;
266 else if (surface->msaa_active)
267 return CAIRO_INT_STATUS_SUCCESS;
268 else if (surface->content_synced) {
269 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
270 if (unlikely (status))
272 _cairo_gl_context_set_destination (ctx, surface, TRUE);
273 return _cairo_gl_context_release (ctx, status);
276 memset (&setup, 0, sizeof (cairo_gl_composite_t));
278 status = _cairo_gl_composite_set_operator (&setup,
279 CAIRO_OPERATOR_SOURCE,
285 setup.clip_region = surface->clip_region;
287 _cairo_pattern_init_for_surface (&pattern, &surface->base);
289 extents.x = extents.y = 0;
290 extents.width = surface->width;
291 extents.height = surface->height;
293 status = _cairo_gl_composite_set_source (&setup, &pattern.base,
294 NULL, &extents, FALSE, FALSE);
295 _cairo_pattern_fini (&pattern.base);
297 if (unlikely (status))
300 _cairo_gl_composite_set_multisample (&setup);
302 status = _cairo_gl_composite_begin (&setup, &ctx);
304 if (unlikely (status))
307 status = _draw_int_rect (ctx, &setup, &extents);
309 if (unlikely (status))
312 surface->content_synced = TRUE;
314 _cairo_gl_composite_fini (&setup);
317 _cairo_gl_composite_flush (ctx);
318 status = _cairo_gl_context_release (ctx, status);
326 _should_use_unbounded_surface (cairo_composite_rectangles_t *composite)
328 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
329 cairo_rectangle_int_t *source = &composite->source;
331 if (composite->is_bounded)
334 /* This isn't just an optimization. It also detects when painting is used
335 to paint back the unbounded surface, preventing infinite recursion. */
336 return ! (source->x <= 0 && source->y <= 0 &&
337 source->height + source->y >= dst->height &&
338 source->width + source->x >= dst->width);
341 static cairo_surface_t*
342 _prepare_unbounded_surface (cairo_gl_surface_t *dst)
345 cairo_surface_t* surface = cairo_gl_surface_create (dst->base.device,
351 if (unlikely (surface->status)) {
352 cairo_surface_destroy (surface);
358 static cairo_int_status_t
359 _paint_back_unbounded_surface (const cairo_compositor_t *compositor,
360 cairo_composite_rectangles_t *composite,
361 cairo_surface_t *surface)
363 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
364 cairo_int_status_t status;
366 cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
367 if (unlikely (pattern->status)) {
368 status = pattern->status;
372 status = _cairo_compositor_paint (compositor, &dst->base,
373 composite->op, pattern,
377 cairo_pattern_destroy (pattern);
378 cairo_surface_destroy (surface);
383 can_use_msaa_compositor (cairo_gl_surface_t *surface,
384 cairo_antialias_t antialias)
386 cairo_gl_flavor_t flavor = ((cairo_gl_context_t *) surface->base.device)->gl_flavor;
387 cairo_bool_t has_angle_multisampling = ((cairo_gl_context_t *) surface->base.device)->has_angle_multisampling;
389 query_surface_capabilities (surface);
390 if (! surface->supports_stencil)
393 /* Multisampling OpenGL ES surfaces only maintain one multisampling
394 framebuffer and thus must use the spans compositor to do non-antialiased
396 if (! (flavor == CAIRO_GL_FLAVOR_DESKTOP ||
397 flavor == CAIRO_GL_FLAVOR_ES3 ||
398 (flavor == CAIRO_GL_FLAVOR_ES2 &&
399 has_angle_multisampling)) &&
400 surface->supports_msaa &&
401 antialias == CAIRO_ANTIALIAS_NONE)
404 /* The MSAA compositor has a single-sample mode, so we can
405 support non-antialiased rendering. */
406 if (antialias == CAIRO_ANTIALIAS_NONE)
409 if ((antialias == CAIRO_ANTIALIAS_GRAY ||
410 antialias== CAIRO_ANTIALIAS_SUBPIXEL ||
411 antialias == CAIRO_ANTIALIAS_FAST ||
412 antialias == CAIRO_ANTIALIAS_DEFAULT) &&
413 surface->num_samples > 1)
414 return surface->supports_msaa;
419 _cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
420 cairo_gl_composite_t *setup)
424 /* We don't need to check CAIRO_OPERATOR_BOUND_BY_MASK in these
426 is_bounded = composite->is_bounded;
427 composite->is_bounded = CAIRO_OPERATOR_BOUND_BY_SOURCE;
428 if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip))
431 _cairo_gl_composite_set_clip (setup, composite->clip);
433 composite->is_bounded = is_bounded;
437 _pattern_is_pixel_aligned (const cairo_pattern_t *pattern)
439 long xoffset, yoffset;
444 xoffset = pattern->matrix.x0;
445 yoffset = pattern->matrix.y0;
447 if (pattern->matrix.xx != 1.0 ||
448 pattern->matrix.xy != 0.0 ||
449 pattern->matrix.yy != 1.0 ||
450 pattern->matrix.yx != 1.0 ||
451 pattern->matrix.x0 != xoffset ||
452 pattern->matrix.y0 != yoffset)
458 _clip_is_pixel_aligned (const cairo_clip_t *clip)
463 if (clip->path || clip->num_boxes > 1)
466 if (_cairo_fixed_is_integer (clip->boxes[0].p1.x) &&
467 _cairo_fixed_is_integer (clip->boxes[0].p1.y) &&
468 _cairo_fixed_is_integer (clip->boxes[0].p2.x) &&
469 _cairo_fixed_is_integer (clip->boxes[0].p2.y))
474 /* Masking with the SOURCE operator requires two passes. In the first
475 * pass we use the mask as the source to get:
476 * result = (1 - ma) * dst
477 * In the second pass we use the add operator to achieve:
478 * result = (src * ma) + dst
479 * Combined this produces:
480 * result = (src * ma) + (1 - ma) * dst
482 static cairo_int_status_t
483 _cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor,
484 cairo_composite_rectangles_t *composite)
486 cairo_gl_composite_t setup;
487 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
488 cairo_gl_context_t *ctx = NULL;
489 cairo_int_status_t status;
491 cairo_clip_t *clip = composite->clip;
493 cairo_bool_t is_pixel_aligned =
494 _pattern_is_pixel_aligned (composite->original_source_pattern) &&
495 _pattern_is_pixel_aligned (composite->original_mask_pattern) &&
496 _clip_is_pixel_aligned (clip);
498 /* If we have a non-rectangular clip, we can avoid using the stencil buffer
499 * for clipping and just draw the clip polygon. */
501 status = _clip_to_traps (clip, &traps);
502 if (unlikely (status)) {
503 _cairo_traps_fini (&traps);
508 if (! is_pixel_aligned) {
509 status = _blit_texture_to_renderbuffer (dst);
510 if (unlikely (status))
514 status = _cairo_gl_composite_init (&setup,
515 CAIRO_OPERATOR_DEST_OUT,
517 FALSE /* assume_component_alpha */);
518 if (unlikely (status))
520 status = _cairo_gl_composite_set_source (&setup,
521 composite->original_mask_pattern,
522 &composite->mask_sample_area,
525 if (unlikely (status))
528 if (! is_pixel_aligned || dst->msaa_active)
529 _cairo_gl_composite_set_multisample (&setup);
531 status = _cairo_gl_composite_begin (&setup, &ctx);
532 if (unlikely (status))
536 status = _draw_int_rect (ctx, &setup, &composite->bounded);
538 status = _draw_traps (ctx, &setup, &traps);
540 /* Now draw the second pass. */
541 status = _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
542 FALSE /* assume_component_alpha */);
543 if (unlikely (status))
545 status = _cairo_gl_composite_set_source (&setup,
546 composite->original_source_pattern,
547 &composite->source_sample_area,
550 if (unlikely (status))
552 status = _cairo_gl_composite_set_mask (&setup,
553 composite->original_mask_pattern,
554 &composite->source_sample_area,
557 if (unlikely (status))
560 _cairo_gl_context_set_destination (ctx, dst, setup.multisample);
562 status = _cairo_gl_set_operands_and_operator (&setup, ctx);
563 if (unlikely (status))
567 status = _draw_int_rect (ctx, &setup, &composite->bounded);
569 status = _draw_traps (ctx, &setup, &traps);
571 if (unlikely (status))
574 dst->content_synced = FALSE;
577 _cairo_gl_composite_fini (&setup);
579 status = _cairo_gl_context_release (ctx, status);
581 _cairo_traps_fini (&traps);
586 static cairo_int_status_t
587 _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
588 cairo_composite_rectangles_t *composite)
590 cairo_gl_composite_t setup;
591 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
592 cairo_gl_context_t *ctx = NULL;
593 cairo_int_status_t status;
594 cairo_operator_t op = composite->op;
595 cairo_clip_t *clip = composite->clip;
596 cairo_bool_t is_pixel_aligned = FALSE;
598 if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
599 return CAIRO_INT_STATUS_UNSUPPORTED;
601 if (composite->op == CAIRO_OPERATOR_CLEAR &&
602 composite->original_mask_pattern != NULL)
603 return CAIRO_INT_STATUS_UNSUPPORTED;
605 /* GL compositing operators cannot properly represent a mask operation
606 using the SOURCE compositing operator in one pass. This only matters if
607 there actually is a mask (there isn't in a paint operation) and if the
608 mask isn't totally opaque. */
609 if (op == CAIRO_OPERATOR_SOURCE &&
610 composite->original_mask_pattern != NULL &&
611 ! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
612 &composite->mask_sample_area)) {
614 if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
615 &composite->source_sample_area)) {
616 return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite);
619 /* If the source is opaque the operation reduces to OVER. */
620 op = CAIRO_OPERATOR_OVER;
623 if (_should_use_unbounded_surface (composite)) {
624 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
626 if (unlikely (surface == NULL))
627 return CAIRO_INT_STATUS_UNSUPPORTED;
629 /* This may be a paint operation. */
630 if (composite->original_mask_pattern == NULL) {
631 status = _cairo_compositor_paint (compositor, surface,
632 CAIRO_OPERATOR_SOURCE,
633 &composite->source_pattern.base,
636 status = _cairo_compositor_mask (compositor, surface,
637 CAIRO_OPERATOR_SOURCE,
638 &composite->source_pattern.base,
639 &composite->mask_pattern.base,
643 if (unlikely (status)) {
644 cairo_surface_destroy (surface);
648 return _paint_back_unbounded_surface (compositor, composite, surface);
651 if (_pattern_is_pixel_aligned (composite->original_source_pattern) &&
652 _pattern_is_pixel_aligned (composite->original_mask_pattern) &&
653 _clip_is_pixel_aligned (composite->clip))
654 is_pixel_aligned = TRUE;
656 if (! is_pixel_aligned) {
657 status = _blit_texture_to_renderbuffer (dst);
658 if (unlikely (status))
662 status = _cairo_gl_composite_init (&setup,
665 FALSE /* assume_component_alpha */);
666 if (unlikely (status))
669 status = _cairo_gl_composite_set_source (&setup,
670 composite->original_source_pattern,
671 &composite->source_sample_area,
674 if (unlikely (status))
677 if (composite->original_mask_pattern != NULL) {
678 status = _cairo_gl_composite_set_mask (&setup,
679 composite->original_mask_pattern,
680 &composite->mask_sample_area,
684 if (unlikely (status))
687 /* if the source, mask and clip are pixel-aligned and
688 msaa is not active, we paint to texture directly */
689 if (! is_pixel_aligned || dst->msaa_active)
690 _cairo_gl_composite_set_multisample (&setup);
692 status = _cairo_gl_composite_begin (&setup, &ctx);
694 if (unlikely (status))
697 if (op != CAIRO_OPERATOR_OVER) {
699 status = _draw_int_rect (ctx, &setup, &composite->bounded);
701 status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
704 /* fast path for CAIRO_OVER_OPERATOR */
705 cairo_rectangle_int_t rect, temp;
707 _cairo_surface_get_extents (&dst->base, &rect);
708 _cairo_pattern_get_extents (composite->original_source_pattern,
710 _cairo_rectangle_intersect (&rect, &temp);
711 if (composite->original_mask_pattern) {
712 _cairo_pattern_get_extents (composite->original_mask_pattern,
714 _cairo_rectangle_intersect (&rect, &temp);
718 cairo_clip_t *clip_copy = _cairo_clip_copy (clip);
720 clip_copy = _cairo_clip_intersect_rectangle (clip_copy, &rect);
721 status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup,
723 _cairo_clip_destroy (clip_copy);
726 status = _draw_int_rect (ctx, &setup, &rect);
729 if (unlikely (status))
732 dst->content_synced = FALSE;
735 _cairo_gl_composite_fini (&setup);
738 status = _cairo_gl_context_release (ctx, status);
743 static cairo_int_status_t
744 _cairo_gl_msaa_compositor_paint (const cairo_compositor_t *compositor,
745 cairo_composite_rectangles_t *composite)
747 return _cairo_gl_msaa_compositor_mask (compositor, composite);
750 static cairo_status_t
751 _stroke_shaper_add_triangle (void *closure,
752 const cairo_point_t triangle[3])
754 struct _tristrip_composite_info *info = closure;
755 return _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx,
760 static cairo_status_t
761 _stroke_shaper_add_triangle_fan (void *closure,
762 const cairo_point_t *midpoint,
763 const cairo_point_t *points,
766 struct _tristrip_composite_info *info = closure;
767 return _draw_triangle_fan (info->ctx, &info->setup,
768 midpoint, points, npoints);
771 static cairo_status_t
772 _stroke_shaper_add_quad (void *closure,
773 const cairo_point_t quad[4])
775 struct _tristrip_composite_info *info = closure;
776 return _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup,
781 _is_continuous_arc (const cairo_path_fixed_t *path,
782 const cairo_stroke_style_t *style)
784 return (_cairo_path_fixed_is_single_arc (path) &&
785 style->dash == NULL);
788 static cairo_int_status_t
789 _prevent_overlapping_strokes (cairo_gl_context_t *ctx,
790 cairo_gl_composite_t *setup,
791 cairo_composite_rectangles_t *composite,
792 const cairo_path_fixed_t *path,
793 const cairo_stroke_style_t *style,
794 const cairo_matrix_t *ctm)
796 cairo_rectangle_int_t stroke_extents;
797 const cairo_pattern_t *pattern = composite->original_source_pattern;
798 cairo_pattern_type_t type = cairo_pattern_get_type ((cairo_pattern_t *) pattern);
800 if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
801 return CAIRO_INT_STATUS_UNSUPPORTED;
804 /* XXX: improve me - since we have lazy init, we cannot use sample
806 if (type == CAIRO_PATTERN_TYPE_SOLID &&
807 _cairo_pattern_is_opaque_solid (pattern))
808 return CAIRO_INT_STATUS_SUCCESS;
810 if (ctx->states_cache.stencil_test_enabled == FALSE) {
811 /* In case we have pending operations we have to flush before
812 adding the stencil buffer. */
813 _cairo_gl_composite_flush (ctx);
815 /* Enable the stencil buffer, even if we are not using it for clipping,
816 so we can use it below to prevent overlapping shapes. We initialize
817 it all to one here which represents infinite clip. */
818 if (! ctx->states_cache.depth_mask) {
819 ctx->dispatch.DepthMask (GL_TRUE);
820 ctx->states_cache.depth_mask = TRUE;
822 ctx->dispatch.Enable (GL_STENCIL_TEST);
823 ctx->states_cache.stencil_test_enabled = TRUE;
825 /* We scissor here so that we don't have to clear the entire stencil
826 * buffer. If the scissor test is already enabled, it was enabled
827 * for clipping. In that case, instead of calculating an intersection,
828 * we just reuse it, and risk clearing too much. */
829 if (ctx->states_cache.scissor_test_enabled == FALSE) {
830 _cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
832 _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
833 ctx->dispatch.Enable (GL_SCISSOR_TEST);
834 ctx->states_cache.scissor_test_enabled = TRUE;
836 ctx->dispatch.ClearStencil (1);
837 ctx->dispatch.Clear (GL_STENCIL_BUFFER_BIT);
838 _disable_scissor_buffer (ctx);
840 ctx->dispatch.StencilFunc (GL_EQUAL, 1, 1);
843 /* This means that once we draw to a particular pixel nothing else can
844 be drawn there until the stencil buffer is reset or the stencil test
846 ctx->dispatch.StencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
848 _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
849 setup->dst->clip_on_stencil_buffer = NULL;
851 /* we must let the next drawing know we have changed stencil buffer
852 * so that next drawing calls flush
854 setup->dst->needs_update = TRUE;
856 return CAIRO_INT_STATUS_SUCCESS;
860 query_surface_capabilities (cairo_gl_surface_t *surface)
862 GLint samples, stencil_bits;
863 cairo_gl_context_t *ctx;
864 cairo_int_status_t status;
866 /* Texture surfaces are create in such a way that they always
867 have stencil and multisample bits if possible, so we don't
868 need to query their capabilities lazily. */
869 if (_cairo_gl_surface_is_texture (surface))
871 if (surface->stencil_and_msaa_caps_initialized)
874 surface->stencil_and_msaa_caps_initialized = TRUE;
875 surface->supports_stencil = FALSE;
876 surface->supports_msaa = FALSE;
878 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
879 if (unlikely (status))
882 _cairo_gl_context_set_destination (ctx, surface, FALSE);
884 //ctx->dispatch.GetIntegerv(GL_SAMPLES, &samples);
885 //ctx->dispatch.GetIntegerv(GL_STENCIL_BITS, &stencil_bits);
888 surface->supports_stencil = stencil_bits > 0;
890 surface->supports_msaa = samples > 1;
892 surface->num_samples = samples;
894 status = _cairo_gl_context_release (ctx, status);
897 static cairo_int_status_t
898 _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor,
899 cairo_composite_rectangles_t *composite,
900 const cairo_path_fixed_t *path,
901 const cairo_stroke_style_t *style,
902 const cairo_matrix_t *ctm,
903 const cairo_matrix_t *ctm_inverse,
905 cairo_antialias_t antialias)
907 cairo_int_status_t status;
908 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
909 struct _tristrip_composite_info info;
910 cairo_bool_t use_color_attribute;
911 cairo_rectangle_int_t stroke_extents;
913 if (! can_use_msaa_compositor (dst, antialias))
914 return CAIRO_INT_STATUS_UNSUPPORTED;
916 if (! _cairo_path_fixed_stroke_is_rectilinear (path)) {
917 _cairo_path_fixed_approximate_fill_extents (path, &stroke_extents);
919 if (stroke_extents.width != 0 &&
920 stroke_extents.height != 0) {
921 if ((stroke_extents.width / stroke_extents.height > 10 &&
922 stroke_extents.height < 10) ||
923 (stroke_extents.height / stroke_extents.width > 10 &&
924 stroke_extents.width < 10)) {
925 return CAIRO_INT_STATUS_UNSUPPORTED;
930 if (composite->is_bounded == FALSE) {
931 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
933 if (unlikely (surface == NULL))
934 return CAIRO_INT_STATUS_UNSUPPORTED;
936 status = _cairo_compositor_stroke (compositor, surface,
937 CAIRO_OPERATOR_SOURCE,
938 &composite->source_pattern.base,
939 path, style, ctm, ctm_inverse,
940 tolerance, antialias, NULL);
941 if (unlikely (status)) {
942 cairo_surface_destroy (surface);
946 return _paint_back_unbounded_surface (compositor, composite, surface);
949 if (antialias != CAIRO_ANTIALIAS_NONE) {
950 status = _blit_texture_to_renderbuffer (dst);
951 if (unlikely (status))
955 status = _cairo_gl_composite_init (&info.setup,
958 FALSE /* assume_component_alpha */);
959 if (unlikely (status))
963 use_color_attribute = _cairo_gl_hairline_style_is_hairline (style, ctm);
965 status = _cairo_gl_composite_set_source (&info.setup,
966 composite->original_source_pattern,
967 &composite->source_sample_area,
969 FALSE, use_color_attribute);
970 if (unlikely (status))
973 _cairo_gl_msaa_compositor_set_clip (composite, &info.setup);
974 if (antialias != CAIRO_ANTIALIAS_NONE)
975 _cairo_gl_composite_set_multisample (&info.setup);
977 status = _cairo_gl_composite_begin (&info.setup, &info.ctx);
978 if (unlikely (status))
981 if (_cairo_gl_hairline_style_is_hairline (style, ctm)) {
982 cairo_gl_hairline_closure_t closure;
984 if (! (_is_continuous_arc (path, style) ||
985 _is_continuous_single_line (path, style))) {
986 status = _prevent_overlapping_strokes (info.ctx, &info.setup,
989 if (unlikely (status))
993 closure.ctx = info.ctx;
995 closure.tolerance = tolerance;
997 status = _cairo_gl_path_fixed_stroke_to_hairline (path, &closure,
1000 _cairo_gl_hairline_move_to,
1002 _cairo_gl_hairline_line_to_dashed :
1003 _cairo_gl_hairline_line_to,
1004 _cairo_gl_hairline_curve_to,
1005 _cairo_gl_hairline_close_path);
1009 if (!_is_continuous_single_line (path, style)) {
1010 status = _prevent_overlapping_strokes (info.ctx, &info.setup,
1011 composite, path, style, ctm);
1012 if (unlikely (status))
1017 _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path,
1022 _stroke_shaper_add_triangle,
1023 _stroke_shaper_add_triangle_fan,
1024 _stroke_shaper_add_quad,
1026 if (unlikely (status))
1029 dst->content_synced = FALSE;
1032 _cairo_gl_composite_fini (&info.setup);
1035 status = _cairo_gl_context_release (info.ctx, status);
1040 static cairo_int_status_t
1041 _draw_simple_quad_path (cairo_gl_context_t *ctx,
1042 cairo_gl_composite_t *setup,
1043 const cairo_path_fixed_t *path)
1045 cairo_point_t triangle[3];
1046 cairo_int_status_t status;
1047 const cairo_point_t *points;
1049 points = cairo_path_head (path)->points;
1051 triangle[0] = points[0];
1052 triangle[1] = points[1];
1053 triangle[2] = points[2];
1054 status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
1058 triangle[0] = points[2];
1059 triangle[1] = points[3];
1060 triangle[2] = points[0];
1061 return _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
1064 static cairo_int_status_t
1065 _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
1066 cairo_composite_rectangles_t *composite,
1067 const cairo_path_fixed_t *path,
1068 cairo_fill_rule_t fill_rule,
1070 cairo_antialias_t antialias)
1072 cairo_gl_composite_t setup;
1073 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
1074 cairo_gl_context_t *ctx = NULL;
1075 cairo_int_status_t status;
1076 cairo_traps_t traps;
1077 cairo_bool_t draw_path_with_traps;
1078 cairo_rectangle_int_t fill_extents;
1080 if (! can_use_msaa_compositor (dst, antialias))
1081 return CAIRO_INT_STATUS_UNSUPPORTED;
1083 if (! _cairo_path_fixed_fill_is_rectilinear (path)) {
1084 _cairo_path_fixed_approximate_fill_extents (path, &fill_extents);
1086 if (fill_extents.width != 0 && fill_extents.height != 0) {
1087 if ((fill_extents.width / fill_extents.height > 10 &&
1088 fill_extents.height < 10) ||
1089 (fill_extents.height / fill_extents.width > 10 &&
1090 fill_extents.width < 10)) {
1091 return CAIRO_INT_STATUS_UNSUPPORTED;
1096 if (composite->is_bounded == FALSE) {
1097 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
1099 if (unlikely (surface == NULL))
1100 return CAIRO_INT_STATUS_UNSUPPORTED;
1103 status = _cairo_compositor_fill (compositor, surface,
1104 CAIRO_OPERATOR_SOURCE,
1105 &composite->source_pattern.base,
1106 path, fill_rule, tolerance,
1109 if (unlikely (status)) {
1110 cairo_surface_destroy (surface);
1114 return _paint_back_unbounded_surface (compositor, composite, surface);
1117 if (antialias != CAIRO_ANTIALIAS_NONE) {
1118 status = _blit_texture_to_renderbuffer (dst);
1119 if (unlikely (status))
1123 draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);
1125 if (draw_path_with_traps) {
1126 _cairo_traps_init (&traps);
1127 status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
1128 if (unlikely (status))
1132 status = _cairo_gl_composite_init (&setup,
1135 FALSE /* assume_component_alpha */);
1136 if (unlikely (status))
1139 status = _cairo_gl_composite_set_source (&setup,
1140 composite->original_source_pattern,
1141 &composite->source_sample_area,
1142 &composite->bounded,
1143 FALSE, ! draw_path_with_traps);
1144 if (unlikely (status))
1147 _cairo_gl_msaa_compositor_set_clip (composite, &setup);
1148 if (antialias != CAIRO_ANTIALIAS_NONE)
1149 _cairo_gl_composite_set_multisample (&setup);
1151 status = _cairo_gl_composite_begin (&setup, &ctx);
1152 if (unlikely (status))
1155 if (! draw_path_with_traps)
1156 status = _draw_simple_quad_path (ctx, &setup, path);
1158 status = _draw_traps (ctx, &setup, &traps);
1159 if (unlikely (status))
1162 dst->content_synced = FALSE;
1165 _cairo_gl_composite_fini (&setup);
1168 status = _cairo_gl_context_release (ctx, status);
1171 if (draw_path_with_traps)
1172 _cairo_traps_fini (&traps);
1177 static cairo_int_status_t
1178 _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor,
1179 cairo_composite_rectangles_t *composite,
1180 cairo_scaled_font_t *scaled_font,
1181 cairo_glyph_t *glyphs,
1183 cairo_bool_t overlap)
1185 cairo_int_status_t status;
1186 cairo_surface_t *src = NULL;
1188 cairo_composite_glyphs_info_t info;
1190 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
1192 query_surface_capabilities (dst);
1193 if (! dst->supports_stencil)
1194 return CAIRO_INT_STATUS_UNSUPPORTED;
1196 if (composite->op == CAIRO_OPERATOR_CLEAR)
1197 return CAIRO_INT_STATUS_UNSUPPORTED;
1199 if (composite->is_bounded == FALSE) {
1200 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
1202 if (unlikely (surface == NULL))
1203 return CAIRO_INT_STATUS_UNSUPPORTED;
1205 status = _cairo_compositor_glyphs (compositor, surface,
1206 CAIRO_OPERATOR_SOURCE,
1207 &composite->source_pattern.base,
1209 scaled_font, composite->clip);
1211 if (unlikely (status)) {
1212 cairo_surface_destroy (surface);
1216 return _paint_back_unbounded_surface (compositor, composite, surface);
1219 src = _cairo_gl_pattern_to_source (&dst->base,
1220 composite->original_source_pattern,
1222 &composite->bounded,
1223 &composite->source_sample_area,
1225 if (unlikely (src->status)) {
1226 status = src->status;
1230 status = _cairo_gl_check_composite_glyphs (composite,
1231 scaled_font, glyphs,
1233 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
1236 info.font = scaled_font;
1237 info.glyphs = glyphs;
1238 info.num_glyphs = num_glyphs;
1239 info.use_mask = overlap || ! composite->is_bounded ||
1240 composite->op == CAIRO_OPERATOR_SOURCE;
1241 info.extents = composite->source;
1243 _cairo_scaled_font_freeze_cache (scaled_font);
1244 status = _cairo_gl_composite_glyphs_with_clip (dst, composite->op,
1249 _cairo_scaled_font_thaw_cache (scaled_font);
1250 if (unlikely (status))
1253 dst->content_synced = FALSE;
1256 cairo_surface_destroy (src);
1262 _cairo_gl_msaa_compositor_init (cairo_compositor_t *compositor,
1263 const cairo_compositor_t *delegate)
1265 compositor->delegate = delegate;
1266 compositor->lazy_init = TRUE;
1268 compositor->paint = _cairo_gl_msaa_compositor_paint;
1269 compositor->mask = _cairo_gl_msaa_compositor_mask;
1270 compositor->fill = _cairo_gl_msaa_compositor_fill;
1271 compositor->stroke = _cairo_gl_msaa_compositor_stroke;
1272 compositor->glyphs = _cairo_gl_msaa_compositor_glyphs;
1275 const cairo_compositor_t *
1276 _cairo_gl_msaa_compositor_get (void)
1278 static cairo_compositor_t compositor;
1279 if (compositor.delegate == NULL)
1280 _cairo_gl_msaa_compositor_init (&compositor,
1281 _cairo_gl_span_compositor_get ());