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 #if CAIRO_HAS_EVASGL_SURFACE
50 #include "cairo-evas-gl.h"
53 #define MAX_MSAA_SAMPLES 4
56 _cairo_gl_image_cache_init (cairo_gl_context_t *ctx, int width, int height,
57 cairo_gl_image_cache_t **image_cache)
59 cairo_surface_t *cache_surface = _cairo_gl_surface_create_scratch (ctx,
60 CAIRO_CONTENT_COLOR_ALPHA,
62 if (unlikely (cache_surface->status)) {
63 cairo_surface_destroy (cache_surface);
64 return CAIRO_INT_STATUS_UNSUPPORTED;
67 _cairo_surface_release_device_reference (cache_surface);
68 *image_cache = _cairo_malloc (sizeof (cairo_gl_image_cache_t));
69 if (*image_cache == NULL)
70 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
72 (*image_cache)->surface = (cairo_gl_surface_t *)cache_surface;
73 (*image_cache)->surface->supports_msaa = FALSE;
75 _cairo_rtree_init (&((*image_cache)->rtree), width, height,
77 sizeof (cairo_gl_image_t),
78 _cairo_gl_image_node_destroy);
80 (*image_cache)->copy_success = TRUE;
81 return CAIRO_INT_STATUS_SUCCESS;
85 _cairo_gl_image_cache_fini (cairo_gl_context_t *ctx)
87 if (ctx->image_cache) {
88 _cairo_rtree_fini (&ctx->image_cache->rtree);
89 cairo_surface_destroy (&ctx->image_cache->surface->base);
91 free (ctx->image_cache);
95 _gl_lock (void *device)
97 cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
103 _gl_unlock (void *device)
105 cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
110 static cairo_status_t
111 _gl_flush (void *device)
113 cairo_gl_context_t *ctx;
114 cairo_status_t status;
116 status = _cairo_gl_context_acquire (device, &ctx);
117 if (unlikely (status))
120 _cairo_gl_composite_flush (ctx);
122 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
123 _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
125 if (ctx->clip_region) {
126 cairo_region_destroy (ctx->clip_region);
127 ctx->clip_region = NULL;
130 ctx->current_target = NULL;
131 ctx->current_operator = -1;
132 ctx->vertex_size = 0;
133 ctx->pre_shader = NULL;
134 _cairo_gl_set_shader (ctx, NULL);
136 ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0);
138 _cairo_gl_context_reset (ctx);
140 _disable_scissor_buffer (ctx);
142 if (ctx->states_cache.blend_enabled == TRUE ) {
143 ctx->dispatch.Disable (GL_BLEND);
144 ctx->states_cache.blend_enabled = FALSE;
147 return _cairo_gl_context_release (ctx, status);
151 _gl_finish (void *device)
153 cairo_gl_context_t *ctx = device;
158 _cairo_cache_fini (&ctx->gradients);
160 _cairo_gl_context_fini_shaders (ctx);
162 for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
163 _cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
166 _cairo_gl_image_cache_fini (ctx);
172 _gl_destroy (void *device)
176 cairo_gl_context_t *ctx = device;
180 if(ctx->glyph_mask) {
181 cairo_surface_destroy (&ctx->glyph_mask->base);
182 ctx->glyph_mask = NULL;
185 for (n = 0; n < 2; n++) {
186 if (ctx->source_scratch_surfaces[n])
187 cairo_surface_destroy (&ctx->source_scratch_surfaces[n]->base);
188 if (ctx->mask_scratch_surfaces[n])
189 cairo_surface_destroy (&ctx->mask_scratch_surfaces[n]->base);
190 if (ctx->shadow_scratch_surfaces[n])
191 cairo_surface_destroy (&ctx->shadow_scratch_surfaces[n]->base);
193 if (ctx->shadow_scratch_surfaces[2])
194 cairo_surface_destroy (&ctx->shadow_scratch_surfaces[2]->base);
196 for (n = 0; n < 4; n++) {
197 if (ctx->shadow_masks[n])
198 cairo_surface_destroy (&ctx->shadow_masks[n]->base);
201 while (! cairo_list_is_empty (&ctx->fonts)) {
202 cairo_gl_font_t *font;
204 font = cairo_list_first_entry (&ctx->fonts,
208 cairo_list_del (&font->base.link);
209 cairo_list_del (&font->link);
213 _cairo_array_fini (&ctx->tristrip_indices);
215 cairo_region_destroy (ctx->clip_region);
224 static const cairo_device_backend_t _cairo_gl_device_backend = {
225 CAIRO_DEVICE_TYPE_GL,
230 _gl_flush, /* flush */
236 _cairo_gl_msaa_compositor_enabled (void)
238 const char *env = getenv ("CAIRO_GL_COMPOSITOR");
239 return env && strcmp(env, "msaa") == 0;
243 test_can_read_bgra (cairo_gl_context_t *ctx, cairo_gl_flavor_t gl_flavor)
245 /* Desktop GL always supports BGRA formats. */
246 if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
249 assert (gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
250 gl_flavor == CAIRO_GL_FLAVOR_ES3);
252 /* For OpenGL ES we have to look for the specific extension and BGRA only
253 * matches cairo's integer packed bytes on little-endian machines. */
254 if (!_cairo_is_little_endian())
256 return _cairo_gl_has_extension (&ctx->dispatch, "EXT_read_format_bgra");
260 _cairo_gl_context_init (cairo_gl_context_t *ctx)
262 cairo_status_t status;
263 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
264 int gl_version = _cairo_gl_get_version (dispatch);
265 cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor (dispatch);
268 cairo_bool_t is_desktop = gl_flavor == CAIRO_GL_FLAVOR_DESKTOP;
269 cairo_bool_t is_gles = (gl_flavor == CAIRO_GL_FLAVOR_ES2 ||
270 gl_flavor == CAIRO_GL_FLAVOR_ES3);
272 _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
274 /* XXX The choice of compositor should be made automatically at runtime.
275 * However, it is useful to force one particular compositor whilst
278 if (_cairo_gl_msaa_compositor_enabled ())
279 ctx->compositor = _cairo_gl_msaa_compositor_get ();
281 ctx->compositor = _cairo_gl_span_compositor_get ();
284 ctx->thread_aware = TRUE;
285 ctx->has_angle_multisampling = FALSE;
287 memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
288 cairo_list_init (&ctx->fonts);
290 /* Support only GL version >= 1.3 */
291 if (gl_version < CAIRO_GL_VERSION_ENCODE (1, 3))
292 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
294 /* Check for required extensions */
296 if (_cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_texture_non_power_of_two")) {
297 ctx->tex_target = GL_TEXTURE_2D;
298 ctx->has_npot_repeat = TRUE;
299 } else if (_cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_texture_rectangle")) {
300 ctx->tex_target = GL_TEXTURE_RECTANGLE;
301 ctx->has_npot_repeat = FALSE;
303 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
305 ctx->tex_target = GL_TEXTURE_2D;
306 if (_cairo_gl_has_extension (&ctx->dispatch, "GL_OES_texture_npot") ||
307 _cairo_gl_has_extension (&ctx->dispatch, "GL_IMG_texture_npot"))
308 ctx->has_npot_repeat = TRUE;
310 ctx->has_npot_repeat = FALSE;
313 if (is_desktop && gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
314 ! _cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_pixel_buffer_object"))
315 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
317 if (is_gles && ! _cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_texture_format_BGRA8888"))
318 return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
320 ctx->has_map_buffer =
321 is_desktop || (is_gles && _cairo_gl_has_extension (&ctx->dispatch, "GL_OES_mapbuffer"));
323 ctx->can_read_bgra = test_can_read_bgra (ctx, gl_flavor);
325 ctx->has_mesa_pack_invert =
326 _cairo_gl_has_extension (&ctx->dispatch, "GL_MESA_pack_invert");
328 ctx->has_packed_depth_stencil =
329 (is_desktop && _cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_packed_depth_stencil")) ||
330 (is_gles && _cairo_gl_has_extension (&ctx->dispatch, "GL_OES_packed_depth_stencil"));
332 ctx->num_samples = 1;
333 ctx->msaa_type = CAIRO_GL_NONE_MULTISAMPLE_TO_TEXTURE;
335 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE
336 if (is_desktop && ctx->has_packed_depth_stencil &&
337 (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
338 _cairo_gl_has_extension (&ctx->dispatch, "GL_ARB_framebuffer_object") ||
339 (_cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_framebuffer_blit") &&
340 _cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_framebuffer_multisample")))) {
341 ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
345 #if (CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE) && GL_MAX_SAMPLES_EXT
346 if (is_gles && ctx->has_packed_depth_stencil &&
347 _cairo_gl_has_extension (&ctx->dispatch, "GL_EXT_multisampled_render_to_texture")) {
348 ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
349 ctx->msaa_type = CAIRO_GL_EXT_MULTISAMPLE_TO_TEXTURE;
353 #if (CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE) && GL_MAX_SAMPLES_IMG
354 if (ctx->msaa_type == CAIRO_GL_NONE_MULTISAMPLE_TO_TEXTURE &&
356 ctx->has_packed_depth_stencil &&
357 _cairo_gl_has_extension (&ctx->dispatch, "GL_IMG_multisampled_render_to_texture")) {
358 ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_IMG, &ctx->num_samples);
359 ctx->msaa_type = CAIRO_GL_IMG_MULTISAMPLE_TO_TEXTURE;
363 #if (CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE) && GL_MAX_SAMPLES_ANGLE
364 if (ctx->msaa_type == CAIRO_GL_NONE_MULTISAMPLE_TO_TEXTURE &&
366 ctx->has_packed_depth_stencil &&
367 _cairo_gl_has_extension (&ctx->dispatch, "GL_ANGLE_framebuffer_blit") &&
368 _cairo_gl_has_extension (&ctx->dispatch, "GL_ANGLE_framebuffer_multisample")) {
369 ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES_ANGLE, &ctx->num_samples);
370 ctx->has_angle_multisampling = TRUE;
374 #if CAIRO_HAS_GLESV3_SURFACE || CAIRO_HAS_EVASGL_SURFACE
375 if (ctx->msaa_type == CAIRO_GL_NONE_MULTISAMPLE_TO_TEXTURE &&
376 is_gles && ctx->has_packed_depth_stencil) {
377 ctx->dispatch.GetIntegerv(GL_MAX_SAMPLES, &ctx->num_samples);
378 /* this is work around for evasgl. At this moment, if
379 we still get samples == 1, it means gles2 does not have any
380 support for extensions we have supported
382 if (gl_flavor == CAIRO_GL_FLAVOR_ES2)
383 ctx->num_samples = 1;
387 /* we always use renderbuffer for rendering in glesv3 */
388 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
389 (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
390 ctx->has_angle_multisampling))
391 ctx->supports_msaa = TRUE;
393 ctx->supports_msaa = ctx->num_samples > 1;
394 if (ctx->num_samples > MAX_MSAA_SAMPLES)
395 ctx->num_samples = MAX_MSAA_SAMPLES;
398 ctx->current_operator = -1;
399 ctx->gl_flavor = gl_flavor;
401 status = _cairo_gl_context_init_shaders (ctx);
402 if (unlikely (status))
405 status = _cairo_cache_init (&ctx->gradients,
406 _cairo_gl_gradient_equal,
408 (cairo_destroy_func_t) _cairo_gl_gradient_destroy,
409 CAIRO_GL_GRADIENT_CACHE_SIZE);
410 if (unlikely (status))
413 ctx->vb = malloc (CAIRO_GL_VBO_SIZE);
414 if (unlikely (ctx->vb == NULL)) {
415 _cairo_cache_fini (&ctx->gradients);
416 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
419 ctx->primitive_type = CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES;
420 _cairo_array_init (&ctx->tristrip_indices, sizeof (unsigned short));
422 /* PBO for any sort of texture upload */
423 dispatch->GenBuffers (1, &ctx->texture_load_pbo);
425 ctx->max_framebuffer_size = 0;
426 ctx->dispatch.GetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size);
427 ctx->max_texture_size = 0;
428 ctx->dispatch.GetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
429 ctx->max_textures = 0;
430 ctx->dispatch.GetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures);
432 for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
433 _cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
435 ctx->image_cache = NULL;
437 for (n = 0; n < 2; n++) {
438 ctx->source_scratch_surfaces[n] = NULL;
439 ctx->mask_scratch_surfaces[n] = NULL;
440 ctx->shadow_scratch_surfaces[n] = NULL;
443 for (n = 0; n < 4; n++)
444 ctx->shadow_masks[n] = NULL;
446 ctx->source_scratch_in_use = FALSE;
448 _cairo_gl_context_reset (ctx);
450 return CAIRO_STATUS_SUCCESS;
454 _cairo_gl_context_activate (cairo_gl_context_t *ctx,
455 cairo_gl_tex_t tex_unit)
457 if (ctx->max_textures <= (GLint) tex_unit) {
459 _cairo_gl_composite_flush (ctx);
460 _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
462 if (ctx->states_cache.active_texture != ctx->max_textures - 1) {
463 ctx->dispatch.ActiveTexture (ctx->max_textures - 1);
464 ctx->states_cache.active_texture = ctx->max_textures - 1;
467 if (ctx->states_cache.active_texture != GL_TEXTURE0 + tex_unit) {
468 ctx->dispatch.ActiveTexture (GL_TEXTURE0 + tex_unit);
469 ctx->states_cache.active_texture = GL_TEXTURE0 + tex_unit;
475 _get_depth_stencil_format (cairo_gl_context_t *ctx)
477 /* This is necessary to properly handle the situation where both
478 OpenGL and OpenGLES are active and returning a sane default. */
479 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE
480 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
481 return GL_DEPTH_STENCIL;
484 #if CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE
485 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
486 return GL_DEPTH24_STENCIL8_OES;
489 #if CAIRO_HAS_GL_SURFACE
490 return GL_DEPTH_STENCIL;
491 #elif CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE
492 return GL_DEPTH24_STENCIL8_OES;
493 #elif CAIRO_HAS_GLESV3_SURFACE || CAIRO_HAS_EVASGL_SURFACE
494 return GL_DEPTH24_STENCIL8;
499 _cairo_gl_clear_framebuffer (cairo_gl_context_t *ctx,
500 cairo_gl_surface_t *surface)
502 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
505 if (_cairo_gl_surface_is_scratch (ctx, surface)) {
506 _disable_scissor_buffer (ctx);
507 _disable_stencil_buffer (ctx);
508 ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
512 #if CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE
514 _cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
515 cairo_gl_surface_t *surface)
517 if (ctx->has_angle_multisampling)
520 if (surface->msaa_active)
523 ctx->dispatch.FramebufferTexture2DMultisample(GL_FRAMEBUFFER,
524 GL_COLOR_ATTACHMENT0,
530 /* From now on MSAA will always be active on this surface. */
531 surface->msaa_active = TRUE;
536 _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
537 cairo_gl_surface_t *surface)
540 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
542 if (likely (surface->fb))
545 /* Create a framebuffer object wrapping the texture so that we can render
548 dispatch->GenFramebuffers (1, &surface->fb);
549 dispatch->BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
551 /* Unlike for desktop GL we only maintain one multisampling framebuffer
552 for OpenGLES since the EXT_multisampled_render_to_texture extension
553 does not require an explicit multisample resolution. */
554 #if CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE
555 if (surface->supports_msaa && _cairo_gl_msaa_compositor_enabled () &&
556 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
557 ! ctx->has_angle_multisampling) {
558 _cairo_gl_ensure_msaa_gles_framebuffer (ctx, surface);
561 dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
562 GL_COLOR_ATTACHMENT0,
567 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE
568 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
569 ctx->dispatch.DrawBuffer &&
570 ctx->dispatch.ReadBuffer) {
571 ctx->dispatch.DrawBuffer (GL_COLOR_ATTACHMENT0);
572 ctx->dispatch.ReadBuffer (GL_COLOR_ATTACHMENT0);
576 status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
577 if (status != GL_FRAMEBUFFER_COMPLETE) {
580 //case GL_FRAMEBUFFER_UNDEFINED: str= "undefined"; break;
581 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: str= "incomplete attachment"; break;
582 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: str= "incomplete/missing attachment"; break;
583 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: str= "incomplete draw buffer"; break;
584 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: str= "incomplete read buffer"; break;
585 case GL_FRAMEBUFFER_UNSUPPORTED: str= "unsupported"; break;
586 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: str= "incomplete multiple"; break;
587 default: str = "unknown error"; break;
591 "destination is framebuffer incomplete: %s [%#x]\n",
597 _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
598 cairo_gl_surface_t *surface)
602 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
603 ! ctx->has_angle_multisampling)
606 assert (surface->supports_msaa);
608 if (surface->msaa_fb)
611 /* We maintain a separate framebuffer for multisampling operations.
612 This allows us to do a fast paint to the non-multisampling framebuffer
613 when mulitsampling is disabled. */
614 ctx->dispatch.GenFramebuffers (1, &surface->msaa_fb);
615 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
616 ctx->dispatch.GenRenderbuffers (1, &surface->msaa_rb);
617 ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, surface->msaa_rb);
619 /* FIXME: For now we assume that textures passed from the outside have GL_RGBA
620 format, but eventually we need to expose a way for the API consumer to pass
622 #if CAIRO_HAS_GLESV3_SURFACE || CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE
623 #if CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_GLESV3_SURFACE
626 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
634 ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
640 ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
641 GL_COLOR_ATTACHMENT0,
645 if (ctx->dispatch.CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
646 ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_rb);
647 surface->msaa_rb = 0;
648 ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_fb);
649 surface->msaa_fb = 0;
653 /* Cairo surfaces start out initialized to transparent (black) */
654 _disable_scissor_buffer (ctx);
655 ctx->dispatch.ClearColor (0, 0, 0, 0);
656 // reset cached clear colors
657 memset (&ctx->states_cache.clear_red, 0, sizeof (GLclampf) * 4);
658 ctx->dispatch.Clear (GL_COLOR_BUFFER_BIT);
662 _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
663 cairo_gl_surface_t *surface)
665 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
666 if (surface->msaa_depth_stencil)
669 _cairo_gl_ensure_multisampling (ctx, surface);
671 dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
672 dispatch->BindRenderbuffer (GL_RENDERBUFFER,
673 surface->msaa_depth_stencil);
675 dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER,
677 _get_depth_stencil_format (ctx),
681 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE || CAIRO_HAS_EVASGL_SURFACE
682 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
683 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) {
684 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
685 GL_DEPTH_STENCIL_ATTACHMENT,
687 surface->msaa_depth_stencil);
691 #if CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE
692 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) {
693 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
696 surface->msaa_depth_stencil);
697 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
698 GL_STENCIL_ATTACHMENT,
700 surface->msaa_depth_stencil);
704 if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
705 dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
706 surface->msaa_depth_stencil = 0;
714 _cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
715 cairo_gl_surface_t *surface)
717 cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
719 if (surface->depth_stencil)
722 _cairo_gl_ensure_framebuffer (ctx, surface);
724 dispatch->GenRenderbuffers (1, &surface->depth_stencil);
725 dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
726 dispatch->RenderbufferStorage (GL_RENDERBUFFER,
727 _get_depth_stencil_format (ctx),
728 surface->width, surface->height);
730 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
731 GL_RENDERBUFFER, surface->depth_stencil);
732 dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
733 GL_RENDERBUFFER, surface->depth_stencil);
734 if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
735 dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
736 surface->depth_stencil = 0;
744 _cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
745 cairo_gl_surface_t *surface)
747 if (! _cairo_gl_surface_is_texture (surface))
748 return TRUE; /* best guess for now, will check later */
749 if (! ctx->has_packed_depth_stencil)
752 if (surface->msaa_active)
753 return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface);
755 return _cairo_gl_ensure_depth_stencil_buffer (ctx, surface);
759 * Stores a parallel projection transformation in matrix 'm',
760 * using column-major order.
762 * This is equivalent to:
767 * The calculation for the ortho tranformation was taken from the
771 _gl_identity_ortho (GLfloat *m,
772 GLfloat left, GLfloat right,
773 GLfloat bottom, GLfloat top)
775 #define M(row,col) m[col*4+row]
776 M(0,0) = 2.f / (right - left);
779 M(0,3) = -(right + left) / (right - left);
782 M(1,1) = 2.f / (top - bottom);
784 M(1,3) = -(top + bottom) / (top - bottom);
799 bind_multisample_framebuffer (cairo_gl_context_t *ctx,
800 cairo_gl_surface_t *surface)
802 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE
803 cairo_bool_t stencil_test_enabled, scissor_test_enabled;
804 cairo_bool_t has_stencil_cache;
807 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
808 stencil_test_enabled = ctx->states_cache.stencil_test_enabled;
809 scissor_test_enabled = ctx->states_cache.scissor_test_enabled;
811 has_stencil_cache = surface->clip_on_stencil_buffer ? TRUE : FALSE;
812 mask = GL_COLOR_BUFFER_BIT;
815 assert (surface->supports_msaa);
817 _cairo_gl_ensure_framebuffer (ctx, surface);
818 _cairo_gl_ensure_multisampling (ctx, surface);
820 if (surface->msaa_active) {
821 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE
822 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
823 ctx->dispatch.Enable (GL_MULTISAMPLE);
826 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
830 _cairo_gl_composite_flush (ctx);
832 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE
833 /* we must disable scissor and stencil test */
834 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
835 _disable_stencil_buffer (ctx);
836 _disable_scissor_buffer (ctx);
838 ctx->dispatch.Enable (GL_MULTISAMPLE);
840 if (has_stencil_cache)
841 mask |= GL_STENCIL_BUFFER_BIT;
843 /* The last time we drew to the surface, we were not using multisampling,
844 so we need to blit from the non-multisampling framebuffer into the
845 multisampling framebuffer. */
846 ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->msaa_fb);
847 ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb);
848 ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
849 0, 0, surface->width, surface->height,
851 surface->content_synced = TRUE;
854 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
856 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE
857 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
858 /* re-enable stencil and scissor test */
859 if (scissor_test_enabled)
860 _enable_scissor_buffer (ctx);
861 if (stencil_test_enabled)
862 _enable_stencil_buffer (ctx);
868 bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
869 cairo_gl_surface_t *surface)
871 cairo_bool_t has_stencil_cache = surface->clip_on_stencil_buffer ? TRUE : FALSE;
872 cairo_bool_t stencil_test_enabled = ctx->states_cache.stencil_test_enabled;
873 cairo_bool_t scissor_test_enabled = ctx->states_cache.scissor_test_enabled;
874 GLbitfield mask = GL_COLOR_BUFFER_BIT;
876 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
877 ! ctx->has_angle_multisampling)
880 _cairo_gl_ensure_framebuffer (ctx, surface);
882 if (! surface->msaa_active) {
883 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_FLAVOR
884 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
885 ctx->dispatch.Disable (GL_MULTISAMPLE);
887 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
891 _cairo_gl_composite_flush (ctx);
893 /* we must disable scissor and stencil test */
894 _disable_stencil_buffer (ctx);
895 _disable_scissor_buffer (ctx);
896 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_FLAVOR
897 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
898 ctx->dispatch.Disable (GL_MULTISAMPLE);
901 if (has_stencil_cache)
902 mask |= GL_STENCIL_BUFFER_BIT;
904 /* The last time we drew to the surface, we were using multisampling,
905 so we need to blit from the multisampling framebuffer into the
906 non-multisampling framebuffer. */
907 #if CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_EVASGL_SURFACE
908 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) {
909 ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER_ANGLE, surface->fb);
910 ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER_ANGLE, surface->msaa_fb);
912 #if CAIRO_HAS_EVASGL_SURFACE
914 ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb);
915 ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->msaa_fb);
919 ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb);
920 ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->msaa_fb);
922 ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
923 0, 0, surface->width, surface->height,
925 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
927 surface->content_synced = TRUE;
928 /* re-enable stencil and scissor test */
929 if (scissor_test_enabled)
930 _enable_scissor_buffer (ctx);
931 if (stencil_test_enabled)
932 _enable_stencil_buffer (ctx);
936 _cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx,
937 cairo_gl_surface_t *surface,
938 cairo_bool_t multisampling)
940 if (_cairo_gl_surface_is_texture (surface)) {
941 /* OpenGL ES surfaces only have either a multisample framebuffer or a
942 * singlesample framebuffer, so we cannot switch back and forth. */
943 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
944 ! ctx->has_angle_multisampling) {
945 _cairo_gl_ensure_framebuffer (ctx, surface);
946 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
947 _cairo_gl_clear_framebuffer (ctx, surface);
952 bind_multisample_framebuffer (ctx, surface);
954 bind_singlesample_framebuffer (ctx, surface);
956 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_GLESV3_SURFACE
957 ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
960 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE
961 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
963 ctx->dispatch.Enable (GL_MULTISAMPLE);
965 ctx->dispatch.Disable (GL_MULTISAMPLE);
970 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
971 ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
972 (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
973 ctx->has_angle_multisampling))
974 surface->msaa_active = multisampling;
976 if (ctx->gl_flavor != CAIRO_GL_FLAVOR_DESKTOP && multisampling)
977 _cairo_gl_clear_framebuffer (ctx, surface);
981 _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
982 cairo_gl_surface_t *surface,
983 cairo_bool_t multisampling)
985 cairo_bool_t changing_surface, changing_sampling;
987 /* The decision whether or not to use multisampling happens when
988 * we create an OpenGL ES surface, so we can never switch modes. */
989 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
990 ! ctx->has_angle_multisampling)
991 multisampling = surface->msaa_active;
993 changing_surface = ctx->current_target != surface || surface->size_changed;
994 changing_sampling = surface->msaa_active != multisampling;
996 if (! changing_surface && ! changing_sampling) {
997 if (surface->needs_update)
998 _cairo_gl_composite_flush (ctx);
1001 if (! changing_surface) {
1002 _cairo_gl_composite_flush (ctx);
1003 _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
1007 _cairo_gl_composite_flush (ctx);
1009 ctx->current_target = surface;
1010 surface->needs_update = FALSE;
1012 if (! _cairo_gl_surface_is_texture (surface)) {
1013 ctx->make_current (ctx, surface);
1016 _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
1018 if (! _cairo_gl_surface_is_texture (surface)) {
1019 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_EVASGL_SURFACE
1020 if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
1021 ctx->dispatch.DrawBuffer &&
1022 ctx->dispatch.ReadBuffer) {
1023 ctx->dispatch.DrawBuffer (GL_BACK_LEFT);
1024 ctx->dispatch.ReadBuffer (GL_BACK_LEFT);
1029 ctx->dispatch.Disable (GL_DITHER);
1030 if (ctx->states_cache.viewport_box.width != surface->width ||
1031 ctx->states_cache.viewport_box.height != surface->height) {
1032 ctx->dispatch.Viewport (0, 0, surface->width, surface->height);
1033 ctx->states_cache.viewport_box.width = surface->width;
1034 ctx->states_cache.viewport_box.height = surface->height;
1037 if (_cairo_gl_surface_is_texture (surface))
1038 _gl_identity_ortho (ctx->modelviewprojection_matrix,
1039 0, surface->width, 0, surface->height);
1041 _gl_identity_ortho (ctx->modelviewprojection_matrix,
1042 0, surface->width, surface->height, 0);
1046 cairo_gl_device_set_thread_aware (cairo_device_t *device,
1047 cairo_bool_t thread_aware)
1049 if ((! device)||(cairo_device_status(device)!= CAIRO_STATUS_SUCCESS)) {
1050 fprintf (stderr, "cairo_gl_device_set_thread_aware(): cairo_device is NULL or not available\n");
1051 _cairo_error_throw (CAIRO_STATUS_DEVICE_ERROR);
1054 if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
1055 _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
1058 if(thread_aware == 0 || thread_aware == 1){
1059 ((cairo_gl_context_t *) device)->thread_aware = thread_aware;
1062 _cairo_device_set_error (device, CAIRO_STATUS_INVALID_STATUS);
1067 void _cairo_gl_context_reset (cairo_gl_context_t *ctx)
1069 ctx->states_cache.viewport_box.width = 0;
1070 ctx->states_cache.viewport_box.height = 0;
1072 ctx->states_cache.clear_red = -1;
1073 ctx->states_cache.clear_green = -1;
1074 ctx->states_cache.clear_blue = -1;
1075 ctx->states_cache.clear_alpha = -1;
1077 ctx->states_cache.blend_enabled = FALSE;
1079 ctx->states_cache.src_color_factor = CAIRO_GL_ENUM_UNINITIALIZED;
1080 ctx->states_cache.dst_color_factor = CAIRO_GL_ENUM_UNINITIALIZED;
1081 ctx->states_cache.src_alpha_factor = CAIRO_GL_ENUM_UNINITIALIZED;
1082 ctx->states_cache.dst_alpha_factor = CAIRO_GL_ENUM_UNINITIALIZED;
1084 ctx->states_cache.active_texture = CAIRO_GL_ENUM_UNINITIALIZED;
1086 ctx->states_cache.depth_mask = FALSE;
1088 /* FIXME: this is hack to fix mali driver*/
1089 ctx->dispatch.Disable (GL_DITHER);
1091 ctx->current_shader = NULL;