diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-01-22 12:41:31 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-01-22 14:10:24 +0000 |
commit | 92badc9c9c2636284af8bc56b098d24ff222f167 (patch) | |
tree | 4420a0841dc91eb5fd7327a11d2a7d77eec42cbe | |
parent | 67a166d1247a1197fc851308c33c4970868f6a21 (diff) |
sna: Avoid a common readback after clearing
It is surprisingly common for a pixmap to be created, cleared and then
used as an upload target or, even worse, as a source for a ShmGetImage.
In order to prevent this folly, we can trivially track when we clear an
entire pixmap and its GPU bo and avoid the readback in such cases.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/sna.h | 2 | ||||
-rw-r--r-- | src/sna/sna_accel.c | 140 | ||||
-rw-r--r-- | src/sna/sna_composite.c | 13 |
3 files changed, 151 insertions, 4 deletions
diff --git a/src/sna/sna.h b/src/sna/sna.h index 0c0cb397..38ae404f 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -137,12 +137,14 @@ struct sna_pixmap { struct list inactive; uint32_t stride; + uint32_t clear_color; #define SOURCE_BIAS 4 uint16_t source_count; uint8_t pinned :1; uint8_t mapped :1; uint8_t flush :1; + uint8_t clear :1; uint8_t undamaged :1; uint8_t gpu :1; uint8_t header :1; diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 1e9ee166..f9b3a48c 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -798,6 +798,7 @@ _sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags) if ((flags & MOVE_READ) == 0) { assert(flags & MOVE_WRITE); sna_damage_destroy(&priv->gpu_damage); + priv->clear = false; if (priv->gpu && pixmap_inplace(sna, pixmap, priv)) { DBG(("%s: write inplace\n", __FUNCTION__)); @@ -882,6 +883,7 @@ skip_inplace_map: sna_damage_all(&priv->gpu_damage, pixmap->drawable.width, pixmap->drawable.height); + priv->clear = false; return true; } @@ -897,6 +899,28 @@ skip_inplace_map: !sna_pixmap_alloc_cpu(sna, pixmap, priv, priv->gpu_damage != NULL)) return false; + if (priv->clear) { + DBG(("%s: applying clear [%08x]\n", + __FUNCTION__, priv->clear_color)); + + if (priv->cpu_bo) { + DBG(("%s: syncing CPU bo\n", __FUNCTION__)); + kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); + } + + pixman_fill(pixmap->devPrivate.ptr, + pixmap->devKind/sizeof(uint32_t), + pixmap->drawable.bitsPerPixel, + 0, 0, + pixmap->drawable.width, + pixmap->drawable.height, + priv->clear_color); + + sna_damage_destroy(&priv->gpu_damage); + priv->undamaged = true; + priv->clear = false; + } + if (priv->gpu_damage) { BoxPtr box; int n; @@ -1082,6 +1106,9 @@ sna_drawable_move_region_to_cpu(DrawablePtr drawable, if (DAMAGE_IS_ALL(priv->cpu_damage)) goto out; + if (priv->clear) + return _sna_pixmap_move_to_cpu(pixmap, flags); + if (priv->gpu_bo == NULL && !priv->gpu && flags & MOVE_WRITE) return _sna_pixmap_move_to_cpu(pixmap, flags); @@ -1575,6 +1602,7 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, BoxPtr box) done: if (!priv->pinned) list_move(&priv->inactive, &sna->active_pixmaps); + priv->clear = false; return true; } @@ -2008,6 +2036,7 @@ done: active: if (!priv->pinned) list_move(&priv->inactive, &sna->active_pixmaps); + priv->clear = false; return priv; } @@ -2341,6 +2370,7 @@ sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, } } + priv->clear = false; return true; } @@ -2373,6 +2403,7 @@ sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, sna_damage_add(&priv->gpu_damage, region); } + priv->clear = false; return true; } } else { @@ -2436,6 +2467,7 @@ sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, } if (priv->flush) list_move(&priv->list, &sna->dirty_pixmaps); + priv->clear = false; } blt: @@ -2969,7 +3001,7 @@ fallback: alu, -1, bpp, reverse, upsidedown); box++; - }while (--n); + } while (--n); } } } @@ -3097,7 +3129,62 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, goto fallback; } - if (src_priv && + if (src_priv && src_priv->clear) { + DBG(("%s: applying src clear[%08x] to dst\n", + __FUNCTION__, src_priv->clear_color)); + RegionTranslate(®ion, dst_dx, dst_dy); + if (n == 1) { + if (!sna->render.fill_one(sna, + dst_pixmap, + dst_priv->gpu_bo, + src_priv->clear_color, + box->x1, box->y1, + box->x2, box->y2, + alu)) { + DBG(("%s: unsupported fill\n", + __FUNCTION__)); + goto fallback; + } + } else { + struct sna_fill_op fill; + + if (!sna_fill_init_blt(&fill, sna, + dst_pixmap, dst_priv->gpu_bo, + alu, src_priv->clear_color)) { + DBG(("%s: unsupported fill\n", + __FUNCTION__)); + goto fallback; + } + + fill.boxes(sna, &fill, box, n); + fill.done(sna, &fill); + } + + if (!DAMAGE_IS_ALL(dst_priv->gpu_damage)) { + if (replaces) { + sna_damage_destroy(&dst_priv->cpu_damage); + sna_damage_all(&dst_priv->gpu_damage, + dst_pixmap->drawable.width, + dst_pixmap->drawable.height); + list_del(&dst_priv->list); + dst_priv->undamaged = false; + + dst_priv->clear = true; + dst_priv->clear_color = src_priv->clear_color; + } else { + assert_pixmap_contains_box(dst_pixmap, + RegionExtents(®ion)); + sna_damage_add(&dst_priv->gpu_damage, ®ion); + } + RegionTranslate(®ion, -dst_dx, -dst_dy); + } + + if (replaces) { + DBG(("%s: mark dst as clear\n", __FUNCTION__)); + dst_priv->clear = true; + dst_priv->clear_color = src_priv->clear_color; + } + } else if (src_priv && move_to_gpu(src_pixmap, src_priv, ®ion.extents, alu) && sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ)) { if (!sna->render.copy_boxes(sna, alu, @@ -3261,11 +3348,43 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, } } } + + goto out; + } + +fallback: + if (alu == GXcopy && src_priv && src_priv->clear) { + DBG(("%s: copying clear [%08x]\n", + __FUNCTION__, src_priv->clear_color)); + + RegionTranslate(®ion, dst_dx, dst_dy); + box = REGION_RECTS(®ion); + n = REGION_NUM_RECTS(®ion); + + if (dst_priv) { + assert_pixmap_contains_box(dst_pixmap, + RegionExtents(®ion)); + + if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, + ®ion, + MOVE_WRITE | MOVE_INPLACE_HINT)) + goto out; + } + + do { + pixman_fill(dst_pixmap->devPrivate.ptr, + dst_pixmap->devKind/sizeof(uint32_t), + dst_pixmap->drawable.bitsPerPixel, + box->x1, box->y1, + box->x2 - box->x1, + box->y2 - box->y1, + src_priv->clear_color); + box++; + } while (--n); } else { FbBits *dst_bits, *src_bits; int dst_stride, src_stride; -fallback: DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n", __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy)); if (src_priv) { @@ -3351,9 +3470,10 @@ fallback: alu, -1, bpp, reverse, upsidedown); box++; - }while (--n); + } while (--n); } } + out: RegionUninit(®ion); } @@ -7219,6 +7339,18 @@ sna_poly_fill_rect_blt(DrawablePtr drawable, } else sna_damage_add_box(damage, &r); } + + if ((gc->alu == GXcopy || gc->alu == GXclear) && + r.x2 - r.x1 == pixmap->drawable.width && + r.y2 - r.y1 == pixmap->drawable.height) { + struct sna_pixmap *priv = sna_pixmap(pixmap); + + priv->clear = true; + priv->clear_color = gc->alu == GXcopy ? pixel : 0; + + DBG(("%s: pixmap=%ld, marking clear [%08x]\n", + __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color)); + } } else success = false; } diff --git a/src/sna/sna_composite.c b/src/sna/sna_composite.c index 47eac636..6fb2d275 100644 --- a/src/sna/sna_composite.c +++ b/src/sna/sna_composite.c @@ -778,6 +778,19 @@ sna_composite_rectangles(CARD8 op, sna_damage_all(&priv->gpu_damage, pixmap->drawable.width, pixmap->drawable.height); priv->undamaged = false; + if (op <= PictOpSrc) { + priv->clear = true; + priv->clear_color = 0; + if (op == PictOpSrc) + sna_get_pixel_from_rgba(&priv->clear_color, + color->red, + color->green, + color->blue, + color->alpha, + dst->format); + DBG(("%s: marking clear [%08x]\n", + __FUNCTION__, priv->clear_color)); + } } else sna_damage_add(&priv->gpu_damage, ®ion); } |