1 /* cairo - a vector graphics library with display and print output
2 *
3 * Copyright © 2009 Eric Anholt
4 * Copyright © 2009 Chris Wilson
5 * Copyright © 2005,2010 Red Hat, Inc
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
14 *
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
20 *
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
25 *
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
29 *
30 * The Original Code is the cairo graphics library.
31 *
32 * The Initial Developer of the Original Code is Red Hat, Inc.
33 *
34 * Contributor(s):
35 * Benjamin Otte <otte@gnome.org>
36 * Carl Worth <cworth@cworth.org>
37 * Chris Wilson <chris@chris-wilson.co.uk>
38 * Eric Anholt <eric@anholt.net>
39 */
40
41 #include "cairoint.h"
42
43 #include "cairo-composite-rectangles-private.h"
44 #include "cairo-error-private.h"
45 #include "cairo-gl-private.h"
46
47 static cairo_int_status_t
48 _cairo_gl_surface_fill_rectangles (void *abstract_dst,
49 cairo_operator_t op,
50 const cairo_color_t *color,
51 cairo_rectangle_int_t *rects,
52 int num_rects);
53
54 static cairo_int_status_t
55 _cairo_gl_surface_composite (cairo_operator_t op,
56 const cairo_pattern_t *src,
57 const cairo_pattern_t *mask,
58 void *abstract_dst,
59 int src_x,
60 int src_y,
61 int mask_x,
62 int mask_y,
63 int dst_x,
64 int dst_y,
65 unsigned int width,
66 unsigned int height,
67 cairo_region_t *clip_region);
68
69 static cairo_status_t
70 _cairo_gl_surface_flush (void *abstract_surface);
71
_cairo_surface_is_gl(cairo_surface_t * surface)72 static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
73 {
74 return surface->backend == &_cairo_gl_surface_backend;
75 }
76
77 cairo_bool_t
_cairo_gl_get_image_format_and_type(pixman_format_code_t pixman_format,GLenum * internal_format,GLenum * format,GLenum * type,cairo_bool_t * has_alpha)78 _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
79 GLenum *internal_format, GLenum *format,
80 GLenum *type, cairo_bool_t *has_alpha)
81 {
82 *has_alpha = TRUE;
83
84 switch (pixman_format) {
85 case PIXMAN_a8r8g8b8:
86 *internal_format = GL_RGBA;
87 *format = GL_BGRA;
88 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
89 return TRUE;
90 case PIXMAN_x8r8g8b8:
91 *internal_format = GL_RGB;
92 *format = GL_BGRA;
93 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
94 *has_alpha = FALSE;
95 return TRUE;
96 case PIXMAN_a8b8g8r8:
97 *internal_format = GL_RGBA;
98 *format = GL_RGBA;
99 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
100 return TRUE;
101 case PIXMAN_x8b8g8r8:
102 *internal_format = GL_RGB;
103 *format = GL_RGBA;
104 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
105 *has_alpha = FALSE;
106 return TRUE;
107 case PIXMAN_b8g8r8a8:
108 *internal_format = GL_RGBA;
109 *format = GL_BGRA;
110 *type = GL_UNSIGNED_INT_8_8_8_8;
111 return TRUE;
112 case PIXMAN_b8g8r8x8:
113 *internal_format = GL_RGB;
114 *format = GL_BGRA;
115 *type = GL_UNSIGNED_INT_8_8_8_8;
116 *has_alpha = FALSE;
117 return TRUE;
118 case PIXMAN_r8g8b8:
119 *internal_format = GL_RGB;
120 *format = GL_RGB;
121 *type = GL_UNSIGNED_BYTE;
122 return TRUE;
123 case PIXMAN_b8g8r8:
124 *internal_format = GL_RGB;
125 *format = GL_BGR;
126 *type = GL_UNSIGNED_BYTE;
127 return TRUE;
128 case PIXMAN_r5g6b5:
129 *internal_format = GL_RGB;
130 *format = GL_RGB;
131 *type = GL_UNSIGNED_SHORT_5_6_5;
132 return TRUE;
133 case PIXMAN_b5g6r5:
134 *internal_format = GL_RGB;
135 *format = GL_RGB;
136 *type = GL_UNSIGNED_SHORT_5_6_5_REV;
137 return TRUE;
138 case PIXMAN_a1r5g5b5:
139 *internal_format = GL_RGBA;
140 *format = GL_BGRA;
141 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
142 return TRUE;
143 case PIXMAN_x1r5g5b5:
144 *internal_format = GL_RGB;
145 *format = GL_BGRA;
146 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
147 *has_alpha = FALSE;
148 return TRUE;
149 case PIXMAN_a1b5g5r5:
150 *internal_format = GL_RGBA;
151 *format = GL_RGBA;
152 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
153 return TRUE;
154 case PIXMAN_x1b5g5r5:
155 *internal_format = GL_RGB;
156 *format = GL_RGBA;
157 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
158 *has_alpha = FALSE;
159 return TRUE;
160 case PIXMAN_a8:
161 *internal_format = GL_ALPHA;
162 *format = GL_ALPHA;
163 *type = GL_UNSIGNED_BYTE;
164 return TRUE;
165
166 case PIXMAN_a2b10g10r10:
167 case PIXMAN_x2b10g10r10:
168 case PIXMAN_a4r4g4b4:
169 case PIXMAN_x4r4g4b4:
170 case PIXMAN_a4b4g4r4:
171 case PIXMAN_x4b4g4r4:
172 case PIXMAN_r3g3b2:
173 case PIXMAN_b2g3r3:
174 case PIXMAN_a2r2g2b2:
175 case PIXMAN_a2b2g2r2:
176 case PIXMAN_c8:
177 case PIXMAN_x4a4:
178 /* case PIXMAN_x4c4: */
179 case PIXMAN_x4g4:
180 case PIXMAN_a4:
181 case PIXMAN_r1g2b1:
182 case PIXMAN_b1g2r1:
183 case PIXMAN_a1r1g1b1:
184 case PIXMAN_a1b1g1r1:
185 case PIXMAN_c4:
186 case PIXMAN_g4:
187 case PIXMAN_a1:
188 case PIXMAN_g1:
189 case PIXMAN_yuy2:
190 case PIXMAN_yv12:
191 case PIXMAN_x2r10g10b10:
192 case PIXMAN_a2r10g10b10:
193 default:
194 return FALSE;
195 }
196 }
197
198 cairo_bool_t
_cairo_gl_operator_is_supported(cairo_operator_t op)199 _cairo_gl_operator_is_supported (cairo_operator_t op)
200 {
201 return op < CAIRO_OPERATOR_SATURATE;
202 }
203
204 void
_cairo_gl_surface_init(cairo_device_t * device,cairo_gl_surface_t * surface,cairo_content_t content,int width,int height)205 _cairo_gl_surface_init (cairo_device_t *device,
206 cairo_gl_surface_t *surface,
207 cairo_content_t content,
208 int width, int height)
209 {
210 _cairo_surface_init (&surface->base,
211 &_cairo_gl_surface_backend,
212 device,
213 content);
214
215 surface->width = width;
216 surface->height = height;
217 }
218
219 static cairo_surface_t *
_cairo_gl_surface_create_scratch_for_texture(cairo_gl_context_t * ctx,cairo_content_t content,GLuint tex,int width,int height)220 _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx,
221 cairo_content_t content,
222 GLuint tex,
223 int width,
224 int height)
225 {
226 cairo_gl_surface_t *surface;
227
228 assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size);
229
230 surface = calloc (1, sizeof (cairo_gl_surface_t));
231 if (unlikely (surface == NULL))
232 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
233
234 _cairo_gl_surface_init (&ctx->base, surface, content, width, height);
235 surface->tex = tex;
236
237 /* Create the texture used to store the surface's data. */
238 _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
239 glBindTexture (ctx->tex_target, surface->tex);
240 glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
241 glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
242
243 return &surface->base;
244 }
245
246 static cairo_surface_t *
_cairo_gl_surface_create_scratch(cairo_gl_context_t * ctx,cairo_content_t content,int width,int height)247 _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
248 cairo_content_t content,
249 int width,
250 int height)
251 {
252 cairo_gl_surface_t *surface;
253 GLenum format;
254 GLuint tex;
255
256 glGenTextures (1, &tex);
257 surface = (cairo_gl_surface_t *)
258 _cairo_gl_surface_create_scratch_for_texture (ctx, content,
259 tex, width, height);
260 if (unlikely (surface->base.status))
261 return &surface->base;
262
263 surface->owns_tex = TRUE;
264
265 /* adjust the texture size after setting our real extents */
266 if (width < 1)
267 width = 1;
268 if (height < 1)
269 height = 1;
270
271 switch (content) {
272 default:
273 ASSERT_NOT_REACHED;
274 case CAIRO_CONTENT_COLOR_ALPHA:
275 format = GL_RGBA;
276 break;
277 case CAIRO_CONTENT_ALPHA:
278 /* We want to be trying GL_ALPHA framebuffer objects here. */
279 format = GL_RGBA;
280 break;
281 case CAIRO_CONTENT_COLOR:
282 /* GL_RGB is almost what we want here -- sampling 1 alpha when
283 * texturing, using 1 as destination alpha factor in blending,
284 * etc. However, when filtering with GL_CLAMP_TO_BORDER, the
285 * alpha channel of the border color will also be clamped to
286 * 1, when we actually want the border color we explicitly
287 * specified. So, we have to store RGBA, and fill the alpha
288 * channel with 1 when blending.
289 */
290 format = GL_RGBA;
291 break;
292 }
293
294 glTexImage2D (ctx->tex_target, 0, format, width, height, 0,
295 format, GL_UNSIGNED_BYTE, NULL);
296
297 return &surface->base;
298 }
299
300 static cairo_status_t
_cairo_gl_surface_clear(cairo_gl_surface_t * surface,const cairo_color_t * color)301 _cairo_gl_surface_clear (cairo_gl_surface_t *surface,
302 const cairo_color_t *color)
303 {
304 cairo_gl_context_t *ctx;
305 cairo_status_t status;
306 double r, g, b, a;
307
308 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
309 if (unlikely (status))
310 return status;
311
312 _cairo_gl_context_set_destination (ctx, surface);
313 if (surface->base.content & CAIRO_CONTENT_COLOR) {
314 r = color->red * color->alpha;
315 g = color->green * color->alpha;
316 b = color->blue * color->alpha;
317 } else {
318 r = g = b = 0;
319 }
320 if (surface->base.content & CAIRO_CONTENT_ALPHA) {
321 a = color->alpha;
322 } else {
323 a = 1.0;
324 }
325
326 glDisable (GL_SCISSOR_TEST);
327 glClearColor (r, g, b, a);
328 glClear (GL_COLOR_BUFFER_BIT);
329
330 return _cairo_gl_context_release (ctx, status);
331 }
332
333 cairo_surface_t *
cairo_gl_surface_create(cairo_device_t * abstract_device,cairo_content_t content,int width,int height)334 cairo_gl_surface_create (cairo_device_t *abstract_device,
335 cairo_content_t content,
336 int width,
337 int height)
338 {
339 cairo_gl_context_t *ctx;
340 cairo_gl_surface_t *surface;
341 cairo_status_t status;
342
343 if (! CAIRO_CONTENT_VALID (content))
344 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
345
346 if (abstract_device == NULL) {
347 return cairo_image_surface_create (_cairo_format_from_content (content),
348 width, height);
349 }
350
351 if (abstract_device->status)
352 return _cairo_surface_create_in_error (abstract_device->status);
353
354 if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
355 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
356
357 status = _cairo_gl_context_acquire (abstract_device, &ctx);
358 if (unlikely (status))
359 return _cairo_surface_create_in_error (status);
360
361 surface = (cairo_gl_surface_t *)
362 _cairo_gl_surface_create_scratch (ctx, content, width, height);
363 if (unlikely (surface->base.status)) {
364 status = _cairo_gl_context_release (ctx, surface->base.status);
365 cairo_surface_destroy (&surface->base);
366 return _cairo_surface_create_in_error (status);
367 }
368
369 /* Cairo surfaces start out initialized to transparent (black) */
370 status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
371
372 status = _cairo_gl_context_release (ctx, status);
373 if (unlikely (status)) {
374 cairo_surface_destroy (&surface->base);
375 return _cairo_surface_create_in_error (status);
376 }
377
378 return &surface->base;
379 }
380 slim_hidden_def (cairo_gl_surface_create);
381
382
383 /**
384 * cairo_gl_surface_create_for_texture:
385 * @content: type of content in the surface
386 * @tex: name of texture to use for storage of surface pixels
387 * @width: width of the surface, in pixels
388 * @height: height of the surface, in pixels
389 *
390 * Creates a GL surface for the specified texture with the specified
391 * content and dimensions. The texture must be kept around until the
392 * #cairo_surface_t is destroyed or cairo_surface_finish() is called
393 * on the surface. The initial contents of @tex will be used as the
394 * initial image contents; you must explicitly clear the buffer,
395 * using, for example, cairo_rectangle() and cairo_fill() if you want
396 * it cleared. The format of @tex should be compatible with @content,
397 * in the sense that it must have the color components required by
398 * @content.
399 *
400 * Return value: a pointer to the newly created surface. The caller
401 * owns the surface and should call cairo_surface_destroy() when done
402 * with it.
403 *
404 * This function always returns a valid pointer, but it will return a
405 * pointer to a "nil" surface if an error such as out of memory
406 * occurs. You can use cairo_surface_status() to check for this.
407 **/
408 cairo_surface_t *
cairo_gl_surface_create_for_texture(cairo_device_t * abstract_device,cairo_content_t content,unsigned int tex,int width,int height)409 cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
410 cairo_content_t content,
411 unsigned int tex,
412 int width,
413 int height)
414 {
415 cairo_gl_context_t *ctx;
416 cairo_gl_surface_t *surface;
417 cairo_status_t status;
418
419 if (! CAIRO_CONTENT_VALID (content))
420 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
421
422 if (abstract_device == NULL)
423 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
424
425 if (abstract_device->status)
426 return _cairo_surface_create_in_error (abstract_device->status);
427
428 if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
429 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
430
431 status = _cairo_gl_context_acquire (abstract_device, &ctx);
432 if (unlikely (status))
433 return _cairo_surface_create_in_error (status);
434
435 surface = (cairo_gl_surface_t *)
436 _cairo_gl_surface_create_scratch_for_texture (ctx, content,
437 tex, width, height);
438 status = _cairo_gl_context_release (ctx, status);
439
440 return &surface->base;
441 }
442 slim_hidden_def (cairo_gl_surface_create_for_texture);
443
444
445 void
cairo_gl_surface_set_size(cairo_surface_t * abstract_surface,int width,int height)446 cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
447 int width,
448 int height)
449 {
450 cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
451 cairo_status_t status;
452
453 if (unlikely (abstract_surface->status))
454 return;
455 if (unlikely (abstract_surface->finished)) {
456 status = _cairo_surface_set_error (abstract_surface,
457 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
458 return;
459 }
460
461 if (! _cairo_surface_is_gl (abstract_surface) ||
462 ! _cairo_gl_surface_is_texture (surface)) {
463 status = _cairo_surface_set_error (abstract_surface,
464 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
465 return;
466 }
467
468 surface->width = width;
469 surface->height = height;
470 }
471
472 int
cairo_gl_surface_get_width(cairo_surface_t * abstract_surface)473 cairo_gl_surface_get_width (cairo_surface_t *abstract_surface)
474 {
475 cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
476
477 if (! _cairo_surface_is_gl (abstract_surface))
478 return 0;
479
480 return surface->width;
481 }
482
483 int
cairo_gl_surface_get_height(cairo_surface_t * abstract_surface)484 cairo_gl_surface_get_height (cairo_surface_t *abstract_surface)
485 {
486 cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
487
488 if (! _cairo_surface_is_gl (abstract_surface))
489 return 0;
490
491 return surface->height;
492 }
493
494 void
cairo_gl_surface_swapbuffers(cairo_surface_t * abstract_surface)495 cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
496 {
497 cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
498 cairo_status_t status;
499
500 if (unlikely (abstract_surface->status))
501 return;
502 if (unlikely (abstract_surface->finished)) {
503 status = _cairo_surface_set_error (abstract_surface,
504 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
505 return;
506 }
507
508 if (! _cairo_surface_is_gl (abstract_surface)) {
509 status = _cairo_surface_set_error (abstract_surface,
510 CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
511 return;
512 }
513
514 if (! _cairo_gl_surface_is_texture (surface)) {
515 cairo_gl_context_t *ctx;
516 cairo_status_t status;
517
518 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
519 if (unlikely (status))
520 return;
521
522 cairo_surface_flush (abstract_surface);
523
524 ctx->swap_buffers (ctx, surface);
525
526 status = _cairo_gl_context_release (ctx, status);
527 if (status)
528 status = _cairo_surface_set_error (abstract_surface, status);
529 }
530 }
531
532 static cairo_surface_t *
_cairo_gl_surface_create_similar(void * abstract_surface,cairo_content_t content,int width,int height)533 _cairo_gl_surface_create_similar (void *abstract_surface,
534 cairo_content_t content,
535 int width,
536 int height)
537 {
538 cairo_surface_t *surface = abstract_surface;
539 cairo_gl_context_t *ctx;
540 cairo_status_t status;
541
542 if (width < 1 || height < 1)
543 return cairo_image_surface_create (_cairo_format_from_content (content),
544 width, height);
545
546 status = _cairo_gl_context_acquire (surface->device, &ctx);
547 if (unlikely (status))
548 return _cairo_surface_create_in_error (status);
549
550 if (width > ctx->max_framebuffer_size ||
551 height > ctx->max_framebuffer_size)
552 {
553 surface = NULL;
554 goto RELEASE;
555 }
556
557 surface = _cairo_gl_surface_create_scratch (ctx, content, width, height);
558
559 RELEASE:
560 status = _cairo_gl_context_release (ctx, status);
561 if (unlikely (status)) {
562 cairo_surface_destroy (surface);
563 return _cairo_surface_create_in_error (status);
564 }
565
566 return surface;
567 }
568
569 cairo_status_t
_cairo_gl_surface_draw_image(cairo_gl_surface_t * dst,cairo_image_surface_t * src,int src_x,int src_y,int width,int height,int dst_x,int dst_y)570 _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
571 cairo_image_surface_t *src,
572 int src_x, int src_y,
573 int width, int height,
574 int dst_x, int dst_y)
575 {
576 GLenum internal_format, format, type;
577 cairo_bool_t has_alpha;
578 cairo_image_surface_t *clone = NULL;
579 cairo_gl_context_t *ctx;
580 int cpp;
581 cairo_status_t status = CAIRO_STATUS_SUCCESS;
582
583 if (! _cairo_gl_get_image_format_and_type (src->pixman_format,
584 &internal_format,
585 &format,
586 &type,
587 &has_alpha))
588 {
589 cairo_bool_t is_supported;
590
591 clone = _cairo_image_surface_coerce (src);
592 if (unlikely (clone->base.status))
593 return clone->base.status;
594
595 is_supported =
596 _cairo_gl_get_image_format_and_type (clone->pixman_format,
597 &internal_format,
598 &format,
599 &type,
600 &has_alpha);
601 assert (is_supported);
602 src = clone;
603 }
604
605 cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
606
607 status = _cairo_gl_context_acquire (dst->base.device, &ctx);
608 if (unlikely (status))
609 return status;
610
611 status = _cairo_gl_surface_flush (&dst->base);
612 if (unlikely (status))
613 goto FAIL;
614
615 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
616 glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
617 if (_cairo_gl_surface_is_texture (dst)) {
618 _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
619 glBindTexture (ctx->tex_target, dst->tex);
620 glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
621 glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
622 glTexSubImage2D (ctx->tex_target, 0,
623 dst_x, dst_y, width, height,
624 format, type,
625 src->data + src_y * src->stride + src_x * cpp);
626
627 /* If we just treated some rgb-only data as rgba, then we have to
628 * go back and fix up the alpha channel where we filled in this
629 * texture data.
630 */
631 if (!has_alpha) {
632 cairo_rectangle_int_t rect;
633
634 rect.x = dst_x;
635 rect.y = dst_y;
636 rect.width = width;
637 rect.height = height;
638
639 _cairo_gl_composite_flush (ctx);
640 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
641 _cairo_gl_surface_fill_rectangles (dst,
642 CAIRO_OPERATOR_SOURCE,
643 CAIRO_COLOR_BLACK,
644 &rect, 1);
645 _cairo_gl_composite_flush (ctx);
646 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
647 }
648 } else {
649 cairo_surface_t *tmp;
650
651 tmp = _cairo_gl_surface_create_scratch (ctx,
652 dst->base.content,
653 width, height);
654 if (unlikely (tmp->status)) {
655 cairo_surface_destroy (tmp);
656 goto FAIL;
657 }
658 status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *) tmp,
659 src,
660 src_x, src_y,
661 width, height,
662 0, 0);
663 if (status == CAIRO_STATUS_SUCCESS) {
664 cairo_surface_pattern_t tmp_pattern;
665
666 _cairo_pattern_init_for_surface (&tmp_pattern, tmp);
667 _cairo_gl_surface_composite (CAIRO_OPERATOR_SOURCE,
668 &tmp_pattern.base,
669 NULL,
670 dst,
671 0, 0,
672 0, 0,
673 dst_x, dst_y,
674 width, height,
675 NULL);
676 _cairo_pattern_fini (&tmp_pattern.base);
677 }
678
679 cairo_surface_destroy (tmp);
680 }
681
682 FAIL:
683 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
684
685 status = _cairo_gl_context_release (ctx, status);
686
687 if (clone)
688 cairo_surface_destroy (&clone->base);
689
690 return status;
691 }
692
693 static cairo_status_t
_cairo_gl_surface_get_image(cairo_gl_surface_t * surface,cairo_rectangle_int_t * interest,cairo_image_surface_t ** image_out,cairo_rectangle_int_t * rect_out)694 _cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
695 cairo_rectangle_int_t *interest,
696 cairo_image_surface_t **image_out,
697 cairo_rectangle_int_t *rect_out)
698 {
699 cairo_image_surface_t *image;
700 cairo_gl_context_t *ctx;
701 GLenum format, type;
702 cairo_format_t cairo_format;
703 unsigned int cpp;
704 cairo_status_t status;
705
706 /* Want to use a switch statement here but the compiler gets whiny. */
707 if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
708 format = GL_BGRA;
709 cairo_format = CAIRO_FORMAT_ARGB32;
710 type = GL_UNSIGNED_INT_8_8_8_8_REV;
711 cpp = 4;
712 } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
713 format = GL_BGRA;
714 cairo_format = CAIRO_FORMAT_RGB24;
715 type = GL_UNSIGNED_INT_8_8_8_8_REV;
716 cpp = 4;
717 } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
718 format = GL_ALPHA;
719 cairo_format = CAIRO_FORMAT_A8;
720 type = GL_UNSIGNED_BYTE;
721 cpp = 1;
722 } else {
723 ASSERT_NOT_REACHED;
724 return CAIRO_INT_STATUS_UNSUPPORTED;
725 }
726
727 image = (cairo_image_surface_t*)
728 cairo_image_surface_create (cairo_format,
729 interest->width, interest->height);
730 if (unlikely (image->base.status))
731 return image->base.status;
732
733 /* This is inefficient, as we'd rather just read the thing without making
734 * it the destination. But then, this is the fallback path, so let's not
735 * fall back instead.
736 */
737 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
738 if (unlikely (status))
739 return status;
740
741 _cairo_gl_composite_flush (ctx);
742 _cairo_gl_context_set_destination (ctx, surface);
743
744 glPixelStorei (GL_PACK_ALIGNMENT, 1);
745 glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
746 if (! _cairo_gl_surface_is_texture (surface) && GLEW_MESA_pack_invert)
747 glPixelStorei (GL_PACK_INVERT_MESA, 1);
748 glReadPixels (interest->x, interest->y,
749 interest->width, interest->height,
750 format, type, image->data);
751 if (! _cairo_gl_surface_is_texture (surface) && GLEW_MESA_pack_invert)
752 glPixelStorei (GL_PACK_INVERT_MESA, 0);
753
754 status = _cairo_gl_context_release (ctx, status);
755 if (unlikely (status)) {
756 cairo_surface_destroy (&image->base);
757 return status;
758 }
759
760 *image_out = image;
761 if (rect_out != NULL)
762 *rect_out = *interest;
763
764 return CAIRO_STATUS_SUCCESS;
765 }
766
767 static cairo_status_t
_cairo_gl_surface_finish(void * abstract_surface)768 _cairo_gl_surface_finish (void *abstract_surface)
769 {
770 cairo_gl_surface_t *surface = abstract_surface;
771 cairo_status_t status;
772 cairo_gl_context_t *ctx;
773
774 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
775 if (unlikely (status))
776 return status;
777
778 if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
779 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
780 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
781 if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
782 ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
783 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
784 if (ctx->current_target == surface)
785 ctx->current_target = NULL;
786
787 if (surface->depth)
788 glDeleteFramebuffersEXT (1, &surface->depth);
789 if (surface->fb)
790 glDeleteFramebuffersEXT (1, &surface->fb);
791 if (surface->owns_tex)
792 glDeleteTextures (1, &surface->tex);
793
794 return _cairo_gl_context_release (ctx, status);
795 }
796
797 static cairo_status_t
_cairo_gl_surface_acquire_source_image(void * abstract_surface,cairo_image_surface_t ** image_out,void ** image_extra)798 _cairo_gl_surface_acquire_source_image (void *abstract_surface,
799 cairo_image_surface_t **image_out,
800 void **image_extra)
801 {
802 cairo_gl_surface_t *surface = abstract_surface;
803 cairo_rectangle_int_t extents;
804
805 *image_extra = NULL;
806
807 extents.x = extents.y = 0;
808 extents.width = surface->width;
809 extents.height = surface->height;
810 return _cairo_gl_surface_get_image (surface, &extents, image_out, NULL);
811 }
812
813 static void
_cairo_gl_surface_release_source_image(void * abstract_surface,cairo_image_surface_t * image,void * image_extra)814 _cairo_gl_surface_release_source_image (void *abstract_surface,
815 cairo_image_surface_t *image,
816 void *image_extra)
817 {
818 cairo_surface_destroy (&image->base);
819 }
820
821 static cairo_status_t
_cairo_gl_surface_acquire_dest_image(void * abstract_surface,cairo_rectangle_int_t * interest_rect,cairo_image_surface_t ** image_out,cairo_rectangle_int_t * image_rect_out,void ** image_extra)822 _cairo_gl_surface_acquire_dest_image (void *abstract_surface,
823 cairo_rectangle_int_t *interest_rect,
824 cairo_image_surface_t **image_out,
825 cairo_rectangle_int_t *image_rect_out,
826 void **image_extra)
827 {
828 cairo_gl_surface_t *surface = abstract_surface;
829
830 *image_extra = NULL;
831 return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
832 image_rect_out);
833 }
834
835 static void
_cairo_gl_surface_release_dest_image(void * abstract_surface,cairo_rectangle_int_t * interest_rect,cairo_image_surface_t * image,cairo_rectangle_int_t * image_rect,void * image_extra)836 _cairo_gl_surface_release_dest_image (void *abstract_surface,
837 cairo_rectangle_int_t *interest_rect,
838 cairo_image_surface_t *image,
839 cairo_rectangle_int_t *image_rect,
840 void *image_extra)
841 {
842 cairo_status_t status;
843
844 status = _cairo_gl_surface_draw_image (abstract_surface, image,
845 0, 0,
846 image->width, image->height,
847 image_rect->x, image_rect->y);
848 /* as we created the image, its format should be directly applicable */
849 assert (status == CAIRO_STATUS_SUCCESS);
850
851 cairo_surface_destroy (&image->base);
852 }
853
854 static cairo_status_t
_cairo_gl_surface_clone_similar(void * abstract_surface,cairo_surface_t * src,int src_x,int src_y,int width,int height,int * clone_offset_x,int * clone_offset_y,cairo_surface_t ** clone_out)855 _cairo_gl_surface_clone_similar (void *abstract_surface,
856 cairo_surface_t *src,
857 int src_x,
858 int src_y,
859 int width,
860 int height,
861 int *clone_offset_x,
862 int *clone_offset_y,
863 cairo_surface_t **clone_out)
864 {
865 cairo_gl_surface_t *surface = abstract_surface;
866
867 /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */
868 if (src->device == surface->base.device &&
869 _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) {
870 *clone_offset_x = 0;
871 *clone_offset_y = 0;
872 *clone_out = cairo_surface_reference (src);
873
874 return CAIRO_STATUS_SUCCESS;
875 } else if (_cairo_surface_is_image (src)) {
876 cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
877 cairo_gl_surface_t *clone;
878 cairo_status_t status;
879
880 clone = (cairo_gl_surface_t *)
881 _cairo_gl_surface_create_similar (&surface->base,
882 src->content,
883 width, height);
884 if (clone == NULL)
885 return UNSUPPORTED ("create_similar failed");
886 if (clone->base.status)
887 return clone->base.status;
888
889 status = _cairo_gl_surface_draw_image (clone, image_src,
890 src_x, src_y,
891 width, height,
892 0, 0);
893 if (status) {
894 cairo_surface_destroy (&clone->base);
895 return status;
896 }
897
898 *clone_out = &clone->base;
899 *clone_offset_x = src_x;
900 *clone_offset_y = src_y;
901
902 return CAIRO_STATUS_SUCCESS;
903 }
904
905 return UNSUPPORTED ("unknown src surface type in clone_similar");
906 }
907
908 /** Creates a cairo-gl pattern surface for the given trapezoids */
909 static cairo_status_t
_cairo_gl_get_traps_pattern(cairo_gl_surface_t * dst,int dst_x,int dst_y,int width,int height,cairo_trapezoid_t * traps,int num_traps,cairo_antialias_t antialias,cairo_surface_pattern_t * pattern)910 _cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
911 int dst_x, int dst_y,
912 int width, int height,
913 cairo_trapezoid_t *traps,
914 int num_traps,
915 cairo_antialias_t antialias,
916 cairo_surface_pattern_t *pattern)
917 {
918 pixman_format_code_t pixman_format;
919 pixman_image_t *image;
920 cairo_surface_t *surface;
921 int i;
922
923 pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
924 image = pixman_image_create_bits (pixman_format, width, height, NULL, 0);
925 if (unlikely (image == NULL))
926 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
927
928 for (i = 0; i < num_traps; i++) {
929 pixman_trapezoid_t trap;
930
931 trap.top = _cairo_fixed_to_16_16 (traps[i].top);
932 trap.bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
933
934 trap.left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
935 trap.left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
936 trap.left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
937 trap.left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
938
939 trap.right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
940 trap.right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
941 trap.right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
942 trap.right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
943
944 pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
945 }
946
947 surface = _cairo_image_surface_create_for_pixman_image (image,
948 pixman_format);
949 if (unlikely (surface->status)) {
950 pixman_image_unref (image);
951 return surface->status;
952 }
953
954 _cairo_pattern_init_for_surface (pattern, surface);
955 cairo_surface_destroy (surface);
956
957 return CAIRO_STATUS_SUCCESS;
958 }
959
960 static cairo_int_status_t
_cairo_gl_surface_composite(cairo_operator_t op,const cairo_pattern_t * src,const cairo_pattern_t * mask,void * abstract_dst,int src_x,int src_y,int mask_x,int mask_y,int dst_x,int dst_y,unsigned int width,unsigned int height,cairo_region_t * clip_region)961 _cairo_gl_surface_composite (cairo_operator_t op,
962 const cairo_pattern_t *src,
963 const cairo_pattern_t *mask,
964 void *abstract_dst,
965 int src_x,
966 int src_y,
967 int mask_x,
968 int mask_y,
969 int dst_x,
970 int dst_y,
971 unsigned int width,
972 unsigned int height,
973 cairo_region_t *clip_region)
974 {
975 cairo_gl_surface_t *dst = abstract_dst;
976 cairo_gl_context_t *ctx;
977 cairo_status_t status;
978 cairo_gl_composite_t setup;
979 cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
980 int dx, dy;
981
982 if (op == CAIRO_OPERATOR_SOURCE &&
983 mask == NULL &&
984 src->type == CAIRO_PATTERN_TYPE_SURFACE &&
985 _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) &&
986 _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) {
987 cairo_image_surface_t *image = (cairo_image_surface_t *)
988 ((cairo_surface_pattern_t *) src)->surface;
989 dx += src_x;
990 dy += src_y;
991 if (dx >= 0 &&
992 dy >= 0 &&
993 dx + width <= (unsigned int) image->width &&
994 dy + height <= (unsigned int) image->height) {
995 status = _cairo_gl_surface_draw_image (dst, image,
996 dx, dy,
997 width, height,
998 dst_x, dst_y);
999 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1000 return status;
1001 }
1002 }
1003
1004 status = _cairo_gl_composite_init (&setup, op, dst,
1005 mask && mask->has_component_alpha,
1006 &rect);
1007 if (unlikely (status))
1008 goto CLEANUP;
1009
1010 status = _cairo_gl_composite_set_source (&setup, src,
1011 src_x, src_y,
1012 dst_x, dst_y,
1013 width, height);
1014 if (unlikely (status))
1015 goto CLEANUP;
1016
1017 status = _cairo_gl_composite_set_mask (&setup, mask,
1018 mask_x, mask_y,
1019 dst_x, dst_y,
1020 width, height);
1021 if (unlikely (status))
1022 goto CLEANUP;
1023
1024 status = _cairo_gl_composite_begin (&setup, &ctx);
1025 if (unlikely (status))
1026 goto CLEANUP;
1027
1028 if (clip_region != NULL) {
1029 int i, num_rectangles;
1030
1031 num_rectangles = cairo_region_num_rectangles (clip_region);
1032
1033 for (i = 0; i < num_rectangles; i++) {
1034 cairo_rectangle_int_t rect;
1035
1036 cairo_region_get_rectangle (clip_region, i, &rect);
1037 _cairo_gl_composite_emit_rect (ctx,
1038 rect.x, rect.y,
1039 rect.x + rect.width, rect.y + rect.height,
1040 0);
1041 }
1042 } else {
1043 _cairo_gl_composite_emit_rect (ctx,
1044 dst_x, dst_y,
1045 dst_x + width, dst_y + height,
1046 0);
1047 }
1048
1049 status = _cairo_gl_context_release (ctx, status);
1050
1051 CLEANUP:
1052 _cairo_gl_composite_fini (&setup);
1053
1054 return status;
1055 }
1056
1057 static cairo_int_status_t
_cairo_gl_surface_composite_trapezoids(cairo_operator_t op,const cairo_pattern_t * pattern,void * abstract_dst,cairo_antialias_t antialias,int src_x,int src_y,int dst_x,int dst_y,unsigned int width,unsigned int height,cairo_trapezoid_t * traps,int num_traps,cairo_region_t * clip_region)1058 _cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
1059 const cairo_pattern_t *pattern,
1060 void *abstract_dst,
1061 cairo_antialias_t antialias,
1062 int src_x, int src_y,
1063 int dst_x, int dst_y,
1064 unsigned int width,
1065 unsigned int height,
1066 cairo_trapezoid_t *traps,
1067 int num_traps,
1068 cairo_region_t *clip_region)
1069 {
1070 cairo_gl_surface_t *dst = abstract_dst;
1071 cairo_surface_pattern_t traps_pattern;
1072 cairo_int_status_t status;
1073
1074 if (! _cairo_gl_operator_is_supported (op))
1075 return UNSUPPORTED ("unsupported operator");
1076
1077 status = _cairo_gl_get_traps_pattern (dst,
1078 dst_x, dst_y, width, height,
1079 traps, num_traps, antialias,
1080 &traps_pattern);
1081 if (unlikely (status))
1082 return status;
1083
1084 status = _cairo_gl_surface_composite (op,
1085 pattern, &traps_pattern.base, dst,
1086 src_x, src_y,
1087 0, 0,
1088 dst_x, dst_y,
1089 width, height,
1090 clip_region);
1091
1092 _cairo_pattern_fini (&traps_pattern.base);
1093
1094 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
1095 return status;
1096 }
1097
1098 static cairo_int_status_t
_cairo_gl_surface_fill_rectangles(void * abstract_dst,cairo_operator_t op,const cairo_color_t * color,cairo_rectangle_int_t * rects,int num_rects)1099 _cairo_gl_surface_fill_rectangles (void *abstract_dst,
1100 cairo_operator_t op,
1101 const cairo_color_t *color,
1102 cairo_rectangle_int_t *rects,
1103 int num_rects)
1104 {
1105 cairo_gl_surface_t *dst = abstract_dst;
1106 cairo_solid_pattern_t solid;
1107 cairo_gl_context_t *ctx;
1108 cairo_status_t status;
1109 cairo_gl_composite_t setup;
1110 int i;
1111
1112 status = _cairo_gl_composite_init (&setup, op, dst,
1113 FALSE,
1114 /* XXX */ NULL);
1115 if (unlikely (status))
1116 goto CLEANUP;
1117
1118 _cairo_pattern_init_solid (&solid, color);
1119 status = _cairo_gl_composite_set_source (&setup, &solid.base,
1120 0, 0,
1121 0, 0,
1122 0, 0);
1123 if (unlikely (status))
1124 goto CLEANUP;
1125
1126 status = _cairo_gl_composite_set_mask (&setup, NULL,
1127 0, 0,
1128 0, 0,
1129 0, 0);
1130 if (unlikely (status))
1131 goto CLEANUP;
1132
1133 status = _cairo_gl_composite_begin (&setup, &ctx);
1134 if (unlikely (status))
1135 goto CLEANUP;
1136
1137 for (i = 0; i < num_rects; i++) {
1138 _cairo_gl_composite_emit_rect (ctx,
1139 rects[i].x,
1140 rects[i].y,
1141 rects[i].x + rects[i].width,
1142 rects[i].y + rects[i].height,
1143 0);
1144 }
1145
1146 status = _cairo_gl_context_release (ctx, status);
1147
1148 CLEANUP:
1149 _cairo_gl_composite_fini (&setup);
1150
1151 return status;
1152 }
1153
1154 typedef struct _cairo_gl_surface_span_renderer {
1155 cairo_span_renderer_t base;
1156
1157 cairo_gl_composite_t setup;
1158
1159 int xmin, xmax;
1160 int ymin, ymax;
1161
1162 cairo_gl_context_t *ctx;
1163 } cairo_gl_surface_span_renderer_t;
1164
1165 static cairo_status_t
_cairo_gl_render_bounded_spans(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * spans,unsigned num_spans)1166 _cairo_gl_render_bounded_spans (void *abstract_renderer,
1167 int y, int height,
1168 const cairo_half_open_span_t *spans,
1169 unsigned num_spans)
1170 {
1171 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1172
1173 if (num_spans == 0)
1174 return CAIRO_STATUS_SUCCESS;
1175
1176 do {
1177 if (spans[0].coverage) {
1178 _cairo_gl_composite_emit_rect (renderer->ctx,
1179 spans[0].x, y,
1180 spans[1].x, y + height,
1181 spans[0].coverage);
1182 }
1183
1184 spans++;
1185 } while (--num_spans > 1);
1186
1187 return CAIRO_STATUS_SUCCESS;
1188 }
1189
1190 static cairo_status_t
_cairo_gl_render_unbounded_spans(void * abstract_renderer,int y,int height,const cairo_half_open_span_t * spans,unsigned num_spans)1191 _cairo_gl_render_unbounded_spans (void *abstract_renderer,
1192 int y, int height,
1193 const cairo_half_open_span_t *spans,
1194 unsigned num_spans)
1195 {
1196 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1197
1198 if (y > renderer->ymin) {
1199 _cairo_gl_composite_emit_rect (renderer->ctx,
1200 renderer->xmin, renderer->ymin,
1201 renderer->xmax, y,
1202 0);
1203 }
1204
1205 if (num_spans == 0) {
1206 _cairo_gl_composite_emit_rect (renderer->ctx,
1207 renderer->xmin, y,
1208 renderer->xmax, y + height,
1209 0);
1210 } else {
1211 if (spans[0].x != renderer->xmin) {
1212 _cairo_gl_composite_emit_rect (renderer->ctx,
1213 renderer->xmin, y,
1214 spans[0].x, y + height,
1215 0);
1216 }
1217
1218 do {
1219 _cairo_gl_composite_emit_rect (renderer->ctx,
1220 spans[0].x, y,
1221 spans[1].x, y + height,
1222 spans[0].coverage);
1223 spans++;
1224 } while (--num_spans > 1);
1225
1226 if (spans[0].x != renderer->xmax) {
1227 _cairo_gl_composite_emit_rect (renderer->ctx,
1228 spans[0].x, y,
1229 renderer->xmax, y + height,
1230 0);
1231 }
1232 }
1233
1234 renderer->ymin = y + height;
1235 return CAIRO_STATUS_SUCCESS;
1236 }
1237
1238 static cairo_status_t
_cairo_gl_finish_unbounded_spans(void * abstract_renderer)1239 _cairo_gl_finish_unbounded_spans (void *abstract_renderer)
1240 {
1241 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1242
1243 if (renderer->ymax > renderer->ymin) {
1244 _cairo_gl_composite_emit_rect (renderer->ctx,
1245 renderer->xmin, renderer->ymin,
1246 renderer->xmax, renderer->ymax,
1247 0);
1248 }
1249
1250 return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
1251 }
1252
1253 static cairo_status_t
_cairo_gl_finish_bounded_spans(void * abstract_renderer)1254 _cairo_gl_finish_bounded_spans (void *abstract_renderer)
1255 {
1256 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1257
1258 return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
1259 }
1260
1261 static void
_cairo_gl_surface_span_renderer_destroy(void * abstract_renderer)1262 _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
1263 {
1264 cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
1265
1266 if (!renderer)
1267 return;
1268
1269 _cairo_gl_composite_fini (&renderer->setup);
1270
1271 free (renderer);
1272 }
1273
1274 static cairo_bool_t
_cairo_gl_surface_check_span_renderer(cairo_operator_t op,const cairo_pattern_t * pattern,void * abstract_dst,cairo_antialias_t antialias)1275 _cairo_gl_surface_check_span_renderer (cairo_operator_t op,
1276 const cairo_pattern_t *pattern,
1277 void *abstract_dst,
1278 cairo_antialias_t antialias)
1279 {
1280 if (! _cairo_gl_operator_is_supported (op))
1281 return FALSE;
1282
1283 return TRUE;
1284
1285 (void) pattern;
1286 (void) abstract_dst;
1287 (void) antialias;
1288 }
1289
1290 static cairo_span_renderer_t *
_cairo_gl_surface_create_span_renderer(cairo_operator_t op,const cairo_pattern_t * src,void * abstract_dst,cairo_antialias_t antialias,const cairo_composite_rectangles_t * rects,cairo_region_t * clip_region)1291 _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
1292 const cairo_pattern_t *src,
1293 void *abstract_dst,
1294 cairo_antialias_t antialias,
1295 const cairo_composite_rectangles_t *rects,
1296 cairo_region_t *clip_region)
1297 {
1298 cairo_gl_surface_t *dst = abstract_dst;
1299 cairo_gl_surface_span_renderer_t *renderer;
1300 cairo_status_t status;
1301 const cairo_rectangle_int_t *extents;
1302
1303 renderer = calloc (1, sizeof (*renderer));
1304 if (unlikely (renderer == NULL))
1305 return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
1306
1307 renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
1308 if (rects->is_bounded) {
1309 renderer->base.render_rows = _cairo_gl_render_bounded_spans;
1310 renderer->base.finish = _cairo_gl_finish_bounded_spans;
1311 extents = &rects->bounded;
1312 } else {
1313 renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
1314 renderer->base.finish = _cairo_gl_finish_unbounded_spans;
1315 extents = &rects->unbounded;
1316 }
1317 renderer->xmin = extents->x;
1318 renderer->xmax = extents->x + extents->width;
1319 renderer->ymin = extents->y;
1320 renderer->ymax = extents->y + extents->height;
1321
1322 status = _cairo_gl_composite_init (&renderer->setup,
1323 op, dst,
1324 FALSE, extents);
1325 if (unlikely (status))
1326 goto FAIL;
1327
1328 status = _cairo_gl_composite_set_source (&renderer->setup, src,
1329 extents->x, extents->y,
1330 extents->x, extents->y,
1331 extents->width, extents->height);
1332 if (unlikely (status))
1333 goto FAIL;
1334
1335 _cairo_gl_composite_set_mask_spans (&renderer->setup);
1336 _cairo_gl_composite_set_clip_region (&renderer->setup, clip_region);
1337
1338 status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx);
1339 if (unlikely (status))
1340 goto FAIL;
1341
1342 return &renderer->base;
1343
1344 FAIL:
1345 _cairo_gl_composite_fini (&renderer->setup);
1346 free (renderer);
1347 return _cairo_span_renderer_create_in_error (status);
1348 }
1349
1350 static cairo_bool_t
_cairo_gl_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * rectangle)1351 _cairo_gl_surface_get_extents (void *abstract_surface,
1352 cairo_rectangle_int_t *rectangle)
1353 {
1354 cairo_gl_surface_t *surface = abstract_surface;
1355
1356 rectangle->x = 0;
1357 rectangle->y = 0;
1358 rectangle->width = surface->width;
1359 rectangle->height = surface->height;
1360
1361 return TRUE;
1362 }
1363
1364 static void
_cairo_gl_surface_get_font_options(void * abstract_surface,cairo_font_options_t * options)1365 _cairo_gl_surface_get_font_options (void *abstract_surface,
1366 cairo_font_options_t *options)
1367 {
1368 _cairo_font_options_init_default (options);
1369
1370 cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
1371 _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
1372 }
1373
1374 static cairo_status_t
_cairo_gl_surface_flush(void * abstract_surface)1375 _cairo_gl_surface_flush (void *abstract_surface)
1376 {
1377 cairo_gl_surface_t *surface = abstract_surface;
1378 cairo_status_t status;
1379 cairo_gl_context_t *ctx;
1380
1381 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
1382 if (unlikely (status))
1383 return status;
1384
1385 if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
1386 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) ||
1387 (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
1388 ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) ||
1389 (ctx->current_target == surface))
1390 _cairo_gl_composite_flush (ctx);
1391
1392 return _cairo_gl_context_release (ctx, status);
1393 }
1394
1395 static cairo_int_status_t
_cairo_gl_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_clip_t * clip)1396 _cairo_gl_surface_paint (void *abstract_surface,
1397 cairo_operator_t op,
1398 const cairo_pattern_t *source,
1399 cairo_clip_t *clip)
1400 {
1401 /* simplify the common case of clearing the surface */
1402 if (clip == NULL) {
1403 if (op == CAIRO_OPERATOR_CLEAR)
1404 return _cairo_gl_surface_clear (abstract_surface, CAIRO_COLOR_TRANSPARENT);
1405 else if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
1406 (op == CAIRO_OPERATOR_SOURCE ||
1407 (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque_solid (source)))) {
1408 return _cairo_gl_surface_clear (abstract_surface,
1409 &((cairo_solid_pattern_t *) source)->color);
1410 }
1411 }
1412
1413 return CAIRO_INT_STATUS_UNSUPPORTED;
1414 }
1415
1416 static cairo_int_status_t
_cairo_gl_surface_polygon(cairo_gl_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * src,cairo_polygon_t * polygon,cairo_fill_rule_t fill_rule,cairo_antialias_t antialias,const cairo_composite_rectangles_t * extents,cairo_clip_t * clip)1417 _cairo_gl_surface_polygon (cairo_gl_surface_t *dst,
1418 cairo_operator_t op,
1419 const cairo_pattern_t *src,
1420 cairo_polygon_t *polygon,
1421 cairo_fill_rule_t fill_rule,
1422 cairo_antialias_t antialias,
1423 const cairo_composite_rectangles_t *extents,
1424 cairo_clip_t *clip)
1425 {
1426 cairo_status_t status;
1427 cairo_region_t *clip_region = NULL;
1428
1429 if (clip != NULL) {
1430 status = _cairo_clip_get_region (clip, &clip_region);
1431 if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
1432 return CAIRO_STATUS_SUCCESS;
1433 if (unlikely (_cairo_status_is_error (status)))
1434 return status;
1435
1436 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
1437 return UNSUPPORTED ("a clip surface would be required");
1438 }
1439
1440 if (! _cairo_surface_check_span_renderer (op, src, &dst->base, antialias))
1441 return UNSUPPORTED ("no span renderer");
1442
1443 if (op == CAIRO_OPERATOR_SOURCE)
1444 return UNSUPPORTED ("SOURCE compositing doesn't work in GL");
1445 if (op == CAIRO_OPERATOR_CLEAR) {
1446 op = CAIRO_OPERATOR_DEST_OUT;
1447 src = &_cairo_pattern_white.base;
1448 }
1449
1450 status = _cairo_surface_composite_polygon (&dst->base,
1451 op,
1452 src,
1453 fill_rule,
1454 antialias,
1455 extents,
1456 polygon,
1457 clip_region);
1458 return status;
1459 }
1460
1461 static cairo_int_status_t
_cairo_gl_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,const cairo_stroke_style_t * style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)1462 _cairo_gl_surface_stroke (void *abstract_surface,
1463 cairo_operator_t op,
1464 const cairo_pattern_t *source,
1465 cairo_path_fixed_t *path,
1466 const cairo_stroke_style_t *style,
1467 const cairo_matrix_t *ctm,
1468 const cairo_matrix_t *ctm_inverse,
1469 double tolerance,
1470 cairo_antialias_t antialias,
1471 cairo_clip_t *clip)
1472 {
1473 cairo_gl_surface_t *surface = abstract_surface;
1474 cairo_composite_rectangles_t extents;
1475 cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1476 int num_boxes = ARRAY_LENGTH (boxes_stack);
1477 cairo_clip_t local_clip;
1478 cairo_bool_t have_clip = FALSE;
1479 cairo_polygon_t polygon;
1480 cairo_status_t status;
1481
1482 status = _cairo_composite_rectangles_init_for_stroke (&extents,
1483 surface->width,
1484 surface->height,
1485 op, source,
1486 path, style, ctm,
1487 clip);
1488 if (unlikely (status))
1489 return status;
1490
1491 if (_cairo_clip_contains_extents (clip, &extents))
1492 clip = NULL;
1493
1494 if (clip != NULL) {
1495 clip = _cairo_clip_init_copy (&local_clip, clip);
1496 have_clip = TRUE;
1497 }
1498
1499 status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1500 if (unlikely (status)) {
1501 if (have_clip)
1502 _cairo_clip_fini (&local_clip);
1503
1504 return status;
1505 }
1506
1507 _cairo_polygon_init (&polygon);
1508 _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1509
1510 status = _cairo_path_fixed_stroke_to_polygon (path,
1511 style,
1512 ctm, ctm_inverse,
1513 tolerance,
1514 &polygon);
1515 if (likely (status == CAIRO_STATUS_SUCCESS)) {
1516 status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
1517 CAIRO_FILL_RULE_WINDING, antialias,
1518 &extents, clip);
1519 }
1520
1521 _cairo_polygon_fini (&polygon);
1522
1523 if (have_clip)
1524 _cairo_clip_fini (&local_clip);
1525
1526 return status;
1527 }
1528
1529 static cairo_int_status_t
_cairo_gl_surface_fill(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)1530 _cairo_gl_surface_fill (void *abstract_surface,
1531 cairo_operator_t op,
1532 const cairo_pattern_t *source,
1533 cairo_path_fixed_t *path,
1534 cairo_fill_rule_t fill_rule,
1535 double tolerance,
1536 cairo_antialias_t antialias,
1537 cairo_clip_t *clip)
1538 {
1539 cairo_gl_surface_t *surface = abstract_surface;
1540 cairo_composite_rectangles_t extents;
1541 cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1542 cairo_clip_t local_clip;
1543 cairo_bool_t have_clip = FALSE;
1544 int num_boxes = ARRAY_LENGTH (boxes_stack);
1545 cairo_polygon_t polygon;
1546 cairo_status_t status;
1547
1548 status = _cairo_composite_rectangles_init_for_fill (&extents,
1549 surface->width,
1550 surface->height,
1551 op, source, path,
1552 clip);
1553 if (unlikely (status))
1554 return status;
1555
1556 if (_cairo_clip_contains_extents (clip, &extents))
1557 clip = NULL;
1558
1559 #if 0
1560 if (extents.is_bounded && clip != NULL) {
1561 cairo_clip_path_t *clip_path;
1562
1563 if (((clip_path = _clip_get_single_path (clip)) != NULL) &&
1564 _cairo_path_fixed_equal (&clip_path->path, path))
1565 {
1566 clip = NULL;
1567 }
1568 }
1569 #endif
1570
1571 if (clip != NULL) {
1572 clip = _cairo_clip_init_copy (&local_clip, clip);
1573 have_clip = TRUE;
1574 }
1575
1576 status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1577 if (unlikely (status)) {
1578 if (have_clip)
1579 _cairo_clip_fini (&local_clip);
1580
1581 return status;
1582 }
1583
1584 _cairo_polygon_init (&polygon);
1585 _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1586
1587 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1588 if (likely (status == CAIRO_STATUS_SUCCESS)) {
1589 status = _cairo_gl_surface_polygon (surface, op, source, &polygon,
1590 fill_rule, antialias,
1591 &extents, clip);
1592 }
1593
1594 _cairo_polygon_fini (&polygon);
1595
1596 if (clip_boxes != boxes_stack)
1597 free (clip_boxes);
1598
1599 if (have_clip)
1600 _cairo_clip_fini (&local_clip);
1601
1602 return status;
1603 }
1604
1605 const cairo_surface_backend_t _cairo_gl_surface_backend = {
1606 CAIRO_SURFACE_TYPE_GL,
1607 _cairo_gl_surface_create_similar,
1608 _cairo_gl_surface_finish,
1609
1610 _cairo_gl_surface_acquire_source_image,
1611 _cairo_gl_surface_release_source_image,
1612 _cairo_gl_surface_acquire_dest_image,
1613 _cairo_gl_surface_release_dest_image,
1614
1615 _cairo_gl_surface_clone_similar,
1616 _cairo_gl_surface_composite,
1617 _cairo_gl_surface_fill_rectangles,
1618 _cairo_gl_surface_composite_trapezoids,
1619 _cairo_gl_surface_create_span_renderer,
1620 _cairo_gl_surface_check_span_renderer,
1621
1622 NULL, /* copy_page */
1623 NULL, /* show_page */
1624 _cairo_gl_surface_get_extents,
1625 NULL, /* old_show_glyphs */
1626 _cairo_gl_surface_get_font_options,
1627 _cairo_gl_surface_flush,
1628 NULL, /* mark_dirty_rectangle */
1629 _cairo_gl_surface_scaled_font_fini,
1630 _cairo_gl_surface_scaled_glyph_fini,
1631 _cairo_gl_surface_paint,
1632 NULL, /* mask */
1633 _cairo_gl_surface_stroke,
1634 _cairo_gl_surface_fill,
1635 _cairo_gl_surface_show_glyphs, /* show_glyphs */
1636 NULL /* snapshot */
1637 };
1638