Exemplo n.º 1
0
static cairo_status_t
_cairo_gl_surface_finish (void *abstract_surface)
{
    cairo_gl_surface_t *surface = abstract_surface;
    cairo_status_t status;
    cairo_gl_context_t *ctx;

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

    if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
        ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
        _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
    if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
        ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
        _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
    if (ctx->current_target == surface)
	ctx->current_target = NULL;

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

    return _cairo_gl_context_release (ctx, status);
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
static cairo_surface_t *
_cairo_gl_surface_create_similar (void		 *abstract_surface,
				  cairo_content_t  content,
				  int		  width,
				  int		  height)
{
    cairo_surface_t *surface = abstract_surface;
    cairo_gl_context_t *ctx;
    cairo_status_t status;

    if (! _cairo_gl_surface_size_valid (abstract_surface, width, height))
        return _cairo_image_surface_create_with_content (content, width, height);

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

    surface = _cairo_gl_surface_create_scratch (ctx, content, width, height);

    status = _cairo_gl_context_release (ctx, status);
    if (unlikely (status)) {
        cairo_surface_destroy (surface);
        return _cairo_surface_create_in_error (status);
    }

    return surface;
}
Exemplo n.º 4
0
/**
 * cairo_gl_surface_create_for_texture:
 * @content: type of content in the surface
 * @tex: name of texture to use for storage of surface pixels
 * @width: width of the surface, in pixels
 * @height: height of the surface, in pixels
 *
 * Creates a GL surface for the specified texture with the specified
 * content and dimensions.  The texture must be kept around until the
 * #cairo_surface_t is destroyed or cairo_surface_finish() is called
 * on the surface.  The initial contents of @tex will be used as the
 * initial image contents; you must explicitly clear the buffer,
 * using, for example, cairo_rectangle() and cairo_fill() if you want
 * it cleared.  The format of @tex should be compatible with @content,
 * in the sense that it must have the color components required by
 * @content.
 *
 * Return value: a pointer to the newly created surface. The caller
 * owns the surface and should call cairo_surface_destroy() when done
 * with it.
 *
 * This function always returns a valid pointer, but it will return a
 * pointer to a "nil" surface if an error such as out of memory
 * occurs. You can use cairo_surface_status() to check for this.
 **/
cairo_surface_t *
cairo_gl_surface_create_for_texture (cairo_device_t	*abstract_device,
				     cairo_content_t	 content,
				     unsigned int	 tex,
				     int		 width,
				     int		 height)
{
    cairo_gl_context_t *ctx;
    cairo_gl_surface_t *surface;
    cairo_status_t status;

    if (! CAIRO_CONTENT_VALID (content))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));

    if (abstract_device == NULL)
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));

    if (abstract_device->status)
	return _cairo_surface_create_in_error (abstract_device->status);

    if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH));

    status = _cairo_gl_context_acquire (abstract_device, &ctx);
    if (unlikely (status))
	return _cairo_surface_create_in_error (status);

    surface = (cairo_gl_surface_t *)
	_cairo_gl_surface_create_scratch_for_texture (ctx, content,
						      tex, width, height);
    status = _cairo_gl_context_release (ctx, status);

    return &surface->base;
}
Exemplo n.º 5
0
static cairo_status_t
_gl_flush (void *device)
{
    cairo_gl_context_t *ctx;
    cairo_status_t status;

    status = _cairo_gl_context_acquire (device, &ctx);
    if (unlikely (status))
        return status;

    _cairo_gl_composite_flush (ctx);

    _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
    _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);

    if (ctx->clip_region) {
        cairo_region_destroy (ctx->clip_region);
        ctx->clip_region = NULL;
    }

    ctx->current_target = NULL;
    ctx->current_operator = -1;
    ctx->vertex_size = 0;
    ctx->pre_shader = NULL;
    _cairo_gl_set_shader (ctx, NULL);

    ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0);

    glDisable (GL_SCISSOR_TEST);
    glDisable (GL_BLEND);

    return _cairo_gl_context_release (ctx, status);
}
Exemplo n.º 6
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);
}
Exemplo n.º 7
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);
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
0
static cairo_int_status_t
_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
				   const cairo_gradient_pattern_t *pattern,
                                   cairo_gl_gradient_t **gradient)
{
    cairo_gl_context_t *ctx;
    cairo_status_t status;

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

    status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);

    return _cairo_gl_context_release (ctx, status);
}
Exemplo n.º 10
0
cairo_surface_t *
cairo_gl_surface_create (cairo_device_t		*abstract_device,
			 cairo_content_t	 content,
			 int			 width,
			 int			 height)
{
    cairo_gl_context_t *ctx;
    cairo_gl_surface_t *surface;
    cairo_status_t status;

    if (! CAIRO_CONTENT_VALID (content))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));

    if (abstract_device == NULL)
	return _cairo_image_surface_create_with_content (content, width, height);

    if (abstract_device->status)
	return _cairo_surface_create_in_error (abstract_device->status);

    if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));

    status = _cairo_gl_context_acquire (abstract_device, &ctx);
    if (unlikely (status))
	return _cairo_surface_create_in_error (status);

    surface = (cairo_gl_surface_t *)
	_cairo_gl_surface_create_scratch (ctx, content, width, height);
    if (unlikely (surface->base.status)) {
	status = _cairo_gl_context_release (ctx, surface->base.status);
	cairo_surface_destroy (&surface->base);
	return _cairo_surface_create_in_error (status);
    }

    /* Cairo surfaces start out initialized to transparent (black) */
    status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);

    status = _cairo_gl_context_release (ctx, status);
    if (unlikely (status)) {
	cairo_surface_destroy (&surface->base);
	return _cairo_surface_create_in_error (status);
    }

    return &surface->base;
}
Exemplo n.º 11
0
void
_cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient)
{
    cairo_gl_context_t *ctx;
    cairo_status_t ignore;

    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));

    if (! _cairo_reference_count_dec_and_test (&gradient->ref_count))
	return;

    if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) {
        glDeleteTextures (1, &gradient->tex);
        ignore = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
    }

    free (gradient);
}
Exemplo n.º 12
0
static cairo_status_t
_cairo_gl_surface_flush (void *abstract_surface)
{
    cairo_gl_surface_t *surface = abstract_surface;
    cairo_status_t status;
    cairo_gl_context_t *ctx;

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

    if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
         ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) ||
        (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
         ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) ||
        (ctx->current_target == surface))
      _cairo_gl_composite_flush (ctx);

    return _cairo_gl_context_release (ctx, status);
}
Exemplo n.º 13
0
void
_cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient)
{
    cairo_gl_context_t *ctx;
    cairo_status_t ignore;

    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));

    if (! _cairo_reference_count_dec_and_test (&gradient->ref_count))
	return;

    if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) {
	/* The gradient my still be active in the last operation, so flush */
	_cairo_gl_composite_flush (ctx);
	glDeleteTextures (1, &gradient->tex);
	ignore = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
    }

    free (gradient);
}
Exemplo n.º 14
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);
    }
}
Exemplo n.º 15
0
static cairo_status_t
_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
				 const cairo_pattern_t *_src,
				 cairo_gl_surface_t *dst,
				 const cairo_rectangle_int_t *extents)
{
    cairo_status_t status;
    cairo_gl_surface_t *surface;
    cairo_gl_context_t *ctx;
    cairo_image_surface_t *image;
    cairo_bool_t src_is_gl_surface = FALSE;
    cairo_rectangle_int_t map_extents;

    if (_src->type == CAIRO_PATTERN_TYPE_SURFACE) {
	cairo_surface_t* src_surface = ((cairo_surface_pattern_t *) _src)->surface;
	src_is_gl_surface = src_surface->type == CAIRO_SURFACE_TYPE_GL;
    }

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

    surface = (cairo_gl_surface_t *)
	_cairo_gl_surface_create_scratch (ctx,
					  CAIRO_CONTENT_COLOR_ALPHA,
					  extents->width, extents->height);
    map_extents = *extents;
    map_extents.x = map_extents.y = 0;
    image = _cairo_surface_map_to_image (&surface->base, &map_extents);

    /* If the pattern is a GL surface, it belongs to some other GL context,
       so we need to release this device while we paint it to the image. */
    if (src_is_gl_surface) {
	status = _cairo_gl_context_release (ctx, status);
	if (unlikely (status)) {
	    _cairo_surface_unmap_image (&surface->base, image);
	    goto fail;
	}
    }

    status = _cairo_surface_offset_paint (&image->base, extents->x, extents->y,
					  CAIRO_OPERATOR_SOURCE, _src, NULL);

    if (src_is_gl_surface) {
	status = _cairo_gl_context_acquire (dst->base.device, &ctx);
	if (unlikely (status)) {
	    _cairo_surface_unmap_image (&surface->base, image);
	    goto fail;
	}
    }

    status = _cairo_surface_unmap_image (&surface->base, image);
    status = _cairo_gl_context_release (ctx, status);
    if (unlikely (status))
	goto fail;

    *operand = surface->operand;
    operand->texture.owns_surface = surface;
    operand->texture.attributes.matrix.x0 -= extents->x * operand->texture.attributes.matrix.xx;
    operand->texture.attributes.matrix.y0 -= extents->y * operand->texture.attributes.matrix.yy;
    return CAIRO_STATUS_SUCCESS;

fail:
    cairo_surface_destroy (&surface->base);
    return status;
}
Exemplo n.º 16
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;
}
Exemplo n.º 17
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;
}
Exemplo n.º 18
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;

    _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;
}
Exemplo n.º 19
0
static cairo_status_t
render_glyphs (cairo_gl_surface_t *dst,
	       int dst_x, int dst_y,
	       cairo_operator_t op,
	       cairo_surface_t *source,
	       cairo_composite_glyphs_info_t *info,
	       cairo_bool_t *has_component_alpha,
	       cairo_clip_t *clip)
{
    cairo_format_t last_format = CAIRO_FORMAT_INVALID;
    cairo_gl_glyph_cache_t *cache = NULL;
    cairo_gl_context_t *ctx;
    cairo_gl_emit_glyph_t emit = NULL;
    cairo_gl_composite_t setup;
    cairo_int_status_t status;
    int i = 0;

    TRACE ((stderr, "%s (%d, %d)x(%d, %d)\n", __FUNCTION__,
	    info->extents.x, info->extents.y,
	    info->extents.width, info->extents.height));

    *has_component_alpha = FALSE;

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

    status = _cairo_gl_composite_init (&setup, op, dst, TRUE);
    if (unlikely (status))
	goto FINISH;

    if (source == NULL) {
	    _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE);
    } else {
	    _cairo_gl_composite_set_source_operand (&setup,
						    source_to_operand (source));

    }

    _cairo_gl_composite_set_clip (&setup, clip);

    for (i = 0; i < info->num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	cairo_gl_glyph_t *glyph;
	double x_offset, y_offset;
	double x1, x2, y1, y2;

	status = _cairo_scaled_glyph_lookup (info->font,
					     info->glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
					     &scaled_glyph);
	if (unlikely (status))
	    goto FINISH;

	if (scaled_glyph->surface->width  == 0 ||
	    scaled_glyph->surface->height == 0)
	{
	    continue;
	}
	if (scaled_glyph->surface->format != last_format) {
	    status = cairo_gl_context_get_glyph_cache (ctx,
						       scaled_glyph->surface->format,
                                                       &cache);
            if (unlikely (status))
                goto FINISH;

	    last_format = scaled_glyph->surface->format;

	    _cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand);
	    *has_component_alpha |= cache->surface->operand.texture.attributes.has_component_alpha;

	    /* XXX Shoot me. */
            status = _cairo_gl_composite_begin (&setup, &ctx);
            status = _cairo_gl_context_release (ctx, status);
	    if (unlikely (status))
		goto FINISH;

	    emit = _cairo_gl_context_choose_emit_glyph (ctx);
	}

	if (scaled_glyph->dev_private_key != cache) {
	    cairo_scaled_glyph_private_t *priv;

	    priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache);
	    if (priv) {
		scaled_glyph->dev_private_key = cache;
		scaled_glyph->dev_private = cairo_container_of (priv,
								cairo_gl_glyph_t,
								base);
	    } else {
		status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);

		if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
		    /* Cache is full, so flush existing prims and try again. */
		    _cairo_gl_composite_flush (ctx);
		    _cairo_gl_glyph_cache_unlock (cache);
		    status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
		}

		if (unlikely (_cairo_int_status_is_error (status)))
		    goto FINISH;
	    }
	}

	x_offset = scaled_glyph->surface->base.device_transform.x0;
	y_offset = scaled_glyph->surface->base.device_transform.y0;

	x1 = _cairo_lround (info->glyphs[i].x - x_offset - dst_x);
	y1 = _cairo_lround (info->glyphs[i].y - y_offset - dst_y);
	x2 = x1 + scaled_glyph->surface->width;
	y2 = y1 + scaled_glyph->surface->height;

	glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
	assert (emit);
	emit (ctx,
	      x1, y1, x2, y2,
	      glyph->p1.x, glyph->p1.y,
	      glyph->p2.x, glyph->p2.y);
    }

    status = CAIRO_STATUS_SUCCESS;
  FINISH:
    status = _cairo_gl_context_release (ctx, status);

    _cairo_gl_composite_fini (&setup);
    return status;
}
Exemplo n.º 20
0
cairo_status_t
_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
			      cairo_image_surface_t *src,
			      int src_x, int src_y,
			      int width, int height,
			      int dst_x, int dst_y)
{
    GLenum internal_format, format, type;
    cairo_bool_t has_alpha, needs_swap;
    cairo_image_surface_t *clone = NULL;
    cairo_gl_context_t *ctx;
    int cpp;
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;

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

    if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
					       src->pixman_format,
					       &internal_format,
					       &format,
					       &type,
					       &has_alpha,
					       &needs_swap))
    {
	cairo_bool_t is_supported;

	clone = _cairo_image_surface_coerce (src);
	if (unlikely (status = clone->base.status))
	    goto FAIL;

	is_supported =
	    _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
						 clone->pixman_format,
		                                 &internal_format,
						 &format,
						 &type,
						 &has_alpha,
						 &needs_swap);
	assert (is_supported);
	assert (!needs_swap);
	src = clone;
    }

    cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;

    status = _cairo_gl_surface_flush (&dst->base);
    if (unlikely (status))
	goto FAIL;

    if (_cairo_gl_surface_is_texture (dst)) {
	void *data_start = src->data + src_y * src->stride + src_x * cpp;
	void *data_start_gles2 = NULL;

	/*
	 * Due to GL_UNPACK_ROW_LENGTH missing in GLES2 we have to extract the
	 * image data ourselves in some cases. In particular, we must extract
	 * the pixels if:
	 * a. we don't want full-length lines or
	 * b. the row stride cannot be handled by GL itself using a 4 byte
	 *     alignment constraint
	 */
	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
	    (src->width * cpp < src->stride - 3 ||
	     width != src->width))
	{
	    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
	    status = _cairo_gl_surface_extract_image_data (src, src_x, src_y,
							   width, height,
							   &data_start_gles2);
	    if (unlikely (status))
		goto FAIL;

	    data_start = data_start_gles2;
	}
	else
	{
	    glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
	    if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
		glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
	}

        _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
	glBindTexture (ctx->tex_target, dst->tex);
	glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexSubImage2D (ctx->tex_target, 0,
			 dst_x, dst_y, width, height,
			 format, type, data_start);

	free (data_start_gles2);

	/* If we just treated some rgb-only data as rgba, then we have to
	 * go back and fix up the alpha channel where we filled in this
	 * texture data.
	 */
	if (!has_alpha) {
	    _cairo_gl_surface_fill_alpha_channel (dst, ctx,
						  dst_x, dst_y,
						  width, height);
	}
    } else {
        cairo_surface_t *tmp;

        tmp = _cairo_gl_surface_create_scratch (ctx,
                                                dst->base.content,
                                                width, height);
        if (unlikely (tmp->status))
            goto FAIL;

        status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *) tmp,
                                               src,
                                               src_x, src_y,
                                               width, height,
                                               0, 0);
        if (status == CAIRO_INT_STATUS_SUCCESS) {
            cairo_surface_pattern_t tmp_pattern;
	    cairo_rectangle_int_t r;
	    cairo_clip_t *clip;

            _cairo_pattern_init_for_surface (&tmp_pattern, tmp);
	    cairo_matrix_init_translate (&tmp_pattern.base.matrix,
					 -dst_x, -dst_y);
	    tmp_pattern.base.filter = CAIRO_FILTER_NEAREST;
	    tmp_pattern.base.extend = CAIRO_EXTEND_NONE;

	    r.x = dst_x;
	    r.y = dst_y;
	    r.width = width;
	    r.height = height;
	    clip = _cairo_clip_intersect_rectangle (NULL, &r);
	    status = _cairo_surface_paint (&dst->base,
					   CAIRO_OPERATOR_SOURCE,
					   &tmp_pattern.base,
					   clip);
	    _cairo_clip_destroy (clip);
            _cairo_pattern_fini (&tmp_pattern.base);
        }

        cairo_surface_destroy (tmp);
    }

FAIL:
    status = _cairo_gl_context_release (ctx, status);

    if (clone)
        cairo_surface_destroy (&clone->base);

    return status;
}
Exemplo n.º 21
0
static cairo_status_t
_cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
					 const cairo_pattern_t *_src,
					 cairo_gl_surface_t *dst,
					 const cairo_rectangle_int_t *sample,
					 const cairo_rectangle_int_t *extents,
					 cairo_bool_t use_texgen)
{
    const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
    cairo_surface_pattern_t local_pattern;
    cairo_surface_subsurface_t *sub;
    cairo_gl_surface_t *surface;
    cairo_gl_context_t *ctx;
    cairo_surface_attributes_t *attributes;
    cairo_status_t status;

    sub = (cairo_surface_subsurface_t *) src->surface;

    if (sub->snapshot &&
	sub->snapshot->type == CAIRO_SURFACE_TYPE_GL &&
	sub->snapshot->device == dst->base.device)
    {
	surface = (cairo_gl_surface_t *)
	    cairo_surface_reference (sub->snapshot);
    }
    else
    {
	status = _cairo_gl_context_acquire (dst->base.device, &ctx);
	if (unlikely (status))
	    return status;

	/* XXX Trim surface to the sample area within the subsurface? */
	surface = (cairo_gl_surface_t *)
	    _cairo_gl_surface_create_scratch (ctx,
					      sub->target->content,
					      sub->extents.width,
					      sub->extents.height);
	if (surface->base.status)
	    return _cairo_gl_context_release (ctx, surface->base.status);

	_cairo_pattern_init_for_surface (&local_pattern, sub->target);
	cairo_matrix_init_translate (&local_pattern.base.matrix,
				     sub->extents.x, sub->extents.y);
	local_pattern.base.filter = CAIRO_FILTER_NEAREST;
	status = _cairo_surface_paint (&surface->base,
				       CAIRO_OPERATOR_SOURCE,
				       &local_pattern.base,
				       NULL);
	_cairo_pattern_fini (&local_pattern.base);

	status = _cairo_gl_context_release (ctx, status);
	if (unlikely (status)) {
	    cairo_surface_destroy (&surface->base);
	    return status;
	}

	_cairo_surface_subsurface_set_snapshot (&sub->base, &surface->base);
    }

    status = _cairo_gl_surface_resolve_multisampling (surface);
    if (unlikely (status))
        return status;

    attributes = &operand->texture.attributes;

    operand->type = CAIRO_GL_OPERAND_TEXTURE;
    operand->texture.surface = surface;
    operand->texture.owns_surface = surface;
    operand->texture.tex = surface->tex;

    if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
	attributes->matrix = src->base.matrix;
    } else {
	cairo_matrix_t m;

	cairo_matrix_init_scale (&m,
				 1.0 / surface->width,
				 1.0 / surface->height);
	cairo_matrix_multiply (&attributes->matrix, &src->base.matrix, &m);
    }

    attributes->extend = src->base.extend;
    attributes->filter = src->base.filter;
    attributes->has_component_alpha = src->base.has_component_alpha;

    operand->texture.texgen = use_texgen;
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_render_glyphs (cairo_gl_surface_t	*dst,
	        int dst_x, int dst_y,
	        cairo_operator_t	 op,
		const cairo_pattern_t	*source,
		cairo_glyph_t		*glyphs,
		int			 num_glyphs,
		const cairo_rectangle_int_t *glyph_extents,
		cairo_scaled_font_t	*scaled_font,
		cairo_region_t		*clip_region,
		int			*remaining_glyphs)
{
    cairo_format_t last_format = (cairo_format_t) -1;
    cairo_gl_glyph_cache_t *cache = NULL;
    cairo_gl_context_t *ctx;
    cairo_gl_glyphs_setup_t setup;
    cairo_gl_composite_setup_t composite_setup;
    cairo_status_t status;
    int i = 0;
    GLuint vbo = 0;

    status = _cairo_gl_operand_init (&composite_setup.src, source, dst,
				     glyph_extents->x, glyph_extents->y,
				     dst_x, dst_y,
				     glyph_extents->width,
				     glyph_extents->height);
    if (unlikely (status))
	return status;

    ctx = _cairo_gl_context_acquire (dst->ctx);

    /* Set up the mask to source from the incoming vertex color. */
    glActiveTexture (GL_TEXTURE1);
    glEnable (GL_TEXTURE_2D);
    /* IN: dst.argb = src.argb * mask.aaaa */
    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);

    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);

    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);

    _cairo_gl_set_destination (dst);
    _cairo_gl_set_operator (dst, op);
    _cairo_gl_set_src_operand (ctx, &composite_setup);

    _cairo_scaled_font_freeze_cache (scaled_font);
    if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
	status = CAIRO_INT_STATUS_UNSUPPORTED;
	goto CLEANUP_FONT;
    }

    if (scaled_font->surface_private == NULL) {
	/* XXX couple into list to remove on context destruction */
	scaled_font->surface_private = ctx;
	scaled_font->surface_backend = &_cairo_gl_surface_backend;
    }

    /* Create our VBO so that we can accumulate a bunch of glyph primitives
     * into one giant DrawArrays.
     */
    memset(&setup, 0, sizeof(setup));
    setup.composite = &composite_setup;
    setup.clip = clip_region;
    setup.dst = dst;
    setup.vertex_size = 4;
    if (composite_setup.src.type == OPERAND_TEXTURE)
	setup.vertex_size += 2;
    setup.vbo_size = num_glyphs * 4 * setup.vertex_size;
    if (setup.vbo_size > 4096)
	setup.vbo_size = 4096;

    glGenBuffersARB (1, &vbo);
    glBindBufferARB (GL_ARRAY_BUFFER_ARB, vbo);

    glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
		     (void *)(uintptr_t)(0));
    glEnableClientState (GL_VERTEX_ARRAY);
    if (composite_setup.src.type == OPERAND_TEXTURE) {
	/* Note that we're packing texcoord 0 after texcoord 1, for
	 * convenience.
	 */
	glClientActiveTexture (GL_TEXTURE0);
	glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
			   (void *)(uintptr_t)(4 * sizeof (GLfloat)));
	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
    }
    glClientActiveTexture (GL_TEXTURE1);
    glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
		       (void *)(uintptr_t)(2 * sizeof (GLfloat)));
    glEnableClientState (GL_TEXTURE_COORD_ARRAY);

    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	double x_offset, y_offset;
	double x1, x2, y1, y2;

	status = _cairo_scaled_glyph_lookup (scaled_font,
					     glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
					     &scaled_glyph);
	if (unlikely (status))
	    goto FINISH;

	if (scaled_glyph->surface->width  == 0 ||
	    scaled_glyph->surface->height == 0)
	{
	    continue;
	}
	if (scaled_glyph->surface->width  > GLYPH_CACHE_MAX_SIZE ||
	    scaled_glyph->surface->height > GLYPH_CACHE_MAX_SIZE)
	{
	    status = CAIRO_INT_STATUS_UNSUPPORTED;
	    goto FINISH;
	}

	if (scaled_glyph->surface->format != last_format) {
	    /* Switching textures, so flush any queued prims. */
	    _cairo_gl_flush_glyphs (ctx, &setup);

	    glActiveTexture (GL_TEXTURE1);
	    cache = cairo_gl_context_get_glyph_cache (ctx,
						      scaled_glyph->surface->format);

	    glBindTexture (GL_TEXTURE_2D, cache->tex);

	    last_format = scaled_glyph->surface->format;
	}

	if (scaled_glyph->surface_private == NULL) {
	    status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
	    if (unlikely (_cairo_status_is_error (status)))
		goto FINISH;

	    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
		/* Cache is full, so flush existing prims and try again. */
		_cairo_gl_flush_glyphs (ctx, &setup);
		_cairo_gl_glyph_cache_unlock (cache);
	    }

	    status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
	    if (unlikely (status))
		goto FINISH;
	}

	x_offset = scaled_glyph->surface->base.device_transform.x0;
	y_offset = scaled_glyph->surface->base.device_transform.y0;

	x1 = _cairo_lround (glyphs[i].x - x_offset);
	y1 = _cairo_lround (glyphs[i].y - y_offset);
	x2 = x1 + scaled_glyph->surface->width;
	y2 = y1 + scaled_glyph->surface->height;

	_cairo_gl_emit_glyph_rectangle (ctx, &setup,
					x1, y1, x2, y2,
					_cairo_gl_glyph_cache_lock (cache, scaled_glyph));
    }

    status = CAIRO_STATUS_SUCCESS;
  FINISH:
    _cairo_gl_flush_glyphs (ctx, &setup);
  CLEANUP_FONT:
    _cairo_scaled_font_thaw_cache (scaled_font);

    glDisable (GL_BLEND);
    glDisable (GL_SCISSOR_TEST);

    glDisableClientState (GL_VERTEX_ARRAY);

    glClientActiveTexture (GL_TEXTURE0);
    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
    glActiveTexture (GL_TEXTURE0);
    glDisable (GL_TEXTURE_2D);

    glClientActiveTexture (GL_TEXTURE1);
    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
    glActiveTexture (GL_TEXTURE1);
    glDisable (GL_TEXTURE_2D);

    if (vbo != 0) {
	glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
	glDeleteBuffersARB (1, &vbo);
    }

    _cairo_gl_context_release (ctx);

    _cairo_gl_operand_destroy (&composite_setup.src);

    *remaining_glyphs = num_glyphs - i;
    return status;
}
Exemplo n.º 23
0
static cairo_status_t
render_glyphs (cairo_gl_surface_t *dst,
	       int dst_x, int dst_y,
	       cairo_operator_t op,
	       cairo_surface_t *source,
	       cairo_composite_glyphs_info_t *info,
	       cairo_bool_t *has_component_alpha,
	       cairo_clip_t *clip,
	       cairo_bool_t via_msaa_compositor)
{
    cairo_format_t last_format = CAIRO_FORMAT_INVALID;
    cairo_gl_glyph_cache_t *cache = NULL;
    cairo_gl_context_t *ctx;
    cairo_gl_composite_t setup;
    cairo_int_status_t status;
    int i = 0;
    cairo_bool_t is_argb32;

    TRACE ((stderr, "%s (%d, %d)x(%d, %d)\n", __FUNCTION__,
	    info->extents.x, info->extents.y,
	    info->extents.width, info->extents.height));

    *has_component_alpha = FALSE;

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

    /* Traps compositor never has CLEAR operator. */
    is_argb32 =
	info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ||
	info->font->options.antialias == CAIRO_ANTIALIAS_BEST;

    /* If we are invoked by traps compositor, we keep what is in code
       otherwise, we handle non-subpixel/best directly in msaa
       compositor. */
    if (!via_msaa_compositor)
            status = _cairo_gl_composite_init (&setup, op, dst, TRUE);
    else if (info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ||
       info->font->options.antialias == CAIRO_ANTIALIAS_BEST)
        status = _cairo_gl_composite_init (&setup, op, dst, TRUE);
    else
        status = _cairo_gl_composite_init (&setup, op, dst, FALSE);

    if (unlikely (status))
	goto FINISH;

    if (source == NULL) {
	    _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE);
    } else {
	    _cairo_gl_composite_set_source_operand (&setup,
						    source_to_operand (source));

    }

    if (setup.src.type == CAIRO_GL_OPERAND_CONSTANT)
        setup.src.use_color_attribute = TRUE;

    _cairo_gl_composite_set_clip (&setup, clip);

    for (i = 0; i < info->num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	cairo_gl_glyph_t *glyph;
	double x_offset, y_offset;
	double x1, x2, y1, y2;

	status = _cairo_scaled_glyph_lookup (info->font,
					     info->glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
					     &scaled_glyph);
	if (unlikely (status))
	    goto FINISH;

	if (scaled_glyph->surface->width  == 0 ||
	    scaled_glyph->surface->height == 0)
	{
	    continue;
	}
	if (scaled_glyph->surface->format != last_format) {
	    status = cairo_gl_context_get_glyph_cache (ctx,
						       scaled_glyph->surface->format,
                                                       &cache);
            if (unlikely (status))
                goto FINISH;

	    last_format = scaled_glyph->surface->format;

	    /* In msaa compositor, clear operator needs component alpha,
	       we need to reset to FALSE if previously clear operator
	       has set it to TRUE. */
	    if (via_msaa_compositor) {
		if (op == CAIRO_OPERATOR_CLEAR || is_argb32)
		    cache->surface->operand.texture.attributes.has_component_alpha = TRUE;
		else
		    cache->surface->operand.texture.attributes.has_component_alpha = FALSE;
	    }
	    _cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand);
	    *has_component_alpha |= cache->surface->operand.texture.attributes.has_component_alpha;

	    /* XXX Shoot me. */
            status = _cairo_gl_composite_begin (&setup, &ctx);
            status = _cairo_gl_context_release (ctx, status);
	    if (unlikely (status))
		goto FINISH;
	}

	if (scaled_glyph->dev_private_key != cache) {
	    cairo_scaled_glyph_private_t *priv;

	    priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache);
	    if (priv) {
		scaled_glyph->dev_private_key = cache;
		scaled_glyph->dev_private = cairo_container_of (priv,
								cairo_gl_glyph_t,
								base);
	    } else {
		status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);

		if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
		    /* Cache is full, so flush existing prims and try again. */
		    _cairo_gl_composite_flush (ctx);
		    _cairo_gl_glyph_cache_unlock (cache);
		    status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
		}

		if (unlikely (_cairo_int_status_is_error (status)))
		    goto FINISH;
	    }
	}

	x_offset = scaled_glyph->surface->base.device_transform.x0;
	y_offset = scaled_glyph->surface->base.device_transform.y0;

	x1 = _cairo_lround (info->glyphs[i].x - x_offset - dst_x);
	y1 = _cairo_lround (info->glyphs[i].y - y_offset - dst_y);
	x2 = x1 + scaled_glyph->surface->width;
	y2 = y1 + scaled_glyph->surface->height;

	glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
	_cairo_gl_composite_emit_glyph (ctx,
					x1, y1, x2, y2,
                                        glyph->p1.x, glyph->p1.y,
                                        glyph->p2.x, glyph->p2.y);
    }

    status = CAIRO_STATUS_SUCCESS;

  FINISH:
    status = _cairo_gl_context_release (ctx, status);

    _cairo_gl_composite_fini (&setup);
    return status;
}
Exemplo n.º 24
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;
}