nvk: support multiple miplevels
authorKarol Herbst <kherbst@redhat.com>
Fri, 10 Jun 2022 20:48:45 +0000 (22:48 +0200)
committerMarge Bot <emma+marge@anholt.net>
Fri, 4 Aug 2023 21:31:54 +0000 (21:31 +0000)
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>

src/nouveau/vulkan/nvk_cmd_blit.c
src/nouveau/vulkan/nvk_cmd_copy.c
src/nouveau/vulkan/nvk_image.c
src/nouveau/vulkan/nvk_image.h
src/nouveau/vulkan/nvk_physical_device.c

index 6543b81..c6d41fb 100644 (file)
@@ -23,61 +23,15 @@ nvk_CmdBlitImage2(
    VK_FROM_HANDLE(nvk_image, dst, pBlitImageInfo->dstImage);
    struct nouveau_ws_push *push = cmd->push;
 
-   uint32_t src_depth = src->vk.extent.depth * src->vk.array_layers;
-   uint32_t dst_depth = dst->vk.extent.depth * dst->vk.array_layers;
-
    nouveau_ws_push_ref(push, src->mem->bo, NOUVEAU_WS_BO_RD);
    nouveau_ws_push_ref(push, dst->mem->bo, NOUVEAU_WS_BO_WR);
 
-   VkDeviceSize src_addr = src->mem->bo->offset + src->offset;
-   VkDeviceSize dst_addr = dst->mem->bo->offset + dst->offset;
-
    P_IMMD(push, NV902D, SET_CLIP_ENABLE, V_FALSE);
    P_IMMD(push, NV902D, SET_COLOR_KEY_ENABLE, V_FALSE);
    P_IMMD(push, NV902D, SET_RENDER_ENABLE_C, MODE_TRUE);
 
    P_IMMD(push, NV902D, SET_SRC_FORMAT, src->format->hw_format);
-   if (src->tile.is_tiled) {
-      P_MTHD(push, NV902D, SET_SRC_MEMORY_LAYOUT);
-      P_NV902D_SET_SRC_MEMORY_LAYOUT(push, V_BLOCKLINEAR);
-      P_NV902D_SET_SRC_BLOCK_SIZE(push, {
-         .height = src->tile.y,
-         .depth = src->tile.z,
-      });
-   } else {
-      P_IMMD(push, NV902D, SET_SRC_MEMORY_LAYOUT, V_PITCH);
-   }
-
-   P_MTHD(push, NV902D, SET_SRC_DEPTH);
-   P_NV902D_SET_SRC_DEPTH(push, src_depth);
-
-   P_MTHD(push, NV902D, SET_SRC_PITCH);
-   P_NV902D_SET_SRC_PITCH(push, src->row_stride);
-   P_NV902D_SET_SRC_WIDTH(push, src->vk.extent.width);
-   P_NV902D_SET_SRC_HEIGHT(push, src->vk.extent.height);
-   P_NV902D_SET_SRC_OFFSET_UPPER(push, src_addr >> 32);
-   P_NV902D_SET_SRC_OFFSET_LOWER(push, src_addr & 0xffffffff);
-
    P_IMMD(push, NV902D, SET_DST_FORMAT, dst->format->hw_format);
-   if (dst->tile.is_tiled) {
-      P_MTHD(push, NV902D, SET_DST_MEMORY_LAYOUT);
-      P_NV902D_SET_DST_MEMORY_LAYOUT(push, V_BLOCKLINEAR);
-      P_NV902D_SET_DST_BLOCK_SIZE(push, {
-         .height = dst->tile.y,
-         .depth = dst->tile.z,
-      });
-   } else {
-      P_IMMD(push, NV902D, SET_DST_MEMORY_LAYOUT, V_PITCH);
-   }
-
-   P_MTHD(push, NV902D, SET_DST_DEPTH);
-   P_NV902D_SET_DST_DEPTH(push, dst_depth);
-   P_NV902D_SET_DST_LAYER(push, 0);
-   P_NV902D_SET_DST_PITCH(push, dst->row_stride);
-   P_NV902D_SET_DST_WIDTH(push, dst->vk.extent.width);
-   P_NV902D_SET_DST_HEIGHT(push, dst->vk.extent.height);
-   P_NV902D_SET_DST_OFFSET_UPPER(push, dst_addr >> 32);
-   P_NV902D_SET_DST_OFFSET_LOWER(push, dst_addr & 0xffffffff);
 
    if (pBlitImageInfo->filter == VK_FILTER_NEAREST) {
       P_IMMD(push, NV902D, SET_PIXELS_FROM_MEMORY_SAMPLE_MODE, {
@@ -113,6 +67,15 @@ nvk_CmdBlitImage2(
    for (unsigned r = 0; r < pBlitImageInfo->regionCount; r++) {
       const VkImageBlit2 *region = &pBlitImageInfo->pRegions[r];
 
+      struct nvk_image_level *src_level = &src->level[region->srcSubresource.mipLevel];
+      struct nvk_image_level *dst_level = &dst->level[region->dstSubresource.mipLevel];
+
+      VkDeviceSize src_addr = nvk_image_base_address(src, region->srcSubresource.mipLevel);
+      VkDeviceSize dst_addr = nvk_image_base_address(dst, region->dstSubresource.mipLevel);
+
+      uint32_t src_depth = src_level->extent.depth * src->vk.array_layers;
+      uint32_t dst_depth = dst_level->extent.depth * dst->vk.array_layers;
+
       unsigned x_i = region->dstOffsets[0].x < region->dstOffsets[1].x ? 0 : 1;
       unsigned y_i = region->dstOffsets[0].y < region->dstOffsets[1].y ? 0 : 1;
 
@@ -141,6 +104,47 @@ nvk_CmdBlitImage2(
       src_start_x_fp += scaling_x_fp / 2;
       src_start_y_fp += scaling_y_fp / 2;
 
+      if (src_level->tile.is_tiled) {
+         P_MTHD(push, NV902D, SET_SRC_MEMORY_LAYOUT);
+         P_NV902D_SET_SRC_MEMORY_LAYOUT(push, V_BLOCKLINEAR);
+         P_NV902D_SET_SRC_BLOCK_SIZE(push, {
+            .height = src_level->tile.y,
+            .depth = src_level->tile.z,
+         });
+      } else {
+         P_IMMD(push, NV902D, SET_SRC_MEMORY_LAYOUT, V_PITCH);
+      }
+
+      P_MTHD(push, NV902D, SET_SRC_DEPTH);
+      P_NV902D_SET_SRC_DEPTH(push, src_depth);
+
+      P_MTHD(push, NV902D, SET_SRC_PITCH);
+      P_NV902D_SET_SRC_PITCH(push, src_level->row_stride);
+      P_NV902D_SET_SRC_WIDTH(push, src_level->extent.width);
+      P_NV902D_SET_SRC_HEIGHT(push, src_level->extent.height);
+      P_NV902D_SET_SRC_OFFSET_UPPER(push, src_addr >> 32);
+      P_NV902D_SET_SRC_OFFSET_LOWER(push, src_addr & 0xffffffff);
+
+      if (dst_level->tile.is_tiled) {
+         P_MTHD(push, NV902D, SET_DST_MEMORY_LAYOUT);
+         P_NV902D_SET_DST_MEMORY_LAYOUT(push, V_BLOCKLINEAR);
+         P_NV902D_SET_DST_BLOCK_SIZE(push, {
+            .height = dst_level->tile.y,
+            .depth = dst_level->tile.z,
+         });
+      } else {
+         P_IMMD(push, NV902D, SET_DST_MEMORY_LAYOUT, V_PITCH);
+      }
+
+      P_MTHD(push, NV902D, SET_DST_DEPTH);
+      P_NV902D_SET_DST_DEPTH(push, dst_depth);
+      P_NV902D_SET_DST_LAYER(push, 0);
+      P_NV902D_SET_DST_PITCH(push, dst_level->row_stride);
+      P_NV902D_SET_DST_WIDTH(push, dst_level->extent.width);
+      P_NV902D_SET_DST_HEIGHT(push, dst_level->extent.height);
+      P_NV902D_SET_DST_OFFSET_UPPER(push, dst_addr >> 32);
+      P_NV902D_SET_DST_OFFSET_LOWER(push, dst_addr & 0xffffffff);
+
       P_MTHD(push, NV902D, SET_PIXELS_FROM_MEMORY_DST_X0);
       P_NV902D_SET_PIXELS_FROM_MEMORY_DST_X0(push, dst_start_x);
       P_NV902D_SET_PIXELS_FROM_MEMORY_DST_Y0(push, dst_start_y);
index d21b09e..fe0cebb 100644 (file)
@@ -81,13 +81,15 @@ nouveau_copy_rect_image(
    VkOffset3D offset,
    const VkImageSubresourceLayers *sub_res)
 {
+   struct nvk_image_level *level = &img->level[sub_res->mipLevel];
+
    struct nouveau_copy_buffer buf = {
-      .base_addr = nvk_image_base_address(img),
+      .base_addr = nvk_image_base_address(img, sub_res->mipLevel),
       .offset = vk_image_sanitize_offset(&img->vk, offset),
-      .extent = img->vk.extent,
-      .row_stride = img->row_stride,
-      .layer_stride = img->layer_stride,
-      .tile = img->tile,
+      .extent = level->extent,
+      .row_stride = level->row_stride,
+      .layer_stride = level->layer_stride,
+      .tile = level->tile,
    };
 
    buf.extent.depth *= img->vk.array_layers;
index c4ef7ba..3a1e2be 100644 (file)
  * This ends being quite wasteful, but it's a more or less plain copy of what gallium does
  */
 static struct nvk_tile
-nvk_image_tile_from_create_info(const VkImageCreateInfo *pCreateInfo, uint64_t modifier)
+nvk_image_tile_from_create_info(
+   VkExtent3D extent,
+   const VkImageCreateInfo *pCreateInfo,
+   uint64_t modifier)
 {
+   VkImageTiling tiling = pCreateInfo->tiling;
    struct nvk_tile tile = {};
 
-   switch (pCreateInfo->tiling) {
+   switch (tiling) {
    case VK_IMAGE_TILING_LINEAR:
       tile.is_tiled = false;
       return tile;
@@ -35,8 +39,8 @@ nvk_image_tile_from_create_info(const VkImageCreateInfo *pCreateInfo, uint64_t m
       break;
    }
 
-   uint32_t height = pCreateInfo->extent.height;
-   uint32_t depth = pCreateInfo->extent.depth;
+   uint32_t height = extent.height;
+   uint32_t depth = extent.depth;
 
    // fermi is the baseline anyway (for now)
    tile.is_fermi = true;
@@ -88,8 +92,6 @@ static VkResult nvk_image_init(struct nvk_device *device,
    const VkImageCreateInfo *pCreateInfo)
 {
    uint64_t block_size = vk_format_get_blocksizebits(pCreateInfo->format) / 8;
-   struct nvk_tile tile = nvk_image_tile_from_create_info(pCreateInfo, 0);
-   VkExtent3D block = nvk_image_tile_to_blocks(tile);
 
    vk_image_init(&device->vk, &image->vk, pCreateInfo);
 
@@ -103,10 +105,30 @@ static VkResult nvk_image_init(struct nvk_device *device,
    }
    assert(image->format);
 
-   image->tile = tile;
-   image->row_stride = align(image->vk.extent.width * block_size, block.width);
-   image->layer_stride = align(image->vk.extent.height, block.height) * image->row_stride;
-   image->min_size = image->vk.array_layers * image->vk.extent.depth * image->layer_stride;
+   for (uint32_t l = 0; l < pCreateInfo->mipLevels; l++) {
+      struct nvk_image_level *level = &image->level[l];
+      VkExtent3D extent = vk_image_mip_level_extent(&image->vk, l);
+      struct nvk_tile tile = nvk_image_tile_from_create_info(
+         extent,
+         pCreateInfo,
+         0
+      );
+      VkExtent3D block = nvk_image_tile_to_blocks(tile);
+
+      /* need to apply a minimum alignment */
+      image->min_size = align(image->min_size, 0x80);
+      level->offset = image->min_size;
+      level->tile = tile;
+      level->extent = extent;
+      level->row_stride = align(extent.width * block_size, block.width);
+
+      /* for untiled images we need to align the row_stride to 0x80 */
+      if (!tile.is_tiled)
+         level->row_stride = align(level->row_stride, 0x80);
+
+      level->layer_stride = level->row_stride * align(extent.height, block.height);
+      image->min_size += level->layer_stride * align(extent.depth * image->vk.array_layers, block.depth);
+   }
 
    return VK_SUCCESS;
 }
index c54ee14..f462338 100644 (file)
@@ -8,6 +8,8 @@
 #include "nouveau_push.h"
 #include "vulkan/runtime/vk_image.h"
 
+#define NVK_MAX_MIP_LEVELS 7
+
 /* x can either be 0x0 or 0xe
  *   0x0: 64 blocks
  *   0xe: 16 blocks (not quite sure how that's even used, so we don't use it)
@@ -27,6 +29,16 @@ struct nvk_tile {
 };
 
 struct nvk_format;
+
+struct nvk_image_level {
+   VkDeviceSize offset;
+   VkExtent3D extent;
+
+   uint32_t row_stride;
+   uint32_t layer_stride;
+   struct nvk_tile tile;
+};
+
 struct nvk_image {
    struct vk_image vk;
    struct nvk_device_memory *mem;
@@ -35,9 +47,7 @@ struct nvk_image {
    VkDeviceSize min_size;
 
    struct nvk_format *format;
-   uint32_t row_stride;
-   uint32_t layer_stride;
-   struct nvk_tile tile;
+   struct nvk_image_level level[NVK_MAX_MIP_LEVELS];
 };
 
 VK_DEFINE_HANDLE_CASTS(nvk_image, vk.base, VkImage, VK_OBJECT_TYPE_IMAGE)
@@ -51,9 +61,9 @@ nvk_push_image_ref(struct nouveau_ws_push *push,
 }
 
 static inline uint64_t
-nvk_image_base_address(struct nvk_image *image)
+nvk_image_base_address(struct nvk_image *image, uint32_t level)
 {
-   return image->mem->bo->offset + image->offset;
+   return image->mem->bo->offset + image->offset + image->level[level].offset;
 }
 
 #endif
index b7432f8..2e75dfc 100644 (file)
@@ -3,6 +3,7 @@
 #include "nvk_bo_sync.h"
 #include "nvk_entrypoints.h"
 #include "nvk_format.h"
+#include "nvk_image.h"
 #include "nvk_instance.h"
 #include "nvk_wsi.h"
 
@@ -433,7 +434,7 @@ nvk_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
       else
          return VK_ERROR_FORMAT_NOT_SUPPORTED;
 
-      base_props->imageFormatProperties.maxMipLevels = 1;
+      base_props->imageFormatProperties.maxMipLevels = NVK_MAX_MIP_LEVELS;
       base_props->imageFormatProperties.maxArrayLayers = 2048;
       base_props->imageFormatProperties.sampleCounts = 0;
       base_props->imageFormatProperties.maxResourceSize = 0xffffffff; // TODO proper value