diff options
-rw-r--r-- | src/cairo-gl-composite.c | 164 | ||||
-rw-r--r-- | src/cairo-gl-device.c | 1 | ||||
-rw-r--r-- | src/cairo-gl-msaa-compositor.c | 155 | ||||
-rw-r--r-- | src/cairo-gl-private.h | 12 |
4 files changed, 181 insertions, 151 deletions
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c index c4d6e0b5..6063dca5 100644 --- a/src/cairo-gl-composite.c +++ b/src/cairo-gl-composite.c @@ -115,6 +115,13 @@ _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup, setup->clip_region = clip_region; } +void +_cairo_gl_composite_set_clip (cairo_gl_composite_t *setup, + cairo_clip_t *clip) +{ + setup->clip = clip; +} + static void _cairo_gl_composite_bind_to_shader (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup) @@ -467,6 +474,132 @@ _cairo_gl_composite_begin_component_alpha (cairo_gl_context_t *ctx, return CAIRO_STATUS_SUCCESS; } +static void +_scissor_to_box (cairo_gl_surface_t *surface, + const cairo_box_t *box) +{ + double x1, y1, x2, y2, height; + _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2); + + height = y2 - y1; + if (_cairo_gl_surface_is_texture (surface) == FALSE) + y1 = surface->height - (y1 + height); + glScissor (x1, y1, x2 - x1, height); + glEnable (GL_SCISSOR_TEST); +} + +static void +_cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx, + unsigned int size_per_vertex) +{ + if (ctx->vertex_size != size_per_vertex) + _cairo_gl_composite_flush (ctx); + + if (_cairo_gl_context_is_flushed (ctx)) { + ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo); + + ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2, + GL_FLOAT, GL_FALSE, size_per_vertex, NULL); + ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX); + } + ctx->vertex_size = size_per_vertex; +} + +static void +_disable_stencil_buffer (void) +{ + glDisable (GL_STENCIL_TEST); + glDepthMask (GL_FALSE); +} + +static cairo_int_status_t +_cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup, + cairo_gl_context_t *ctx, + int vertex_size) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + + cairo_gl_surface_t *dst = setup->dst; + cairo_clip_t *clip = setup->clip; + + if (clip->num_boxes == 1 && clip->path == NULL) { + _scissor_to_box (dst, &clip->boxes[0]); + goto disable_stencil_buffer_and_return; + } + + /* If we cannot reduce the clip to a rectangular region, + we clip using the stencil buffer. */ + glDisable (GL_SCISSOR_TEST); + + if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto disable_stencil_buffer_and_return; + } + + 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 = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip); + + if (unlikely (status)) { + glColorMask (1, 1, 1, 1); + goto disable_stencil_buffer_and_return; + } + + /* We want to only render to the stencil buffer, so draw everything now. + Flushing also unbinds the VBO, which we want to rebind for regular + drawing. */ + _cairo_gl_composite_flush (ctx); + _cairo_gl_composite_setup_vbo (ctx, vertex_size); + + glColorMask (1, 1, 1, 1); + glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc (GL_EQUAL, 1, 0xffffffff); + return CAIRO_INT_STATUS_SUCCESS; + +disable_stencil_buffer_and_return: + _disable_stencil_buffer (); + return status; +} + +static cairo_int_status_t +_cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup, + cairo_gl_context_t *ctx, + int vertex_size) +{ + + if (! _cairo_gl_context_is_flushed (ctx) && + (! cairo_region_equal (ctx->clip_region, setup->clip_region) || + ! _cairo_clip_equal (ctx->clip, setup->clip))) + _cairo_gl_composite_flush (ctx); + + cairo_region_destroy (ctx->clip_region); + ctx->clip_region = cairo_region_reference (setup->clip_region); + _cairo_clip_destroy (ctx->clip); + ctx->clip = _cairo_clip_copy (setup->clip); + + assert (!setup->clip_region || !setup->clip); + + if (ctx->clip_region) { + _disable_stencil_buffer (); + glEnable (GL_SCISSOR_TEST); + return CAIRO_INT_STATUS_SUCCESS; + } + + if (ctx->clip) + return _cairo_gl_composite_setup_painted_clipping (setup, ctx, + vertex_size); + + _disable_stencil_buffer (); + glDisable (GL_SCISSOR_TEST); + return CAIRO_INT_STATUS_SUCCESS; +} + cairo_status_t _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup, cairo_gl_context_t **ctx_out, @@ -484,6 +617,8 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup, if (unlikely (status)) return status; + _cairo_gl_context_set_destination (ctx, setup->dst, multisampling); + glEnable (GL_BLEND); component_alpha = @@ -522,23 +657,12 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup, dst_size = 2 * sizeof (GLfloat); src_size = _cairo_gl_operand_get_vertex_size (setup->src.type); mask_size = _cairo_gl_operand_get_vertex_size (setup->mask.type); - vertex_size = dst_size + src_size + mask_size; + if (setup->spans) vertex_size += sizeof (GLfloat); - if (ctx->vertex_size != vertex_size) - _cairo_gl_composite_flush (ctx); - - _cairo_gl_context_set_destination (ctx, setup->dst, multisampling); - - if (_cairo_gl_context_is_flushed (ctx)) { - ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo); - - ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2, - GL_FLOAT, GL_FALSE, vertex_size, NULL); - ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX); - } + _cairo_gl_composite_setup_vbo (ctx, vertex_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size); _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size); @@ -549,8 +673,6 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup, _cairo_gl_set_operator (ctx, setup->op, component_alpha); - ctx->vertex_size = vertex_size; - if (_cairo_gl_context_is_flushed (ctx)) { if (ctx->pre_shader) { _cairo_gl_set_shader (ctx, ctx->pre_shader); @@ -560,15 +682,9 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup, _cairo_gl_composite_bind_to_shader (ctx, setup); } - if (! _cairo_gl_context_is_flushed (ctx) && - ! cairo_region_equal (ctx->clip_region, setup->clip_region)) - _cairo_gl_composite_flush (ctx); - cairo_region_destroy (ctx->clip_region); - ctx->clip_region = cairo_region_reference (setup->clip_region); - if (ctx->clip_region) - glEnable (GL_SCISSOR_TEST); - else - glDisable (GL_SCISSOR_TEST); + status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size); + if (unlikely (status)) + goto FAIL; *ctx_out = ctx; diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c index ffa4b042..f2b2243a 100644 --- a/src/cairo-gl-device.c +++ b/src/cairo-gl-device.c @@ -137,6 +137,7 @@ _gl_destroy (void *device) _cairo_array_fini (&ctx->tristrip_indices); cairo_region_destroy (ctx->clip_region); + _cairo_clip_destroy (ctx->clip); free (ctx->vb_mem); diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c index 59cb1e30..f5bb6f46 100644 --- a/src/cairo-gl-msaa-compositor.c +++ b/src/cairo-gl-msaa-compositor.c @@ -157,10 +157,10 @@ _draw_triangle_fan (cairo_gl_context_t *ctx, return CAIRO_STATUS_SUCCESS; } -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 +_cairo_gl_msaa_compositor_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; @@ -198,93 +198,6 @@ _draw_clip (cairo_gl_context_t *ctx, 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 (! _cairo_gl_ensure_stencil (ctx, setup->dst)) - 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)) { - glColorMask (1, 1, 1, 1); - _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 void -_scissor_to_rectangle (cairo_gl_surface_t *surface, - const cairo_rectangle_int_t *r) -{ - int y = r->y; - if (_cairo_gl_surface_is_texture (surface) == FALSE) - y = surface->height - (r->y + r->height); - glScissor (r->x, y, r->width, r->height); - glEnable (GL_SCISSOR_TEST); -} - -static cairo_int_status_t -_scissor_and_clip (cairo_gl_context_t *ctx, - cairo_gl_composite_t *setup, - cairo_composite_rectangles_t *composite, - cairo_bool_t *used_stencil_buffer) -{ - cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; - cairo_rectangle_int_t *bounds = &composite->unbounded; - cairo_clip_t *clip = composite->clip; - cairo_rectangle_int_t r; - - *used_stencil_buffer = FALSE; - - if (_cairo_composite_rectangles_can_reduce_clip (composite, clip)) { - _scissor_to_rectangle (dst, bounds); - return CAIRO_INT_STATUS_SUCCESS; - } - - /* If we cannot reduce the clip to a rectangular region, - we scissor and clip using the stencil buffer */ - if (clip->num_boxes > 1 || clip->path != NULL) { - *used_stencil_buffer = TRUE; - _scissor_to_rectangle (dst, bounds); - return _draw_clip_to_stencil_buffer (ctx, setup, clip); - } - - /* Always interpret the clip path as ANTIALIAS_NONE */ - _cairo_box_round_to_rectangle (clip->boxes, &r); - _scissor_to_rectangle (dst, &r); - return CAIRO_INT_STATUS_SUCCESS; -} - static cairo_bool_t _should_use_unbounded_surface (cairo_composite_rectangles_t *composite) { @@ -365,6 +278,15 @@ should_fall_back (cairo_gl_surface_t *surface, return ! surface->supports_msaa; } +static void +_cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite, + cairo_gl_composite_t *setup) +{ + if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip)) + return; + _cairo_gl_composite_set_clip (setup, composite->clip); +} + static cairo_int_status_t _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor, cairo_composite_rectangles_t *composite) @@ -372,7 +294,6 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor, cairo_gl_composite_t setup; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; cairo_gl_context_t *ctx = NULL; - cairo_bool_t used_stencil_buffer; cairo_int_status_t status; cairo_operator_t op = composite->op; @@ -447,27 +368,22 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor, if (unlikely (status)) goto finish; + _cairo_gl_msaa_compositor_set_clip (composite, &setup); + /* We always use multisampling here, because we do not yet have the smarts to calculate when the clip or the source requires it. */ status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE); if (unlikely (status)) goto finish; - status = _scissor_and_clip (ctx, &setup, composite, &used_stencil_buffer); - if (unlikely (status)) - goto finish; - _draw_int_rect (ctx, &setup, &composite->bounded); _cairo_gl_composite_flush (ctx); finish: _cairo_gl_composite_fini (&setup); - if (ctx) { - glDisable (GL_SCISSOR_TEST); - _disable_stencil_buffer (); + if (ctx) status = _cairo_gl_context_release (ctx, status); - } return status; } @@ -512,8 +428,7 @@ _stroke_shaper_add_quad (void *closure, static cairo_int_status_t _prevent_overlapping_drawing (cairo_gl_context_t *ctx, cairo_gl_composite_t *setup, - cairo_composite_rectangles_t *composite, - cairo_bool_t used_stencil_buffer_for_clip) + cairo_composite_rectangles_t *composite) { if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -522,9 +437,9 @@ _prevent_overlapping_drawing (cairo_gl_context_t *ctx, &composite->source_sample_area)) return CAIRO_INT_STATUS_SUCCESS; - if (used_stencil_buffer_for_clip == FALSE) { - /* Enable the stencil buffer, even if we have no clip so that - we can use it below to prevent overlapping shapes. We initialize + if (glIsEnabled (GL_STENCIL_TEST) == FALSE) { + /* Enable the stencil buffer, even if we are not using it for clipping, + so we can use it below to prevent overlapping shapes. We initialize it all to one here which represents infinite clip. */ glDepthMask (GL_TRUE); glEnable (GL_STENCIL_TEST); @@ -586,7 +501,6 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor, cairo_int_status_t status; cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface; struct _tristrip_composite_info info; - cairo_bool_t used_stencil_buffer_for_clip; if (should_fall_back (dst, antialias)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -626,18 +540,14 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor, if (unlikely (status)) goto finish; + _cairo_gl_msaa_compositor_set_clip (composite, &info.setup); + status = _cairo_gl_composite_begin_multisample (&info.setup, &info.ctx, antialias != CAIRO_ANTIALIAS_NONE); if (unlikely (status)) goto finish; - status = _scissor_and_clip (info.ctx, &info.setup, composite, - &used_stencil_buffer_for_clip); - if (unlikely (status)) - goto finish; - - status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite, - used_stencil_buffer_for_clip); + status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite); if (unlikely (status)) goto finish; @@ -658,11 +568,8 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor, finish: _cairo_gl_composite_fini (&info.setup); - if (info.ctx) { - glDisable (GL_SCISSOR_TEST); - _disable_stencil_buffer (); + if (info.ctx) status = _cairo_gl_context_release (info.ctx, status); - } return status; } @@ -680,7 +587,6 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cairo_gl_context_t *ctx = NULL; cairo_int_status_t status; cairo_traps_t traps; - cairo_bool_t used_stencil_buffer; if (should_fall_back (dst, antialias)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -725,16 +631,13 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, if (unlikely (status)) goto cleanup_setup; + _cairo_gl_msaa_compositor_set_clip (composite, &setup); + status = _cairo_gl_composite_begin_multisample (&setup, &ctx, antialias != CAIRO_ANTIALIAS_NONE); if (unlikely (status)) goto cleanup_setup; - status = _scissor_and_clip (ctx, &setup, composite, - &used_stencil_buffer); - if (unlikely (status)) - goto cleanup_setup; - status = _draw_traps (ctx, &setup, &traps); if (unlikely (status)) goto cleanup_setup; @@ -743,11 +646,9 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor, cleanup_setup: _cairo_gl_composite_fini (&setup); - if (ctx) { - glDisable (GL_SCISSOR_TEST); - _disable_stencil_buffer (); + if (ctx) status = _cairo_gl_context_release (ctx, status); - } + cleanup_traps: _cairo_traps_fini (&traps); diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 16353de0..0664320e 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -335,6 +335,7 @@ struct _cairo_gl_context { unsigned int vb_offset; unsigned int vertex_size; cairo_region_t *clip_region; + cairo_clip_t *clip; cairo_array_t tristrip_indices; cairo_bool_t has_mesa_pack_invert; @@ -361,6 +362,8 @@ typedef struct _cairo_gl_composite { cairo_gl_operand_t src; cairo_gl_operand_t mask; cairo_bool_t spans; + + cairo_clip_t *clip; } cairo_gl_composite_t; typedef struct _cairo_gl_font { @@ -489,6 +492,10 @@ cairo_private void _cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup, cairo_region_t *clip_region); +cairo_private void +_cairo_gl_composite_set_clip(cairo_gl_composite_t *setup, + cairo_clip_t *clip); + cairo_private cairo_int_status_t _cairo_gl_composite_set_source (cairo_gl_composite_t *setup, const cairo_pattern_t *pattern, @@ -747,6 +754,11 @@ _cairo_gl_pattern_to_source (cairo_surface_t *dst, const cairo_rectangle_int_t *sample, int *src_x, int *src_y); +cairo_private cairo_int_status_t +_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx, + cairo_gl_composite_t *setup, + cairo_clip_t *clip); + cairo_private cairo_surface_t * _cairo_gl_white_source (void); |