beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-gl-device.c
blob7235d9ae123e555f8d4dbf11b7ec2e505ff1d6a9
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.
35 * Contributor(s):
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>
43 #include "cairoint.h"
45 #include "cairo-error-private.h"
46 #include "cairo-gl-private.h"
48 #define MAX_MSAA_SAMPLES 4
50 static void
51 _gl_lock (void *device)
53 cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
55 ctx->acquire (ctx);
58 static void
59 _gl_unlock (void *device)
61 cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
63 ctx->release (ctx);
66 static cairo_status_t
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))
74 return 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;
88 ctx->vertex_size = 0;
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);
95 glDisable (GL_BLEND);
97 return _cairo_gl_context_release (ctx, status);
100 static void
101 _gl_finish (void *device)
103 cairo_gl_context_t *ctx = device;
104 int n;
106 _gl_lock (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]);
115 _gl_unlock (device);
118 static void
119 _gl_destroy (void *device)
121 cairo_gl_context_t *ctx = device;
123 ctx->acquire (ctx);
125 while (! cairo_list_is_empty (&ctx->fonts)) {
126 cairo_gl_font_t *font;
128 font = cairo_list_first_entry (&ctx->fonts,
129 cairo_gl_font_t,
130 link);
132 cairo_list_del (&font->base.link);
133 cairo_list_del (&font->link);
134 free (font);
137 _cairo_array_fini (&ctx->tristrip_indices);
139 cairo_region_destroy (ctx->clip_region);
140 _cairo_clip_destroy (ctx->clip);
142 free (ctx->vb);
144 ctx->destroy (ctx);
146 free (ctx);
149 static const cairo_device_backend_t _cairo_gl_device_backend = {
150 CAIRO_DEVICE_TYPE_GL,
152 _gl_lock,
153 _gl_unlock,
155 _gl_flush, /* flush */
156 _gl_finish,
157 _gl_destroy,
160 static cairo_bool_t
161 _cairo_gl_msaa_compositor_enabled (void)
163 const char *env = getenv ("CAIRO_GL_COMPOSITOR");
164 return env && strcmp(env, "msaa") == 0;
167 static cairo_bool_t
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)
172 return TRUE;
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())
179 return FALSE;
180 return _cairo_gl_has_extension ("EXT_read_format_bgra");
183 cairo_status_t
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 ();
190 int n;
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
199 * testing.
201 if (_cairo_gl_msaa_compositor_enabled ())
202 ctx->compositor = _cairo_gl_msaa_compositor_get ();
203 else
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 */
217 if (is_desktop) {
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;
224 } else
225 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
226 } else {
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;
231 else
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);
264 #endif
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);
271 #endif
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);
278 #endif
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))
290 return status;
292 status = _cairo_cache_init (&ctx->gradients,
293 _cairo_gl_gradient_equal,
294 NULL,
295 (cairo_destroy_func_t) _cairo_gl_gradient_destroy,
296 CAIRO_GL_GRADIENT_CACHE_SIZE);
297 if (unlikely (status))
298 return 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;
327 void
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) {
332 if (tex_unit < 2) {
333 _cairo_gl_composite_flush (ctx);
334 _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
336 glActiveTexture (ctx->max_textures - 1);
337 } else {
338 glActiveTexture (GL_TEXTURE0 + tex_unit);
342 static GLenum
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;
350 #endif
352 #if CAIRO_HAS_GLESV2_SURFACE
353 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
354 return GL_DEPTH24_STENCIL8_OES;
355 #endif
357 #if CAIRO_HAS_GL_SURFACE
358 return GL_DEPTH_STENCIL;
359 #elif CAIRO_HAS_GLESV2_SURFACE
360 return GL_DEPTH24_STENCIL8_OES;
361 #endif
364 #if CAIRO_HAS_GLESV2_SURFACE
365 static void
366 _cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
367 cairo_gl_surface_t *surface)
369 if (surface->msaa_active)
370 return;
372 ctx->dispatch.FramebufferTexture2DMultisample(GL_FRAMEBUFFER,
373 GL_COLOR_ATTACHMENT0,
374 ctx->tex_target,
375 surface->tex,
377 ctx->num_samples);
379 /* From now on MSAA will always be active on this surface. */
380 surface->msaa_active = TRUE;
382 #endif
384 static void
385 _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
386 cairo_gl_surface_t *surface)
388 GLenum status;
389 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
391 if (likely (surface->fb))
392 return;
394 /* Create a framebuffer object wrapping the texture so that we can render
395 * to it.
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);
407 } else
408 #endif
409 dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
410 GL_COLOR_ATTACHMENT0,
411 ctx->tex_target,
412 surface->tex,
415 #if CAIRO_HAS_GL_SURFACE
416 glDrawBuffer (GL_COLOR_ATTACHMENT0);
417 glReadBuffer (GL_COLOR_ATTACHMENT0);
418 #endif
420 status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
421 if (status != GL_FRAMEBUFFER_COMPLETE) {
422 const char *str;
423 switch (status) {
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;
434 fprintf (stderr,
435 "destination is framebuffer incomplete: %s [%#x]\n",
436 str, status);
439 #if CAIRO_HAS_GL_SURFACE
440 static void
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)
448 return;
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
460 this information. */
461 ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
462 ctx->num_samples,
463 GL_RGBA,
464 surface->width,
465 surface->height);
466 ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
467 GL_COLOR_ATTACHMENT0,
468 GL_RENDERBUFFER,
469 surface->msaa_rb);
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);
476 #endif
478 static cairo_bool_t
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)
484 return TRUE;
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);
490 #endif
492 dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
493 dispatch->BindRenderbuffer (GL_RENDERBUFFER,
494 surface->msaa_depth_stencil);
496 dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER,
497 ctx->num_samples,
498 _get_depth_stencil_format (ctx),
499 surface->width,
500 surface->height);
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,
506 GL_RENDERBUFFER,
507 surface->msaa_depth_stencil);
509 #endif
511 #if CAIRO_HAS_GLESV2_SURFACE
512 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
513 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
514 GL_DEPTH_ATTACHMENT,
515 GL_RENDERBUFFER,
516 surface->msaa_depth_stencil);
517 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
518 GL_STENCIL_ATTACHMENT,
519 GL_RENDERBUFFER,
520 surface->msaa_depth_stencil);
522 #endif
524 if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
525 dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
526 surface->msaa_depth_stencil = 0;
527 return FALSE;
530 return TRUE;
533 static cairo_bool_t
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)
540 return TRUE;
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;
557 return FALSE;
560 return TRUE;
563 cairo_bool_t
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)
570 return FALSE;
572 if (surface->msaa_active)
573 return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface);
574 else
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:
584 * glLoadIdentity()
585 * gluOrtho2D()
587 * The calculation for the ortho tranformation was taken from the
588 * mesa source code.
590 static void
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);
597 M(0,1) = 0.f;
598 M(0,2) = 0.f;
599 M(0,3) = -(right + left) / (right - left);
601 M(1,0) = 0.f;
602 M(1,1) = 2.f / (top - bottom);
603 M(1,2) = 0.f;
604 M(1,3) = -(top + bottom) / (top - bottom);
606 M(2,0) = 0.f;
607 M(2,1) = 0.f;
608 M(2,2) = -1.f;
609 M(2,3) = 0.f;
611 M(3,0) = 0.f;
612 M(3,1) = 0.f;
613 M(3,2) = 0.f;
614 M(3,3) = 1.f;
615 #undef M
618 #if CAIRO_HAS_GL_SURFACE
619 static void
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);
635 return;
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);
662 #endif
664 #if CAIRO_HAS_GL_SURFACE
665 static void
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);
678 return;
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);
705 #endif
707 void
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);
718 return;
721 #if CAIRO_HAS_GL_SURFACE
722 if (multisampling)
723 bind_multisample_framebuffer (ctx, surface);
724 else
725 bind_singlesample_framebuffer (ctx, surface);
726 #endif
727 } else {
728 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
730 #if CAIRO_HAS_GL_SURFACE
731 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
732 if (multisampling)
733 glEnable (GL_MULTISAMPLE);
734 else
735 glDisable (GL_MULTISAMPLE);
737 #endif
740 surface->msaa_active = multisampling;
743 void
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)
758 return;
760 if (! changing_surface) {
761 _cairo_gl_composite_flush (ctx);
762 _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
763 return;
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);
781 #endif
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);
790 else
791 _gl_identity_ortho (ctx->modelviewprojection_matrix,
792 0, surface->width, surface->height, 0);
795 void
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);
801 return;
803 ((cairo_gl_context_t *) device)->thread_aware = thread_aware;