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)
54 cairo_surface_t *cache_surface = _cairo_gl_surface_create_scratch (ctx,
55 CAIRO_CONTENT_COLOR_ALPHA,
59 if (unlikely (cache_surface->status)) {
60 cairo_surface_destroy (cache_surface);
61 return CAIRO_INT_STATUS_UNSUPPORTED;
64 _cairo_surface_release_device_reference (cache_surface);
65 ctx->image_cache.surface = (cairo_gl_surface_t *)cache_surface;
68 return CAIRO_INT_STATUS_SUCCESS;
72 _cairo_gl_image_cache_fini (cairo_gl_context_t *ctx)
74 _cairo_rtree_fini (&ctx->image_cache.rtree);
75 cairo_surface_destroy (&ctx->image_cache.surface->base);
79 _gl_lock (void *device)
81 cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
87 _gl_unlock (void *device)
89 cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
95 _gl_flush (void *device)
97 cairo_gl_context_t *ctx;
98 cairo_status_t status;
100 status = _cairo_gl_context_acquire (device, &ctx);
101 if (unlikely (status))
104 _cairo_gl_composite_flush (ctx);
106 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
107 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
109 if (ctx->clip_region) {
110 cairo_region_destroy (ctx->clip_region);
111 ctx->clip_region = NULL;
114 ctx->current_target = NULL;
115 ctx->current_operator = -1;
116 ctx->vertex_size = 0;
117 ctx->pre_shader = NULL;
118 _cairo_gl_set_shader (ctx, NULL);
120 ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0);
122 _disable_scissor_buffer ();
123 glDisable (GL_BLEND);
125 return _cairo_gl_context_release (ctx, status);
129 _gl_finish (void *device)
131 cairo_gl_context_t *ctx = device;
136 _cairo_cache_fini (&ctx->gradients);
138 _cairo_gl_context_fini_shaders (ctx);
140 if (ctx->shared_depth_stencil)
141 ctx->dispatch.DeleteRenderbuffers (1, &ctx->shared_depth_stencil);
142 if (ctx->shared_msaa_depth_stencil)
143 ctx->dispatch.DeleteRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
145 for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
146 _cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
148 _cairo_gl_image_cache_fini (ctx);
154 _gl_destroy (void *device)
156 cairo_gl_context_t *ctx = device;
160 while (! cairo_list_is_empty (&ctx->fonts)) {
161 cairo_gl_font_t *font;
163 font = cairo_list_first_entry (&ctx->fonts,
167 cairo_list_del (&font->base.link);
168 cairo_list_del (&font->link);
172 _cairo_array_fini (&ctx->tristrip_indices);
174 cairo_region_destroy (ctx->clip_region);
175 _cairo_clip_destroy (ctx->clip);
184 static const cairo_device_backend_t _cairo_gl_device_backend = {
185 CAIRO_DEVICE_TYPE_GL,
190 _gl_flush, /* flush */
196 _cairo_gl_msaa_compositor_enabled (void)
198 const char *env = getenv ("CAIRO_GL_COMPOSITOR");
199 return env && strcmp(env, "msaa") == 0;
203 _cairo_gl_context_init (cairo_gl_context_t *ctx)
205 cairo_status_t status;
206 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
207 int gl_version = _cairo_gl_get_version ();
208 cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor ();
211 _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
213 /* XXX The choice of compositor should be made automatically at runtime.
214 * However, it is useful to force one particular compositor whilst
217 if (_cairo_gl_msaa_compositor_enabled ())
218 ctx->compositor = _cairo_gl_msaa_compositor_get ();
220 ctx->compositor = _cairo_gl_span_compositor_get ();
223 ctx->thread_aware = TRUE;
225 memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
226 cairo_list_init (&ctx->fonts);
228 /* Support only GL version >= 1.3 */
229 if (gl_version < CAIRO_GL_VERSION_ENCODE (1, 3))
230 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
232 /* Check for required extensions */
233 if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
234 if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) {
235 ctx->tex_target = GL_TEXTURE_2D;
236 ctx->has_npot_repeat = TRUE;
237 } else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) {
238 ctx->tex_target = GL_TEXTURE_RECTANGLE;
239 ctx->has_npot_repeat = FALSE;
241 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
243 ctx->tex_target = GL_TEXTURE_2D;
244 if (_cairo_gl_has_extension ("GL_OES_texture_npot"))
245 ctx->has_npot_repeat = TRUE;
247 ctx->has_npot_repeat = FALSE;
250 if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
251 gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
252 ! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
253 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
255 if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
256 ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
257 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
259 ctx->has_map_buffer = (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
260 (gl_flavor == CAIRO_GL_FLAVOR_ES &&
261 _cairo_gl_has_extension ("GL_OES_mapbuffer")));
263 ctx->has_mesa_pack_invert =
264 _cairo_gl_has_extension ("GL_MESA_pack_invert");
266 ctx->has_packed_depth_stencil =
267 ((gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
268 _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
269 (gl_flavor == CAIRO_GL_FLAVOR_ES &&
270 _cairo_gl_has_extension ("GL_OES_packed_depth_stencil")));
272 ctx->num_samples = 1;
274 #if CAIRO_HAS_GL_SURFACE
275 if (ctx->has_packed_depth_stencil &&
276 _cairo_gl_has_extension ("GL_ARB_framebuffer_object")) {
277 glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
281 #if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
282 if (ctx->has_packed_depth_stencil &&
283 _cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
284 glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
287 ctx->supports_msaa = ctx->num_samples > 1;
288 if (ctx->num_samples > MAX_MSAA_SAMPLES)
289 ctx->num_samples = MAX_MSAA_SAMPLES;
292 ctx->current_operator = -1;
293 ctx->gl_flavor = gl_flavor;
295 status = _cairo_gl_context_init_shaders (ctx);
296 if (unlikely (status))
299 status = _cairo_cache_init (&ctx->gradients,
300 _cairo_gl_gradient_equal,
302 (cairo_destroy_func_t) _cairo_gl_gradient_destroy,
303 CAIRO_GL_GRADIENT_CACHE_SIZE);
304 if (unlikely (status))
307 if (! ctx->has_map_buffer) {
308 ctx->vb_mem = _cairo_malloc_ab (CAIRO_GL_VBO_SIZE, 1);
309 if (unlikely (ctx->vb_mem == NULL)) {
310 _cairo_cache_fini (&ctx->gradients);
311 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
315 _cairo_array_init (&ctx->tristrip_indices, sizeof (unsigned short));
317 /* PBO for any sort of texture upload */
318 dispatch->GenBuffers (1, &ctx->texture_load_pbo);
319 dispatch->GenBuffers (1, &ctx->vbo);
321 ctx->max_framebuffer_size = 0;
322 glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size);
323 ctx->max_texture_size = 0;
324 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
325 ctx->max_textures = 0;
326 glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures);
328 for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
329 _cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
331 ctx->image_cache.surface = NULL;
332 _cairo_rtree_init (&ctx->image_cache.rtree, IMAGE_CACHE_WIDTH,
333 IMAGE_CACHE_HEIGHT, IMAGE_CACHE_MIN_SIZE,
334 sizeof (cairo_gl_image_t),
335 _cairo_gl_image_node_destroy);
337 return CAIRO_STATUS_SUCCESS;
341 _cairo_gl_context_activate (cairo_gl_context_t *ctx,
342 cairo_gl_tex_t tex_unit)
344 if (ctx->max_textures <= (GLint) tex_unit) {
346 _cairo_gl_composite_flush (ctx);
347 _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
349 glActiveTexture (ctx->max_textures - 1);
351 glActiveTexture (GL_TEXTURE0 + tex_unit);
356 _get_depth_stencil_format (cairo_gl_context_t *ctx)
358 /* This is necessary to properly handle the situation where both
359 OpenGL and OpenGLES are active and returning a sane default. */
360 #if CAIRO_HAS_GL_SURFACE
361 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
362 return GL_DEPTH_STENCIL;
365 #if CAIRO_HAS_GLESV2_SURFACE
366 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
367 return GL_DEPTH24_STENCIL8_OES;
370 #if CAIRO_HAS_GL_SURFACE
371 return GL_DEPTH_STENCIL;
372 #elif CAIRO_HAS_GLESV2_SURFACE
373 return GL_DEPTH24_STENCIL8_OES;
377 #if CAIRO_HAS_GLESV2_SURFACE
379 _cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
380 cairo_gl_surface_t *surface)
382 if (surface->msaa_active)
385 ctx->dispatch.FramebufferTexture2DMultisample(GL_FRAMEBUFFER,
386 GL_COLOR_ATTACHMENT0,
392 /* From now on MSAA will always be active on this surface. */
393 surface->msaa_active = TRUE;
398 _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
399 cairo_gl_surface_t *surface)
402 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
404 if (likely (surface->fb))
407 /* Create a framebuffer object wrapping the texture so that we can render
410 dispatch->GenFramebuffers (1, &surface->fb);
411 dispatch->BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
413 /* Unlike for desktop GL we only maintain one multisampling framebuffer
414 for OpenGLES since the EXT_multisampled_render_to_texture extension
415 does not require an explicit multisample resolution. */
416 #if CAIRO_HAS_GLESV2_SURFACE
417 if (surface->supports_msaa && _cairo_gl_msaa_compositor_enabled () &&
418 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
419 _cairo_gl_ensure_msaa_gles_framebuffer (ctx, surface);
422 dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
423 GL_COLOR_ATTACHMENT0,
428 #if CAIRO_HAS_GL_SURFACE
429 glDrawBuffer (GL_COLOR_ATTACHMENT0);
430 glReadBuffer (GL_COLOR_ATTACHMENT0);
433 status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
434 if (status != GL_FRAMEBUFFER_COMPLETE) {
437 //case GL_FRAMEBUFFER_UNDEFINED: str= "undefined"; break;
438 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: str= "incomplete attachment"; break;
439 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: str= "incomplete/missing attachment"; break;
440 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: str= "incomplete draw buffer"; break;
441 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: str= "incomplete read buffer"; break;
442 case GL_FRAMEBUFFER_UNSUPPORTED: str= "unsupported"; break;
443 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: str= "incomplete multiple"; break;
444 default: str = "unknown error"; break;
448 "destination is framebuffer incomplete: %s [%#x]\n",
453 #if CAIRO_HAS_GL_SURFACE
455 _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
456 cairo_gl_surface_t *surface)
458 assert (surface->supports_msaa);
459 assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
461 if (surface->msaa_fb)
464 /* We maintain a separate framebuffer for multisampling operations.
465 This allows us to do a fast paint to the non-multisampling framebuffer
466 when mulitsampling is disabled. */
467 ctx->dispatch.GenFramebuffers (1, &surface->msaa_fb);
468 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
469 ctx->dispatch.GenRenderbuffers (1, &surface->msaa_rb);
470 ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, surface->msaa_rb);
472 /* FIXME: For now we assume that textures passed from the outside have GL_RGBA
473 format, but eventually we need to expose a way for the API consumer to pass
475 ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
480 ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
481 GL_COLOR_ATTACHMENT0,
485 /* Cairo surfaces start out initialized to transparent (black) */
486 _disable_scissor_buffer ();
487 glClearColor (0, 0, 0, 0);
488 glClear (GL_COLOR_BUFFER_BIT);
493 _cairo_gl_replace_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
497 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
499 if (ctx->shared_msaa_depth_stencil)
500 dispatch->DeleteRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
502 dispatch->GenRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
503 dispatch->BindRenderbuffer (GL_RENDERBUFFER, ctx->shared_msaa_depth_stencil);
504 dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER, ctx->num_samples,
505 _get_depth_stencil_format (ctx),
507 ctx->shared_msaa_depth_stencil_width = width;
508 ctx->shared_msaa_depth_stencil_height = height;
512 _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
513 cairo_gl_surface_t *surface)
515 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
516 _cairo_gl_ensure_framebuffer (ctx, surface);
517 #if CAIRO_HAS_GL_SURFACE
518 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
519 _cairo_gl_ensure_multisampling (ctx, surface);
522 if (! ctx->shared_msaa_depth_stencil ||
523 ctx->shared_msaa_depth_stencil_width < surface->width ||
524 ctx->shared_msaa_depth_stencil_height < surface->height) {
525 _cairo_gl_replace_msaa_depth_stencil_buffer (ctx,
530 assert (ctx->shared_msaa_depth_stencil);
531 if (surface->msaa_depth_stencil == ctx->shared_msaa_depth_stencil)
534 #if CAIRO_HAS_GL_SURFACE
535 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
536 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
537 GL_DEPTH_STENCIL_ATTACHMENT,
539 ctx->shared_msaa_depth_stencil);
543 #if CAIRO_HAS_GLESV2_SURFACE
544 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
545 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
548 ctx->shared_msaa_depth_stencil);
549 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
550 GL_STENCIL_ATTACHMENT,
552 ctx->shared_msaa_depth_stencil);
556 surface->msaa_depth_stencil = ctx->shared_msaa_depth_stencil;
558 if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
559 dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
560 surface->msaa_depth_stencil = 0;
568 _cairo_gl_replace_depth_stencil_buffer (cairo_gl_context_t *ctx,
572 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
574 if (ctx->shared_depth_stencil)
575 dispatch->DeleteRenderbuffers (1, &ctx->shared_depth_stencil);
577 dispatch->GenRenderbuffers (1, &ctx->shared_depth_stencil);
578 dispatch->BindRenderbuffer (GL_RENDERBUFFER, ctx->shared_depth_stencil);
579 dispatch->RenderbufferStorage (GL_RENDERBUFFER,
580 _get_depth_stencil_format (ctx),
582 ctx->shared_depth_stencil_width = width;
583 ctx->shared_depth_stencil_height = height;
587 _cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
588 cairo_gl_surface_t *surface)
590 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
592 _cairo_gl_ensure_framebuffer (ctx, surface);
594 if (! ctx->shared_depth_stencil ||
595 ctx->shared_depth_stencil_width < surface->width ||
596 ctx->shared_depth_stencil_height < surface->height) {
597 _cairo_gl_replace_depth_stencil_buffer (ctx,
602 if (surface->depth_stencil == ctx->shared_depth_stencil)
605 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
606 GL_RENDERBUFFER, ctx->shared_depth_stencil);
607 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
608 GL_RENDERBUFFER, ctx->shared_depth_stencil);
609 surface->depth_stencil = ctx->shared_depth_stencil;
611 if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
612 dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
613 surface->depth_stencil = 0;
621 _cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
622 cairo_gl_surface_t *surface)
624 if (! _cairo_gl_surface_is_texture (surface))
625 return TRUE; /* best guess for now, will check later */
627 if (! ctx->has_packed_depth_stencil)
630 if (surface->msaa_active)
631 return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface);
633 return _cairo_gl_ensure_depth_stencil_buffer (ctx, surface);
637 * Stores a parallel projection transformation in matrix 'm',
638 * using column-major order.
640 * This is equivalent to:
645 * The calculation for the ortho tranformation was taken from the
649 _gl_identity_ortho (GLfloat *m,
650 GLfloat left, GLfloat right,
651 GLfloat bottom, GLfloat top)
653 #define M(row,col) m[col*4+row]
654 M(0,0) = 2.f / (right - left);
657 M(0,3) = -(right + left) / (right - left);
660 M(1,1) = 2.f / (top - bottom);
662 M(1,3) = -(top + bottom) / (top - bottom);
676 #if CAIRO_HAS_GL_SURFACE
678 _cairo_gl_activate_surface_as_multisampling (cairo_gl_context_t *ctx,
679 cairo_gl_surface_t *surface)
681 assert (surface->supports_msaa);
682 assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
684 _cairo_gl_ensure_framebuffer (ctx, surface);
685 _cairo_gl_ensure_multisampling (ctx, surface);
688 if (surface->msaa_active) {
689 glEnable (GL_MULTISAMPLE);
690 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
694 _cairo_gl_composite_flush (ctx);
695 glEnable (GL_MULTISAMPLE);
697 /* The last time we drew to the surface, we were not using multisampling,
698 so we need to blit from the non-multisampling framebuffer into the
699 multisampling framebuffer. */
700 ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->msaa_fb);
701 ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb);
702 ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
703 0, 0, surface->width, surface->height,
704 GL_COLOR_BUFFER_BIT, GL_NEAREST);
705 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
706 surface->msaa_active = TRUE;
711 _cairo_gl_activate_surface_as_nonmultisampling (cairo_gl_context_t *ctx,
712 cairo_gl_surface_t *surface)
714 assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
715 _cairo_gl_ensure_framebuffer (ctx, surface);
717 #if CAIRO_HAS_GL_SURFACE
718 if (! surface->msaa_active) {
719 glDisable (GL_MULTISAMPLE);
720 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
724 _cairo_gl_composite_flush (ctx);
725 glDisable (GL_MULTISAMPLE);
727 /* The last time we drew to the surface, we were using multisampling,
728 so we need to blit from the multisampling framebuffer into the
729 non-multisampling framebuffer. */
730 ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb);
731 ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->msaa_fb);
732 ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
733 0, 0, surface->width, surface->height,
734 GL_COLOR_BUFFER_BIT, GL_NEAREST);
735 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
736 surface->msaa_active = FALSE;
741 _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
742 cairo_gl_surface_t *surface,
743 cairo_bool_t multisampling)
745 /* OpenGL ES surfaces are always in MSAA mode once it's been turned on,
746 * so we don't need to check whether we are switching modes for that
748 if (ctx->current_target == surface && ! surface->needs_update &&
749 (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES ||
750 surface->msaa_active == multisampling))
753 _cairo_gl_composite_flush (ctx);
755 ctx->current_target = surface;
756 surface->needs_update = FALSE;
758 if (_cairo_gl_surface_is_texture (surface)) {
759 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
760 _cairo_gl_ensure_framebuffer (ctx, surface);
761 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
762 #if CAIRO_HAS_GL_SURFACE
763 } else if (multisampling)
764 _cairo_gl_activate_surface_as_multisampling (ctx, surface);
766 _cairo_gl_activate_surface_as_nonmultisampling (ctx, surface);
770 ctx->make_current (ctx, surface);
772 #if CAIRO_HAS_GL_SURFACE
774 glEnable(GL_MULTISAMPLE);
776 glDisable(GL_MULTISAMPLE);
779 surface->msaa_active = multisampling;
780 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
782 #if CAIRO_HAS_GL_SURFACE
783 glDrawBuffer (GL_BACK_LEFT);
784 glReadBuffer (GL_BACK_LEFT);
788 glViewport (0, 0, surface->width, surface->height);
790 if (_cairo_gl_surface_is_texture (surface))
791 _gl_identity_ortho (ctx->modelviewprojection_matrix,
792 0, surface->width, 0, surface->height);
794 _gl_identity_ortho (ctx->modelviewprojection_matrix,
795 0, surface->width, surface->height, 0);
799 cairo_gl_device_set_thread_aware (cairo_device_t *device,
800 cairo_bool_t thread_aware)
802 if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
803 _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
806 ((cairo_gl_context_t *) device)->thread_aware = thread_aware;