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
6 * Copyright © 2010 Linaro Limited
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is Red Hat, Inc.
36 * Benjamin Otte <otte@gnome.org>
37 * Carl Worth <cworth@cworth.org>
38 * Chris Wilson <chris@chris-wilson.co.uk>
39 * Eric Anholt <eric@anholt.net>
40 * Alexandros Frantzis <alexandros.frantzis@linaro.org>
45 #include "cairo-error-private.h"
46 #include "cairo-gl-private.h"
48 #define MAX_MSAA_SAMPLES 4
51 _gl_lock (void *device
)
53 cairo_gl_context_t
*ctx
= (cairo_gl_context_t
*) device
;
59 _gl_unlock (void *device
)
61 cairo_gl_context_t
*ctx
= (cairo_gl_context_t
*) device
;
67 _gl_flush (void *device
)
69 cairo_gl_context_t
*ctx
;
70 cairo_status_t status
;
72 status
= _cairo_gl_context_acquire (device
, &ctx
);
73 if (unlikely (status
))
76 _cairo_gl_composite_flush (ctx
);
78 _cairo_gl_context_destroy_operand (ctx
, CAIRO_GL_TEX_SOURCE
);
79 _cairo_gl_context_destroy_operand (ctx
, CAIRO_GL_TEX_MASK
);
81 if (ctx
->clip_region
) {
82 cairo_region_destroy (ctx
->clip_region
);
83 ctx
->clip_region
= NULL
;
86 ctx
->current_target
= NULL
;
87 ctx
->current_operator
= -1;
89 ctx
->pre_shader
= NULL
;
90 _cairo_gl_set_shader (ctx
, NULL
);
92 ctx
->dispatch
.BindBuffer (GL_ARRAY_BUFFER
, 0);
94 glDisable (GL_SCISSOR_TEST
);
97 return _cairo_gl_context_release (ctx
, status
);
101 _gl_finish (void *device
)
103 cairo_gl_context_t
*ctx
= device
;
108 _cairo_cache_fini (&ctx
->gradients
);
110 _cairo_gl_context_fini_shaders (ctx
);
112 for (n
= 0; n
< ARRAY_LENGTH (ctx
->glyph_cache
); n
++)
113 _cairo_gl_glyph_cache_fini (ctx
, &ctx
->glyph_cache
[n
]);
119 _gl_destroy (void *device
)
121 cairo_gl_context_t
*ctx
= device
;
125 while (! cairo_list_is_empty (&ctx
->fonts
)) {
126 cairo_gl_font_t
*font
;
128 font
= cairo_list_first_entry (&ctx
->fonts
,
132 cairo_list_del (&font
->base
.link
);
133 cairo_list_del (&font
->link
);
137 _cairo_array_fini (&ctx
->tristrip_indices
);
139 cairo_region_destroy (ctx
->clip_region
);
140 _cairo_clip_destroy (ctx
->clip
);
149 static const cairo_device_backend_t _cairo_gl_device_backend
= {
150 CAIRO_DEVICE_TYPE_GL
,
155 _gl_flush
, /* flush */
161 _cairo_gl_msaa_compositor_enabled (void)
163 const char *env
= getenv ("CAIRO_GL_COMPOSITOR");
164 return env
&& strcmp(env
, "msaa") == 0;
168 test_can_read_bgra (cairo_gl_flavor_t gl_flavor
)
170 /* Desktop GL always supports BGRA formats. */
171 if (gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
)
174 assert (gl_flavor
== CAIRO_GL_FLAVOR_ES
);
176 /* For OpenGL ES we have to look for the specific extension and BGRA only
177 * matches cairo's integer packed bytes on little-endian machines. */
178 if (!_cairo_is_little_endian())
180 return _cairo_gl_has_extension ("EXT_read_format_bgra");
184 _cairo_gl_context_init (cairo_gl_context_t
*ctx
)
186 cairo_status_t status
;
187 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
188 int gl_version
= _cairo_gl_get_version ();
189 cairo_gl_flavor_t gl_flavor
= _cairo_gl_get_flavor ();
192 cairo_bool_t is_desktop
= gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
;
193 cairo_bool_t is_gles
= gl_flavor
== CAIRO_GL_FLAVOR_ES
;
195 _cairo_device_init (&ctx
->base
, &_cairo_gl_device_backend
);
197 /* XXX The choice of compositor should be made automatically at runtime.
198 * However, it is useful to force one particular compositor whilst
201 if (_cairo_gl_msaa_compositor_enabled ())
202 ctx
->compositor
= _cairo_gl_msaa_compositor_get ();
204 ctx
->compositor
= _cairo_gl_span_compositor_get ();
207 ctx
->thread_aware
= TRUE
;
209 memset (ctx
->glyph_cache
, 0, sizeof (ctx
->glyph_cache
));
210 cairo_list_init (&ctx
->fonts
);
212 /* Support only GL version >= 1.3 */
213 if (gl_version
< CAIRO_GL_VERSION_ENCODE (1, 3))
214 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR
);
216 /* Check for required extensions */
218 if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) {
219 ctx
->tex_target
= GL_TEXTURE_2D
;
220 ctx
->has_npot_repeat
= TRUE
;
221 } else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) {
222 ctx
->tex_target
= GL_TEXTURE_RECTANGLE
;
223 ctx
->has_npot_repeat
= FALSE
;
225 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR
);
227 ctx
->tex_target
= GL_TEXTURE_2D
;
228 if (_cairo_gl_has_extension ("GL_OES_texture_npot") ||
229 _cairo_gl_has_extension ("GL_IMG_texture_npot"))
230 ctx
->has_npot_repeat
= TRUE
;
232 ctx
->has_npot_repeat
= FALSE
;
235 if (is_desktop
&& gl_version
< CAIRO_GL_VERSION_ENCODE (2, 1) &&
236 ! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
237 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR
);
239 if (is_gles
&& ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
240 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR
);
242 ctx
->has_map_buffer
=
243 is_desktop
|| (is_gles
&& _cairo_gl_has_extension ("GL_OES_mapbuffer"));
245 ctx
->can_read_bgra
= test_can_read_bgra (gl_flavor
);
247 ctx
->has_mesa_pack_invert
=
248 _cairo_gl_has_extension ("GL_MESA_pack_invert");
250 ctx
->has_packed_depth_stencil
=
251 (is_desktop
&& _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
252 (is_gles
&& _cairo_gl_has_extension ("GL_OES_packed_depth_stencil"));
254 ctx
->num_samples
= 1;
256 #if CAIRO_HAS_GL_SURFACE
257 if (is_desktop
&& ctx
->has_packed_depth_stencil
&&
258 (gl_version
>= CAIRO_GL_VERSION_ENCODE (3, 0) ||
259 _cairo_gl_has_extension ("GL_ARB_framebuffer_object") ||
260 (_cairo_gl_has_extension ("GL_EXT_framebuffer_blit") &&
261 _cairo_gl_has_extension ("GL_EXT_framebuffer_multisample")))) {
262 glGetIntegerv(GL_MAX_SAMPLES_EXT
, &ctx
->num_samples
);
266 #if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
267 if (is_gles
&& ctx
->has_packed_depth_stencil
&&
268 _cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
269 glGetIntegerv(GL_MAX_SAMPLES_EXT
, &ctx
->num_samples
);
273 #if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_IMG)
274 if (is_gles
&& ctx
->has_packed_depth_stencil
&&
275 _cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture")) {
276 glGetIntegerv(GL_MAX_SAMPLES_IMG
, &ctx
->num_samples
);
280 ctx
->supports_msaa
= ctx
->num_samples
> 1;
281 if (ctx
->num_samples
> MAX_MSAA_SAMPLES
)
282 ctx
->num_samples
= MAX_MSAA_SAMPLES
;
285 ctx
->current_operator
= -1;
286 ctx
->gl_flavor
= gl_flavor
;
288 status
= _cairo_gl_context_init_shaders (ctx
);
289 if (unlikely (status
))
292 status
= _cairo_cache_init (&ctx
->gradients
,
293 _cairo_gl_gradient_equal
,
295 (cairo_destroy_func_t
) _cairo_gl_gradient_destroy
,
296 CAIRO_GL_GRADIENT_CACHE_SIZE
);
297 if (unlikely (status
))
300 ctx
->vbo_size
= _cairo_gl_get_vbo_size();
302 ctx
->vb
= malloc (ctx
->vbo_size
);
303 if (unlikely (ctx
->vb
== NULL
)) {
304 _cairo_cache_fini (&ctx
->gradients
);
305 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
308 ctx
->primitive_type
= CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES
;
309 _cairo_array_init (&ctx
->tristrip_indices
, sizeof (unsigned short));
311 /* PBO for any sort of texture upload */
312 dispatch
->GenBuffers (1, &ctx
->texture_load_pbo
);
314 ctx
->max_framebuffer_size
= 0;
315 glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE
, &ctx
->max_framebuffer_size
);
316 ctx
->max_texture_size
= 0;
317 glGetIntegerv (GL_MAX_TEXTURE_SIZE
, &ctx
->max_texture_size
);
318 ctx
->max_textures
= 0;
319 glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS
, &ctx
->max_textures
);
321 for (n
= 0; n
< ARRAY_LENGTH (ctx
->glyph_cache
); n
++)
322 _cairo_gl_glyph_cache_init (&ctx
->glyph_cache
[n
]);
324 return CAIRO_STATUS_SUCCESS
;
328 _cairo_gl_context_activate (cairo_gl_context_t
*ctx
,
329 cairo_gl_tex_t tex_unit
)
331 if (ctx
->max_textures
<= (GLint
) tex_unit
) {
333 _cairo_gl_composite_flush (ctx
);
334 _cairo_gl_context_destroy_operand (ctx
, ctx
->max_textures
- 1);
336 glActiveTexture (ctx
->max_textures
- 1);
338 glActiveTexture (GL_TEXTURE0
+ tex_unit
);
343 _get_depth_stencil_format (cairo_gl_context_t
*ctx
)
345 /* This is necessary to properly handle the situation where both
346 OpenGL and OpenGLES are active and returning a sane default. */
347 #if CAIRO_HAS_GL_SURFACE
348 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
)
349 return GL_DEPTH_STENCIL
;
352 #if CAIRO_HAS_GLESV2_SURFACE
353 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
)
354 return GL_DEPTH24_STENCIL8_OES
;
357 #if CAIRO_HAS_GL_SURFACE
358 return GL_DEPTH_STENCIL
;
359 #elif CAIRO_HAS_GLESV2_SURFACE
360 return GL_DEPTH24_STENCIL8_OES
;
364 #if CAIRO_HAS_GLESV2_SURFACE
366 _cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t
*ctx
,
367 cairo_gl_surface_t
*surface
)
369 if (surface
->msaa_active
)
372 ctx
->dispatch
.FramebufferTexture2DMultisample(GL_FRAMEBUFFER
,
373 GL_COLOR_ATTACHMENT0
,
379 /* From now on MSAA will always be active on this surface. */
380 surface
->msaa_active
= TRUE
;
385 _cairo_gl_ensure_framebuffer (cairo_gl_context_t
*ctx
,
386 cairo_gl_surface_t
*surface
)
389 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
391 if (likely (surface
->fb
))
394 /* Create a framebuffer object wrapping the texture so that we can render
397 dispatch
->GenFramebuffers (1, &surface
->fb
);
398 dispatch
->BindFramebuffer (GL_FRAMEBUFFER
, surface
->fb
);
400 /* Unlike for desktop GL we only maintain one multisampling framebuffer
401 for OpenGLES since the EXT_multisampled_render_to_texture extension
402 does not require an explicit multisample resolution. */
403 #if CAIRO_HAS_GLESV2_SURFACE
404 if (surface
->supports_msaa
&& _cairo_gl_msaa_compositor_enabled () &&
405 ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
) {
406 _cairo_gl_ensure_msaa_gles_framebuffer (ctx
, surface
);
409 dispatch
->FramebufferTexture2D (GL_FRAMEBUFFER
,
410 GL_COLOR_ATTACHMENT0
,
415 #if CAIRO_HAS_GL_SURFACE
416 glDrawBuffer (GL_COLOR_ATTACHMENT0
);
417 glReadBuffer (GL_COLOR_ATTACHMENT0
);
420 status
= dispatch
->CheckFramebufferStatus (GL_FRAMEBUFFER
);
421 if (status
!= GL_FRAMEBUFFER_COMPLETE
) {
424 //case GL_FRAMEBUFFER_UNDEFINED: str= "undefined"; break;
425 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
: str
= "incomplete attachment"; break;
426 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
: str
= "incomplete/missing attachment"; break;
427 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
: str
= "incomplete draw buffer"; break;
428 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
: str
= "incomplete read buffer"; break;
429 case GL_FRAMEBUFFER_UNSUPPORTED
: str
= "unsupported"; break;
430 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
: str
= "incomplete multiple"; break;
431 default: str
= "unknown error"; break;
435 "destination is framebuffer incomplete: %s [%#x]\n",
439 #if CAIRO_HAS_GL_SURFACE
441 _cairo_gl_ensure_multisampling (cairo_gl_context_t
*ctx
,
442 cairo_gl_surface_t
*surface
)
444 assert (surface
->supports_msaa
);
445 assert (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
);
447 if (surface
->msaa_fb
)
450 /* We maintain a separate framebuffer for multisampling operations.
451 This allows us to do a fast paint to the non-multisampling framebuffer
452 when mulitsampling is disabled. */
453 ctx
->dispatch
.GenFramebuffers (1, &surface
->msaa_fb
);
454 ctx
->dispatch
.BindFramebuffer (GL_FRAMEBUFFER
, surface
->msaa_fb
);
455 ctx
->dispatch
.GenRenderbuffers (1, &surface
->msaa_rb
);
456 ctx
->dispatch
.BindRenderbuffer (GL_RENDERBUFFER
, surface
->msaa_rb
);
458 /* FIXME: For now we assume that textures passed from the outside have GL_RGBA
459 format, but eventually we need to expose a way for the API consumer to pass
461 ctx
->dispatch
.RenderbufferStorageMultisample (GL_RENDERBUFFER
,
466 ctx
->dispatch
.FramebufferRenderbuffer (GL_FRAMEBUFFER
,
467 GL_COLOR_ATTACHMENT0
,
471 /* Cairo surfaces start out initialized to transparent (black) */
472 glDisable (GL_SCISSOR_TEST
);
473 glClearColor (0, 0, 0, 0);
474 glClear (GL_COLOR_BUFFER_BIT
);
479 _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t
*ctx
,
480 cairo_gl_surface_t
*surface
)
482 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
483 if (surface
->msaa_depth_stencil
)
486 _cairo_gl_ensure_framebuffer (ctx
, surface
);
487 #if CAIRO_HAS_GL_SURFACE
488 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
)
489 _cairo_gl_ensure_multisampling (ctx
, surface
);
492 dispatch
->GenRenderbuffers (1, &surface
->msaa_depth_stencil
);
493 dispatch
->BindRenderbuffer (GL_RENDERBUFFER
,
494 surface
->msaa_depth_stencil
);
496 dispatch
->RenderbufferStorageMultisample (GL_RENDERBUFFER
,
498 _get_depth_stencil_format (ctx
),
502 #if CAIRO_HAS_GL_SURFACE
503 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
) {
504 dispatch
->FramebufferRenderbuffer (GL_FRAMEBUFFER
,
505 GL_DEPTH_STENCIL_ATTACHMENT
,
507 surface
->msaa_depth_stencil
);
511 #if CAIRO_HAS_GLESV2_SURFACE
512 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
) {
513 dispatch
->FramebufferRenderbuffer (GL_FRAMEBUFFER
,
516 surface
->msaa_depth_stencil
);
517 dispatch
->FramebufferRenderbuffer (GL_FRAMEBUFFER
,
518 GL_STENCIL_ATTACHMENT
,
520 surface
->msaa_depth_stencil
);
524 if (dispatch
->CheckFramebufferStatus (GL_FRAMEBUFFER
) != GL_FRAMEBUFFER_COMPLETE
) {
525 dispatch
->DeleteRenderbuffers (1, &surface
->msaa_depth_stencil
);
526 surface
->msaa_depth_stencil
= 0;
534 _cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t
*ctx
,
535 cairo_gl_surface_t
*surface
)
537 cairo_gl_dispatch_t
*dispatch
= &ctx
->dispatch
;
539 if (surface
->depth_stencil
)
542 _cairo_gl_ensure_framebuffer (ctx
, surface
);
544 dispatch
->GenRenderbuffers (1, &surface
->depth_stencil
);
545 dispatch
->BindRenderbuffer (GL_RENDERBUFFER
, surface
->depth_stencil
);
546 dispatch
->RenderbufferStorage (GL_RENDERBUFFER
,
547 _get_depth_stencil_format (ctx
),
548 surface
->width
, surface
->height
);
550 dispatch
->FramebufferRenderbuffer (GL_FRAMEBUFFER
, GL_STENCIL_ATTACHMENT
,
551 GL_RENDERBUFFER
, surface
->depth_stencil
);
552 dispatch
->FramebufferRenderbuffer (GL_FRAMEBUFFER
, GL_DEPTH_ATTACHMENT
,
553 GL_RENDERBUFFER
, surface
->depth_stencil
);
554 if (dispatch
->CheckFramebufferStatus (GL_FRAMEBUFFER
) != GL_FRAMEBUFFER_COMPLETE
) {
555 dispatch
->DeleteRenderbuffers (1, &surface
->depth_stencil
);
556 surface
->depth_stencil
= 0;
564 _cairo_gl_ensure_stencil (cairo_gl_context_t
*ctx
,
565 cairo_gl_surface_t
*surface
)
567 if (! _cairo_gl_surface_is_texture (surface
))
568 return TRUE
; /* best guess for now, will check later */
569 if (! ctx
->has_packed_depth_stencil
)
572 if (surface
->msaa_active
)
573 return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx
, surface
);
575 return _cairo_gl_ensure_depth_stencil_buffer (ctx
, surface
);
579 * Stores a parallel projection transformation in matrix 'm',
580 * using column-major order.
582 * This is equivalent to:
587 * The calculation for the ortho tranformation was taken from the
591 _gl_identity_ortho (GLfloat
*m
,
592 GLfloat left
, GLfloat right
,
593 GLfloat bottom
, GLfloat top
)
595 #define M(row,col) m[col*4+row]
596 M(0,0) = 2.f
/ (right
- left
);
599 M(0,3) = -(right
+ left
) / (right
- left
);
602 M(1,1) = 2.f
/ (top
- bottom
);
604 M(1,3) = -(top
+ bottom
) / (top
- bottom
);
618 #if CAIRO_HAS_GL_SURFACE
620 bind_multisample_framebuffer (cairo_gl_context_t
*ctx
,
621 cairo_gl_surface_t
*surface
)
623 cairo_bool_t stencil_test_enabled
;
624 cairo_bool_t scissor_test_enabled
;
626 assert (surface
->supports_msaa
);
627 assert (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
);
629 _cairo_gl_ensure_framebuffer (ctx
, surface
);
630 _cairo_gl_ensure_multisampling (ctx
, surface
);
632 if (surface
->msaa_active
) {
633 glEnable (GL_MULTISAMPLE
);
634 ctx
->dispatch
.BindFramebuffer (GL_FRAMEBUFFER
, surface
->msaa_fb
);
638 _cairo_gl_composite_flush (ctx
);
640 stencil_test_enabled
= glIsEnabled (GL_STENCIL_TEST
);
641 scissor_test_enabled
= glIsEnabled (GL_SCISSOR_TEST
);
642 glDisable (GL_STENCIL_TEST
);
643 glDisable (GL_SCISSOR_TEST
);
645 glEnable (GL_MULTISAMPLE
);
647 /* The last time we drew to the surface, we were not using multisampling,
648 so we need to blit from the non-multisampling framebuffer into the
649 multisampling framebuffer. */
650 ctx
->dispatch
.BindFramebuffer (GL_DRAW_FRAMEBUFFER
, surface
->msaa_fb
);
651 ctx
->dispatch
.BindFramebuffer (GL_READ_FRAMEBUFFER
, surface
->fb
);
652 ctx
->dispatch
.BlitFramebuffer (0, 0, surface
->width
, surface
->height
,
653 0, 0, surface
->width
, surface
->height
,
654 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
655 ctx
->dispatch
.BindFramebuffer (GL_FRAMEBUFFER
, surface
->msaa_fb
);
657 if (stencil_test_enabled
)
658 glEnable (GL_STENCIL_TEST
);
659 if (scissor_test_enabled
)
660 glEnable (GL_SCISSOR_TEST
);
664 #if CAIRO_HAS_GL_SURFACE
666 bind_singlesample_framebuffer (cairo_gl_context_t
*ctx
,
667 cairo_gl_surface_t
*surface
)
669 cairo_bool_t stencil_test_enabled
;
670 cairo_bool_t scissor_test_enabled
;
672 assert (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
);
673 _cairo_gl_ensure_framebuffer (ctx
, surface
);
675 if (! surface
->msaa_active
) {
676 glDisable (GL_MULTISAMPLE
);
677 ctx
->dispatch
.BindFramebuffer (GL_FRAMEBUFFER
, surface
->fb
);
681 _cairo_gl_composite_flush (ctx
);
683 stencil_test_enabled
= glIsEnabled (GL_STENCIL_TEST
);
684 scissor_test_enabled
= glIsEnabled (GL_SCISSOR_TEST
);
685 glDisable (GL_STENCIL_TEST
);
686 glDisable (GL_SCISSOR_TEST
);
688 glDisable (GL_MULTISAMPLE
);
690 /* The last time we drew to the surface, we were using multisampling,
691 so we need to blit from the multisampling framebuffer into the
692 non-multisampling framebuffer. */
693 ctx
->dispatch
.BindFramebuffer (GL_DRAW_FRAMEBUFFER
, surface
->fb
);
694 ctx
->dispatch
.BindFramebuffer (GL_READ_FRAMEBUFFER
, surface
->msaa_fb
);
695 ctx
->dispatch
.BlitFramebuffer (0, 0, surface
->width
, surface
->height
,
696 0, 0, surface
->width
, surface
->height
,
697 GL_COLOR_BUFFER_BIT
, GL_NEAREST
);
698 ctx
->dispatch
.BindFramebuffer (GL_FRAMEBUFFER
, surface
->fb
);
700 if (stencil_test_enabled
)
701 glEnable (GL_STENCIL_TEST
);
702 if (scissor_test_enabled
)
703 glEnable (GL_SCISSOR_TEST
);
708 _cairo_gl_context_bind_framebuffer (cairo_gl_context_t
*ctx
,
709 cairo_gl_surface_t
*surface
,
710 cairo_bool_t multisampling
)
712 if (_cairo_gl_surface_is_texture (surface
)) {
713 /* OpenGL ES surfaces only have either a multisample framebuffer or a
714 * singlesample framebuffer, so we cannot switch back and forth. */
715 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
) {
716 _cairo_gl_ensure_framebuffer (ctx
, surface
);
717 ctx
->dispatch
.BindFramebuffer (GL_FRAMEBUFFER
, surface
->fb
);
721 #if CAIRO_HAS_GL_SURFACE
723 bind_multisample_framebuffer (ctx
, surface
);
725 bind_singlesample_framebuffer (ctx
, surface
);
728 ctx
->dispatch
.BindFramebuffer (GL_FRAMEBUFFER
, 0);
730 #if CAIRO_HAS_GL_SURFACE
731 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_DESKTOP
) {
733 glEnable (GL_MULTISAMPLE
);
735 glDisable (GL_MULTISAMPLE
);
740 surface
->msaa_active
= multisampling
;
744 _cairo_gl_context_set_destination (cairo_gl_context_t
*ctx
,
745 cairo_gl_surface_t
*surface
,
746 cairo_bool_t multisampling
)
748 cairo_bool_t changing_surface
, changing_sampling
;
750 /* The decision whether or not to use multisampling happens when
751 * we create an OpenGL ES surface, so we can never switch modes. */
752 if (ctx
->gl_flavor
== CAIRO_GL_FLAVOR_ES
)
753 multisampling
= surface
->msaa_active
;
755 changing_surface
= ctx
->current_target
!= surface
|| surface
->needs_update
;
756 changing_sampling
= surface
->msaa_active
!= multisampling
;
757 if (! changing_surface
&& ! changing_sampling
)
760 if (! changing_surface
) {
761 _cairo_gl_composite_flush (ctx
);
762 _cairo_gl_context_bind_framebuffer (ctx
, surface
, multisampling
);
766 _cairo_gl_composite_flush (ctx
);
768 ctx
->current_target
= surface
;
769 surface
->needs_update
= FALSE
;
771 if (! _cairo_gl_surface_is_texture (surface
)) {
772 ctx
->make_current (ctx
, surface
);
775 _cairo_gl_context_bind_framebuffer (ctx
, surface
, multisampling
);
777 if (! _cairo_gl_surface_is_texture (surface
)) {
778 #if CAIRO_HAS_GL_SURFACE
779 glDrawBuffer (GL_BACK_LEFT
);
780 glReadBuffer (GL_BACK_LEFT
);
784 glDisable (GL_DITHER
);
785 glViewport (0, 0, surface
->width
, surface
->height
);
787 if (_cairo_gl_surface_is_texture (surface
))
788 _gl_identity_ortho (ctx
->modelviewprojection_matrix
,
789 0, surface
->width
, 0, surface
->height
);
791 _gl_identity_ortho (ctx
->modelviewprojection_matrix
,
792 0, surface
->width
, surface
->height
, 0);
796 cairo_gl_device_set_thread_aware (cairo_device_t
*device
,
797 cairo_bool_t thread_aware
)
799 if (device
->backend
->type
!= CAIRO_DEVICE_TYPE_GL
) {
800 _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH
);
803 ((cairo_gl_context_t
*) device
)->thread_aware
= thread_aware
;