[cairo] [PATCH 1/1] cairo/gl MSAA -optimze text rendering
Henry (Yu) Song - SISA
hsong at sisa.samsung.com
Fri Nov 11 07:38:14 PST 2011
Instead of rendering one glyph at a time when initially caching
them, cache as many as possible and then render. This results in
a modest speedup and should be even more noticeable on slow
GPUs.
This patch works on top of the following patch
http://lists.cairographics.org/archives/cairo/2011-November/022451.html
---
src/cairo-gl-glyphs.c | 160 +++++++++++++++++++++++++++++++++++--------------
1 files changed, 114 insertions(+), 46 deletions(-)
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 2324922..cdba3fa 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -213,6 +213,71 @@ _cairo_gl_font_fini (cairo_scaled_font_private_t *_priv,
free (priv);
}
+typedef struct {
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_gl_glyph_t *glyph;
+ int info_offset;
+} renderable_glyph_info_t;
+
+static void
+render_cached_glyphs (cairo_gl_context_t *ctx,
+ cairo_composite_glyphs_info_t *info,
+ cairo_gl_composite_t setup,
+ cairo_array_t *glyphs_to_render)
+{
+ int n_glyphs = _cairo_array_num_elements (glyphs_to_render);
+ int i;
+ renderable_glyph_info_t *glyphs = _cairo_array_index (glyphs_to_render, 0);
+
+ for (i = 0; i < n_glyphs; i++) {
+ double x_offset, y_offset, x1, y1, x2, y2;
+ cairo_scaled_glyph_t *scaled_glyph = glyphs[i].scaled_glyph;
+ cairo_gl_glyph_t *glyph = glyphs[i].glyph;
+ int info_offset = glyphs[i].info_offset;
+
+ x_offset = scaled_glyph->surface->base.device_transform.x0;
+ y_offset = scaled_glyph->surface->base.device_transform.y0;
+
+ x1 = _cairo_lround (info->glyphs[info_offset].x - x_offset);
+ y1 = _cairo_lround (info->glyphs[info_offset].y - y_offset);
+ x2 = x1 + scaled_glyph->surface->width;
+ y2 = y1 + scaled_glyph->surface->height;
+
+ _cairo_gl_composite_emit_glyph (ctx,
+ x1, y1, x2, y2,
+ glyph->p1.x, glyph->p1.y,
+ glyph->p2.x, glyph->p2.y);
+ }
+
+ _cairo_array_truncate (glyphs_to_render, 0);
+}
+
+static cairo_status_t
+setup_glyph_cache_and_begin_composite (cairo_gl_context_t *ctx,
+ cairo_gl_composite_t *setup,
+ cairo_composite_glyphs_info_t *info,
+ cairo_scaled_glyph_t *scaled_glyph,
+ cairo_gl_glyph_cache_t **cache)
+{
+ cairo_int_status_t status;
+
+ status = cairo_gl_context_get_glyph_cache (ctx,
+ scaled_glyph->surface->format,
+ cache);
+
+ if (unlikely (_cairo_int_status_is_error (status)))
+ return status;
+
+ status = _cairo_gl_composite_set_mask (setup,
+ &(*cache)->pattern.base,
+ 0, 0, 0, 0, 0, 0);
+ if (unlikely (_cairo_int_status_is_error (status)))
+ return status;
+
+ status = _cairo_gl_composite_begin (setup, &ctx);
+ return status;
+}
+
static cairo_status_t
render_glyphs (cairo_gl_surface_t *dst,
int dst_x, int dst_y,
@@ -229,15 +294,21 @@ render_glyphs (cairo_gl_surface_t *dst,
cairo_int_status_t status;
int i = 0;
+ cairo_array_t glyphs_to_render;
+
*has_component_alpha = FALSE;
+ /* FIXME: The caches are stored as properties of the context, but we need
+ to read the cache before we can call _cairo_gl_composite_begin,
+ which also acquires the device context. We end up acquiring it twice
+ to work around this. */
status = _cairo_gl_context_acquire (dst->base.device, &ctx);
- if (unlikely (status))
- return status;
+ if (unlikely (_cairo_int_status_is_error (status)))
+ return status;
status = _cairo_gl_composite_init (&setup, op, dst, TRUE, &info->extents);
if (unlikely (status))
- goto FINISH;
+ goto finish;
if (source_pattern) {
status = _cairo_gl_composite_set_source (&setup,
@@ -248,7 +319,7 @@ render_glyphs (cairo_gl_surface_t *dst,
info->extents.width,
info->extents.height);
if (unlikely (status))
- goto FINISH;
+ goto finish;
} else {
_cairo_gl_composite_set_source_operand (&setup,
&((cairo_gl_source_t *) source_surface)->operand);
@@ -256,49 +327,44 @@ render_glyphs (cairo_gl_surface_t *dst,
//_cairo_gl_composite_set_clip_region (&setup, _cairo_clip_get_region (extents->clip));
+ _cairo_array_init (&glyphs_to_render, sizeof (renderable_glyph_info_t));
+
for (i = 0; i < info->num_glyphs; i++) {
+ renderable_glyph_info_t item;
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 (unlikely (_cairo_int_status_is_error (status)))
+ return status;
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;
+ /* If we need to change the operands in the middle of run,
+ then first render all glyphs we've cached so far and then continue. */
+ if (i != 0) {
+ render_cached_glyphs (ctx, info, setup, &glyphs_to_render);
+ _cairo_gl_composite_flush (ctx);
+ status = _cairo_gl_context_release (ctx, status);
+ ctx = NULL;
+ if (unlikely (_cairo_int_status_is_error (status)))
+ goto finish;
+ }
last_format = scaled_glyph->surface->format;
-
- status = _cairo_gl_composite_set_mask (&setup,
- &cache->pattern.base,
- 0, 0, 0, 0, 0, 0);
- if (unlikely (status))
- goto FINISH;
+ setup_glyph_cache_and_begin_composite (ctx, &setup, info,
+ scaled_glyph, &cache);
+ if (unlikely (_cairo_int_status_is_error (status)))
+ goto finish;
*has_component_alpha |= cache->pattern.base.has_component_alpha;
-
- /* XXX: _cairo_gl_composite_begin() acquires the context a
- * second time. Need to refactor this loop so this doesn't happen.
- */
- 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) {
@@ -314,34 +380,36 @@ render_glyphs (cairo_gl_surface_t *dst,
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);
+ /* If the cache is full in the middle of run, then first flush
+ * all glyphs we've cached so far and then continue. */
+ if (i != 0) {
+ render_cached_glyphs (ctx, info, setup, &glyphs_to_render);
+ _cairo_gl_composite_flush (ctx);
+ }
+
+ /* Now try adding the glyph to cache, allowing replacements. */
_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;
+ goto finish;
}
}
- x_offset = scaled_glyph->surface->base.device_transform.x0;
- y_offset = scaled_glyph->surface->base.device_transform.y0;
+ item.scaled_glyph = scaled_glyph;
+ item.glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
+ item.info_offset = i;
+ status = _cairo_array_append (&glyphs_to_render, &item);
+ }
- x1 = _cairo_lround (info->glyphs[i].x - x_offset);
- y1 = _cairo_lround (info->glyphs[i].y - y_offset);
- x2 = x1 + scaled_glyph->surface->width;
- y2 = y1 + scaled_glyph->surface->height;
+ render_cached_glyphs (ctx, info, setup, &glyphs_to_render);
- 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);
- }
+finish:
+ _cairo_array_fini (&glyphs_to_render);
- status = CAIRO_STATUS_SUCCESS;
- FINISH:
+ /* FIXME: See above. */
+ status = _cairo_gl_context_release (ctx, status);
status = _cairo_gl_context_release (ctx, status);
_cairo_gl_composite_fini (&setup);
--
1.7.5.4
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cairographics.org/archives/cairo/attachments/20111111/d83e58f5/attachment-0001.htm>
More information about the cairo
mailing list