From e49a66c40cc90982ec6aa3214e4ea3c0f75bcdd5 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Fri, 10 Jun 2022 22:48:45 +0200 Subject: [PATCH] nvk: support multiple miplevels Part-of: --- src/nouveau/vulkan/nvk_cmd_blit.c | 96 ++++++++++++------------ src/nouveau/vulkan/nvk_cmd_copy.c | 12 +-- src/nouveau/vulkan/nvk_image.c | 42 ++++++++--- src/nouveau/vulkan/nvk_image.h | 20 +++-- src/nouveau/vulkan/nvk_physical_device.c | 3 +- 5 files changed, 106 insertions(+), 67 deletions(-) diff --git a/src/nouveau/vulkan/nvk_cmd_blit.c b/src/nouveau/vulkan/nvk_cmd_blit.c index 6543b81fb5a..c6d41fbd620 100644 --- a/src/nouveau/vulkan/nvk_cmd_blit.c +++ b/src/nouveau/vulkan/nvk_cmd_blit.c @@ -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); diff --git a/src/nouveau/vulkan/nvk_cmd_copy.c b/src/nouveau/vulkan/nvk_cmd_copy.c index d21b09e61aa..fe0cebb3989 100644 --- a/src/nouveau/vulkan/nvk_cmd_copy.c +++ b/src/nouveau/vulkan/nvk_cmd_copy.c @@ -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; diff --git a/src/nouveau/vulkan/nvk_image.c b/src/nouveau/vulkan/nvk_image.c index c4ef7baba93..3a1e2be9467 100644 --- a/src/nouveau/vulkan/nvk_image.c +++ b/src/nouveau/vulkan/nvk_image.c @@ -12,11 +12,15 @@ * 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; } diff --git a/src/nouveau/vulkan/nvk_image.h b/src/nouveau/vulkan/nvk_image.h index c54ee14d3b2..f462338cde8 100644 --- a/src/nouveau/vulkan/nvk_image.h +++ b/src/nouveau/vulkan/nvk_image.h @@ -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 diff --git a/src/nouveau/vulkan/nvk_physical_device.c b/src/nouveau/vulkan/nvk_physical_device.c index b7432f83a8f..2e75dfce08b 100644 --- a/src/nouveau/vulkan/nvk_physical_device.c +++ b/src/nouveau/vulkan/nvk_physical_device.c @@ -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