pvr: Fix cubemap layer stride
authorKarmjit Mahil <Karmjit.Mahil@imgtec.com>
Tue, 19 Sep 2023 16:08:41 +0000 (17:08 +0100)
committerMarge Bot <emma+marge@anholt.net>
Mon, 9 Oct 2023 13:35:56 +0000 (13:35 +0000)
The hw calculates the layer stride with the assumption of a full
mip chain being there even though certain levels might never be
used.

Fix the `layer_size` by accounting for any missing mip levels.

Fixes: 8991e6464 ("pvr: Add a Vulkan driver for Imagination Technologies PowerVR Rogue GPUs")
Reported-by: James Glanville <james.glanville@imgtec.com>
Signed-off-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com>
Reviewed-by: Frank Binns <frank.binns@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25344>

src/imagination/vulkan/pvr_image.c

index 88c4bed..c215441 100644 (file)
@@ -98,20 +98,36 @@ static void pvr_image_setup_mip_levels(struct pvr_image *image)
    image->layer_size = 0;
 
    for (uint32_t i = 0; i < image->vk.mip_levels; i++) {
-      const uint32_t height = u_minify(extent.height, i);
-      const uint32_t width = u_minify(extent.width, i);
-      const uint32_t depth = u_minify(extent.depth, i);
       struct pvr_mip_level *mip_level = &image->mip_levels[i];
 
-      mip_level->pitch = cpp * ALIGN(width, extent_alignment);
-      mip_level->height_pitch = ALIGN(height, extent_alignment);
+      mip_level->pitch = cpp * ALIGN(extent.width, extent_alignment);
+      mip_level->height_pitch = ALIGN(extent.height, extent_alignment);
       mip_level->size = image->vk.samples * mip_level->pitch *
                         mip_level->height_pitch *
-                        ALIGN(depth, extent_alignment);
+                        ALIGN(extent.depth, extent_alignment);
       mip_level->size = ALIGN(mip_level->size, level_alignment);
       mip_level->offset = image->layer_size;
 
       image->layer_size += mip_level->size;
+
+      extent.height = u_minify(extent.height, 1);
+      extent.width = u_minify(extent.width, 1);
+      extent.depth = u_minify(extent.depth, 1);
+   }
+
+   /* The hw calculates layer strides as if a full mip chain up until 1x1x1
+    * were present so we need to account for that in the `layer_size`.
+    */
+   while (extent.height != 1 || extent.width != 1 || extent.depth != 1) {
+      const uint32_t height_pitch = ALIGN(extent.height, extent_alignment);
+      const uint32_t pitch = cpp * ALIGN(extent.width, extent_alignment);
+
+      image->layer_size += image->vk.samples * pitch * height_pitch *
+                           ALIGN(extent.depth, extent_alignment);
+
+      extent.height = u_minify(extent.height, 1);
+      extent.width = u_minify(extent.width, 1);
+      extent.depth = u_minify(extent.depth, 1);
    }
 
    /* TODO: It might be useful to store the alignment in the image so it can be