nvk: support multiple miplevels

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>
This commit is contained in:
Karol Herbst 2022-06-10 22:48:45 +02:00 committed by Marge Bot
parent d8a9d662e4
commit e49a66c40c
5 changed files with 106 additions and 67 deletions

View 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);

View 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;

View file

@ -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;
}

View 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

View 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