glamor: Improve the performance of PushPixels by, well, pushing pixels.
authorEric Anholt <eric@anholt.net>
Sun, 5 Jan 2014 13:54:48 +0000 (21:54 +0800)
committerEric Anholt <eric@anholt.net>
Mon, 17 Mar 2014 21:30:56 +0000 (14:30 -0700)
Otherwise, mi will fall back to GetSpans()ing the bitmap, walking the
bitmap, computing spans to be filled, and calling FillSpans().

Improves x11perf -f8text by 759.373% +/- 3.33096% (n=166)

Signed-off-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Markus Wick <markus@selfnet.de>
glamor/glamor_glyphblt.c

index 6f754ce..0a99a95 100644 (file)
@@ -91,15 +91,130 @@ glamor_poly_glyph_blt_nf(DrawablePtr pDrawable, GCPtr pGC,
 }
 
 static Bool
+glamor_push_pixels_points(GCPtr gc, PixmapPtr bitmap,
+                          DrawablePtr drawable, int w, int h, int x, int y)
+{
+    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;
+    uint8_t *bitmap_data = bitmap->devPrivate.ptr;
+    int bitmap_stride = bitmap->devKind;
+    int off_x, off_y;
+    int yy, xx;
+    GLfloat xscale, yscale;
+    float color[4];
+    unsigned long fg_pixel = gc->fgPixel;
+    float *points, *next_point;
+    int num_points = 0;
+    char *vbo_offset;
+    RegionPtr clip;
+
+    if (w * h > MAXINT / (2 * sizeof(float)))
+        return FALSE;
+
+    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);
+
+    points = glamor_get_vbo_space(screen, w * h * sizeof(float) * 2,
+                                  &vbo_offset);
+    next_point = points;
+
+    clip = fbGetCompositeClip(gc);
+
+    /* Note that because fb sets miTranslate in the GC, our incoming X
+     * and Y are in screen coordinate space (same for spans, but not
+     * other operations).
+     */
+    for (yy = 0; yy < h; yy++) {
+        uint8_t *bitmap_row = bitmap_data + yy * bitmap_stride;
+        for (xx = 0; xx < w; xx++) {
+            if (bitmap_row[xx / 8] & (1 << xx % 8) &&
+                RegionContainsPoint(clip,
+                                    x + xx,
+                                    y + yy,
+                                    NULL)) {
+                next_point[0] = v_from_x_coord_x(xscale, x + xx + off_x + 0.5);
+                if (glamor_priv->yInverted)
+                    next_point[1] = v_from_x_coord_y_inverted(yscale, y + yy + off_y + 0.5);
+                else
+                    next_point[1] = v_from_x_coord_y(yscale, y + yy + off_y + 0.5);
+
+                next_point += 2;
+                num_points++;
+            }
+        }
+    }
+    glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+                          GL_FALSE, 2 * sizeof(float),
+                          vbo_offset);
+    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+
+    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_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
                     DrawablePtr pDrawable, int w, int h, int x, int y,
                     Bool fallback)
 {
+    glamor_pixmap_private *pixmap_priv;
+
     if (!fallback && glamor_ddx_fallback_check_pixmap(pDrawable)
         && glamor_ddx_fallback_check_pixmap(&pBitmap->drawable)
         && glamor_ddx_fallback_check_gc(pGC))
         return FALSE;
 
+    pixmap_priv = glamor_get_pixmap_private(pBitmap);
+    if (pixmap_priv->type == GLAMOR_MEMORY) {
+        if (glamor_push_pixels_points(pGC, pBitmap, pDrawable, w, h, x, y))
+            return TRUE;
+    }
+
     miPushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
     return TRUE;
 }