Ejemplo n.º 1
0
cairo_status_t
_cairo_gl_context_init (cairo_gl_context_t *ctx)
{
    cairo_status_t status;
    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
    int gl_version = _cairo_gl_get_version ();
    cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor ();
    int n;

    _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);

    /* XXX The choice of compositor should be made automatically at runtime.
     * However, it is useful to force one particular compositor whilst
     * testing.
     */
     if (_cairo_gl_msaa_compositor_enabled ())
	ctx->compositor = _cairo_gl_msaa_compositor_get ();
    else
	ctx->compositor = _cairo_gl_span_compositor_get ();


    ctx->thread_aware = TRUE;

    memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
    cairo_list_init (&ctx->fonts);

    /* Support only GL version >= 1.3 */
    if (gl_version < CAIRO_GL_VERSION_ENCODE (1, 3))
	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);

    /* Check for required extensions */
    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
	if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) {
	    ctx->tex_target = GL_TEXTURE_2D;
	    ctx->has_npot_repeat = TRUE;
	} else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) {
	    ctx->tex_target = GL_TEXTURE_RECTANGLE;
	    ctx->has_npot_repeat = FALSE;
	} else
	    return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
    } else {
	ctx->tex_target = GL_TEXTURE_2D;
	if (_cairo_gl_has_extension ("GL_OES_texture_npot"))
	    ctx->has_npot_repeat = TRUE;
	else
	    ctx->has_npot_repeat = FALSE;
    }

    if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
	gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
	! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);

    if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
	! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
	return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);

    ctx->has_map_buffer = (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
			   (gl_flavor == CAIRO_GL_FLAVOR_ES &&
			    _cairo_gl_has_extension ("GL_OES_mapbuffer")));

    ctx->has_mesa_pack_invert =
	_cairo_gl_has_extension ("GL_MESA_pack_invert");

    ctx->has_packed_depth_stencil =
	((gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
	 _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
	(gl_flavor == CAIRO_GL_FLAVOR_ES &&
	 _cairo_gl_has_extension ("GL_OES_packed_depth_stencil")));

    ctx->num_samples = 1;

#if CAIRO_HAS_GL_SURFACE
    if (ctx->has_packed_depth_stencil &&
	_cairo_gl_has_extension ("GL_ARB_framebuffer_object")) {
	glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
    }
#endif

#if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
    if (ctx->has_packed_depth_stencil &&
	_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
	glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
    }
#endif
    ctx->supports_msaa = ctx->num_samples > 1;
    if (ctx->num_samples > MAX_MSAA_SAMPLES)
	ctx->num_samples = MAX_MSAA_SAMPLES;


    ctx->current_operator = -1;
    ctx->gl_flavor = gl_flavor;

    status = _cairo_gl_context_init_shaders (ctx);
    if (unlikely (status))
        return status;

    status = _cairo_cache_init (&ctx->gradients,
                                _cairo_gl_gradient_equal,
                                NULL,
                                (cairo_destroy_func_t) _cairo_gl_gradient_destroy,
                                CAIRO_GL_GRADIENT_CACHE_SIZE);
    if (unlikely (status))
        return status;

    ctx->vb = malloc (CAIRO_GL_VBO_SIZE);
    if (unlikely (ctx->vb == NULL)) {
	    _cairo_cache_fini (&ctx->gradients);
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    ctx->primitive_type = CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES;
    _cairo_array_init (&ctx->tristrip_indices, sizeof (unsigned short));

    /* PBO for any sort of texture upload */
    dispatch->GenBuffers (1, &ctx->texture_load_pbo);

    ctx->max_framebuffer_size = 0;
    glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size);
    ctx->max_texture_size = 0;
    glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
    ctx->max_textures = 0;
    glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures);

    for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
	_cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);

    return CAIRO_STATUS_SUCCESS;
}
Ejemplo n.º 2
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;
}
static cairo_int_status_t
traps_to_operand (void *_dst,
		  const cairo_rectangle_int_t *extents,
		  cairo_antialias_t	antialias,
		  cairo_traps_t		*traps,
		  cairo_gl_operand_t	*operand,
		  int dst_x, int dst_y)
{
    pixman_format_code_t pixman_format;
    pixman_image_t *pixman_image;
    cairo_surface_t *image, *mask;
    cairo_surface_pattern_t pattern;
    cairo_status_t status;

    pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1;
    pixman_image = pixman_image_create_bits (pixman_format,
					     extents->width,
					     extents->height,
					     NULL, 0);
    if (unlikely (pixman_image == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps);
    image = _cairo_image_surface_create_for_pixman_image (pixman_image,
							  pixman_format);
    if (unlikely (image->status)) {
	pixman_image_unref (pixman_image);
	return image->status;
    }

    /* GLES2 only supports RGB/RGBA when uploading */
    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) {
	cairo_surface_pattern_t pattern;
	cairo_surface_t *rgba_image;

	/* XXX perform this fixup inside _cairo_gl_draw_image() */

	rgba_image =
	    _cairo_image_surface_create_with_pixman_format (NULL,
							    _cairo_is_little_endian () ?  PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8,
							    extents->width,
							    extents->height,
							    0);
	if (unlikely (rgba_image->status))
	    return rgba_image->status;

	_cairo_pattern_init_for_surface (&pattern, image);
	status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE,
				       &pattern.base, NULL);
	_cairo_pattern_fini (&pattern.base);

	cairo_surface_destroy (image);
	image = rgba_image;

	if (unlikely (status)) {
	    cairo_surface_destroy (image);
	    return status;
	}
    }

    mask = _cairo_surface_create_similar_scratch (_dst,
						  CAIRO_CONTENT_COLOR_ALPHA,
						  extents->width,
						  extents->height);
    if (unlikely (mask->status)) {
	cairo_surface_destroy (image);
	return mask->status;
    }

    status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
					   (cairo_image_surface_t *)image,
					   0, 0,
					   extents->width, extents->height,
					   0, 0);
    cairo_surface_destroy (image);

    if (unlikely (status))
	goto error;

    _cairo_pattern_init_for_surface (&pattern, mask);
    cairo_matrix_init_translate (&pattern.base.matrix,
				 -extents->x+dst_x, -extents->y+dst_y);
    pattern.base.filter = CAIRO_FILTER_NEAREST;
    pattern.base.extend = CAIRO_EXTEND_NONE;
    status = _cairo_gl_operand_init (operand, &pattern.base, _dst,
				     &_cairo_unbounded_rectangle,
				     &_cairo_unbounded_rectangle);
    _cairo_pattern_fini (&pattern.base);

    if (unlikely (status))
	goto error;

    operand->texture.owns_surface = mask;
    return CAIRO_STATUS_SUCCESS;

error:
    cairo_surface_destroy (mask);
    return status;
}