panfrost: mandate proper alignment requirement depending format and arch
authorItalo Nicola <italonicola@collabora.com>
Wed, 1 Feb 2023 19:21:26 +0000 (19:21 +0000)
committerMarge Bot <emma+marge@anholt.net>
Mon, 7 Aug 2023 19:35:12 +0000 (19:35 +0000)
v7+ mandates row_stride alignment to be equal to surface alignment.
AFBC surface alignment is always 16-bytes.
NV12/NV21 formats on v7+ have 16-byte surface alignment.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21109>

src/gallium/drivers/panfrost/pan_resource.c
src/panfrost/lib/pan_layout.c
src/panfrost/lib/pan_texture.h
src/panfrost/lib/tests/test-layout.cpp
src/panfrost/vulkan/panvk_image.c

index 24f7d21..a75d453 100644 (file)
@@ -132,7 +132,8 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen,
       .nr_slices = 1,
    };
 
-   bool valid = pan_image_layout_init(&rsc->image.layout, &explicit_layout);
+   bool valid =
+      pan_image_layout_init(dev, &rsc->image.layout, &explicit_layout);
 
    if (!valid) {
       FREE(rsc);
@@ -491,7 +492,7 @@ panfrost_resource_setup(struct panfrost_device *dev,
       .crc = panfrost_should_checksum(dev, pres),
    };
 
-   ASSERTED bool valid = pan_image_layout_init(&pres->image.layout, NULL);
+   ASSERTED bool valid = pan_image_layout_init(dev, &pres->image.layout, NULL);
    assert(valid);
 }
 
index b63b6e3..abe654e 100644 (file)
@@ -184,6 +184,26 @@ pan_afbc_body_align(uint64_t modifier)
    return (modifier & AFBC_FORMAT_MOD_TILED) ? 4096 : 64;
 }
 
+static inline unsigned
+format_minimum_alignment(const struct panfrost_device *dev,
+                         enum pipe_format format, bool afbc)
+{
+   if (afbc)
+      return 16;
+
+   if (dev->arch < 7)
+      return 63;
+
+   switch (format) {
+   /* For v7+, NV12 and NV21 have a looser alignment requirement of 16 bytes */
+   case PIPE_FORMAT_R8_G8B8_420_UNORM:
+   case PIPE_FORMAT_G8_B8R8_420_UNORM:
+      return 16;
+   default:
+      return 64;
+   }
+}
+
 /* 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". */
@@ -262,7 +282,8 @@ panfrost_texture_offset(const struct pan_image_layout *layout, unsigned level,
 }
 
 bool
-pan_image_layout_init(struct pan_image_layout *layout,
+pan_image_layout_init(const struct panfrost_device *dev,
+                      struct pan_image_layout *layout,
                       const struct pan_image_explicit_layout *explicit_layout)
 {
    /* Explicit stride only work with non-mipmap, non-array, single-sample
@@ -274,9 +295,29 @@ pan_image_layout_init(struct pan_image_layout *layout,
         layout->crc))
       return false;
 
-   /* Mandate 64 byte alignement */
-   if (explicit_layout && (explicit_layout->offset & 63))
-      return false;
+   bool afbc = drm_is_afbc(layout->modifier);
+   int align_req = format_minimum_alignment(dev, layout->format, afbc);
+
+   /* Mandate alignment */
+   if (explicit_layout) {
+      bool rejected = false;
+
+      int align_mask = align_req - 1;
+
+      if (dev->arch >= 7) {
+         rejected = ((explicit_layout->offset & align_mask) ||
+                     (explicit_layout->row_stride & align_mask));
+      } else {
+         rejected = (explicit_layout->offset & align_mask);
+      }
+
+      if (rejected) {
+         mesa_loge(
+            "panfrost: rejecting image due to unsupported offset or stride "
+            "alignment.\n");
+         return false;
+      }
+   }
 
    unsigned fmt_blocksize = util_format_get_blocksize(layout->format);
 
@@ -285,7 +326,6 @@ pan_image_layout_init(struct pan_image_layout *layout,
 
    assert(layout->depth == 1 || layout->nr_samples == 1);
 
-   bool afbc = drm_is_afbc(layout->modifier);
    bool linear = layout->modifier == DRM_FORMAT_MOD_LINEAR;
    bool is_3d = layout->dim == MALI_TEXTURE_DIMENSION_3D;
 
@@ -323,10 +363,17 @@ pan_image_layout_init(struct pan_image_layout *layout,
 
       unsigned row_stride = fmt_blocksize * effective_width * block_size.height;
 
+      /* On v7+ row_stride and offset alignment requirement are equal */
+      if (dev->arch >= 7) {
+         row_stride = ALIGN_POT(row_stride, align_req);
+      }
+
       if (explicit_layout && !afbc) {
          /* Make sure the explicit stride is valid */
-         if (explicit_layout->row_stride < row_stride)
+         if (explicit_layout->row_stride < row_stride) {
+            mesa_loge("panfrost: rejecting image due to invalid row stride.\n");
             return false;
+         }
 
          row_stride = explicit_layout->row_stride;
       } else if (linear) {
@@ -345,8 +392,11 @@ pan_image_layout_init(struct pan_image_layout *layout,
             ALIGN_POT(slice->row_stride * (effective_height / align_h),
                       pan_afbc_body_align(layout->modifier));
 
-         if (explicit_layout && explicit_layout->row_stride < slice->row_stride)
+         if (explicit_layout &&
+             explicit_layout->row_stride < slice->row_stride) {
+            mesa_loge("panfrost: rejecting image due to invalid row stride.\n");
             return false;
+         }
 
          /* AFBC body size */
          slice->afbc.body_size = slice_one_size;
index 7582266..790e34d 100644 (file)
@@ -287,7 +287,8 @@ struct pan_image_explicit_layout {
 };
 
 bool
-pan_image_layout_init(struct pan_image_layout *layout,
+pan_image_layout_init(const struct panfrost_device *dev,
+                      struct pan_image_layout *layout,
                       const struct pan_image_explicit_layout *explicit_layout);
 
 unsigned panfrost_get_legacy_stride(const struct pan_image_layout *layout,
index f47337a..0628e0b 100644 (file)
@@ -267,6 +267,8 @@ TEST(LegacyStride, FromLegacyAFBC)
 /* dEQP-GLES3.functional.texture.format.compressed.etc1_2d_pot */
 TEST(Layout, ImplicitLayoutInterleavedETC2)
 {
+   struct panfrost_device dev = {0};
+
    struct pan_image_layout l = {
       .modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
       .format = PIPE_FORMAT_ETC2_RGB8,
@@ -280,7 +282,7 @@ TEST(Layout, ImplicitLayoutInterleavedETC2)
    unsigned offsets[9] = {0,     8192,  10240, 10752, 10880,
                           11008, 11136, 11264, 11392};
 
-   ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+   ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
 
    for (unsigned i = 0; i < 8; ++i) {
       unsigned size = (offsets[i + 1] - offsets[i]);
@@ -295,6 +297,8 @@ TEST(Layout, ImplicitLayoutInterleavedETC2)
 
 TEST(Layout, ImplicitLayoutInterleavedASTC5x5)
 {
+   struct panfrost_device dev = {0};
+
    struct pan_image_layout l = {
       .modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
       .format = PIPE_FORMAT_ASTC_5x5,
@@ -305,7 +309,7 @@ TEST(Layout, ImplicitLayoutInterleavedASTC5x5)
       .dim = MALI_TEXTURE_DIMENSION_2D,
       .nr_slices = 1};
 
-   ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+   ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
 
    /* The image is 50x50 pixels, with 5x5 blocks. So it is a 10x10 grid of ASTC
     * blocks. 4x4 tiles of ASTC blocks are u-interleaved, so we have to round up
@@ -321,6 +325,8 @@ TEST(Layout, ImplicitLayoutInterleavedASTC5x5)
 
 TEST(Layout, ImplicitLayoutLinearASTC5x5)
 {
+   struct panfrost_device dev = {0};
+
    struct pan_image_layout l = {.modifier = DRM_FORMAT_MOD_LINEAR,
                                 .format = PIPE_FORMAT_ASTC_5x5,
                                 .width = 50,
@@ -330,7 +336,7 @@ TEST(Layout, ImplicitLayoutLinearASTC5x5)
                                 .dim = MALI_TEXTURE_DIMENSION_2D,
                                 .nr_slices = 1};
 
-   ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+   ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
 
    /* The image is 50x50 pixels, with 5x5 blocks. So it is a 10x10 grid of ASTC
     * blocks. Each ASTC block is 16 bytes, so the row stride is 160 bytes,
@@ -346,6 +352,8 @@ TEST(Layout, ImplicitLayoutLinearASTC5x5)
 /* dEQP-GLES3.functional.texture.format.unsized.rgba_unsigned_byte_3d_pot */
 TEST(AFBCLayout, Linear3D)
 {
+   struct panfrost_device dev = {0};
+
    uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC(
       AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE);
 
@@ -358,7 +366,7 @@ TEST(AFBCLayout, Linear3D)
                                 .dim = MALI_TEXTURE_DIMENSION_3D,
                                 .nr_slices = 1};
 
-   ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+   ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
 
    /* AFBC Surface stride is bytes between consecutive surface headers, which is
     * the header size since this is a 3D texture. At superblock size 16x16, the
@@ -384,6 +392,8 @@ TEST(AFBCLayout, Linear3D)
 
 TEST(AFBCLayout, Tiled16x16)
 {
+   struct panfrost_device dev = {0};
+
    uint64_t modifier =
       DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
                               AFBC_FORMAT_MOD_TILED | AFBC_FORMAT_MOD_SPARSE);
@@ -397,7 +407,7 @@ TEST(AFBCLayout, Tiled16x16)
                                 .dim = MALI_TEXTURE_DIMENSION_2D,
                                 .nr_slices = 1};
 
-   ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+   ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
 
    /* The image is 917x417. Superblocks are 16x16, so there are 58x27
     * superblocks. Superblocks are grouped into 8x8 tiles, so there are 8x4
@@ -421,6 +431,8 @@ TEST(AFBCLayout, Tiled16x16)
 
 TEST(AFBCLayout, Linear16x16Minimal)
 {
+   struct panfrost_device dev = {0};
+
    uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC(
       AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE);
 
@@ -433,7 +445,7 @@ TEST(AFBCLayout, Linear16x16Minimal)
                                 .dim = MALI_TEXTURE_DIMENSION_2D,
                                 .nr_slices = 1};
 
-   ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+   ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
 
    /* Image is 1x1 to test for correct alignment everywhere. */
    EXPECT_EQ(l.slices[0].offset, 0);
@@ -446,6 +458,8 @@ TEST(AFBCLayout, Linear16x16Minimal)
 
 TEST(AFBCLayout, Tiled16x16Minimal)
 {
+   struct panfrost_device dev = {0};
+
    uint64_t modifier =
       DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
                               AFBC_FORMAT_MOD_TILED | AFBC_FORMAT_MOD_SPARSE);
@@ -459,7 +473,7 @@ TEST(AFBCLayout, Tiled16x16Minimal)
                                 .dim = MALI_TEXTURE_DIMENSION_2D,
                                 .nr_slices = 1};
 
-   ASSERT_TRUE(pan_image_layout_init(&l, NULL));
+   ASSERT_TRUE(pan_image_layout_init(&dev, &l, NULL));
 
    /* Image is 1x1 to test for correct alignment everywhere. */
    EXPECT_EQ(l.slices[0].offset, 0);
index 5a1d3a6..938eadf 100644 (file)
@@ -70,6 +70,7 @@ panvk_image_create(VkDevice _device, const VkImageCreateInfo *pCreateInfo,
                    uint64_t modifier, const VkSubresourceLayout *plane_layouts)
 {
    VK_FROM_HANDLE(panvk_device, device, _device);
+   const struct panfrost_device *pdev = &device->physical_device->pdev;
    struct panvk_image *image = NULL;
 
    image = vk_image_create(&device->vk, pCreateInfo, alloc, sizeof(*image));
@@ -88,7 +89,7 @@ panvk_image_create(VkDevice _device, const VkImageCreateInfo *pCreateInfo,
       .nr_slices = image->vk.mip_levels,
    };
 
-   pan_image_layout_init(&image->pimage.layout, NULL);
+   pan_image_layout_init(pdev, &image->pimage.layout, NULL);
 
    *pImage = panvk_image_to_handle(image);
    return VK_SUCCESS;