From 40af32a0e9ed971a1f2c2a45266f32016bda7ed3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 21 Oct 2011 20:10:02 +0100 Subject: sna: Execute blits directly for PolyRectangle By constructing the batch buffer directly for PolyRectangle, rather than via miPolyRectangle->(PolyFillRectangle/PolyLine), we dramatically reduce the CPU overhead and can saturate the GPU. Signed-off-by: Chris Wilson --- src/sna/sna_accel.c | 558 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 557 insertions(+), 1 deletion(-) diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 636544e5..11f5c21c 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -2940,6 +2940,562 @@ fallback: fbPolySegment(drawable, gc, n, seg); } +static unsigned +sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc, + int n, xRectangle *r, + BoxPtr out) +{ + BoxRec box; + int extra = gc->lineWidth >> 1; + bool clipped; + + if (n == 0) + return 0; + + box.x1 = r->x; + box.y1 = r->y; + box.x2 = r->x + r->width; + box.y2 = r->y + r->height; + + while (--n) { + r++; + if (r->x < box.x1) + box.x1 = r->x; + if (r->x + r->width > box.x2) + box.x2 = r->x + r->width; + if (r->y < box.y1) + box.y1 = r->y; + if (r->y + r->width > box.y2) + box.y2 = r->y + r->height; + } + + box.x2++; + box.y2++; + + if (extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + if (box_empty(&box)) + return 0; + + clipped = trim_and_translate_box(&box, drawable, gc); + *out = box; + return 1 | clipped << 1; +} + +static Bool +sna_poly_rectangle_blt(DrawablePtr drawable, + struct kgem_bo *bo, + struct sna_damage **damage, + GCPtr gc, int n, xRectangle *r, + const BoxRec *extents, bool clipped) +{ + struct sna *sna = to_sna_from_drawable(drawable); + PixmapPtr pixmap = get_drawable_pixmap(drawable); + struct sna_fill_op fill; + int16_t dx, dy; + static void * const jump[] = { + &&no_damage_zero, + &&maybe_damage_zero_clipped, + &&no_damage_wide, + &&maybe_damage_wide_clipped, + + &&damage_zero, + &&maybe_damage_zero_clipped, + &&damage_wide, + &&maybe_damage_wide_clipped, + }; + unsigned v; + + DBG(("%s: alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n", + __FUNCTION__, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped)); + + if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel)) + return FALSE; + + get_drawable_deltas(drawable, pixmap, &dx, &dy); + + v = !!clipped; + v |= (gc->lineWidth != 0) << 1; + v |= (damage != NULL) << 2; + goto *jump[v]; + +damage_zero: + dx += drawable->x; + dy += drawable->y; + + do { + BoxRec box; + + if (r->width <= 1 || r->height <= 1) { + box.x1 = r->x + dx; + box.y1 = r->y + dy; + box.x2 = box.x1 + r->width + 1; + box.y2 = box.y1 + r->height + 1; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + } else { + box.x1 = r->x + dx; + box.y1 = r->y + dy; + box.x2 = box.x1 + r->width + 1; + box.y2 = box.y1 + 1; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + + box.y1 += r->height; + box.y2 += r->height; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + + box.y1 = r->y + dy + 1; + box.y2 = box.y1 + r->height - 1; + box.x1 = r->x + dx; + box.x2 = box.x1 + 1; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + + box.x1 += r->width; + box.x2 += r->width; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + } + r++; + } while (--n); + goto done; + +no_damage_zero: + dx += drawable->x; + dy += drawable->y; + + do { + BoxRec box; + + if (r->width <= 1 || r->height <= 1) { + box.x1 = r->x + dx; + box.y1 = r->y + dy; + box.x2 = box.x1 + r->width + 1; + box.y2 = box.y1 + r->height + 1; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + } else { + box.x1 = r->x + dx; + box.y1 = r->y + dy; + box.x2 = box.x1 + r->width + 1; + box.y2 = box.y1 + 1; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + + box.y1 += r->height; + box.y2 += r->height; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + + box.y1 = r->y + dy + 1; + box.y2 = box.y1 + r->height - 1; + box.x1 = r->x + dx; + box.x2 = box.x1 + 1; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + + box.x1 += r->width; + box.x2 += r->width; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + box.x1, box.y1, box.x2, box.y2)); + fill.box(sna, &fill, &box); + } + r++; + } while (--n); + goto done; + +maybe_damage_zero_clipped: + { + RegionRec clip; + BoxRec box[4], *b, *c; + int count = 0, i, j; + + region_set(&clip, extents); + region_maybe_clip(&clip, gc->pCompositeClip); + + do { + if (r->width <= 1 || r->height <= 1) { + box[0].x1 = r->x + drawable->x; + box[0].y1 = r->y + drawable->y; + box[0].x2 = box[0].x1 + r->width + 1; + box[0].y2 = box[0].y1 + r->height + 1; + count = 1; + } else { + box[0].x1 = r->x + drawable->x; + box[0].y1 = r->y + drawable->y; + box[0].x2 = box[0].x1 + r->width + 1; + box[0].y2 = box[0].y1 + 1; + + box[1] = box[0]; + box[1].y1 += r->height; + box[1].y2 += r->height; + + box[2].y1 = r->y + drawable->y + 1; + box[2].y2 = box[2].y1 + r->height - 1; + box[2].x1 = r->x + drawable->x; + box[2].x2 = box[2].x1 + 1; + + box[3] = box[2]; + box[3].x1 += r->width; + box[3].x2 += r->width; + count = 4; + } + + for (i = REGION_NUM_RECTS(&clip), c = REGION_RECTS(&clip); i--; c++) { + for (j = count, b = box; j--; b++) { + BoxRec clipped = *b; + if (box_intersect(&clipped, c)) { + clipped.x1 += dx; + clipped.x2 += dx; + clipped.y1 += dy; + clipped.y2 += dy; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + clipped.x1, clipped.y1, clipped.x2, clipped.y2)); + fill.box(sna, &fill, &clipped); + if (damage) { + assert_pixmap_contains_box(pixmap, &clipped); + sna_damage_add_box(damage, &clipped); + } + } + } + } + r++; + } while (--n); + } + goto done; + +maybe_damage_wide_clipped: + { + RegionRec clip; + int16_t offset2 = gc->lineWidth; + int16_t offset1 = offset2 >> 1; + int16_t offset3 = offset2 - offset1; + + region_set(&clip, extents); + region_maybe_clip(&clip, gc->pCompositeClip); + + do { + BoxRec box[4], *c, *b; + int16_t x = r->x + drawable->x; + int16_t y = r->y + drawable->y; + int16_t width = r->width; + int16_t height = r->height; + int count, i, j; + r++; + + if (height < offset2 || width < offset1) { + if (height == 0) { + box[0].x1 = x; + box[0].x2 = x + width + 1; + } else { + box[0].x1 = x - offset1; + box[0].x2 = box[0].x1 + width + offset2; + } + if (width == 0) { + box[0].y1 = y; + box[0].y2 = y + height + 1; + } else { + box[0].y1 = y - offset1; + box[0].y2 = box[0].y1 + height + offset2; + } + count = 1; + } else { + box[0].x1 = x - offset1; + box[0].x2 = box[0].x1 + width + offset2; + box[0].y1 = y - offset1; + box[0].y2 = box[0].y1 + offset2; + + box[1].x1 = x - offset1; + box[1].x2 = box[1].x1 + offset2; + box[1].y1 = y + offset3; + box[1].y2 = y + height - offset1; + + box[2].x1 = x + width - offset1; + box[2].x2 = box[2].x1 + offset2; + box[2].y1 = y + offset3; + box[2].y2 = y + height - offset1; + + box[3] = box[1]; + box[3].y1 += height; + box[3].y2 += height; + count = 4; + } + + for (i = REGION_NUM_RECTS(&clip), c = REGION_RECTS(&clip); i--; c++) { + for (j = count, b = box; j--; b++) { + BoxRec clipped = *b; + if (box_intersect(&clipped, c)) { + clipped.x1 += dx; + clipped.x2 += dx; + clipped.y1 += dy; + clipped.y2 += dy; + DBG(("%s: blt (%d, %d), (%d, %d)\n", + __FUNCTION__, + clipped.x1, clipped.y1, clipped.x2, clipped.y2)); + fill.box(sna, &fill, &clipped); + if (damage) { + assert_pixmap_contains_box(pixmap, &clipped); + sna_damage_add_box(damage, &clipped); + } + } + } + } + } while (--n); + } + goto done; + +no_damage_wide: + { + int offset2 = gc->lineWidth; + int offset1 = offset2 >> 1; + int offset3 = offset2 - offset1; + + dx += drawable->x; + dy += drawable->y; + + do { + BoxRec box; + int16_t x = r->x + dx; + int16_t y = r->y + dy; + int16_t width = r->width; + int16_t height = r->height; + r++; + + if (height < offset2 || width < offset1) { + if (height == 0) { + box.x1 = x; + box.x2 = x + width + 1; + } else { + box.x1 = x - offset1; + box.x2 = box.x1 + width + offset2; + } + if (width == 0) { + box.y1 = y; + box.y2 = y + height + 1; + } else { + box.y1 = y - offset1; + box.y2 = box.y1 + height + offset2; + } + fill.box(sna, &fill, &box); + } else { + box.x1 = x - offset1; + box.x2 = box.x1 + width + offset2; + box.y1 = y - offset1; + box.y2 = box.y1 + offset2; + fill.box(sna, &fill, &box); + + box.x1 = x - offset1; + box.x2 = box.x1 + offset2; + box.y1 = y + offset3; + box.y2 = y + height - offset1; + fill.box(sna, &fill, &box); + + box.x1 = x + width - offset1; + box.x2 = box.x1 + offset2; + fill.box(sna, &fill, &box); + + box.x1 = x - offset1; + box.x2 = box.x1 + width + offset2; + box.y1 = y + height - offset1; + box.y2 = box.y1 + offset2; + fill.box(sna, &fill, &box); + } + + } while (--n); + } + goto done; + +damage_wide: + { + int offset2 = gc->lineWidth; + int offset1 = offset2 >> 1; + int offset3 = offset2 - offset1; + + dx += drawable->x; + dy += drawable->y; + + do { + BoxRec box; + int16_t x = r->x + dx; + int16_t y = r->y + dy; + int16_t width = r->width; + int16_t height = r->height; + r++; + + if (height < offset2 || width < offset1) { + if (height == 0) { + box.x1 = x; + box.x2 = x + width + 1; + } else { + box.x1 = x - offset1; + box.x2 = box.x1 + width + offset2; + } + if (width == 0) { + box.y1 = y; + box.y2 = y + height + 1; + } else { + box.y1 = y - offset1; + box.y2 = box.y1 + height + offset2; + } + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + } else { + box.x1 = x - offset1; + box.x2 = box.x1 + width + offset2; + box.y1 = y - offset1; + box.y2 = box.y1 + offset2; + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + + box.x1 = x - offset1; + box.x2 = box.x1 + offset2; + box.y1 = y + offset3; + box.y2 = y + height - offset1; + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + + box.x1 = x + width - offset1; + box.x2 = box.x1 + offset2; + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + + box.x1 = x - offset1; + box.x2 = box.x1 + width + offset2; + box.y1 = y + height - offset1; + box.y2 = box.y1 + offset2; + fill.box(sna, &fill, &box); + assert_pixmap_contains_box(pixmap, &box); + sna_damage_add_box(damage, &box); + } + } while (--n); + } + goto done; + +done: + fill.done(sna, &fill); + return TRUE; +} + +static void +sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r) +{ + struct sna *sna = to_sna_from_drawable(drawable); + RegionRec region; + unsigned flags; + + DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n", + __FUNCTION__, + n, r->x, r->y, r->width, r->height, + gc->lineWidth)); + + flags = sna_poly_rectangle_extents(drawable, gc, n, r, ®ion.extents); + if (flags == 0) + return; + + DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, + region.extents.x1, region.extents.y1, + region.extents.x2, region.extents.y2, + flags)); + + if (FORCE_FALLBACK) + goto fallback; + + if (wedged(sna)) { + DBG(("%s: fallback -- wedged\n", __FUNCTION__)); + goto fallback; + } + + DBG(("%s: line=%d [%d], join=%d [%d], mask=%lu [%d]\n", + __FUNCTION__, + gc->lineStyle, gc->lineStyle == LineSolid, + gc->joinStyle, gc->joinStyle == JoinMiter, + gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); + if (gc->lineStyle == LineSolid && + gc->joinStyle == JoinMiter && + PM_IS_SOLID(drawable, gc->planemask)) { + struct sna_pixmap *priv = sna_pixmap_from_drawable(drawable); + + DBG(("%s: trying blt solid fill [%08lx] paths\n", + __FUNCTION__, gc->fgPixel)); + + if (sna_drawable_use_gpu_bo(drawable, ®ion.extents) && + sna_poly_rectangle_blt(drawable, priv->gpu_bo, + priv->gpu_only ? NULL : reduce_damage(drawable, &priv->gpu_damage, ®ion.extents), + gc, n, r, ®ion.extents, flags&2)) + return; + + if (sna_drawable_use_cpu_bo(drawable, ®ion.extents) && + sna_poly_rectangle_blt(drawable, priv->cpu_bo, + reduce_damage(drawable, &priv->cpu_damage, ®ion.extents), + gc, n, r, ®ion.extents, flags&2)) + return; + } + + /* Not a trivial outline, but we still maybe able to break it + * down into simpler operations that we can accelerate. + */ + if (sna_drawable_use_gpu_bo(drawable, ®ion.extents)) { + miPolyRectangle(drawable, gc, n, r); + return; + } + +fallback: + DBG(("%s: fallback\n", __FUNCTION__)); + + region.data = NULL; + region_maybe_clip(®ion, gc->pCompositeClip); + if (!RegionNotEmpty(®ion)) + return; + + sna_gc_move_to_cpu(gc); + sna_drawable_move_region_to_cpu(drawable, ®ion, true); + RegionUninit(®ion); + + DBG(("%s: fbPolyRectangle\n", __FUNCTION__)); + fbPolyRectangle(drawable, gc, n, r); +} + static Bool sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc, int n, xArc *arc, @@ -3901,7 +4457,7 @@ static const GCOps sna_gc_ops = { sna_poly_point, sna_poly_line, sna_poly_segment, - miPolyRectangle, + sna_poly_rectangle, sna_poly_arc, miFillPolygon, sna_poly_fill_rect, -- cgit v1.2.3