Cemu/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp
2022-08-22 22:21:23 +02:00

142 lines
5.3 KiB
C++

#include "Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
LatteTextureVk::LatteTextureVk(class VulkanRenderer* vkRenderer, uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle,
Latte::E_HWTILEMODE tileMode, bool isDepth)
: LatteTexture(textureUnit, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_vkr(vkRenderer)
{
vkObjTex = new VKRObjectTexture();
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
sint32 effectiveBaseWidth = width;
sint32 effectiveBaseHeight = height;
sint32 effectiveBaseDepth = depth;
if (overwriteInfo.hasResolutionOverwrite)
{
effectiveBaseWidth = overwriteInfo.width;
effectiveBaseHeight = overwriteInfo.height;
effectiveBaseDepth = overwriteInfo.depth;
}
effectiveBaseDepth = std::max(1, effectiveBaseDepth);
imageInfo.extent.width = effectiveBaseWidth;
imageInfo.extent.height = effectiveBaseHeight;
imageInfo.mipLevels = mipLevels;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
if (dim == Latte::E_DIM::DIM_3D)
{
imageInfo.extent.depth = effectiveBaseDepth;
imageInfo.arrayLayers = 1;
imageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
}
else
{
imageInfo.extent.depth = 1;
imageInfo.arrayLayers = effectiveBaseDepth;
if (dim != Latte::E_DIM::DIM_1D && (effectiveBaseDepth % 6) == 0 && effectiveBaseWidth == effectiveBaseHeight)
imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
}
VulkanRenderer::FormatInfoVK texFormatInfo;
vkRenderer->GetTextureFormatInfoVK(format, isDepth, dim, effectiveBaseWidth, effectiveBaseHeight, &texFormatInfo);
hasStencil = (texFormatInfo.vkImageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
imageInfo.format = texFormatInfo.vkImageFormat;
vkObjTex->m_imageAspect = texFormatInfo.vkImageAspect;
if (isDepth == false && texFormatInfo.isCompressed)
{
imageInfo.flags |= VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
}
if (isDepth == false)
imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
if (isDepth)
{
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
else
{
if(Latte::IsCompressedFormat(format) == false && texFormatInfo.vkImageFormat != VK_FORMAT_R4G4_UNORM_PACK8) // Vulkan's R4G4 cant be used as a color attachment
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
if (dim == Latte::E_DIM::DIM_2D)
imageInfo.imageType = VK_IMAGE_TYPE_2D;
else if (dim == Latte::E_DIM::DIM_1D)
imageInfo.imageType = VK_IMAGE_TYPE_1D;
else if (dim == Latte::E_DIM::DIM_3D)
imageInfo.imageType = VK_IMAGE_TYPE_3D;
else if (dim == Latte::E_DIM::DIM_2D_ARRAY)
imageInfo.imageType = VK_IMAGE_TYPE_2D;
else if (dim == Latte::E_DIM::DIM_CUBEMAP)
imageInfo.imageType = VK_IMAGE_TYPE_2D;
else if (dim == Latte::E_DIM::DIM_2D_MSAA)
imageInfo.imageType = VK_IMAGE_TYPE_2D;
else
{
cemu_assert_unimplemented();
}
if (vkCreateImage(m_vkr->GetLogicalDevice(), &imageInfo, nullptr, &vkObjTex->m_image) != VK_SUCCESS)
m_vkr->UnrecoverableError("Failed to create texture image");
if (m_vkr->IsDebugUtilsEnabled() && vkSetDebugUtilsObjectNameEXT)
{
VkDebugUtilsObjectNameInfoEXT objName{};
objName.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
objName.objectType = VK_OBJECT_TYPE_IMAGE;
objName.pNext = nullptr;
objName.objectHandle = (uint64_t)vkObjTex->m_image;
auto objNameStr = fmt::format("tex_{:08x}_fmt{:04x}", physAddress, (uint32)format);
objName.pObjectName = objNameStr.c_str();
vkSetDebugUtilsObjectNameEXT(m_vkr->GetLogicalDevice(), &objName);
}
vkObjTex->m_flags = imageInfo.flags;
vkObjTex->m_format = imageInfo.format;
// init layout array
m_layoutsMips = std::max(mipLevels, 1u); // todo - use effective mip count
m_layoutsDepth = std::max(depth, 1u);
if (Is3DTexture())
m_layouts.resize(m_layoutsMips, VK_IMAGE_LAYOUT_UNDEFINED); // one per mip
else
m_layouts.resize(m_layoutsMips * m_layoutsDepth, VK_IMAGE_LAYOUT_UNDEFINED); // one per layer per mip
}
LatteTextureVk::~LatteTextureVk()
{
cemu_assert_debug(views.empty());
m_vkr->surfaceCopy_notifyTextureRelease(this);
VulkanRenderer::GetInstance()->releaseDestructibleObject(vkObjTex);
vkObjTex = nullptr;
}
LatteTextureView* LatteTextureVk::CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
{
cemu_assert_debug(mipCount > 0);
cemu_assert_debug(sliceCount > 0);
cemu_assert_debug((firstMip + mipCount) <= this->mipLevels);
cemu_assert_debug((firstSlice + sliceCount) <= this->depth);
return new LatteTextureViewVk(m_vkr->GetLogicalDevice(), this, dim, format, firstMip, mipCount, firstSlice, sliceCount);
}
void LatteTextureVk::setAllocation(struct VkImageMemAllocation* memAllocation)
{
vkObjTex->m_allocation = memAllocation;
}
struct VkImageMemAllocation* LatteTextureVk::getAllocation() const
{
return vkObjTex->m_allocation;
}