mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-02-19 04:10:31 +01:00
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:
parent
13d9d07ccd
commit
32aa361c5e
5 changed files with 139 additions and 10 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue