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"
47 #include "cairo-rtree-private.h"
49 #define MAX_MSAA_SAMPLES 4
52 _cairo_gl_image_cache_init (cairo_gl_context_t *ctx, int width, int height,
53 cairo_gl_image_cache_t **image_cache)
55 cairo_surface_t *cache_surface = _cairo_gl_surface_create_scratch (ctx,
56 CAIRO_CONTENT_COLOR_ALPHA,
58 if (unlikely (cache_surface->status)) {
59 cairo_surface_destroy (cache_surface);
60 return CAIRO_INT_STATUS_UNSUPPORTED;
63 _cairo_surface_release_device_reference (cache_surface);
64 *image_cache = _cairo_malloc (sizeof (cairo_gl_image_cache_t));
65 (*image_cache)->surface = (cairo_gl_surface_t *)cache_surface;
66 (*image_cache)->surface->supports_msaa = FALSE;
68 _cairo_rtree_init (&((*image_cache)->rtree), width, height,
70 sizeof (cairo_gl_image_t),
71 _cairo_gl_image_node_destroy);
73 (*image_cache)->copy_success = TRUE;
74 return CAIRO_INT_STATUS_SUCCESS;
78 _cairo_gl_image_cache_fini (cairo_gl_context_t *ctx)
80 if (ctx->image_cache) {
81 _cairo_rtree_fini (&ctx->image_cache->rtree);
82 cairo_surface_destroy (&ctx->image_cache->surface->base);
84 free (ctx->image_cache);
88 _gl_lock (void *device)
90 cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
96 _gl_unlock (void *device)
98 cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
103 static cairo_status_t
104 _gl_flush (void *device)
106 cairo_gl_context_t *ctx;
107 cairo_status_t status;
109 status = _cairo_gl_context_acquire (device, &ctx);
110 if (unlikely (status))
113 _cairo_gl_composite_flush (ctx);
115 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
116 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
118 if (ctx->clip_region) {
119 cairo_region_destroy (ctx->clip_region);
120 ctx->clip_region = NULL;
123 ctx->current_target = NULL;
124 ctx->current_operator = -1;
125 ctx->vertex_size = 0;
126 ctx->pre_shader = NULL;
127 _cairo_gl_set_shader (ctx, NULL);
129 ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0);
131 _cairo_gl_context_reset (ctx);
133 _disable_scissor_buffer (ctx);
135 if (ctx->states_cache.blend_enabled == TRUE ) {
136 glDisable (GL_BLEND);
137 ctx->states_cache.blend_enabled = FALSE;
140 return _cairo_gl_context_release (ctx, status);
144 _gl_finish (void *device)
146 cairo_gl_context_t *ctx = device;
151 _cairo_cache_fini (&ctx->gradients);
153 _cairo_gl_context_fini_shaders (ctx);
155 for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
156 _cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
159 _cairo_gl_image_cache_fini (ctx);
165 _gl_destroy (void *device)
169 cairo_gl_context_t *ctx = device;
173 if(ctx->glyph_mask) {
174 cairo_surface_destroy (&ctx->glyph_mask->base);
175 ctx->glyph_mask = NULL;
178 for (n = 0; n < 2; n++) {
179 if (ctx->source_scratch_surfaces[n])
180 cairo_surface_destroy (&ctx->source_scratch_surfaces[n]->base);
181 if (ctx->mask_scratch_surfaces[n])
182 cairo_surface_destroy (&ctx->mask_scratch_surfaces[n]->base);
183 if (ctx->shadow_scratch_surfaces[n])
184 cairo_surface_destroy (&ctx->shadow_scratch_surfaces[n]->base);
186 if (ctx->shadow_scratch_surfaces[2])
187 cairo_surface_destroy (&ctx->shadow_scratch_surfaces[2]->base);
189 for (n = 0; n < 4; n++) {
190 if (ctx->shadow_masks[n])
191 cairo_surface_destroy (&ctx->shadow_masks[n]->base);
194 while (! cairo_list_is_empty (&ctx->fonts)) {
195 cairo_gl_font_t *font;
197 font = cairo_list_first_entry (&ctx->fonts,
201 cairo_list_del (&font->base.link);
202 cairo_list_del (&font->link);
206 _cairo_array_fini (&ctx->tristrip_indices);
208 cairo_region_destroy (ctx->clip_region);
217 static const cairo_device_backend_t _cairo_gl_device_backend = {
218 CAIRO_DEVICE_TYPE_GL,
223 _gl_flush, /* flush */
229 _cairo_gl_msaa_compositor_enabled (void)
231 const char *env = getenv ("CAIRO_GL_COMPOSITOR");
232 return env && strcmp(env, "msaa") == 0;
236 test_can_read_bgra (cairo_gl_flavor_t gl_flavor)
238 /* Desktop GL always supports BGRA formats. */
239 if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
242 assert (gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
243 gl_flavor == CAIRO_GL_FLAVOR_ES3);
245 /* For OpenGL ES we have to look for the specific extension and BGRA only
246 * matches cairo's integer packed bytes on little-endian machines. */
247 if (!_cairo_is_little_endian())
249 return _cairo_gl_has_extension ("EXT_read_format_bgra");
253 _cairo_gl_context_init (cairo_gl_context_t *ctx)
255 cairo_status_t status;
256 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
257 int gl_version = _cairo_gl_get_version ();
258 cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor ();
261 cairo_bool_t is_desktop = gl_flavor == CAIRO_GL_FLAVOR_DESKTOP;
262 cairo_bool_t is_gles = (gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
263 gl_flavor == CAIRO_GL_FLAVOR_ES3);
265 _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
267 /* XXX The choice of compositor should be made automatically at runtime.
268 * However, it is useful to force one particular compositor whilst
271 if (_cairo_gl_msaa_compositor_enabled ())
272 ctx->compositor = _cairo_gl_msaa_compositor_get ();
274 ctx->compositor = _cairo_gl_span_compositor_get ();
277 ctx->thread_aware = TRUE;
278 ctx->has_angle_multisampling = FALSE;
280 memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
281 cairo_list_init (&ctx->fonts);
283 /* Support only GL version >= 1.3 */
284 if (gl_version < CAIRO_GL_VERSION_ENCODE (1, 3))
285 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
287 /* Check for required extensions */
289 if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) {
290 ctx->tex_target = GL_TEXTURE_2D;
291 ctx->has_npot_repeat = TRUE;
292 } else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) {
293 ctx->tex_target = GL_TEXTURE_RECTANGLE;
294 ctx->has_npot_repeat = FALSE;
296 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
298 ctx->tex_target = GL_TEXTURE_2D;
299 if (_cairo_gl_has_extension ("GL_OES_texture_npot") ||
300 _cairo_gl_has_extension ("GL_IMG_texture_npot"))
301 ctx->has_npot_repeat = TRUE;
303 ctx->has_npot_repeat = FALSE;
306 if (is_desktop && gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
307 ! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
308 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
310 if (is_gles && ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
311 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
313 ctx->has_map_buffer =
314 is_desktop || (is_gles && _cairo_gl_has_extension ("GL_OES_mapbuffer"));
316 ctx->can_read_bgra = test_can_read_bgra (gl_flavor);
318 ctx->has_mesa_pack_invert =
319 _cairo_gl_has_extension ("GL_MESA_pack_invert");
321 ctx->has_packed_depth_stencil =
322 (is_desktop && _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
323 (is_gles && _cairo_gl_has_extension ("GL_OES_packed_depth_stencil"));
325 ctx->num_samples = 1;
327 #if CAIRO_HAS_GL_SURFACE
328 if (is_desktop && ctx->has_packed_depth_stencil &&
329 (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
330 _cairo_gl_has_extension ("GL_ARB_framebuffer_object") ||
331 (_cairo_gl_has_extension ("GL_EXT_framebuffer_blit") &&
332 _cairo_gl_has_extension ("GL_EXT_framebuffer_multisample")))) {
333 glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
337 #if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
338 if (is_gles && ctx->has_packed_depth_stencil &&
339 _cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
340 glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
344 #if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_IMG)
345 if (is_gles && ctx->has_packed_depth_stencil &&
346 _cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture")) {
347 glGetIntegerv(GL_MAX_SAMPLES_IMG, &ctx->num_samples);
351 #if CAIRO_HAS_GLESV2_SURFACE && defined (GL_MAX_SAMPLES_ANGLE)
352 if (is_gles && ctx->has_packed_depth_stencil &&
353 _cairo_gl_has_extension ("GL_ANGLE_framebuffer_blit") &&
354 _cairo_gl_has_extension ("GL_ANGLE_framebuffer_multisample")) {
355 glGetIntegerv(GL_MAX_SAMPLES_ANGLE, &ctx->num_samples);
356 ctx->has_angle_multisampling = TRUE;
360 #if CAIRO_HAS_GLESV3_SURFACE
361 if (is_gles && ctx->has_packed_depth_stencil) {
362 glGetIntegerv(GL_MAX_SAMPLES, &ctx->num_samples);
366 /* we always use renderbuffer for rendering in glesv3 */
367 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
368 (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
369 ctx->has_angle_multisampling))
370 ctx->supports_msaa = TRUE;
372 ctx->supports_msaa = ctx->num_samples > 1;
373 if (ctx->num_samples > MAX_MSAA_SAMPLES)
374 ctx->num_samples = MAX_MSAA_SAMPLES;
377 ctx->current_operator = -1;
378 ctx->gl_flavor = gl_flavor;
380 status = _cairo_gl_context_init_shaders (ctx);
381 if (unlikely (status))
384 status = _cairo_cache_init (&ctx->gradients,
385 _cairo_gl_gradient_equal,
387 (cairo_destroy_func_t) _cairo_gl_gradient_destroy,
388 CAIRO_GL_GRADIENT_CACHE_SIZE);
389 if (unlikely (status))
392 ctx->vb = malloc (CAIRO_GL_VBO_SIZE);
393 if (unlikely (ctx->vb == NULL)) {
394 _cairo_cache_fini (&ctx->gradients);
395 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
398 ctx->primitive_type = CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES;
399 _cairo_array_init (&ctx->tristrip_indices, sizeof (unsigned short));
401 /* PBO for any sort of texture upload */
402 dispatch->GenBuffers (1, &ctx->texture_load_pbo);
404 ctx->max_framebuffer_size = 0;
405 glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size);
406 ctx->max_texture_size = 0;
407 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
408 ctx->max_textures = 0;
409 glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures);
411 for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
412 _cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
414 ctx->image_cache = NULL;
416 for (n = 0; n < 2; n++) {
417 ctx->source_scratch_surfaces[n] = NULL;
418 ctx->mask_scratch_surfaces[n] = NULL;
419 ctx->shadow_scratch_surfaces[n] = NULL;
422 for (n = 0; n < 4; n++)
423 ctx->shadow_masks[n] = NULL;
425 ctx->source_scratch_in_use = FALSE;
427 _cairo_gl_context_reset (ctx);
429 return CAIRO_STATUS_SUCCESS;
433 _cairo_gl_context_activate (cairo_gl_context_t *ctx,
434 cairo_gl_tex_t tex_unit)
436 if (ctx->max_textures <= (GLint) tex_unit) {
438 _cairo_gl_composite_flush (ctx);
439 _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
441 if (ctx->states_cache.active_texture != ctx->max_textures - 1) {
442 glActiveTexture (ctx->max_textures - 1);
443 ctx->states_cache.active_texture = ctx->max_textures - 1;
446 if (ctx->states_cache.active_texture != GL_TEXTURE0 + tex_unit) {
447 glActiveTexture (GL_TEXTURE0 + tex_unit);
448 ctx->states_cache.active_texture = GL_TEXTURE0 + tex_unit;
454 _get_depth_stencil_format (cairo_gl_context_t *ctx)
456 /* This is necessary to properly handle the situation where both
457 OpenGL and OpenGLES are active and returning a sane default. */
458 #if CAIRO_HAS_GL_SURFACE
459 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
460 return GL_DEPTH_STENCIL;
463 #if CAIRO_HAS_GLESV2_SURFACE
464 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
465 return GL_DEPTH24_STENCIL8_OES;
468 #if CAIRO_HAS_GL_SURFACE
469 return GL_DEPTH_STENCIL;
470 #elif CAIRO_HAS_GLESV2_SURFACE
471 return GL_DEPTH24_STENCIL8_OES;
472 #elif CAIRO_HAS_GLESV3_SURFACE
473 return GL_DEPTH24_STENCIL8;
478 _cairo_gl_clear_framebuffer (cairo_gl_context_t *ctx,
479 cairo_gl_surface_t *surface)
481 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
484 if (_cairo_gl_surface_is_scratch (ctx, surface)) {
485 _disable_scissor_buffer (ctx);
486 _disable_stencil_buffer (ctx);
487 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
491 #if CAIRO_HAS_GLESV2_SURFACE
493 _cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
494 cairo_gl_surface_t *surface)
496 if (ctx->has_angle_multisampling)
499 if (surface->msaa_active)
502 ctx->dispatch.FramebufferTexture2DMultisample(GL_FRAMEBUFFER,
503 GL_COLOR_ATTACHMENT0,
509 /* From now on MSAA will always be active on this surface. */
510 surface->msaa_active = TRUE;
515 _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
516 cairo_gl_surface_t *surface)
519 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
521 if (likely (surface->fb))
524 /* Create a framebuffer object wrapping the texture so that we can render
527 dispatch->GenFramebuffers (1, &surface->fb);
528 dispatch->BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
530 /* Unlike for desktop GL we only maintain one multisampling framebuffer
531 for OpenGLES since the EXT_multisampled_render_to_texture extension
532 does not require an explicit multisample resolution. */
533 #if CAIRO_HAS_GLESV2_SURFACE
534 if (surface->supports_msaa && _cairo_gl_msaa_compositor_enabled () &&
535 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
536 ! ctx->has_angle_multisampling) {
537 _cairo_gl_ensure_msaa_gles_framebuffer (ctx, surface);
540 dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
541 GL_COLOR_ATTACHMENT0,
546 #if CAIRO_HAS_GL_SURFACE
547 glDrawBuffer (GL_COLOR_ATTACHMENT0);
548 glReadBuffer (GL_COLOR_ATTACHMENT0);
551 status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
552 if (status != GL_FRAMEBUFFER_COMPLETE) {
555 //case GL_FRAMEBUFFER_UNDEFINED: str= "undefined"; break;
556 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: str= "incomplete attachment"; break;
557 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: str= "incomplete/missing attachment"; break;
558 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: str= "incomplete draw buffer"; break;
559 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: str= "incomplete read buffer"; break;
560 case GL_FRAMEBUFFER_UNSUPPORTED: str= "unsupported"; break;
561 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: str= "incomplete multiple"; break;
562 default: str = "unknown error"; break;
566 "destination is framebuffer incomplete: %s [%#x]\n",
572 _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
573 cairo_gl_surface_t *surface)
575 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
576 ! ctx->has_angle_multisampling)
579 assert (surface->supports_msaa);
581 if (surface->msaa_fb)
584 /* We maintain a separate framebuffer for multisampling operations.
585 This allows us to do a fast paint to the non-multisampling framebuffer
586 when mulitsampling is disabled. */
587 ctx->dispatch.GenFramebuffers (1, &surface->msaa_fb);
588 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
589 ctx->dispatch.GenRenderbuffers (1, &surface->msaa_rb);
590 ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, surface->msaa_rb);
592 /* FIXME: For now we assume that textures passed from the outside have GL_RGBA
593 format, but eventually we need to expose a way for the API consumer to pass
595 ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
597 #if CAIRO_HAS_GLESV3_SURFACE || CAIRO_HAS_GLESV2_SURFACE
605 ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
606 GL_COLOR_ATTACHMENT0,
610 if (ctx->dispatch.CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
611 ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_rb);
612 surface->msaa_rb = 0;
613 ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_fb);
614 surface->msaa_fb = 0;
618 /* Cairo surfaces start out initialized to transparent (black) */
619 _disable_scissor_buffer (ctx);
620 glClearColor (0, 0, 0, 0);
621 // reset cached clear colors
622 memset (&ctx->states_cache.clear_red, 0, sizeof (GLclampf) * 4);
623 glClear (GL_COLOR_BUFFER_BIT);
627 _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
628 cairo_gl_surface_t *surface)
630 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
631 if (surface->msaa_depth_stencil)
634 _cairo_gl_ensure_multisampling (ctx, surface);
636 dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
637 dispatch->BindRenderbuffer (GL_RENDERBUFFER,
638 surface->msaa_depth_stencil);
640 dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER,
642 _get_depth_stencil_format (ctx),
646 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
647 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
648 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) {
649 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
650 GL_DEPTH_STENCIL_ATTACHMENT,
652 surface->msaa_depth_stencil);
656 #if CAIRO_HAS_GLESV2_SURFACE
657 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) {
658 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
661 surface->msaa_depth_stencil);
662 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
663 GL_STENCIL_ATTACHMENT,
665 surface->msaa_depth_stencil);
669 if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
670 dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
671 surface->msaa_depth_stencil = 0;
679 _cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
680 cairo_gl_surface_t *surface)
682 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
684 if (surface->depth_stencil)
687 _cairo_gl_ensure_framebuffer (ctx, surface);
689 dispatch->GenRenderbuffers (1, &surface->depth_stencil);
690 dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
691 dispatch->RenderbufferStorage (GL_RENDERBUFFER,
692 _get_depth_stencil_format (ctx),
693 surface->width, surface->height);
695 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
696 GL_RENDERBUFFER, surface->depth_stencil);
697 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
698 GL_RENDERBUFFER, surface->depth_stencil);
699 if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
700 dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
701 surface->depth_stencil = 0;
709 _cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
710 cairo_gl_surface_t *surface)
712 if (! _cairo_gl_surface_is_texture (surface))
713 return TRUE; /* best guess for now, will check later */
714 if (! ctx->has_packed_depth_stencil)
717 if (surface->msaa_active)
718 return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface);
720 return _cairo_gl_ensure_depth_stencil_buffer (ctx, surface);
724 * Stores a parallel projection transformation in matrix 'm',
725 * using column-major order.
727 * This is equivalent to:
732 * The calculation for the ortho tranformation was taken from the
736 _gl_identity_ortho (GLfloat *m,
737 GLfloat left, GLfloat right,
738 GLfloat bottom, GLfloat top)
740 #define M(row,col) m[col*4+row]
741 M(0,0) = 2.f / (right - left);
744 M(0,3) = -(right + left) / (right - left);
747 M(1,1) = 2.f / (top - bottom);
749 M(1,3) = -(top + bottom) / (top - bottom);
764 bind_multisample_framebuffer (cairo_gl_context_t *ctx,
765 cairo_gl_surface_t *surface)
767 #if CAIRO_HAS_GL_SURFACE
768 cairo_bool_t stencil_test_enabled = ctx->states_cache.stencil_test_enabled;
769 cairo_bool_t scissor_test_enabled = ctx->states_cache.scissor_test_enabled;
771 cairo_bool_t has_stencil_cache = surface->clip_on_stencil_buffer ? TRUE : FALSE;
772 GLbitfield mask = GL_COLOR_BUFFER_BIT;
774 assert (surface->supports_msaa);
776 _cairo_gl_ensure_framebuffer (ctx, surface);
777 _cairo_gl_ensure_multisampling (ctx, surface);
779 if (surface->msaa_active) {
780 #if CAIRO_HAS_GL_SURFACE
781 glEnable (GL_MULTISAMPLE);
784 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
788 _cairo_gl_composite_flush (ctx);
790 #if CAIRO_HAS_GL_SURFACE
791 /* we must disable scissor and stencil test */
792 _disable_stencil_buffer (ctx);
793 _disable_scissor_buffer (ctx);
795 glEnable (GL_MULTISAMPLE);
797 if (has_stencil_cache)
798 mask |= GL_STENCIL_BUFFER_BIT;
800 /* The last time we drew to the surface, we were not using multisampling,
801 so we need to blit from the non-multisampling framebuffer into the
802 multisampling framebuffer. */
803 ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->msaa_fb);
804 ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb);
805 ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
806 0, 0, surface->width, surface->height,
808 surface->content_synced = TRUE;
810 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
812 #if CAIRO_HAS_GL_SURFACE
813 /* re-enable stencil and scissor test */
814 if (scissor_test_enabled)
815 _enable_scissor_buffer (ctx);
816 if (stencil_test_enabled)
817 _enable_stencil_buffer (ctx);
822 bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
823 cairo_gl_surface_t *surface)
825 cairo_bool_t has_stencil_cache = surface->clip_on_stencil_buffer ? TRUE : FALSE;
826 cairo_bool_t stencil_test_enabled = ctx->states_cache.stencil_test_enabled;
827 cairo_bool_t scissor_test_enabled = ctx->states_cache.scissor_test_enabled;
828 GLbitfield mask = GL_COLOR_BUFFER_BIT;
830 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
831 ! ctx->has_angle_multisampling)
834 _cairo_gl_ensure_framebuffer (ctx, surface);
836 if (! surface->msaa_active) {
837 #if CAIRO_HAS_GL_SURFACE
838 glDisable (GL_MULTISAMPLE);
840 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
844 _cairo_gl_composite_flush (ctx);
846 /* we must disable scissor and stencil test */
847 _disable_stencil_buffer (ctx);
848 _disable_scissor_buffer (ctx);
849 #if CAIRO_HAS_GL_SURFACE
850 glDisable (GL_MULTISAMPLE);
853 if (has_stencil_cache)
854 mask |= GL_STENCIL_BUFFER_BIT;
856 /* The last time we drew to the surface, we were using multisampling,
857 so we need to blit from the multisampling framebuffer into the
858 non-multisampling framebuffer. */
859 #if CAIRO_HAS_GLESV2_SURFACE
860 ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER_ANGLE, surface->fb);
861 ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER_ANGLE, surface->msaa_fb);
863 ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb);
864 ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->msaa_fb);
866 ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
867 0, 0, surface->width, surface->height,
869 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
871 surface->content_synced = TRUE;
872 /* re-enable stencil and scissor test */
873 if (scissor_test_enabled)
874 _enable_scissor_buffer (ctx);
875 if (stencil_test_enabled)
876 _enable_stencil_buffer (ctx);
880 _cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx,
881 cairo_gl_surface_t *surface,
882 cairo_bool_t multisampling)
884 if (_cairo_gl_surface_is_texture (surface)) {
885 /* OpenGL ES surfaces only have either a multisample framebuffer or a
886 * singlesample framebuffer, so we cannot switch back and forth. */
887 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
888 ! ctx->has_angle_multisampling) {
889 _cairo_gl_ensure_framebuffer (ctx, surface);
890 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
891 _cairo_gl_clear_framebuffer (ctx, surface);
896 bind_multisample_framebuffer (ctx, surface);
898 bind_singlesample_framebuffer (ctx, surface);
900 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
902 #if CAIRO_HAS_GL_SURFACE
903 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
905 glEnable (GL_MULTISAMPLE);
907 glDisable (GL_MULTISAMPLE);
912 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
913 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
914 (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
915 ctx->has_angle_multisampling))
916 surface->msaa_active = multisampling;
918 if (ctx->gl_flavor != CAIRO_GL_FLAVOR_DESKTOP && multisampling)
919 _cairo_gl_clear_framebuffer (ctx, surface);
923 _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
924 cairo_gl_surface_t *surface,
925 cairo_bool_t multisampling)
927 cairo_bool_t changing_surface, changing_sampling;
929 /* The decision whether or not to use multisampling happens when
930 * we create an OpenGL ES surface, so we can never switch modes. */
931 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
932 ! ctx->has_angle_multisampling)
933 multisampling = surface->msaa_active;
935 changing_surface = ctx->current_target != surface || surface->size_changed;
936 changing_sampling = surface->msaa_active != multisampling;
938 if (! changing_surface && ! changing_sampling) {
939 if (surface->needs_update)
940 _cairo_gl_composite_flush (ctx);
943 if (! changing_surface) {
944 _cairo_gl_composite_flush (ctx);
945 _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
949 _cairo_gl_composite_flush (ctx);
951 ctx->current_target = surface;
952 surface->needs_update = FALSE;
954 if (! _cairo_gl_surface_is_texture (surface)) {
955 ctx->make_current (ctx, surface);
958 _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
960 if (! _cairo_gl_surface_is_texture (surface)) {
961 #if CAIRO_HAS_GL_SURFACE
962 glDrawBuffer (GL_BACK_LEFT);
963 glReadBuffer (GL_BACK_LEFT);
967 glDisable (GL_DITHER);
968 if (ctx->states_cache.viewport_box.width != surface->width ||
969 ctx->states_cache.viewport_box.height != surface->height) {
970 glViewport (0, 0, surface->width, surface->height);
971 ctx->states_cache.viewport_box.width = surface->width;
972 ctx->states_cache.viewport_box.height = surface->height;
975 if (_cairo_gl_surface_is_texture (surface))
976 _gl_identity_ortho (ctx->modelviewprojection_matrix,
977 0, surface->width, 0, surface->height);
979 _gl_identity_ortho (ctx->modelviewprojection_matrix,
980 0, surface->width, surface->height, 0);
984 cairo_gl_device_set_thread_aware (cairo_device_t *device,
985 cairo_bool_t thread_aware)
987 if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
988 _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
991 ((cairo_gl_context_t *) device)->thread_aware = thread_aware;
994 void _cairo_gl_context_reset (cairo_gl_context_t *ctx)
996 ctx->states_cache.viewport_box.width = 0;
997 ctx->states_cache.viewport_box.height = 0;
999 ctx->states_cache.clear_red = -1;
1000 ctx->states_cache.clear_green = -1;
1001 ctx->states_cache.clear_blue = -1;
1002 ctx->states_cache.clear_alpha = -1;
1004 ctx->states_cache.blend_enabled = FALSE;
1006 ctx->states_cache.src_color_factor = CAIRO_GL_ENUM_UNINITIALIZED;
1007 ctx->states_cache.dst_color_factor = CAIRO_GL_ENUM_UNINITIALIZED;
1008 ctx->states_cache.src_alpha_factor = CAIRO_GL_ENUM_UNINITIALIZED;
1009 ctx->states_cache.dst_alpha_factor = CAIRO_GL_ENUM_UNINITIALIZED;
1011 ctx->states_cache.active_texture = CAIRO_GL_ENUM_UNINITIALIZED;
1013 ctx->states_cache.depth_mask = FALSE;