[Glamor] [PATCH 27/34] glamor: Improve the performance of PolyGlyphBlt.

Alex Deucher alexdeucher at gmail.com
Fri Feb 28 10:02:22 PST 2014


From: Eric Anholt <eric at anholt.net>

Using the same idea as the previous PushPixels code, just make points
for each point in the glyph. This is an advantage over the pushpixels
fallback because we can batch the BO mappings and draw calls across
glyphs.

Improves performance of x11perf -f8text by 881.481% +/- 50.5971% (n=6).

Ported from Eric's xserver glamor tree.

Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
 src/glamor_glyphblt.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)

diff --git a/src/glamor_glyphblt.c b/src/glamor_glyphblt.c
index 35be282..ca92100 100644
--- a/src/glamor_glyphblt.c
+++ b/src/glamor_glyphblt.c
@@ -27,6 +27,143 @@
  */
 
 #include "glamor_priv.h"
+#include <dixfontstr.h>
+
+static Bool
+glamor_poly_glyph_blt_pixels(DrawablePtr drawable, GCPtr gc,
+			     int x, int y, unsigned int nglyph,
+			     CharInfoPtr *ppci)
+{
+	ScreenPtr screen = drawable->pScreen;
+	glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+	PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+	glamor_pixmap_private *pixmap_priv;
+	int off_x, off_y;
+	GLfloat xscale, yscale;
+	float color[4];
+	unsigned long fg_pixel = gc->fgPixel;
+	char *vbo_offset;
+	RegionPtr clip;
+	int num_points, max_points;
+	float *points = NULL;
+	glamor_gl_dispatch *dispatch;
+
+	x += drawable->x;
+	y += drawable->y;
+
+	if (gc->fillStyle != FillSolid) {
+	    glamor_fallback("gc fillstyle not solid\n");
+	    return FALSE;
+	}
+
+	pixmap_priv = glamor_get_pixmap_private(pixmap);
+	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+	    return FALSE;
+
+	dispatch = glamor_get_dispatch(glamor_priv);
+	if (!glamor_set_alu(dispatch, gc->alu)) {
+	    if (gc->alu == GXclear)
+		fg_pixel = 0;
+	    else {
+		glamor_fallback("unsupported alu %x\n", gc->alu);
+		glamor_put_dispatch(glamor_priv);
+		return FALSE;
+	    }
+	}
+
+	if (!glamor_set_planemask(pixmap, gc->planemask)) {
+	    glamor_fallback("Failed to set planemask in %s.\n", __FUNCTION__);
+	    glamor_put_dispatch(glamor_priv);
+	    return FALSE;
+	}
+
+	glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
+
+	glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+	pixmap_priv_get_dest_scale(pixmap_priv, &xscale, &yscale);
+
+	dispatch->glUseProgram(glamor_priv->solid_prog);
+
+	glamor_get_rgba_from_pixel(fg_pixel,
+				   &color[0], &color[1], &color[2], &color[3],
+				   format_for_pixmap(pixmap));
+	dispatch->glUniform4fv(glamor_priv->solid_color_uniform_location, 1, color);
+
+	clip = fbGetCompositeClip(gc);
+
+	dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+
+	max_points = 500;
+	num_points = 0;
+	while (nglyph--) {
+	    CharInfoPtr charinfo = *ppci++;
+	    int w = GLYPHWIDTHPIXELS(charinfo);
+	    int h = GLYPHHEIGHTPIXELS(charinfo);
+	    uint8_t *glyphbits = FONTGLYPHBITS(NULL, charinfo);
+
+	    if (w && h) {
+		int glyph_x = x + charinfo->metrics.leftSideBearing;
+		int glyph_y = y - charinfo->metrics.ascent;
+		int glyph_stride = GLYPHWIDTHBYTESPADDED(charinfo);
+		int xx, yy;
+
+		for (yy = 0; yy < h; yy++) {
+		    uint8_t *glyph_row = glyphbits + glyph_stride * yy;
+		    for (xx = 0; xx < w; xx++) {
+			int pt_x_i = glyph_x + xx;
+			int pt_y_i = glyph_y + yy;
+			float pt_x_f, pt_y_f;
+			if (!(glyph_row[xx / 8] & (1 << xx % 8)))
+			    continue;
+
+			if (!RegionContainsPoint(clip, pt_x_i, pt_y_i, NULL))
+				continue;
+
+			if (!num_points) {
+			    points = glamor_get_vbo_space(screen,
+							  max_points * 2 * sizeof(float),
+							  &vbo_offset);
+
+			    dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+							    GL_FALSE, 2 * sizeof(float),
+							    vbo_offset);
+			}
+
+			pt_x_f = v_from_x_coord_x(xscale, pt_x_i + off_x + 0.5);
+			if (glamor_priv->yInverted)
+			    pt_y_f = v_from_x_coord_y_inverted(yscale, pt_y_i + off_y + 0.5);
+			else
+			    pt_y_f = v_from_x_coord_y(yscale, pt_y_i + off_y + 0.5);
+
+			points[num_points * 2 + 0] = pt_x_f;
+			points[num_points * 2 + 1] = pt_y_f;
+			num_points++;
+
+			if (num_points == max_points) {
+			    glamor_put_vbo_space(screen);
+			    dispatch->glDrawArrays(GL_POINTS, 0, num_points);
+			    num_points = 0;
+			}
+		    }
+		}
+	    }
+
+	    x += charinfo->metrics.characterWidth;
+	}
+
+	if (num_points) {
+	    glamor_put_vbo_space(screen);
+	    dispatch->glDrawArrays(GL_POINTS, 0, num_points);
+	}
+
+	dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+	dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+	dispatch->glUseProgram(0);
+
+	glamor_put_dispatch(glamor_priv);
+
+	return TRUE;
+}
 
 static Bool
 _glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
@@ -63,6 +200,9 @@ _glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
                     int x, int y, unsigned int nglyph,
                     CharInfoPtr * ppci, pointer pglyphBase, Bool fallback)
 {
+	if (glamor_poly_glyph_blt_pixels(pDrawable, pGC, x, y, nglyph, ppci))
+		return TRUE;
+
 	if (!fallback
 	    && glamor_ddx_fallback_check_pixmap(pDrawable)
 	    && glamor_ddx_fallback_check_gc(pGC))
-- 
1.8.3.1



More information about the Glamor mailing list