Ejemplo n.º 1
0
void
_cairo_gl_composite_flush (cairo_gl_context_t *ctx)
{
    unsigned int count;
    int i;

    if (_cairo_gl_context_is_flushed (ctx))
        return;

    count = ctx->vb_offset / ctx->vertex_size;
    _cairo_gl_composite_unmap_vertex_buffer (ctx);

    if ( _cairo_array_num_elements (&ctx->tristrip_indices) > 0) {
	_cairo_gl_composite_draw_tristrip (ctx);
    } else if (ctx->clip_region) {
	int i, num_rectangles = cairo_region_num_rectangles (ctx->clip_region);

	for (i = 0; i < num_rectangles; i++) {
	    cairo_rectangle_int_t rect;

	    cairo_region_get_rectangle (ctx->clip_region, i, &rect);

	    glScissor (rect.x, rect.y, rect.width, rect.height);
            _cairo_gl_composite_draw (ctx, count);
	}
    } else {
        _cairo_gl_composite_draw (ctx, count);
    }

    for (i = 0; i < ARRAY_LENGTH (&ctx->glyph_cache); i++)
	_cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
}
Ejemplo n.º 2
0
void
_cairo_gl_composite_flush (cairo_gl_context_t *ctx)
{
    unsigned int count;
    int i;

    if (_cairo_gl_context_is_flushed (ctx))
        return;

    count = ctx->vb_offset / ctx->vertex_size;
    _cairo_gl_composite_unmap_vertex_buffer (ctx);

    if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) {
	if (ctx->draw_mode == CAIRO_GL_LINE_STRIP ||
	    ctx->draw_mode == CAIRO_GL_LINES)
	    _cairo_gl_composite_draw_line (ctx);
	else
	    _cairo_gl_composite_draw_tristrip (ctx);
    } else {
	assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
	_cairo_gl_composite_draw_triangles_with_clip_region (ctx, count);
    }

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

    _cairo_gl_image_cache_unlock (ctx);
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
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;
}
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;
}