Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-gl-msaa-compositor.c
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
3  *
4  * Copyright © 2002 University of Southern California
5  * Copyright © 2005 Red Hat, Inc.
6  * Copyright © 2011 Intel Corporation
7  * Copyright © 2011 Samsung Electronics
8  *
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.
16  *
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
22  *
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/
27  *
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.
31  *
32  * The Original Code is the cairo graphics library.
33  *
34  * The Initial Developer of the Original Code is University of Southern
35  * California.
36  *
37  * Contributor(s):
38  *      Henry Song <hsong@sisa.samsung.com>
39  *      Martin Robinson <mrobinson@igalia.com>
40  */
41
42 #include "cairoint.h"
43
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-traps-private.h"
49
50 static cairo_bool_t
51 can_use_msaa_compositor (cairo_gl_surface_t *surface,
52                          cairo_antialias_t antialias);
53
54 static void
55 query_surface_capabilities (cairo_gl_surface_t *surface);
56
57 struct _tristrip_composite_info {
58     cairo_gl_composite_t        setup;
59     cairo_gl_context_t          *ctx;
60 };
61
62 static cairo_bool_t
63 _is_continuous_single_line (const cairo_path_fixed_t   *path,
64                             const cairo_stroke_style_t *style)
65 {
66     return (_cairo_path_fixed_is_single_line (path) &&
67             style->dash == NULL);
68 }
69
70
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)
75 {
76     cairo_point_t quad[4];
77
78     quad[0].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
79                                                           &trap->left.p2,
80                                                           trap->top);
81     quad[0].y = trap->top;
82
83     quad[1].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
84                                                       &trap->left.p2,
85                                                       trap->bottom);
86     quad[1].y = trap->bottom;
87
88     quad[2].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
89                                                       &trap->right.p2,
90                                                       trap->bottom);
91     quad[2].y = trap->bottom;
92
93     quad[3].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
94                                                       &trap->right.p2,
95                                                       trap->top);
96     quad[3].y = trap->top;
97     return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
98 }
99
100 static cairo_int_status_t
101 _draw_traps (cairo_gl_context_t         *ctx,
102              cairo_gl_composite_t       *setup,
103              cairo_traps_t              *traps)
104 {
105     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
106     int i;
107
108     for (i = 0; i < traps->num_traps; i++) {
109         cairo_trapezoid_t *trap = traps->traps + i;
110         if (unlikely ((status = _draw_trap (ctx, setup, trap))))
111             return status;
112     }
113
114    return status;
115 }
116
117 static cairo_int_status_t
118 _draw_box (cairo_gl_context_t *ctx,
119            cairo_gl_composite_t *setup,
120            cairo_box_t *box)
121 {
122     cairo_point_t quad[4];
123
124     quad[0].x = box->p1.x;
125     quad[0].y = box->p1.y;
126     quad[1].x = box->p1.x;
127     quad[1].y = box->p2.y;
128     quad[2].x = box->p2.x;
129     quad[2].y = box->p2.y;
130     quad[3].x = box->p2.x;
131     quad[3].y = box->p1.y;
132
133     return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
134 }
135
136 static cairo_int_status_t
137 _draw_int_rect (cairo_gl_context_t      *ctx,
138                 cairo_gl_composite_t    *setup,
139                 cairo_rectangle_int_t   *rect)
140 {
141     cairo_box_t box;
142     _cairo_box_from_rectangle (&box, rect);
143     return _draw_box (ctx, setup, &box);
144 }
145
146 static cairo_int_status_t
147 _draw_triangle_fan (cairo_gl_context_t          *ctx,
148                     cairo_gl_composite_t        *setup,
149                     const cairo_point_t         *midpt,
150                     const cairo_point_t         *points,
151                     int                          npoints)
152 {
153     int i;
154
155     /* Our strategy here is to not even try to build a triangle fan, but to
156        draw each triangle as if it was an unconnected member of a triangle strip. */
157     for (i = 1; i < npoints; i++) {
158         cairo_int_status_t status;
159         cairo_point_t triangle[3];
160
161         triangle[0] = *midpt;
162         triangle[1] = points[i - 1];
163         triangle[2] = points[i];
164
165         status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
166         if (unlikely (status))
167             return status;
168     }
169
170     return CAIRO_STATUS_SUCCESS;
171 }
172
173 static cairo_int_status_t
174 _clip_to_traps (cairo_clip_t *clip,
175                 cairo_traps_t *traps)
176 {
177     cairo_int_status_t status;
178     cairo_polygon_t polygon;
179     cairo_antialias_t antialias;
180     cairo_fill_rule_t fill_rule;
181
182     _cairo_traps_init (traps);
183
184     if (clip->num_boxes == 1 && clip->path == NULL) {
185         cairo_boxes_t boxes;
186         _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
187         return _cairo_traps_init_boxes (traps, &boxes);
188     }
189
190     status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
191     if (unlikely (status))
192         return status;
193
194     /* We ignore the antialias mode of the clip here, since the user requested
195      * unantialiased rendering of their path and we expect that this stencil
196      * based rendering of the clip to be a reasonable approximation to
197      * the intersection between that clip and the path.
198      *
199      * In other words, what the user expects when they try to perform
200      * a geometric intersection between an unantialiased polygon and an
201      * antialiased polygon is open to interpretation. And we choose the fast
202      * option.
203      */
204
205     _cairo_traps_init (traps);
206     status = _cairo_bentley_ottmann_tessellate_polygon (traps,
207                                                         &polygon,
208                                                         fill_rule);
209     return status;
210 }
211
212 cairo_int_status_t
213 _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
214                                      cairo_gl_composite_t *setup,
215                                      cairo_clip_t *clip)
216 {
217     cairo_int_status_t status;
218     cairo_traps_t traps;
219
220     status = _clip_to_traps (clip, &traps);
221     if (unlikely (status))
222         return status;
223     status = _draw_traps (ctx, setup, &traps);
224
225     _cairo_traps_fini (&traps);
226     return status;
227 }
228
229 static cairo_bool_t
230 _should_use_unbounded_surface (cairo_composite_rectangles_t *composite)
231 {
232     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
233     cairo_rectangle_int_t *source = &composite->source;
234
235     if (composite->is_bounded)
236         return FALSE;
237
238     /* This isn't just an optimization. It also detects when painting is used
239        to paint back the unbounded surface, preventing infinite recursion. */
240     return ! (source->x <= 0 && source->y <= 0 &&
241               source->height + source->y >= dst->height &&
242               source->width + source->x >= dst->width);
243 }
244
245 static cairo_surface_t*
246 _prepare_unbounded_surface (cairo_gl_surface_t *dst)
247 {
248
249     cairo_surface_t* surface = cairo_gl_surface_create (dst->base.device,
250                                                         dst->base.content,
251                                                         dst->width,
252                                                         dst->height);
253     if (surface == NULL)
254         return NULL;
255     if (unlikely (surface->status)) {
256         cairo_surface_destroy (surface);
257         return NULL;
258     }
259     return surface;
260 }
261
262 static cairo_int_status_t
263 _paint_back_unbounded_surface (const cairo_compositor_t         *compositor,
264                                cairo_composite_rectangles_t     *composite,
265                                cairo_surface_t                  *surface)
266 {
267     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
268     cairo_int_status_t status;
269
270     cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
271     if (unlikely (pattern->status)) {
272         status = pattern->status;
273         goto finish;
274     }
275
276     status = _cairo_compositor_paint (compositor, &dst->base,
277                                       composite->op, pattern,
278                                       composite->clip);
279
280 finish:
281     cairo_pattern_destroy (pattern);
282     cairo_surface_destroy (surface);
283     return status;
284 }
285
286 static cairo_bool_t
287 can_use_msaa_compositor (cairo_gl_surface_t *surface,
288                          cairo_antialias_t antialias)
289 {
290     query_surface_capabilities (surface);
291     if (! surface->supports_stencil)
292         return FALSE;
293
294     /* Multisampling OpenGL ES surfaces only maintain one multisampling
295        framebuffer and thus must use the spans compositor to do non-antialiased
296        rendering. */
297     if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES
298          && surface->supports_msaa
299          && antialias == CAIRO_ANTIALIAS_NONE)
300         return FALSE;
301
302     /* The MSAA compositor has a single-sample mode, so we can
303        support non-antialiased rendering. */
304     if (antialias == CAIRO_ANTIALIAS_NONE)
305         return TRUE;
306
307     if (antialias == CAIRO_ANTIALIAS_FAST || antialias == CAIRO_ANTIALIAS_DEFAULT)
308         return surface->supports_msaa;
309     return FALSE;
310 }
311
312 static void
313 _cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
314                                     cairo_gl_composite_t *setup)
315 {
316     uint32_t is_bounded;
317
318     if (_cairo_clip_is_all_clipped (composite->clip))
319         return;
320
321     /* We don't need to check CAIRO_OPERATOR_BOUND_BY_MASK in these
322        situations. */
323     is_bounded = composite->is_bounded;
324     composite->is_bounded = CAIRO_OPERATOR_BOUND_BY_SOURCE;
325     if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip))
326         return;
327
328     _cairo_gl_composite_set_clip (setup, composite->clip);
329
330     composite->is_bounded = is_bounded;
331 }
332
333 /* Masking with the SOURCE operator requires two passes. In the first
334  * pass we use the mask as the source to get:
335  * result = (1 - ma) * dst
336  * In the second pass we use the add operator to achieve:
337  * result = (src * ma) + dst
338  * Combined this produces:
339  * result = (src * ma) + (1 - ma) * dst
340  */
341 static cairo_int_status_t
342 _cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor,
343                                                 cairo_composite_rectangles_t *composite)
344 {
345     cairo_gl_composite_t setup;
346     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
347     cairo_gl_context_t *ctx = NULL;
348     cairo_int_status_t status;
349
350     cairo_clip_t *clip = composite->clip;
351     cairo_traps_t traps;
352
353     /* If we have a non-rectangular clip, we can avoid using the stencil buffer
354      * for clipping and just draw the clip polygon. */
355     if (clip) {
356         status = _clip_to_traps (clip, &traps);
357         if (unlikely (status)) {
358             _cairo_traps_fini (&traps);
359             return status;
360         }
361     }
362
363     status = _cairo_gl_composite_init (&setup,
364                                        CAIRO_OPERATOR_DEST_OUT,
365                                        dst,
366                                        FALSE /* assume_component_alpha */);
367     if (unlikely (status))
368         return status;
369     status = _cairo_gl_composite_set_source (&setup,
370                                              composite->original_mask_pattern,
371                                              &composite->mask_sample_area,
372                                              &composite->bounded,
373                                              FALSE);
374     if (unlikely (status))
375         goto finish;
376
377     status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
378     if (unlikely (status))
379         goto finish;
380
381     if (! clip)
382         status = _draw_int_rect (ctx, &setup, &composite->bounded);
383     else
384         status = _draw_traps (ctx, &setup, &traps);
385
386     /* Now draw the second pass. */
387     _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
388                                       FALSE /* assume_component_alpha */);
389     if (unlikely (status))
390         goto finish;
391     status = _cairo_gl_composite_set_source (&setup,
392                                              composite->original_source_pattern,
393                                              &composite->source_sample_area,
394                                              &composite->bounded,
395                                              FALSE);
396     if (unlikely (status))
397         goto finish;
398     status = _cairo_gl_composite_set_mask (&setup,
399                                            composite->original_mask_pattern,
400                                            &composite->source_sample_area,
401                                            &composite->bounded);
402     if (unlikely (status))
403         goto finish;
404     status = _cairo_gl_set_operands_and_operator (&setup, ctx, TRUE);
405     if (unlikely (status))
406         goto finish;
407
408     if (! clip)
409         status = _draw_int_rect (ctx, &setup, &composite->bounded);
410     else
411         status = _draw_traps (ctx, &setup, &traps);
412
413 finish:
414     _cairo_gl_composite_fini (&setup);
415     if (ctx)
416         status = _cairo_gl_context_release (ctx, status);
417     if (clip)
418         _cairo_traps_fini (&traps);
419
420     return status;
421 }
422
423 static cairo_int_status_t
424 _cairo_gl_msaa_compositor_mask (const cairo_compositor_t        *compositor,
425                                 cairo_composite_rectangles_t    *composite)
426 {
427     cairo_gl_composite_t setup;
428     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
429     cairo_gl_context_t *ctx = NULL;
430     cairo_int_status_t status;
431     cairo_operator_t op = composite->op;
432     cairo_bool_t use_color_attribute = FALSE;
433     cairo_clip_t *clip = composite->clip;
434
435     if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
436         return CAIRO_INT_STATUS_UNSUPPORTED;
437
438     /* GL compositing operators cannot properly represent a mask operation
439        using the SOURCE compositing operator in one pass. This only matters if
440        there actually is a mask (there isn't in a paint operation) and if the
441        mask isn't totally opaque. */
442     if (op == CAIRO_OPERATOR_SOURCE &&
443          composite->original_mask_pattern != NULL &&
444         ! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
445                                     &composite->mask_sample_area)) {
446
447         if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
448                                       &composite->source_sample_area)) {
449             return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite);
450         }
451
452         /* If the source is opaque the operation reduces to OVER. */
453         op = CAIRO_OPERATOR_OVER;
454     }
455
456     if (_should_use_unbounded_surface (composite)) {
457         cairo_surface_t* surface = _prepare_unbounded_surface (dst);
458
459         if (unlikely (surface == NULL))
460             return CAIRO_INT_STATUS_UNSUPPORTED;
461
462         /* This may be a paint operation. */
463         if (composite->original_mask_pattern == NULL) {
464             status = _cairo_compositor_paint (compositor, surface,
465                                               CAIRO_OPERATOR_SOURCE,
466                                               &composite->source_pattern.base,
467                                               NULL);
468         } else {
469             status = _cairo_compositor_mask (compositor, surface,
470                                              CAIRO_OPERATOR_SOURCE,
471                                              &composite->source_pattern.base,
472                                              &composite->mask_pattern.base,
473                                              NULL);
474         }
475
476         if (unlikely (status)) {
477             cairo_surface_destroy (surface);
478             return status;
479         }
480
481         return _paint_back_unbounded_surface (compositor, composite, surface);
482     }
483
484     status = _cairo_gl_composite_init (&setup,
485                                        op,
486                                        dst,
487                                        FALSE /* assume_component_alpha */);
488     if (unlikely (status))
489         return status;
490
491     if (! composite->clip ||
492         (composite->clip->num_boxes == 1 && ! composite->clip->path))
493         use_color_attribute = TRUE;
494
495     status = _cairo_gl_composite_set_source (&setup,
496                                              composite->original_source_pattern,
497                                              &composite->source_sample_area,
498                                              &composite->bounded,
499                                              use_color_attribute);
500     if (unlikely (status))
501         goto finish;
502
503     if (composite->original_mask_pattern != NULL) {
504         status = _cairo_gl_composite_set_mask (&setup,
505                                                composite->original_mask_pattern,
506                                                &composite->mask_sample_area,
507                                                &composite->bounded);
508     }
509     if (unlikely (status))
510         goto finish;
511
512     /* We always use multisampling here, because we do not yet have the smarts
513        to calculate when the clip or the source requires it. */
514     status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
515     if (unlikely (status))
516         goto finish;
517
518     if (! clip)
519         status = _draw_int_rect (ctx, &setup, &composite->bounded);
520     else
521         status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
522
523 finish:
524     _cairo_gl_composite_fini (&setup);
525
526     if (ctx)
527         status = _cairo_gl_context_release (ctx, status);
528
529     return status;
530 }
531
532 static cairo_int_status_t
533 _cairo_gl_msaa_compositor_paint (const cairo_compositor_t       *compositor,
534                                  cairo_composite_rectangles_t   *composite)
535 {
536     return _cairo_gl_msaa_compositor_mask (compositor, composite);
537 }
538
539 static cairo_status_t
540 _stroke_shaper_add_triangle (void                       *closure,
541                              const cairo_point_t         triangle[3])
542 {
543     struct _tristrip_composite_info *info = closure;
544     return _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx,
545                                                           &info->setup,
546                                                           triangle);
547 }
548
549 static cairo_status_t
550 _stroke_shaper_add_triangle_fan (void                   *closure,
551                                  const cairo_point_t    *midpoint,
552                                  const cairo_point_t    *points,
553                                  int                     npoints)
554 {
555     struct _tristrip_composite_info *info = closure;
556     return _draw_triangle_fan (info->ctx, &info->setup,
557                                midpoint, points, npoints);
558 }
559
560 static cairo_status_t
561 _stroke_shaper_add_quad (void                   *closure,
562                          const cairo_point_t     quad[4])
563 {
564     struct _tristrip_composite_info *info = closure;
565     return _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup,
566                                                       quad);
567 }
568
569 static cairo_bool_t
570 _is_continuous_arc (const cairo_path_fixed_t   *path,
571                     const cairo_stroke_style_t *style)
572 {
573     return (_cairo_path_fixed_is_single_arc (path) &&
574             style->dash == NULL);
575 }
576
577 static cairo_int_status_t
578 _prevent_overlapping_strokes (cairo_gl_context_t                *ctx,
579                               cairo_gl_composite_t              *setup,
580                               cairo_composite_rectangles_t      *composite,
581                               const cairo_path_fixed_t          *path,
582                               const cairo_stroke_style_t        *style,
583                               const cairo_matrix_t              *ctm)
584 {
585     cairo_rectangle_int_t stroke_extents;
586     const cairo_pattern_t *pattern = composite->original_source_pattern;
587     cairo_pattern_type_t type = cairo_pattern_get_type ((cairo_pattern_t *) pattern);
588
589     if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
590         return CAIRO_INT_STATUS_UNSUPPORTED;
591
592
593     /* XXX: improve me - since we have lazy init, we cannot use sample
594        area */
595     if (type == CAIRO_PATTERN_TYPE_SOLID &&
596         _cairo_pattern_is_opaque_solid (pattern))
597         return CAIRO_INT_STATUS_SUCCESS;
598
599    if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
600         cairo_bool_t scissor_was_enabled;
601
602        /* In case we have pending operations we have to flush before
603           adding the stencil buffer. */
604        _cairo_gl_composite_flush (ctx);
605
606         /* Enable the stencil buffer, even if we are not using it for clipping,
607            so we can use it below to prevent overlapping shapes. We initialize
608            it all to one here which represents infinite clip. */
609         if (! ctx->states_cache.depth_mask) {
610             glDepthMask (GL_TRUE);
611             ctx->states_cache.depth_mask = TRUE;
612         }
613         glEnable (GL_STENCIL_TEST);
614
615         /* We scissor here so that we don't have to clear the entire stencil
616          * buffer. If the scissor test is already enabled, it was enabled
617          * for clipping. In that case, instead of calculating an intersection,
618          * we just reuse it, and risk clearing too much. */
619         scissor_was_enabled = glIsEnabled (GL_SCISSOR_TEST);
620         if (! scissor_was_enabled) {
621             _cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
622                                                           &stroke_extents);
623             _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
624         }
625         glClearStencil (1);
626         glClear (GL_STENCIL_BUFFER_BIT);
627         if (! scissor_was_enabled)
628             glDisable (GL_SCISSOR_TEST);
629
630         glStencilFunc (GL_EQUAL, 1, 1);
631     }
632
633     /* This means that once we draw to a particular pixel nothing else can
634        be drawn there until the stencil buffer is reset or the stencil test
635        is disabled. */
636     glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
637
638     return CAIRO_INT_STATUS_SUCCESS;
639 }
640
641 static void
642 query_surface_capabilities (cairo_gl_surface_t *surface)
643 {
644     GLint samples, stencil_bits;
645     cairo_gl_context_t *ctx;
646     cairo_int_status_t status;
647
648     /* Texture surfaces are create in such a way that they always
649        have stencil and multisample bits if possible, so we don't
650        need to query their capabilities lazily. */
651     if (_cairo_gl_surface_is_texture (surface))
652         return;
653     if (surface->stencil_and_msaa_caps_initialized)
654         return;
655
656     surface->stencil_and_msaa_caps_initialized = TRUE;
657     surface->supports_stencil = FALSE;
658     surface->supports_msaa = FALSE;
659
660     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
661     if (unlikely (status))
662         return;
663
664     _cairo_gl_context_set_destination (ctx, surface, FALSE);
665
666     glGetIntegerv(GL_SAMPLES, &samples);
667     glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
668     surface->supports_stencil = stencil_bits > 0;
669     surface->supports_msaa = samples > 1;
670
671     status = _cairo_gl_context_release (ctx, status);
672 }
673
674 static cairo_int_status_t
675 _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t      *compositor,
676                                   cairo_composite_rectangles_t  *composite,
677                                   const cairo_path_fixed_t      *path,
678                                   const cairo_stroke_style_t    *style,
679                                   const cairo_matrix_t          *ctm,
680                                   const cairo_matrix_t          *ctm_inverse,
681                                   double                         tolerance,
682                                   cairo_antialias_t              antialias)
683 {
684     cairo_int_status_t status;
685     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
686     struct _tristrip_composite_info info;
687     cairo_bool_t use_color_attribute;
688
689     if (! can_use_msaa_compositor (dst, antialias))
690         return CAIRO_INT_STATUS_UNSUPPORTED;
691
692     if (composite->is_bounded == FALSE) {
693         cairo_surface_t* surface = _prepare_unbounded_surface (dst);
694
695         if (unlikely (surface == NULL))
696             return CAIRO_INT_STATUS_UNSUPPORTED;
697
698         status = _cairo_compositor_stroke (compositor, surface,
699                                            CAIRO_OPERATOR_SOURCE,
700                                            &composite->source_pattern.base,
701                                            path, style, ctm, ctm_inverse,
702                                            tolerance, antialias, NULL);
703         if (unlikely (status)) {
704             cairo_surface_destroy (surface);
705             return status;
706         }
707
708         return _paint_back_unbounded_surface (compositor, composite, surface);
709     }
710
711     status = _cairo_gl_composite_init (&info.setup,
712                                        composite->op,
713                                        dst,
714                                        FALSE /* assume_component_alpha */);
715     if (unlikely (status))
716         return status;
717
718     info.ctx = NULL;
719     use_color_attribute = _cairo_path_fixed_stroke_is_rectilinear (path) ||
720                           _cairo_gl_hairline_style_is_hairline (style, ctm);
721
722     status = _cairo_gl_composite_set_source (&info.setup,
723                                              composite->original_source_pattern,
724                                              &composite->source_sample_area,
725                                              &composite->bounded,
726                                              use_color_attribute);
727     if (unlikely (status))
728         goto finish;
729
730     _cairo_gl_msaa_compositor_set_clip (composite, &info.setup);
731
732     status = _cairo_gl_composite_begin_multisample (&info.setup, &info.ctx,
733         antialias != CAIRO_ANTIALIAS_NONE);
734     if (unlikely (status))
735         goto finish;
736
737     if (_cairo_gl_hairline_style_is_hairline (style, ctm)) {
738         cairo_gl_hairline_closure_t closure;
739
740         if (! (_is_continuous_arc (path, style) ||
741                _is_continuous_single_line (path, style))) {
742             status = _prevent_overlapping_strokes (info.ctx, &info.setup,
743                                                    composite, path,
744                                                    style, ctm);
745             if (unlikely (status))
746                 goto finish;
747         }
748
749         closure.ctx = info.ctx;
750
751         closure.tolerance = tolerance;
752
753         status = _cairo_gl_path_fixed_stroke_to_hairline (path, &closure,
754                                                           style, ctm,
755                                                           ctm_inverse,
756                                                           _cairo_gl_hairline_move_to,
757                                                           style->dash ?
758                                                           _cairo_gl_hairline_line_to_dashed :
759                                                           _cairo_gl_hairline_line_to,
760                                                           _cairo_gl_hairline_curve_to,
761                                                           _cairo_gl_hairline_close_path);
762         goto finish;
763     }
764
765     if (use_color_attribute) {
766         cairo_traps_t traps;
767
768         _cairo_traps_init (&traps);
769
770         status = _cairo_path_fixed_stroke_to_traps (path, style,
771                                                     ctm, ctm_inverse,
772                                                     tolerance, &traps);
773         if (unlikely (status)) {
774             _cairo_traps_fini (&traps);
775             goto finish;
776         }
777
778         status = _draw_traps (info.ctx, &info.setup, &traps);
779         _cairo_traps_fini (&traps);
780     } else {
781         if (!_is_continuous_single_line (path, style)) {
782             status = _prevent_overlapping_strokes (info.ctx, &info.setup,
783                                                    composite, path, style, ctm);
784             if (unlikely (status))
785                 goto finish;
786         }
787
788         status =
789             _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path,
790                                                 style,
791                                                 ctm,
792                                                 ctm_inverse,
793                                                 tolerance,
794                                                 _stroke_shaper_add_triangle,
795                                                 _stroke_shaper_add_triangle_fan,
796                                                 _stroke_shaper_add_quad,
797                                                 &info);
798         if (unlikely (status))
799             goto finish;
800     }
801 finish:
802     _cairo_gl_composite_fini (&info.setup);
803
804     if (info.ctx)
805         status = _cairo_gl_context_release (info.ctx, status);
806
807     return status;
808 }
809
810 static cairo_int_status_t
811 _cairo_gl_msaa_compositor_fill_rectilinear (const cairo_compositor_t *compositor,
812                                             cairo_composite_rectangles_t *composite,
813                                             const cairo_path_fixed_t *path,
814                                             cairo_fill_rule_t fill_rule,
815                                             double tolerance,
816                                             cairo_antialias_t antialias,
817                                             cairo_clip_t *clip)
818 {
819     cairo_gl_composite_t setup;
820     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
821     cairo_gl_context_t *ctx = NULL;
822     cairo_int_status_t status;
823     int i;
824
825     status = _cairo_gl_composite_init (&setup,
826                                        composite->op,
827                                        dst,
828                                        FALSE /* assume_component_alpha */);
829     if (unlikely (status))
830         goto cleanup_setup;
831
832     status = _cairo_gl_composite_set_source (&setup,
833                                              composite->original_source_pattern,
834                                              &composite->source_sample_area,
835                                              &composite->bounded,
836                                              TRUE);
837     if (unlikely (status))
838         goto cleanup_setup;
839
840     status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
841         antialias != CAIRO_ANTIALIAS_NONE);
842     if (unlikely (status))
843         goto cleanup_setup;
844
845     for (i = 0; i < clip->num_boxes; i++) {
846         status = _draw_box (ctx, &setup, &clip->boxes[i]);
847         if (unlikely (status))
848             goto cleanup_setup;
849     }
850
851 cleanup_setup:
852     _cairo_gl_composite_fini (&setup);
853
854     if (ctx)
855         status = _cairo_gl_context_release (ctx, status);
856
857     return status;
858 }
859
860 static cairo_int_status_t
861 _cairo_gl_msaa_compositor_fill (const cairo_compositor_t        *compositor,
862                                 cairo_composite_rectangles_t    *composite,
863                                 const cairo_path_fixed_t        *path,
864                                 cairo_fill_rule_t                fill_rule,
865                                 double                           tolerance,
866                                 cairo_antialias_t                antialias)
867 {
868     cairo_gl_composite_t setup;
869     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
870     cairo_gl_context_t *ctx = NULL;
871     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
872     cairo_traps_t traps;
873     cairo_bool_t use_color_attr = FALSE;
874
875     if (! can_use_msaa_compositor (dst, antialias))
876         return CAIRO_INT_STATUS_UNSUPPORTED;
877
878     if (composite->is_bounded == FALSE) {
879         cairo_surface_t* surface = _prepare_unbounded_surface (dst);
880
881         if (unlikely (surface == NULL))
882             return CAIRO_INT_STATUS_UNSUPPORTED;
883
884
885         status = _cairo_compositor_fill (compositor, surface,
886                                          CAIRO_OPERATOR_SOURCE,
887                                          &composite->source_pattern.base,
888                                          path, fill_rule, tolerance,
889                                          antialias, NULL);
890
891         if (unlikely (status)) {
892             cairo_surface_destroy (surface);
893             return status;
894         }
895
896         return _paint_back_unbounded_surface (compositor, composite, surface);
897     }
898
899     if (_cairo_path_fixed_fill_is_rectilinear (path) &&
900         composite->clip != NULL &&
901         composite->clip->num_boxes == 1 &&
902         composite->clip->path == NULL) {
903         cairo_clip_t *clip = _cairo_clip_copy (composite->clip);
904         clip = _cairo_clip_intersect_rectilinear_path (clip,
905                                                        path,
906                                                        fill_rule,
907                                                        antialias);
908         if (clip->num_boxes)
909                 status = _cairo_gl_msaa_compositor_fill_rectilinear (compositor,
910                                                                      composite,
911                                                                      path,
912                                                                      fill_rule,
913                                                                      tolerance,
914                                                                      antialias,
915                                                                      clip);
916         _cairo_clip_destroy (clip);
917
918         return status;
919     }
920
921     _cairo_traps_init (&traps);
922     if (_cairo_path_fixed_fill_is_rectilinear (path)) {
923         status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
924                                                               fill_rule,
925                                                               antialias,
926                                                               &traps);
927         use_color_attr = TRUE;
928     } else {
929         status = _cairo_path_fixed_fill_to_traps (path, fill_rule,
930                                                   tolerance, &traps);
931     }
932
933     status = _cairo_gl_composite_init (&setup,
934                                        composite->op,
935                                        dst,
936                                        FALSE /* assume_component_alpha */);
937     if (unlikely (status))
938         goto cleanup_traps;
939
940     status = _cairo_gl_composite_set_source (&setup,
941                                              composite->original_source_pattern,
942                                              &composite->source_sample_area,
943                                              &composite->bounded,
944                                              use_color_attr);
945     if (unlikely (status))
946         goto cleanup_setup;
947
948     _cairo_gl_msaa_compositor_set_clip (composite, &setup);
949
950     status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
951         antialias != CAIRO_ANTIALIAS_NONE);
952     if (unlikely (status))
953         goto cleanup_setup;
954
955     status = _draw_traps (ctx, &setup, &traps);
956     if (unlikely (status))
957         goto cleanup_setup;
958
959 cleanup_setup:
960     _cairo_gl_composite_fini (&setup);
961
962     if (ctx)
963         status = _cairo_gl_context_release (ctx, status);
964
965 cleanup_traps:
966     _cairo_traps_fini (&traps);
967
968     return status;
969 }
970
971 static cairo_int_status_t
972 _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t      *compositor,
973                                   cairo_composite_rectangles_t  *composite,
974                                   cairo_scaled_font_t           *scaled_font,
975                                   cairo_glyph_t                 *glyphs,
976                                   int                            num_glyphs,
977                                   cairo_bool_t                   overlap)
978 {
979     cairo_int_status_t status;
980     cairo_surface_t *src = NULL;
981     int src_x, src_y;
982     cairo_composite_glyphs_info_t info;
983
984     cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
985
986     query_surface_capabilities (dst);
987     if (! dst->supports_stencil)
988         return CAIRO_INT_STATUS_UNSUPPORTED;
989
990     if (composite->is_bounded == FALSE) {
991         cairo_surface_t* surface = _prepare_unbounded_surface (dst);
992
993         if (unlikely (surface == NULL))
994             return CAIRO_INT_STATUS_UNSUPPORTED;
995
996         status = _cairo_compositor_glyphs (compositor, surface,
997                                            CAIRO_OPERATOR_SOURCE,
998                                            &composite->source_pattern.base,
999                                            glyphs, num_glyphs,
1000                                            scaled_font, composite->clip);
1001
1002         if (unlikely (status)) {
1003             cairo_surface_destroy (surface);
1004             return status;
1005         }
1006
1007         return _paint_back_unbounded_surface (compositor, composite, surface);
1008     }
1009
1010     src = _cairo_gl_pattern_to_source (&dst->base,
1011                                        composite->original_source_pattern,
1012                                        FALSE,
1013                                        &composite->bounded,
1014                                        &composite->source_sample_area,
1015                                        &src_x, &src_y);
1016     if (unlikely (src->status)) {
1017         status = src->status;
1018         goto finish;
1019     }
1020
1021     status = _cairo_gl_check_composite_glyphs (composite,
1022                                                scaled_font, glyphs,
1023                                                &num_glyphs);
1024     if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
1025         goto finish;
1026
1027     info.font = scaled_font;
1028     info.glyphs = glyphs;
1029     info.num_glyphs = num_glyphs;
1030     info.use_mask = overlap || ! composite->is_bounded ||
1031                     composite->op == CAIRO_OPERATOR_SOURCE;
1032     info.extents = composite->bounded;
1033
1034     _cairo_scaled_font_freeze_cache (scaled_font);
1035     status = _cairo_gl_composite_glyphs_with_clip (dst, composite->op,
1036                                                    src, src_x, src_y,
1037                                                    0, 0, &info,
1038                                                    composite->clip,
1039                                                    TRUE);
1040
1041     _cairo_scaled_font_thaw_cache (scaled_font);
1042
1043 finish:
1044     if (src)
1045         cairo_surface_destroy (src);
1046
1047     return status;
1048 }
1049
1050 static void
1051 _cairo_gl_msaa_compositor_init (cairo_compositor_t       *compositor,
1052                                 const cairo_compositor_t *delegate)
1053 {
1054     compositor->delegate = delegate;
1055     compositor->lazy_init = TRUE;
1056
1057     compositor->paint = _cairo_gl_msaa_compositor_paint;
1058     compositor->mask = _cairo_gl_msaa_compositor_mask;
1059     compositor->fill = _cairo_gl_msaa_compositor_fill;
1060     compositor->stroke = _cairo_gl_msaa_compositor_stroke;
1061     compositor->glyphs = _cairo_gl_msaa_compositor_glyphs;
1062 }
1063
1064 const cairo_compositor_t *
1065 _cairo_gl_msaa_compositor_get (void)
1066 {
1067     static cairo_compositor_t compositor;
1068     if (compositor.delegate == NULL)
1069         _cairo_gl_msaa_compositor_init (&compositor,
1070                                         _cairo_gl_span_compositor_get ());
1071
1072     return &compositor;
1073 }