[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