Mesa (main): panfrost: Prepare texture helpers to per-gen XML

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Sep 20 14:02:10 UTC 2021


Module: Mesa
Branch: main
Commit: 0d57a76458a8a3bf690b30471165f47ab7a84ae9
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=0d57a76458a8a3bf690b30471165f47ab7a84ae9

Author: Boris Brezillon <boris.brezillon at collabora.com>
Date:   Fri Aug  6 14:24:31 2021 +0200

panfrost: Prepare texture helpers to per-gen XML

Signed-off-by: Boris Brezillon <boris.brezillon at collabora.com>
Reviewed-by: Alyssa Rosenzweig <alyssa at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12935>

---

 src/gallium/drivers/panfrost/pan_cmdstream.c |   6 +-
 src/panfrost/lib/meson.build                 |   1 +
 src/panfrost/lib/pan_blitter.c               |   8 +-
 src/panfrost/lib/pan_texture.c               | 914 +++++++++++++--------------
 src/panfrost/lib/pan_texture.h               |  15 +-
 src/panfrost/vulkan/panvk_vX_image.c         |   4 +-
 6 files changed, 469 insertions(+), 479 deletions(-)

diff --git a/src/gallium/drivers/panfrost/pan_cmdstream.c b/src/gallium/drivers/panfrost/pan_cmdstream.c
index f04f35e684e..ff5f6b190e9 100644
--- a/src/gallium/drivers/panfrost/pan_cmdstream.c
+++ b/src/gallium/drivers/panfrost/pan_cmdstream.c
@@ -1315,8 +1315,8 @@ panfrost_create_sampler_view_bo(struct panfrost_sampler_view *so,
         };
 
         unsigned size =
-                (PAN_ARCH <= 5 ? pan_size(MIDGARD_TEXTURE) : 0) +
-                panfrost_estimate_texture_payload_size(device, &iview);
+                (PAN_ARCH <= 5 ? pan_size(TEXTURE) : 0) +
+                GENX(panfrost_estimate_texture_payload_size)(&iview);
 
         struct panfrost_ptr payload = pan_pool_alloc_aligned(&ctx->descs.base, size, 64);
         so->state = panfrost_pool_take_ref(&ctx->descs, payload.gpu);
@@ -1328,7 +1328,7 @@ panfrost_create_sampler_view_bo(struct panfrost_sampler_view *so,
                 payload.gpu += pan_size(MIDGARD_TEXTURE);
         }
 
-        panfrost_new_texture(device, &iview, tex, &payload);
+        GENX(panfrost_new_texture)(device, &iview, tex, &payload);
 }
 
 static void
diff --git a/src/panfrost/lib/meson.build b/src/panfrost/lib/meson.build
index 522149466b3..8658637f607 100644
--- a/src/panfrost/lib/meson.build
+++ b/src/panfrost/lib/meson.build
@@ -60,6 +60,7 @@ foreach ver : ['4', '5', '6', '7']
       'pan_cs.c',
       'pan_indirect_dispatch.c',
       'pan_indirect_draw.c',
+      'pan_texture.c',
     ],
     include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux, inc_panfrost_hw],
     c_args : ['-DPAN_ARCH=' + ver],
diff --git a/src/panfrost/lib/pan_blitter.c b/src/panfrost/lib/pan_blitter.c
index abb375b6528..69cc967dd49 100644
--- a/src/panfrost/lib/pan_blitter.c
+++ b/src/panfrost/lib/pan_blitter.c
@@ -883,12 +883,12 @@ pan_blitter_emit_textures(struct pan_pool *pool,
         for (unsigned i = 0; i < tex_count; i++) {
                 void *texture = textures.cpu + (pan_size(TEXTURE) * i);
                 size_t payload_size =
-                        panfrost_estimate_texture_payload_size(pool->dev, views[i]);
+                        GENX(panfrost_estimate_texture_payload_size)(views[i]);
                 struct panfrost_ptr surfaces =
                         pan_pool_alloc_aligned(pool, payload_size,
                                                pan_alignment(SURFACE_WITH_STRIDE));
 
-                panfrost_new_texture(pool->dev, views[i], texture, &surfaces);
+                GENX(panfrost_new_texture)(pool->dev, views[i], texture, &surfaces);
         }
 
         return textures.gpu;
@@ -897,7 +897,7 @@ pan_blitter_emit_textures(struct pan_pool *pool,
 
         for (unsigned i = 0; i < tex_count; i++) {
                 size_t sz = pan_size(TEXTURE) +
-                            panfrost_estimate_texture_payload_size(pool->dev, views[i]);
+                            GENX(panfrost_estimate_texture_payload_size)(views[i]);
                 struct panfrost_ptr texture =
                         pan_pool_alloc_aligned(pool, sz, pan_alignment(TEXTURE));
                 struct panfrost_ptr surfaces = {
@@ -905,7 +905,7 @@ pan_blitter_emit_textures(struct pan_pool *pool,
                         .gpu = texture.gpu + pan_size(TEXTURE),
                 };
 
-                panfrost_new_texture(pool->dev, views[i], texture.cpu, &surfaces);
+                GENX(panfrost_new_texture)(pool->dev, views[i], texture.cpu, &surfaces);
                 textures[i] = texture.gpu;
         }
 
diff --git a/src/panfrost/lib/pan_texture.c b/src/panfrost/lib/pan_texture.c
index 49da5340d0a..226f98a4be6 100644
--- a/src/panfrost/lib/pan_texture.c
+++ b/src/panfrost/lib/pan_texture.c
@@ -30,6 +30,8 @@
 #include "pan_texture.h"
 #include "panfrost-quirks.h"
 
+#ifndef PAN_ARCH
+
 /* Generates a texture descriptor. Ideally, descriptors are immutable after the
  * texture is created, so we can keep these hanging around in GPU memory in a
  * dedicated BO and not have to worry. In practice there are some minor gotchas
@@ -57,165 +59,6 @@ uint64_t pan_best_modifiers[PAN_MODIFIER_COUNT] = {
         DRM_FORMAT_MOD_LINEAR
 };
 
-/* Check if we need to set a custom stride by computing the "expected"
- * stride and comparing it to what the user actually wants. Only applies
- * to linear textures, since tiled/compressed textures have strict
- * alignment requirements for their strides as it is */
-
-static bool
-panfrost_needs_explicit_stride(const struct panfrost_device *dev,
-                               const struct pan_image_view *iview)
-{
-        /* Stride is explicit on Bifrost */
-        if (pan_is_bifrost(dev))
-                return true;
-
-        if (iview->image->layout.modifier != DRM_FORMAT_MOD_LINEAR)
-                return false;
-
-        unsigned bytes_per_block = util_format_get_blocksize(iview->format);
-        unsigned block_w = util_format_get_blockwidth(iview->format);
-
-        for (unsigned l = iview->first_level; l <= iview->last_level; ++l) {
-                unsigned actual = iview->image->layout.slices[l].line_stride;
-                unsigned expected =
-                        DIV_ROUND_UP(u_minify(iview->image->layout.width, l), block_w) *
-                        bytes_per_block;
-
-                if (actual != expected)
-                        return true;
-        }
-
-        return false;
-}
-
-/* A Scalable Texture Compression (ASTC) corresponds to just a few texture type
- * in the hardware, but in fact can be parametrized to have various widths and
- * heights for the so-called "stretch factor". It turns out these parameters
- * are stuffed in the bottom bits of the payload pointers. This functions
- * computes these magic stuffing constants based on the ASTC format in use. The
- * constant in a given dimension is 3-bits, and two are stored side-by-side for
- * each active dimension.
- */
-
-static unsigned
-panfrost_astc_stretch(unsigned dim)
-{
-        assert(dim >= 4 && dim <= 12);
-        return MIN2(dim, 11) - 4;
-}
-
-/* Texture addresses are tagged with information about compressed formats.
- * AFBC uses a bit for whether the colorspace transform is enabled (RGB and
- * RGBA only).
- * For ASTC, this is a "stretch factor" encoding the block size. */
-
-static unsigned
-panfrost_compression_tag(const struct panfrost_device *dev,
-                         const struct util_format_description *desc,
-                         enum mali_texture_dimension dim,
-                         uint64_t modifier)
-{
-        if (drm_is_afbc(modifier)) {
-                unsigned flags = (modifier & AFBC_FORMAT_MOD_YTR) ?
-                                 MALI_AFBC_SURFACE_FLAG_YTR : 0;
-
-                if (!pan_is_bifrost(dev))
-                        return flags;
-
-                /* Prefetch enable */
-                flags |= MALI_AFBC_SURFACE_FLAG_PREFETCH;
-
-                /* Wide blocks (> 16x16) */
-                if (panfrost_block_dim(modifier, true, 0) > 16)
-                        flags |= MALI_AFBC_SURFACE_FLAG_WIDE_BLOCK;
-
-                /* Used to make sure AFBC headers don't point outside the AFBC
-                 * body. HW is using the AFBC surface stride to do this check,
-                 * which doesn't work for 3D textures because the surface
-                 * stride does not cover the body. Only supported on v7+.
-                 */
-                if (dev->arch >= 7 && dim != MALI_TEXTURE_DIMENSION_3D)
-                        flags |= MALI_AFBC_SURFACE_FLAG_CHECK_PAYLOAD_RANGE;
-
-                return flags;
-        } else if (desc->layout == UTIL_FORMAT_LAYOUT_ASTC) {
-                return (panfrost_astc_stretch(desc->block.height) << 3) |
-                        panfrost_astc_stretch(desc->block.width);
-        } else {
-                return 0;
-        }
-}
-
-
-/* Cubemaps have 6 faces as "layers" in between each actual layer. We
- * need to fix this up. TODO: logic wrong in the asserted out cases ...
- * can they happen, perhaps from cubemap arrays? */
-
-static void
-panfrost_adjust_cube_dimensions(
-                unsigned *first_face, unsigned *last_face,
-                unsigned *first_layer, unsigned *last_layer)
-{
-        *first_face = *first_layer % 6;
-        *last_face = *last_layer % 6;
-        *first_layer /= 6;
-        *last_layer /= 6;
-
-        assert((*first_layer == *last_layer) || (*first_face == 0 && *last_face == 5));
-}
-
-/* Following the texture descriptor is a number of pointers. How many? */
-
-static unsigned
-panfrost_texture_num_elements(
-                unsigned first_level, unsigned last_level,
-                unsigned first_layer, unsigned last_layer,
-                unsigned nr_samples,
-                bool is_cube, bool manual_stride)
-{
-        unsigned first_face  = 0, last_face = 0;
-
-        if (is_cube) {
-                panfrost_adjust_cube_dimensions(&first_face, &last_face,
-                                &first_layer, &last_layer);
-        }
-
-        unsigned levels = 1 + last_level - first_level;
-        unsigned layers = 1 + last_layer - first_layer;
-        unsigned faces  = 1 + last_face  - first_face;
-        unsigned num_elements = levels * layers * faces * MAX2(nr_samples, 1);
-
-        if (manual_stride)
-                num_elements *= 2;
-
-        return num_elements;
-}
-
-/* Conservative estimate of the size of the texture payload a priori.
- * Average case, size equal to the actual size. Worst case, off by 2x (if
- * a manual stride is not needed on a linear texture). Returned value
- * must be greater than or equal to the actual size, so it's safe to use
- * as an allocation amount */
-
-unsigned
-panfrost_estimate_texture_payload_size(const struct panfrost_device *dev,
-                                       const struct pan_image_view *iview)
-{
-        /* Assume worst case */
-        unsigned manual_stride = pan_is_bifrost(dev) ||
-                                 (iview->image->layout.modifier == DRM_FORMAT_MOD_LINEAR);
-
-        unsigned elements =
-                panfrost_texture_num_elements(iview->first_level, iview->last_level,
-                                              iview->first_layer, iview->last_layer,
-                                              iview->image->layout.nr_samples,
-                                              iview->dim == MALI_TEXTURE_DIMENSION_CUBE,
-                                              manual_stride);
-
-        return sizeof(mali_ptr) * elements;
-}
-
 /* If not explicitly, line stride is calculated for block-based formats as
  * (ceil(width / block_width) * block_size). As a special case, this is left
  * zero if there is only a single block vertically. So, we have a helper to
@@ -245,323 +88,51 @@ panfrost_block_dim(uint64_t modifier, bool width, unsigned plane)
         }
 }
 
-static void
-panfrost_get_surface_strides(const struct panfrost_device *dev,
-                             const struct pan_image_layout *layout,
-                             unsigned l,
-                             int32_t *row_stride, int32_t *surf_stride)
-{
-        const struct pan_image_slice_layout *slice = &layout->slices[l];
+/* Computes sizes for checksumming, which is 8 bytes per 16x16 tile.
+ * Checksumming is believed to be a CRC variant (CRC64 based on the size?).
+ * This feature is also known as "transaction elimination". */
 
-        if (drm_is_afbc(layout->modifier)) {
-                /* Pre v7 don't have a row stride field. This field is
-                 * repurposed as a Y offset which we don't use */
-                *row_stride = dev->arch < 7 ? 0 : slice->afbc.row_stride;
-                *surf_stride = slice->afbc.surface_stride;
-        } else {
-                *row_stride = slice->row_stride;
-                *surf_stride = slice->surface_stride;
-        }
-}
+#define CHECKSUM_TILE_WIDTH 16
+#define CHECKSUM_TILE_HEIGHT 16
+#define CHECKSUM_BYTES_PER_TILE 8
 
-static mali_ptr
-panfrost_get_surface_pointer(const struct pan_image_layout *layout,
-                             enum mali_texture_dimension dim,
-                             mali_ptr base,
-                             unsigned l, unsigned w, unsigned f, unsigned s)
+unsigned
+panfrost_compute_checksum_size(
+        struct pan_image_slice_layout *slice,
+        unsigned width,
+        unsigned height)
 {
-        unsigned face_mult = dim == MALI_TEXTURE_DIMENSION_CUBE ? 6 : 1;
-        unsigned offset;
+        unsigned tile_count_x = DIV_ROUND_UP(width, CHECKSUM_TILE_WIDTH);
+        unsigned tile_count_y = DIV_ROUND_UP(height, CHECKSUM_TILE_HEIGHT);
 
-        if (layout->dim == MALI_TEXTURE_DIMENSION_3D) {
-                assert(!f && !s);
-                offset = layout->slices[l].offset +
-                         (w * panfrost_get_layer_stride(layout, l));
-        } else {
-                offset = panfrost_texture_offset(layout, l, (w * face_mult) + f, s);
-        }
+        slice->crc.stride = tile_count_x * CHECKSUM_BYTES_PER_TILE;
 
-        return base + offset;
+        return slice->crc.stride * tile_count_y;
 }
 
-struct panfrost_surface_iter {
-        unsigned layer, last_layer;
-        unsigned level, first_level, last_level;
-        unsigned face, first_face, last_face;
-        unsigned sample, first_sample, last_sample;
-};
-
-static void
-panfrost_surface_iter_begin(struct panfrost_surface_iter *iter,
-                            unsigned first_layer, unsigned last_layer,
-                            unsigned first_level, unsigned last_level,
-                            unsigned first_face, unsigned last_face,
-                            unsigned nr_samples)
+unsigned
+panfrost_get_layer_stride(const struct pan_image_layout *layout,
+                          unsigned level)
 {
-        iter->layer = first_layer;
-        iter->last_layer = last_layer;
-        iter->level = iter->first_level = first_level;
-        iter->last_level = last_level;
-        iter->face = iter->first_face = first_face;
-        iter->last_face = last_face;
-        iter->sample = iter->first_sample = 0;
-        iter->last_sample = nr_samples - 1;
+        if (layout->dim != MALI_TEXTURE_DIMENSION_3D)
+                return layout->array_stride;
+        else if (drm_is_afbc(layout->modifier))
+                return layout->slices[level].afbc.surface_stride;
+        else
+                return layout->slices[level].surface_stride;
 }
 
-static bool
-panfrost_surface_iter_end(const struct panfrost_surface_iter *iter)
-{
-        return iter->layer > iter->last_layer;
-}
+/* Computes the offset into a texture at a particular level/face. Add to
+ * the base address of a texture to get the address to that level/face */
 
-static void
-panfrost_surface_iter_next(const struct panfrost_device *dev,
-                           struct panfrost_surface_iter *iter)
+unsigned
+panfrost_texture_offset(const struct pan_image_layout *layout,
+                        unsigned level, unsigned array_idx,
+                        unsigned surface_idx)
 {
-#define INC_TEST(field) \
-        do { \
-                if (iter->field++ < iter->last_ ## field) \
-                       return; \
-                iter->field = iter->first_ ## field; \
-        } while (0)
-
-        /* Ordering is different on v7: inner loop is iterating on levels */
-        if (dev->arch >= 7)
-                INC_TEST(level);
-
-        INC_TEST(sample);
-        INC_TEST(face);
-
-        if (dev->arch < 7)
-                INC_TEST(level);
-
-        iter->layer++;
-
-#undef INC_TEST
-}
-
-static void
-panfrost_emit_texture_payload(const struct panfrost_device *dev,
-                              const struct pan_image_view *iview,
-                              enum pipe_format format,
-                              bool manual_stride,
-                              void *payload)
-{
-        const struct pan_image_layout *layout = &iview->image->layout;
-        const struct util_format_description *desc =
-                util_format_description(format);
-
-        mali_ptr base = iview->image->data.bo->ptr.gpu + iview->image->data.offset;
-
-        if (iview->buf.size) {
-                assert (iview->dim == MALI_TEXTURE_DIMENSION_1D);
-                base += iview->buf.offset;
-        }
-
-        /* panfrost_compression_tag() wants the dimension of the resource, not the
-         * one of the image view (those might differ).
-         */
-        base |= panfrost_compression_tag(dev, desc, layout->dim, layout->modifier);
-
-        /* Inject the addresses in, interleaving array indices, mip levels,
-         * cube faces, and strides in that order */
-
-        unsigned first_layer = iview->first_layer, last_layer = iview->last_layer;
-        unsigned nr_samples = layout->nr_samples;
-        unsigned first_face = 0, last_face = 0;
-
-        if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) {
-                panfrost_adjust_cube_dimensions(&first_face, &last_face,
-                                                &first_layer, &last_layer);
-        }
-
-        struct panfrost_surface_iter iter;
-
-        for (panfrost_surface_iter_begin(&iter, first_layer, last_layer,
-                                         iview->first_level, iview->last_level,
-                                         first_face, last_face, nr_samples);
-             !panfrost_surface_iter_end(&iter);
-             panfrost_surface_iter_next(dev, &iter)) {
-                mali_ptr pointer =
-                        panfrost_get_surface_pointer(layout, iview->dim, base,
-                                                     iter.level, iter.layer,
-                                                     iter.face, iter.sample);
-
-                if (!manual_stride) {
-                        pan_pack(payload, SURFACE, cfg) {
-                                cfg.pointer = pointer;
-                        }
-                        payload += pan_size(SURFACE);
-                } else {
-                        pan_pack(payload, SURFACE_WITH_STRIDE, cfg) {
-                                cfg.pointer = pointer;
-                                panfrost_get_surface_strides(dev, layout, iter.level,
-                                                             &cfg.row_stride,
-                                                             &cfg.surface_stride);
-                        }
-                        payload += pan_size(SURFACE_WITH_STRIDE);
-                }
-        }
-}
-
-/* Map modifiers to mali_texture_layout for packing in a texture descriptor */
-
-static enum mali_texture_layout
-panfrost_modifier_to_layout(uint64_t modifier)
-{
-        if (drm_is_afbc(modifier))
-                return MALI_TEXTURE_LAYOUT_AFBC;
-        else if (modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED)
-                return MALI_TEXTURE_LAYOUT_TILED;
-        else if (modifier == DRM_FORMAT_MOD_LINEAR)
-                return MALI_TEXTURE_LAYOUT_LINEAR;
-        else
-                unreachable("Invalid modifer");
-}
-
-void
-panfrost_new_texture(const struct panfrost_device *dev,
-                     const struct pan_image_view *iview,
-                     void *out, const struct panfrost_ptr *payload)
-{
-        const struct pan_image_layout *layout = &iview->image->layout;
-        enum pipe_format format = iview->format;
-        unsigned swizzle;
-
-        if (dev->arch == 7 && util_format_is_depth_or_stencil(format)) {
-                /* v7 doesn't have an _RRRR component order, combine the
-                 * user swizzle with a .XXXX swizzle to emulate that.
-                 */
-                static const unsigned char replicate_x[4] = {
-                        PIPE_SWIZZLE_X, PIPE_SWIZZLE_X,
-                        PIPE_SWIZZLE_X, PIPE_SWIZZLE_X,
-                };
-                unsigned char patched_swizzle[4];
-
-                util_format_compose_swizzles(replicate_x,
-                                             iview->swizzle,
-                                             patched_swizzle);
-                swizzle = panfrost_translate_swizzle_4(patched_swizzle);
-        } else {
-                swizzle = panfrost_translate_swizzle_4(iview->swizzle);
-        }
-
-        bool manual_stride =
-                panfrost_needs_explicit_stride(dev, iview);
-
-        panfrost_emit_texture_payload(dev, iview, format,
-                                      manual_stride,
-                                      payload->cpu);
-
-        unsigned array_size = iview->last_layer - iview->first_layer + 1;
-
-        if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) {
-                assert(iview->first_layer % 6 == 0);
-                assert(iview->last_layer % 6 == 5);
-                array_size /=  6;
-        }
-
-        unsigned width;
-
-        if (iview->buf.size) {
-                assert(iview->dim == MALI_TEXTURE_DIMENSION_1D);
-                assert(!iview->first_level && !iview->last_level);
-                assert(!iview->first_layer && !iview->last_layer);
-                assert(layout->nr_samples == 1);
-                assert(layout->height == 1 && layout->depth == 1);
-                assert(iview->buf.offset + iview->buf.size <= layout->width);
-                width = iview->buf.size;
-        } else {
-                width = u_minify(layout->width, iview->first_level);
-        }
-
-        if (pan_is_bifrost(dev)) {
-                pan_pack(out, BIFROST_TEXTURE, cfg) {
-                        cfg.dimension = iview->dim;
-                        cfg.format = dev->formats[format].hw;
-                        cfg.width = width;
-                        cfg.height = u_minify(layout->height, iview->first_level);
-                        if (iview->dim == MALI_TEXTURE_DIMENSION_3D)
-                                cfg.depth = u_minify(layout->depth, iview->first_level);
-                        else
-                                cfg.sample_count = layout->nr_samples;
-                        cfg.swizzle = swizzle;
-                        cfg.texel_ordering =
-                                panfrost_modifier_to_layout(layout->modifier);
-                        cfg.levels = iview->last_level - iview->first_level + 1;
-                        cfg.array_size = array_size;
-                        cfg.surfaces = payload->gpu;
-
-                        /* We specify API-level LOD clamps in the sampler descriptor
-                         * and use these clamps simply for bounds checking */
-                        cfg.minimum_lod = FIXED_16(0, false);
-                        cfg.maximum_lod = FIXED_16(cfg.levels - 1, false);
-                }
-        } else {
-                pan_pack(out, MIDGARD_TEXTURE, cfg) {
-                        cfg.width = width;
-                        cfg.height = u_minify(layout->height, iview->first_level);
-                        if (iview->dim == MALI_TEXTURE_DIMENSION_3D)
-                                cfg.depth = u_minify(layout->depth, iview->first_level);
-                        else
-                                cfg.sample_count = layout->nr_samples;
-                        cfg.array_size = array_size;
-                        cfg.format = panfrost_pipe_format_v6[format].hw;
-                        cfg.dimension = iview->dim;
-                        cfg.texel_ordering =
-                                panfrost_modifier_to_layout(layout->modifier);
-                        cfg.manual_stride = manual_stride;
-                        cfg.levels = iview->last_level - iview->first_level + 1;
-                        cfg.swizzle = swizzle;
-                };
-        }
-}
-
-/* Computes sizes for checksumming, which is 8 bytes per 16x16 tile.
- * Checksumming is believed to be a CRC variant (CRC64 based on the size?).
- * This feature is also known as "transaction elimination". */
-
-#define CHECKSUM_TILE_WIDTH 16
-#define CHECKSUM_TILE_HEIGHT 16
-#define CHECKSUM_BYTES_PER_TILE 8
-
-unsigned
-panfrost_compute_checksum_size(
-        struct pan_image_slice_layout *slice,
-        unsigned width,
-        unsigned height)
-{
-        unsigned tile_count_x = DIV_ROUND_UP(width, CHECKSUM_TILE_WIDTH);
-        unsigned tile_count_y = DIV_ROUND_UP(height, CHECKSUM_TILE_HEIGHT);
-
-        slice->crc.stride = tile_count_x * CHECKSUM_BYTES_PER_TILE;
-
-        return slice->crc.stride * tile_count_y;
-}
-
-unsigned
-panfrost_get_layer_stride(const struct pan_image_layout *layout,
-                          unsigned level)
-{
-        if (layout->dim != MALI_TEXTURE_DIMENSION_3D)
-                return layout->array_stride;
-        else if (drm_is_afbc(layout->modifier))
-                return layout->slices[level].afbc.surface_stride;
-        else
-                return layout->slices[level].surface_stride;
-}
-
-/* Computes the offset into a texture at a particular level/face. Add to
- * the base address of a texture to get the address to that level/face */
-
-unsigned
-panfrost_texture_offset(const struct pan_image_layout *layout,
-                        unsigned level, unsigned array_idx,
-                        unsigned surface_idx)
-{
-        return layout->slices[level].offset +
-               (array_idx * layout->array_stride) +
-               (surface_idx * layout->slices[level].surface_stride);
+        return layout->slices[level].offset +
+               (array_idx * layout->array_stride) +
+               (surface_idx * layout->slices[level].surface_stride);
 }
 
 bool
@@ -774,3 +345,418 @@ pan_iview_get_surface(const struct pan_image_view *iview,
                                                      array_idx, surface_idx);
         }
 }
+
+#else /* ifndef PAN_ARCH */
+
+/* A Scalable Texture Compression (ASTC) corresponds to just a few texture type
+ * in the hardware, but in fact can be parametrized to have various widths and
+ * heights for the so-called "stretch factor". It turns out these parameters
+ * are stuffed in the bottom bits of the payload pointers. This functions
+ * computes these magic stuffing constants based on the ASTC format in use. The
+ * constant in a given dimension is 3-bits, and two are stored side-by-side for
+ * each active dimension.
+ */
+
+static unsigned
+panfrost_astc_stretch(unsigned dim)
+{
+        assert(dim >= 4 && dim <= 12);
+        return MIN2(dim, 11) - 4;
+}
+
+/* Texture addresses are tagged with information about compressed formats.
+ * AFBC uses a bit for whether the colorspace transform is enabled (RGB and
+ * RGBA only).
+ * For ASTC, this is a "stretch factor" encoding the block size. */
+
+static unsigned
+panfrost_compression_tag(const struct util_format_description *desc,
+                         enum mali_texture_dimension dim,
+                         uint64_t modifier)
+{
+        if (drm_is_afbc(modifier)) {
+                unsigned flags = (modifier & AFBC_FORMAT_MOD_YTR) ?
+                                 MALI_AFBC_SURFACE_FLAG_YTR : 0;
+
+#if PAN_ARCH >= 6
+                /* Prefetch enable */
+                flags |= MALI_AFBC_SURFACE_FLAG_PREFETCH;
+
+                /* Wide blocks (> 16x16) */
+                if (panfrost_block_dim(modifier, true, 0) > 16)
+                        flags |= MALI_AFBC_SURFACE_FLAG_WIDE_BLOCK;
+
+                /* Used to make sure AFBC headers don't point outside the AFBC
+                 * body. HW is using the AFBC surface stride to do this check,
+                 * which doesn't work for 3D textures because the surface
+                 * stride does not cover the body. Only supported on v7+.
+                 */
+#endif
+
+#if PAN_ARCH >= 7
+                if (dim != MALI_TEXTURE_DIMENSION_3D)
+                        flags |= MALI_AFBC_SURFACE_FLAG_CHECK_PAYLOAD_RANGE;
+#endif
+
+                return flags;
+        } else if (desc->layout == UTIL_FORMAT_LAYOUT_ASTC) {
+                return (panfrost_astc_stretch(desc->block.height) << 3) |
+                        panfrost_astc_stretch(desc->block.width);
+        } else {
+                return 0;
+        }
+}
+
+/* Cubemaps have 6 faces as "layers" in between each actual layer. We
+ * need to fix this up. TODO: logic wrong in the asserted out cases ...
+ * can they happen, perhaps from cubemap arrays? */
+
+static void
+panfrost_adjust_cube_dimensions(
+                unsigned *first_face, unsigned *last_face,
+                unsigned *first_layer, unsigned *last_layer)
+{
+        *first_face = *first_layer % 6;
+        *last_face = *last_layer % 6;
+        *first_layer /= 6;
+        *last_layer /= 6;
+
+        assert((*first_layer == *last_layer) || (*first_face == 0 && *last_face == 5));
+}
+
+/* Following the texture descriptor is a number of pointers. How many? */
+
+static unsigned
+panfrost_texture_num_elements(
+                unsigned first_level, unsigned last_level,
+                unsigned first_layer, unsigned last_layer,
+                unsigned nr_samples,
+                bool is_cube, bool manual_stride)
+{
+        unsigned first_face  = 0, last_face = 0;
+
+        if (is_cube) {
+                panfrost_adjust_cube_dimensions(&first_face, &last_face,
+                                &first_layer, &last_layer);
+        }
+
+        unsigned levels = 1 + last_level - first_level;
+        unsigned layers = 1 + last_layer - first_layer;
+        unsigned faces  = 1 + last_face  - first_face;
+        unsigned num_elements = levels * layers * faces * MAX2(nr_samples, 1);
+
+        if (manual_stride)
+                num_elements *= 2;
+
+        return num_elements;
+}
+
+/* Conservative estimate of the size of the texture payload a priori.
+ * Average case, size equal to the actual size. Worst case, off by 2x (if
+ * a manual stride is not needed on a linear texture). Returned value
+ * must be greater than or equal to the actual size, so it's safe to use
+ * as an allocation amount */
+
+unsigned
+GENX(panfrost_estimate_texture_payload_size)(const struct pan_image_view *iview)
+{
+        /* Assume worst case */
+        unsigned manual_stride = PAN_ARCH >= 6 ||
+                                 (iview->image->layout.modifier == DRM_FORMAT_MOD_LINEAR);
+
+        unsigned elements =
+                panfrost_texture_num_elements(iview->first_level, iview->last_level,
+                                              iview->first_layer, iview->last_layer,
+                                              iview->image->layout.nr_samples,
+                                              iview->dim == MALI_TEXTURE_DIMENSION_CUBE,
+                                              manual_stride);
+
+        return sizeof(mali_ptr) * elements;
+}
+
+struct panfrost_surface_iter {
+        unsigned layer, last_layer;
+        unsigned level, first_level, last_level;
+        unsigned face, first_face, last_face;
+        unsigned sample, first_sample, last_sample;
+};
+
+static void
+panfrost_surface_iter_begin(struct panfrost_surface_iter *iter,
+                            unsigned first_layer, unsigned last_layer,
+                            unsigned first_level, unsigned last_level,
+                            unsigned first_face, unsigned last_face,
+                            unsigned nr_samples)
+{
+        iter->layer = first_layer;
+        iter->last_layer = last_layer;
+        iter->level = iter->first_level = first_level;
+        iter->last_level = last_level;
+        iter->face = iter->first_face = first_face;
+        iter->last_face = last_face;
+        iter->sample = iter->first_sample = 0;
+        iter->last_sample = nr_samples - 1;
+}
+
+static bool
+panfrost_surface_iter_end(const struct panfrost_surface_iter *iter)
+{
+        return iter->layer > iter->last_layer;
+}
+
+static void
+panfrost_surface_iter_next(struct panfrost_surface_iter *iter)
+{
+#define INC_TEST(field) \
+        do { \
+                if (iter->field++ < iter->last_ ## field) \
+                       return; \
+                iter->field = iter->first_ ## field; \
+        } while (0)
+
+        /* Ordering is different on v7: inner loop is iterating on levels */
+        if (PAN_ARCH >= 7)
+                INC_TEST(level);
+
+        INC_TEST(sample);
+        INC_TEST(face);
+
+        if (PAN_ARCH < 7)
+                INC_TEST(level);
+
+        iter->layer++;
+
+#undef INC_TEST
+}
+
+static void
+panfrost_get_surface_strides(const struct pan_image_layout *layout,
+                             unsigned l,
+                             int32_t *row_stride, int32_t *surf_stride)
+{
+        const struct pan_image_slice_layout *slice = &layout->slices[l];
+
+        if (drm_is_afbc(layout->modifier)) {
+                /* Pre v7 don't have a row stride field. This field is
+                 * repurposed as a Y offset which we don't use */
+                *row_stride = PAN_ARCH < 7 ? 0 : slice->afbc.row_stride;
+                *surf_stride = slice->afbc.surface_stride;
+        } else {
+                *row_stride = slice->row_stride;
+                *surf_stride = slice->surface_stride;
+        }
+}
+
+static mali_ptr
+panfrost_get_surface_pointer(const struct pan_image_layout *layout,
+                             enum mali_texture_dimension dim,
+                             mali_ptr base,
+                             unsigned l, unsigned w, unsigned f, unsigned s)
+{
+        unsigned face_mult = dim == MALI_TEXTURE_DIMENSION_CUBE ? 6 : 1;
+        unsigned offset;
+
+        if (layout->dim == MALI_TEXTURE_DIMENSION_3D) {
+                assert(!f && !s);
+                offset = layout->slices[l].offset +
+                         (w * panfrost_get_layer_stride(layout, l));
+        } else {
+                offset = panfrost_texture_offset(layout, l, (w * face_mult) + f, s);
+        }
+
+        return base + offset;
+}
+
+static void
+panfrost_emit_texture_payload(const struct pan_image_view *iview,
+                              enum pipe_format format,
+                              bool manual_stride,
+                              void *payload)
+{
+        const struct pan_image_layout *layout = &iview->image->layout;
+        const struct util_format_description *desc =
+                util_format_description(format);
+
+        mali_ptr base = iview->image->data.bo->ptr.gpu + iview->image->data.offset;
+
+        if (iview->buf.size) {
+                assert (iview->dim == MALI_TEXTURE_DIMENSION_1D);
+                base += iview->buf.offset;
+        }
+
+        /* panfrost_compression_tag() wants the dimension of the resource, not the
+         * one of the image view (those might differ).
+         */
+        base |= panfrost_compression_tag(desc, layout->dim, layout->modifier);
+
+        /* Inject the addresses in, interleaving array indices, mip levels,
+         * cube faces, and strides in that order */
+
+        unsigned first_layer = iview->first_layer, last_layer = iview->last_layer;
+        unsigned nr_samples = layout->nr_samples;
+        unsigned first_face = 0, last_face = 0;
+
+        if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) {
+                panfrost_adjust_cube_dimensions(&first_face, &last_face,
+                                                &first_layer, &last_layer);
+        }
+
+        struct panfrost_surface_iter iter;
+
+        for (panfrost_surface_iter_begin(&iter, first_layer, last_layer,
+                                         iview->first_level, iview->last_level,
+                                         first_face, last_face, nr_samples);
+             !panfrost_surface_iter_end(&iter);
+             panfrost_surface_iter_next(&iter)) {
+                mali_ptr pointer =
+                        panfrost_get_surface_pointer(layout, iview->dim, base,
+                                                     iter.level, iter.layer,
+                                                     iter.face, iter.sample);
+
+                if (!manual_stride) {
+                        pan_pack(payload, SURFACE, cfg) {
+                                cfg.pointer = pointer;
+                        }
+                        payload += pan_size(SURFACE);
+                } else {
+                        pan_pack(payload, SURFACE_WITH_STRIDE, cfg) {
+                                cfg.pointer = pointer;
+                                panfrost_get_surface_strides(layout, iter.level,
+                                                             &cfg.row_stride,
+                                                             &cfg.surface_stride);
+                        }
+                        payload += pan_size(SURFACE_WITH_STRIDE);
+                }
+        }
+}
+
+/* Check if we need to set a custom stride by computing the "expected"
+ * stride and comparing it to what the user actually wants. Only applies
+ * to linear textures, since tiled/compressed textures have strict
+ * alignment requirements for their strides as it is */
+
+static bool
+panfrost_needs_explicit_stride(const struct pan_image_view *iview)
+{
+        /* Stride is explicit on Bifrost */
+        if (PAN_ARCH >= 6)
+                return true;
+
+        if (iview->image->layout.modifier != DRM_FORMAT_MOD_LINEAR)
+                return false;
+
+        unsigned bytes_per_block = util_format_get_blocksize(iview->format);
+        unsigned block_w = util_format_get_blockwidth(iview->format);
+
+        for (unsigned l = iview->first_level; l <= iview->last_level; ++l) {
+                unsigned actual = iview->image->layout.slices[l].line_stride;
+                unsigned expected =
+                        DIV_ROUND_UP(u_minify(iview->image->layout.width, l), block_w) *
+                        bytes_per_block;
+
+                if (actual != expected)
+                        return true;
+        }
+
+        return false;
+}
+
+/* Map modifiers to mali_texture_layout for packing in a texture descriptor */
+
+static enum mali_texture_layout
+panfrost_modifier_to_layout(uint64_t modifier)
+{
+        if (drm_is_afbc(modifier))
+                return MALI_TEXTURE_LAYOUT_AFBC;
+        else if (modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED)
+                return MALI_TEXTURE_LAYOUT_TILED;
+        else if (modifier == DRM_FORMAT_MOD_LINEAR)
+                return MALI_TEXTURE_LAYOUT_LINEAR;
+        else
+                unreachable("Invalid modifer");
+}
+
+void
+GENX(panfrost_new_texture)(const struct panfrost_device *dev,
+                           const struct pan_image_view *iview,
+                           void *out, const struct panfrost_ptr *payload)
+{
+        const struct pan_image_layout *layout = &iview->image->layout;
+        enum pipe_format format = iview->format;
+        unsigned swizzle;
+
+        if (PAN_ARCH == 7 && util_format_is_depth_or_stencil(format)) {
+                /* v7 doesn't have an _RRRR component order, combine the
+                 * user swizzle with a .XXXX swizzle to emulate that.
+                 */
+                static const unsigned char replicate_x[4] = {
+                        PIPE_SWIZZLE_X, PIPE_SWIZZLE_X,
+                        PIPE_SWIZZLE_X, PIPE_SWIZZLE_X,
+                };
+                unsigned char patched_swizzle[4];
+
+                util_format_compose_swizzles(replicate_x,
+                                             iview->swizzle,
+                                             patched_swizzle);
+                swizzle = panfrost_translate_swizzle_4(patched_swizzle);
+        } else {
+                swizzle = panfrost_translate_swizzle_4(iview->swizzle);
+        }
+
+        bool manual_stride =
+                panfrost_needs_explicit_stride(iview);
+
+        panfrost_emit_texture_payload(iview, format,
+                                      manual_stride,
+                                      payload->cpu);
+
+        unsigned array_size = iview->last_layer - iview->first_layer + 1;
+
+        if (iview->dim == MALI_TEXTURE_DIMENSION_CUBE) {
+                assert(iview->first_layer % 6 == 0);
+                assert(iview->last_layer % 6 == 5);
+                array_size /=  6;
+        }
+
+        unsigned width;
+
+        if (iview->buf.size) {
+                assert(iview->dim == MALI_TEXTURE_DIMENSION_1D);
+                assert(!iview->first_level && !iview->last_level);
+                assert(!iview->first_layer && !iview->last_layer);
+                assert(layout->nr_samples == 1);
+                assert(layout->height == 1 && layout->depth == 1);
+                assert(iview->buf.offset + iview->buf.size <= layout->width);
+                width = iview->buf.size;
+        } else {
+                width = u_minify(layout->width, iview->first_level);
+        }
+
+        pan_pack(out, TEXTURE, cfg) {
+                cfg.dimension = iview->dim;
+                cfg.format = dev->formats[format].hw;
+                cfg.width = width;
+                cfg.height = u_minify(layout->height, iview->first_level);
+                if (iview->dim == MALI_TEXTURE_DIMENSION_3D)
+                        cfg.depth = u_minify(layout->depth, iview->first_level);
+                else
+                        cfg.sample_count = layout->nr_samples;
+                cfg.swizzle = swizzle;
+                cfg.texel_ordering =
+                        panfrost_modifier_to_layout(layout->modifier);
+                cfg.levels = iview->last_level - iview->first_level + 1;
+                cfg.array_size = array_size;
+
+#if PAN_ARCH >= 6
+                cfg.surfaces = payload->gpu;
+
+                /* We specify API-level LOD clamps in the sampler descriptor
+                 * and use these clamps simply for bounds checking */
+                cfg.minimum_lod = FIXED_16(0, false);
+                cfg.maximum_lod = FIXED_16(cfg.levels - 1, false);
+#else
+                cfg.manual_stride = manual_stride;
+#endif
+        }
+}
+#endif /* ifdef PAN_ARCH */
diff --git a/src/panfrost/lib/pan_texture.h b/src/panfrost/lib/pan_texture.h
index 0b797b9fc11..992731791ff 100644
--- a/src/panfrost/lib/pan_texture.h
+++ b/src/panfrost/lib/pan_texture.h
@@ -28,6 +28,8 @@
 #ifndef __PAN_TEXTURE_H
 #define __PAN_TEXTURE_H
 
+#include "gen_macros.h"
+
 #include <stdbool.h>
 #include "drm-uapi/drm_fourcc.h"
 #include "util/format/u_format.h"
@@ -157,15 +159,16 @@ panfrost_afbc_can_ytr(enum pipe_format format);
 unsigned
 panfrost_block_dim(uint64_t modifier, bool width, unsigned plane);
 
+#ifdef PAN_ARCH
 unsigned
-panfrost_estimate_texture_payload_size(const struct panfrost_device *dev,
-                                       const struct pan_image_view *iview);
+GENX(panfrost_estimate_texture_payload_size)(const struct pan_image_view *iview);
 
 void
-panfrost_new_texture(const struct panfrost_device *dev,
-                     const struct pan_image_view *iview,
-                     void *out,
-                     const struct panfrost_ptr *payload);
+GENX(panfrost_new_texture)(const struct panfrost_device *dev,
+                           const struct pan_image_view *iview,
+                           void *out,
+                           const struct panfrost_ptr *payload);
+#endif
 
 unsigned
 panfrost_get_layer_stride(const struct pan_image_layout *layout,
diff --git a/src/panfrost/vulkan/panvk_vX_image.c b/src/panfrost/vulkan/panvk_vX_image.c
index f75f7b21305..232fe270336 100644
--- a/src/panfrost/vulkan/panvk_vX_image.c
+++ b/src/panfrost/vulkan/panvk_vX_image.c
@@ -127,7 +127,7 @@ panvk_per_arch(CreateImageView)(VkDevice _device,
 
    struct panfrost_device *pdev = &device->physical_device->pdev;
    unsigned bo_size =
-      panfrost_estimate_texture_payload_size(pdev, &view->pview) +
+      GENX(panfrost_estimate_texture_payload_size)(&view->pview) +
       pan_size(TEXTURE);
 
    unsigned surf_descs_offset = PAN_ARCH <= 5 ? pan_size(TEXTURE) : 0;
@@ -142,7 +142,7 @@ panvk_per_arch(CreateImageView)(VkDevice _device,
                     &view->desc : view->bo->ptr.cpu;
 
    STATIC_ASSERT(sizeof(view->desc) >= pan_size(TEXTURE));
-   panfrost_new_texture(pdev, &view->pview, tex_desc, &surf_descs);
+   GENX(panfrost_new_texture)(pdev, &view->pview, tex_desc, &surf_descs);
 
    *pView = panvk_image_view_to_handle(view);
    return VK_SUCCESS;



More information about the mesa-commit mailing list