[PATCH] Use new pixman_glyph_cache_t API that will be in pixman 0.28.0

Søren Sandmann sandmann at cs.au.dk
Wed May 30 17:27:02 PDT 2012


From: Søren Sandmann Pedersen <ssp at redhat.com>

This new API allows glyphs to be cached in a data structure in pixman,
and entire glyph strings to be composited in one go.

Results from the cairo peformance test suite running against Xvfb with
a screen size of 1680x1050 at 32bpp:

Speedups
========
 xlib          firefox-talos-gfx  13669.42 -> 3717.03:  3.68x speedup
██▋
 xlib          xfce4-terminal-a1  1842.63 -> 1086.13:   1.70x speedup
▊
 xlib                  evolution  1401.95 -> 897.70:    1.56x speedup
▌
 xlib         gnome-terminal-vim  1859.13 -> 1192.92:   1.56x speedup
▌
 xlib                    poppler  1650.37 -> 1244.72:   1.33x speedup
▍
 xlib       firefox-planet-gnome  7300.14 -> 5751.90:   1.27x speedup
▎
 xlib                       gvim  1385.19 -> 1284.40:   1.08x speedup
▏

No slowdowns were reported.

Results of x11perf -aa10text:

Before:

    7200000 reps @   0.0007 msec (1430000.0/sec)
    7200000 reps @   0.0007 msec (1420000.0/sec)
    7200000 reps @   0.0007 msec (1420000.0/sec)
    7200000 reps @   0.0007 msec (1420000.0/sec)
    7200000 reps @   0.0007 msec (1420000.0/sec)
    36000000 trep @   0.0007 msec (1420000.0/sec)

After:

    32000000 reps @   0.0002 msec (5310000.0/sec)
    32000000 reps @   0.0002 msec (5380000.0/sec)
    32000000 reps @   0.0002 msec (5310000.0/sec)
    32000000 reps @   0.0002 msec (5400000.0/sec)
    32000000 reps @   0.0002 msec (5290000.0/sec)
    160000000 trep @   0.0002 msec (5340000.0/sec)
---
 fb/fbpict.c |  143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 142 insertions(+), 1 deletion(-)

diff --git a/fb/fbpict.c b/fb/fbpict.c
index 097a1a6..b58f476 100644
--- a/fb/fbpict.c
+++ b/fb/fbpict.c
@@ -70,6 +70,146 @@ fbComposite(CARD8 op,
     free_pixman_pict(pDst, dest);
 }
 
+static pixman_glyph_cache_t *glyphCache;
+
+static void
+fbUnrealizeGlyph(ScreenPtr pScreen,
+		 GlyphPtr pGlyph)
+{
+    if (glyphCache)
+	pixman_glyph_cache_remove (glyphCache, pGlyph, NULL);
+}
+
+static void
+fbGlyphs(CARD8 op,
+	 PicturePtr pSrc,
+	 PicturePtr pDst,
+	 PictFormatPtr maskFormat,
+	 INT16 xSrc,
+	 INT16 ySrc, int nlist,
+	 GlyphListPtr list,
+	 GlyphPtr *glyphs)
+{
+#define N_STACK_GLYPHS 512
+    ScreenPtr pScreen = pDst->pDrawable->pScreen;
+    pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
+    pixman_glyph_t *pglyphs = stack_glyphs;
+    pixman_image_t *srcImage, *dstImage;
+    int srcXoff, srcYoff, dstXoff, dstYoff;
+    GlyphPtr glyph;
+    int n_glyphs;
+    int x, y;
+    int i, n;
+    int xDst = list->xOff, yDst = list->yOff;
+
+    miCompositeSourceValidate(pSrc);
+    
+    n_glyphs = 0;
+    for (i = 0; i < nlist; ++i)
+	n_glyphs += list[i].len;
+
+    if (!glyphCache)
+	glyphCache = pixman_glyph_cache_create();
+
+    pixman_glyph_cache_freeze (glyphCache);
+    
+    if (n_glyphs > N_STACK_GLYPHS) {
+	if (!(pglyphs = malloc (n_glyphs * sizeof (pixman_glyph_t))))
+	    goto out;
+    }
+    
+    i = 0;
+    x = y = 0;
+    while (nlist--) {
+        x += list->xOff;
+        y += list->yOff;
+        n = list->len;
+        while (n--) {
+	    const void *g;
+
+            glyph = *glyphs++;
+
+	    if (!(g = pixman_glyph_cache_lookup (glyphCache, glyph, NULL))) {
+		pixman_image_t *glyphImage;
+		PicturePtr pPicture;
+		int xoff, yoff;
+
+		pPicture = GetGlyphPicture(glyph, pScreen);
+		if (!pPicture) {
+		    n_glyphs--;
+		    goto next;
+		}
+
+		if (!(glyphImage = image_from_pict(pPicture, FALSE, &xoff, &yoff)))
+		    goto out;
+
+		g = pixman_glyph_cache_insert(glyphCache, glyph, NULL,
+					      glyph->info.x,
+					      glyph->info.y,
+					      glyphImage);
+
+		free_pixman_pict(pPicture, glyphImage);
+
+		if (!g)
+		    goto out;
+	    }
+
+	    pglyphs[i].x = x;
+	    pglyphs[i].y = y;
+	    pglyphs[i].glyph = g;
+	    i++;
+
+	next:
+            x += glyph->info.xOff;
+            y += glyph->info.yOff;
+	}
+	list++;
+    }
+
+    if (!(srcImage = image_from_pict(pSrc, FALSE, &srcXoff, &srcYoff)))
+	goto out;
+
+    if (!(dstImage = image_from_pict(pDst, TRUE, &dstXoff, &dstYoff)))
+	goto out_free_src;
+
+    if (maskFormat) {
+	pixman_format_code_t format;
+	pixman_box32_t extents;
+	int x, y;
+
+	format = maskFormat->format | (maskFormat->depth << 24);
+
+	pixman_glyph_get_extents(glyphCache, n_glyphs, pglyphs, &extents);
+
+	x = extents.x1;
+	y = extents.y1;
+
+	pixman_composite_glyphs(op, srcImage, dstImage, format,
+				xSrc + srcXoff + xDst, ySrc + srcYoff + yDst,
+				x, y,
+				x + dstXoff, y + dstYoff,
+				extents.x2 - extents.x1,
+				extents.y2 - extents.y1,
+				glyphCache, n_glyphs, pglyphs);
+    }
+    else {
+	pixman_composite_glyphs_no_mask(op, srcImage, dstImage,
+					xSrc + srcXoff - xDst, ySrc + srcYoff - yDst,
+					dstXoff, dstYoff,
+					glyphCache, n_glyphs, pglyphs);
+    }
+
+    free_pixman_pict(pDst, dstImage);
+
+out_free_src:
+    free_pixman_pict(pSrc, srcImage);
+
+out:
+    pixman_glyph_cache_thaw (glyphCache);
+    if (pglyphs != stack_glyphs)
+	free (pglyphs);
+}
+
 static pixman_image_t *
 create_solid_fill_image(PicturePtr pict)
 {
@@ -357,7 +497,8 @@ fbPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
         return FALSE;
     ps = GetPictureScreen(pScreen);
     ps->Composite = fbComposite;
-    ps->Glyphs = miGlyphs;
+    ps->Glyphs = fbGlyphs;
+    ps->UnrealizeGlyph = fbUnrealizeGlyph;
     ps->CompositeRects = miCompositeRects;
     ps->RasterizeTrapezoid = fbRasterizeTrapezoid;
     ps->Trapezoids = fbTrapezoids;
-- 
1.7.10.2



More information about the xorg-devel mailing list