broadcom/vc5: Fix layout of 3D textures.
authorEric Anholt <eric@anholt.net>
Thu, 2 Nov 2017 23:59:10 +0000 (16:59 -0700)
committerEric Anholt <eric@anholt.net>
Fri, 23 Feb 2018 23:07:26 +0000 (15:07 -0800)
Cube maps are entire miptrees repeated, while 3D textures have each level
have all of its layers next to each other.  Fixes tex3d and
tex-miplevel-selection GL2:texture() 3D.

src/gallium/drivers/vc5/vc5_resource.c
src/gallium/drivers/vc5/vc5_resource.h

index 157eb1c1013afa268b37fcf9249535c943ccbdda..e1645a4fde91b28456329a31ecceaed2324fbdcc 100644 (file)
@@ -75,18 +75,22 @@ vc5_debug_resource_layout(struct vc5_resource *rsc, const char *caller)
 
                 int level_width = slice->stride / rsc->cpp;
                 int level_height = slice->padded_height;
+                int level_depth =
+                        u_minify(util_next_power_of_two(prsc->depth0), i);
 
                 fprintf(stderr,
                         "rsc %s %p (format %s), %dx%d: "
-                        "level %d (%s) %dx%d -> %dx%d, stride %d@0x%08x\n",
+                        "level %d (%s) %dx%dx%d -> %dx%dx%d, stride %d@0x%08x\n",
                         caller, rsc,
                         util_format_short_name(prsc->format),
                         prsc->width0, prsc->height0,
                         i, tiling_descriptions[slice->tiling],
                         u_minify(prsc->width0, i),
                         u_minify(prsc->height0, i),
+                        u_minify(prsc->depth0, i),
                         level_width,
                         level_height,
+                        level_depth,
                         slice->stride,
                         rsc->bo->offset + slice->offset);
         }
@@ -98,14 +102,8 @@ vc5_resource_bo_alloc(struct vc5_resource *rsc)
         struct pipe_resource *prsc = &rsc->base;
         struct pipe_screen *pscreen = prsc->screen;
         struct vc5_bo *bo;
-        int layers = (prsc->target == PIPE_TEXTURE_3D ?
-                      prsc->depth0 : prsc->array_size);
-
-        bo = vc5_bo_alloc(vc5_screen(pscreen),
-                          rsc->slices[0].offset +
-                          rsc->slices[0].size +
-                          rsc->cube_map_stride * layers - 1,
-                          "resource");
+
+        bo = vc5_bo_alloc(vc5_screen(pscreen), rsc->size, "resource");
         if (bo) {
                 vc5_bo_unreference(&rsc->bo);
                 rsc->bo = bo;
@@ -128,13 +126,21 @@ vc5_resource_transfer_unmap(struct pipe_context *pctx,
                 struct vc5_resource_slice *slice = &rsc->slices[ptrans->level];
 
                 if (ptrans->usage & PIPE_TRANSFER_WRITE) {
-                        vc5_store_tiled_image(rsc->bo->map + slice->offset +
-                                              ptrans->box.z * rsc->cube_map_stride,
-                                              slice->stride,
-                                              trans->map, ptrans->stride,
-                                              slice->tiling, rsc->cpp,
-                                              slice->padded_height,
-                                              &ptrans->box);
+                        for (int z = 0; z < ptrans->box.depth; z++) {
+                                void *dst = rsc->bo->map +
+                                        vc5_layer_offset(&rsc->base,
+                                                         ptrans->level,
+                                                         ptrans->box.z + z);
+                                vc5_store_tiled_image(dst,
+                                                      slice->stride,
+                                                      (trans->map +
+                                                       ptrans->stride *
+                                                       ptrans->box.height * z),
+                                                      ptrans->stride,
+                                                      slice->tiling, rsc->cpp,
+                                                      slice->padded_height,
+                                                      &ptrans->box);
+                        }
                 }
                 free(trans->map);
         }
@@ -259,13 +265,21 @@ vc5_resource_transfer_map(struct pipe_context *pctx,
                 trans->map = malloc(ptrans->layer_stride * ptrans->box.depth);
 
                 if (usage & PIPE_TRANSFER_READ) {
-                        vc5_load_tiled_image(trans->map, ptrans->stride,
-                                             buf + slice->offset +
-                                             ptrans->box.z * rsc->cube_map_stride,
-                                             slice->stride,
-                                             slice->tiling, rsc->cpp,
-                                             slice->padded_height,
+                        for (int z = 0; z < ptrans->box.depth; z++) {
+                                void *src = rsc->bo->map +
+                                        vc5_layer_offset(&rsc->base,
+                                                         ptrans->level,
+                                                         ptrans->box.z + z);
+                                vc5_load_tiled_image((trans->map +
+                                                      ptrans->stride *
+                                                      ptrans->box.height * z),
+                                                     ptrans->stride,
+                                                     src,
+                                                     slice->stride,
+                                                     slice->tiling, rsc->cpp,
+                                                     slice->padded_height,
                                              &ptrans->box);
+                        }
                 }
                 return trans->map;
         } else {
@@ -378,8 +392,10 @@ vc5_setup_slices(struct vc5_resource *rsc)
         struct pipe_resource *prsc = &rsc->base;
         uint32_t width = prsc->width0;
         uint32_t height = prsc->height0;
+        uint32_t depth = prsc->depth0;
         uint32_t pot_width = util_next_power_of_two(width);
         uint32_t pot_height = util_next_power_of_two(height);
+        uint32_t pot_depth = util_next_power_of_two(depth);
         uint32_t offset = 0;
         uint32_t utile_w = vc5_utile_width(rsc->cpp);
         uint32_t utile_h = vc5_utile_height(rsc->cpp);
@@ -396,7 +412,7 @@ vc5_setup_slices(struct vc5_resource *rsc)
         for (int i = prsc->last_level; i >= 0; i--) {
                 struct vc5_resource_slice *slice = &rsc->slices[i];
 
-                uint32_t level_width, level_height;
+                uint32_t level_width, level_height, level_depth;
                 if (i < 2) {
                         level_width = u_minify(width, i);
                         level_height = u_minify(height, i);
@@ -404,6 +420,10 @@ vc5_setup_slices(struct vc5_resource *rsc)
                         level_width = u_minify(pot_width, i);
                         level_height = u_minify(pot_height, i);
                 }
+                if (i < 1)
+                        level_depth = u_minify(depth, i);
+                else
+                        level_depth = u_minify(pot_depth, i);
 
                 if (msaa) {
                         level_width *= 2;
@@ -468,6 +488,9 @@ vc5_setup_slices(struct vc5_resource *rsc)
                 slice->padded_height = level_height;
                 slice->size = level_height * slice->stride;
 
+                offset += slice->size * level_depth;
+
+
                 /* The HW aligns level 1's base to a page if any of level 1 or
                  * below could be UIF XOR.  The lower levels then inherit the
                  * alignment for as long as necesary, thanks to being power of
@@ -476,11 +499,10 @@ vc5_setup_slices(struct vc5_resource *rsc)
                 if (i == 1 &&
                     level_width > 4 * uif_block_w &&
                     level_height > PAGE_CACHE_MINUS_1_5_UB_ROWS * uif_block_h) {
-                        slice->size = align(slice->size, VC5_UIFCFG_PAGE_SIZE);
+                        offset = align(offset, VC5_UIFCFG_PAGE_SIZE);
                 }
-
-                offset += slice->size;
         }
+        rsc->size = offset;
 
         /* UIF/UBLINEAR levels need to be aligned to UIF-blocks, and LT only
          * needs to be aligned to utile boundaries.  Since tiles are laid out
@@ -493,15 +515,34 @@ vc5_setup_slices(struct vc5_resource *rsc)
         uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) -
                                       rsc->slices[0].offset);
         if (page_align_offset) {
+                rsc->size += page_align_offset;
                 for (int i = 0; i <= prsc->last_level; i++)
                         rsc->slices[i].offset += page_align_offset;
         }
 
-        /* Arrays, cubes, and 3D textures have a stride which is the distance
-         * from one full mipmap tree to the next (64b aligned).
+        /* Arrays and cube textures have a stride which is the distance from
+         * one full mipmap tree to the next (64b aligned).  For 3D textures,
+         * we need to program the stride between slices of miplevel 0.
          */
-        rsc->cube_map_stride = align(rsc->slices[0].offset +
-                                     rsc->slices[0].size, 64);
+        if (prsc->target != PIPE_TEXTURE_3D) {
+                rsc->cube_map_stride = align(rsc->slices[0].offset +
+                                             rsc->slices[0].size, 64);
+                rsc->size += rsc->cube_map_stride * (prsc->array_size - 1);
+        } else {
+                rsc->cube_map_stride = rsc->slices[0].size;
+        }
+}
+
+uint32_t
+vc5_layer_offset(struct pipe_resource *prsc, uint32_t level, uint32_t layer)
+{
+        struct vc5_resource *rsc = vc5_resource(prsc);
+        struct vc5_resource_slice *slice = &rsc->slices[level];
+
+        if (prsc->target == PIPE_TEXTURE_3D)
+                return slice->offset + layer * slice->size;
+        else
+                return slice->offset + layer * rsc->cube_map_stride;
 }
 
 static struct vc5_resource *
@@ -737,8 +778,8 @@ vc5_create_surface(struct pipe_context *pctx,
         psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
         psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
 
-        surface->offset = (slice->offset +
-                           psurf->u.tex.first_layer * rsc->cube_map_stride);
+        surface->offset = vc5_layer_offset(ptex, level,
+                                           psurf->u.tex.first_layer);
         surface->tiling = slice->tiling;
 
         surface->format = vc5_get_rt_format(&screen->devinfo, psurf->format);
index 1bba480115b01efb96eb8b35f4e7d03271a9522c..2af355354abb94fafc05d1637eaa66cde5c1f7c2 100644 (file)
@@ -74,6 +74,10 @@ struct vc5_resource_slice {
         uint32_t offset;
         uint32_t stride;
         uint32_t padded_height;
+        /* Size of a single pane of the slice.  For 3D textures, there will be
+         * a number of panes equal to the minified, power-of-two-aligned
+         * depth.
+         */
         uint32_t size;
         uint8_t ub_pad;
         enum vc5_tiling_mode tiling;
@@ -113,6 +117,7 @@ struct vc5_resource {
         struct vc5_bo *bo;
         struct vc5_resource_slice slices[VC5_MAX_MIP_LEVELS];
         uint32_t cube_map_stride;
+        uint32_t size;
         int cpp;
         bool tiled;
 
@@ -163,5 +168,8 @@ void vc5_resource_screen_init(struct pipe_screen *pscreen);
 void vc5_resource_context_init(struct pipe_context *pctx);
 struct pipe_resource *vc5_resource_create(struct pipe_screen *pscreen,
                                           const struct pipe_resource *tmpl);
+uint32_t vc5_layer_offset(struct pipe_resource *prsc, uint32_t level,
+                          uint32_t layer);
+
 
 #endif /* VC5_RESOURCE_H */