1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Eric Anholt
4 * Copyright © 2009 Chris Wilson
5 * Copyright © 2005,2010 Red Hat, Inc
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.
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
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/
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.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is Red Hat, Inc.
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>
43 #include "cairo-gl-private.h"
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"
52 static const cairo_surface_backend_t _cairo_gl_surface_backend
;
55 _cairo_gl_surface_flush (void *abstract_surface
, unsigned flags
);
57 static cairo_bool_t
_cairo_surface_is_gl (cairo_surface_t
*surface
)
59 return surface
->backend
== &_cairo_gl_surface_backend
;
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
)
68 cairo_bool_t is_little_endian
= _cairo_is_little_endian ();
72 switch ((int) pixman_format
) {
74 *internal_format
= GL_BGRA
;
76 *type
= GL_UNSIGNED_BYTE
;
77 *needs_swap
= !is_little_endian
;
81 *internal_format
= GL_BGRA
;
83 *type
= GL_UNSIGNED_BYTE
;
85 *needs_swap
= !is_little_endian
;
89 *internal_format
= GL_RGBA
;
91 *type
= GL_UNSIGNED_BYTE
;
92 *needs_swap
= !is_little_endian
;
96 *internal_format
= GL_RGBA
;
98 *type
= GL_UNSIGNED_BYTE
;
100 *needs_swap
= !is_little_endian
;
103 case PIXMAN_b8g8r8a8
:
104 *internal_format
= GL_BGRA
;
106 *type
= GL_UNSIGNED_BYTE
;
107 *needs_swap
= is_little_endian
;
110 case PIXMAN_b8g8r8x8
:
111 *internal_format
= GL_BGRA
;
113 *type
= GL_UNSIGNED_BYTE
;
115 *needs_swap
= is_little_endian
;
119 *internal_format
= GL_RGB
;
121 *type
= GL_UNSIGNED_BYTE
;
122 *needs_swap
= is_little_endian
;
126 *internal_format
= GL_RGB
;
128 *type
= GL_UNSIGNED_BYTE
;
129 *needs_swap
= !is_little_endian
;
133 *internal_format
= GL_RGB
;
135 *type
= GL_UNSIGNED_SHORT_5_6_5
;
140 *internal_format
= GL_RGB
;
142 *type
= GL_UNSIGNED_SHORT_5_6_5
;
146 case PIXMAN_a1b5g5r5
:
147 *internal_format
= GL_RGBA
;
149 *type
= GL_UNSIGNED_SHORT_5_5_5_1
;
153 case PIXMAN_x1b5g5r5
:
154 *internal_format
= GL_RGBA
;
156 *type
= GL_UNSIGNED_SHORT_5_5_5_1
;
162 *internal_format
= GL_ALPHA
;
164 *type
= GL_UNSIGNED_BYTE
;
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
)
182 switch (pixman_format
) {
183 case PIXMAN_a8r8g8b8
:
184 *internal_format
= GL_RGBA
;
186 *type
= GL_UNSIGNED_INT_8_8_8_8_REV
;
188 case PIXMAN_x8r8g8b8
:
189 *internal_format
= GL_RGB
;
191 *type
= GL_UNSIGNED_INT_8_8_8_8_REV
;
194 case PIXMAN_a8b8g8r8
:
195 *internal_format
= GL_RGBA
;
197 *type
= GL_UNSIGNED_INT_8_8_8_8_REV
;
199 case PIXMAN_x8b8g8r8
:
200 *internal_format
= GL_RGB
;
202 *type
= GL_UNSIGNED_INT_8_8_8_8_REV
;
205 case PIXMAN_b8g8r8a8
:
206 *internal_format
= GL_RGBA
;
208 *type
= GL_UNSIGNED_INT_8_8_8_8
;
210 case PIXMAN_b8g8r8x8
:
211 *internal_format
= GL_RGB
;
213 *type
= GL_UNSIGNED_INT_8_8_8_8
;
217 *internal_format
= GL_RGB
;
219 *type
= GL_UNSIGNED_BYTE
;
222 *internal_format
= GL_RGB
;
224 *type
= GL_UNSIGNED_BYTE
;
227 *internal_format
= GL_RGB
;
229 *type
= GL_UNSIGNED_SHORT_5_6_5
;
232 *internal_format
= GL_RGB
;
234 *type
= GL_UNSIGNED_SHORT_5_6_5_REV
;
236 case PIXMAN_a1r5g5b5
:
237 *internal_format
= GL_RGBA
;
239 *type
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
241 case PIXMAN_x1r5g5b5
:
242 *internal_format
= GL_RGB
;
244 *type
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
247 case PIXMAN_a1b5g5r5
:
248 *internal_format
= GL_RGBA
;
250 *type
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
252 case PIXMAN_x1b5g5r5
:
253 *internal_format
= GL_RGB
;
255 *type
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
259 *internal_format
= GL_ALPHA
;
261 *type
= GL_UNSIGNED_BYTE
;
264 #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,27,2)
265 case PIXMAN_a8r8g8b8_sRGB
:
267 case PIXMAN_a2b10g10r10
:
268 case PIXMAN_x2b10g10r10
:
269 case PIXMAN_a4r4g4b4
:
270 case PIXMAN_x4r4g4b4
:
271 case PIXMAN_a4b4g4r4
:
272 case PIXMAN_x4b4g4r4
:
275 case PIXMAN_a2r2g2b2
:
276 case PIXMAN_a2b2g2r2
:
279 /* case PIXMAN_x4c4: */
284 case PIXMAN_a1r1g1b1
:
285 case PIXMAN_a1b1g1r1
:
292 case PIXMAN_x2r10g10b10
:
293 case PIXMAN_a2r10g10b10
:
294 case PIXMAN_r8g8b8x8
:
295 case PIXMAN_r8g8b8a8
:
296 case PIXMAN_x14r6g6b6
:
303 * Extracts pixel data from an image surface.
305 static cairo_status_t
306 _cairo_gl_surface_extract_image_data (cairo_image_surface_t
*image
,
308 int width
, int height
,
311 int cpp
= PIXMAN_FORMAT_BPP (image
->pixman_format
) / 8;
312 char *data
= _cairo_malloc_ab (width
* height
, cpp
);
314 unsigned char *src
= image
->data
+ y
* image
->stride
+ x
* cpp
;
317 if (unlikely (data
== NULL
))
318 return CAIRO_STATUS_NO_MEMORY
;
320 for (i
= 0; i
< height
; i
++) {
321 memcpy (dst
, src
, width
* cpp
);
322 src
+= image
->stride
;
328 return CAIRO_STATUS_SUCCESS
;
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
)
338 if (flavor
== CAIRO_GL_FLAVOR_DESKTOP
)
339 return _cairo_gl_get_image_format_and_type_gl (pixman_format
,
340 internal_format
, format
,
344 return _cairo_gl_get_image_format_and_type_gles2 (pixman_format
,
345 internal_format
, format
,
352 _cairo_gl_operator_is_supported (cairo_operator_t op
)
354 return op
< CAIRO_OPERATOR_SATURATE
;
358 _cairo_gl_surface_embedded_operand_init (cairo_gl_surface_t
*surface
)
360 cairo_gl_operand_t
*operand
= &surface
->operand
;
361 cairo_surface_attributes_t
*attributes
= &operand
->texture
.attributes
;
363 memset (operand
, 0, sizeof (cairo_gl_operand_t
));
365 operand
->type
= CAIRO_GL_OPERAND_TEXTURE
;
366 operand
->texture
.surface
= surface
;
367 operand
->texture
.tex
= surface
->tex
;
369 if (_cairo_gl_device_requires_power_of_two_textures (surface
->base
.device
)) {
370 cairo_matrix_init_identity (&attributes
->matrix
);
372 cairo_matrix_init_scale (&attributes
->matrix
,
373 1.0 / surface
->width
,
374 1.0 / surface
->height
);
377 attributes
->extend
= CAIRO_EXTEND_NONE
;
378 attributes
->filter
= CAIRO_FILTER_NEAREST
;
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
)
387 assert (width
> 0 && height
> 0);
389 _cairo_surface_init (&surface
->base
,
390 &_cairo_gl_surface_backend
,
394 surface
->width
= width
;
395 surface
->height
= height
;
396 surface
->needs_update
= FALSE
;
398 _cairo_gl_surface_embedded_operand_init (surface
);
402 _cairo_gl_surface_size_valid_for_context (cairo_gl_context_t
*ctx
,
403 int width
, int height
)
405 return width
> 0 && height
> 0 &&
406 width
<= ctx
->max_framebuffer_size
&&
407 height
<= ctx
->max_framebuffer_size
;
411 _cairo_gl_surface_size_valid (cairo_gl_surface_t
*surface
,
412 int width
, int height
)
414 cairo_gl_context_t
*ctx
= (cairo_gl_context_t
*)surface
->base
.device
;
415 return _cairo_gl_surface_size_valid_for_context (ctx
, width
, height
);
418 static cairo_surface_t
*
419 _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t
*ctx
,
420 cairo_content_t content
,
425 cairo_gl_surface_t
*surface
;
427 surface
= calloc (1, sizeof (cairo_gl_surface_t
));
428 if (unlikely (surface
== NULL
))
429 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
432 _cairo_gl_surface_init (&ctx
->base
, surface
, content
, width
, height
);
434 surface
->supports_msaa
= ctx
->supports_msaa
;
435 surface
->supports_stencil
= TRUE
;
437 /* Create the texture used to store the surface's data. */
438 _cairo_gl_context_activate (ctx
, CAIRO_GL_TEX_TEMP
);
439 glBindTexture (ctx
->tex_target
, surface
->tex
);
440 glTexParameteri (ctx
->tex_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
441 glTexParameteri (ctx
->tex_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
443 return &surface
->base
;
446 static cairo_surface_t
*
447 _create_scratch_internal (cairo_gl_context_t
*ctx
,
448 cairo_content_t content
,
451 cairo_bool_t for_caching
)
453 cairo_gl_surface_t
*surface
;
457 glGenTextures (1, &tex
);
458 surface
= (cairo_gl_surface_t
*)
459 _cairo_gl_surface_create_scratch_for_texture (ctx
, content
,
461 if (unlikely (surface
->base
.status
))
462 return &surface
->base
;
464 surface
->owns_tex
= TRUE
;
466 /* adjust the texture size after setting our real extents */
475 case CAIRO_CONTENT_COLOR_ALPHA
:
478 case CAIRO_CONTENT_ALPHA
:
479 /* When using GL_ALPHA, compositing doesn't work properly, but for
480 * caching surfaces, we are just uploading pixel data, so it isn't
487 case CAIRO_CONTENT_COLOR
:
488 /* GL_RGB is almost what we want here -- sampling 1 alpha when
489 * texturing, using 1 as destination alpha factor in blending,
490 * etc. However, when filtering with GL_CLAMP_TO_BORDER, the
491 * alpha channel of the border color will also be clamped to
492 * 1, when we actually want the border color we explicitly
493 * specified. So, we have to store RGBA, and fill the alpha
494 * channel with 1 when blending.
500 glTexImage2D (ctx
->tex_target
, 0, format
, width
, height
, 0,
501 format
, GL_UNSIGNED_BYTE
, NULL
);
503 return &surface
->base
;
507 _cairo_gl_surface_create_scratch (cairo_gl_context_t
*ctx
,
508 cairo_content_t content
,
512 return _create_scratch_internal (ctx
, content
, width
, height
, FALSE
);
516 _cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t
*ctx
,
517 cairo_content_t content
,
521 return _create_scratch_internal (ctx
, content
, width
, height
, TRUE
);
524 static cairo_status_t
525 _cairo_gl_surface_clear (cairo_gl_surface_t
*surface
,
526 const cairo_color_t
*color
)
528 cairo_gl_context_t
*ctx
;
529 cairo_status_t status
;
532 status
= _cairo_gl_context_acquire (surface
->base
.device
, &ctx
);
533 if (unlikely (status
))
536 _cairo_gl_context_set_destination (ctx
, surface
, surface
->msaa_active
);
537 if (surface
->base
.content
& CAIRO_CONTENT_COLOR
) {
538 r
= color
->red
* color
->alpha
;
539 g
= color
->green
* color
->alpha
;
540 b
= color
->blue
* color
->alpha
;
544 if (surface
->base
.content
& CAIRO_CONTENT_ALPHA
) {
550 glDisable (GL_SCISSOR_TEST
);
551 glClearColor (r
, g
, b
, a
);
552 glClear (GL_COLOR_BUFFER_BIT
);
555 surface
->base
.is_clear
= TRUE
;
557 return _cairo_gl_context_release (ctx
, status
);
560 static cairo_surface_t
*
561 _cairo_gl_surface_create_and_clear_scratch (cairo_gl_context_t
*ctx
,
562 cairo_content_t content
,
566 cairo_gl_surface_t
*surface
;
567 cairo_int_status_t status
;
569 surface
= (cairo_gl_surface_t
*)
570 _cairo_gl_surface_create_scratch (ctx
, content
, width
, height
);
571 if (unlikely (surface
->base
.status
))
572 return &surface
->base
;
574 /* Cairo surfaces start out initialized to transparent (black) */
575 status
= _cairo_gl_surface_clear (surface
, CAIRO_COLOR_TRANSPARENT
);
576 if (unlikely (status
)) {
577 cairo_surface_destroy (&surface
->base
);
578 return _cairo_surface_create_in_error (status
);
581 return &surface
->base
;
585 cairo_gl_surface_create (cairo_device_t
*abstract_device
,
586 cairo_content_t content
,
590 cairo_gl_context_t
*ctx
;
591 cairo_gl_surface_t
*surface
;
592 cairo_status_t status
;
594 if (! CAIRO_CONTENT_VALID (content
))
595 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT
));
597 if (abstract_device
== NULL
)
598 return _cairo_image_surface_create_with_content (content
, width
, height
);
600 if (abstract_device
->status
)
601 return _cairo_surface_create_in_error (abstract_device
->status
);
603 if (abstract_device
->backend
->type
!= CAIRO_DEVICE_TYPE_GL
)
604 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
));
606 status
= _cairo_gl_context_acquire (abstract_device
, &ctx
);
607 if (unlikely (status
))
608 return _cairo_surface_create_in_error (status
);
610 if (! _cairo_gl_surface_size_valid_for_context (ctx
, width
, height
)) {
611 status
= _cairo_gl_context_release (ctx
, status
);
612 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE
));
615 surface
= (cairo_gl_surface_t
*)
616 _cairo_gl_surface_create_and_clear_scratch (ctx
, content
, width
, height
);
617 if (unlikely (surface
->base
.status
)) {
618 status
= _cairo_gl_context_release (ctx
, surface
->base
.status
);
619 cairo_surface_destroy (&surface
->base
);
620 return _cairo_surface_create_in_error (status
);
623 status
= _cairo_gl_context_release (ctx
, status
);
624 if (unlikely (status
)) {
625 cairo_surface_destroy (&surface
->base
);
626 return _cairo_surface_create_in_error (status
);
629 return &surface
->base
;
631 slim_hidden_def (cairo_gl_surface_create
);
634 * cairo_gl_surface_create_for_texture:
635 * @content: type of content in the surface
636 * @tex: name of texture to use for storage of surface pixels
637 * @width: width of the surface, in pixels
638 * @height: height of the surface, in pixels
640 * Creates a GL surface for the specified texture with the specified
641 * content and dimensions. The texture must be kept around until the
642 * #cairo_surface_t is destroyed or cairo_surface_finish() is called
643 * on the surface. The initial contents of @tex will be used as the
644 * initial image contents; you must explicitly clear the buffer,
645 * using, for example, cairo_rectangle() and cairo_fill() if you want
646 * it cleared. The format of @tex should be compatible with @content,
647 * in the sense that it must have the color components required by
650 * Return value: a pointer to the newly created surface. The caller
651 * owns the surface and should call cairo_surface_destroy() when done
654 * This function always returns a valid pointer, but it will return a
655 * pointer to a "nil" surface if an error such as out of memory
656 * occurs. You can use cairo_surface_status() to check for this.
661 cairo_gl_surface_create_for_texture (cairo_device_t
*abstract_device
,
662 cairo_content_t content
,
667 cairo_gl_context_t
*ctx
;
668 cairo_gl_surface_t
*surface
;
669 cairo_status_t status
;
671 if (! CAIRO_CONTENT_VALID (content
))
672 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT
));
674 if (abstract_device
== NULL
)
675 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER
));
677 if (abstract_device
->status
)
678 return _cairo_surface_create_in_error (abstract_device
->status
);
680 if (abstract_device
->backend
->type
!= CAIRO_DEVICE_TYPE_GL
)
681 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH
));
683 status
= _cairo_gl_context_acquire (abstract_device
, &ctx
);
684 if (unlikely (status
))
685 return _cairo_surface_create_in_error (status
);
687 if (! _cairo_gl_surface_size_valid_for_context (ctx
, width
, height
)) {
688 status
= _cairo_gl_context_release (ctx
, status
);
689 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE
));
692 surface
= (cairo_gl_surface_t
*)
693 _cairo_gl_surface_create_scratch_for_texture (ctx
, content
,
695 status
= _cairo_gl_context_release (ctx
, status
);
697 return &surface
->base
;
699 slim_hidden_def (cairo_gl_surface_create_for_texture
);
703 cairo_gl_surface_set_size (cairo_surface_t
*abstract_surface
,
707 cairo_gl_surface_t
*surface
= (cairo_gl_surface_t
*) abstract_surface
;
709 if (unlikely (abstract_surface
->status
))
711 if (unlikely (abstract_surface
->finished
)) {
712 _cairo_surface_set_error (abstract_surface
,
713 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED
));
717 if (! _cairo_surface_is_gl (abstract_surface
) ||
718 _cairo_gl_surface_is_texture (surface
)) {
719 _cairo_surface_set_error (abstract_surface
,
720 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
));
724 if (surface
->width
!= width
|| surface
->height
!= height
) {
725 surface
->needs_update
= TRUE
;
726 surface
->width
= width
;
727 surface
->height
= height
;
732 cairo_gl_surface_get_width (cairo_surface_t
*abstract_surface
)
734 cairo_gl_surface_t
*surface
= (cairo_gl_surface_t
*) abstract_surface
;
736 if (! _cairo_surface_is_gl (abstract_surface
))
739 return surface
->width
;
743 cairo_gl_surface_get_height (cairo_surface_t
*abstract_surface
)
745 cairo_gl_surface_t
*surface
= (cairo_gl_surface_t
*) abstract_surface
;
747 if (! _cairo_surface_is_gl (abstract_surface
))
750 return surface
->height
;
754 cairo_gl_surface_swapbuffers (cairo_surface_t
*abstract_surface
)
756 cairo_gl_surface_t
*surface
= (cairo_gl_surface_t
*) abstract_surface
;
758 if (unlikely (abstract_surface
->status
))
760 if (unlikely (abstract_surface
->finished
)) {
761 _cairo_surface_set_error (abstract_surface
,
762 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED
));
766 if (! _cairo_surface_is_gl (abstract_surface
)) {
767 _cairo_surface_set_error (abstract_surface
,
768 CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
772 if (! _cairo_gl_surface_is_texture (surface
)) {
773 cairo_gl_context_t
*ctx
;
774 cairo_status_t status
;
776 status
= _cairo_gl_context_acquire (surface
->base
.device
, &ctx
);
777 if (unlikely (status
))
780 /* For swapping on EGL, at least, we need a valid context/target. */
781 _cairo_gl_context_set_destination (ctx
, surface
, FALSE
);
782 /* And in any case we should flush any pending operations. */
783 _cairo_gl_composite_flush (ctx
);
785 ctx
->swap_buffers (ctx
, surface
);
787 status
= _cairo_gl_context_release (ctx
, status
);
789 status
= _cairo_surface_set_error (abstract_surface
, status
);
793 static cairo_surface_t
*
794 _cairo_gl_surface_create_similar (void *abstract_surface
,
795 cairo_content_t content
,
799 cairo_surface_t
*surface
= abstract_surface
;
800 cairo_gl_context_t
*ctx
;
801 cairo_status_t status
;
803 if (! _cairo_gl_surface_size_valid (abstract_surface
, width
, height
))
804 return _cairo_image_surface_create_with_content (content
, width
, height
);
806 status
= _cairo_gl_context_acquire (surface
->device
, &ctx
);
807 if (unlikely (status
))
808 return _cairo_surface_create_in_error (status
);
810 surface
= _cairo_gl_surface_create_and_clear_scratch (ctx
, content
, width
, height
);
812 status
= _cairo_gl_context_release (ctx
, status
);
813 if (unlikely (status
)) {
814 cairo_surface_destroy (surface
);
815 return _cairo_surface_create_in_error (status
);
821 static cairo_int_status_t
822 _cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t
*dst
,
823 cairo_gl_context_t
*ctx
,
825 int width
, int height
)
827 cairo_gl_composite_t setup
;
828 cairo_status_t status
;
830 _cairo_gl_composite_flush (ctx
);
831 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_TRUE
);
833 status
= _cairo_gl_composite_init (&setup
, CAIRO_OPERATOR_SOURCE
,
835 if (unlikely (status
))
838 _cairo_gl_composite_set_solid_source (&setup
, CAIRO_COLOR_BLACK
);
840 status
= _cairo_gl_composite_begin (&setup
, &ctx
);
841 if (unlikely (status
))
844 _cairo_gl_context_emit_rect (ctx
, x
, y
, x
+ width
, y
+ height
);
846 status
= _cairo_gl_context_release (ctx
, status
);
849 _cairo_gl_composite_fini (&setup
);
851 _cairo_gl_composite_flush (ctx
);
852 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
858 _cairo_gl_surface_draw_image (cairo_gl_surface_t
*dst
,
859 cairo_image_surface_t
*src
,
860 int src_x
, int src_y
,
861 int width
, int height
,
862 int dst_x
, int dst_y
,
863 cairo_bool_t force_flush
)
865 GLenum internal_format
, format
, type
;
866 cairo_bool_t has_alpha
, needs_swap
;
867 cairo_image_surface_t
*clone
= NULL
;
868 cairo_gl_context_t
*ctx
;
870 cairo_int_status_t status
= CAIRO_INT_STATUS_SUCCESS
;
872 status
= _cairo_gl_context_acquire (dst
->base
.device
, &ctx
);
873 if (unlikely (status
))
876 if (! _cairo_gl_get_image_format_and_type (ctx
->gl_flavor
,
884 cairo_bool_t is_supported
;
886 clone
= _cairo_image_surface_coerce (src
);
887 if (unlikely (status
= clone
->base
.status
))
891 _cairo_gl_get_image_format_and_type (ctx
->gl_flavor
,
892 clone
->pixman_format
,
898 assert (is_supported
);
899 assert (!needs_swap
);
903 cpp
= PIXMAN_FORMAT_BPP (src
->pixman_format
) / 8;
906 status
= _cairo_gl_surface_flush (&dst
->base
, 0);
907 if (unlikely (status
))
911 if (_cairo_gl_surface_is_texture (dst
)) {
912 void *data_start
= src
->data
+ src_y
* src
->stride
+ src_x
* cpp
;
913 void *data_start_gles2
= NULL
;
916 * Due to GL_UNPACK_ROW_LENGTH missing in GLES2 we have to extract the
917 * image data ourselves in some cases. In particular, we must extract
919 * a. we don't want full-length lines or
920 * b. the row stride cannot be handled by GL itself using a 4 byte
921 * alignment constraint
923 if (src
->stride
< 0 ||
924 (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
&&
925 (src
->width
* cpp
< src
->stride
- 3 ||
926 width
!= src
->width
)))
928 glPixelStorei (GL_UNPACK_ALIGNMENT
, 1);
929 status
= _cairo_gl_surface_extract_image_data (src
, src_x
, src_y
,
932 if (unlikely (status
))
935 data_start
= data_start_gles2
;
939 glPixelStorei (GL_UNPACK_ALIGNMENT
, 4);
940 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
)
941 glPixelStorei (GL_UNPACK_ROW_LENGTH
, src
->stride
/ cpp
);
944 _cairo_gl_context_activate (ctx
, CAIRO_GL_TEX_TEMP
);
945 glBindTexture (ctx
->tex_target
, dst
->tex
);
946 glTexParameteri (ctx
->tex_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
947 glTexParameteri (ctx
->tex_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
948 glTexSubImage2D (ctx
->tex_target
, 0,
949 dst_x
, dst_y
, width
, height
,
950 format
, type
, data_start
);
952 free (data_start_gles2
);
954 /* If we just treated some rgb-only data as rgba, then we have to
955 * go back and fix up the alpha channel where we filled in this
959 _cairo_gl_surface_fill_alpha_channel (dst
, ctx
,
964 cairo_surface_t
*tmp
;
966 tmp
= _cairo_gl_surface_create_scratch (ctx
,
969 if (unlikely (tmp
->status
))
972 status
= _cairo_gl_surface_draw_image ((cairo_gl_surface_t
*) tmp
,
977 if (status
== CAIRO_INT_STATUS_SUCCESS
) {
978 cairo_surface_pattern_t tmp_pattern
;
979 cairo_rectangle_int_t r
;
982 _cairo_pattern_init_for_surface (&tmp_pattern
, tmp
);
983 cairo_matrix_init_translate (&tmp_pattern
.base
.matrix
,
985 tmp_pattern
.base
.filter
= CAIRO_FILTER_NEAREST
;
986 tmp_pattern
.base
.extend
= CAIRO_EXTEND_NONE
;
992 clip
= _cairo_clip_intersect_rectangle (NULL
, &r
);
993 status
= _cairo_surface_paint (&dst
->base
,
994 CAIRO_OPERATOR_SOURCE
,
997 _cairo_clip_destroy (clip
);
998 _cairo_pattern_fini (&tmp_pattern
.base
);
1001 cairo_surface_destroy (tmp
);
1005 status
= _cairo_gl_context_release (ctx
, status
);
1008 cairo_surface_destroy (&clone
->base
);
1013 static int _cairo_gl_surface_flavor (cairo_gl_surface_t
*surface
)
1015 cairo_gl_context_t
*ctx
= (cairo_gl_context_t
*)surface
->base
.device
;
1016 return ctx
->gl_flavor
;
1019 static cairo_status_t
1020 _cairo_gl_surface_finish (void *abstract_surface
)
1022 cairo_gl_surface_t
*surface
= abstract_surface
;
1023 cairo_status_t status
;
1024 cairo_gl_context_t
*ctx
;
1026 status
= _cairo_gl_context_acquire (surface
->base
.device
, &ctx
);
1027 if (unlikely (status
))
1030 if (ctx
->operands
[CAIRO_GL_TEX_SOURCE
].type
== CAIRO_GL_OPERAND_TEXTURE
&&
1031 ctx
->operands
[CAIRO_GL_TEX_SOURCE
].texture
.surface
== surface
)
1032 _cairo_gl_context_destroy_operand (ctx
, CAIRO_GL_TEX_SOURCE
);
1033 if (ctx
->operands
[CAIRO_GL_TEX_MASK
].type
== CAIRO_GL_OPERAND_TEXTURE
&&
1034 ctx
->operands
[CAIRO_GL_TEX_MASK
].texture
.surface
== surface
)
1035 _cairo_gl_context_destroy_operand (ctx
, CAIRO_GL_TEX_MASK
);
1036 if (ctx
->current_target
== surface
)
1037 ctx
->current_target
= NULL
;
1040 ctx
->dispatch
.DeleteFramebuffers (1, &surface
->fb
);
1041 if (surface
->depth_stencil
)
1042 ctx
->dispatch
.DeleteRenderbuffers (1, &surface
->depth_stencil
);
1043 if (surface
->owns_tex
)
1044 glDeleteTextures (1, &surface
->tex
);
1046 if (surface
->msaa_depth_stencil
)
1047 ctx
->dispatch
.DeleteRenderbuffers (1, &surface
->msaa_depth_stencil
);
1049 #if CAIRO_HAS_GL_SURFACE
1050 if (surface
->msaa_fb
)
1051 ctx
->dispatch
.DeleteFramebuffers (1, &surface
->msaa_fb
);
1052 if (surface
->msaa_rb
)
1053 ctx
->dispatch
.DeleteRenderbuffers (1, &surface
->msaa_rb
);
1056 _cairo_clip_destroy (surface
->clip_on_stencil_buffer
);
1058 return _cairo_gl_context_release (ctx
, status
);
1061 static cairo_image_surface_t
*
1062 _cairo_gl_surface_map_to_image (void *abstract_surface
,
1063 const cairo_rectangle_int_t
*extents
)
1065 cairo_gl_surface_t
*surface
= abstract_surface
;
1066 cairo_image_surface_t
*image
;
1067 cairo_gl_context_t
*ctx
;
1068 GLenum format
, type
;
1069 pixman_format_code_t pixman_format
;
1071 cairo_bool_t flipped
, mesa_invert
;
1072 cairo_status_t status
;
1075 status
= _cairo_gl_context_acquire (surface
->base
.device
, &ctx
);
1076 if (unlikely (status
)) {
1077 return _cairo_image_surface_create_in_error (status
);
1080 /* Want to use a switch statement here but the compiler gets whiny. */
1081 if (surface
->base
.content
== CAIRO_CONTENT_COLOR_ALPHA
) {
1083 pixman_format
= PIXMAN_a8r8g8b8
;
1084 type
= GL_UNSIGNED_INT_8_8_8_8_REV
;
1086 } else if (surface
->base
.content
== CAIRO_CONTENT_COLOR
) {
1088 pixman_format
= PIXMAN_x8r8g8b8
;
1089 type
= GL_UNSIGNED_INT_8_8_8_8_REV
;
1091 } else if (surface
->base
.content
== CAIRO_CONTENT_ALPHA
) {
1093 pixman_format
= PIXMAN_a8
;
1094 type
= GL_UNSIGNED_BYTE
;
1101 if (_cairo_gl_surface_flavor (surface
) == CAIRO_GL_FLAVOR_ES
) {
1102 /* If only RGBA is supported, we must download data in a compatible
1103 * format. This means that pixman will convert the data on the CPU when
1104 * interacting with other image surfaces. For ALPHA, GLES2 does not
1105 * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
1106 * pixman image that is created has row_stride = row_width * bpp. */
1107 if (surface
->base
.content
== CAIRO_CONTENT_ALPHA
|| !ctx
->can_read_bgra
) {
1108 cairo_bool_t little_endian
= _cairo_is_little_endian ();
1111 if (surface
->base
.content
== CAIRO_CONTENT_COLOR
) {
1112 pixman_format
= little_endian
?
1113 PIXMAN_x8b8g8r8
: PIXMAN_r8g8b8x8
;
1115 pixman_format
= little_endian
?
1116 PIXMAN_a8b8g8r8
: PIXMAN_r8g8b8a8
;
1120 /* GLES2 only supports GL_UNSIGNED_BYTE. */
1121 type
= GL_UNSIGNED_BYTE
;
1125 image
= (cairo_image_surface_t
*)
1126 _cairo_image_surface_create_with_pixman_format (NULL
,
1131 if (unlikely (image
->base
.status
)) {
1132 status
= _cairo_gl_context_release (ctx
, status
);
1136 cairo_surface_set_device_offset (&image
->base
, -extents
->x
, -extents
->y
);
1138 /* If the original surface has not been modified or
1139 * is clear, we can avoid downloading data. */
1140 if (surface
->base
.is_clear
|| surface
->base
.serial
== 0) {
1141 status
= _cairo_gl_context_release (ctx
, status
);
1145 /* This is inefficient, as we'd rather just read the thing without making
1146 * it the destination. But then, this is the fallback path, so let's not
1147 * fall back instead.
1149 _cairo_gl_composite_flush (ctx
);
1150 _cairo_gl_context_set_destination (ctx
, surface
, FALSE
);
1152 flipped
= ! _cairo_gl_surface_is_texture (surface
);
1153 mesa_invert
= flipped
&& ctx
->has_mesa_pack_invert
;
1155 glPixelStorei (GL_PACK_ALIGNMENT
, 4);
1156 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
)
1157 glPixelStorei (GL_PACK_ROW_LENGTH
, image
->stride
/ cpp
);
1159 glPixelStorei (GL_PACK_INVERT_MESA
, 1);
1163 y
= surface
->height
- extents
->y
- extents
->height
;
1165 glReadPixels (extents
->x
, y
,
1166 extents
->width
, extents
->height
,
1167 format
, type
, image
->data
);
1169 glPixelStorei (GL_PACK_INVERT_MESA
, 0);
1171 status
= _cairo_gl_context_release (ctx
, status
);
1172 if (unlikely (status
)) {
1173 cairo_surface_destroy (&image
->base
);
1174 return _cairo_image_surface_create_in_error (status
);
1177 /* We must invert the image manualy if we lack GL_MESA_pack_invert */
1178 if (flipped
&& ! mesa_invert
) {
1179 uint8_t stack
[1024], *row
= stack
;
1180 uint8_t *top
= image
->data
;
1181 uint8_t *bot
= image
->data
+ (image
->height
-1)*image
->stride
;
1183 if (image
->stride
> (int)sizeof(stack
)) {
1184 row
= malloc (image
->stride
);
1185 if (unlikely (row
== NULL
)) {
1186 cairo_surface_destroy (&image
->base
);
1187 return _cairo_image_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1192 memcpy (row
, top
, image
->stride
);
1193 memcpy (top
, bot
, image
->stride
);
1194 memcpy (bot
, row
, image
->stride
);
1195 top
+= image
->stride
;
1196 bot
-= image
->stride
;
1203 image
->base
.is_clear
= FALSE
;
1207 static cairo_surface_t
*
1208 _cairo_gl_surface_source (void *abstract_surface
,
1209 cairo_rectangle_int_t
*extents
)
1211 cairo_gl_surface_t
*surface
= abstract_surface
;
1214 extents
->x
= extents
->y
= 0;
1215 extents
->width
= surface
->width
;
1216 extents
->height
= surface
->height
;
1219 return &surface
->base
;
1222 static cairo_status_t
1223 _cairo_gl_surface_acquire_source_image (void *abstract_surface
,
1224 cairo_image_surface_t
**image_out
,
1227 cairo_gl_surface_t
*surface
= abstract_surface
;
1228 cairo_rectangle_int_t extents
;
1230 *image_extra
= NULL
;
1232 extents
.x
= extents
.y
= 0;
1233 extents
.width
= surface
->width
;
1234 extents
.height
= surface
->height
;
1236 *image_out
= (cairo_image_surface_t
*)
1237 _cairo_gl_surface_map_to_image (surface
, &extents
);
1238 return (*image_out
)->base
.status
;
1242 _cairo_gl_surface_release_source_image (void *abstract_surface
,
1243 cairo_image_surface_t
*image
,
1246 cairo_surface_destroy (&image
->base
);
1249 static cairo_int_status_t
1250 _cairo_gl_surface_unmap_image (void *abstract_surface
,
1251 cairo_image_surface_t
*image
)
1253 cairo_int_status_t status
;
1255 status
= _cairo_gl_surface_draw_image (abstract_surface
, image
,
1257 image
->width
, image
->height
,
1258 image
->base
.device_transform_inverse
.x0
,
1259 image
->base
.device_transform_inverse
.y0
,
1262 cairo_surface_finish (&image
->base
);
1263 cairo_surface_destroy (&image
->base
);
1269 _cairo_gl_surface_get_extents (void *abstract_surface
,
1270 cairo_rectangle_int_t
*rectangle
)
1272 cairo_gl_surface_t
*surface
= abstract_surface
;
1276 rectangle
->width
= surface
->width
;
1277 rectangle
->height
= surface
->height
;
1282 static cairo_status_t
1283 _cairo_gl_surface_flush (void *abstract_surface
, unsigned flags
)
1285 cairo_gl_surface_t
*surface
= abstract_surface
;
1286 cairo_status_t status
;
1287 cairo_gl_context_t
*ctx
;
1290 return CAIRO_STATUS_SUCCESS
;
1292 status
= _cairo_gl_context_acquire (surface
->base
.device
, &ctx
);
1293 if (unlikely (status
))
1296 if ((ctx
->operands
[CAIRO_GL_TEX_SOURCE
].type
== CAIRO_GL_OPERAND_TEXTURE
&&
1297 ctx
->operands
[CAIRO_GL_TEX_SOURCE
].texture
.surface
== surface
) ||
1298 (ctx
->operands
[CAIRO_GL_TEX_MASK
].type
== CAIRO_GL_OPERAND_TEXTURE
&&
1299 ctx
->operands
[CAIRO_GL_TEX_MASK
].texture
.surface
== surface
) ||
1300 (ctx
->current_target
== surface
))
1301 _cairo_gl_composite_flush (ctx
);
1303 status
= _cairo_gl_surface_resolve_multisampling (surface
);
1305 return _cairo_gl_context_release (ctx
, status
);
1309 _cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t
*surface
)
1311 cairo_gl_context_t
*ctx
;
1312 cairo_int_status_t status
;
1314 if (! surface
->msaa_active
)
1315 return CAIRO_INT_STATUS_SUCCESS
;
1317 if (surface
->base
.device
== NULL
)
1318 return CAIRO_INT_STATUS_SUCCESS
;
1320 /* GLES surfaces do not need explicit resolution. */
1321 if (((cairo_gl_context_t
*) surface
->base
.device
)->gl_flavor
== CAIRO_GL_FLAVOR_ES
)
1322 return CAIRO_INT_STATUS_SUCCESS
;
1324 if (! _cairo_gl_surface_is_texture (surface
))
1325 return CAIRO_INT_STATUS_SUCCESS
;
1327 status
= _cairo_gl_context_acquire (surface
->base
.device
, &ctx
);
1328 if (unlikely (status
))
1331 ctx
->current_target
= surface
;
1333 #if CAIRO_HAS_GL_SURFACE
1334 _cairo_gl_context_bind_framebuffer (ctx
, surface
, FALSE
);
1337 status
= _cairo_gl_context_release (ctx
, status
);
1341 static const cairo_compositor_t
*
1342 get_compositor (cairo_gl_surface_t
*surface
)
1344 cairo_gl_context_t
*ctx
= (cairo_gl_context_t
*)surface
->base
.device
;
1345 return ctx
->compositor
;
1348 static cairo_int_status_t
1349 _cairo_gl_surface_paint (void *surface
,
1350 cairo_operator_t op
,
1351 const cairo_pattern_t
*source
,
1352 const cairo_clip_t
*clip
)
1354 /* simplify the common case of clearing the surface */
1356 if (op
== CAIRO_OPERATOR_CLEAR
)
1357 return _cairo_gl_surface_clear (surface
, CAIRO_COLOR_TRANSPARENT
);
1358 else if (source
->type
== CAIRO_PATTERN_TYPE_SOLID
&&
1359 (op
== CAIRO_OPERATOR_SOURCE
||
1360 (op
== CAIRO_OPERATOR_OVER
&& _cairo_pattern_is_opaque_solid (source
)))) {
1361 return _cairo_gl_surface_clear (surface
,
1362 &((cairo_solid_pattern_t
*) source
)->color
);
1366 return _cairo_compositor_paint (get_compositor (surface
), surface
,
1370 static cairo_int_status_t
1371 _cairo_gl_surface_mask (void *surface
,
1372 cairo_operator_t op
,
1373 const cairo_pattern_t
*source
,
1374 const cairo_pattern_t
*mask
,
1375 const cairo_clip_t
*clip
)
1377 return _cairo_compositor_mask (get_compositor (surface
), surface
,
1378 op
, source
, mask
, clip
);
1381 static cairo_int_status_t
1382 _cairo_gl_surface_stroke (void *surface
,
1383 cairo_operator_t op
,
1384 const cairo_pattern_t
*source
,
1385 const cairo_path_fixed_t
*path
,
1386 const cairo_stroke_style_t
*style
,
1387 const cairo_matrix_t
*ctm
,
1388 const cairo_matrix_t
*ctm_inverse
,
1390 cairo_antialias_t antialias
,
1391 const cairo_clip_t
*clip
)
1393 return _cairo_compositor_stroke (get_compositor (surface
), surface
,
1394 op
, source
, path
, style
,
1395 ctm
, ctm_inverse
, tolerance
, antialias
,
1399 static cairo_int_status_t
1400 _cairo_gl_surface_fill (void *surface
,
1401 cairo_operator_t op
,
1402 const cairo_pattern_t
*source
,
1403 const cairo_path_fixed_t
*path
,
1404 cairo_fill_rule_t fill_rule
,
1406 cairo_antialias_t antialias
,
1407 const cairo_clip_t
*clip
)
1409 return _cairo_compositor_fill (get_compositor (surface
), surface
,
1411 fill_rule
, tolerance
, antialias
,
1415 static cairo_int_status_t
1416 _cairo_gl_surface_glyphs (void *surface
,
1417 cairo_operator_t op
,
1418 const cairo_pattern_t
*source
,
1419 cairo_glyph_t
*glyphs
,
1421 cairo_scaled_font_t
*font
,
1422 const cairo_clip_t
*clip
)
1424 return _cairo_compositor_glyphs (get_compositor (surface
), surface
,
1425 op
, source
, glyphs
, num_glyphs
, font
,
1429 static const cairo_surface_backend_t _cairo_gl_surface_backend
= {
1430 CAIRO_SURFACE_TYPE_GL
,
1431 _cairo_gl_surface_finish
,
1432 _cairo_default_context_create
,
1434 _cairo_gl_surface_create_similar
,
1435 NULL
, /* similar image */
1436 _cairo_gl_surface_map_to_image
,
1437 _cairo_gl_surface_unmap_image
,
1439 _cairo_gl_surface_source
,
1440 _cairo_gl_surface_acquire_source_image
,
1441 _cairo_gl_surface_release_source_image
,
1442 NULL
, /* snapshot */
1444 NULL
, /* copy_page */
1445 NULL
, /* show_page */
1447 _cairo_gl_surface_get_extents
,
1448 _cairo_image_surface_get_font_options
,
1450 _cairo_gl_surface_flush
,
1451 NULL
, /* mark_dirty_rectangle */
1453 _cairo_gl_surface_paint
,
1454 _cairo_gl_surface_mask
,
1455 _cairo_gl_surface_stroke
,
1456 _cairo_gl_surface_fill
,
1457 NULL
, /* fill/stroke */
1458 _cairo_gl_surface_glyphs
,