Esempio n. 1
0
static cairo_status_t
_cairo_gl_surface_clear (cairo_gl_surface_t  *surface,
                         const cairo_color_t *color)
{
    cairo_gl_context_t *ctx;
    cairo_status_t status;
    double r, g, b, a;

    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
    if (unlikely (status))
	return status;

    _cairo_gl_context_set_destination (ctx, surface);
    if (surface->base.content & CAIRO_CONTENT_COLOR) {
        r = color->red   * color->alpha;
        g = color->green * color->alpha;
        b = color->blue  * color->alpha;
    } else {
        r = g = b = 0;
    }
    if (surface->base.content & CAIRO_CONTENT_ALPHA) {
        a = color->alpha;
    } else {
        a = 1.0;
    }

    glDisable (GL_SCISSOR_TEST);
    glClearColor (r, g, b, a);
    glClear (GL_COLOR_BUFFER_BIT);

    return _cairo_gl_context_release (ctx, status);
}
Esempio n. 2
0
static void
query_surface_capabilities (cairo_gl_surface_t *surface)
{
    GLint samples, stencil_bits;
    cairo_gl_context_t *ctx;
    cairo_int_status_t status;

    /* Texture surfaces are create in such a way that they always
       have stencil and multisample bits if possible, so we don't
       need to query their capabilities lazily. */
    if (_cairo_gl_surface_is_texture (surface))
	return;
    if (surface->stencil_and_msaa_caps_initialized)
	return;

    surface->stencil_and_msaa_caps_initialized = TRUE;
    surface->supports_stencil = FALSE;
    surface->supports_msaa = FALSE;

    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
    if (unlikely (status))
	return;

    _cairo_gl_context_set_destination (ctx, surface, FALSE);

    glGetIntegerv(GL_SAMPLES, &samples);
    glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
    surface->supports_stencil = stencil_bits > 0;
    surface->supports_msaa = samples > 1;

    status = _cairo_gl_context_release (ctx, status);
}
cairo_status_t
_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
			   cairo_gl_context_t **ctx_out)
{
    cairo_gl_context_t *ctx;
    cairo_status_t status;

    assert (setup->dst);

    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
    if (unlikely (status))
	return status;

    _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
    glEnable (GL_BLEND);

    status = _cairo_gl_set_operands_and_operator (setup, ctx);
    if (unlikely (status))
	goto FAIL;

    status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
    if (unlikely (status))
	goto FAIL;

    *ctx_out = ctx;

FAIL:
    if (unlikely (status))
        status = _cairo_gl_context_release (ctx, status);

    return status;
}
Esempio n. 4
0
cairo_status_t
_cairo_gl_composite_begin_tristrip (cairo_gl_composite_t	*setup,
				    cairo_gl_context_t		**ctx_out)
{
    cairo_gl_context_t *ctx;
    cairo_status_t status;
    cairo_gl_shader_t *shader;
    int src_size, dst_size;

    cairo_gl_operand_t default_mask;
    memset (&default_mask, 0, sizeof (cairo_gl_operand_t));

    assert (setup->dst);

    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
    if (unlikely (status))
	return status;
    *ctx_out = ctx;

    /* Finish any pending operations from other GL compositors. */
    if (! _cairo_gl_context_is_flushed (ctx))
	_cairo_gl_composite_flush (ctx);

    glEnable (GL_BLEND);

    status = _cairo_gl_get_shader_by_type (ctx,
					   &setup->src,
					   &default_mask,
					   setup->spans,
					   CAIRO_GL_SHADER_IN_NORMAL,
                                           &shader);
    if (unlikely (status)) {
	status = _cairo_gl_context_release (ctx, status);
	return status;
    }

    _cairo_gl_context_set_destination (ctx, setup->dst);

    _cairo_gl_set_operator (ctx, setup->op, FALSE);
    _cairo_gl_set_shader (ctx, shader);
    _cairo_gl_composite_bind_to_shader (ctx, setup);

    dst_size  = 2 * sizeof (GLfloat);
    src_size  = _cairo_gl_operand_get_vertex_size (setup->src.type);

    ctx->vertex_size = dst_size + src_size;

    ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, ctx->vbo);
    ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
				       GL_FLOAT, GL_FALSE, ctx->vertex_size, NULL);
    ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);

    _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src,
				     ctx->vertex_size, dst_size);

    return status;
}
Esempio n. 5
0
void
cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
{
    cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;

    if (unlikely (abstract_surface->status))
	return;
    if (unlikely (abstract_surface->finished)) {
	_cairo_surface_set_error (abstract_surface,
				  _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
        return;
    }

    if (! _cairo_surface_is_gl (abstract_surface)) {
	_cairo_surface_set_error (abstract_surface,
				  CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return;
    }

    if (! _cairo_gl_surface_is_texture (surface)) {
	cairo_gl_context_t *ctx;
        cairo_status_t status;

        status = _cairo_gl_context_acquire (surface->base.device, &ctx);
        if (unlikely (status))
            return;

	/* For swapping on EGL, at least, we need a valid context/target. */
	_cairo_gl_context_set_destination (ctx, surface);
	/* And in any case we should flush any pending operations. */
	_cairo_gl_composite_flush (ctx);

	ctx->swap_buffers (ctx, surface);

        status = _cairo_gl_context_release (ctx, status);
        if (status)
            status = _cairo_surface_set_error (abstract_surface, status);
    }
}
Esempio n. 6
0
cairo_status_t
_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
                           cairo_gl_context_t **ctx_out)
{
    unsigned int dst_size, src_size, mask_size, vertex_size;
    cairo_gl_context_t *ctx;
    cairo_status_t status;
    cairo_bool_t component_alpha;
    cairo_gl_shader_t *shader;

    assert (setup->dst);

    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
    if (unlikely (status))
	return status;

    glEnable (GL_BLEND);

    component_alpha =
	setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
	setup->mask.texture.attributes.has_component_alpha;

    /* Do various magic for component alpha */
    if (component_alpha) {
        status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
        if (unlikely (status))
            goto FAIL;
    } else {
        if (ctx->pre_shader) {
            _cairo_gl_composite_flush (ctx);
            ctx->pre_shader = NULL;
        }
    }

    status = _cairo_gl_get_shader_by_type (ctx,
					   &setup->src,
					   &setup->mask,
					   setup->spans,
                                           component_alpha ?
					   CAIRO_GL_SHADER_IN_CA_SOURCE :
					   CAIRO_GL_SHADER_IN_NORMAL,
                                           &shader);
    if (unlikely (status)) {
        ctx->pre_shader = NULL;
        goto FAIL;
    }
    if (ctx->current_shader != shader)
        _cairo_gl_composite_flush (ctx);

    status = CAIRO_STATUS_SUCCESS;

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

    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_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);
    if (setup->spans)
	_cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size);
    else
	ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);

    _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);
            _cairo_gl_composite_bind_to_shader (ctx, setup);
        }
        _cairo_gl_set_shader (ctx, shader);
        _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);

    *ctx_out = ctx;

FAIL:
    if (unlikely (status))
        status = _cairo_gl_context_release (ctx, status);

    return status;
}
Esempio n. 7
0
cairo_status_t
_cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
				       cairo_gl_context_t **ctx_out,
				       cairo_bool_t multisampling)
{
    unsigned int dst_size, src_size, mask_size, vertex_size;
    cairo_gl_context_t *ctx;
    cairo_status_t status;
    cairo_bool_t component_alpha;
    cairo_gl_shader_t *shader;
    cairo_operator_t op = setup->op;
    cairo_surface_t *mask_surface = NULL;

    assert (setup->dst);

    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
    if (unlikely (status))
	return status;

    _cairo_gl_context_set_destination (ctx, setup->dst, multisampling);

    if (ctx->states_cache.blend_enabled == FALSE) {
	glEnable (GL_BLEND);
	ctx->states_cache.blend_enabled = TRUE;
    }

    component_alpha =
	setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
	setup->mask.texture.attributes.has_component_alpha;

    /* Do various magic for component alpha */
    if (component_alpha) {
        status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
        if (unlikely (status))
            goto FAIL;
    } else {
        if (ctx->pre_shader) {
            _cairo_gl_composite_flush (ctx);
            ctx->pre_shader = NULL;
        }
    }

    status = _cairo_gl_get_shader_by_type (ctx,
					   &setup->src,
					   &setup->mask,
					   setup->spans,
                                           component_alpha ?
					   CAIRO_GL_SHADER_IN_CA_SOURCE :
					   CAIRO_GL_SHADER_IN_NORMAL,
                                           &shader);
    if (unlikely (status)) {
        ctx->pre_shader = NULL;
        goto FAIL;
    }
    if (ctx->current_shader != shader)
        _cairo_gl_composite_flush (ctx);

    status = CAIRO_STATUS_SUCCESS;

    dst_size  = 2 * sizeof (GLfloat);
    src_size  = _cairo_gl_operand_get_vertex_size (&setup->src);
    mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
    vertex_size = dst_size + src_size + mask_size;

    if (setup->spans)
	    vertex_size += sizeof (GLfloat);

    _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);
    if (setup->spans)
	_cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size);
    else {
        ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COVERAGE_ATTRIB_INDEX);
        ctx->spans = FALSE;
    }

    /* XXX: Shoot me - we have converted CLEAR to DEST_OUT,
       so the dst_factor would be GL_ONE_MINUS_SRC_ALPHA, if the
       mask is a surface and mask content not content_alpha, we want to use
       GL_ONE_MINUS_SRC_COLOR, otherwise, we use GL_ONE_MINUS_SRC_ALPHA
     */
    if (setup->mask.type == CAIRO_GL_OPERAND_TEXTURE)
	mask_surface = &setup->mask.texture.surface->base;
    if (op == CAIRO_OPERATOR_CLEAR &&
	component_alpha &&
	mask_surface != NULL &&
	cairo_surface_get_content (mask_surface) == CAIRO_CONTENT_ALPHA)
	component_alpha = FALSE;

    _cairo_gl_set_operator (ctx, setup->op, component_alpha);

    if (_cairo_gl_context_is_flushed (ctx)) {
        if (ctx->pre_shader) {
            _cairo_gl_set_shader (ctx, ctx->pre_shader);
            _cairo_gl_composite_bind_to_shader (ctx, setup);
        }
        _cairo_gl_set_shader (ctx, shader);
        _cairo_gl_composite_bind_to_shader (ctx, setup);
    }

    status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size);
    if (unlikely (status))
	goto FAIL;

    *ctx_out = ctx;

FAIL:
    if (unlikely (status))
        status = _cairo_gl_context_release (ctx, status);

    return status;
}
cairo_status_t
_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
			   cairo_gl_context_t **ctx_out)
{
    unsigned int dst_size, src_size, mask_size, vertex_size;
    cairo_gl_context_t *ctx;
    cairo_status_t status;
    cairo_bool_t component_alpha;
    cairo_gl_shader_t *shader;

    assert (setup->dst);

    status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
    if (unlikely (status))
	return status;

    _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);

    glEnable (GL_BLEND);

    component_alpha =
	setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
	setup->mask.texture.attributes.has_component_alpha;

    /* Do various magic for component alpha */
    if (component_alpha) {
        status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
        if (unlikely (status))
            goto FAIL;
    } else {
        if (ctx->pre_shader) {
            _cairo_gl_composite_flush (ctx);
            ctx->pre_shader = NULL;
        }
    }

    status = _cairo_gl_get_shader_by_type (ctx,
					   &setup->src,
					   &setup->mask,
					   setup->spans,
                                           component_alpha ?
					   CAIRO_GL_SHADER_IN_CA_SOURCE :
					   CAIRO_GL_SHADER_IN_NORMAL,
                                           &shader);
    if (unlikely (status)) {
        ctx->pre_shader = NULL;
        goto FAIL;
    }
    if (ctx->current_shader != shader)
        _cairo_gl_composite_flush (ctx);

    status = CAIRO_STATUS_SUCCESS;

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

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

    _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
				   dst_size + src_size + mask_size);

    _cairo_gl_set_operator (ctx, setup->op, component_alpha);

    if (_cairo_gl_context_is_flushed (ctx)) {
        if (ctx->pre_shader) {
            _cairo_gl_set_shader (ctx, ctx->pre_shader);
            _cairo_gl_composite_bind_to_shader (ctx, setup);
        }
        _cairo_gl_set_shader (ctx, shader);
        _cairo_gl_composite_bind_to_shader (ctx, setup);
    }

    status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size);
    if (unlikely (status))
	goto FAIL;

    *ctx_out = ctx;

FAIL:
    if (unlikely (status))
        status = _cairo_gl_context_release (ctx, status);

    return status;
}
Esempio n. 9
0
static cairo_surface_t *
_cairo_gl_surface_map_to_image (void      *abstract_surface,
				const cairo_rectangle_int_t   *extents)
{
    cairo_gl_surface_t *surface = abstract_surface;
    cairo_image_surface_t *image;
    cairo_gl_context_t *ctx;
    GLenum format, type;
    pixman_format_code_t pixman_format;
    unsigned int cpp;
    cairo_bool_t invert;
    cairo_status_t status;

    /* Want to use a switch statement here but the compiler gets whiny. */
    if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
	format = GL_BGRA;
	pixman_format = PIXMAN_a8r8g8b8;
	type = GL_UNSIGNED_INT_8_8_8_8_REV;
	cpp = 4;
    } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
	format = GL_BGRA;
	pixman_format = PIXMAN_x8r8g8b8;
	type = GL_UNSIGNED_INT_8_8_8_8_REV;
	cpp = 4;
    } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
	format = GL_ALPHA;
	pixman_format = PIXMAN_a8;
	type = GL_UNSIGNED_BYTE;
	cpp = 1;
    } else {
	ASSERT_NOT_REACHED;
	return NULL;
    }

    /*
     * GLES2 supports only RGBA, UNSIGNED_BYTE so use that.
     * We are also using this format for ALPHA as GLES2 does not
     * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
     * pixman image that is created has row_stride = row_width * bpp.
     */
    if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) {
	format = GL_RGBA;
	if (! _cairo_is_little_endian ()) {
	    if (surface->base.content == CAIRO_CONTENT_COLOR)
		pixman_format = PIXMAN_r8g8b8x8;
	    else
		pixman_format = PIXMAN_r8g8b8a8;
	} else {
	    if (surface->base.content == CAIRO_CONTENT_COLOR)
		pixman_format = PIXMAN_x8b8g8r8;
	    else
		pixman_format = PIXMAN_a8b8g8r8;
	}
	type = GL_UNSIGNED_BYTE;
	cpp = 4;
    }

    image = (cairo_image_surface_t*)
	_cairo_image_surface_create_with_pixman_format (NULL,
							pixman_format,
							extents->width,
							extents->height,
							-1);
    if (unlikely (image->base.status))
	return &image->base;

    if (surface->base.serial == 0)
	return &image->base;

    status = _cairo_gl_context_acquire (surface->base.device, &ctx);
    if (unlikely (status)) {
	cairo_surface_destroy (&image->base);
	return _cairo_surface_create_in_error (status);
    }

    cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y);

    /* This is inefficient, as we'd rather just read the thing without making
     * it the destination.  But then, this is the fallback path, so let's not
     * fall back instead.
     */
    _cairo_gl_composite_flush (ctx);
    _cairo_gl_context_set_destination (ctx, surface);

    invert = ! _cairo_gl_surface_is_texture (surface) &&
	    ctx->has_mesa_pack_invert;

    glPixelStorei (GL_PACK_ALIGNMENT, 4);
    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
	glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
    if (invert)
	glPixelStorei (GL_PACK_INVERT_MESA, 1);
    glReadPixels (extents->x, extents->y,
		  extents->width, extents->height,
		  format, type, image->data);
    if (invert)
	glPixelStorei (GL_PACK_INVERT_MESA, 0);

    status = _cairo_gl_context_release (ctx, status);
    if (unlikely (status)) {
	cairo_surface_destroy (&image->base);
	image = (cairo_image_surface_t *)
	    _cairo_surface_create_in_error (status);
    }

    return &image->base;
}