[PATCH 1/1] cairo/gl MSAA -optimze text rendering

"Henry (Yu) Song - SISA" <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <3955FA337689574EB32F94B12A7E6E9E0B41D2CB@ex10mail>
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

--
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.