Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 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 |
||
39 | * Martin Robinson |
||
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-path-private.h" |
||
49 | #include "cairo-traps-private.h" |
||
50 | |||
51 | static cairo_bool_t |
||
52 | can_use_msaa_compositor (cairo_gl_surface_t *surface, |
||
53 | cairo_antialias_t antialias); |
||
54 | |||
55 | static void |
||
56 | query_surface_capabilities (cairo_gl_surface_t *surface); |
||
57 | |||
58 | struct _tristrip_composite_info { |
||
59 | cairo_gl_composite_t setup; |
||
60 | cairo_gl_context_t *ctx; |
||
61 | }; |
||
62 | |||
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) |
||
67 | { |
||
68 | cairo_point_t quad[4]; |
||
69 | |||
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; |
||
74 | |||
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; |
||
79 | |||
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; |
||
84 | |||
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); |
||
90 | } |
||
91 | |||
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) |
||
96 | { |
||
97 | cairo_int_status_t status = CAIRO_STATUS_SUCCESS; |
||
98 | int i; |
||
99 | |||
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; |
||
104 | } |
||
105 | |||
106 | return status; |
||
107 | } |
||
108 | |||
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) |
||
113 | { |
||
114 | cairo_box_t box; |
||
115 | cairo_point_t quad[4]; |
||
116 | |||
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; |
||
126 | |||
127 | return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad); |
||
128 | } |
||
129 | |||
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) |
||
136 | { |
||
137 | int i; |
||
138 | |||
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]; |
||
144 | |||
145 | triangle[0] = *midpt; |
||
146 | triangle[1] = points[i - 1]; |
||
147 | triangle[2] = points[i]; |
||
148 | |||
149 | status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle); |
||
150 | if (unlikely (status)) |
||
151 | return status; |
||
152 | } |
||
153 | |||
154 | return CAIRO_STATUS_SUCCESS; |
||
155 | } |
||
156 | |||
157 | static cairo_int_status_t |
||
158 | _clip_to_traps (cairo_clip_t *clip, |
||
159 | cairo_traps_t *traps) |
||
160 | { |
||
161 | cairo_int_status_t status; |
||
162 | cairo_polygon_t polygon; |
||
163 | cairo_antialias_t antialias; |
||
164 | cairo_fill_rule_t fill_rule; |
||
165 | |||
166 | _cairo_traps_init (traps); |
||
167 | |||
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); |
||
172 | } |
||
173 | |||
174 | status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias); |
||
175 | if (unlikely (status)) |
||
176 | return status; |
||
177 | |||
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. |
||
182 | * |
||
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. |
||
187 | */ |
||
188 | |||
189 | _cairo_traps_init (traps); |
||
190 | status = _cairo_bentley_ottmann_tessellate_polygon (traps, |
||
191 | &polygon, |
||
192 | fill_rule); |
||
193 | _cairo_polygon_fini (&polygon); |
||
194 | |||
195 | return status; |
||
196 | } |
||
197 | |||
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) |
||
202 | { |
||
203 | cairo_int_status_t status; |
||
204 | cairo_traps_t traps; |
||
205 | |||
206 | status = _clip_to_traps (clip, &traps); |
||
207 | if (unlikely (status)) |
||
208 | return status; |
||
209 | status = _draw_traps (ctx, setup, &traps); |
||
210 | |||
211 | _cairo_traps_fini (&traps); |
||
212 | return status; |
||
213 | } |
||
214 | |||
215 | static cairo_bool_t |
||
216 | _should_use_unbounded_surface (cairo_composite_rectangles_t *composite) |
||
217 | { |
||
218 | cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; |
||
219 | cairo_rectangle_int_t *source = &composite->source; |
||
220 | |||
221 | if (composite->is_bounded) |
||
222 | return FALSE; |
||
223 | |||
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); |
||
229 | } |
||
230 | |||
231 | static cairo_surface_t* |
||
232 | _prepare_unbounded_surface (cairo_gl_surface_t *dst) |
||
233 | { |
||
234 | |||
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; |
||
244 | } |
||
245 | return surface; |
||
246 | } |
||
247 | |||
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) |
||
252 | { |
||
253 | cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; |
||
254 | cairo_int_status_t status; |
||
255 | |||
256 | cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface); |
||
257 | if (unlikely (pattern->status)) { |
||
258 | status = pattern->status; |
||
259 | goto finish; |
||
260 | } |
||
261 | |||
262 | status = _cairo_compositor_paint (compositor, &dst->base, |
||
263 | composite->op, pattern, |
||
264 | composite->clip); |
||
265 | |||
266 | finish: |
||
267 | cairo_pattern_destroy (pattern); |
||
268 | cairo_surface_destroy (surface); |
||
269 | return status; |
||
270 | } |
||
271 | |||
272 | static cairo_bool_t |
||
273 | can_use_msaa_compositor (cairo_gl_surface_t *surface, |
||
274 | cairo_antialias_t antialias) |
||
275 | { |
||
276 | query_surface_capabilities (surface); |
||
277 | if (! surface->supports_stencil) |
||
278 | return FALSE; |
||
279 | |||
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; |
||
287 | |||
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; |
||
292 | |||
293 | if (antialias == CAIRO_ANTIALIAS_FAST || antialias == CAIRO_ANTIALIAS_DEFAULT) |
||
294 | return surface->supports_msaa; |
||
295 | return FALSE; |
||
296 | } |
||
297 | |||
298 | static void |
||
299 | _cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite, |
||
300 | cairo_gl_composite_t *setup) |
||
301 | { |
||
302 | if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip)) |
||
303 | return; |
||
304 | _cairo_gl_composite_set_clip (setup, composite->clip); |
||
305 | } |
||
306 | |||
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 |
||
314 | */ |
||
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) |
||
318 | { |
||
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; |
||
323 | |||
324 | cairo_clip_t *clip = composite->clip; |
||
325 | cairo_traps_t traps; |
||
326 | |||
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; |
||
334 | } |
||
335 | } |
||
336 | |||
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; |
||
354 | |||
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; |
||
361 | |||
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; |
||
384 | |||
385 | if (! clip) |
||
386 | status = _draw_int_rect (ctx, &setup, &composite->bounded); |
||
387 | else |
||
388 | status = _draw_traps (ctx, &setup, &traps); |
||
389 | |||
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); |
||
396 | |||
397 | return status; |
||
398 | } |
||
399 | |||
400 | static cairo_int_status_t |
||
401 | _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor, |
||
402 | cairo_composite_rectangles_t *composite) |
||
403 | { |
||
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; |
||
410 | |||
411 | if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT)) |
||
412 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
413 | |||
414 | if (composite->op == CAIRO_OPERATOR_CLEAR && |
||
415 | composite->original_mask_pattern != NULL) |
||
416 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
417 | |||
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)) { |
||
426 | |||
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); |
||
430 | } |
||
431 | |||
432 | /* If the source is opaque the operation reduces to OVER. */ |
||
433 | op = CAIRO_OPERATOR_OVER; |
||
434 | } |
||
435 | |||
436 | if (_should_use_unbounded_surface (composite)) { |
||
437 | cairo_surface_t* surface = _prepare_unbounded_surface (dst); |
||
438 | |||
439 | if (unlikely (surface == NULL)) |
||
440 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
441 | |||
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); |
||
454 | } |
||
455 | |||
456 | if (unlikely (status)) { |
||
457 | cairo_surface_destroy (surface); |
||
458 | return status; |
||
459 | } |
||
460 | |||
461 | return _paint_back_unbounded_surface (compositor, composite, surface); |
||
462 | } |
||
463 | |||
464 | status = _cairo_gl_composite_init (&setup, |
||
465 | op, |
||
466 | dst, |
||
467 | FALSE /* assume_component_alpha */); |
||
468 | if (unlikely (status)) |
||
469 | return status; |
||
470 | |||
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; |
||
478 | |||
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); |
||
485 | } |
||
486 | if (unlikely (status)) |
||
487 | goto finish; |
||
488 | |||
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); |
||
492 | |||
493 | status = _cairo_gl_composite_begin (&setup, &ctx); |
||
494 | if (unlikely (status)) |
||
495 | goto finish; |
||
496 | |||
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); |
||
501 | |||
502 | finish: |
||
503 | _cairo_gl_composite_fini (&setup); |
||
504 | |||
505 | if (ctx) |
||
506 | status = _cairo_gl_context_release (ctx, status); |
||
507 | |||
508 | return status; |
||
509 | } |
||
510 | |||
511 | static cairo_int_status_t |
||
512 | _cairo_gl_msaa_compositor_paint (const cairo_compositor_t *compositor, |
||
513 | cairo_composite_rectangles_t *composite) |
||
514 | { |
||
515 | return _cairo_gl_msaa_compositor_mask (compositor, composite); |
||
516 | } |
||
517 | |||
518 | static cairo_status_t |
||
519 | _stroke_shaper_add_triangle (void *closure, |
||
520 | const cairo_point_t triangle[3]) |
||
521 | { |
||
522 | struct _tristrip_composite_info *info = closure; |
||
523 | return _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx, |
||
524 | &info->setup, |
||
525 | triangle); |
||
526 | } |
||
527 | |||
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) |
||
533 | { |
||
534 | struct _tristrip_composite_info *info = closure; |
||
535 | return _draw_triangle_fan (info->ctx, &info->setup, |
||
536 | midpoint, points, npoints); |
||
537 | } |
||
538 | |||
539 | static cairo_status_t |
||
540 | _stroke_shaper_add_quad (void *closure, |
||
541 | const cairo_point_t quad[4]) |
||
542 | { |
||
543 | struct _tristrip_composite_info *info = closure; |
||
544 | return _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup, |
||
545 | quad); |
||
546 | } |
||
547 | |||
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) |
||
555 | { |
||
556 | cairo_rectangle_int_t stroke_extents; |
||
557 | |||
558 | if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) |
||
559 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
560 | |||
561 | if (_cairo_pattern_is_opaque (&composite->source_pattern.base, |
||
562 | &composite->source_sample_area)) |
||
563 | return CAIRO_INT_STATUS_SUCCESS; |
||
564 | |||
565 | if (glIsEnabled (GL_STENCIL_TEST) == FALSE) { |
||
566 | cairo_bool_t scissor_was_enabled; |
||
567 | |||
568 | /* In case we have pending operations we have to flush before |
||
569 | adding the stencil buffer. */ |
||
570 | _cairo_gl_composite_flush (ctx); |
||
571 | |||
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); |
||
577 | |||
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); |
||
587 | } |
||
588 | glClearStencil (1); |
||
589 | glClear (GL_STENCIL_BUFFER_BIT); |
||
590 | if (! scissor_was_enabled) |
||
591 | glDisable (GL_SCISSOR_TEST); |
||
592 | |||
593 | glStencilFunc (GL_EQUAL, 1, 1); |
||
594 | } |
||
595 | |||
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); |
||
600 | |||
601 | _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer); |
||
602 | setup->dst->clip_on_stencil_buffer = NULL; |
||
603 | |||
604 | return CAIRO_INT_STATUS_SUCCESS; |
||
605 | } |
||
606 | |||
607 | static void |
||
608 | query_surface_capabilities (cairo_gl_surface_t *surface) |
||
609 | { |
||
610 | GLint samples, stencil_bits; |
||
611 | cairo_gl_context_t *ctx; |
||
612 | cairo_int_status_t status; |
||
613 | |||
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; |
||
621 | |||
622 | surface->stencil_and_msaa_caps_initialized = TRUE; |
||
623 | surface->supports_stencil = FALSE; |
||
624 | surface->supports_msaa = FALSE; |
||
625 | |||
626 | status = _cairo_gl_context_acquire (surface->base.device, &ctx); |
||
627 | if (unlikely (status)) |
||
628 | return; |
||
629 | |||
630 | _cairo_gl_context_set_destination (ctx, surface, FALSE); |
||
631 | |||
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; |
||
636 | |||
637 | status = _cairo_gl_context_release (ctx, status); |
||
638 | } |
||
639 | |||
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) |
||
649 | { |
||
650 | cairo_int_status_t status; |
||
651 | cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; |
||
652 | struct _tristrip_composite_info info; |
||
653 | |||
654 | if (! can_use_msaa_compositor (dst, antialias)) |
||
655 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
656 | |||
657 | if (composite->is_bounded == FALSE) { |
||
658 | cairo_surface_t* surface = _prepare_unbounded_surface (dst); |
||
659 | |||
660 | if (unlikely (surface == NULL)) |
||
661 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
662 | |||
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; |
||
671 | } |
||
672 | |||
673 | return _paint_back_unbounded_surface (compositor, composite, surface); |
||
674 | } |
||
675 | |||
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; |
||
682 | |||
683 | info.ctx = NULL; |
||
684 | |||
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; |
||
692 | |||
693 | _cairo_gl_msaa_compositor_set_clip (composite, &info.setup); |
||
694 | if (antialias != CAIRO_ANTIALIAS_NONE) |
||
695 | _cairo_gl_composite_set_multisample (&info.setup); |
||
696 | |||
697 | status = _cairo_gl_composite_begin (&info.setup, &info.ctx); |
||
698 | if (unlikely (status)) |
||
699 | goto finish; |
||
700 | |||
701 | status = _prevent_overlapping_strokes (info.ctx, &info.setup, |
||
702 | composite, path, style, ctm); |
||
703 | if (unlikely (status)) |
||
704 | goto finish; |
||
705 | |||
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; |
||
717 | |||
718 | finish: |
||
719 | _cairo_gl_composite_fini (&info.setup); |
||
720 | |||
721 | if (info.ctx) |
||
722 | status = _cairo_gl_context_release (info.ctx, status); |
||
723 | |||
724 | return status; |
||
725 | } |
||
726 | |||
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) |
||
731 | { |
||
732 | cairo_point_t triangle[3]; |
||
733 | cairo_int_status_t status; |
||
734 | const cairo_point_t *points; |
||
735 | |||
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; |
||
743 | |||
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); |
||
748 | } |
||
749 | |||
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) |
||
757 | { |
||
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; |
||
764 | |||
765 | if (! can_use_msaa_compositor (dst, antialias)) |
||
766 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
767 | |||
768 | if (composite->is_bounded == FALSE) { |
||
769 | cairo_surface_t* surface = _prepare_unbounded_surface (dst); |
||
770 | |||
771 | if (unlikely (surface == NULL)) |
||
772 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
773 | |||
774 | |||
775 | status = _cairo_compositor_fill (compositor, surface, |
||
776 | CAIRO_OPERATOR_SOURCE, |
||
777 | &composite->source_pattern.base, |
||
778 | path, fill_rule, tolerance, |
||
779 | antialias, NULL); |
||
780 | |||
781 | if (unlikely (status)) { |
||
782 | cairo_surface_destroy (surface); |
||
783 | return status; |
||
784 | } |
||
785 | |||
786 | return _paint_back_unbounded_surface (compositor, composite, surface); |
||
787 | } |
||
788 | |||
789 | draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path); |
||
790 | |||
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; |
||
796 | } |
||
797 | |||
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; |
||
804 | |||
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; |
||
812 | |||
813 | _cairo_gl_msaa_compositor_set_clip (composite, &setup); |
||
814 | if (antialias != CAIRO_ANTIALIAS_NONE) |
||
815 | _cairo_gl_composite_set_multisample (&setup); |
||
816 | |||
817 | status = _cairo_gl_composite_begin (&setup, &ctx); |
||
818 | if (unlikely (status)) |
||
819 | goto cleanup_setup; |
||
820 | |||
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; |
||
827 | |||
828 | cleanup_setup: |
||
829 | _cairo_gl_composite_fini (&setup); |
||
830 | |||
831 | if (ctx) |
||
832 | status = _cairo_gl_context_release (ctx, status); |
||
833 | |||
834 | cleanup_traps: |
||
835 | if (draw_path_with_traps) |
||
836 | _cairo_traps_fini (&traps); |
||
837 | |||
838 | return status; |
||
839 | } |
||
840 | |||
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) |
||
848 | { |
||
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; |
||
853 | |||
854 | cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; |
||
855 | |||
856 | query_surface_capabilities (dst); |
||
857 | if (! dst->supports_stencil) |
||
858 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
859 | |||
860 | if (composite->op == CAIRO_OPERATOR_CLEAR) |
||
861 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
862 | |||
863 | if (composite->is_bounded == FALSE) { |
||
864 | cairo_surface_t* surface = _prepare_unbounded_surface (dst); |
||
865 | |||
866 | if (unlikely (surface == NULL)) |
||
867 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
868 | |||
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); |
||
874 | |||
875 | if (unlikely (status)) { |
||
876 | cairo_surface_destroy (surface); |
||
877 | return status; |
||
878 | } |
||
879 | |||
880 | return _paint_back_unbounded_surface (compositor, composite, surface); |
||
881 | } |
||
882 | |||
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; |
||
892 | } |
||
893 | |||
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; |
||
899 | |||
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; |
||
906 | |||
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); |
||
912 | |||
913 | _cairo_scaled_font_thaw_cache (scaled_font); |
||
914 | |||
915 | finish: |
||
916 | if (src) |
||
917 | cairo_surface_destroy (src); |
||
918 | |||
919 | return status; |
||
920 | } |
||
921 | |||
922 | static void |
||
923 | _cairo_gl_msaa_compositor_init (cairo_compositor_t *compositor, |
||
924 | const cairo_compositor_t *delegate) |
||
925 | { |
||
926 | compositor->delegate = delegate; |
||
927 | |||
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; |
||
933 | } |
||
934 | |||
935 | const cairo_compositor_t * |
||
936 | _cairo_gl_msaa_compositor_get (void) |
||
937 | { |
||
938 | static cairo_compositor_t compositor; |
||
939 | if (compositor.delegate == NULL) |
||
940 | _cairo_gl_msaa_compositor_init (&compositor, |
||
941 | _cairo_gl_span_compositor_get ()); |
||
942 | |||
943 | return &compositor; |
||
944 | }=>=>>> |