beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-gl-msaa-compositor.c
blob83e8eb2d16067f1ea8328be1e51d8a09a58aff7c
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
35 * California.
37 * Contributor(s):
38 * Henry Song <hsong@sisa.samsung.com>
39 * Martin Robinson <mrobinson@igalia.com>
42 #include "cairoint.h"
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"
51 static cairo_bool_t
52 can_use_msaa_compositor (cairo_gl_surface_t *surface,
53 cairo_antialias_t antialias);
55 static void
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;
63 static cairo_int_status_t
64 _draw_trap (cairo_gl_context_t *ctx,
65 cairo_gl_composite_t *setup,
66 cairo_trapezoid_t *trap)
68 cairo_point_t quad[4];
70 quad[0].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
71 &trap->left.p2,
72 trap->top);
73 quad[0].y = trap->top;
75 quad[1].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
76 &trap->left.p2,
77 trap->bottom);
78 quad[1].y = trap->bottom;
80 quad[2].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
81 &trap->right.p2,
82 trap->bottom);
83 quad[2].y = trap->bottom;
85 quad[3].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
86 &trap->right.p2,
87 trap->top);
88 quad[3].y = trap->top;
89 return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
92 static cairo_int_status_t
93 _draw_traps (cairo_gl_context_t *ctx,
94 cairo_gl_composite_t *setup,
95 cairo_traps_t *traps)
97 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
98 int i;
100 for (i = 0; i < traps->num_traps; i++) {
101 cairo_trapezoid_t *trap = traps->traps + i;
102 if (unlikely ((status = _draw_trap (ctx, setup, trap))))
103 return status;
106 return status;
109 static cairo_int_status_t
110 _draw_int_rect (cairo_gl_context_t *ctx,
111 cairo_gl_composite_t *setup,
112 cairo_rectangle_int_t *rect)
114 cairo_box_t box;
115 cairo_point_t quad[4];
117 _cairo_box_from_rectangle (&box, rect);
118 quad[0].x = box.p1.x;
119 quad[0].y = box.p1.y;
120 quad[1].x = box.p1.x;
121 quad[1].y = box.p2.y;
122 quad[2].x = box.p2.x;
123 quad[2].y = box.p2.y;
124 quad[3].x = box.p2.x;
125 quad[3].y = box.p1.y;
127 return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
130 static cairo_int_status_t
131 _draw_triangle_fan (cairo_gl_context_t *ctx,
132 cairo_gl_composite_t *setup,
133 const cairo_point_t *midpt,
134 const cairo_point_t *points,
135 int npoints)
137 int i;
139 /* Our strategy here is to not even try to build a triangle fan, but to
140 draw each triangle as if it was an unconnected member of a triangle strip. */
141 for (i = 1; i < npoints; i++) {
142 cairo_int_status_t status;
143 cairo_point_t triangle[3];
145 triangle[0] = *midpt;
146 triangle[1] = points[i - 1];
147 triangle[2] = points[i];
149 status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
150 if (unlikely (status))
151 return status;
154 return CAIRO_STATUS_SUCCESS;
157 static cairo_int_status_t
158 _clip_to_traps (cairo_clip_t *clip,
159 cairo_traps_t *traps)
161 cairo_int_status_t status;
162 cairo_polygon_t polygon;
163 cairo_antialias_t antialias;
164 cairo_fill_rule_t fill_rule;
166 _cairo_traps_init (traps);
168 if (clip->num_boxes == 1 && clip->path == NULL) {
169 cairo_boxes_t boxes;
170 _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
171 return _cairo_traps_init_boxes (traps, &boxes);
174 status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
175 if (unlikely (status))
176 return status;
178 /* We ignore the antialias mode of the clip here, since the user requested
179 * unantialiased rendering of their path and we expect that this stencil
180 * based rendering of the clip to be a reasonable approximation to
181 * the intersection between that clip and the path.
183 * In other words, what the user expects when they try to perform
184 * a geometric intersection between an unantialiased polygon and an
185 * antialiased polygon is open to interpretation. And we choose the fast
186 * option.
189 _cairo_traps_init (traps);
190 status = _cairo_bentley_ottmann_tessellate_polygon (traps,
191 &polygon,
192 fill_rule);
193 _cairo_polygon_fini (&polygon);
195 return status;
198 cairo_int_status_t
199 _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
200 cairo_gl_composite_t *setup,
201 cairo_clip_t *clip)
203 cairo_int_status_t status;
204 cairo_traps_t traps;
206 status = _clip_to_traps (clip, &traps);
207 if (unlikely (status))
208 return status;
209 status = _draw_traps (ctx, setup, &traps);
211 _cairo_traps_fini (&traps);
212 return status;
215 static cairo_bool_t
216 _should_use_unbounded_surface (cairo_composite_rectangles_t *composite)
218 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
219 cairo_rectangle_int_t *source = &composite->source;
221 if (composite->is_bounded)
222 return FALSE;
224 /* This isn't just an optimization. It also detects when painting is used
225 to paint back the unbounded surface, preventing infinite recursion. */
226 return ! (source->x <= 0 && source->y <= 0 &&
227 source->height + source->y >= dst->height &&
228 source->width + source->x >= dst->width);
231 static cairo_surface_t*
232 _prepare_unbounded_surface (cairo_gl_surface_t *dst)
235 cairo_surface_t* surface = cairo_gl_surface_create (dst->base.device,
236 dst->base.content,
237 dst->width,
238 dst->height);
239 if (surface == NULL)
240 return NULL;
241 if (unlikely (surface->status)) {
242 cairo_surface_destroy (surface);
243 return NULL;
245 return surface;
248 static cairo_int_status_t
249 _paint_back_unbounded_surface (const cairo_compositor_t *compositor,
250 cairo_composite_rectangles_t *composite,
251 cairo_surface_t *surface)
253 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
254 cairo_int_status_t status;
256 cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
257 if (unlikely (pattern->status)) {
258 status = pattern->status;
259 goto finish;
262 status = _cairo_compositor_paint (compositor, &dst->base,
263 composite->op, pattern,
264 composite->clip);
266 finish:
267 cairo_pattern_destroy (pattern);
268 cairo_surface_destroy (surface);
269 return status;
272 static cairo_bool_t
273 can_use_msaa_compositor (cairo_gl_surface_t *surface,
274 cairo_antialias_t antialias)
276 query_surface_capabilities (surface);
277 if (! surface->supports_stencil)
278 return FALSE;
280 /* Multisampling OpenGL ES surfaces only maintain one multisampling
281 framebuffer and thus must use the spans compositor to do non-antialiased
282 rendering. */
283 if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES
284 && surface->supports_msaa
285 && antialias == CAIRO_ANTIALIAS_NONE)
286 return FALSE;
288 /* The MSAA compositor has a single-sample mode, so we can
289 support non-antialiased rendering. */
290 if (antialias == CAIRO_ANTIALIAS_NONE)
291 return TRUE;
293 if (antialias == CAIRO_ANTIALIAS_FAST || antialias == CAIRO_ANTIALIAS_DEFAULT)
294 return surface->supports_msaa;
295 return FALSE;
298 static void
299 _cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
300 cairo_gl_composite_t *setup)
302 if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip))
303 return;
304 _cairo_gl_composite_set_clip (setup, composite->clip);
307 /* Masking with the SOURCE operator requires two passes. In the first
308 * pass we use the mask as the source to get:
309 * result = (1 - ma) * dst
310 * In the second pass we use the add operator to achieve:
311 * result = (src * ma) + dst
312 * Combined this produces:
313 * result = (src * ma) + (1 - ma) * dst
315 static cairo_int_status_t
316 _cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor,
317 cairo_composite_rectangles_t *composite)
319 cairo_gl_composite_t setup;
320 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
321 cairo_gl_context_t *ctx = NULL;
322 cairo_int_status_t status;
324 cairo_clip_t *clip = composite->clip;
325 cairo_traps_t traps;
327 /* If we have a non-rectangular clip, we can avoid using the stencil buffer
328 * for clipping and just draw the clip polygon. */
329 if (clip) {
330 status = _clip_to_traps (clip, &traps);
331 if (unlikely (status)) {
332 _cairo_traps_fini (&traps);
333 return status;
337 status = _cairo_gl_composite_init (&setup,
338 CAIRO_OPERATOR_DEST_OUT,
339 dst,
340 FALSE /* assume_component_alpha */);
341 if (unlikely (status))
342 return status;
343 status = _cairo_gl_composite_set_source (&setup,
344 &composite->mask_pattern.base,
345 &composite->mask_sample_area,
346 &composite->bounded,
347 FALSE);
348 if (unlikely (status))
349 goto finish;
350 _cairo_gl_composite_set_multisample (&setup);
351 status = _cairo_gl_composite_begin (&setup, &ctx);
352 if (unlikely (status))
353 goto finish;
355 if (! clip)
356 status = _draw_int_rect (ctx, &setup, &composite->bounded);
357 else
358 status = _draw_traps (ctx, &setup, &traps);
359 if (unlikely (status))
360 goto finish;
362 /* Now draw the second pass. */
363 status = _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
364 FALSE /* assume_component_alpha */);
365 if (unlikely (status))
366 goto finish;
367 status = _cairo_gl_composite_set_source (&setup,
368 &composite->source_pattern.base,
369 &composite->source_sample_area,
370 &composite->bounded,
371 FALSE);
372 if (unlikely (status))
373 goto finish;
374 status = _cairo_gl_composite_set_mask (&setup,
375 &composite->mask_pattern.base,
376 &composite->source_sample_area,
377 &composite->bounded,
378 FALSE);
379 if (unlikely (status))
380 goto finish;
381 status = _cairo_gl_set_operands_and_operator (&setup, ctx);
382 if (unlikely (status))
383 goto finish;
385 if (! clip)
386 status = _draw_int_rect (ctx, &setup, &composite->bounded);
387 else
388 status = _draw_traps (ctx, &setup, &traps);
390 finish:
391 _cairo_gl_composite_fini (&setup);
392 if (ctx)
393 status = _cairo_gl_context_release (ctx, status);
394 if (clip)
395 _cairo_traps_fini (&traps);
397 return status;
400 static cairo_int_status_t
401 _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
402 cairo_composite_rectangles_t *composite)
404 cairo_gl_composite_t setup;
405 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
406 cairo_gl_context_t *ctx = NULL;
407 cairo_int_status_t status;
408 cairo_operator_t op = composite->op;
409 cairo_clip_t *clip = composite->clip;
411 if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
412 return CAIRO_INT_STATUS_UNSUPPORTED;
414 if (composite->op == CAIRO_OPERATOR_CLEAR &&
415 composite->original_mask_pattern != NULL)
416 return CAIRO_INT_STATUS_UNSUPPORTED;
418 /* GL compositing operators cannot properly represent a mask operation
419 using the SOURCE compositing operator in one pass. This only matters if
420 there actually is a mask (there isn't in a paint operation) and if the
421 mask isn't totally opaque. */
422 if (op == CAIRO_OPERATOR_SOURCE &&
423 composite->original_mask_pattern != NULL &&
424 ! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
425 &composite->mask_sample_area)) {
427 if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
428 &composite->source_sample_area)) {
429 return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite);
432 /* If the source is opaque the operation reduces to OVER. */
433 op = CAIRO_OPERATOR_OVER;
436 if (_should_use_unbounded_surface (composite)) {
437 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
439 if (unlikely (surface == NULL))
440 return CAIRO_INT_STATUS_UNSUPPORTED;
442 /* This may be a paint operation. */
443 if (composite->original_mask_pattern == NULL) {
444 status = _cairo_compositor_paint (compositor, surface,
445 CAIRO_OPERATOR_SOURCE,
446 &composite->source_pattern.base,
447 NULL);
448 } else {
449 status = _cairo_compositor_mask (compositor, surface,
450 CAIRO_OPERATOR_SOURCE,
451 &composite->source_pattern.base,
452 &composite->mask_pattern.base,
453 NULL);
456 if (unlikely (status)) {
457 cairo_surface_destroy (surface);
458 return status;
461 return _paint_back_unbounded_surface (compositor, composite, surface);
464 status = _cairo_gl_composite_init (&setup,
466 dst,
467 FALSE /* assume_component_alpha */);
468 if (unlikely (status))
469 return status;
471 status = _cairo_gl_composite_set_source (&setup,
472 &composite->source_pattern.base,
473 &composite->source_sample_area,
474 &composite->bounded,
475 FALSE);
476 if (unlikely (status))
477 goto finish;
479 if (composite->original_mask_pattern != NULL) {
480 status = _cairo_gl_composite_set_mask (&setup,
481 &composite->mask_pattern.base,
482 &composite->mask_sample_area,
483 &composite->bounded,
484 FALSE);
486 if (unlikely (status))
487 goto finish;
489 /* We always use multisampling here, because we do not yet have the smarts
490 to calculate when the clip or the source requires it. */
491 _cairo_gl_composite_set_multisample (&setup);
493 status = _cairo_gl_composite_begin (&setup, &ctx);
494 if (unlikely (status))
495 goto finish;
497 if (! clip)
498 status = _draw_int_rect (ctx, &setup, &composite->bounded);
499 else
500 status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
502 finish:
503 _cairo_gl_composite_fini (&setup);
505 if (ctx)
506 status = _cairo_gl_context_release (ctx, status);
508 return status;
511 static cairo_int_status_t
512 _cairo_gl_msaa_compositor_paint (const cairo_compositor_t *compositor,
513 cairo_composite_rectangles_t *composite)
515 return _cairo_gl_msaa_compositor_mask (compositor, composite);
518 static cairo_status_t
519 _stroke_shaper_add_triangle (void *closure,
520 const cairo_point_t triangle[3])
522 struct _tristrip_composite_info *info = closure;
523 return _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx,
524 &info->setup,
525 triangle);
528 static cairo_status_t
529 _stroke_shaper_add_triangle_fan (void *closure,
530 const cairo_point_t *midpoint,
531 const cairo_point_t *points,
532 int npoints)
534 struct _tristrip_composite_info *info = closure;
535 return _draw_triangle_fan (info->ctx, &info->setup,
536 midpoint, points, npoints);
539 static cairo_status_t
540 _stroke_shaper_add_quad (void *closure,
541 const cairo_point_t quad[4])
543 struct _tristrip_composite_info *info = closure;
544 return _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup,
545 quad);
548 static cairo_int_status_t
549 _prevent_overlapping_strokes (cairo_gl_context_t *ctx,
550 cairo_gl_composite_t *setup,
551 cairo_composite_rectangles_t *composite,
552 const cairo_path_fixed_t *path,
553 const cairo_stroke_style_t *style,
554 const cairo_matrix_t *ctm)
556 cairo_rectangle_int_t stroke_extents;
558 if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
559 return CAIRO_INT_STATUS_UNSUPPORTED;
561 if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
562 &composite->source_sample_area))
563 return CAIRO_INT_STATUS_SUCCESS;
565 if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
566 cairo_bool_t scissor_was_enabled;
568 /* In case we have pending operations we have to flush before
569 adding the stencil buffer. */
570 _cairo_gl_composite_flush (ctx);
572 /* Enable the stencil buffer, even if we are not using it for clipping,
573 so we can use it below to prevent overlapping shapes. We initialize
574 it all to one here which represents infinite clip. */
575 glDepthMask (GL_TRUE);
576 glEnable (GL_STENCIL_TEST);
578 /* We scissor here so that we don't have to clear the entire stencil
579 * buffer. If the scissor test is already enabled, it was enabled
580 * for clipping. In that case, instead of calculating an intersection,
581 * we just reuse it, and risk clearing too much. */
582 scissor_was_enabled = glIsEnabled (GL_SCISSOR_TEST);
583 if (! scissor_was_enabled) {
584 _cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
585 &stroke_extents);
586 _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
588 glClearStencil (1);
589 glClear (GL_STENCIL_BUFFER_BIT);
590 if (! scissor_was_enabled)
591 glDisable (GL_SCISSOR_TEST);
593 glStencilFunc (GL_EQUAL, 1, 1);
596 /* This means that once we draw to a particular pixel nothing else can
597 be drawn there until the stencil buffer is reset or the stencil test
598 is disabled. */
599 glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
601 _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
602 setup->dst->clip_on_stencil_buffer = NULL;
604 return CAIRO_INT_STATUS_SUCCESS;
607 static void
608 query_surface_capabilities (cairo_gl_surface_t *surface)
610 GLint samples, stencil_bits;
611 cairo_gl_context_t *ctx;
612 cairo_int_status_t status;
614 /* Texture surfaces are create in such a way that they always
615 have stencil and multisample bits if possible, so we don't
616 need to query their capabilities lazily. */
617 if (_cairo_gl_surface_is_texture (surface))
618 return;
619 if (surface->stencil_and_msaa_caps_initialized)
620 return;
622 surface->stencil_and_msaa_caps_initialized = TRUE;
623 surface->supports_stencil = FALSE;
624 surface->supports_msaa = FALSE;
626 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
627 if (unlikely (status))
628 return;
630 _cairo_gl_context_set_destination (ctx, surface, FALSE);
632 glGetIntegerv(GL_SAMPLES, &samples);
633 glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
634 surface->supports_stencil = stencil_bits > 0;
635 surface->supports_msaa = samples > 1;
637 status = _cairo_gl_context_release (ctx, status);
640 static cairo_int_status_t
641 _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor,
642 cairo_composite_rectangles_t *composite,
643 const cairo_path_fixed_t *path,
644 const cairo_stroke_style_t *style,
645 const cairo_matrix_t *ctm,
646 const cairo_matrix_t *ctm_inverse,
647 double tolerance,
648 cairo_antialias_t antialias)
650 cairo_int_status_t status;
651 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
652 struct _tristrip_composite_info info;
654 if (! can_use_msaa_compositor (dst, antialias))
655 return CAIRO_INT_STATUS_UNSUPPORTED;
657 if (composite->is_bounded == FALSE) {
658 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
660 if (unlikely (surface == NULL))
661 return CAIRO_INT_STATUS_UNSUPPORTED;
663 status = _cairo_compositor_stroke (compositor, surface,
664 CAIRO_OPERATOR_SOURCE,
665 &composite->source_pattern.base,
666 path, style, ctm, ctm_inverse,
667 tolerance, antialias, NULL);
668 if (unlikely (status)) {
669 cairo_surface_destroy (surface);
670 return status;
673 return _paint_back_unbounded_surface (compositor, composite, surface);
676 status = _cairo_gl_composite_init (&info.setup,
677 composite->op,
678 dst,
679 FALSE /* assume_component_alpha */);
680 if (unlikely (status))
681 return status;
683 info.ctx = NULL;
685 status = _cairo_gl_composite_set_source (&info.setup,
686 &composite->source_pattern.base,
687 &composite->source_sample_area,
688 &composite->bounded,
689 FALSE);
690 if (unlikely (status))
691 goto finish;
693 _cairo_gl_msaa_compositor_set_clip (composite, &info.setup);
694 if (antialias != CAIRO_ANTIALIAS_NONE)
695 _cairo_gl_composite_set_multisample (&info.setup);
697 status = _cairo_gl_composite_begin (&info.setup, &info.ctx);
698 if (unlikely (status))
699 goto finish;
701 status = _prevent_overlapping_strokes (info.ctx, &info.setup,
702 composite, path, style, ctm);
703 if (unlikely (status))
704 goto finish;
706 status = _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path,
707 style,
708 ctm,
709 ctm_inverse,
710 tolerance,
711 _stroke_shaper_add_triangle,
712 _stroke_shaper_add_triangle_fan,
713 _stroke_shaper_add_quad,
714 &info);
715 if (unlikely (status))
716 goto finish;
718 finish:
719 _cairo_gl_composite_fini (&info.setup);
721 if (info.ctx)
722 status = _cairo_gl_context_release (info.ctx, status);
724 return status;
727 static cairo_int_status_t
728 _draw_simple_quad_path (cairo_gl_context_t *ctx,
729 cairo_gl_composite_t *setup,
730 const cairo_path_fixed_t *path)
732 cairo_point_t triangle[3];
733 cairo_int_status_t status;
734 const cairo_point_t *points;
736 points = cairo_path_head (path)->points;
737 triangle[0] = points[0];
738 triangle[1] = points[1];
739 triangle[2] = points[2];
740 status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
741 if (status)
742 return status;
744 triangle[0] = points[2];
745 triangle[1] = points[3];
746 triangle[2] = points[0];
747 return _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
750 static cairo_int_status_t
751 _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
752 cairo_composite_rectangles_t *composite,
753 const cairo_path_fixed_t *path,
754 cairo_fill_rule_t fill_rule,
755 double tolerance,
756 cairo_antialias_t antialias)
758 cairo_gl_composite_t setup;
759 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
760 cairo_gl_context_t *ctx = NULL;
761 cairo_int_status_t status;
762 cairo_traps_t traps;
763 cairo_bool_t draw_path_with_traps;
765 if (! can_use_msaa_compositor (dst, antialias))
766 return CAIRO_INT_STATUS_UNSUPPORTED;
768 if (composite->is_bounded == FALSE) {
769 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
771 if (unlikely (surface == NULL))
772 return CAIRO_INT_STATUS_UNSUPPORTED;
775 status = _cairo_compositor_fill (compositor, surface,
776 CAIRO_OPERATOR_SOURCE,
777 &composite->source_pattern.base,
778 path, fill_rule, tolerance,
779 antialias, NULL);
781 if (unlikely (status)) {
782 cairo_surface_destroy (surface);
783 return status;
786 return _paint_back_unbounded_surface (compositor, composite, surface);
789 draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);
791 if (draw_path_with_traps) {
792 _cairo_traps_init (&traps);
793 status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
794 if (unlikely (status))
795 goto cleanup_traps;
798 status = _cairo_gl_composite_init (&setup,
799 composite->op,
800 dst,
801 FALSE /* assume_component_alpha */);
802 if (unlikely (status))
803 goto cleanup_traps;
805 status = _cairo_gl_composite_set_source (&setup,
806 &composite->source_pattern.base,
807 &composite->source_sample_area,
808 &composite->bounded,
809 FALSE);
810 if (unlikely (status))
811 goto cleanup_setup;
813 _cairo_gl_msaa_compositor_set_clip (composite, &setup);
814 if (antialias != CAIRO_ANTIALIAS_NONE)
815 _cairo_gl_composite_set_multisample (&setup);
817 status = _cairo_gl_composite_begin (&setup, &ctx);
818 if (unlikely (status))
819 goto cleanup_setup;
821 if (! draw_path_with_traps)
822 status = _draw_simple_quad_path (ctx, &setup, path);
823 else
824 status = _draw_traps (ctx, &setup, &traps);
825 if (unlikely (status))
826 goto cleanup_setup;
828 cleanup_setup:
829 _cairo_gl_composite_fini (&setup);
831 if (ctx)
832 status = _cairo_gl_context_release (ctx, status);
834 cleanup_traps:
835 if (draw_path_with_traps)
836 _cairo_traps_fini (&traps);
838 return status;
841 static cairo_int_status_t
842 _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor,
843 cairo_composite_rectangles_t *composite,
844 cairo_scaled_font_t *scaled_font,
845 cairo_glyph_t *glyphs,
846 int num_glyphs,
847 cairo_bool_t overlap)
849 cairo_int_status_t status;
850 cairo_surface_t *src = NULL;
851 int src_x, src_y;
852 cairo_composite_glyphs_info_t info;
854 cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
856 query_surface_capabilities (dst);
857 if (! dst->supports_stencil)
858 return CAIRO_INT_STATUS_UNSUPPORTED;
860 if (composite->op == CAIRO_OPERATOR_CLEAR)
861 return CAIRO_INT_STATUS_UNSUPPORTED;
863 if (composite->is_bounded == FALSE) {
864 cairo_surface_t* surface = _prepare_unbounded_surface (dst);
866 if (unlikely (surface == NULL))
867 return CAIRO_INT_STATUS_UNSUPPORTED;
869 status = _cairo_compositor_glyphs (compositor, surface,
870 CAIRO_OPERATOR_SOURCE,
871 &composite->source_pattern.base,
872 glyphs, num_glyphs,
873 scaled_font, composite->clip);
875 if (unlikely (status)) {
876 cairo_surface_destroy (surface);
877 return status;
880 return _paint_back_unbounded_surface (compositor, composite, surface);
883 src = _cairo_gl_pattern_to_source (&dst->base,
884 &composite->source_pattern.base,
885 FALSE,
886 &composite->bounded,
887 &composite->source_sample_area,
888 &src_x, &src_y);
889 if (unlikely (src->status)) {
890 status = src->status;
891 goto finish;
894 status = _cairo_gl_check_composite_glyphs (composite,
895 scaled_font, glyphs,
896 &num_glyphs);
897 if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
898 goto finish;
900 info.font = scaled_font;
901 info.glyphs = glyphs;
902 info.num_glyphs = num_glyphs;
903 info.use_mask = overlap || ! composite->is_bounded ||
904 composite->op == CAIRO_OPERATOR_SOURCE;
905 info.extents = composite->bounded;
907 _cairo_scaled_font_freeze_cache (scaled_font);
908 status = _cairo_gl_composite_glyphs_with_clip (dst, composite->op,
909 src, src_x, src_y,
910 0, 0, &info,
911 composite->clip);
913 _cairo_scaled_font_thaw_cache (scaled_font);
915 finish:
916 if (src)
917 cairo_surface_destroy (src);
919 return status;
922 static void
923 _cairo_gl_msaa_compositor_init (cairo_compositor_t *compositor,
924 const cairo_compositor_t *delegate)
926 compositor->delegate = delegate;
928 compositor->paint = _cairo_gl_msaa_compositor_paint;
929 compositor->mask = _cairo_gl_msaa_compositor_mask;
930 compositor->fill = _cairo_gl_msaa_compositor_fill;
931 compositor->stroke = _cairo_gl_msaa_compositor_stroke;
932 compositor->glyphs = _cairo_gl_msaa_compositor_glyphs;
935 const cairo_compositor_t *
936 _cairo_gl_msaa_compositor_get (void)
938 static cairo_compositor_t compositor;
939 if (compositor.delegate == NULL)
940 _cairo_gl_msaa_compositor_init (&compositor,
941 _cairo_gl_span_compositor_get ());
943 return &compositor;