[cairo-commit] 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

Martin Robinson mrobinson at kemper.freedesktop.org
Thu May 17 13:08:55 PDT 2012


 src/cairo-gl-device.c           |  165 ++++++++++++++++++++++++++++++----------
 src/cairo-gl-dispatch-private.h |    7 -
 src/cairo-gl-msaa-compositor.c  |   12 ++
 src/cairo-gl-operand.c          |    4 
 src/cairo-gl-private.h          |   13 +--
 5 files changed, 152 insertions(+), 49 deletions(-)

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

    gl/msaa: Support the OpenGLES EXT multisampling extension
    
    Add support for OpenGLES GPUs that support the EXT multisampling
    extension.

diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 88656a6..7400107 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -156,6 +156,13 @@ static const cairo_device_backend_t _cairo_gl_device_backend = {
     _gl_destroy,
 };
 
+static cairo_bool_t
+_cairo_gl_msaa_compositor_enabled (void)
+{
+    const char *env = getenv ("CAIRO_GL_COMPOSITOR");
+    return env && strcmp(env, "msaa") == 0;
+}
+
 cairo_status_t
 _cairo_gl_context_init (cairo_gl_context_t *ctx)
 {
@@ -163,22 +170,19 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
     int gl_version = _cairo_gl_get_version ();
     cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor ();
-    const char *env;
     int n;
 
     _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
 
-    ctx->compositor = _cairo_gl_span_compositor_get ();
-
     /* XXX The choice of compositor should be made automatically at runtime.
      * However, it is useful to force one particular compositor whilst
      * testing.
      */
-    env = getenv ("CAIRO_GL_COMPOSITOR");
-    if (env) {
-	if (strcmp(env, "msaa") == 0)
-	    ctx->compositor = _cairo_gl_msaa_compositor_get ();
-    }
+     if (_cairo_gl_msaa_compositor_enabled ())
+	ctx->compositor = _cairo_gl_msaa_compositor_get ();
+    else
+	ctx->compositor = _cairo_gl_span_compositor_get ();
+
 
     memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
     cairo_list_init (&ctx->fonts);
@@ -236,6 +240,12 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
     }
 #endif
 
+#if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
+    if (ctx->has_packed_depth_stencil &&
+	_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
+	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;
@@ -298,6 +308,48 @@ _cairo_gl_context_activate (cairo_gl_context_t *ctx,
     }
 }
 
+static GLenum
+_get_depth_stencil_format (cairo_gl_context_t *ctx)
+{
+    /* This is necessary to properly handle the situation where both
+       OpenGL and OpenGLES are active and returning a sane default. */
+#if CAIRO_HAS_GL_SURFACE
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	return GL_DEPTH_STENCIL;
+#endif
+
+#if CAIRO_HAS_GLESV2_SURFACE
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	return GL_DEPTH24_STENCIL8_OES;
+#endif
+
+#if CAIRO_HAS_GL_SURFACE
+    return GL_DEPTH_STENCIL;
+#elif CAIRO_HAS_GLESV2_SURFACE
+    return GL_DEPTH24_STENCIL8_OES;
+#endif
+}
+
+#if CAIRO_HAS_GLESV2_SURFACE
+static void
+_cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
+					cairo_gl_surface_t *surface)
+{
+    if (surface->msaa_active)
+	return;
+
+    ctx->dispatch.FramebufferTexture2DMultisample(GL_FRAMEBUFFER,
+						  GL_COLOR_ATTACHMENT0,
+						  ctx->tex_target,
+						  surface->tex,
+						  0,
+						  ctx->num_samples);
+
+    /* From now on MSAA will always be active on this surface. */
+    surface->msaa_active = TRUE;
+}
+#endif
+
 static void
 _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
                               cairo_gl_surface_t *surface)
@@ -313,11 +365,22 @@ _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
      */
     dispatch->GenFramebuffers (1, &surface->fb);
     dispatch->BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
-    dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
-				    GL_COLOR_ATTACHMENT0,
-				    ctx->tex_target,
-				    surface->tex,
-				    0);
+
+    /* Unlike for desktop GL we only maintain one multisampling framebuffer
+       for OpenGLES since the EXT_multisampled_render_to_texture extension
+       does not require an explicit multisample resolution. */
+#if CAIRO_HAS_GLESV2_SURFACE
+    if (surface->supports_msaa && _cairo_gl_msaa_compositor_enabled () &&
+	ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
+	_cairo_gl_ensure_msaa_gles_framebuffer (ctx, surface);
+    } else
+#endif
+	dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
+					GL_COLOR_ATTACHMENT0,
+					ctx->tex_target,
+					surface->tex,
+					0);
+
 #if CAIRO_HAS_GL_SURFACE
     glDrawBuffer (GL_COLOR_ATTACHMENT0);
     glReadBuffer (GL_COLOR_ATTACHMENT0);
@@ -342,13 +405,13 @@ _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
 		 str, status);
     }
 }
-
 #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);
+    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
 
     if (surface->msaa_fb)
 	return;
@@ -361,9 +424,6 @@ _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
     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. */
@@ -377,12 +437,12 @@ _cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
 					   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);
 }
+#endif
 
 static cairo_bool_t
 _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
@@ -393,20 +453,42 @@ _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
 	return TRUE;
 
     _cairo_gl_ensure_framebuffer (ctx, surface);
-    _cairo_gl_ensure_multisampling (ctx, surface);
+#if CAIRO_HAS_GL_SURFACE
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+	_cairo_gl_ensure_multisampling (ctx, surface);
+#endif
 
     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,
+					      _get_depth_stencil_format (ctx),
 					      surface->width,
 					      surface->height);
-    dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
-				       GL_DEPTH_STENCIL_ATTACHMENT,
-				       GL_RENDERBUFFER,
-				       surface->msaa_depth_stencil);
+
+#if CAIRO_HAS_GL_SURFACE
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
+	dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
+					   GL_DEPTH_STENCIL_ATTACHMENT,
+					   GL_RENDERBUFFER,
+					   surface->msaa_depth_stencil);
+    }
+#endif
+
+#if CAIRO_HAS_GLESV2_SURFACE
+    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
+	dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
+					   GL_DEPTH_ATTACHMENT,
+					   GL_RENDERBUFFER,
+					   surface->msaa_depth_stencil);
+	dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
+					   GL_STENCIL_ATTACHMENT,
+					   GL_RENDERBUFFER,
+					   surface->msaa_depth_stencil);
+    }
+#endif
 
     if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
 	dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
@@ -416,18 +498,12 @@ _cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
 
     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;
-#elif CAIRO_HAS_GLESV2_SURFACE
-    GLenum internal_format = GL_DEPTH24_STENCIL8_OES;
-#endif
 
     if (surface->depth_stencil)
 	return TRUE;
@@ -436,8 +512,9 @@ _cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
 
     dispatch->GenRenderbuffers (1, &surface->depth_stencil);
     dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
-    dispatch->RenderbufferStorage (GL_RENDERBUFFER, internal_format,
-			       surface->width, surface->height);
+    dispatch->RenderbufferStorage (GL_RENDERBUFFER,
+				   _get_depth_stencil_format (ctx),
+				   surface->width, surface->height);
 
     dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
 				       GL_RENDERBUFFER, surface->depth_stencil);
@@ -461,11 +538,9 @@ _cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
     if (! ctx->has_packed_depth_stencil)
 	return FALSE;
 
-#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);
 }
 
@@ -515,6 +590,8 @@ _cairo_gl_activate_surface_as_multisampling (cairo_gl_context_t *ctx,
 					     cairo_gl_surface_t *surface)
 {
     assert (surface->supports_msaa);
+    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
+
     _cairo_gl_ensure_framebuffer (ctx, surface);
     _cairo_gl_ensure_multisampling (ctx, surface);
 
@@ -539,14 +616,16 @@ _cairo_gl_activate_surface_as_multisampling (cairo_gl_context_t *ctx,
     ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
     surface->msaa_active = TRUE;
 }
+#endif
 
 void
 _cairo_gl_activate_surface_as_nonmultisampling (cairo_gl_context_t *ctx,
 						cairo_gl_surface_t *surface)
 {
+    assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP);
     _cairo_gl_ensure_framebuffer (ctx, surface);
 
-
+#if CAIRO_HAS_GL_SURFACE
     if (! surface->msaa_active) {
 	glDisable (GL_MULTISAMPLE);
 	ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
@@ -566,16 +645,20 @@ _cairo_gl_activate_surface_as_nonmultisampling (cairo_gl_context_t *ctx,
 				   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_bool_t multisampling)
 {
+    /* OpenGL ES surfaces are always in MSAA mode once it's been turned on,
+     * so we don't need to check whether we are switching modes for that
+     * surface type. */
     if (ctx->current_target == surface && ! surface->needs_update &&
-	surface->msaa_active == multisampling)
+	(ctx->gl_flavor == CAIRO_GL_FLAVOR_ES ||
+	 surface->msaa_active == multisampling))
 	return;
 
     _cairo_gl_composite_flush (ctx);
@@ -584,12 +667,16 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
     surface->needs_update = FALSE;
 
     if (_cairo_gl_surface_is_texture (surface)) {
+	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
+	    _cairo_gl_ensure_framebuffer (ctx, surface);
+	    ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
 #if CAIRO_HAS_GL_SURFACE
-	if (multisampling)
+	} else if (multisampling)
 	    _cairo_gl_activate_surface_as_multisampling (ctx, surface);
-	else
+	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 60ff025..0c5dc39 100644
--- a/src/cairo-gl-dispatch-private.h
+++ b/src/cairo-gl-dispatch-private.h
@@ -53,6 +53,8 @@ typedef struct _cairo_gl_dispatch_entry {
 				   offsetof(cairo_gl_dispatch_t, name) }
 #define DISPATCH_ENTRY_ARB_OES(name) { { "gl"#name, "gl"#name"ARB", "gl"#name"OES" }, \
 				       offsetof(cairo_gl_dispatch_t, name) }
+#define DISPATCH_ENTRY_EXT_EXT(name) { { "gl"#name, "gl"#name"EXT", "gl"#name"EXT" }, \
+				       offsetof(cairo_gl_dispatch_t, name) }
 #define DISPATCH_ENTRY_CUSTOM(name, name2) { { "gl"#name, "gl"#name2, "gl"#name }, \
 			                     offsetof(cairo_gl_dispatch_t, name)}
 #define DISPATCH_ENTRY_LAST { { NULL, NULL, NULL }, 0 }
@@ -114,10 +116,9 @@ 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_EXT_EXT (RenderbufferStorageMultisample),
+    DISPATCH_ENTRY_EXT_EXT (FramebufferTexture2DMultisample),
     DISPATCH_ENTRY_LAST
 };
 
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 392338c..6a12200 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -51,6 +51,10 @@ static void
 _scissor_to_rectangle (cairo_gl_surface_t	*surface,
 		       const cairo_rectangle_int_t	*rect);
 
+static cairo_bool_t
+should_fall_back (cairo_gl_surface_t *surface,
+		  cairo_antialias_t antialias);
+
 struct _tristrip_composite_info {
     cairo_gl_composite_t	setup;
     cairo_gl_context_t		*ctx;
@@ -339,6 +343,14 @@ static cairo_bool_t
 should_fall_back (cairo_gl_surface_t *surface,
 		  cairo_antialias_t antialias)
 {
+    /* Multisampling OpenGL ES surfaces only maintain one multisampling
+       framebuffer and thus must use the spans compositor to do non-antialiased
+       rendering. */
+    if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES
+	 && surface->supports_msaa
+	 && antialias == CAIRO_ANTIALIAS_NONE)
+	return TRUE;
+
     if (antialias == CAIRO_ANTIALIAS_FAST)
 	return TRUE;
     if (antialias == CAIRO_ANTIALIAS_NONE)
diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
index 8b617f4..000b32b 100644
--- a/src/cairo-gl-operand.c
+++ b/src/cairo-gl-operand.c
@@ -81,6 +81,10 @@ _resolve_multisampling (cairo_gl_surface_t *surface)
     if (surface->base.device == NULL)
 	return CAIRO_INT_STATUS_SUCCESS;
 
+    /* GLES surfaces do not need explicit resolution. */
+    if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES)
+	return CAIRO_INT_STATUS_SUCCESS;
+
     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
     if (unlikely (status))
 	return status;
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 042aee9..21aad24 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -167,8 +167,8 @@ struct _cairo_gl_surface {
 #if CAIRO_HAS_GL_SURFACE
     GLuint msaa_rb; /* The ARB MSAA path uses a renderbuffer. */
     GLuint msaa_fb;
-    GLuint msaa_depth_stencil;
 #endif
+    GLuint msaa_depth_stencil;
 
     cairo_bool_t supports_msaa;
     cairo_bool_t msaa_active; /* Whether the multisampling
@@ -283,16 +283,15 @@ 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,
+    void (*RenderbufferStorageMultisample) (GLenum target, GLsizei samples,
 					    GLenum internalformat,
-					    GLsizei width,
-					    GLsizei height);
-#endif
+					    GLsizei width, GLsizei height);
+    void (*FramebufferTexture2DMultisample) (GLenum target, GLenum attachment,
+					     GLenum textarget, GLuint texture,
+					     GLint level, GLsizei samples);
 } cairo_gl_dispatch_t;
 
 struct _cairo_gl_context {


More information about the cairo-commit mailing list