summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-12-10 13:14:45 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2011-12-10 13:18:44 +0000
commitb5a6bc9e33a2797c926969e1f98b4a9a796248c5 (patch)
treeffdc20ca972a1c78cfc0d88ba4bdb88f5a23f9bd
parentc0dab7b1cf17fe751c86ad2b3fabce682eb50366 (diff)
sna/gen[23]: Fixup render targets with pitches below hw minimum
gen2/3 have a restriction that the 3D pipeline cannot render to a pixmap with a pitch less than 8/16 respectively. Rather than mandating all pixmaps to be created with a stride greater than 16, fixup the bo for the rare occasions when it is necessary. Reported-by: Paul Neumann <paul104x@yahoo.de> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=43688 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/gen2_render.c23
-rw-r--r--src/sna/gen3_render.c24
-rw-r--r--src/sna/kgem.c82
-rw-r--r--src/sna/kgem.h8
4 files changed, 131 insertions, 6 deletions
diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c
index d35f2da5..cd2dcf42 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -1186,7 +1186,8 @@ gen2_composite_picture(struct sna *sna,
}
static Bool
-gen2_composite_set_target(struct sna_composite_op *op,
+gen2_composite_set_target(struct sna *sna,
+ struct sna_composite_op *op,
PicturePtr dst)
{
struct sna_pixmap *priv;
@@ -1200,6 +1201,22 @@ gen2_composite_set_target(struct sna_composite_op *op,
if (priv == NULL)
return FALSE;
+ if (priv->gpu_bo->pitch < 8) {
+ struct kgem_bo *bo;
+
+ if (priv->pinned)
+ return FALSE;
+
+ bo = kgem_replace_bo(&sna->kgem, priv->gpu_bo,
+ op->dst.width, op->dst.height, 16,
+ op->dst.pixmap->drawable.bitsPerPixel);
+ if (bo == NULL)
+ return FALSE;
+
+ kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
+ priv->gpu_bo = bo;
+ }
+
op->dst.bo = priv->gpu_bo;
op->damage = &priv->gpu_damage;
if (sna_damage_is_all(&priv->gpu_damage, op->dst.width, op->dst.height))
@@ -1396,7 +1413,7 @@ gen2_render_composite(struct sna *sna,
width, height,
tmp);
- if (!gen2_composite_set_target(tmp, dst)) {
+ if (!gen2_composite_set_target(sna, tmp, dst)) {
DBG(("%s: unable to set render target\n",
__FUNCTION__));
return FALSE;
@@ -1822,7 +1839,7 @@ gen2_render_composite_spans(struct sna *sna,
if (need_tiling(sna, width, height))
return FALSE;
- if (!gen2_composite_set_target(&tmp->base, dst)) {
+ if (!gen2_composite_set_target(sna, &tmp->base, dst)) {
DBG(("%s: unable to set render target\n",
__FUNCTION__));
return FALSE;
diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c
index ea9d40ab..33bdfd24 100644
--- a/src/sna/gen3_render.c
+++ b/src/sna/gen3_render.c
@@ -2175,7 +2175,9 @@ gen3_align_vertex(struct sna *sna,
}
static Bool
-gen3_composite_set_target(struct sna_composite_op *op, PicturePtr dst)
+gen3_composite_set_target(struct sna *sna,
+ struct sna_composite_op *op,
+ PicturePtr dst)
{
struct sna_pixmap *priv;
@@ -2189,6 +2191,22 @@ gen3_composite_set_target(struct sna_composite_op *op, PicturePtr dst)
if (priv == NULL)
return FALSE;
+ if (priv->gpu_bo->pitch < 16) {
+ struct kgem_bo *bo;
+
+ if (priv->pinned)
+ return FALSE;
+
+ bo = kgem_replace_bo(&sna->kgem, priv->gpu_bo,
+ op->dst.width, op->dst.height, 16,
+ op->dst.pixmap->drawable.bitsPerPixel);
+ if (bo == NULL)
+ return FALSE;
+
+ kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
+ priv->gpu_bo = bo;
+ }
+
op->dst.bo = priv->gpu_bo;
op->damage = &priv->gpu_damage;
if (sna_damage_is_all(op->damage, op->dst.width, op->dst.height))
@@ -2380,7 +2398,7 @@ gen3_render_composite(struct sna *sna,
memset(&tmp->u.gen3, 0, sizeof(tmp->u.gen3));
- if (!gen3_composite_set_target(tmp, dst)) {
+ if (!gen3_composite_set_target(sna, tmp, dst)) {
DBG(("%s: unable to set render target\n",
__FUNCTION__));
return FALSE;
@@ -2913,7 +2931,7 @@ gen3_render_composite_spans(struct sna *sna,
if (need_tiling(sna, width, height))
return FALSE;
- if (!gen3_composite_set_target(&tmp->base, dst)) {
+ if (!gen3_composite_set_target(sna, &tmp->base, dst)) {
DBG(("%s: unable to set render target\n",
__FUNCTION__));
return FALSE;
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 1c9da8ec..34ce7459 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -2356,3 +2356,85 @@ void kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset)
bo->binding.next = b;
}
}
+
+struct kgem_bo *
+kgem_replace_bo(struct kgem *kgem,
+ struct kgem_bo *src,
+ uint32_t width,
+ uint32_t height,
+ uint32_t pitch,
+ uint32_t bpp)
+{
+ struct kgem_bo *dst;
+ uint32_t br00, br13;
+ uint32_t handle;
+ uint32_t size;
+ uint32_t *b;
+
+ DBG(("%s: replacing bo handle=%d, size=%dx%d pitch=%d, with pitch=%d\n",
+ __FUNCTION__, src->handle, width, height, src->pitch, pitch));
+
+ /* We only expect to be called to fixup small buffers, hence why
+ * we only attempt to allocate a linear bo.
+ */
+ assert(src->tiling == I915_TILING_NONE);
+
+ size = height * pitch;
+
+ dst = search_linear_cache(kgem, size, true);
+ if (dst == NULL)
+ dst = search_linear_cache(kgem, size, false);
+ if (dst == NULL) {
+ handle = gem_create(kgem->fd, size);
+ if (handle == 0)
+ return NULL;
+
+ dst = __kgem_bo_alloc(handle, size);
+ }
+ dst->pitch = pitch;
+
+ kgem_set_mode(kgem, KGEM_BLT);
+ if (!kgem_check_batch(kgem, 8) ||
+ !kgem_check_reloc(kgem, 2) ||
+ !kgem_check_bo_fenced(kgem, src, dst, NULL)) {
+ _kgem_submit(kgem);
+ _kgem_set_mode(kgem, KGEM_BLT);
+ }
+
+ br00 = XY_SRC_COPY_BLT_CMD;
+ br13 = pitch;
+ pitch = src->pitch;
+ if (kgem->gen >= 40 && src->tiling) {
+ br00 |= BLT_SRC_TILED;
+ pitch >>= 2;
+ }
+
+ br13 |= 0xcc << 16;
+ switch (bpp) {
+ default:
+ case 32: br00 |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
+ br13 |= 1 << 25; /* RGB8888 */
+ case 16: br13 |= 1 << 24; /* RGB565 */
+ case 8: break;
+ }
+
+ b = kgem->batch + kgem->nbatch;
+ b[0] = br00;
+ b[1] = br13;
+ b[2] = 0;
+ b[3] = height << 16 | width;
+ b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst,
+ I915_GEM_DOMAIN_RENDER << 16 |
+ I915_GEM_DOMAIN_RENDER |
+ KGEM_RELOC_FENCED,
+ 0);
+ b[5] = 0;
+ b[6] = pitch;
+ b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src,
+ I915_GEM_DOMAIN_RENDER << 16 |
+ KGEM_RELOC_FENCED,
+ 0);
+ kgem->nbatch += 8;
+
+ return dst;
+}
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index 14faa709..8649512e 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -170,6 +170,14 @@ int kgem_choose_tiling(struct kgem *kgem,
int tiling, int width, int height, int bpp);
bool kgem_can_create_2d(struct kgem *kgem,
int width, int height, int bpp, int tiling);
+
+struct kgem_bo *
+kgem_replace_bo(struct kgem *kgem,
+ struct kgem_bo *src,
+ uint32_t width,
+ uint32_t height,
+ uint32_t pitch,
+ uint32_t bpp);
enum {
CREATE_EXACT = 0x1,
CREATE_INACTIVE = 0x2,