[PATCH 22/27] glamor: Improve the performance of PolyGlyphBlt.
Markus Wick
markus at selfnet.de
Wed Mar 12 13:55:01 PDT 2014
Are we able to add cached textures to CharInfoPtr? If not, then this
would be the ideal use case for texture_arrays ;)
Again, using GL_POINTS and check for every bit on CPU isn't the way to
go.
Am 2014-03-11 22:30, schrieb Eric Anholt:
> 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 773.389% +/- 3.50754%
> (n=10).
>
> Signed-off-by: Eric Anholt <eric at anholt.net>
> ---
> glamor/glamor_glyphblt.c | 138
> +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 138 insertions(+)
>
> diff --git a/glamor/glamor_glyphblt.c b/glamor/glamor_glyphblt.c
> index 0a99a95..5d785a0 100644
> --- a/glamor/glamor_glyphblt.c
> +++ b/glamor/glamor_glyphblt.c
> @@ -27,6 +27,141 @@
> */
>
> #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;
> +
> + 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;
> +
> + glamor_get_context(glamor_priv);
> + if (!glamor_set_alu(screen, gc->alu)) {
> + if (gc->alu == GXclear)
> + fg_pixel = 0;
> + else {
> + glamor_fallback("unsupported alu %x\n", gc->alu);
> + glamor_put_context(glamor_priv);
> + return FALSE;
> + }
> + }
> +
> + if (!glamor_set_planemask(pixmap, gc->planemask)) {
> + glamor_fallback("Failed to set planemask in %s.\n",
> __FUNCTION__);
> + glamor_put_context(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);
> +
> + glUseProgram(glamor_priv->solid_prog);
> +
> + glamor_get_rgba_from_pixel(fg_pixel,
> + &color[0], &color[1], &color[2],
> &color[3],
> + format_for_pixmap(pixmap));
> + glUniform4fv(glamor_priv->solid_color_uniform_location, 1, color);
> +
> + clip = fbGetCompositeClip(gc);
> +
> + 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);
> +
> + 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);
> + glDrawArrays(GL_POINTS, 0, num_points);
> + num_points = 0;
> + }
> + }
> + }
> + }
> +
> + x += charinfo->metrics.characterWidth;
> + }
> +
> + if (num_points) {
> + glamor_put_vbo_space(screen);
> + glDrawArrays(GL_POINTS, 0, num_points);
> + }
> +
> + glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
> + glUseProgram(0);
> +
> + glamor_put_context(glamor_priv);
> +
> + return TRUE;
> +}
>
> static Bool
> _glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
> @@ -64,6 +199,9 @@ _glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr
> pGC,
> int x, int y, unsigned int nglyph,
> CharInfoPtr *ppci, void *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))
> return FALSE;
More information about the xorg-devel
mailing list