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;
}
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)
{
    cairo_bool_t clip_changing = TRUE;
    cairo_bool_t clip_region_changing = TRUE;

    if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
	goto disable_all_clipping;

    clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
    clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
    if (! _cairo_gl_context_is_flushed (ctx) &&
	(clip_region_changing || clip_changing))
	_cairo_gl_composite_flush (ctx);

    assert (!setup->clip_region || !setup->clip);

    /* setup->clip is only used by the msaa compositor and setup->clip_region
     * only by the other compositors, so it's safe to wait to clean up obsolete
     * clips. */
    if (clip_region_changing) {
	cairo_region_destroy (ctx->clip_region);
	ctx->clip_region = cairo_region_reference (setup->clip_region);
    }
    if (clip_changing) {
	_cairo_clip_destroy (ctx->clip);
	ctx->clip = _cairo_clip_copy (setup->clip);
    }

    /* For clip regions, we scissor right before drawing. */
    if (setup->clip_region)
	goto disable_all_clipping;

    if (setup->clip)
	return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
                                                           vertex_size);
disable_all_clipping:
    _disable_stencil_buffer ();
    glDisable (GL_SCISSOR_TEST);
    return CAIRO_INT_STATUS_SUCCESS;
}
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;;
}
Example #5
0
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_bool_t equal_clip)
{
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;

    cairo_gl_surface_t *dst = setup->dst;
    cairo_clip_t *clip = setup->clip;
    cairo_traps_t traps;
    const cairo_rectangle_int_t *clip_extents;

    if (clip->num_boxes == 1 && clip->path == NULL) {
	_scissor_to_box (dst, &clip->boxes[0]);
	goto disable_stencil_buffer_and_return;
    }

    if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
	status = CAIRO_INT_STATUS_UNSUPPORTED;
	goto disable_stencil_buffer_and_return;
    }

    if (! ctx->states_cache.depth_mask ) {
	glDepthMask (GL_TRUE);
	ctx->states_cache.depth_mask = TRUE;
    }
    glEnable (GL_STENCIL_TEST);
    clip_extents = _cairo_clip_get_extents ((const cairo_clip_t *)clip);
    _cairo_gl_scissor_to_extents (dst, clip_extents);

    if (equal_clip)
	return CAIRO_INT_STATUS_SUCCESS;

    glClearStencil (0);
    glClear (GL_STENCIL_BUFFER_BIT);
    glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
    glStencilFunc (GL_EQUAL, 1, 0xffffffff);
    glColorMask (0, 0, 0, 0);

    _cairo_traps_init (&traps);
    status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip, &traps);
    _cairo_traps_fini (&traps);

    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_msaa_compositor_fill (const cairo_compositor_t	*compositor,
				cairo_composite_rectangles_t	*composite,
				const cairo_path_fixed_t	*path,
				cairo_fill_rule_t		 fill_rule,
				double				 tolerance,
				cairo_antialias_t		 antialias)
{
    cairo_gl_composite_t setup;
    cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
    cairo_gl_context_t *ctx = NULL;
    cairo_int_status_t status;
    cairo_traps_t traps;
    cairo_bool_t used_stencil_buffer;

    if (antialias != CAIRO_ANTIALIAS_NONE)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    _cairo_traps_init (&traps);
    status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
    if (unlikely (status))
	goto cleanup_traps;

    status = _cairo_gl_composite_init (&setup,
				       composite->op,
				       dst,
				       FALSE, /* assume_component_alpha */
				       &composite->bounded);
    if (unlikely (status))
	goto cleanup_traps;

    status = _cairo_gl_composite_set_source (&setup,
					     &composite->source_pattern.base,
					     &composite->source_sample_area,
					     &composite->bounded);
    if (unlikely (status))
	goto cleanup_setup;

    status = _cairo_gl_composite_begin_tristrip (&setup, &ctx);
    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;

    _cairo_gl_composite_flush (ctx);
cleanup_setup:
    _cairo_gl_composite_fini (&setup);

    if (ctx) {
	glDisable (GL_SCISSOR_TEST);
	_disable_stencil_buffer ();
	status = _cairo_gl_context_release (ctx, status);
    }
cleanup_traps:
    _cairo_traps_fini (&traps);

    return status;
}
static cairo_int_status_t
_cairo_gl_msaa_compositor_stroke (const cairo_compositor_t	*compositor,
				  cairo_composite_rectangles_t	*composite,
				  const cairo_path_fixed_t	*path,
				  const cairo_stroke_style_t	*style,
				  const cairo_matrix_t		*ctm,
				  const cairo_matrix_t		*ctm_inverse,
				  double			 tolerance,
				  cairo_antialias_t		 antialias)
{
    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 (antialias != CAIRO_ANTIALIAS_NONE)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    status = _cairo_gl_composite_init (&info.setup,
				       composite->op,
				       dst,
				       FALSE, /* assume_component_alpha */
				       &composite->bounded);
    if (unlikely (status))
	return status;

    info.ctx = NULL;

    status = _cairo_gl_composite_set_source (&info.setup,
					     &composite->source_pattern.base,
					     &composite->source_sample_area,
					     &composite->bounded);
    if (unlikely (status))
	goto finish;

    status = _cairo_gl_composite_begin_tristrip (&info.setup, &info.ctx);
    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 = _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path,
						 style,
						 ctm,
						 ctm_inverse,
						 tolerance,
						 _stroke_shaper_add_triangle,
						 _stroke_shaper_add_triangle_fan,
						 _stroke_shaper_add_quad,
						 &info);
    if (unlikely (status))
	goto finish;

    _cairo_gl_composite_flush (info.ctx);

finish:
    _cairo_gl_composite_fini (&info.setup);

    if (info.ctx) {
	glDisable (GL_SCISSOR_TEST);
	_disable_stencil_buffer ();
	status = _cairo_gl_context_release (info.ctx, status);
    }

    return status;
}
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 (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
	status = CAIRO_INT_STATUS_UNSUPPORTED;
	goto disable_stencil_buffer_and_return;
    }

    /* We only want to clear the part of the stencil buffer
     * that we are about to use. It also does not hurt to
     * scissor around the painted clip. */
    _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip));

    /* The clip is not rectangular, so use the stencil buffer. */
    glDepthMask (GL_TRUE);
    glEnable (GL_STENCIL_TEST);

    /* Texture surfaces have private depth/stencil buffers, so we can
     * rely on any previous clip being cached there. */
    if (_cairo_gl_surface_is_texture (setup->dst)) {
	cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
	if (_cairo_clip_equal (old_clip, setup->clip))
	    goto activate_stencil_buffer_and_return;

	if (old_clip) {
	    _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
	}

	setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
    }

    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);

activate_stencil_buffer_and_return:
    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;
}