From e01f622107eb36927c71018932f6064618a29412 Mon Sep 17 00:00:00 2001 From: Henry Song Date: Tue, 27 Sep 2011 08:42:36 -0700 Subject: [PATCH 3/4] Add clipping support to the MSAA OpenGL compositor. Adds basic clipping to the OpenGL MSAA compositor via the depth and stencil buffers. Stenciling and depth bits are stored in a renderbuffer. --- src/cairo-gl-device.c | 31 +++++++++++++++ src/cairo-gl-dispatch-private.h | 5 ++ src/cairo-gl-msaa-compositor.c | 81 ++++++++++++++++++++++++++++++++++++++- src/cairo-gl-private.h | 10 +++++ src/cairo-gl-surface.c | 2 + 5 files changed, 128 insertions(+), 1 deletions(-) diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c index 33af08e..db4d441 100644 --- a/src/cairo-gl-device.c +++ b/src/cairo-gl-device.c @@ -207,6 +207,12 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) ctx->has_mesa_pack_invert = _cairo_gl_has_extension ("GL_MESA_pack_invert"); + ctx->has_packed_depth_stencil = + ((gl_flavor == CAIRO_GL_FLAVOR_DESKTOP && + _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) || + (gl_flavor == CAIRO_GL_FLAVOR_ES && + _cairo_gl_has_extension ("GL_OES_packed_depth_stencil"))); + ctx->current_operator = -1; ctx->gl_flavor = gl_flavor; @@ -289,6 +295,19 @@ _cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx, glReadBuffer (GL_COLOR_ATTACHMENT0); #endif + if (ctx->has_packed_depth_stencil) { +#if CAIRO_HAS_GL_SURFACE + GLenum internal_format = GL_DEPTH_STENCIL; +#elif CAIRO_HAS_GLESV2_SURFACE + GLenum internal_format = GL_DEPTH24_STENCIL8_OES, +#endif + + dispatch->GenRenderbuffers (1, &surface->rb); + dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->rb); + dispatch->RenderbufferStorage (GL_RENDERBUFFER, internal_format, + surface->width, surface->height); + } + status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { const char *str; @@ -364,9 +383,21 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx, if (_cairo_gl_surface_is_texture (surface)) { _cairo_gl_ensure_framebuffer (ctx, surface); ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb); + + if (ctx->has_packed_depth_stencil) { + ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, surface->rb); + ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, surface->rb); + ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, surface->rb); + } + } else { ctx->make_current (ctx, surface); ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0); + if (ctx->has_packed_depth_stencil) + ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, 0); + #if CAIRO_HAS_GL_SURFACE glDrawBuffer (GL_BACK_LEFT); glReadBuffer (GL_BACK_LEFT); diff --git a/src/cairo-gl-dispatch-private.h b/src/cairo-gl-dispatch-private.h index 751913c..fdd0cf6 100644 --- a/src/cairo-gl-dispatch-private.h +++ b/src/cairo-gl-dispatch-private.h @@ -109,6 +109,11 @@ cairo_private cairo_gl_dispatch_entry_t dispatch_fbo_entries[] = { DISPATCH_ENTRY_EXT (FramebufferTexture2D), DISPATCH_ENTRY_EXT (CheckFramebufferStatus), DISPATCH_ENTRY_EXT (DeleteFramebuffers), + DISPATCH_ENTRY_EXT (GenRenderbuffers), + DISPATCH_ENTRY_EXT (BindRenderbuffer), + DISPATCH_ENTRY_EXT (RenderbufferStorage), + DISPATCH_ENTRY_EXT (FramebufferRenderbuffer), + DISPATCH_ENTRY_EXT (DeleteRenderbuffers), DISPATCH_ENTRY_LAST }; diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c index 3565658..94c24a6 100644 --- a/src/cairo-gl-msaa-compositor.c +++ b/src/cairo-gl-msaa-compositor.c @@ -93,6 +93,80 @@ _draw_traps (cairo_gl_context_t *ctx, return status; } +static cairo_status_t +_draw_clip (cairo_gl_context_t *ctx, + cairo_gl_composite_t *setup, + cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_traps_t traps; + + cairo_polygon_t polygon; + cairo_antialias_t antialias; + cairo_fill_rule_t fill_rule; + + status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias); + if (unlikely (status)) + return status; + + _cairo_traps_init (&traps); + status = _cairo_bentley_ottmann_tessellate_polygon (&traps, + &polygon, + fill_rule); + _cairo_polygon_fini (&polygon); + if (unlikely (status)) + return status; + + _draw_traps (ctx, setup, &traps); + + _cairo_traps_fini (&traps); + return status; +} + +static void +_disable_stencil_buffer (void) +{ + glDisable (GL_STENCIL_TEST); + glDepthMask (GL_FALSE); +} + +static cairo_status_t +_draw_clip_to_stencil_buffer (cairo_gl_context_t *ctx, + cairo_gl_composite_t *setup, + cairo_clip_t *clip) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (clip->path == NULL && clip->num_boxes == 0) + return CAIRO_STATUS_SUCCESS; + + if (ctx->has_packed_depth_stencil == FALSE) + return CAIRO_INT_STATUS_DEVICE_ERROR; + + glDepthMask (GL_TRUE); + glEnable (GL_STENCIL_TEST); + glClearStencil (0); + glClear (GL_STENCIL_BUFFER_BIT); + glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc (GL_EQUAL, 1, 0xffffffff); + glColorMask (0, 0, 0, 0); + + status = _draw_clip (ctx, setup, clip); + if (unlikely (status)) { + _disable_stencil_buffer (); + return status; + } + + /* We want to only render to the stencil buffer, so draw everything now. */ + _cairo_gl_composite_flush (ctx); + + glColorMask (1, 1, 1, 1); + glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc (GL_EQUAL, 1, 0xffffffff); + + return status;; +} + static cairo_int_status_t _cairo_gl_msaa_compositor_paint (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *extents) @@ -166,6 +240,8 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, if (unlikely (status)) goto FINISH; + _draw_clip_to_stencil_buffer (ctx, &setup, extents->clip); + status = _draw_traps (ctx, &setup, &traps); if (unlikely (status)) goto FINISH; @@ -175,8 +251,11 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, FINISH: _cairo_traps_fini (&traps); _cairo_gl_composite_fini (&setup); - if (ctx) + + if (ctx) { + _disable_stencil_buffer (); status = _cairo_gl_context_release (ctx, status); + } return status; } diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 1bb59b3..91fb40b 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -116,6 +116,7 @@ typedef struct _cairo_gl_surface { GLuint tex; /* GL texture object containing our data. */ GLuint fb; /* GL framebuffer object wrapping our data. */ + GLuint rb; /* GL renderbuffer object for holding stencil buffer clip. */ GLuint depth; /* GL framebuffer object holding depth */ int owns_tex; cairo_bool_t needs_update; @@ -254,6 +255,14 @@ typedef struct _cairo_gl_dispatch { GLint level); GLenum (*CheckFramebufferStatus) (GLenum target); void (*DeleteFramebuffers) (GLsizei n, const GLuint* framebuffers); + void (*GenRenderbuffers) (GLsizei n, GLuint *renderbuffers); + void (*BindRenderbuffer) (GLenum target, GLuint renderbuffer); + void (*RenderbufferStorage) (GLenum target, GLenum internal_format, + GLsizei width, GLsizei height); + void (*FramebufferRenderbuffer) (GLenum target, GLenum attachment, + GLenum renderbuffer_ttarget, GLuint renderbuffer); + void (*DeleteRenderbuffers) (GLsizei n, GLuint *renderbuffers); + } cairo_gl_dispatch_t; struct _cairo_gl_context { @@ -299,6 +308,7 @@ struct _cairo_gl_context { GLfloat modelviewprojection_matrix[16]; cairo_gl_flavor_t gl_flavor; cairo_bool_t has_map_buffer; + cairo_bool_t has_packed_depth_stencil; void (*acquire) (void *ctx); void (*release) (void *ctx); diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index dec4b82..98c34fe 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -924,6 +924,8 @@ _cairo_gl_surface_finish (void *abstract_surface) ctx->dispatch.DeleteFramebuffers (1, &surface->depth); if (surface->fb) ctx->dispatch.DeleteFramebuffers (1, &surface->fb); + if (surface->rb) + ctx->dispatch.DeleteRenderbuffers (1, &surface->rb); if (surface->owns_tex) glDeleteTextures (1, &surface->tex); -- 1.7.4.1