static void
_gl_pattern_fix_reference_count (const cairo_pattern_t *pattern)
{
   cairo_pattern_type_t pattern_type = cairo_pattern_get_type ((cairo_pattern_t *)pattern);

   /* We need to increase reference count on surface and gradient if
      the original_source_pattern is a cairo_gl_source_t type. */
    if (pattern_type == CAIRO_PATTERN_TYPE_SURFACE) {

	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)pattern;
	cairo_surface_t *pattern_surface = surface_pattern->surface;

	if (cairo_surface_get_type (pattern_surface) == CAIRO_SURFACE_TYPE_GL &&
	    ! pattern_surface->device &&
	    ! _cairo_surface_is_subsurface (pattern_surface)) {

	    cairo_gl_source_t *_source = (cairo_gl_source_t *)pattern_surface;

	    switch (_source->operand.type) {
	    case CAIRO_GL_OPERAND_TEXTURE:
		cairo_surface_reference (&(_source->operand.texture.owns_surface)->base);
		break;
	    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
	    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
	    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
	    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
		_cairo_gl_gradient_reference (_source->operand.gradient.gradient);
		break;
	    default:
	    case CAIRO_GL_OPERAND_NONE:
	    case CAIRO_GL_OPERAND_CONSTANT:
	    case CAIRO_GL_OPERAND_COUNT:
		break;
	    }
	}
    }
}
void
_cairo_gl_operand_copy (cairo_gl_operand_t *dst,
			const cairo_gl_operand_t *src)
{
    *dst = *src;
    switch (dst->type) {
    case CAIRO_GL_OPERAND_CONSTANT:
	break;
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
	_cairo_gl_gradient_reference (dst->gradient.gradient);
	break;
    case CAIRO_GL_OPERAND_TEXTURE:
	cairo_surface_reference (&dst->texture.owns_surface->base);
	break;
    default:
    case CAIRO_GL_OPERAND_COUNT:
        ASSERT_NOT_REACHED;
    case CAIRO_GL_OPERAND_NONE:
        break;
    }
}
Exemple #3
0
cairo_int_status_t
_cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
			   unsigned int                  n_stops,
			   const cairo_gradient_stop_t  *stops,
			   cairo_gl_gradient_t         **gradient_out)
{
    unsigned long hash;
    cairo_gl_gradient_t *gradient;
    cairo_status_t status;
    int tex_width;
    GLint internal_format;
    void *data;

    if ((unsigned int) ctx->max_texture_size / 2 <= n_stops)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    hash = _cairo_gl_gradient_hash (n_stops, stops);

    gradient = _cairo_gl_gradient_lookup (ctx, hash, n_stops, stops);
    if (gradient) {
	*gradient_out = _cairo_gl_gradient_reference (gradient);
	return CAIRO_STATUS_SUCCESS;
    }

    gradient = _cairo_malloc (sizeof (cairo_gl_gradient_t) + sizeof (cairo_gradient_stop_t) * (n_stops - 1));
    if (gradient == NULL)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    tex_width = _cairo_gl_gradient_sample_width (n_stops, stops);
    if (tex_width > ctx->max_texture_size)
	tex_width = ctx->max_texture_size;

    CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 2);
    gradient->cache_entry.hash = hash;
    gradient->cache_entry.size = tex_width;
    gradient->device = &ctx->base;
    gradient->n_stops = n_stops;
    gradient->stops = gradient->stops_embedded;
    memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t));

    glGenTextures (1, &gradient->tex);
    _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
    glBindTexture (ctx->tex_target, gradient->tex);

    data = _cairo_malloc_ab (tex_width, sizeof (uint32_t));
    if (unlikely (data == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto cleanup_gradient;
    }

    status = _cairo_gl_gradient_render (ctx, n_stops, stops, data, tex_width);
    if (unlikely (status))
	goto cleanup_data;

    /*
     * In OpenGL ES 2.0 no format conversion is allowed i.e. 'internalFormat'
     * must match 'format' in glTexImage2D.
     */
    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES3 ||
	_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2)
	internal_format = GL_BGRA;
    else
	internal_format = GL_RGBA;

    glTexImage2D (ctx->tex_target, 0, internal_format, tex_width, 1, 0,
		  GL_BGRA, GL_UNSIGNED_BYTE, data);

    free (data);

    /* we ignore errors here and just return an uncached gradient */
    if (unlikely (_cairo_cache_insert (&ctx->gradients, &gradient->cache_entry)))
	CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1);

    *gradient_out = gradient;
    return CAIRO_STATUS_SUCCESS;

cleanup_data:
    free (data);
cleanup_gradient:
    free (gradient);
    return status;
}