From b5a6bc9e33a2797c926969e1f98b4a9a796248c5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Dec 2011 13:14:45 +0000 Subject: 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 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=43688 Signed-off-by: Chris Wilson --- src/sna/gen2_render.c | 23 +++++++++++++-- src/sna/gen3_render.c | 24 +++++++++++++-- src/sna/kgem.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/sna/kgem.h | 8 +++++ 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, -- cgit v1.2.3