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

Søren Sandmann sandmann at cs.au.dk
Sat Jun 2 15:56:43 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  12416.63 -> 3603.93   3.45x speedup
██▌
 xlib          xfce4-terminal-a1   1727.57 -> 1048.85:  1.65x speedup
▋
 xlib                  evolution   1370.49 -> 869.34:   1.58x speedup
▋
 xlib         gnome-terminal-vim   1832.83 -> 1251.94:  1.46x speedup
▌
 xlib                    poppler   1519.70 -> 1204.05:  1.26x speedup
▎
 xlib       firefox-planet-gnome   6982.55 -> 5598.16:  1.25x speedup
▎
 xlib                  ocitysmap   1142.77 -> 1071.53:  1.07x speedup
▏

No slowdowns were reported.

Results of x11perf -aa10text:

Before:

      8000000 reps @   0.0007 msec (1450000.0/sec)
      8000000 reps @   0.0007 msec (1460000.0/sec)
      8000000 reps @   0.0007 msec (1460000.0/sec)
      8000000 reps @   0.0007 msec (1470000.0/sec)
      8000000 reps @   0.0007 msec (1480000.0/sec)
     40000000 trep @   0.0007 msec (1460000.0/sec)

After:

     32000000 reps @   0.0002 msec (4910000.0/sec)
     32000000 reps @   0.0002 msec (4830000.0/sec)
     32000000 reps @   0.0002 msec (4890000.0/sec)
     32000000 reps @   0.0002 msec (4830000.0/sec)
     32000000 reps @   0.0002 msec (4900000.0/sec)
    160000000 trep @   0.0002 msec (4870000.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..a70fa18 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