[RFC,1/2] etnaviv: add support for CPU-based super/multi tile tiling/untiling

Submitted by Boris Brezillon on Feb. 20, 2019, 5:01 p.m.

Details

Message ID 20190220170137.23115-2-boris.brezillon@collabora.com
State New
Headers show
Series "etnaviv: use CPU-based tiling/untiling for small regions" ( rev: 1 ) in Mesa

Not browsing as part of any series.

Commit Message

Boris Brezillon Feb. 20, 2019, 5:01 p.m.
Sometimes using CPU based untiling/tiling makes, like when updating
a really small region of the texture atlas which is not RS-aligned.
CPU-based support for simple tile layout was already supported, but
not the multi/super tile cases.
Make the etna_texture_[un]tile() more generic to support those cases.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
---
 src/gallium/drivers/etnaviv/etnaviv_tiling.c  | 85 ++++++++++++++++---
 src/gallium/drivers/etnaviv/etnaviv_tiling.h  | 10 ++-
 .../drivers/etnaviv/etnaviv_transfer.c        | 16 ++--
 3 files changed, 84 insertions(+), 27 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/gallium/drivers/etnaviv/etnaviv_tiling.c b/src/gallium/drivers/etnaviv/etnaviv_tiling.c
index f4f85c1d6e6c..7e2b8bd48d3a 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_tiling.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_tiling.c
@@ -32,39 +32,95 @@ 
 #define TEX_TILE_WIDTH (4)
 #define TEX_TILE_HEIGHT (4)
 #define TEX_TILE_WORDS (TEX_TILE_WIDTH * TEX_TILE_HEIGHT)
+#define TEX_SUPERTILE_WIDTH (64)
+#define TEX_SUPERTILE_HEIGHT (64)
+#define TEX_SUPERTILE_TWIDTH (16)
+#define TEX_SUPERTILE_THEIGHT (16)
+#define TEX_SUPERTILE_WORDS (TEX_SUPERTILE_WIDTH * TEX_SUPERTILE_HEIGHT)
+#define TEX_TILES_PER_SUPERTILE (TEX_SUPERTILE_TWIDTH * TEX_SUPERTILE_THEIGHT)
+
+static unsigned tile_buf_offset(enum etna_surface_layout tlayout,
+                                unsigned tx, unsigned ty,
+				unsigned tstride, unsigned th,
+				unsigned elmtsize)
+{
+   unsigned offs = 0, tile;
+   unsigned tiles_per_line = (tstride / elmtsize) / TEX_TILE_WIDTH;
+
+   /* Multi tile layouts are described here:
+    * https://github.com/laanwj/etna_viv/blob/master/doc/hardware.md#multi-tiling
+    */
+   if (tlayout & ETNA_LAYOUT_BIT_MULTI) {
+      if ((((tx / (TEX_TILE_WIDTH * 2)) & 1) ^ ((ty / TEX_TILE_HEIGHT) & 1))) {
+         offs += ((tstride / elmtsize) * (th / 2));
+         if ((tx / (TEX_TILE_WIDTH * 2)) & 1)
+            tx -= TEX_TILE_WIDTH * 2;
+	 else
+            tx += TEX_TILE_HEIGHT * 2;
+      }
+
+      ty = ((ty / 2) & ~(TEX_TILE_HEIGHT - 1)) +
+           (ty % TEX_TILE_HEIGHT);
+   }
+
+   if (tlayout & ETNA_LAYOUT_BIT_SUPER) {
+      /* We use the supertile layout described here:
+       * https://github.com/laanwj/etna_viv/blob/master/doc/hardware.md#supertiling
+       * FIXME: According to
+       * https://github.com/laanwj/etna_viv/blob/master/tools/detiler.py
+       * another layout exists. We should probably support CPU-based detiling
+       * for this layout too and determine the layout to used based on HW
+       * features. */
+      tile = (ty / TEX_SUPERTILE_HEIGHT) * tiles_per_line *
+             TEX_SUPERTILE_THEIGHT;
+      ty &= TEX_SUPERTILE_HEIGHT - 1;
+      tile += (tx / TEX_SUPERTILE_WIDTH) * TEX_TILES_PER_SUPERTILE;
+      tx &= TEX_SUPERTILE_WIDTH - 1;
+      tile += (ty / (4 * TEX_TILE_HEIGHT)) * 16 * 4;
+      ty &= (4 * TEX_TILE_HEIGHT) - 1;
+      tile += (ty / TEX_TILE_HEIGHT) * 2;
+      tile += ((tx / TEX_TILE_WIDTH) & ~0x1) * 4;
+      tile += (tx / TEX_TILE_WIDTH) & 0x1;
+   } else {
+      tile = (ty / TEX_TILE_HEIGHT) * tiles_per_line;
+      tile += tx / TEX_TILE_WIDTH;
+   }
+
+   offs += tile * TEX_TILE_WORDS;
+   ty &= TEX_TILE_HEIGHT - 1;
+   tx &= TEX_TILE_WIDTH - 1;
+   offs += (ty * TEX_TILE_WIDTH) + tx;
+
+   return offs;
+}
 
 #define DO_TILE(type)                                                   \
    src_stride /= sizeof(type);                                          \
-   dst_stride = (dst_stride * TEX_TILE_HEIGHT) / sizeof(type);          \
    for (unsigned srcy = 0; srcy < height; ++srcy) {                     \
-      unsigned dsty = basey + srcy;                                     \
-      unsigned ty = (dsty / TEX_TILE_HEIGHT) * dst_stride +             \
-                    (dsty % TEX_TILE_HEIGHT) * TEX_TILE_WIDTH;          \
       for (unsigned srcx = 0; srcx < width; ++srcx) {                   \
-         unsigned dstx = basex + srcx;                                  \
-         ((type *)dest)[ty + (dstx / TEX_TILE_WIDTH) * TEX_TILE_WORDS + \
-                        (dstx % TEX_TILE_WIDTH)] =                      \
+         unsigned destoffs = tile_buf_offset(baselayout, basex + srcx,  \
+                                             basey + srcy, dst_stride,  \
+                                             baseh, elmtsize);          \
+         ((type *)dest)[destoffs] =                                     \
             ((type *)src)[srcy * src_stride + srcx];                    \
       }                                                                 \
    }
 
 #define DO_UNTILE(type)                                                   \
-   src_stride = (src_stride * TEX_TILE_HEIGHT) / sizeof(type);            \
    dst_stride /= sizeof(type);                                            \
    for (unsigned dsty = 0; dsty < height; ++dsty) {                       \
-      unsigned srcy = basey + dsty;                                       \
-      unsigned sy = (srcy / TEX_TILE_HEIGHT) * src_stride +               \
-                    (srcy % TEX_TILE_HEIGHT) * TEX_TILE_WIDTH;            \
       for (unsigned dstx = 0; dstx < width; ++dstx) {                     \
-         unsigned srcx = basex + dstx;                                    \
+         unsigned srcoffs = tile_buf_offset(baselayout, basex + dstx,     \
+                                            basey + dsty, src_stride,     \
+                                            baseh, elmtsize);             \
          ((type *)dest)[dsty * dst_stride + dstx] =                       \
-            ((type *)src)[sy + (srcx / TEX_TILE_WIDTH) * TEX_TILE_WORDS + \
-                          (srcx % TEX_TILE_WIDTH)];                       \
+            ((type *)src)[srcoffs];                                       \
       }                                                                   \
    }
 
 void
 etna_texture_tile(void *dest, void *src, unsigned basex, unsigned basey,
+                  enum etna_surface_layout baselayout, unsigned int baseh,
                   unsigned dst_stride, unsigned width, unsigned height,
                   unsigned src_stride, unsigned elmtsize)
 {
@@ -81,6 +137,7 @@  etna_texture_tile(void *dest, void *src, unsigned basex, unsigned basey,
 
 void
 etna_texture_untile(void *dest, void *src, unsigned basex, unsigned basey,
+                    enum etna_surface_layout baselayout, unsigned int baseh,
                     unsigned src_stride, unsigned width, unsigned height,
                     unsigned dst_stride, unsigned elmtsize)
 {
diff --git a/src/gallium/drivers/etnaviv/etnaviv_tiling.h b/src/gallium/drivers/etnaviv/etnaviv_tiling.h
index 3c69e22463dc..f18ba09796f5 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_tiling.h
+++ b/src/gallium/drivers/etnaviv/etnaviv_tiling.h
@@ -43,12 +43,14 @@  enum etna_surface_layout {
 
 void
 etna_texture_tile(void *dest, void *src, unsigned basex, unsigned basey,
-                 unsigned dst_stride, unsigned width, unsigned height,
-                 unsigned src_stride, unsigned elmtsize);
+                  enum etna_surface_layout baselayout, unsigned int baseh,
+                  unsigned dst_stride, unsigned width, unsigned height,
+                  unsigned src_stride, unsigned elmtsize);
 void
 etna_texture_untile(void *dest, void *src, unsigned basex, unsigned basey,
-                   unsigned src_stride, unsigned width, unsigned height,
-                   unsigned dst_stride, unsigned elmtsize);
+                    enum etna_surface_layout baselayout, unsigned int baseh,
+                    unsigned src_stride, unsigned width, unsigned height,
+                    unsigned dst_stride, unsigned elmtsize);
 
 /* XXX from/to supertiling (can have different layouts, may be better
  * to leave to RS) */
diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.c b/src/gallium/drivers/etnaviv/etnaviv_transfer.c
index 30ae3bfc39dd..38648564b701 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_transfer.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.c
@@ -93,10 +93,11 @@  etna_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
          struct etna_resource_level *res_level = &rsc->levels[ptrans->level];
          void *mapped = etna_bo_map(rsc->bo) + res_level->offset;
 
-         if (rsc->layout == ETNA_LAYOUT_TILED) {
+         if (rsc->layout & ETNA_LAYOUT_BIT_TILE) {
             etna_texture_tile(
                mapped + ptrans->box.z * res_level->layer_stride,
                trans->staging, ptrans->box.x, ptrans->box.y,
+               rsc->layout, res_level->padded_height,
                res_level->stride, ptrans->box.width, ptrans->box.height,
                ptrans->stride, util_format_get_blocksize(rsc->base.format));
          } else if (rsc->layout == ETNA_LAYOUT_LINEAR) {
@@ -106,8 +107,6 @@  etna_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
                           ptrans->box.height, ptrans->box.depth,
                           trans->staging, ptrans->stride,
                           ptrans->layer_stride, 0, 0, 0 /* src x,y,z */);
-         } else {
-            BUG("unsupported tiling %i", rsc->layout);
          }
 
          FREE(trans->staging);
@@ -359,11 +358,13 @@  etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
          goto fail;
 
       if (usage & PIPE_TRANSFER_READ) {
-         if (rsc->layout == ETNA_LAYOUT_TILED) {
+         if (rsc->layout & ETNA_LAYOUT_BIT_TILE) {
             etna_texture_untile(trans->staging,
                                 mapped + ptrans->box.z * res_level->layer_stride,
-                                ptrans->box.x, ptrans->box.y, res_level->stride,
-                                ptrans->box.width, ptrans->box.height, ptrans->stride,
+                                ptrans->box.x, ptrans->box.y,
+                                rsc->layout, res_level->padded_height,
+                                res_level->stride, ptrans->box.width,
+                                ptrans->box.height, ptrans->stride,
                                 util_format_get_blocksize(rsc->base.format));
          } else if (rsc->layout == ETNA_LAYOUT_LINEAR) {
             util_copy_box(trans->staging, rsc->base.format, ptrans->stride,
@@ -372,9 +373,6 @@  etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
                           ptrans->box.depth, mapped, res_level->stride,
                           res_level->layer_stride, ptrans->box.x,
                           ptrans->box.y, ptrans->box.z);
-         } else {
-            /* TODO supertiling */
-            BUG("unsupported tiling %i for reading", rsc->layout);
          }
       }