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-gl-private.h"
44
45 #include "cairo-composite-rectangles-private.h"
46 #include "cairo-compositor-private.h"
47 #include "cairo-default-context-private.h"
48 #include "cairo-error-private.h"
49 #include "cairo-image-surface-inline.h"
50 #include "cairo-surface-backend-private.h"
51
52 static const cairo_surface_backend_t _cairo_gl_surface_backend;
53
54 static cairo_status_t
55 _cairo_gl_surface_flush (void *abstract_surface, unsigned flags);
56
_cairo_surface_is_gl(cairo_surface_t * surface)57 static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
58 {
59 return surface->backend == &_cairo_gl_surface_backend;
60 }
61
62 static cairo_bool_t
_cairo_gl_get_image_format_and_type_gles2(pixman_format_code_t pixman_format,GLenum * internal_format,GLenum * format,GLenum * type,cairo_bool_t * has_alpha,cairo_bool_t * needs_swap)63 _cairo_gl_get_image_format_and_type_gles2 (pixman_format_code_t pixman_format,
64 GLenum *internal_format, GLenum *format,
65 GLenum *type, cairo_bool_t *has_alpha,
66 cairo_bool_t *needs_swap)
67 {
68 cairo_bool_t is_little_endian = _cairo_is_little_endian ();
69
70 *has_alpha = TRUE;
71
72 switch ((int) pixman_format) {
73 case PIXMAN_a8r8g8b8:
74 *internal_format = GL_BGRA;
75 *format = GL_BGRA;
76 *type = GL_UNSIGNED_BYTE;
77 *needs_swap = !is_little_endian;
78 return TRUE;
79
80 case PIXMAN_x8r8g8b8:
81 *internal_format = GL_BGRA;
82 *format = GL_BGRA;
83 *type = GL_UNSIGNED_BYTE;
84 *has_alpha = FALSE;
85 *needs_swap = !is_little_endian;
86 return TRUE;
87
88 case PIXMAN_a8b8g8r8:
89 *internal_format = GL_RGBA;
90 *format = GL_RGBA;
91 *type = GL_UNSIGNED_BYTE;
92 *needs_swap = !is_little_endian;
93 return TRUE;
94
95 case PIXMAN_x8b8g8r8:
96 *internal_format = GL_RGBA;
97 *format = GL_RGBA;
98 *type = GL_UNSIGNED_BYTE;
99 *has_alpha = FALSE;
100 *needs_swap = !is_little_endian;
101 return TRUE;
102
103 case PIXMAN_b8g8r8a8:
104 *internal_format = GL_BGRA;
105 *format = GL_BGRA;
106 *type = GL_UNSIGNED_BYTE;
107 *needs_swap = is_little_endian;
108 return TRUE;
109
110 case PIXMAN_b8g8r8x8:
111 *internal_format = GL_BGRA;
112 *format = GL_BGRA;
113 *type = GL_UNSIGNED_BYTE;
114 *has_alpha = FALSE;
115 *needs_swap = is_little_endian;
116 return TRUE;
117
118 case PIXMAN_r8g8b8:
119 *internal_format = GL_RGB;
120 *format = GL_RGB;
121 *type = GL_UNSIGNED_BYTE;
122 *needs_swap = is_little_endian;
123 return TRUE;
124
125 case PIXMAN_b8g8r8:
126 *internal_format = GL_RGB;
127 *format = GL_RGB;
128 *type = GL_UNSIGNED_BYTE;
129 *needs_swap = !is_little_endian;
130 return TRUE;
131
132 case PIXMAN_r5g6b5:
133 *internal_format = GL_RGB;
134 *format = GL_RGB;
135 *type = GL_UNSIGNED_SHORT_5_6_5;
136 *needs_swap = FALSE;
137 return TRUE;
138
139 case PIXMAN_b5g6r5:
140 *internal_format = GL_RGB;
141 *format = GL_RGB;
142 *type = GL_UNSIGNED_SHORT_5_6_5;
143 *needs_swap = TRUE;
144 return TRUE;
145
146 case PIXMAN_a1b5g5r5:
147 *internal_format = GL_RGBA;
148 *format = GL_RGBA;
149 *type = GL_UNSIGNED_SHORT_5_5_5_1;
150 *needs_swap = TRUE;
151 return TRUE;
152
153 case PIXMAN_x1b5g5r5:
154 *internal_format = GL_RGBA;
155 *format = GL_RGBA;
156 *type = GL_UNSIGNED_SHORT_5_5_5_1;
157 *has_alpha = FALSE;
158 *needs_swap = TRUE;
159 return TRUE;
160
161 case PIXMAN_a8:
162 *internal_format = GL_ALPHA;
163 *format = GL_ALPHA;
164 *type = GL_UNSIGNED_BYTE;
165 *needs_swap = FALSE;
166 return TRUE;
167
168 default:
169 return FALSE;
170 }
171 }
172
173 static cairo_bool_t
_cairo_gl_get_image_format_and_type_gl(pixman_format_code_t pixman_format,GLenum * internal_format,GLenum * format,GLenum * type,cairo_bool_t * has_alpha,cairo_bool_t * needs_swap)174 _cairo_gl_get_image_format_and_type_gl (pixman_format_code_t pixman_format,
175 GLenum *internal_format, GLenum *format,
176 GLenum *type, cairo_bool_t *has_alpha,
177 cairo_bool_t *needs_swap)
178 {
179 *has_alpha = TRUE;
180 *needs_swap = FALSE;
181
182 switch (pixman_format) {
183 case PIXMAN_a8r8g8b8:
184 *internal_format = GL_RGBA;
185 *format = GL_BGRA;
186 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
187 return TRUE;
188 case PIXMAN_x8r8g8b8:
189 *internal_format = GL_RGB;
190 *format = GL_BGRA;
191 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
192 *has_alpha = FALSE;
193 return TRUE;
194 case PIXMAN_a8b8g8r8:
195 *internal_format = GL_RGBA;
196 *format = GL_RGBA;
197 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
198 return TRUE;
199 case PIXMAN_x8b8g8r8:
200 *internal_format = GL_RGB;
201 *format = GL_RGBA;
202 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
203 *has_alpha = FALSE;
204 return TRUE;
205 case PIXMAN_b8g8r8a8:
206 *internal_format = GL_RGBA;
207 *format = GL_BGRA;
208 *type = GL_UNSIGNED_INT_8_8_8_8;
209 return TRUE;
210 case PIXMAN_b8g8r8x8:
211 *internal_format = GL_RGB;
212 *format = GL_BGRA;
213 *type = GL_UNSIGNED_INT_8_8_8_8;
214 *has_alpha = FALSE;
215 return TRUE;
216 case PIXMAN_r8g8b8:
217 *internal_format = GL_RGB;
218 *format = GL_RGB;
219 *type = GL_UNSIGNED_BYTE;
220 return TRUE;
221 case PIXMAN_b8g8r8:
222 *internal_format = GL_RGB;
223 *format = GL_BGR;
224 *type = GL_UNSIGNED_BYTE;
225 return TRUE;
226 case PIXMAN_r5g6b5:
227 *internal_format = GL_RGB;
228 *format = GL_RGB;
229 *type = GL_UNSIGNED_SHORT_5_6_5;
230 return TRUE;
231 case PIXMAN_b5g6r5:
232 *internal_format = GL_RGB;
233 *format = GL_RGB;
234 *type = GL_UNSIGNED_SHORT_5_6_5_REV;
235 return TRUE;
236 case PIXMAN_a1r5g5b5:
237 *internal_format = GL_RGBA;
238 *format = GL_BGRA;
239 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
240 return TRUE;
241 case PIXMAN_x1r5g5b5:
242 *internal_format = GL_RGB;
243 *format = GL_BGRA;
244 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
245 *has_alpha = FALSE;
246 return TRUE;
247 case PIXMAN_a1b5g5r5:
248 *internal_format = GL_RGBA;
249 *format = GL_RGBA;
250 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
251 return TRUE;
252 case PIXMAN_x1b5g5r5:
253 *internal_format = GL_RGB;
254 *format = GL_RGBA;
255 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
256 *has_alpha = FALSE;
257 return TRUE;
258 case PIXMAN_a8:
259 *internal_format = GL_ALPHA;
260 *format = GL_ALPHA;
261 *type = GL_UNSIGNED_BYTE;
262 return TRUE;
263
264 #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,27,2)
265 case PIXMAN_a8r8g8b8_sRGB:
266 #endif
267 case PIXMAN_a2b10g10r10:
268 case PIXMAN_x2b10g10r10:
269 case PIXMAN_a4r4g4b4:
270 case PIXMAN_x4r4g4b4:
271 case PIXMAN_a4b4g4r4:
272 case PIXMAN_x4b4g4r4:
273 case PIXMAN_r3g3b2:
274 case PIXMAN_b2g3r3:
275 case PIXMAN_a2r2g2b2:
276 case PIXMAN_a2b2g2r2:
277 case PIXMAN_c8:
278 case PIXMAN_x4a4:
279 /* case PIXMAN_x4c4: */
280 case PIXMAN_x4g4:
281 case PIXMAN_a4:
282 case PIXMAN_r1g2b1:
283 case PIXMAN_b1g2r1:
284 case PIXMAN_a1r1g1b1:
285 case PIXMAN_a1b1g1r1:
286 case PIXMAN_c4:
287 case PIXMAN_g4:
288 case PIXMAN_a1:
289 case PIXMAN_g1:
290 case PIXMAN_yuy2:
291 case PIXMAN_yv12:
292 case PIXMAN_x2r10g10b10:
293 case PIXMAN_a2r10g10b10:
294 case PIXMAN_r8g8b8x8:
295 case PIXMAN_r8g8b8a8:
296 case PIXMAN_x14r6g6b6:
297 default:
298 return FALSE;
299 }
300 }
301
302 /*
303 * Extracts pixel data from an image surface.
304 */
305 static cairo_status_t
_cairo_gl_surface_extract_image_data(cairo_image_surface_t * image,int x,int y,int width,int height,void ** output)306 _cairo_gl_surface_extract_image_data (cairo_image_surface_t *image,
307 int x, int y,
308 int width, int height,
309 void **output)
310 {
311 int cpp = PIXMAN_FORMAT_BPP (image->pixman_format) / 8;
312 char *data = _cairo_malloc_ab (width * height, cpp);
313 char *dst = data;
314 unsigned char *src = image->data + y * image->stride + x * cpp;
315 int i;
316
317 if (unlikely (data == NULL))
318 return CAIRO_STATUS_NO_MEMORY;
319
320 for (i = 0; i < height; i++) {
321 memcpy (dst, src, width * cpp);
322 src += image->stride;
323 dst += width * cpp;
324 }
325
326 *output = data;
327
328 return CAIRO_STATUS_SUCCESS;
329 }
330
331 cairo_bool_t
_cairo_gl_get_image_format_and_type(cairo_gl_flavor_t flavor,pixman_format_code_t pixman_format,GLenum * internal_format,GLenum * format,GLenum * type,cairo_bool_t * has_alpha,cairo_bool_t * needs_swap)332 _cairo_gl_get_image_format_and_type (cairo_gl_flavor_t flavor,
333 pixman_format_code_t pixman_format,
334 GLenum *internal_format, GLenum *format,
335 GLenum *type, cairo_bool_t *has_alpha,
336 cairo_bool_t *needs_swap)
337 {
338 if (flavor == CAIRO_GL_FLAVOR_DESKTOP)
339 return _cairo_gl_get_image_format_and_type_gl (pixman_format,
340 internal_format, format,
341 type, has_alpha,
342 needs_swap);
343 else
344 return _cairo_gl_get_image_format_and_type_gles2 (pixman_format,
345 internal_format, format,
346 type, has_alpha,
347 needs_swap);
348
349 }
350
351 cairo_bool_t
_cairo_gl_operator_is_supported(cairo_operator_t op)352 _cairo_gl_operator_is_supported (cairo_operator_t op)
353 {
354 return op < CAIRO_OPERATOR_SATURATE;
355 }
356
357 static void
_cairo_gl_surface_embedded_operand_init(cairo_gl_surface_t * surface)358 _cairo_gl_surface_embedded_operand_init (cairo_gl_surface_t *surface)
359 {
360 cairo_gl_operand_t *operand = &surface->operand;
361 cairo_surface_attributes_t *attributes = &operand->texture.attributes;
362
363 memset (operand, 0, sizeof (cairo_gl_operand_t));
364
365 operand->type = CAIRO_GL_OPERAND_TEXTURE;
366 operand->texture.surface = surface;
367 operand->texture.tex = surface->tex;
368
369 if (_cairo_gl_device_requires_power_of_two_textures (surface->base.device)) {
370 cairo_matrix_init_identity (&attributes->matrix);
371 } else {
372 cairo_matrix_init_scale (&attributes->matrix,
373 1.0 / surface->width,
374 1.0 / surface->height);
375 }
376
377 attributes->extend = CAIRO_EXTEND_NONE;
378 attributes->filter = CAIRO_FILTER_NEAREST;
379 }
380
381 void
_cairo_gl_surface_init(cairo_device_t * device,cairo_gl_surface_t * surface,cairo_content_t content,int width,int height)382 _cairo_gl_surface_init (cairo_device_t *device,
383 cairo_gl_surface_t *surface,
384 cairo_content_t content,
385 int width, int height)
386 {
387 assert (width > 0 && height > 0);
388
389 _cairo_surface_init (&surface->base,
390 &_cairo_gl_surface_backend,
391 device,
392 content,
393 FALSE); /* is_vector */
394
395 surface->width = width;
396 surface->height = height;
397 surface->needs_update = FALSE;
398 surface->content_in_texture = FALSE;
399
400 _cairo_gl_surface_embedded_operand_init (surface);
401 }
402
403 static cairo_bool_t
_cairo_gl_surface_size_valid_for_context(cairo_gl_context_t * ctx,int width,int height)404 _cairo_gl_surface_size_valid_for_context (cairo_gl_context_t *ctx,
405 int width, int height)
406 {
407 return width > 0 && height > 0 &&
408 width <= ctx->max_framebuffer_size &&
409 height <= ctx->max_framebuffer_size;
410 }
411
412 static cairo_bool_t
_cairo_gl_surface_size_valid(cairo_gl_surface_t * surface,int width,int height)413 _cairo_gl_surface_size_valid (cairo_gl_surface_t *surface,
414 int width, int height)
415 {
416 cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
417 return _cairo_gl_surface_size_valid_for_context (ctx, width, height);
418 }
419
420 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)421 _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx,
422 cairo_content_t content,
423 GLuint tex,
424 int width,
425 int height)
426 {
427 cairo_gl_surface_t *surface;
428
429 surface = calloc (1, sizeof (cairo_gl_surface_t));
430 if (unlikely (surface == NULL))
431 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
432
433 surface->tex = tex;
434 _cairo_gl_surface_init (&ctx->base, surface, content, width, height);
435
436 surface->supports_msaa = ctx->supports_msaa;
437 surface->num_samples = ctx->num_samples;
438 surface->supports_stencil = TRUE;
439
440 /* Create the texture used to store the surface's data. */
441 _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
442 glBindTexture (ctx->tex_target, surface->tex);
443 glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
444 glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
445
446 return &surface->base;
447 }
448
449 static cairo_surface_t *
_create_scratch_internal(cairo_gl_context_t * ctx,cairo_content_t content,int width,int height,cairo_bool_t for_caching)450 _create_scratch_internal (cairo_gl_context_t *ctx,
451 cairo_content_t content,
452 int width,
453 int height,
454 cairo_bool_t for_caching)
455 {
456 cairo_gl_surface_t *surface;
457 GLenum format;
458 GLuint tex;
459
460 glGenTextures (1, &tex);
461 surface = (cairo_gl_surface_t *)
462 _cairo_gl_surface_create_scratch_for_texture (ctx, content,
463 tex, width, height);
464 if (unlikely (surface->base.status))
465 return &surface->base;
466
467 surface->owns_tex = TRUE;
468
469 /* adjust the texture size after setting our real extents */
470 if (width < 1)
471 width = 1;
472 if (height < 1)
473 height = 1;
474
475 switch (content) {
476 default:
477 ASSERT_NOT_REACHED;
478 case CAIRO_CONTENT_COLOR_ALPHA:
479 format = GL_RGBA;
480 break;
481 case CAIRO_CONTENT_ALPHA:
482 /* When using GL_ALPHA, compositing doesn't work properly, but for
483 * caching surfaces, we are just uploading pixel data, so it isn't
484 * an issue. */
485 if (for_caching)
486 format = GL_ALPHA;
487 else
488 format = GL_RGBA;
489 break;
490 case CAIRO_CONTENT_COLOR:
491 /* GL_RGB is almost what we want here -- sampling 1 alpha when
492 * texturing, using 1 as destination alpha factor in blending,
493 * etc. However, when filtering with GL_CLAMP_TO_BORDER, the
494 * alpha channel of the border color will also be clamped to
495 * 1, when we actually want the border color we explicitly
496 * specified. So, we have to store RGBA, and fill the alpha
497 * channel with 1 when blending.
498 */
499 format = GL_RGBA;
500 break;
501 }
502
503 glTexImage2D (ctx->tex_target, 0, format, width, height, 0,
504 format, GL_UNSIGNED_BYTE, NULL);
505
506 return &surface->base;
507 }
508
509 cairo_surface_t *
_cairo_gl_surface_create_scratch(cairo_gl_context_t * ctx,cairo_content_t content,int width,int height)510 _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
511 cairo_content_t content,
512 int width,
513 int height)
514 {
515 return _create_scratch_internal (ctx, content, width, height, FALSE);
516 }
517
518 cairo_surface_t *
_cairo_gl_surface_create_scratch_for_caching(cairo_gl_context_t * ctx,cairo_content_t content,int width,int height)519 _cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx,
520 cairo_content_t content,
521 int width,
522 int height)
523 {
524 return _create_scratch_internal (ctx, content, width, height, TRUE);
525 }
526
527 static cairo_status_t
_cairo_gl_surface_clear(cairo_gl_surface_t * surface,const cairo_color_t * color)528 _cairo_gl_surface_clear (cairo_gl_surface_t *surface,
529 const cairo_color_t *color)
530 {
531 cairo_gl_context_t *ctx;
532 cairo_status_t status;
533 double r, g, b, a;
534
535 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
536 if (unlikely (status))
537 return status;
538
539 _cairo_gl_context_set_destination (ctx, surface, surface->msaa_active);
540 if (surface->base.content & CAIRO_CONTENT_COLOR) {
541 r = color->red * color->alpha;
542 g = color->green * color->alpha;
543 b = color->blue * color->alpha;
544 } else {
545 r = g = b = 0;
546 }
547 if (surface->base.content & CAIRO_CONTENT_ALPHA) {
548 a = color->alpha;
549 } else {
550 a = 1.0;
551 }
552
553 glDisable (GL_SCISSOR_TEST);
554 glClearColor (r, g, b, a);
555 glClear (GL_COLOR_BUFFER_BIT);
556
557 if (a == 0)
558 surface->base.is_clear = TRUE;
559
560 return _cairo_gl_context_release (ctx, status);
561 }
562
563 static cairo_surface_t *
_cairo_gl_surface_create_and_clear_scratch(cairo_gl_context_t * ctx,cairo_content_t content,int width,int height)564 _cairo_gl_surface_create_and_clear_scratch (cairo_gl_context_t *ctx,
565 cairo_content_t content,
566 int width,
567 int height)
568 {
569 cairo_gl_surface_t *surface;
570 cairo_int_status_t status;
571
572 surface = (cairo_gl_surface_t *)
573 _cairo_gl_surface_create_scratch (ctx, content, width, height);
574 if (unlikely (surface->base.status))
575 return &surface->base;
576
577 /* Cairo surfaces start out initialized to transparent (black) */
578 status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
579 if (unlikely (status)) {
580 cairo_surface_destroy (&surface->base);
581 return _cairo_surface_create_in_error (status);
582 }
583
584 return &surface->base;
585 }
586
587 cairo_surface_t *
cairo_gl_surface_create(cairo_device_t * abstract_device,cairo_content_t content,int width,int height)588 cairo_gl_surface_create (cairo_device_t *abstract_device,
589 cairo_content_t content,
590 int width,
591 int height)
592 {
593 cairo_gl_context_t *ctx;
594 cairo_gl_surface_t *surface;
595 cairo_status_t status;
596
597 if (! CAIRO_CONTENT_VALID (content))
598 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
599
600 if (abstract_device == NULL)
601 return _cairo_image_surface_create_with_content (content, width, height);
602
603 if (abstract_device->status)
604 return _cairo_surface_create_in_error (abstract_device->status);
605
606 if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
607 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
608
609 status = _cairo_gl_context_acquire (abstract_device, &ctx);
610 if (unlikely (status))
611 return _cairo_surface_create_in_error (status);
612
613 if (! _cairo_gl_surface_size_valid_for_context (ctx, width, height)) {
614 status = _cairo_gl_context_release (ctx, status);
615 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
616 }
617
618 surface = (cairo_gl_surface_t *)
619 _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
620 if (unlikely (surface->base.status)) {
621 status = _cairo_gl_context_release (ctx, surface->base.status);
622 cairo_surface_destroy (&surface->base);
623 return _cairo_surface_create_in_error (status);
624 }
625
626 status = _cairo_gl_context_release (ctx, status);
627 if (unlikely (status)) {
628 cairo_surface_destroy (&surface->base);
629 return _cairo_surface_create_in_error (status);
630 }
631
632 return &surface->base;
633 }
634 slim_hidden_def (cairo_gl_surface_create);
635
636 /**
637 * cairo_gl_surface_create_for_texture:
638 * @content: type of content in the surface
639 * @tex: name of texture to use for storage of surface pixels
640 * @width: width of the surface, in pixels
641 * @height: height of the surface, in pixels
642 *
643 * Creates a GL surface for the specified texture with the specified
644 * content and dimensions. The texture must be kept around until the
645 * #cairo_surface_t is destroyed or cairo_surface_finish() is called
646 * on the surface. The initial contents of @tex will be used as the
647 * initial image contents; you must explicitly clear the buffer,
648 * using, for example, cairo_rectangle() and cairo_fill() if you want
649 * it cleared. The format of @tex should be compatible with @content,
650 * in the sense that it must have the color components required by
651 * @content.
652 *
653 * Return value: a pointer to the newly created surface. The caller
654 * owns the surface and should call cairo_surface_destroy() when done
655 * with it.
656 *
657 * This function always returns a valid pointer, but it will return a
658 * pointer to a "nil" surface if an error such as out of memory
659 * occurs. You can use cairo_surface_status() to check for this.
660 *
661 * Since: TBD
662 **/
663 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)664 cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
665 cairo_content_t content,
666 unsigned int tex,
667 int width,
668 int height)
669 {
670 cairo_gl_context_t *ctx;
671 cairo_gl_surface_t *surface;
672 cairo_status_t status;
673
674 if (! CAIRO_CONTENT_VALID (content))
675 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
676
677 if (abstract_device == NULL)
678 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
679
680 if (abstract_device->status)
681 return _cairo_surface_create_in_error (abstract_device->status);
682
683 if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
684 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH));
685
686 status = _cairo_gl_context_acquire (abstract_device, &ctx);
687 if (unlikely (status))
688 return _cairo_surface_create_in_error (status);
689
690 if (! _cairo_gl_surface_size_valid_for_context (ctx, width, height)) {
691 status = _cairo_gl_context_release (ctx, status);
692 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
693 }
694
695 surface = (cairo_gl_surface_t *)
696 _cairo_gl_surface_create_scratch_for_texture (ctx, content,
697 tex, width, height);
698 status = _cairo_gl_context_release (ctx, status);
699
700 return &surface->base;
701 }
702 slim_hidden_def (cairo_gl_surface_create_for_texture);
703
704
705 void
cairo_gl_surface_set_size(cairo_surface_t * abstract_surface,int width,int height)706 cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
707 int width,
708 int height)
709 {
710 cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
711
712 if (unlikely (abstract_surface->status))
713 return;
714 if (unlikely (abstract_surface->finished)) {
715 _cairo_surface_set_error (abstract_surface,
716 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
717 return;
718 }
719
720 if (! _cairo_surface_is_gl (abstract_surface) ||
721 _cairo_gl_surface_is_texture (surface)) {
722 _cairo_surface_set_error (abstract_surface,
723 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
724 return;
725 }
726
727 if (surface->width != width || surface->height != height) {
728 surface->needs_update = TRUE;
729 surface->width = width;
730 surface->height = height;
731 }
732 }
733
734 int
cairo_gl_surface_get_width(cairo_surface_t * abstract_surface)735 cairo_gl_surface_get_width (cairo_surface_t *abstract_surface)
736 {
737 cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
738
739 if (! _cairo_surface_is_gl (abstract_surface))
740 return 0;
741
742 return surface->width;
743 }
744
745 int
cairo_gl_surface_get_height(cairo_surface_t * abstract_surface)746 cairo_gl_surface_get_height (cairo_surface_t *abstract_surface)
747 {
748 cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
749
750 if (! _cairo_surface_is_gl (abstract_surface))
751 return 0;
752
753 return surface->height;
754 }
755
756 void
cairo_gl_surface_swapbuffers(cairo_surface_t * abstract_surface)757 cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
758 {
759 cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
760
761 if (unlikely (abstract_surface->status))
762 return;
763 if (unlikely (abstract_surface->finished)) {
764 _cairo_surface_set_error (abstract_surface,
765 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
766 return;
767 }
768
769 if (! _cairo_surface_is_gl (abstract_surface)) {
770 _cairo_surface_set_error (abstract_surface,
771 CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
772 return;
773 }
774
775 if (! _cairo_gl_surface_is_texture (surface)) {
776 cairo_gl_context_t *ctx;
777 cairo_status_t status;
778
779 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
780 if (unlikely (status))
781 return;
782
783 /* For swapping on EGL, at least, we need a valid context/target. */
784 _cairo_gl_context_set_destination (ctx, surface, FALSE);
785 /* And in any case we should flush any pending operations. */
786 _cairo_gl_composite_flush (ctx);
787
788 ctx->swap_buffers (ctx, surface);
789
790 status = _cairo_gl_context_release (ctx, status);
791 if (status)
792 status = _cairo_surface_set_error (abstract_surface, status);
793 }
794 }
795
796 static cairo_surface_t *
_cairo_gl_surface_create_similar(void * abstract_surface,cairo_content_t content,int width,int height)797 _cairo_gl_surface_create_similar (void *abstract_surface,
798 cairo_content_t content,
799 int width,
800 int height)
801 {
802 cairo_surface_t *surface = abstract_surface;
803 cairo_gl_context_t *ctx;
804 cairo_status_t status;
805
806 if (! _cairo_gl_surface_size_valid (abstract_surface, width, height))
807 return _cairo_image_surface_create_with_content (content, width, height);
808
809 status = _cairo_gl_context_acquire (surface->device, &ctx);
810 if (unlikely (status))
811 return _cairo_surface_create_in_error (status);
812
813 surface = _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
814
815 status = _cairo_gl_context_release (ctx, status);
816 if (unlikely (status)) {
817 cairo_surface_destroy (surface);
818 return _cairo_surface_create_in_error (status);
819 }
820
821 return surface;
822 }
823
824 static cairo_int_status_t
_cairo_gl_surface_fill_alpha_channel(cairo_gl_surface_t * dst,cairo_gl_context_t * ctx,int x,int y,int width,int height)825 _cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t *dst,
826 cairo_gl_context_t *ctx,
827 int x, int y,
828 int width, int height)
829 {
830 cairo_gl_composite_t setup;
831 cairo_status_t status;
832
833 _cairo_gl_composite_flush (ctx);
834 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
835
836 status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_SOURCE,
837 dst, FALSE);
838 if (unlikely (status))
839 goto CLEANUP;
840
841 _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_BLACK);
842
843 status = _cairo_gl_composite_begin (&setup, &ctx);
844 if (unlikely (status))
845 goto CLEANUP;
846
847 _cairo_gl_context_emit_rect (ctx, x, y, x + width, y + height);
848
849 status = _cairo_gl_context_release (ctx, status);
850
851 CLEANUP:
852 _cairo_gl_composite_fini (&setup);
853
854 _cairo_gl_composite_flush (ctx);
855 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
856
857 return status;
858 }
859
860 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,cairo_bool_t force_flush)861 _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
862 cairo_image_surface_t *src,
863 int src_x, int src_y,
864 int width, int height,
865 int dst_x, int dst_y,
866 cairo_bool_t force_flush)
867 {
868 GLenum internal_format, format, type;
869 cairo_bool_t has_alpha, needs_swap;
870 cairo_image_surface_t *clone = NULL;
871 cairo_gl_context_t *ctx;
872 int cpp;
873 cairo_image_surface_t *rgba_clone = NULL;
874 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
875
876 status = _cairo_gl_context_acquire (dst->base.device, &ctx);
877 if (unlikely (status))
878 return status;
879
880 if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES3 ||
881 _cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2) {
882 pixman_format_code_t pixman_format;
883 cairo_surface_pattern_t pattern;
884 cairo_bool_t require_conversion = FALSE;
885 pixman_format = _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
886
887 if (src->base.content != CAIRO_CONTENT_ALPHA) {
888 if (src->pixman_format != pixman_format)
889 require_conversion = TRUE;
890 }
891 else if (dst->base.content != CAIRO_CONTENT_ALPHA) {
892 require_conversion = TRUE;
893 }
894 else if (src->pixman_format != PIXMAN_a8) {
895 pixman_format = PIXMAN_a8;
896 require_conversion = TRUE;
897 }
898
899 if (require_conversion) {
900 rgba_clone = (cairo_image_surface_t *)
901 _cairo_image_surface_create_with_pixman_format (NULL,
902 pixman_format,
903 src->width,
904 src->height,
905 0);
906 if (unlikely (rgba_clone->base.status))
907 goto FAIL;
908
909 _cairo_pattern_init_for_surface (&pattern, &src->base);
910 status = _cairo_surface_paint (&rgba_clone->base,
911 CAIRO_OPERATOR_SOURCE,
912 &pattern.base, NULL);
913 _cairo_pattern_fini (&pattern.base);
914 if (unlikely (status))
915 goto FAIL;
916
917 src = rgba_clone;
918 }
919 }
920
921 if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
922 src->pixman_format,
923 &internal_format,
924 &format,
925 &type,
926 &has_alpha,
927 &needs_swap))
928 {
929 cairo_bool_t is_supported;
930
931 clone = _cairo_image_surface_coerce (src);
932 if (unlikely (status = clone->base.status))
933 goto FAIL;
934
935 is_supported =
936 _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
937 clone->pixman_format,
938 &internal_format,
939 &format,
940 &type,
941 &has_alpha,
942 &needs_swap);
943 assert (is_supported);
944 assert (!needs_swap);
945 src = clone;
946 }
947
948 cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
949
950 if (force_flush) {
951 status = _cairo_gl_surface_flush (&dst->base, 0);
952 if (unlikely (status))
953 goto FAIL;
954 }
955
956 if (_cairo_gl_surface_is_texture (dst)) {
957 void *data_start = src->data + src_y * src->stride + src_x * cpp;
958 void *data_start_gles2 = NULL;
959
960 /*
961 * Due to GL_UNPACK_ROW_LENGTH missing in GLES2 we have to extract the
962 * image data ourselves in some cases. In particular, we must extract
963 * the pixels if:
964 * a. we don't want full-length lines or
965 * b. the row stride cannot be handled by GL itself using a 4 byte
966 * alignment constraint
967 */
968 if (src->stride < 0 ||
969 (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
970 (src->width * cpp < src->stride - 3 ||
971 width != src->width)))
972 {
973 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
974 status = _cairo_gl_surface_extract_image_data (src, src_x, src_y,
975 width, height,
976 &data_start_gles2);
977 if (unlikely (status))
978 goto FAIL;
979
980 data_start = data_start_gles2;
981 }
982 else
983 {
984 glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
985 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
986 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
987 glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
988 }
989
990 /* we must resolve the renderbuffer to texture before we
991 upload image */
992 status = _cairo_gl_surface_resolve_multisampling (dst);
993 if (unlikely (status)) {
994 free (data_start_gles2);
995 goto FAIL;
996 }
997
998 _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
999 glBindTexture (ctx->tex_target, dst->tex);
1000 glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1001 glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1002 glTexSubImage2D (ctx->tex_target, 0,
1003 dst_x, dst_y, width, height,
1004 format, type, data_start);
1005
1006 free (data_start_gles2);
1007
1008 /* If we just treated some rgb-only data as rgba, then we have to
1009 * go back and fix up the alpha channel where we filled in this
1010 * texture data.
1011 */
1012 if (!has_alpha) {
1013 _cairo_gl_surface_fill_alpha_channel (dst, ctx,
1014 dst_x, dst_y,
1015 width, height);
1016 }
1017 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
1018 dst->content_in_texture = TRUE;
1019 } else {
1020 cairo_surface_t *tmp;
1021
1022 tmp = _cairo_gl_surface_create_scratch (ctx,
1023 dst->base.content,
1024 width, height);
1025 if (unlikely (tmp->status))
1026 goto FAIL;
1027
1028 status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *) tmp,
1029 src,
1030 src_x, src_y,
1031 width, height,
1032 0, 0, force_flush);
1033 if (status == CAIRO_INT_STATUS_SUCCESS) {
1034 cairo_surface_pattern_t tmp_pattern;
1035 cairo_rectangle_int_t r;
1036 cairo_clip_t *clip;
1037
1038 _cairo_pattern_init_for_surface (&tmp_pattern, tmp);
1039 cairo_matrix_init_translate (&tmp_pattern.base.matrix,
1040 -dst_x, -dst_y);
1041 tmp_pattern.base.filter = CAIRO_FILTER_NEAREST;
1042 tmp_pattern.base.extend = CAIRO_EXTEND_NONE;
1043
1044 r.x = dst_x;
1045 r.y = dst_y;
1046 r.width = width;
1047 r.height = height;
1048 clip = _cairo_clip_intersect_rectangle (NULL, &r);
1049 status = _cairo_surface_paint (&dst->base,
1050 CAIRO_OPERATOR_SOURCE,
1051 &tmp_pattern.base,
1052 clip);
1053 _cairo_clip_destroy (clip);
1054 _cairo_pattern_fini (&tmp_pattern.base);
1055 }
1056
1057 cairo_surface_destroy (tmp);
1058 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
1059 dst->content_in_texture = TRUE;
1060 }
1061
1062 FAIL:
1063 status = _cairo_gl_context_release (ctx, status);
1064
1065 if (clone)
1066 cairo_surface_destroy (&clone->base);
1067
1068 if (rgba_clone)
1069 cairo_surface_destroy (&rgba_clone->base);
1070
1071 return status;
1072 }
1073
_cairo_gl_surface_flavor(cairo_gl_surface_t * surface)1074 static int _cairo_gl_surface_flavor (cairo_gl_surface_t *surface)
1075 {
1076 cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
1077 return ctx->gl_flavor;
1078 }
1079
1080 static cairo_status_t
_cairo_gl_surface_finish(void * abstract_surface)1081 _cairo_gl_surface_finish (void *abstract_surface)
1082 {
1083 cairo_gl_surface_t *surface = abstract_surface;
1084 cairo_status_t status;
1085 cairo_gl_context_t *ctx;
1086
1087 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
1088 if (unlikely (status))
1089 return status;
1090
1091 if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
1092 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
1093 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
1094 if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
1095 ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
1096 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
1097 if (ctx->current_target == surface)
1098 ctx->current_target = NULL;
1099
1100 if (surface->fb)
1101 ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
1102 if (surface->depth_stencil)
1103 ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil);
1104 if (surface->owns_tex)
1105 glDeleteTextures (1, &surface->tex);
1106
1107 if (surface->msaa_depth_stencil)
1108 ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
1109
1110 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
1111 if (surface->msaa_fb)
1112 ctx->dispatch.DeleteFramebuffers (1, &surface->msaa_fb);
1113 if (surface->msaa_rb)
1114 ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_rb);
1115 #endif
1116
1117 _cairo_clip_destroy (surface->clip_on_stencil_buffer);
1118
1119 return _cairo_gl_context_release (ctx, status);
1120 }
1121
1122 static cairo_image_surface_t *
_cairo_gl_surface_map_to_image(void * abstract_surface,const cairo_rectangle_int_t * extents)1123 _cairo_gl_surface_map_to_image (void *abstract_surface,
1124 const cairo_rectangle_int_t *extents)
1125 {
1126 cairo_gl_surface_t *surface = abstract_surface;
1127 cairo_image_surface_t *image;
1128 cairo_gl_context_t *ctx;
1129 GLenum format, type;
1130 pixman_format_code_t pixman_format;
1131 unsigned int cpp;
1132 cairo_bool_t flipped, mesa_invert;
1133 cairo_status_t status;
1134 int y;
1135
1136 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
1137 if (unlikely (status)) {
1138 return _cairo_image_surface_create_in_error (status);
1139 }
1140
1141 /* Want to use a switch statement here but the compiler gets whiny. */
1142 if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
1143 format = GL_BGRA;
1144 pixman_format = PIXMAN_a8r8g8b8;
1145 type = GL_UNSIGNED_INT_8_8_8_8_REV;
1146 cpp = 4;
1147 } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
1148 format = GL_BGRA;
1149 pixman_format = PIXMAN_x8r8g8b8;
1150 type = GL_UNSIGNED_INT_8_8_8_8_REV;
1151 cpp = 4;
1152 } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
1153 format = GL_ALPHA;
1154 pixman_format = PIXMAN_a8;
1155 type = GL_UNSIGNED_BYTE;
1156 cpp = 1;
1157 } else {
1158 ASSERT_NOT_REACHED;
1159 return NULL;
1160 }
1161
1162 if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES3 ||
1163 _cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES2) {
1164 /* If only RGBA is supported, we must download data in a compatible
1165 * format. This means that pixman will convert the data on the CPU when
1166 * interacting with other image surfaces. For ALPHA, GLES2 does not
1167 * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
1168 * pixman image that is created has row_stride = row_width * bpp. */
1169 if (surface->base.content == CAIRO_CONTENT_ALPHA || !ctx->can_read_bgra) {
1170 cairo_bool_t little_endian = _cairo_is_little_endian ();
1171 format = GL_RGBA;
1172
1173 if (surface->base.content == CAIRO_CONTENT_COLOR) {
1174 pixman_format = little_endian ?
1175 PIXMAN_x8b8g8r8 : PIXMAN_r8g8b8x8;
1176 } else {
1177 pixman_format = little_endian ?
1178 PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
1179 }
1180 }
1181
1182 /* GLES2 only supports GL_UNSIGNED_BYTE. */
1183 type = GL_UNSIGNED_BYTE;
1184 cpp = 4;
1185 }
1186
1187 image = (cairo_image_surface_t*)
1188 _cairo_image_surface_create_with_pixman_format (NULL,
1189 pixman_format,
1190 extents->width,
1191 extents->height,
1192 -1);
1193 if (unlikely (image->base.status)) {
1194 status = _cairo_gl_context_release (ctx, status);
1195 return image;
1196 }
1197
1198 cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y);
1199
1200 /* If the original surface has not been modified or
1201 * is clear, we can avoid downloading data. */
1202 if (surface->base.is_clear || surface->base.serial == 0) {
1203 status = _cairo_gl_context_release (ctx, status);
1204 return image;
1205 }
1206
1207 /* This is inefficient, as we'd rather just read the thing without making
1208 * it the destination. But then, this is the fallback path, so let's not
1209 * fall back instead.
1210 */
1211 _cairo_gl_composite_flush (ctx);
1212
1213 if (ctx->gl_flavor != CAIRO_GL_FLAVOR_ES3) {
1214 _cairo_gl_context_set_destination (ctx, surface, FALSE);
1215 } else {
1216 if (surface->content_in_texture) {
1217 _cairo_gl_ensure_framebuffer (ctx, surface);
1218 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
1219 } else {
1220 status = _cairo_gl_surface_resolve_multisampling (surface);
1221 if (unlikely (status)) {
1222 status = _cairo_gl_context_release (ctx, status);
1223 cairo_surface_destroy (&image->base);
1224 return _cairo_image_surface_create_in_error (status);
1225 }
1226 }
1227 }
1228
1229 flipped = ! _cairo_gl_surface_is_texture (surface);
1230 mesa_invert = flipped && ctx->has_mesa_pack_invert;
1231
1232 glPixelStorei (GL_PACK_ALIGNMENT, 4);
1233 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
1234 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
1235 glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
1236 if (mesa_invert)
1237 glPixelStorei (GL_PACK_INVERT_MESA, 1);
1238
1239 y = extents->y;
1240 if (flipped)
1241 y = surface->height - extents->y - extents->height;
1242
1243 glReadPixels (extents->x, y,
1244 extents->width, extents->height,
1245 format, type, image->data);
1246 if (mesa_invert)
1247 glPixelStorei (GL_PACK_INVERT_MESA, 0);
1248
1249 status = _cairo_gl_context_release (ctx, status);
1250 if (unlikely (status)) {
1251 cairo_surface_destroy (&image->base);
1252 return _cairo_image_surface_create_in_error (status);
1253 }
1254
1255 /* We must invert the image manually if we lack GL_MESA_pack_invert */
1256 if (flipped && ! mesa_invert) {
1257 uint8_t stack[1024], *row = stack;
1258 uint8_t *top = image->data;
1259 uint8_t *bot = image->data + (image->height-1)*image->stride;
1260
1261 if (image->stride > (int)sizeof(stack)) {
1262 row = _cairo_malloc (image->stride);
1263 if (unlikely (row == NULL)) {
1264 cairo_surface_destroy (&image->base);
1265 return _cairo_image_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1266 }
1267 }
1268
1269 while (top < bot) {
1270 memcpy (row, top, image->stride);
1271 memcpy (top, bot, image->stride);
1272 memcpy (bot, row, image->stride);
1273 top += image->stride;
1274 bot -= image->stride;
1275 }
1276
1277 if (row != stack)
1278 free(row);
1279 }
1280
1281 image->base.is_clear = FALSE;
1282 return image;
1283 }
1284
1285 static cairo_surface_t *
_cairo_gl_surface_source(void * abstract_surface,cairo_rectangle_int_t * extents)1286 _cairo_gl_surface_source (void *abstract_surface,
1287 cairo_rectangle_int_t *extents)
1288 {
1289 cairo_gl_surface_t *surface = abstract_surface;
1290
1291 if (extents) {
1292 extents->x = extents->y = 0;
1293 extents->width = surface->width;
1294 extents->height = surface->height;
1295 }
1296
1297 return &surface->base;
1298 }
1299
1300 static cairo_status_t
_cairo_gl_surface_acquire_source_image(void * abstract_surface,cairo_image_surface_t ** image_out,void ** image_extra)1301 _cairo_gl_surface_acquire_source_image (void *abstract_surface,
1302 cairo_image_surface_t **image_out,
1303 void **image_extra)
1304 {
1305 cairo_gl_surface_t *surface = abstract_surface;
1306 cairo_rectangle_int_t extents;
1307
1308 *image_extra = NULL;
1309
1310 extents.x = extents.y = 0;
1311 extents.width = surface->width;
1312 extents.height = surface->height;
1313
1314 *image_out = (cairo_image_surface_t *)
1315 _cairo_gl_surface_map_to_image (surface, &extents);
1316 return (*image_out)->base.status;
1317 }
1318
1319 static void
_cairo_gl_surface_release_source_image(void * abstract_surface,cairo_image_surface_t * image,void * image_extra)1320 _cairo_gl_surface_release_source_image (void *abstract_surface,
1321 cairo_image_surface_t *image,
1322 void *image_extra)
1323 {
1324 cairo_surface_destroy (&image->base);
1325 }
1326
1327 static cairo_int_status_t
_cairo_gl_surface_unmap_image(void * abstract_surface,cairo_image_surface_t * image)1328 _cairo_gl_surface_unmap_image (void *abstract_surface,
1329 cairo_image_surface_t *image)
1330 {
1331 cairo_int_status_t status;
1332
1333 status = _cairo_gl_surface_draw_image (abstract_surface, image,
1334 0, 0,
1335 image->width, image->height,
1336 image->base.device_transform_inverse.x0,
1337 image->base.device_transform_inverse.y0,
1338 TRUE);
1339
1340 cairo_surface_finish (&image->base);
1341 cairo_surface_destroy (&image->base);
1342
1343 return status;
1344 }
1345
1346 static cairo_bool_t
_cairo_gl_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * rectangle)1347 _cairo_gl_surface_get_extents (void *abstract_surface,
1348 cairo_rectangle_int_t *rectangle)
1349 {
1350 cairo_gl_surface_t *surface = abstract_surface;
1351
1352 rectangle->x = 0;
1353 rectangle->y = 0;
1354 rectangle->width = surface->width;
1355 rectangle->height = surface->height;
1356
1357 return TRUE;
1358 }
1359
1360 static cairo_status_t
_cairo_gl_surface_flush(void * abstract_surface,unsigned flags)1361 _cairo_gl_surface_flush (void *abstract_surface, unsigned flags)
1362 {
1363 cairo_gl_surface_t *surface = abstract_surface;
1364 cairo_status_t status;
1365 cairo_gl_context_t *ctx;
1366
1367 if (flags)
1368 return CAIRO_STATUS_SUCCESS;
1369
1370 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
1371 if (unlikely (status))
1372 return status;
1373
1374 if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
1375 ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) ||
1376 (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
1377 ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) ||
1378 (ctx->current_target == surface))
1379 _cairo_gl_composite_flush (ctx);
1380
1381 status = _cairo_gl_surface_resolve_multisampling (surface);
1382
1383 return _cairo_gl_context_release (ctx, status);
1384 }
1385
1386 cairo_int_status_t
_cairo_gl_surface_resolve_multisampling(cairo_gl_surface_t * surface)1387 _cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t *surface)
1388 {
1389 cairo_gl_context_t *ctx;
1390 cairo_int_status_t status;
1391
1392 if (! surface->msaa_active)
1393 return CAIRO_INT_STATUS_SUCCESS;
1394
1395 if (surface->base.device == NULL)
1396 return CAIRO_INT_STATUS_SUCCESS;
1397
1398 /* GLES surfaces do not need explicit resolution. */
1399 if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES2)
1400 return CAIRO_INT_STATUS_SUCCESS;
1401 else if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES3 &&
1402 surface->content_in_texture)
1403 return CAIRO_INT_STATUS_SUCCESS;
1404
1405 if (! _cairo_gl_surface_is_texture (surface))
1406 return CAIRO_INT_STATUS_SUCCESS;
1407
1408 status = _cairo_gl_context_acquire (surface->base.device, &ctx);
1409 if (unlikely (status))
1410 return status;
1411
1412 #if CAIRO_HAS_GLESV3_SURFACE
1413 _cairo_gl_composite_flush (ctx);
1414 ctx->current_target = NULL;
1415 _cairo_gl_context_bind_framebuffer (ctx, surface, FALSE);
1416 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
1417 surface->content_in_texture = TRUE;
1418
1419 #elif CAIRO_HAS_GL_SURFACE
1420 ctx->current_target = surface;
1421 _cairo_gl_context_bind_framebuffer (ctx, surface, FALSE);
1422
1423 #else
1424 ctx->current_target = surface;
1425
1426 #endif
1427
1428 status = _cairo_gl_context_release (ctx, status);
1429 return status;
1430 }
1431
1432 static const cairo_compositor_t *
get_compositor(cairo_gl_surface_t * surface)1433 get_compositor (cairo_gl_surface_t *surface)
1434 {
1435 cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
1436 return ctx->compositor;
1437 }
1438
1439 static cairo_int_status_t
_cairo_gl_surface_paint(void * surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_clip_t * clip)1440 _cairo_gl_surface_paint (void *surface,
1441 cairo_operator_t op,
1442 const cairo_pattern_t *source,
1443 const cairo_clip_t *clip)
1444 {
1445 /* simplify the common case of clearing the surface */
1446 if (clip == NULL) {
1447 if (op == CAIRO_OPERATOR_CLEAR)
1448 return _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
1449 else if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
1450 (op == CAIRO_OPERATOR_SOURCE ||
1451 (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque_solid (source)))) {
1452 return _cairo_gl_surface_clear (surface,
1453 &((cairo_solid_pattern_t *) source)->color);
1454 }
1455 }
1456
1457 return _cairo_compositor_paint (get_compositor (surface), surface,
1458 op, source, clip);
1459 }
1460
1461 static cairo_int_status_t
_cairo_gl_surface_mask(void * surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_pattern_t * mask,const cairo_clip_t * clip)1462 _cairo_gl_surface_mask (void *surface,
1463 cairo_operator_t op,
1464 const cairo_pattern_t *source,
1465 const cairo_pattern_t *mask,
1466 const cairo_clip_t *clip)
1467 {
1468 return _cairo_compositor_mask (get_compositor (surface), surface,
1469 op, source, mask, clip);
1470 }
1471
1472 static cairo_int_status_t
_cairo_gl_surface_stroke(void * surface,cairo_operator_t op,const cairo_pattern_t * source,const 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,const cairo_clip_t * clip)1473 _cairo_gl_surface_stroke (void *surface,
1474 cairo_operator_t op,
1475 const cairo_pattern_t *source,
1476 const cairo_path_fixed_t *path,
1477 const cairo_stroke_style_t *style,
1478 const cairo_matrix_t *ctm,
1479 const cairo_matrix_t *ctm_inverse,
1480 double tolerance,
1481 cairo_antialias_t antialias,
1482 const cairo_clip_t *clip)
1483 {
1484 return _cairo_compositor_stroke (get_compositor (surface), surface,
1485 op, source, path, style,
1486 ctm, ctm_inverse, tolerance, antialias,
1487 clip);
1488 }
1489
1490 static cairo_int_status_t
_cairo_gl_surface_fill(void * surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,const cairo_clip_t * clip)1491 _cairo_gl_surface_fill (void *surface,
1492 cairo_operator_t op,
1493 const cairo_pattern_t *source,
1494 const cairo_path_fixed_t*path,
1495 cairo_fill_rule_t fill_rule,
1496 double tolerance,
1497 cairo_antialias_t antialias,
1498 const cairo_clip_t *clip)
1499 {
1500 return _cairo_compositor_fill (get_compositor (surface), surface,
1501 op, source, path,
1502 fill_rule, tolerance, antialias,
1503 clip);
1504 }
1505
1506 static cairo_int_status_t
_cairo_gl_surface_glyphs(void * surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_glyph_t * glyphs,int num_glyphs,cairo_scaled_font_t * font,const cairo_clip_t * clip)1507 _cairo_gl_surface_glyphs (void *surface,
1508 cairo_operator_t op,
1509 const cairo_pattern_t *source,
1510 cairo_glyph_t *glyphs,
1511 int num_glyphs,
1512 cairo_scaled_font_t *font,
1513 const cairo_clip_t *clip)
1514 {
1515 return _cairo_compositor_glyphs (get_compositor (surface), surface,
1516 op, source, glyphs, num_glyphs, font,
1517 clip);
1518 }
1519
1520 static const cairo_surface_backend_t _cairo_gl_surface_backend = {
1521 CAIRO_SURFACE_TYPE_GL,
1522 _cairo_gl_surface_finish,
1523 _cairo_default_context_create,
1524
1525 _cairo_gl_surface_create_similar,
1526 NULL, /* similar image */
1527 _cairo_gl_surface_map_to_image,
1528 _cairo_gl_surface_unmap_image,
1529
1530 _cairo_gl_surface_source,
1531 _cairo_gl_surface_acquire_source_image,
1532 _cairo_gl_surface_release_source_image,
1533 NULL, /* snapshot */
1534
1535 NULL, /* copy_page */
1536 NULL, /* show_page */
1537
1538 _cairo_gl_surface_get_extents,
1539 _cairo_image_surface_get_font_options,
1540
1541 _cairo_gl_surface_flush,
1542 NULL, /* mark_dirty_rectangle */
1543
1544 _cairo_gl_surface_paint,
1545 _cairo_gl_surface_mask,
1546 _cairo_gl_surface_stroke,
1547 _cairo_gl_surface_fill,
1548 NULL, /* fill/stroke */
1549 _cairo_gl_surface_glyphs,
1550 };
1551