[cairo-commit] src/cairo-gl-composite.c src/cairo-gl-device.c src/cairo-gl-dispatch-private.h src/cairo-gl-msaa-compositor.c src/cairo-gl-operand.c src/cairo-gl-private.h src/cairo-gl-surface.c

Martin Robinson mrobinson at kemper.freedesktop.org
Thu May 17 11:16:03 PDT 2012


 src/cairo-gl-composite.c        |   14 +-
 src/cairo-gl-device.c           |  236 ++++++++++++++++++++++++++++++++++------
 src/cairo-gl-dispatch-private.h |    4 
 src/cairo-gl-msaa-compositor.c  |   28 +++-
 src/cairo-gl-operand.c          |   40 ++++++
 src/cairo-gl-private.h          |   38 ++++++
 src/cairo-gl-surface.c          |   21 +++
 7 files changed, 334 insertions(+), 47 deletions(-)

New commits:
commit 4d9064d578434cadfae2b248ef29075a1a1be8b8
Author: Henry (Yu) Song <hsong at sisa.samsung.com>
Date:   Fri Dec 16 15:56:00 2011 -0800

    gl/msaa: Add ARB multisampling support
    
    This implementation is not very efficient at the moment and does not
    work with platforms using the incompatible IMG extension (mobile
    GPUs).  Performance improvements and mobile GPU support will follow.

diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index a7891b9..05046ec 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -468,8 +468,9 @@ _cairo_gl_composite_begin_component_alpha  (cairo_gl_context_t *ctx,
 }
 
 cairo_status_t
-_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
-                           cairo_gl_context_t **ctx_out)
+_cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
+				       cairo_gl_context_t **ctx_out,
+				       cairo_bool_t multisampling)
 {
     unsigned int dst_size, src_size, mask_size, vertex_size;
     cairo_gl_context_t *ctx;
@@ -529,7 +530,7 @@ _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
     if (ctx->vertex_size != vertex_size)
         _cairo_gl_composite_flush (ctx);
 
-    _cairo_gl_context_set_destination (ctx, setup->dst);
+    _cairo_gl_context_set_destination (ctx, setup->dst, multisampling);
 
     if (_cairo_gl_context_is_flushed (ctx)) {
         ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo);
@@ -578,6 +579,13 @@ FAIL:
     return status;
 }
 
+cairo_status_t
+_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
+                           cairo_gl_context_t **ctx_out)
+{
+    return _cairo_gl_composite_begin_multisample (setup, ctx_out, FALSE);
+}
+
 static inline void
 _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
 {
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 3ecd51e..f710ab0 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -45,6 +45,8 @@
 #include "cairo-error-private.h"
 #include "cairo-gl-private.h"
 
+#define MAX_MSAA_SAMPLES 4
+
 static void
 _gl_lock (void *device)
 {
@@ -225,6 +227,20 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
 	(gl_flavor == CAIRO_GL_FLAVOR_ES &&
 	 _cairo_gl_has_extension ("GL_OES_packed_depth_stencil")));
 
+    ctx->num_samples = 1;
+
+#if CAIRO_HAS_GL_SURFACE
+    if (ctx->has_packed_depth_stencil &&
+	_cairo_gl_has_extension ("GL_ARB_framebuffer_object")) {
+	glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
+    }
+#endif
+
+    ctx->supports_msaa = ctx->num_samples > 1;
+    if (ctx->num_samples > MAX_MSAA_SAMPLES)
+	ctx->num_samples = MAX_MSAA_SAMPLES;
+
+
     ctx->current_operator = -1;
     ctx->gl_flavor = gl_flavor;
 
@@ -327,44 +343,130 @@ _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
     }
 }
 
-cairo_bool_t
-_cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
-			  cairo_gl_surface_t *surface)
+#if CAIRO_HAS_GL_SURFACE
+static void
+_cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
+				cairo_gl_surface_t *surface)
+{
+    assert (surface->supports_msaa);
+
+    if (surface->msaa_fb)
+	return;
+
+    /* We maintain a separate framebuffer for multisampling operations.
+       This allows us to do a fast paint to the non-multisampling framebuffer
+       when mulitsampling is disabled. */
+    ctx->dispatch.GenFramebuffers (1, &surface->msaa_fb);
+    ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
+    ctx->dispatch.GenRenderbuffers (1, &surface->msaa_rb);
+    ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, surface->msaa_rb);
+
+    ctx->dispatch.GenRenderbuffers (1, &(surface->msaa_rb));
+    ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, surface->msaa_rb);
+
+    /* FIXME: For now we assume that textures passed from the outside have GL_RGBA
+       format, but eventually we need to expose a way for the API consumer to pass
+       this information. */
+    ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
+						  ctx->num_samples,
+						  GL_RGBA,
+						  surface->width,
+						  surface->height);
+    ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
+					   GL_COLOR_ATTACHMENT0,
+					   GL_RENDERBUFFER,
+					   surface->msaa_rb);
+
+
+    /* Cairo surfaces start out initialized to transparent (black) */
+    glDisable (GL_SCISSOR_TEST);
+    glClearColor (0, 0, 0, 0);
+    glClear (GL_COLOR_BUFFER_BIT);
+}
+
+static cairo_bool_t
+_cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
+					    cairo_gl_surface_t *surface)
 {
-	cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+    if (surface->msaa_depth_stencil)
+	return TRUE;
+
+    _cairo_gl_ensure_framebuffer (ctx, surface);
+    _cairo_gl_ensure_multisampling (ctx, surface);
+
+    dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
+    dispatch->BindRenderbuffer (GL_RENDERBUFFER,
+			        surface->msaa_depth_stencil);
+    dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER,
+					      ctx->num_samples,
+					      GL_DEPTH_STENCIL,
+					      surface->width,
+					      surface->height);
+    dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
+				       GL_DEPTH_STENCIL_ATTACHMENT,
+				       GL_RENDERBUFFER,
+				       surface->msaa_depth_stencil);
+
+    if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+	dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
+	surface->msaa_depth_stencil = 0;
+	return FALSE;
+    }
+
+    return TRUE;
+}
+#endif
+
+static cairo_bool_t
+_cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
+				       cairo_gl_surface_t *surface)
+{
+    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
 #if CAIRO_HAS_GL_SURFACE
-	GLenum internal_format = GL_DEPTH_STENCIL;
+    GLenum internal_format = GL_DEPTH_STENCIL;
 #elif CAIRO_HAS_GLESV2_SURFACE
-	GLenum internal_format = GL_DEPTH24_STENCIL8_OES;
+    GLenum internal_format = GL_DEPTH24_STENCIL8_OES;
 #endif
 
-	if (! _cairo_gl_surface_is_texture (surface))
-		return TRUE; /* best guess for now, will check later */
-
-	if (surface->depth_stencil)
-		return TRUE;
-
-	if (! ctx->has_packed_depth_stencil)
-		return FALSE;
+    if (surface->depth_stencil)
+	return TRUE;
 
-	_cairo_gl_ensure_framebuffer (ctx, surface);
+    _cairo_gl_ensure_framebuffer (ctx, surface);
+
+    dispatch->GenRenderbuffers (1, &surface->depth_stencil);
+    dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
+    dispatch->RenderbufferStorage (GL_RENDERBUFFER, internal_format,
+			       surface->width, surface->height);
+
+    dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+				       GL_RENDERBUFFER, surface->depth_stencil);
+    dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+				       GL_RENDERBUFFER, surface->depth_stencil);
+    if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+	dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
+	surface->depth_stencil = 0;
+	return FALSE;
+    }
 
-	dispatch->GenRenderbuffers (1, &surface->depth_stencil);
-	dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
-	dispatch->RenderbufferStorage (GL_RENDERBUFFER, internal_format,
-				       surface->width, surface->height);
+    return TRUE;
+}
 
-	ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-					       GL_RENDERBUFFER, surface->depth_stencil);
-	ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-					       GL_RENDERBUFFER, surface->depth_stencil);
-	if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-		ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil);
-		surface->depth_stencil = 0;
-		return FALSE;
-	}
+cairo_bool_t
+_cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
+			  cairo_gl_surface_t *surface)
+{
+    if (! _cairo_gl_surface_is_texture (surface))
+	return TRUE; /* best guess for now, will check later */
+    if (! ctx->has_packed_depth_stencil)
+	return FALSE;
 
-	return TRUE;
+#if CAIRO_HAS_GL_SURFACE
+    if (surface->msaa_active)
+	return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface);
+    else
+#endif
+	return _cairo_gl_ensure_depth_stencil_buffer (ctx, surface);
 }
 
 /*
@@ -407,12 +509,74 @@ _gl_identity_ortho (GLfloat *m,
 #undef M
 }
 
+#if CAIRO_HAS_GL_SURFACE
+static void
+_cairo_gl_activate_surface_as_multisampling (cairo_gl_context_t *ctx,
+					     cairo_gl_surface_t *surface)
+{
+    assert (surface->supports_msaa);
+    _cairo_gl_ensure_framebuffer (ctx, surface);
+    _cairo_gl_ensure_multisampling (ctx, surface);
+
+
+    if (surface->msaa_active) {
+	glEnable (GL_MULTISAMPLE);
+	ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
+	return;
+    }
+
+    _cairo_gl_composite_flush (ctx);
+    glEnable (GL_MULTISAMPLE);
+
+    /* The last time we drew to the surface, we were not using multisampling,
+       so we need to blit from the non-multisampling framebuffer into the
+       multisampling framebuffer. */
+    ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->msaa_fb);
+    ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb);
+    ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
+				   0, 0, surface->width, surface->height,
+				   GL_COLOR_BUFFER_BIT, GL_NEAREST);
+    ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
+    surface->msaa_active = TRUE;
+}
+
+void
+_cairo_gl_activate_surface_as_nonmultisampling (cairo_gl_context_t *ctx,
+						cairo_gl_surface_t *surface)
+{
+    _cairo_gl_ensure_framebuffer (ctx, surface);
+
+
+    if (! surface->msaa_active) {
+	glDisable (GL_MULTISAMPLE);
+	ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
+	return;
+    }
+
+    _cairo_gl_composite_flush (ctx);
+    glDisable (GL_MULTISAMPLE);
+
+    /* The last time we drew to the surface, we were using multisampling,
+       so we need to blit from the multisampling framebuffer into the
+       non-multisampling framebuffer. */
+    ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb);
+    ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->msaa_fb);
+    ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
+				   0, 0, surface->width, surface->height,
+				   GL_COLOR_BUFFER_BIT, GL_NEAREST);
+    ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
+    surface->msaa_active = FALSE;
+}
+#endif
+
 void
 _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
-                                   cairo_gl_surface_t *surface)
+                                   cairo_gl_surface_t *surface,
+                                   cairo_bool_t multisampling)
 {
-    if (ctx->current_target == surface && ! surface->needs_update)
-        return;
+    if (ctx->current_target == surface && ! surface->needs_update &&
+	surface->msaa_active == multisampling)
+	return;
 
     _cairo_gl_composite_flush (ctx);
 
@@ -420,8 +584,12 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
     surface->needs_update = FALSE;
 
     if (_cairo_gl_surface_is_texture (surface)) {
-        _cairo_gl_ensure_framebuffer (ctx, surface);
-        ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
+#if CAIRO_HAS_GL_SURFACE
+	if (multisampling)
+	    _cairo_gl_activate_surface_as_multisampling (ctx, surface);
+	else
+	    _cairo_gl_activate_surface_as_nonmultisampling (ctx, surface);
+#endif
     } else {
         ctx->make_current (ctx, surface);
         ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
diff --git a/src/cairo-gl-dispatch-private.h b/src/cairo-gl-dispatch-private.h
index fdd0cf6..60ff025 100644
--- a/src/cairo-gl-dispatch-private.h
+++ b/src/cairo-gl-dispatch-private.h
@@ -114,6 +114,10 @@ cairo_private cairo_gl_dispatch_entry_t dispatch_fbo_entries[] = {
     DISPATCH_ENTRY_EXT (RenderbufferStorage),
     DISPATCH_ENTRY_EXT (FramebufferRenderbuffer),
     DISPATCH_ENTRY_EXT (DeleteRenderbuffers),
+#if CAIRO_HAS_GL_SURFACE
+    DISPATCH_ENTRY_EXT (BlitFramebuffer),
+    DISPATCH_ENTRY_EXT (RenderbufferStorageMultisample),
+#endif
     DISPATCH_ENTRY_LAST
 };
 
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 87cc535..0080d14 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -319,6 +319,17 @@ finish:
     return status;
 }
 
+static cairo_bool_t
+should_fall_back (cairo_gl_surface_t *surface,
+		  cairo_antialias_t antialias)
+{
+    if (antialias == CAIRO_ANTIALIAS_FAST)
+	return TRUE;
+    if (antialias == CAIRO_ANTIALIAS_NONE)
+	return FALSE;
+    return ! surface->supports_msaa;
+}
+
 static cairo_int_status_t
 _cairo_gl_msaa_compositor_paint (const cairo_compositor_t	*compositor,
 				 cairo_composite_rectangles_t	*composite)
@@ -337,6 +348,9 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t	*compositor,
     cairo_int_status_t status;
     cairo_operator_t op = composite->op;
 
+    if (should_fall_back (dst, CAIRO_ANTIALIAS_GOOD))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
     /* GL compositing operators cannot properly represent a mask operation
        using the SOURCE compositing operator in one pass. This only matters if
        there actually is a mask (there isn't in a paint operation) and if the
@@ -394,7 +408,9 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t	*compositor,
     if (unlikely (status))
 	goto finish;
 
-    status = _cairo_gl_composite_begin (&setup, &ctx);
+    /* We always use multisampling here, because we do not yet have the smarts
+       to calculate when the clip or the source requires it. */
+    status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
     if (unlikely (status))
 	goto finish;
 
@@ -493,7 +509,7 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
     struct _tristrip_composite_info info;
     cairo_bool_t used_stencil_buffer_for_clip;
 
-    if (antialias != CAIRO_ANTIALIAS_NONE)
+    if (should_fall_back (dst, antialias))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (composite->is_bounded == FALSE) {
@@ -531,7 +547,8 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
     if (unlikely (status))
 	goto finish;
 
-    status = _cairo_gl_composite_begin (&info.setup, &info.ctx);
+    status = _cairo_gl_composite_begin_multisample (&info.setup, &info.ctx,
+	antialias != CAIRO_ANTIALIAS_NONE);
     if (unlikely (status))
 	goto finish;
 
@@ -586,7 +603,7 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
     cairo_traps_t traps;
     cairo_bool_t used_stencil_buffer;
 
-    if (antialias != CAIRO_ANTIALIAS_NONE)
+    if (should_fall_back (dst, antialias))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (composite->is_bounded == FALSE) {
@@ -629,7 +646,8 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t	*compositor,
     if (unlikely (status))
 	goto cleanup_setup;
 
-    status = _cairo_gl_composite_begin (&setup, &ctx);
+    status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
+	antialias != CAIRO_ANTIALIAS_NONE);
     if (unlikely (status))
 	goto cleanup_setup;
 
diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
index a6c7185..8b617f4 100644
--- a/src/cairo-gl-operand.c
+++ b/src/cairo-gl-operand.c
@@ -69,6 +69,32 @@ _cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
     return _cairo_gl_context_release (ctx, status);
 }
 
+static cairo_int_status_t
+_resolve_multisampling (cairo_gl_surface_t *surface)
+{
+    cairo_gl_context_t *ctx;
+    cairo_int_status_t status;
+
+    if (! surface->msaa_active)
+	return CAIRO_INT_STATUS_SUCCESS;
+
+    if (surface->base.device == NULL)
+	return CAIRO_INT_STATUS_SUCCESS;
+
+    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+    if (unlikely (status))
+	return status;
+
+    ctx->current_target = surface;
+
+#if CAIRO_HAS_GL_SURFACE
+    _cairo_gl_activate_surface_as_nonmultisampling (ctx, surface);
+#endif
+
+    status = _cairo_gl_context_release (ctx, status);
+    return status;
+}
+
 static cairo_status_t
 _cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
 					 const cairo_pattern_t *_src,
@@ -127,6 +153,10 @@ _cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
 	_cairo_surface_subsurface_set_snapshot (&sub->base, &surface->base);
     }
 
+    status = _resolve_multisampling (surface);
+    if (unlikely (status))
+        return status;
+
     attributes = &operand->texture.attributes;
 
     operand->type = CAIRO_GL_OPERAND_TEXTURE;
@@ -162,6 +192,7 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
     cairo_surface_subsurface_t *sub;
     cairo_gl_surface_t *surface;
     cairo_surface_attributes_t *attributes;
+    cairo_int_status_t status;
 
     sub = (cairo_surface_subsurface_t *) src->surface;
 
@@ -177,6 +208,10 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
     if (surface->base.device && surface->base.device != dst->base.device)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    status = _resolve_multisampling (surface);
+    if (unlikely (status))
+	return status;
+
     /* Translate the matrix from
      * (unnormalized src -> unnormalized src) to
      * (unnormalized dst -> unnormalized src)
@@ -207,6 +242,7 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
     const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
     cairo_gl_surface_t *surface;
     cairo_surface_attributes_t *attributes;
+    cairo_int_status_t status;
 
     surface = (cairo_gl_surface_t *) src->surface;
     if (surface->base.type != CAIRO_SURFACE_TYPE_GL)
@@ -223,6 +259,10 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
     if (surface->base.device && surface->base.device != dst->base.device)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    status = _resolve_multisampling (surface);
+    if (unlikely (status))
+	return status;
+
     *operand = surface->operand;
 
     attributes = &operand->texture.attributes;
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 103eade..042aee9 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -163,6 +163,17 @@ struct _cairo_gl_surface {
     GLuint tex; /* GL texture object containing our data. */
     GLuint fb; /* GL framebuffer object wrapping our data. */
     GLuint depth_stencil; /* GL renderbuffer object for holding stencil buffer clip. */
+
+#if CAIRO_HAS_GL_SURFACE
+    GLuint msaa_rb; /* The ARB MSAA path uses a renderbuffer. */
+    GLuint msaa_fb;
+    GLuint msaa_depth_stencil;
+#endif
+
+    cairo_bool_t supports_msaa;
+    cairo_bool_t msaa_active; /* Whether the multisampling
+			         framebuffer is active or not. */
+
     int owns_tex;
     cairo_bool_t needs_update;
 
@@ -272,7 +283,16 @@ typedef struct _cairo_gl_dispatch {
     void (*FramebufferRenderbuffer) (GLenum target, GLenum attachment,
 				     GLenum renderbuffer_ttarget, GLuint renderbuffer);
     void (*DeleteRenderbuffers) (GLsizei n, GLuint *renderbuffers);
-
+#if CAIRO_HAS_GL_SURFACE
+    void (*BlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+			     GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+			     GLbitfield mask, GLenum filter);
+    void (*RenderbufferStorageMultisample) (GLenum target,
+					    GLsizei samples,
+					    GLenum internalformat,
+					    GLsizei width,
+					    GLsizei height);
+#endif
 } cairo_gl_dispatch_t;
 
 struct _cairo_gl_context {
@@ -287,6 +307,9 @@ struct _cairo_gl_context {
     GLint max_textures;
     GLenum tex_target;
 
+    GLint num_samples;
+    cairo_bool_t supports_msaa;
+
     const cairo_gl_shader_impl_t *shader_impl;
 
     GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1];
@@ -433,7 +456,13 @@ _cairo_gl_context_release (cairo_gl_context_t *ctx, cairo_status_t status)
 }
 
 cairo_private void
-_cairo_gl_context_set_destination (cairo_gl_context_t *ctx, cairo_gl_surface_t *surface);
+_cairo_gl_activate_surface_as_nonmultisampling (cairo_gl_context_t *ctx,
+						cairo_gl_surface_t *surface);
+
+cairo_private void
+_cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
+				   cairo_gl_surface_t *surface,
+				   cairo_bool_t multisampling);
 
 cairo_private void
 _cairo_gl_context_activate (cairo_gl_context_t *ctx,
@@ -490,6 +519,11 @@ cairo_private cairo_status_t
 _cairo_gl_composite_begin (cairo_gl_composite_t *setup,
                            cairo_gl_context_t **ctx);
 
+cairo_private cairo_status_t
+_cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
+				       cairo_gl_context_t **ctx_out,
+				       cairo_bool_t multisampling);
+
 cairo_private void
 _cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
                                GLfloat x1,
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index f480260..9b8cf27 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -392,6 +392,10 @@ _cairo_gl_surface_init (cairo_device_t *device,
     surface->height = height;
     surface->needs_update = FALSE;
 
+    /* Support for multisampling in non-texture surfaces is still spotty. */
+    surface->supports_msaa = FALSE;
+    surface->msaa_active = FALSE;
+
     _cairo_gl_surface_embedded_operand_init (surface);
 }
 
@@ -412,6 +416,8 @@ _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t   *ctx,
     surface->tex = tex;
     _cairo_gl_surface_init (&ctx->base, surface, content, width, height);
 
+    surface->supports_msaa = ctx->supports_msaa;
+
     /* Create the texture used to store the surface's data. */
     _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
     glBindTexture (ctx->tex_target, surface->tex);
@@ -487,7 +493,7 @@ _cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
     if (unlikely (status))
 	return status;
 
-    _cairo_gl_context_set_destination (ctx, surface);
+    _cairo_gl_context_set_destination (ctx, surface, surface->msaa_active);
     if (surface->base.content & CAIRO_CONTENT_COLOR) {
         r = color->red   * color->alpha;
         g = color->green * color->alpha;
@@ -698,7 +704,7 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
             return;
 
 	/* For swapping on EGL, at least, we need a valid context/target. */
-	_cairo_gl_context_set_destination (ctx, surface);
+	_cairo_gl_context_set_destination (ctx, surface, FALSE);
 	/* And in any case we should flush any pending operations. */
 	_cairo_gl_composite_flush (ctx);
 
@@ -970,6 +976,15 @@ _cairo_gl_surface_finish (void *abstract_surface)
     if (surface->owns_tex)
 	glDeleteTextures (1, &surface->tex);
 
+#if CAIRO_HAS_GL_SURFACE
+    if (surface->msaa_depth_stencil)
+	ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
+    if (surface->msaa_fb)
+	ctx->dispatch.DeleteFramebuffers (1, &surface->msaa_fb);
+    if (surface->msaa_rb)
+	ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_rb);
+#endif
+
     return _cairo_gl_context_release (ctx, status);
 }
 
@@ -1056,7 +1071,7 @@ _cairo_gl_surface_map_to_image (void      *abstract_surface,
      * fall back instead.
      */
     _cairo_gl_composite_flush (ctx);
-    _cairo_gl_context_set_destination (ctx, surface);
+    _cairo_gl_context_set_destination (ctx, surface, FALSE);
 
     invert = ! _cairo_gl_surface_is_texture (surface) &&
 	    ctx->has_mesa_pack_invert;


More information about the cairo-commit mailing list