gl/msaa: Add clipping support

Adds basic clipping to the OpenGL MSAA compositor via the
depth and stencil buffers. Stenciling and depth bits are
stored in a renderbuffer.

Note that we only attach renderbuffers to surfaces created by ourselves
and not for foreign drawables (e.g. X Windows).
This commit is contained in:
Martin Robinson 2011-09-27 08:42:36 -07:00 committed by Chris Wilson
parent 13d9d07ccd
commit 32aa361c5e
5 changed files with 139 additions and 10 deletions

View file

@ -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;
@ -256,7 +262,7 @@ _cairo_gl_context_activate (cairo_gl_context_t *ctx,
if (ctx->max_textures <= (GLint) tex_unit) {
if (tex_unit < 2) {
_cairo_gl_composite_flush (ctx);
_cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
_cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
}
glActiveTexture (ctx->max_textures - 1);
} else {
@ -289,6 +295,24 @@ _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->depth_stencil);
dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
dispatch->RenderbufferStorage (GL_RENDERBUFFER, internal_format,
surface->width, surface->height);
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);
}
status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
const char *str;
@ -367,6 +391,7 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
} else {
ctx->make_current (ctx, surface);
ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
#if CAIRO_HAS_GL_SURFACE
glDrawBuffer (GL_BACK_LEFT);
glReadBuffer (GL_BACK_LEFT);

View file

@ -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
};

View file

@ -81,8 +81,8 @@ _draw_traps (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
cairo_traps_t *traps)
{
int i;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
int i;
for (i = 0; i < traps->num_traps; i++) {
cairo_trapezoid_t *trap = traps->traps + i;
@ -93,6 +93,84 @@ _draw_traps (cairo_gl_context_t *ctx,
return status;
}
static cairo_int_status_t
_draw_clip (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
cairo_clip_t *clip)
{
cairo_int_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;
if (antialias != CAIRO_ANTIALIAS_NONE) {
_cairo_polygon_fini (&polygon);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
_cairo_traps_init (&traps);
status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
&polygon,
fill_rule);
_cairo_polygon_fini (&polygon);
if (unlikely (status))
return status;
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_int_status_t
_draw_clip_to_stencil_buffer (cairo_gl_context_t *ctx,
cairo_gl_composite_t *setup,
cairo_clip_t *clip)
{
cairo_int_status_t status;
assert (! _cairo_clip_is_all_clipped (clip));
if (! setup->dst->depth_stencil)
return CAIRO_INT_STATUS_UNSUPPORTED;
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 *composite)
@ -137,10 +215,6 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
if (antialias != CAIRO_ANTIALIAS_NONE)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (! _cairo_composite_rectangles_can_reduce_clip (composite,
composite->clip))
return CAIRO_INT_STATUS_UNSUPPORTED;
_cairo_traps_init (&traps);
status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
if (unlikely (status))
@ -169,6 +243,18 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
if (unlikely (status))
goto cleanup_setup;
glScissor (composite->unbounded.x, composite->unbounded.y,
composite->unbounded.width, composite->unbounded.height);
glEnable (GL_SCISSOR_TEST);
if (! _cairo_composite_rectangles_can_reduce_clip (composite,
composite->clip))
{
status = _draw_clip_to_stencil_buffer (ctx, &setup, composite->clip);
if (unlikely (status))
goto cleanup_setup;
}
status = _draw_traps (ctx, &setup, &traps);
if (unlikely (status))
goto cleanup_setup;
@ -176,8 +262,12 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
_cairo_gl_composite_flush (ctx);
cleanup_setup:
_cairo_gl_composite_fini (&setup);
if (ctx)
if (ctx) {
glDisable (GL_SCISSOR_TEST);
_disable_stencil_buffer ();
status = _cairo_gl_context_release (ctx, status);
}
cleanup_traps:
_cairo_traps_fini (&traps);

View file

@ -116,7 +116,7 @@ typedef struct _cairo_gl_surface {
GLuint tex; /* GL texture object containing our data. */
GLuint fb; /* GL framebuffer object wrapping our data. */
GLuint depth; /* GL framebuffer object holding depth */
GLuint depth_stencil; /* GL renderbuffer object for holding stencil buffer clip. */
int owns_tex;
cairo_bool_t needs_update;
} cairo_gl_surface_t;
@ -254,6 +254,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 +307,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);

View file

@ -919,10 +919,10 @@ _cairo_gl_surface_finish (void *abstract_surface)
if (ctx->current_target == surface)
ctx->current_target = NULL;
if (surface->depth)
ctx->dispatch.DeleteFramebuffers (1, &surface->depth);
if (surface->fb)
ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
if (surface->depth_stencil)
ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil);
if (surface->owns_tex)
glDeleteTextures (1, &surface->tex);