Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /* cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2009 Eric Anholt
  4.  * Copyright © 2009 Chris Wilson
  5.  * Copyright © 2005,2010 Red Hat, Inc
  6.  * Copyright © 2010 Linaro Limited
  7.  *
  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.
  15.  *
  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
  21.  *
  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/
  26.  *
  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.
  30.  *
  31.  * The Original Code is the cairo graphics library.
  32.  *
  33.  * The Initial Developer of the Original Code is Red Hat, Inc.
  34.  *
  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>
  41.  */
  42.  
  43. #include "cairoint.h"
  44.  
  45. #include "cairo-error-private.h"
  46. #include "cairo-gl-private.h"
  47.  
  48. #define MAX_MSAA_SAMPLES 4
  49.  
  50. static void
  51. _gl_lock (void *device)
  52. {
  53.     cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
  54.  
  55.     ctx->acquire (ctx);
  56. }
  57.  
  58. static void
  59. _gl_unlock (void *device)
  60. {
  61.     cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
  62.  
  63.     ctx->release (ctx);
  64. }
  65.  
  66. static cairo_status_t
  67. _gl_flush (void *device)
  68. {
  69.     cairo_gl_context_t *ctx;
  70.     cairo_status_t status;
  71.  
  72.     status = _cairo_gl_context_acquire (device, &ctx);
  73.     if (unlikely (status))
  74.         return status;
  75.  
  76.     _cairo_gl_composite_flush (ctx);
  77.  
  78.     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
  79.     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
  80.  
  81.     if (ctx->clip_region) {
  82.         cairo_region_destroy (ctx->clip_region);
  83.         ctx->clip_region = NULL;
  84.     }
  85.  
  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);
  91.  
  92.     ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0);
  93.  
  94.     glDisable (GL_SCISSOR_TEST);
  95.     glDisable (GL_BLEND);
  96.  
  97.     return _cairo_gl_context_release (ctx, status);
  98. }
  99.  
  100. static void
  101. _gl_finish (void *device)
  102. {
  103.     cairo_gl_context_t *ctx = device;
  104.     int n;
  105.  
  106.     _gl_lock (device);
  107.  
  108.     _cairo_cache_fini (&ctx->gradients);
  109.  
  110.     _cairo_gl_context_fini_shaders (ctx);
  111.  
  112.     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
  113.         _cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
  114.  
  115.     _gl_unlock (device);
  116. }
  117.  
  118. static void
  119. _gl_destroy (void *device)
  120. {
  121.     cairo_gl_context_t *ctx = device;
  122.  
  123.     ctx->acquire (ctx);
  124.  
  125.     while (! cairo_list_is_empty (&ctx->fonts)) {
  126.         cairo_gl_font_t *font;
  127.  
  128.         font = cairo_list_first_entry (&ctx->fonts,
  129.                                        cairo_gl_font_t,
  130.                                        link);
  131.  
  132.         cairo_list_del (&font->base.link);
  133.         cairo_list_del (&font->link);
  134.         free (font);
  135.     }
  136.  
  137.     _cairo_array_fini (&ctx->tristrip_indices);
  138.  
  139.     cairo_region_destroy (ctx->clip_region);
  140.     _cairo_clip_destroy (ctx->clip);
  141.  
  142.     free (ctx->vb);
  143.  
  144.     ctx->destroy (ctx);
  145.  
  146.     free (ctx);
  147. }
  148.  
  149. static const cairo_device_backend_t _cairo_gl_device_backend = {
  150.     CAIRO_DEVICE_TYPE_GL,
  151.  
  152.     _gl_lock,
  153.     _gl_unlock,
  154.  
  155.     _gl_flush, /* flush */
  156.     _gl_finish,
  157.     _gl_destroy,
  158. };
  159.  
  160. static cairo_bool_t
  161. _cairo_gl_msaa_compositor_enabled (void)
  162. {
  163.     const char *env = getenv ("CAIRO_GL_COMPOSITOR");
  164.     return env && strcmp(env, "msaa") == 0;
  165. }
  166.  
  167. static cairo_bool_t
  168. test_can_read_bgra (cairo_gl_flavor_t gl_flavor)
  169. {
  170.     /* Desktop GL always supports BGRA formats. */
  171.     if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
  172.         return TRUE;
  173.  
  174.     assert (gl_flavor == CAIRO_GL_FLAVOR_ES);
  175.  
  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");
  181. }
  182.  
  183. cairo_status_t
  184. _cairo_gl_context_init (cairo_gl_context_t *ctx)
  185. {
  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;
  191.  
  192.     cairo_bool_t is_desktop = gl_flavor == CAIRO_GL_FLAVOR_DESKTOP;
  193.     cairo_bool_t is_gles = gl_flavor == CAIRO_GL_FLAVOR_ES;
  194.  
  195.     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
  196.  
  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.
  200.      */
  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 ();
  205.  
  206.  
  207.     ctx->thread_aware = TRUE;
  208.  
  209.     memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
  210.     cairo_list_init (&ctx->fonts);
  211.  
  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);
  215.  
  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;
  233.     }
  234.  
  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);
  238.  
  239.     if (is_gles && ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
  240.         return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
  241.  
  242.     ctx->has_map_buffer =
  243.         is_desktop || (is_gles && _cairo_gl_has_extension ("GL_OES_mapbuffer"));
  244.  
  245.     ctx->can_read_bgra = test_can_read_bgra (gl_flavor);
  246.  
  247.     ctx->has_mesa_pack_invert =
  248.         _cairo_gl_has_extension ("GL_MESA_pack_invert");
  249.  
  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"));
  253.  
  254.     ctx->num_samples = 1;
  255.  
  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);
  263.     }
  264. #endif
  265.  
  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);
  270.     }
  271. #endif
  272.  
  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);
  277.     }
  278. #endif
  279.  
  280.     ctx->supports_msaa = ctx->num_samples > 1;
  281.     if (ctx->num_samples > MAX_MSAA_SAMPLES)
  282.         ctx->num_samples = MAX_MSAA_SAMPLES;
  283.  
  284.  
  285.     ctx->current_operator = -1;
  286.     ctx->gl_flavor = gl_flavor;
  287.  
  288.     status = _cairo_gl_context_init_shaders (ctx);
  289.     if (unlikely (status))
  290.         return status;
  291.  
  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;
  299.  
  300.     ctx->vb = malloc (CAIRO_GL_VBO_SIZE);
  301.     if (unlikely (ctx->vb == NULL)) {
  302.             _cairo_cache_fini (&ctx->gradients);
  303.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  304.     }
  305.  
  306.     ctx->primitive_type = CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES;
  307.     _cairo_array_init (&ctx->tristrip_indices, sizeof (unsigned short));
  308.  
  309.     /* PBO for any sort of texture upload */
  310.     dispatch->GenBuffers (1, &ctx->texture_load_pbo);
  311.  
  312.     ctx->max_framebuffer_size = 0;
  313.     glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size);
  314.     ctx->max_texture_size = 0;
  315.     glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
  316.     ctx->max_textures = 0;
  317.     glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures);
  318.  
  319.     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
  320.         _cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
  321.  
  322.     return CAIRO_STATUS_SUCCESS;
  323. }
  324.  
  325. void
  326. _cairo_gl_context_activate (cairo_gl_context_t *ctx,
  327.                             cairo_gl_tex_t      tex_unit)
  328. {
  329.     if (ctx->max_textures <= (GLint) tex_unit) {
  330.         if (tex_unit < 2) {
  331.             _cairo_gl_composite_flush (ctx);
  332.             _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
  333.         }
  334.         glActiveTexture (ctx->max_textures - 1);
  335.     } else {
  336.         glActiveTexture (GL_TEXTURE0 + tex_unit);
  337.     }
  338. }
  339.  
  340. static GLenum
  341. _get_depth_stencil_format (cairo_gl_context_t *ctx)
  342. {
  343.     /* This is necessary to properly handle the situation where both
  344.        OpenGL and OpenGLES are active and returning a sane default. */
  345. #if CAIRO_HAS_GL_SURFACE
  346.     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
  347.         return GL_DEPTH_STENCIL;
  348. #endif
  349.  
  350. #if CAIRO_HAS_GLESV2_SURFACE
  351.     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
  352.         return GL_DEPTH24_STENCIL8_OES;
  353. #endif
  354.  
  355. #if CAIRO_HAS_GL_SURFACE
  356.     return GL_DEPTH_STENCIL;
  357. #elif CAIRO_HAS_GLESV2_SURFACE
  358.     return GL_DEPTH24_STENCIL8_OES;
  359. #endif
  360. }
  361.  
  362. #if CAIRO_HAS_GLESV2_SURFACE
  363. static void
  364. _cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
  365.                                         cairo_gl_surface_t *surface)
  366. {
  367.     if (surface->msaa_active)
  368.         return;
  369.  
  370.     ctx->dispatch.FramebufferTexture2DMultisample(GL_FRAMEBUFFER,
  371.                                                   GL_COLOR_ATTACHMENT0,
  372.                                                   ctx->tex_target,
  373.                                                   surface->tex,
  374.                                                   0,
  375.                                                   ctx->num_samples);
  376.  
  377.     /* From now on MSAA will always be active on this surface. */
  378.     surface->msaa_active = TRUE;
  379. }
  380. #endif
  381.  
  382. static void
  383. _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
  384.                               cairo_gl_surface_t *surface)
  385. {
  386.     GLenum status;
  387.     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
  388.  
  389.     if (likely (surface->fb))
  390.         return;
  391.  
  392.     /* Create a framebuffer object wrapping the texture so that we can render
  393.      * to it.
  394.      */
  395.     dispatch->GenFramebuffers (1, &surface->fb);
  396.     dispatch->BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
  397.  
  398.     /* Unlike for desktop GL we only maintain one multisampling framebuffer
  399.        for OpenGLES since the EXT_multisampled_render_to_texture extension
  400.        does not require an explicit multisample resolution. */
  401. #if CAIRO_HAS_GLESV2_SURFACE
  402.     if (surface->supports_msaa && _cairo_gl_msaa_compositor_enabled () &&
  403.         ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
  404.         _cairo_gl_ensure_msaa_gles_framebuffer (ctx, surface);
  405.     } else
  406. #endif
  407.         dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
  408.                                         GL_COLOR_ATTACHMENT0,
  409.                                         ctx->tex_target,
  410.                                         surface->tex,
  411.                                         0);
  412.  
  413. #if CAIRO_HAS_GL_SURFACE
  414.     glDrawBuffer (GL_COLOR_ATTACHMENT0);
  415.     glReadBuffer (GL_COLOR_ATTACHMENT0);
  416. #endif
  417.  
  418.     status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
  419.     if (status != GL_FRAMEBUFFER_COMPLETE) {
  420.         const char *str;
  421.         switch (status) {
  422.         //case GL_FRAMEBUFFER_UNDEFINED: str= "undefined"; break;
  423.         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: str= "incomplete attachment"; break;
  424.         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: str= "incomplete/missing attachment"; break;
  425.         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: str= "incomplete draw buffer"; break;
  426.         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: str= "incomplete read buffer"; break;
  427.         case GL_FRAMEBUFFER_UNSUPPORTED: str= "unsupported"; break;
  428.         case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: str= "incomplete multiple"; break;
  429.         default: str = "unknown error"; break;
  430.         }
  431.  
  432.         fprintf (stderr,
  433.                  "destination is framebuffer incomplete: %s [%#x]\n",
  434.                  str, status);
  435.     }
  436. }
  437. #if CAIRO_HAS_GL_SURFACE
  438. static void
  439. _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
  440.                                 cairo_gl_surface_t *surface)
  441. {
  442.     assert (surface->supports_msaa);
  443.     assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
  444.  
  445.     if (surface->msaa_fb)
  446.         return;
  447.  
  448.     /* We maintain a separate framebuffer for multisampling operations.
  449.        This allows us to do a fast paint to the non-multisampling framebuffer
  450.        when mulitsampling is disabled. */
  451.     ctx->dispatch.GenFramebuffers (1, &surface->msaa_fb);
  452.     ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
  453.     ctx->dispatch.GenRenderbuffers (1, &surface->msaa_rb);
  454.     ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, surface->msaa_rb);
  455.  
  456.     /* FIXME: For now we assume that textures passed from the outside have GL_RGBA
  457.        format, but eventually we need to expose a way for the API consumer to pass
  458.        this information. */
  459.     ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
  460.                                                   ctx->num_samples,
  461.                                                   GL_RGBA,
  462.                                                   surface->width,
  463.                                                   surface->height);
  464.     ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
  465.                                            GL_COLOR_ATTACHMENT0,
  466.                                            GL_RENDERBUFFER,
  467.                                            surface->msaa_rb);
  468.  
  469.     /* Cairo surfaces start out initialized to transparent (black) */
  470.     glDisable (GL_SCISSOR_TEST);
  471.     glClearColor (0, 0, 0, 0);
  472.     glClear (GL_COLOR_BUFFER_BIT);
  473. }
  474. #endif
  475.  
  476. static cairo_bool_t
  477. _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
  478.                                             cairo_gl_surface_t *surface)
  479. {
  480.     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
  481.     if (surface->msaa_depth_stencil)
  482.         return TRUE;
  483.  
  484.     _cairo_gl_ensure_framebuffer (ctx, surface);
  485. #if CAIRO_HAS_GL_SURFACE
  486.     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
  487.         _cairo_gl_ensure_multisampling (ctx, surface);
  488. #endif
  489.  
  490.     dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
  491.     dispatch->BindRenderbuffer (GL_RENDERBUFFER,
  492.                                 surface->msaa_depth_stencil);
  493.  
  494.     dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER,
  495.                                               ctx->num_samples,
  496.                                               _get_depth_stencil_format (ctx),
  497.                                               surface->width,
  498.                                               surface->height);
  499.  
  500. #if CAIRO_HAS_GL_SURFACE
  501.     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
  502.         dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
  503.                                            GL_DEPTH_STENCIL_ATTACHMENT,
  504.                                            GL_RENDERBUFFER,
  505.                                            surface->msaa_depth_stencil);
  506.     }
  507. #endif
  508.  
  509. #if CAIRO_HAS_GLESV2_SURFACE
  510.     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
  511.         dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
  512.                                            GL_DEPTH_ATTACHMENT,
  513.                                            GL_RENDERBUFFER,
  514.                                            surface->msaa_depth_stencil);
  515.         dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
  516.                                            GL_STENCIL_ATTACHMENT,
  517.                                            GL_RENDERBUFFER,
  518.                                            surface->msaa_depth_stencil);
  519.     }
  520. #endif
  521.  
  522.     if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
  523.         dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
  524.         surface->msaa_depth_stencil = 0;
  525.         return FALSE;
  526.     }
  527.  
  528.     return TRUE;
  529. }
  530.  
  531. static cairo_bool_t
  532. _cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
  533.                                        cairo_gl_surface_t *surface)
  534. {
  535.     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
  536.  
  537.     if (surface->depth_stencil)
  538.         return TRUE;
  539.  
  540.     _cairo_gl_ensure_framebuffer (ctx, surface);
  541.  
  542.     dispatch->GenRenderbuffers (1, &surface->depth_stencil);
  543.     dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
  544.     dispatch->RenderbufferStorage (GL_RENDERBUFFER,
  545.                                    _get_depth_stencil_format (ctx),
  546.                                    surface->width, surface->height);
  547.  
  548.     dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
  549.                                        GL_RENDERBUFFER, surface->depth_stencil);
  550.     dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
  551.                                        GL_RENDERBUFFER, surface->depth_stencil);
  552.     if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
  553.         dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
  554.         surface->depth_stencil = 0;
  555.         return FALSE;
  556.     }
  557.  
  558.     return TRUE;
  559. }
  560.  
  561. cairo_bool_t
  562. _cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
  563.                           cairo_gl_surface_t *surface)
  564. {
  565.     if (! _cairo_gl_surface_is_texture (surface))
  566.         return TRUE; /* best guess for now, will check later */
  567.     if (! ctx->has_packed_depth_stencil)
  568.         return FALSE;
  569.  
  570.     if (surface->msaa_active)
  571.         return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface);
  572.     else
  573.         return _cairo_gl_ensure_depth_stencil_buffer (ctx, surface);
  574. }
  575.  
  576. /*
  577.  * Stores a parallel projection transformation in matrix 'm',
  578.  * using column-major order.
  579.  *
  580.  * This is equivalent to:
  581.  *
  582.  * glLoadIdentity()
  583.  * gluOrtho2D()
  584.  *
  585.  * The calculation for the ortho tranformation was taken from the
  586.  * mesa source code.
  587.  */
  588. static void
  589. _gl_identity_ortho (GLfloat *m,
  590.                     GLfloat left, GLfloat right,
  591.                     GLfloat bottom, GLfloat top)
  592. {
  593. #define M(row,col)  m[col*4+row]
  594.     M(0,0) = 2.f / (right - left);
  595.     M(0,1) = 0.f;
  596.     M(0,2) = 0.f;
  597.     M(0,3) = -(right + left) / (right - left);
  598.  
  599.     M(1,0) = 0.f;
  600.     M(1,1) = 2.f / (top - bottom);
  601.     M(1,2) = 0.f;
  602.     M(1,3) = -(top + bottom) / (top - bottom);
  603.  
  604.     M(2,0) = 0.f;
  605.     M(2,1) = 0.f;
  606.     M(2,2) = -1.f;
  607.     M(2,3) = 0.f;
  608.  
  609.     M(3,0) = 0.f;
  610.     M(3,1) = 0.f;
  611.     M(3,2) = 0.f;
  612.     M(3,3) = 1.f;
  613. #undef M
  614. }
  615.  
  616. #if CAIRO_HAS_GL_SURFACE
  617. static void
  618. bind_multisample_framebuffer (cairo_gl_context_t *ctx,
  619.                                cairo_gl_surface_t *surface)
  620. {
  621.     cairo_bool_t stencil_test_enabled;
  622.     cairo_bool_t scissor_test_enabled;
  623.  
  624.     assert (surface->supports_msaa);
  625.     assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
  626.  
  627.     _cairo_gl_ensure_framebuffer (ctx, surface);
  628.     _cairo_gl_ensure_multisampling (ctx, surface);
  629.  
  630.     if (surface->msaa_active) {
  631.         glEnable (GL_MULTISAMPLE);
  632.         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
  633.         return;
  634.     }
  635.  
  636.     _cairo_gl_composite_flush (ctx);
  637.  
  638.     stencil_test_enabled = glIsEnabled (GL_STENCIL_TEST);
  639.     scissor_test_enabled = glIsEnabled (GL_SCISSOR_TEST);
  640.     glDisable (GL_STENCIL_TEST);
  641.     glDisable (GL_SCISSOR_TEST);
  642.  
  643.     glEnable (GL_MULTISAMPLE);
  644.  
  645.     /* The last time we drew to the surface, we were not using multisampling,
  646.        so we need to blit from the non-multisampling framebuffer into the
  647.        multisampling framebuffer. */
  648.     ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->msaa_fb);
  649.     ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb);
  650.     ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
  651.                                    0, 0, surface->width, surface->height,
  652.                                    GL_COLOR_BUFFER_BIT, GL_NEAREST);
  653.     ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
  654.  
  655.     if (stencil_test_enabled)
  656.         glEnable (GL_STENCIL_TEST);
  657.     if (scissor_test_enabled)
  658.         glEnable (GL_SCISSOR_TEST);
  659. }
  660. #endif
  661.  
  662. #if CAIRO_HAS_GL_SURFACE
  663. static void
  664. bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
  665.                                cairo_gl_surface_t *surface)
  666. {
  667.     cairo_bool_t stencil_test_enabled;
  668.     cairo_bool_t scissor_test_enabled;
  669.  
  670.     assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
  671.     _cairo_gl_ensure_framebuffer (ctx, surface);
  672.  
  673.     if (! surface->msaa_active) {
  674.         glDisable (GL_MULTISAMPLE);
  675.         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
  676.         return;
  677.     }
  678.  
  679.     _cairo_gl_composite_flush (ctx);
  680.  
  681.     stencil_test_enabled = glIsEnabled (GL_STENCIL_TEST);
  682.     scissor_test_enabled = glIsEnabled (GL_SCISSOR_TEST);
  683.     glDisable (GL_STENCIL_TEST);
  684.     glDisable (GL_SCISSOR_TEST);
  685.  
  686.     glDisable (GL_MULTISAMPLE);
  687.  
  688.     /* The last time we drew to the surface, we were using multisampling,
  689.        so we need to blit from the multisampling framebuffer into the
  690.        non-multisampling framebuffer. */
  691.     ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb);
  692.     ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->msaa_fb);
  693.     ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
  694.                                    0, 0, surface->width, surface->height,
  695.                                    GL_COLOR_BUFFER_BIT, GL_NEAREST);
  696.     ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
  697.  
  698.     if (stencil_test_enabled)
  699.         glEnable (GL_STENCIL_TEST);
  700.     if (scissor_test_enabled)
  701.         glEnable (GL_SCISSOR_TEST);
  702. }
  703. #endif
  704.  
  705. void
  706. _cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx,
  707.                                     cairo_gl_surface_t *surface,
  708.                                     cairo_bool_t multisampling)
  709. {
  710.     if (_cairo_gl_surface_is_texture (surface)) {
  711.         /* OpenGL ES surfaces only have either a multisample framebuffer or a
  712.          * singlesample framebuffer, so we cannot switch back and forth. */
  713.         if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
  714.             _cairo_gl_ensure_framebuffer (ctx, surface);
  715.             ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
  716.             return;
  717.         }
  718.  
  719. #if CAIRO_HAS_GL_SURFACE
  720.         if (multisampling)
  721.             bind_multisample_framebuffer (ctx, surface);
  722.         else
  723.             bind_singlesample_framebuffer (ctx, surface);
  724. #endif
  725.     } else {
  726.         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
  727.  
  728. #if CAIRO_HAS_GL_SURFACE
  729.         if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
  730.             if (multisampling)
  731.                 glEnable (GL_MULTISAMPLE);
  732.             else
  733.                 glDisable (GL_MULTISAMPLE);
  734.         }
  735. #endif
  736.     }
  737.  
  738.     surface->msaa_active = multisampling;
  739. }
  740.  
  741. void
  742. _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
  743.                                    cairo_gl_surface_t *surface,
  744.                                    cairo_bool_t multisampling)
  745. {
  746.     cairo_bool_t changing_surface, changing_sampling;
  747.  
  748.     /* The decision whether or not to use multisampling happens when
  749.      * we create an OpenGL ES surface, so we can never switch modes. */
  750.     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES)
  751.         multisampling = surface->msaa_active;
  752.  
  753.     changing_surface = ctx->current_target != surface || surface->needs_update;
  754.     changing_sampling = surface->msaa_active != multisampling;
  755.     if (! changing_surface && ! changing_sampling)
  756.         return;
  757.  
  758.     if (! changing_surface) {
  759.         _cairo_gl_composite_flush (ctx);
  760.         _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
  761.         return;
  762.     }
  763.  
  764.     _cairo_gl_composite_flush (ctx);
  765.  
  766.     ctx->current_target = surface;
  767.     surface->needs_update = FALSE;
  768.  
  769.     if (! _cairo_gl_surface_is_texture (surface)) {
  770.         ctx->make_current (ctx, surface);
  771.     }
  772.  
  773.     _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
  774.  
  775.     if (! _cairo_gl_surface_is_texture (surface)) {
  776. #if CAIRO_HAS_GL_SURFACE
  777.         glDrawBuffer (GL_BACK_LEFT);
  778.         glReadBuffer (GL_BACK_LEFT);
  779. #endif
  780.     }
  781.  
  782.     glDisable (GL_DITHER);
  783.     glViewport (0, 0, surface->width, surface->height);
  784.  
  785.     if (_cairo_gl_surface_is_texture (surface))
  786.         _gl_identity_ortho (ctx->modelviewprojection_matrix,
  787.                             0, surface->width, 0, surface->height);
  788.     else
  789.         _gl_identity_ortho (ctx->modelviewprojection_matrix,
  790.                             0, surface->width, surface->height, 0);
  791. }
  792.  
  793. void
  794. cairo_gl_device_set_thread_aware (cairo_device_t        *device,
  795.                                   cairo_bool_t           thread_aware)
  796. {
  797.     if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
  798.         _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
  799.         return;
  800.     }
  801.     ((cairo_gl_context_t *) device)->thread_aware = thread_aware;
  802. }
  803.