From a79235dafa72192507a68723492c7b24772b4447 Mon Sep 17 00:00:00 2001 From: Henry Song Date: Tue, 27 Sep 2011 08:42:36 -0700 Subject: [PATCH 2/2] 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-composite.c | 3 +- src/cairo-gl-device.c | 31 ++++++++++ src/cairo-gl-dispatch-private.h | 5 ++ src/cairo-gl-msaa-traps-compositor.c | 105 +++++++++++++++++++++++++++++++++- src/cairo-gl-private.h | 10 +++ src/cairo-gl-surface.c | 2 + 6 files changed, 153 insertions(+), 3 deletions(-) diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c index 8347f20..6444e34 100644 --- a/src/cairo-gl-composite.c +++ b/src/cairo-gl-composite.c @@ -575,7 +575,7 @@ FAIL: return status; } -static inline void +static void _cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx) { cairo_array_t* indices = &ctx->tristrip_indices; @@ -869,7 +869,6 @@ _cairo_gl_composite_begin_tristrip (cairo_gl_composite_t *setup, cairo_gl_context_t **ctx_out) { unsigned int coordinates_size, color_size; - cairo_gl_context_t *ctx; cairo_status_t status; cairo_gl_shader_t *shader; 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-traps-compositor.c b/src/cairo-gl-msaa-traps-compositor.c index ed3fed8..64b5a28 100644 --- a/src/cairo-gl-msaa-traps-compositor.c +++ b/src/cairo-gl-msaa-traps-compositor.c @@ -93,6 +93,104 @@ _draw_traps (cairo_gl_context_t *ctx, return status; } +struct _tristrip_composite_info { + cairo_gl_context_t *ctx; + cairo_gl_composite_t *setup; +}; + +static +cairo_bool_t _draw_box (cairo_box_t *box, void *closure) +{ + struct _tristrip_composite_info *info = closure; + cairo_point_t quad[4]; + quad[0].x = box->p1.x; + quad[0].y = box->p1.y; + quad[1].x = box->p1.x; + quad[1].y = box->p2.y; + quad[2].x = box->p2.x; + quad[2].y = box->p2.y; + quad[3].x = box->p2.x; + quad[3].y = box->p1.y; + _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, info->setup, quad); + return TRUE; +} + +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_STATUS_SUCCESS; + cairo_traps_t traps; + + if (_cairo_clip_is_region (clip)) { + cairo_boxes_t boxes; + struct _tristrip_composite_info info = { ctx, setup }; + + _cairo_clip_steal_boxes (clip, &boxes); + _cairo_boxes_for_each_box (&boxes, _draw_box, &info); + _cairo_clip_unsteal_boxes (clip, &boxes); + + return CAIRO_STATUS_SUCCESS; + } + + _cairo_traps_init (&traps); + status = _cairo_path_fixed_fill_to_traps (&(clip->path->path), + clip->path->fill_rule, + clip->path->tolerance, + &traps); + if (unlikely (status == CAIRO_STATUS_SUCCESS && traps.num_traps == 0)) + return CAIRO_STATUS_CLIP_NOT_REPRESENTABLE; + if (unlikely (status)) + return status; + + _draw_traps (ctx, setup, &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); + glClear (GL_STENCIL_BUFFER_BIT); + glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc (GL_ALWAYS, 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, 1); + + return status;; +} + static cairo_int_status_t _cairo_gl_msaa_compositor_paint (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *extents) @@ -179,6 +277,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; @@ -188,8 +288,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