Upload Tizen2.0 source
[framework/graphics/cairo.git] / src / cairo-gl-device.c
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 #include "cairo-rtree-private.h"
48
49 #define MAX_MSAA_SAMPLES 4
50
51 cairo_int_status_t
52 _cairo_gl_image_cache_init (cairo_gl_context_t *ctx)
53 {
54     cairo_surface_t *cache_surface = _cairo_gl_surface_create_scratch (ctx,
55                                                 CAIRO_CONTENT_COLOR_ALPHA,
56                                                 IMAGE_CACHE_WIDTH,
57                                                 IMAGE_CACHE_HEIGHT,
58                                                 FALSE);
59     if (unlikely (cache_surface->status)) {
60         cairo_surface_destroy (cache_surface);
61         return CAIRO_INT_STATUS_UNSUPPORTED;
62     }
63
64     _cairo_surface_release_device_reference (cache_surface);
65     ctx->image_cache.surface = (cairo_gl_surface_t *)cache_surface;
66
67
68     return CAIRO_INT_STATUS_SUCCESS;
69 }
70
71 static void
72 _cairo_gl_image_cache_fini (cairo_gl_context_t *ctx)
73 {
74     _cairo_rtree_fini (&ctx->image_cache.rtree);
75     cairo_surface_destroy (&ctx->image_cache.surface->base);
76 }
77
78 static void
79 _gl_lock (void *device)
80 {
81     cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
82
83     ctx->acquire (ctx);
84 }
85
86 static void
87 _gl_unlock (void *device)
88 {
89     cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
90
91     ctx->release (ctx);
92 }
93
94 static cairo_status_t
95 _gl_flush (void *device)
96 {
97     cairo_gl_context_t *ctx;
98     cairo_status_t status;
99
100     status = _cairo_gl_context_acquire (device, &ctx);
101     if (unlikely (status))
102         return status;
103
104     _cairo_gl_composite_flush (ctx);
105
106     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
107     _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
108
109     if (ctx->clip_region) {
110         cairo_region_destroy (ctx->clip_region);
111         ctx->clip_region = NULL;
112     }
113
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);
119
120     ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0);
121
122     _disable_scissor_buffer ();
123     glDisable (GL_BLEND);
124
125     return _cairo_gl_context_release (ctx, status);
126 }
127
128 static void
129 _gl_finish (void *device)
130 {
131     cairo_gl_context_t *ctx = device;
132     int n;
133
134     _gl_lock (device);
135
136     _cairo_cache_fini (&ctx->gradients);
137
138     _cairo_gl_context_fini_shaders (ctx);
139
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);
144
145     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
146         _cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
147
148     _cairo_gl_image_cache_fini (ctx);
149
150     _gl_unlock (device);
151 }
152
153 static void
154 _gl_destroy (void *device)
155 {
156     cairo_gl_context_t *ctx = device;
157
158     ctx->acquire (ctx);
159
160     while (! cairo_list_is_empty (&ctx->fonts)) {
161         cairo_gl_font_t *font;
162
163         font = cairo_list_first_entry (&ctx->fonts,
164                                        cairo_gl_font_t,
165                                        link);
166
167         cairo_list_del (&font->base.link);
168         cairo_list_del (&font->link);
169         free (font);
170     }
171
172     _cairo_array_fini (&ctx->tristrip_indices);
173
174     cairo_region_destroy (ctx->clip_region);
175     _cairo_clip_destroy (ctx->clip);
176
177     free (ctx->vb_mem);
178
179     ctx->destroy (ctx);
180
181     free (ctx);
182 }
183
184 static const cairo_device_backend_t _cairo_gl_device_backend = {
185     CAIRO_DEVICE_TYPE_GL,
186
187     _gl_lock,
188     _gl_unlock,
189
190     _gl_flush, /* flush */
191     _gl_finish,
192     _gl_destroy,
193 };
194
195 static cairo_bool_t
196 _cairo_gl_msaa_compositor_enabled (void)
197 {
198     const char *env = getenv ("CAIRO_GL_COMPOSITOR");
199     return env && strcmp(env, "msaa") == 0;
200 }
201
202 cairo_status_t
203 _cairo_gl_context_init (cairo_gl_context_t *ctx)
204 {
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 ();
209     int n;
210
211     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
212
213     /* XXX The choice of compositor should be made automatically at runtime.
214      * However, it is useful to force one particular compositor whilst
215      * testing.
216      */
217      if (_cairo_gl_msaa_compositor_enabled ())
218         ctx->compositor = _cairo_gl_msaa_compositor_get ();
219     else
220         ctx->compositor = _cairo_gl_span_compositor_get ();
221
222
223     ctx->thread_aware = TRUE;
224
225     memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
226     cairo_list_init (&ctx->fonts);
227
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);
231
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;
240         } else
241             return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
242     } else {
243         ctx->tex_target = GL_TEXTURE_2D;
244         if (_cairo_gl_has_extension ("GL_OES_texture_npot"))
245             ctx->has_npot_repeat = TRUE;
246         else
247             ctx->has_npot_repeat = FALSE;
248     }
249
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);
254
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);
258
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")));
262
263     ctx->has_mesa_pack_invert =
264         _cairo_gl_has_extension ("GL_MESA_pack_invert");
265
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")));
271
272     ctx->num_samples = 1;
273
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);
278     }
279 #endif
280
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);
285     }
286 #endif
287     ctx->supports_msaa = ctx->num_samples > 1;
288     if (ctx->num_samples > MAX_MSAA_SAMPLES)
289         ctx->num_samples = MAX_MSAA_SAMPLES;
290
291
292     ctx->current_operator = -1;
293     ctx->gl_flavor = gl_flavor;
294
295     status = _cairo_gl_context_init_shaders (ctx);
296     if (unlikely (status))
297         return status;
298
299     status = _cairo_cache_init (&ctx->gradients,
300                                 _cairo_gl_gradient_equal,
301                                 NULL,
302                                 (cairo_destroy_func_t) _cairo_gl_gradient_destroy,
303                                 CAIRO_GL_GRADIENT_CACHE_SIZE);
304     if (unlikely (status))
305         return status;
306
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);
312         }
313     }
314
315     _cairo_array_init (&ctx->tristrip_indices, sizeof (unsigned short));
316
317     /* PBO for any sort of texture upload */
318     dispatch->GenBuffers (1, &ctx->texture_load_pbo);
319     dispatch->GenBuffers (1, &ctx->vbo);
320
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);
327
328     for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
329         _cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
330
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);
336
337     return CAIRO_STATUS_SUCCESS;
338 }
339
340 void
341 _cairo_gl_context_activate (cairo_gl_context_t *ctx,
342                             cairo_gl_tex_t      tex_unit)
343 {
344     if (ctx->max_textures <= (GLint) tex_unit) {
345         if (tex_unit < 2) {
346             _cairo_gl_composite_flush (ctx);
347             _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
348         }
349         glActiveTexture (ctx->max_textures - 1);
350     } else {
351         glActiveTexture (GL_TEXTURE0 + tex_unit);
352     }
353 }
354
355 static GLenum
356 _get_depth_stencil_format (cairo_gl_context_t *ctx)
357 {
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;
363 #endif
364
365 #if CAIRO_HAS_GLESV2_SURFACE
366     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
367         return GL_DEPTH24_STENCIL8_OES;
368 #endif
369
370 #if CAIRO_HAS_GL_SURFACE
371     return GL_DEPTH_STENCIL;
372 #elif CAIRO_HAS_GLESV2_SURFACE
373     return GL_DEPTH24_STENCIL8_OES;
374 #endif
375 }
376
377 #if CAIRO_HAS_GLESV2_SURFACE
378 static void
379 _cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
380                                         cairo_gl_surface_t *surface)
381 {
382     if (surface->msaa_active)
383         return;
384
385     ctx->dispatch.FramebufferTexture2DMultisample(GL_FRAMEBUFFER,
386                                                   GL_COLOR_ATTACHMENT0,
387                                                   ctx->tex_target,
388                                                   surface->tex,
389                                                   0,
390                                                   ctx->num_samples);
391
392     /* From now on MSAA will always be active on this surface. */
393     surface->msaa_active = TRUE;
394 }
395 #endif
396
397 void
398 _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
399                               cairo_gl_surface_t *surface)
400 {
401     GLenum status;
402     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
403
404     if (likely (surface->fb))
405         return;
406
407     /* Create a framebuffer object wrapping the texture so that we can render
408      * to it.
409      */
410     dispatch->GenFramebuffers (1, &surface->fb);
411     dispatch->BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
412
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);
420     } else
421 #endif
422         dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
423                                         GL_COLOR_ATTACHMENT0,
424                                         ctx->tex_target,
425                                         surface->tex,
426                                         0);
427
428 #if CAIRO_HAS_GL_SURFACE
429     glDrawBuffer (GL_COLOR_ATTACHMENT0);
430     glReadBuffer (GL_COLOR_ATTACHMENT0);
431 #endif
432
433     status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
434     if (status != GL_FRAMEBUFFER_COMPLETE) {
435         const char *str;
436         switch (status) {
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;
445         }
446
447         fprintf (stderr,
448                  "destination is framebuffer incomplete: %s [%#x]\n",
449                  str, status);
450     }
451 }
452
453 #if CAIRO_HAS_GL_SURFACE
454 static void
455 _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
456                                 cairo_gl_surface_t *surface)
457 {
458     assert (surface->supports_msaa);
459     assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
460
461     if (surface->msaa_fb)
462         return;
463
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);
471
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
474        this information. */
475     ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
476                                                   ctx->num_samples,
477                                                   GL_RGBA,
478                                                   surface->width,
479                                                   surface->height);
480     ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
481                                            GL_COLOR_ATTACHMENT0,
482                                            GL_RENDERBUFFER,
483                                            surface->msaa_rb);
484
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);
489 }
490 #endif
491
492 static void
493 _cairo_gl_replace_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
494                                              int width,
495                                              int height)
496 {
497     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
498
499     if (ctx->shared_msaa_depth_stencil)
500         dispatch->DeleteRenderbuffers (1, &ctx->shared_msaa_depth_stencil);
501
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),
506                                               width, height);
507     ctx->shared_msaa_depth_stencil_width = width;
508     ctx->shared_msaa_depth_stencil_height = height;
509 }
510
511 static cairo_bool_t
512 _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
513                                             cairo_gl_surface_t *surface)
514 {
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);
520 #endif
521
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,
526                                                      surface->width,
527                                                      surface->height);
528     }
529
530     assert (ctx->shared_msaa_depth_stencil);
531     if (surface->msaa_depth_stencil == ctx->shared_msaa_depth_stencil)
532         return TRUE;
533
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,
538                                            GL_RENDERBUFFER,
539                                            ctx->shared_msaa_depth_stencil);
540     }
541 #endif
542
543 #if CAIRO_HAS_GLESV2_SURFACE
544     if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
545         dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
546                                            GL_DEPTH_ATTACHMENT,
547                                            GL_RENDERBUFFER,
548                                            ctx->shared_msaa_depth_stencil);
549         dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
550                                            GL_STENCIL_ATTACHMENT,
551                                            GL_RENDERBUFFER,
552                                            ctx->shared_msaa_depth_stencil);
553     }
554 #endif
555
556     surface->msaa_depth_stencil = ctx->shared_msaa_depth_stencil;
557
558     if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
559         dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
560         surface->msaa_depth_stencil = 0;
561         return FALSE;
562     }
563
564     return TRUE;
565 }
566
567 static void
568 _cairo_gl_replace_depth_stencil_buffer (cairo_gl_context_t *ctx,
569                                         int width,
570                                         int height)
571 {
572     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
573
574     if (ctx->shared_depth_stencil)
575         dispatch->DeleteRenderbuffers (1, &ctx->shared_depth_stencil);
576
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),
581                                    width, height);
582     ctx->shared_depth_stencil_width = width;
583     ctx->shared_depth_stencil_height = height;
584 }
585
586 static cairo_bool_t
587 _cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
588                                        cairo_gl_surface_t *surface)
589 {
590     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
591
592     _cairo_gl_ensure_framebuffer (ctx, surface);
593
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,
598                                                 surface->width,
599                                                 surface->height);
600     }
601
602     if (surface->depth_stencil == ctx->shared_depth_stencil)
603         return TRUE;
604
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;
610
611     if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
612         dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
613         surface->depth_stencil = 0;
614         return FALSE;
615     }
616
617     return TRUE;
618 }
619
620 cairo_bool_t
621 _cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
622                           cairo_gl_surface_t *surface)
623 {
624     if (! _cairo_gl_surface_is_texture (surface))
625         return TRUE; /* best guess for now, will check later */
626
627     if (! ctx->has_packed_depth_stencil)
628         return FALSE;
629
630     if (surface->msaa_active)
631         return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface);
632     else
633         return _cairo_gl_ensure_depth_stencil_buffer (ctx, surface);
634 }
635
636 /*
637  * Stores a parallel projection transformation in matrix 'm',
638  * using column-major order.
639  *
640  * This is equivalent to:
641  *
642  * glLoadIdentity()
643  * gluOrtho2D()
644  *
645  * The calculation for the ortho tranformation was taken from the
646  * mesa source code.
647  */
648 static void
649 _gl_identity_ortho (GLfloat *m,
650                     GLfloat left, GLfloat right,
651                     GLfloat bottom, GLfloat top)
652 {
653 #define M(row,col)  m[col*4+row]
654     M(0,0) = 2.f / (right - left);
655     M(0,1) = 0.f;
656     M(0,2) = 0.f;
657     M(0,3) = -(right + left) / (right - left);
658
659     M(1,0) = 0.f;
660     M(1,1) = 2.f / (top - bottom);
661     M(1,2) = 0.f;
662     M(1,3) = -(top + bottom) / (top - bottom);
663
664     M(2,0) = 0.f;
665     M(2,1) = 0.f;
666     M(2,2) = -1.f;
667     M(2,3) = 0.f;
668
669     M(3,0) = 0.f;
670     M(3,1) = 0.f;
671     M(3,2) = 0.f;
672     M(3,3) = 1.f;
673 #undef M
674 }
675
676 #if CAIRO_HAS_GL_SURFACE
677 static void
678 _cairo_gl_activate_surface_as_multisampling (cairo_gl_context_t *ctx,
679                                              cairo_gl_surface_t *surface)
680 {
681     assert (surface->supports_msaa);
682     assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
683
684     _cairo_gl_ensure_framebuffer (ctx, surface);
685     _cairo_gl_ensure_multisampling (ctx, surface);
686
687
688     if (surface->msaa_active) {
689         glEnable (GL_MULTISAMPLE);
690         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
691         return;
692     }
693
694     _cairo_gl_composite_flush (ctx);
695     glEnable (GL_MULTISAMPLE);
696
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;
707 }
708 #endif
709
710 void
711 _cairo_gl_activate_surface_as_nonmultisampling (cairo_gl_context_t *ctx,
712                                                 cairo_gl_surface_t *surface)
713 {
714     assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
715     _cairo_gl_ensure_framebuffer (ctx, surface);
716
717 #if CAIRO_HAS_GL_SURFACE
718     if (! surface->msaa_active) {
719         glDisable (GL_MULTISAMPLE);
720         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
721         return;
722     }
723
724     _cairo_gl_composite_flush (ctx);
725     glDisable (GL_MULTISAMPLE);
726
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;
737 #endif
738 }
739
740 void
741 _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
742                                    cairo_gl_surface_t *surface,
743                                    cairo_bool_t multisampling)
744 {
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
747      * surface type. */
748     if (ctx->current_target == surface && ! surface->needs_update &&
749         (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES ||
750          surface->msaa_active == multisampling))
751         return;
752
753     _cairo_gl_composite_flush (ctx);
754
755     ctx->current_target = surface;
756     surface->needs_update = FALSE;
757
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);
765         else {
766             _cairo_gl_activate_surface_as_nonmultisampling (ctx, surface);
767 #endif
768         }
769     } else {
770         ctx->make_current (ctx, surface);
771
772 #if CAIRO_HAS_GL_SURFACE
773         if (multisampling)
774             glEnable(GL_MULTISAMPLE);
775         else
776             glDisable(GL_MULTISAMPLE);
777 #endif
778
779         surface->msaa_active = multisampling;
780         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
781
782 #if CAIRO_HAS_GL_SURFACE
783         glDrawBuffer (GL_BACK_LEFT);
784         glReadBuffer (GL_BACK_LEFT);
785 #endif
786     }
787
788     glViewport (0, 0, surface->width, surface->height);
789
790     if (_cairo_gl_surface_is_texture (surface))
791         _gl_identity_ortho (ctx->modelviewprojection_matrix,
792                             0, surface->width, 0, surface->height);
793     else
794         _gl_identity_ortho (ctx->modelviewprojection_matrix,
795                             0, surface->width, surface->height, 0);
796 }
797
798 void
799 cairo_gl_device_set_thread_aware (cairo_device_t        *device,
800                                   cairo_bool_t           thread_aware)
801 {
802     if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
803         _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
804         return;
805     }
806     ((cairo_gl_context_t *) device)->thread_aware = thread_aware;
807 }