summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-01-10 23:32:29 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2012-01-10 23:39:33 +0000
commit3cf5da1090ac777044912ec24619d349d1f6b521 (patch)
tree9e6de1b0c9ea21a113212debcbf4a3f5aa0f4bde
parentf0e3f6b5bebf7471d3e3e84bd9b2d8469eb64093 (diff)
sna: Amalgamate small replacements into upload buffers
Similar for the standard io paths, try to reuse an upload buffer for a small replacement pixmap. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/sna_io.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/sna/sna_io.c b/src/sna/sna_io.c
index 50fae258..3c17d3aa 100644
--- a/src/sna/sna_io.c
+++ b/src/sna/sna_io.c
@@ -777,6 +777,107 @@ fallback:
sna->blt_state.fill_bo = 0;
}
+static bool
+indirect_replace(struct sna *sna,
+ PixmapPtr pixmap,
+ struct kgem_bo *bo,
+ const void *src, int stride)
+{
+ struct kgem *kgem = &sna->kgem;
+ struct kgem_bo *src_bo;
+ void *ptr;
+ bool ret;
+
+ if (pixmap->devKind * pixmap->drawable.height >> 12 > kgem->half_cpu_cache_pages)
+ return false;
+
+ if (bo->tiling == I915_TILING_Y || kgem->ring == KGEM_RENDER) {
+ BoxRec box;
+
+ src_bo = kgem_create_buffer_2d(kgem,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ pixmap->drawable.bitsPerPixel,
+ KGEM_BUFFER_WRITE,
+ &ptr);
+ if (!src_bo)
+ return false;
+
+ memcpy_blt(src, ptr, pixmap->drawable.bitsPerPixel,
+ stride, src_bo->pitch,
+ 0, 0,
+ 0, 0,
+ pixmap->drawable.width,
+ pixmap->drawable.height);
+
+ box.x1 = box.y1 = 0;
+ box.x2 = pixmap->drawable.width;
+ box.y2 = pixmap->drawable.height;
+
+ ret = sna->render.copy_boxes(sna, GXcopy,
+ pixmap, src_bo, 0, 0,
+ pixmap, bo, 0, 0,
+ &box, 1);
+ } else {
+ uint32_t cmd, br13, *b;
+
+ src_bo = kgem_create_buffer(kgem,
+ stride * pixmap->drawable.height,
+ KGEM_BUFFER_WRITE,
+ &ptr);
+ if (!src_bo)
+ return false;
+
+ cmd = XY_SRC_COPY_BLT_CMD;
+ br13 = bo->pitch;
+ if (kgem->gen >= 40 && bo->tiling) {
+ cmd |= BLT_DST_TILED;
+ br13 >>= 2;
+ }
+ br13 |= 0xcc << 16;
+ switch (pixmap->drawable.bitsPerPixel) {
+ default:
+ case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
+ br13 |= 1 << 25; /* RGB8888 */
+ case 16: br13 |= 1 << 24; /* RGB565 */
+ case 8: break;
+ }
+
+ kgem_set_mode(kgem, KGEM_BLT);
+ if (kgem->nexec + 2 > KGEM_EXEC_SIZE(kgem) ||
+ kgem->nreloc + 2 > KGEM_RELOC_SIZE(kgem) ||
+ !kgem_check_batch(kgem, 8) ||
+ !kgem_check_bo_fenced(kgem, bo, NULL)) {
+ _kgem_submit(kgem);
+ _kgem_set_mode(kgem, KGEM_BLT);
+ }
+
+ memcpy(ptr, src, stride * pixmap->drawable.height);
+
+ b = kgem->batch + kgem->nbatch;
+ b[0] = cmd;
+ b[1] = br13;
+ b[2] = 0;
+ b[3] = pixmap->drawable.height << 16 | pixmap->drawable.width;
+ b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, bo,
+ I915_GEM_DOMAIN_RENDER << 16 |
+ I915_GEM_DOMAIN_RENDER |
+ KGEM_RELOC_FENCED,
+ 0);
+ b[5] = 0;
+ b[6] = stride;
+ b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
+ I915_GEM_DOMAIN_RENDER << 16 |
+ KGEM_RELOC_FENCED,
+ 0);
+ kgem->nbatch += 8;
+ ret = true;
+ }
+
+ kgem_bo_destroy(kgem, src_bo);
+ return ret;
+}
+
struct kgem_bo *sna_replace(struct sna *sna,
PixmapPtr pixmap,
struct kgem_bo *bo,
@@ -792,6 +893,9 @@ struct kgem_bo *sna_replace(struct sna *sna,
pixmap->drawable.bitsPerPixel,
bo->tiling));
+ if (indirect_replace(sna, pixmap, bo, src, stride))
+ return bo;
+
if (kgem_bo_is_busy(bo)) {
struct kgem_bo *new_bo;