[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