From 99a5db20eb0aaa52b58c37b945c6edddc3cc99ca Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:06:07 +0300 Subject: [PATCH] Decode unsuported formats --- src/Cafe/HW/Latte/Core/LatteTextureLoader.h | 240 ++++++++++++++++++ .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 130 ++++++++-- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 5 + 3 files changed, 355 insertions(+), 20 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h index f6de57d6..31b04904 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h +++ b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h @@ -1640,6 +1640,99 @@ public: } }; +class TextureDecoder_BC1_To_R8G8B8A8 : public TextureDecoder, public SingletonClass +{ +public: + + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 4; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 blockSizeX = (std::min)(4, textureLoader->width - x); + sint32 blockSizeY = (std::min)(4, textureLoader->height - y); + // decode 4x4 pixels at once + float rgbaBlock[4 * 4 * 4]; + decodeBC1Block(blockData, rgbaBlock); + for (sint32 py = 0; py < blockSizeY; py++) + { + sint32 yc = y + py; + for (sint32 px = 0; px < blockSizeX; px++) + { + sint32 pixelOffset = (x + px + yc * textureLoader->width) * 4; // write to target buffer + float red = rgbaBlock[(px + py * 4) * 4 + 0]; + float green = rgbaBlock[(px + py * 4) * 4 + 1]; + float blue = rgbaBlock[(px + py * 4) * 4 + 2]; + float alpha = rgbaBlock[(px + py * 4) * 4 + 3]; + *(outputData + pixelOffset + 0) = red * 255; + *(outputData + pixelOffset + 1) = green * 255; + *(outputData + pixelOffset + 2) = blue * 255; + *(outputData + pixelOffset + 3) = alpha * 255; + } + } + } + } + } + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + return; + } +}; + +class TextureDecoder_BC2_To_R8G8B8A8 : public TextureDecoder, public SingletonClass +{ +public: + + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 4; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 blockSizeX = (std::min)(4, textureLoader->width - x); + sint32 blockSizeY = (std::min)(4, textureLoader->height - y); + // decode 4x4 pixels at once + float rgbaBlock[4 * 4 * 4]; + decodeBC2Block_UNORM(blockData, rgbaBlock); + for (sint32 py = 0; py < blockSizeY; py++) + { + sint32 yc = y + py; + for (sint32 px = 0; px < blockSizeX; px++) + { + sint32 pixelOffset = (x + px + yc * textureLoader->width) * 4; // write to target buffer + float red = rgbaBlock[(px + py * 4) * 4 + 0]; + float green = rgbaBlock[(px + py * 4) * 4 + 1]; + float blue = rgbaBlock[(px + py * 4) * 4 + 2]; + float alpha = rgbaBlock[(px + py * 4) * 4 + 3]; + *(outputData + pixelOffset + 0) = red * 255; + *(outputData + pixelOffset + 1) = green * 255; + *(outputData + pixelOffset + 2) = blue * 255; + *(outputData + pixelOffset + 3) = alpha * 255; + } + } + } + } + } + + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + return; + } +}; + class TextureDecoder_BC2 : public TextureDecoder, public SingletonClass { public: @@ -1849,6 +1942,53 @@ public: } }; +class TextureDecoder_BC3_To_R8G8B8A8 : public TextureDecoder, public SingletonClass +{ +public: + + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 4; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 blockSizeX = (std::min)(4, textureLoader->width - x); + sint32 blockSizeY = (std::min)(4, textureLoader->height - y); + // decode 4x4 pixels at once + float rgbaBlock[4 * 4 * 4]; + decodeBC3Block_UNORM(blockData, rgbaBlock); + for (sint32 py = 0; py < blockSizeY; py++) + { + sint32 yc = y + py; + for (sint32 px = 0; px < blockSizeX; px++) + { + sint32 pixelOffset = (x + px + yc * textureLoader->width) * 4; // write to target buffer + float red = rgbaBlock[(px + py * 4) * 4 + 0]; + float green = rgbaBlock[(px + py * 4) * 4 + 1]; + float blue = rgbaBlock[(px + py * 4) * 4 + 2]; + float alpha = rgbaBlock[(px + py * 4) * 4 + 3]; + *(outputData + pixelOffset + 0) = (uint8)(red * 255); + *(outputData + pixelOffset + 1) = (uint8)(green * 255); + *(outputData + pixelOffset + 2) = (uint8)(blue * 255); + *(outputData + pixelOffset + 3) = (uint8)(alpha * 255); + } + } + } + } + } + + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + return; + } +}; + class TextureDecoder_BC3_UNORM_uncompress : public TextureDecoder_BC3_uncompress_generic, public SingletonClass { // reuse TextureDecoder_BC3_uncompress_generic @@ -1947,6 +2087,55 @@ public: } }; + +class TextureDecoder_BC4_To_R8 : public TextureDecoder, public SingletonClass +{ +public: + + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 1; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 blockSizeX = (std::min)(4, textureLoader->width - x); + sint32 blockSizeY = (std::min)(4, textureLoader->height - y); + // decode 4x4 pixels at once + float rBlock[4 * 4 * 1]; + decodeBC4Block_UNORM(blockData, rBlock); + + for (sint32 py = 0; py < blockSizeY; py++) + { + sint32 yc = y + py; + for (sint32 px = 0; px < blockSizeX; px++) + { + sint32 pixelOffset = (x + px + yc * textureLoader->width); // write to target buffer + float red = rBlock[(px + py * 4) * 1 + 0]; + *(outputData + pixelOffset + 0) = (uint8)(red * 255); + } + } + } + } + } + + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + float rBlock[4 * 4 * 1]; + decodeBC4Block_UNORM(blockData, rBlock); + float red = rBlock[(blockOffsetX + blockOffsetY * 4) * 1 + 0]; + *(outputPixel + 0) = (uint8)(red * 255.0f); + *(outputPixel + 1) = 0; + *(outputPixel + 2) = 0; + *(outputPixel + 3) = 255; + } +}; + class TextureDecoder_BC4 : public TextureDecoder, public SingletonClass { public: @@ -1983,6 +2172,57 @@ public: } }; +class TextureDecoder_BC5_To_R8G8 : public TextureDecoder, public SingletonClass +{ +public: + + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 2; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 blockSizeX = (std::min)(4, textureLoader->width - x); + sint32 blockSizeY = (std::min)(4, textureLoader->height - y); + // decode 4x4 pixels at once + float rgBlock[4 * 4 * 2]; + decodeBC5Block_UNORM(blockData, rgBlock); + + for (sint32 py = 0; py < blockSizeY; py++) + { + sint32 yc = y + py; + for (sint32 px = 0; px < blockSizeX; px++) + { + sint32 pixelOffset = (x + px + yc * textureLoader->width) * 2; // write to target buffer + float red = rgBlock[(px + py * 4) * 2 + 0]; + float green = rgBlock[(px + py * 4) * 2 + 1]; + *(outputData + pixelOffset + 0) = (uint8)(red * 255); + *(outputData + pixelOffset + 1) = (uint8)(green * 255); + } + } + } + } + } + + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + float rgBlock[4 * 4 * 2]; + decodeBC5Block_UNORM(blockData, rgBlock); + float red = rgBlock[(blockOffsetX + blockOffsetY * 4) * 2 + 0]; + float green = rgBlock[(blockOffsetX + blockOffsetY * 4) * 2 + 1]; + *(outputPixel + 0) = (uint8)(red * 255.0f); + *(outputPixel + 1) = (uint8)(green * 255.0f); + *(outputPixel + 2) = 0; + *(outputPixel + 3) = 255; + } +}; + class TextureDecoder_BC5_UNORM_uncompress : public TextureDecoder, public SingletonClass { public: diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 75c60268..c61c1d04 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -1735,6 +1735,16 @@ void VulkanRenderer::QueryMemoryInfo() void VulkanRenderer::QueryAvailableFormats() { + auto isFormatOptimal = [this](VkFormat format) -> bool { + VkFormatProperties fmtProp{}; + vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &fmtProp); + return fmtProp.optimalTilingFeatures != 0; + }; + m_supportedFormatInfo.fmt_bc1 = isFormatOptimal(VK_FORMAT_BC1_RGBA_SRGB_BLOCK) && isFormatOptimal(VK_FORMAT_BC1_RGBA_UNORM_BLOCK); + m_supportedFormatInfo.fmt_bc2 = isFormatOptimal(VK_FORMAT_BC2_UNORM_BLOCK) && isFormatOptimal(VK_FORMAT_BC2_SRGB_BLOCK); + m_supportedFormatInfo.fmt_bc3 = isFormatOptimal(VK_FORMAT_BC3_UNORM_BLOCK) && isFormatOptimal(VK_FORMAT_BC3_SRGB_BLOCK); + m_supportedFormatInfo.fmt_bc4 = isFormatOptimal(VK_FORMAT_BC4_UNORM_BLOCK) && isFormatOptimal(VK_FORMAT_BC4_SNORM_BLOCK); + m_supportedFormatInfo.fmt_bc5 = isFormatOptimal(VK_FORMAT_BC5_UNORM_BLOCK) && isFormatOptimal(VK_FORMAT_BC5_SNORM_BLOCK); VkFormatProperties fmtProp{}; vkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_D24_UNORM_S8_UINT, &fmtProp); // D24S8 @@ -2465,44 +2475,124 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD break; // compressed formats case Latte::E_GX2SURFFMT::BC1_SRGB: - formatInfoOut->vkImageFormat = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; // todo - verify - formatInfoOut->decoder = TextureDecoder_BC1::getInstance(); + if (m_supportedFormatInfo.fmt_bc1) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; // todo - verify + formatInfoOut->decoder = TextureDecoder_BC1::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_SRGB; + formatInfoOut->decoder = TextureDecoder_BC1_To_R8G8B8A8::getInstance(); + } break; case Latte::E_GX2SURFFMT::BC1_UNORM: - formatInfoOut->vkImageFormat = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; // todo - verify - formatInfoOut->decoder = TextureDecoder_BC1::getInstance(); + if (m_supportedFormatInfo.fmt_bc1) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; // todo - verify + formatInfoOut->decoder = TextureDecoder_BC1::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; + formatInfoOut->decoder = TextureDecoder_BC1_To_R8G8B8A8::getInstance(); + } break; case Latte::E_GX2SURFFMT::BC2_UNORM: - formatInfoOut->vkImageFormat = VK_FORMAT_BC2_UNORM_BLOCK; // todo - verify - formatInfoOut->decoder = TextureDecoder_BC2::getInstance(); + if (m_supportedFormatInfo.fmt_bc2) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC2_UNORM_BLOCK; // todo - verify + formatInfoOut->decoder = TextureDecoder_BC2::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; + formatInfoOut->decoder = TextureDecoder_BC2_To_R8G8B8A8::getInstance(); + } break; case Latte::E_GX2SURFFMT::BC2_SRGB: - formatInfoOut->vkImageFormat = VK_FORMAT_BC2_SRGB_BLOCK; // todo - verify - formatInfoOut->decoder = TextureDecoder_BC2::getInstance(); + if (m_supportedFormatInfo.fmt_bc2) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC2_SRGB_BLOCK; // todo - verify + formatInfoOut->decoder = TextureDecoder_BC2::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_SRGB; + formatInfoOut->decoder = TextureDecoder_BC2_To_R8G8B8A8::getInstance(); + } break; case Latte::E_GX2SURFFMT::BC3_UNORM: - formatInfoOut->vkImageFormat = VK_FORMAT_BC3_UNORM_BLOCK; - formatInfoOut->decoder = TextureDecoder_BC3::getInstance(); + if (m_supportedFormatInfo.fmt_bc3) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC3_UNORM_BLOCK; + formatInfoOut->decoder = TextureDecoder_BC3::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; + formatInfoOut->decoder = TextureDecoder_BC3_To_R8G8B8A8::getInstance(); + } break; case Latte::E_GX2SURFFMT::BC3_SRGB: - formatInfoOut->vkImageFormat = VK_FORMAT_BC3_SRGB_BLOCK; - formatInfoOut->decoder = TextureDecoder_BC3::getInstance(); + if (m_supportedFormatInfo.fmt_bc3) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC3_SRGB_BLOCK; + formatInfoOut->decoder = TextureDecoder_BC3::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_SRGB; + formatInfoOut->decoder = TextureDecoder_BC3_To_R8G8B8A8::getInstance(); + } break; case Latte::E_GX2SURFFMT::BC4_UNORM: - formatInfoOut->vkImageFormat = VK_FORMAT_BC4_UNORM_BLOCK; - formatInfoOut->decoder = TextureDecoder_BC4::getInstance(); + if (m_supportedFormatInfo.fmt_bc4) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC4_UNORM_BLOCK; + formatInfoOut->decoder = TextureDecoder_BC4::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8_UNORM; + formatInfoOut->decoder = TextureDecoder_BC4_To_R8::getInstance(); + } break; case Latte::E_GX2SURFFMT::BC4_SNORM: - formatInfoOut->vkImageFormat = VK_FORMAT_BC4_SNORM_BLOCK; - formatInfoOut->decoder = TextureDecoder_BC4::getInstance(); + if (m_supportedFormatInfo.fmt_bc4) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC4_SNORM_BLOCK; + formatInfoOut->decoder = TextureDecoder_BC4::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8_SNORM; + formatInfoOut->decoder = TextureDecoder_BC4_To_R8::getInstance(); + } break; case Latte::E_GX2SURFFMT::BC5_UNORM: - formatInfoOut->vkImageFormat = VK_FORMAT_BC5_UNORM_BLOCK; - formatInfoOut->decoder = TextureDecoder_BC5::getInstance(); + if (m_supportedFormatInfo.fmt_bc5) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC5_UNORM_BLOCK; + formatInfoOut->decoder = TextureDecoder_BC5::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8_UNORM; + formatInfoOut->decoder = TextureDecoder_BC5_To_R8G8::getInstance(); + } break; case Latte::E_GX2SURFFMT::BC5_SNORM: - formatInfoOut->vkImageFormat = VK_FORMAT_BC5_SNORM_BLOCK; - formatInfoOut->decoder = TextureDecoder_BC5::getInstance(); + if (m_supportedFormatInfo.fmt_bc5) + { + formatInfoOut->vkImageFormat = VK_FORMAT_BC5_SNORM_BLOCK; + formatInfoOut->decoder = TextureDecoder_BC5::getInstance(); + } + else + { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8_SNORM; + formatInfoOut->decoder = TextureDecoder_BC5_To_R8G8::getInstance(); + } break; case Latte::E_GX2SURFFMT::R24_X8_UNORM: formatInfoOut->vkImageFormat = VK_FORMAT_R32_SFLOAT; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index af501b5f..dccc0079 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -21,6 +21,11 @@ struct VkSupportedFormatInfo_t bool fmt_r5g6b5_unorm_pack{}; bool fmt_r4g4b4a4_unorm_pack{}; bool fmt_a1r5g5b5_unorm_pack{}; + bool fmt_bc1{}; + bool fmt_bc2{}; + bool fmt_bc3{}; + bool fmt_bc4{}; + bool fmt_bc5{}; }; struct VkDescriptorSetInfo