Merge pull request #15727 from hrydgard/texture-3d

Implement the PSP's equal-size mips "3D texturing"
This commit is contained in:
Henrik Rydgård
2022-08-01 08:35:43 +02:00
committed by GitHub
42 changed files with 450 additions and 192 deletions
+7 -5
View File
@@ -31,7 +31,7 @@ static bool IsDepthStencilFormat(VkFormat format) {
}
}
bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) {
bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) {
if (w == 0 || h == 0 || numMips == 0) {
ERROR_LOG(G3D, "Can't create a zero-size VulkanTexture");
return false;
@@ -41,17 +41,18 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
width_ = w;
height_ = h;
depth_ = depth;
numMips_ = numMips;
format_ = format;
VkImageAspectFlags aspect = IsDepthStencilFormat(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
VkImageCreateInfo image_create_info{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.imageType = depth > 1 ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
image_create_info.format = format_;
image_create_info.extent.width = width_;
image_create_info.extent.height = height_;
image_create_info.extent.depth = 1;
image_create_info.extent.depth = depth;
image_create_info.mipLevels = numMips;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
@@ -98,7 +99,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
// Create the view while we're at it.
VkImageViewCreateInfo view_info{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
view_info.image = image_;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.viewType = depth > 1 ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D;
view_info.format = format_;
if (mapping) {
view_info.components = *mapping;
@@ -122,11 +123,12 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
}
// TODO: Batch these.
void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) {
void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, int depthLayer, VkBuffer buffer, uint32_t offset, size_t rowLength) {
VkBufferImageCopy copy_region{};
copy_region.bufferOffset = offset;
copy_region.bufferRowLength = (uint32_t)rowLength;
copy_region.bufferImageHeight = 0; // 2D
copy_region.imageOffset.z = depthLayer;
copy_region.imageExtent.width = mipWidth;
copy_region.imageExtent.height = mipHeight;
copy_region.imageExtent.depth = 1;
+9 -6
View File
@@ -22,9 +22,11 @@ public:
// Fast uploads from buffer. Mipmaps supported.
// Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip.
// When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
bool CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr);
bool CreateDirect(VkCommandBuffer cmd, int w, int h, int depth, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr);
void ClearMip(VkCommandBuffer cmd, int mip, uint32_t value);
void UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels
// Can also be used to copy individual levels of a 3D texture.
void UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, int depthLayer, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels
void GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bool fromCompute);
void EndCreate(VkCommandBuffer cmd, bool vertexTexture, VkPipelineStageFlags prevStage, VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
@@ -62,10 +64,11 @@ private:
VkImageView view_ = VK_NULL_HANDLE;
VmaAllocation allocation_ = VK_NULL_HANDLE;
int32_t width_ = 0;
int32_t height_ = 0;
int32_t numMips_ = 1;
int16_t width_ = 0;
int16_t height_ = 0;
int16_t numMips_ = 1;
int16_t depth_ = 1;
VkFormat format_ = VK_FORMAT_UNDEFINED;
size_t offset_ = 0;
std::string tag_;
};
+5 -4
View File
@@ -640,7 +640,7 @@ VulkanTexture *VKContext::GetNullTexture() {
nullTexture_->SetTag("Null");
int w = 8;
int h = 8;
nullTexture_->CreateDirect(cmdInit, w, h, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
nullTexture_->CreateDirect(cmdInit, w, h, 1, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
uint32_t bindOffset;
VkBuffer bindBuf;
@@ -651,7 +651,7 @@ VulkanTexture *VKContext::GetNullTexture() {
data[y*w + x] = 0; // black
}
}
nullTexture_->UploadMip(cmdInit, 0, w, h, bindBuf, bindOffset, w);
nullTexture_->UploadMip(cmdInit, 0, w, h, 0, bindBuf, bindOffset, w);
nullTexture_->EndCreate(cmdInit, false, VK_PIPELINE_STAGE_TRANSFER_BIT);
} else {
nullTexture_->Touch();
@@ -733,7 +733,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur
usageBits |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
if (!vkTex_->CreateDirect(cmd, width_, height_, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits)) {
if (!vkTex_->CreateDirect(cmd, width_, height_, 1, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits)) {
ERROR_LOG(G3D, "Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_);
return false;
}
@@ -755,7 +755,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur
} else {
offset = push->PushAligned((const void *)desc.initData[i], size, 16, &buf);
}
vkTex_->UploadMip(cmd, i, w, h, buf, offset, w);
vkTex_->UploadMip(cmd, i, w, h, 0, buf, offset, w);
w = (w + 1) / 2;
h = (h + 1) / 2;
d = (d + 1) / 2;
@@ -787,6 +787,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
caps_.framebufferDepthBlitSupported = false; // Can be checked for.
caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case.
caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan.
caps_.texture3DSupported = true;
auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDeviceIndex()).properties;
switch (deviceProps.vendorID) {