mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-09-25 10:36:08 -05:00
Latte: Add non-zero mip support to texture readback + refactor
y
This commit is contained in:
@@ -206,13 +206,6 @@ bool LatteTC_HasTextureChanged(LatteTexture* hostTexture, bool force)
|
||||
debug_printf("Force invalidate 0x%08x\n", hostTexture->physAddress);
|
||||
hostTexture->forceInvalidate = false;
|
||||
}
|
||||
// if texture is written by GPU operations we switch to a faster hash implementation
|
||||
// if (hostTexture->isUpdatedOnGPU && hostTexture->useLightHash == false)
|
||||
// {
|
||||
// hostTexture->useLightHash = true;
|
||||
// // update hash
|
||||
// hostTexture->texDataHash2 = LatteTexture_CalculateTextureDataHash(hostTexture);
|
||||
// }
|
||||
// only check each texture for updates once a frame
|
||||
// todo: Instead of relying on frames, it would be better to recheck only after any GPU wait operation occurred.
|
||||
if( hostTexture->lastDataUpdateFrameCounter == LatteGPUState.frameCounter && force == false)
|
||||
|
||||
@@ -742,7 +742,9 @@ void LatteTextureLoader_writeReadbackTextureToMemory(LatteTextureDefinition* tex
|
||||
{
|
||||
optimizedLinearReadbackWriteLoop<uint64>(&textureLoader, linearPixelData, sourceRowPitch);
|
||||
}
|
||||
else if (textureData->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT)
|
||||
else if (textureData->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT ||
|
||||
textureData->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_SINT ||
|
||||
textureData->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT)
|
||||
{
|
||||
for (sint32 y = 0; y < textureLoader.height; y += textureLoader.stepY)
|
||||
{
|
||||
|
||||
@@ -181,3 +181,20 @@ bool LatteTextureReadback_ReadbackToLinearBlocking(LatteTextureView* sourceView,
|
||||
delete info;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 LatteTextureReadbackInfo::GetReadbackRowPitch(LatteTextureView* textureView, uint32 rowAlignment)
|
||||
{
|
||||
uint32 width = textureView->baseTexture->GetMipWidth(textureView->firstMip);
|
||||
if (Latte::IsCompressedFormat(textureView->format))
|
||||
width = (width + 3) / 4;
|
||||
uint32 rowPitch = width * (Latte::GetFormatBits(textureView->format) / 8);
|
||||
return (rowPitch + rowAlignment - 1) & ~(rowAlignment - 1);
|
||||
}
|
||||
|
||||
uint32 LatteTextureReadbackInfo::GetReadbackImageSize(LatteTextureView* textureView, uint32 rowPitch)
|
||||
{
|
||||
uint32 height = textureView->baseTexture->GetMipHeight(textureView->firstMip);
|
||||
if (Latte::IsCompressedFormat(textureView->format))
|
||||
height = (height + 3) / 4;
|
||||
return height * rowPitch;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ public:
|
||||
uint32 m_rowPitch = 0; // bytes between rows in GetData(). Set by the backend
|
||||
|
||||
protected:
|
||||
static uint32 GetReadbackRowPitch(LatteTextureView* textureView, uint32 rowAlignment = 1);
|
||||
static uint32 GetReadbackImageSize(LatteTextureView* textureView, uint32 rowPitch);
|
||||
|
||||
LatteTextureView* m_textureView;
|
||||
uint32 m_image_size = 0;
|
||||
};
|
||||
|
||||
@@ -75,6 +75,7 @@ LatteTextureMtl::LatteTextureMtl(class MetalRenderer* mtlRenderer, Latte::E_DIM
|
||||
}
|
||||
|
||||
auto pixelFormat = GetMtlPixelFormat(format, isDepth);
|
||||
m_isAlternateFormat = GetMtlPixelFormatInfo(format, isDepth).isAlternateFormat;
|
||||
desc->setPixelFormat(pixelFormat);
|
||||
|
||||
MTL::TextureUsage usage = MTL::TextureUsageShaderRead | MTL::TextureUsagePixelFormatView;
|
||||
|
||||
@@ -19,6 +19,8 @@ public:
|
||||
|
||||
void AllocateOnHost() override;
|
||||
|
||||
bool m_isAlternateFormat{}; // true if Metal pixel format does not 1:1 match Latte format
|
||||
|
||||
protected:
|
||||
LatteTextureView* CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) override;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
|
||||
|
||||
LatteTextureReadbackInfoMtl::~LatteTextureReadbackInfoMtl()
|
||||
{
|
||||
@@ -18,13 +17,12 @@ void LatteTextureReadbackInfoMtl::StartTransfer()
|
||||
cemu_assert_debug(m_textureView->firstMip == 0);
|
||||
cemu_assert_debug(m_textureView->baseTexture->dim != Latte::E_DIM::DIM_3D);
|
||||
|
||||
size_t bytesPerRow = GetMtlTextureBytesPerRow(baseTexture->format, baseTexture->isDepth, baseTexture->width);
|
||||
m_rowPitch = static_cast<uint32>(bytesPerRow);
|
||||
size_t bytesPerImage = GetMtlTextureBytesPerImage(baseTexture->format, baseTexture->isDepth, baseTexture->height, bytesPerRow);
|
||||
m_rowPitch = GetReadbackRowPitch(m_textureView);
|
||||
m_image_size = GetReadbackImageSize(m_textureView, m_rowPitch);
|
||||
|
||||
auto blitCommandEncoder = m_mtlr->GetBlitCommandEncoder();
|
||||
|
||||
blitCommandEncoder->copyFromTexture(baseTexture->GetTexture(), m_firstSlice, 0, MTL::Origin{0, 0, 0}, MTL::Size{(uint32)baseTexture->width, (uint32)baseTexture->height, 1}, m_mtlr->GetTextureReadbackBuffer(), m_bufferOffset, bytesPerRow, bytesPerImage);
|
||||
blitCommandEncoder->copyFromTexture(baseTexture->GetTexture(), m_firstSlice, 0, MTL::Origin{0, 0, 0}, MTL::Size{(uint32)baseTexture->width, (uint32)baseTexture->height, 1}, m_mtlr->GetTextureReadbackBuffer(), m_bufferOffset, m_rowPitch, m_image_size);
|
||||
|
||||
m_commandBuffer = m_mtlr->GetCurrentCommandBuffer()->retain();
|
||||
// TODO: uncomment?
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
std::map<Latte::E_GX2SURFFMT, MetalPixelFormatInfo> MTL_COLOR_FORMAT_TABLE = {
|
||||
{Latte::E_GX2SURFFMT::INVALID_FORMAT, {MTL::PixelFormatInvalid, MetalDataType::NONE, 0}},
|
||||
|
||||
{Latte::E_GX2SURFFMT::R4_G4_UNORM, {MTL::PixelFormatABGR4Unorm, MetalDataType::FLOAT, 2}},
|
||||
{Latte::E_GX2SURFFMT::R5_G6_B5_UNORM, {MTL::PixelFormatB5G6R5Unorm, MetalDataType::FLOAT, 2}},
|
||||
{Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM, {MTL::PixelFormatBGR5A1Unorm, MetalDataType::FLOAT, 2}},
|
||||
{Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM, {MTL::PixelFormatABGR4Unorm, MetalDataType::FLOAT, 2}},
|
||||
{Latte::E_GX2SURFFMT::R4_G4_UNORM, {MTL::PixelFormatABGR4Unorm, MetalDataType::FLOAT, 2, {1, 1}, false, nullptr, true}},
|
||||
{Latte::E_GX2SURFFMT::R5_G6_B5_UNORM, {MTL::PixelFormatB5G6R5Unorm, MetalDataType::FLOAT, 2, {1, 1}, false, nullptr, true}},
|
||||
{Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM, {MTL::PixelFormatBGR5A1Unorm, MetalDataType::FLOAT, 2, {1, 1}, false, nullptr, true}},
|
||||
{Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM, {MTL::PixelFormatABGR4Unorm, MetalDataType::FLOAT, 2, {1, 1}, false, nullptr, true}},
|
||||
{Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM, {MTL::PixelFormatA1BGR5Unorm, MetalDataType::FLOAT, 2}},
|
||||
{Latte::E_GX2SURFFMT::R8_UNORM, {MTL::PixelFormatR8Unorm, MetalDataType::FLOAT, 1}},
|
||||
{Latte::E_GX2SURFFMT::R8_SNORM, {MTL::PixelFormatR8Snorm, MetalDataType::FLOAT, 1}},
|
||||
@@ -25,12 +25,12 @@ std::map<Latte::E_GX2SURFFMT, MetalPixelFormatInfo> MTL_COLOR_FORMAT_TABLE = {
|
||||
{Latte::E_GX2SURFFMT::R8_G8_B8_A8_SINT, {MTL::PixelFormatRGBA8Sint, MetalDataType::INT, 4}},
|
||||
{Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB, {MTL::PixelFormatRGBA8Unorm_sRGB, MetalDataType::FLOAT, 4}},
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM, {MTL::PixelFormatRGB10A2Unorm, MetalDataType::FLOAT, 4}},
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM, {MTL::PixelFormatRGBA16Snorm, MetalDataType::FLOAT, 8}},
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM, {MTL::PixelFormatRGBA16Snorm, MetalDataType::FLOAT, 8, {1, 1}, false, nullptr, true}},
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_UINT, {MTL::PixelFormatRGB10A2Uint, MetalDataType::UINT, 4}},
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SINT, {MTL::PixelFormatRGBA16Sint, MetalDataType::INT, 8}},
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB, {MTL::PixelFormatRGB10A2Unorm, MetalDataType::FLOAT, 4}}, // TODO: sRGB?
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SINT, {MTL::PixelFormatRGBA16Sint, MetalDataType::INT, 8, {1, 1}, false, nullptr, true}},
|
||||
{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB, {MTL::PixelFormatRGB10A2Unorm, MetalDataType::FLOAT, 4, {1, 1}, false, nullptr, true}}, // TODO: sRGB?
|
||||
{Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM, {MTL::PixelFormatBGR10A2Unorm, MetalDataType::FLOAT, 4}},
|
||||
{Latte::E_GX2SURFFMT::A2_B10_G10_R10_UINT, {MTL::PixelFormatRGB10A2Uint, MetalDataType::UINT, 4}},
|
||||
{Latte::E_GX2SURFFMT::A2_B10_G10_R10_UINT, {MTL::PixelFormatRGB10A2Uint, MetalDataType::UINT, 4, {1, 1}, false, nullptr, true}},
|
||||
{Latte::E_GX2SURFFMT::R16_UNORM, {MTL::PixelFormatR16Unorm, MetalDataType::FLOAT, 2}},
|
||||
{Latte::E_GX2SURFFMT::R16_SNORM, {MTL::PixelFormatR16Snorm, MetalDataType::FLOAT, 2}},
|
||||
{Latte::E_GX2SURFFMT::R16_UINT, {MTL::PixelFormatR16Uint, MetalDataType::UINT, 2}},
|
||||
@@ -46,11 +46,11 @@ std::map<Latte::E_GX2SURFFMT, MetalPixelFormatInfo> MTL_COLOR_FORMAT_TABLE = {
|
||||
{Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT, {MTL::PixelFormatRGBA16Uint, MetalDataType::UINT, 8}},
|
||||
{Latte::E_GX2SURFFMT::R16_G16_B16_A16_SINT, {MTL::PixelFormatRGBA16Sint, MetalDataType::INT, 8}},
|
||||
{Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT, {MTL::PixelFormatRGBA16Float, MetalDataType::FLOAT, 8}},
|
||||
{Latte::E_GX2SURFFMT::R24_X8_UNORM, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R24_X8_FLOAT, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::X24_G8_UINT, {MTL::PixelFormatRGBA8Uint, MetalDataType::UINT, 4}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R32_X8_FLOAT, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::X32_G8_UINT_X24, {MTL::PixelFormatRGBA16Uint, MetalDataType::UINT, 8}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R24_X8_UNORM, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4, {1, 1}, false, nullptr, true}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R24_X8_FLOAT, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4, {1, 1}, false, nullptr, true}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::X24_G8_UINT, {MTL::PixelFormatRGBA8Uint, MetalDataType::UINT, 4, {1, 1}, false, nullptr, true}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R32_X8_FLOAT, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4, {1, 1}, false, nullptr, true}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::X32_G8_UINT_X24, {MTL::PixelFormatRGBA16Uint, MetalDataType::UINT, 8, {1, 1}, false, nullptr, true}}, // TODO: correct?
|
||||
{Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT, {MTL::PixelFormatRG11B10Float, MetalDataType::FLOAT, 4}},
|
||||
{Latte::E_GX2SURFFMT::R32_UINT, {MTL::PixelFormatR32Uint, MetalDataType::UINT, 4}},
|
||||
{Latte::E_GX2SURFFMT::R32_SINT, {MTL::PixelFormatR32Sint, MetalDataType::INT, 4}},
|
||||
@@ -77,8 +77,8 @@ std::map<Latte::E_GX2SURFFMT, MetalPixelFormatInfo> MTL_DEPTH_FORMAT_TABLE = {
|
||||
{Latte::E_GX2SURFFMT::INVALID_FORMAT, {MTL::PixelFormatInvalid, MetalDataType::NONE, 0}},
|
||||
|
||||
{Latte::E_GX2SURFFMT::D24_S8_UNORM, {MTL::PixelFormatDepth24Unorm_Stencil8, MetalDataType::NONE, 4, {1, 1}, true}},
|
||||
{Latte::E_GX2SURFFMT::D24_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, MetalDataType::NONE, 4, {1, 1}, true}},
|
||||
{Latte::E_GX2SURFFMT::D32_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, MetalDataType::NONE, 5, {1, 1}, true}},
|
||||
{Latte::E_GX2SURFFMT::D24_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, MetalDataType::NONE, 4, {1, 1}, true, nullptr, true}},
|
||||
{Latte::E_GX2SURFFMT::D32_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, MetalDataType::NONE, 5, {1, 1}, true, nullptr, true}},
|
||||
{Latte::E_GX2SURFFMT::D16_UNORM, {MTL::PixelFormatDepth16Unorm, MetalDataType::NONE, 2, {1, 1}}},
|
||||
{Latte::E_GX2SURFFMT::D32_FLOAT, {MTL::PixelFormatDepth32Float, MetalDataType::NONE, 4, {1, 1}}},
|
||||
};
|
||||
@@ -142,24 +142,29 @@ void CheckForPixelFormatSupport(const MetalPixelFormatSupport& support)
|
||||
{
|
||||
// B5G6R5Unorm
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G6_B5_UNORM].pixelFormat = MTL::PixelFormatRGBA8Unorm;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G6_B5_UNORM].isAlternateFormat = true;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G6_B5_UNORM].bytesPerBlock = 4;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G6_B5_UNORM].textureDecoder = TextureDecoder_R5G6B5_UNORM_To_RGBA8::getInstance();
|
||||
|
||||
// A1BGR5Unorm
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM].pixelFormat = MTL::PixelFormatRGBA8Unorm;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM].isAlternateFormat = true;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM].textureDecoder = TextureDecoder_A1_B5_G5_R5_UNORM_vulkan_To_RGBA8::getInstance();
|
||||
|
||||
// ABGR4Unorm
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_UNORM].pixelFormat = MTL::PixelFormatRG8Unorm;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_UNORM].isAlternateFormat = true;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_UNORM].bytesPerBlock = 2;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_UNORM].textureDecoder = TextureDecoder_R4G4_UNORM_To_RG8::getInstance();
|
||||
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM].pixelFormat = MTL::PixelFormatRGBA8Unorm;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM].isAlternateFormat = true;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM].bytesPerBlock = 4;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM].textureDecoder = TextureDecoder_R4G4B4A4_UNORM_To_RGBA8::getInstance();
|
||||
|
||||
// BGR5A1Unorm
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM].pixelFormat = MTL::PixelFormatRGBA8Unorm;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM].isAlternateFormat = true;
|
||||
MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM].textureDecoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB_To_RGBA8::getInstance();
|
||||
}
|
||||
|
||||
@@ -174,6 +179,7 @@ void CheckForPixelFormatSupport(const MetalPixelFormatSupport& support)
|
||||
{
|
||||
// Depth24Unorm_Stencil8
|
||||
MTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D24_S8_UNORM].pixelFormat = MTL::PixelFormatDepth32Float_Stencil8;
|
||||
MTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D24_S8_UNORM].isAlternateFormat = true;
|
||||
// TODO: implement the decoder
|
||||
//MTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D24_S8_UNORM].textureDecoder = TextureDecoder_D24_S8_To_D32_S8::getInstance();
|
||||
}
|
||||
@@ -185,7 +191,7 @@ const MetalPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format, boo
|
||||
{
|
||||
auto it = MTL_DEPTH_FORMAT_TABLE.find(format);
|
||||
if (it == MTL_DEPTH_FORMAT_TABLE.end())
|
||||
return {MTL::PixelFormatDepth16Unorm, MetalDataType::NONE, 2}; // Fallback
|
||||
return {MTL::PixelFormatDepth16Unorm, MetalDataType::NONE, 2, {1, 1}, false, nullptr, true}; // Fallback
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
@@ -193,7 +199,7 @@ const MetalPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format, boo
|
||||
{
|
||||
auto it = MTL_COLOR_FORMAT_TABLE.find(format);
|
||||
if (it == MTL_COLOR_FORMAT_TABLE.end())
|
||||
return {MTL::PixelFormatR8Unorm, MetalDataType::FLOAT, 1}; // Fallback
|
||||
return {MTL::PixelFormatR8Unorm, MetalDataType::FLOAT, 1, {1, 1}, false, nullptr, true}; // Fallback
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ struct MetalPixelFormatInfo {
|
||||
Uvec2 blockTexelSize = {1, 1};
|
||||
bool hasStencil = false;
|
||||
TextureDecoder* textureDecoder = nullptr;
|
||||
bool isAlternateFormat = false; // if true then pixel format does not match Latte 1:1
|
||||
};
|
||||
|
||||
void CheckForPixelFormatSupport(const MetalPixelFormatSupport& support);
|
||||
|
||||
@@ -965,7 +965,13 @@ void MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, s
|
||||
|
||||
LatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView* textureView)
|
||||
{
|
||||
size_t uploadSize = static_cast<LatteTextureMtl*>(textureView->baseTexture)->GetTexture()->allocatedSize();
|
||||
auto* baseTexture = static_cast<LatteTextureMtl*>(textureView->baseTexture);
|
||||
if (baseTexture->m_isAlternateFormat)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "Metal does not support readback of texture format 0x{:x}", (uint32)baseTexture->format);
|
||||
return nullptr;
|
||||
}
|
||||
size_t uploadSize = baseTexture->GetTexture()->allocatedSize();
|
||||
|
||||
if ((m_readbackBufferWriteOffset + uploadSize) > TEXTURE_READBACK_SIZE)
|
||||
{
|
||||
|
||||
@@ -387,6 +387,14 @@ void LatteTextureGL::GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT forma
|
||||
glSuppliedFormatType = GL_UNSIGNED_INT;
|
||||
glIsCompressed = false;
|
||||
}
|
||||
else if (format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_SINT)
|
||||
{
|
||||
glInternalFormat = GL_RGBA32I;
|
||||
// supplied format
|
||||
glSuppliedFormat = GL_RGBA_INTEGER;
|
||||
glSuppliedFormatType = GL_INT;
|
||||
glIsCompressed = false;
|
||||
}
|
||||
else if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT)
|
||||
{
|
||||
glInternalFormat = GL_RGBA16UI;
|
||||
|
||||
@@ -546,7 +546,9 @@ void OpenGLRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad
|
||||
const sint32 pixelDataSize = screenshotWidth * screenshotHeight * 3;
|
||||
std::vector<uint8> rgb_data(pixelDataSize);
|
||||
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, rgb_data.data());
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
texture_bindAndActivate(nullptr, 0);
|
||||
|
||||
const bool srcUsesSRGB = HAS_FLAG(texView->format, Latte::E_GX2SURFFMT::FMT_BIT_SRGB);
|
||||
@@ -983,6 +985,8 @@ TextureDecoder* OpenGLRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT
|
||||
texDecoder = TextureDecoder_R11_G11_B10_FLOAT::getInstance();
|
||||
else if (format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT)
|
||||
texDecoder = TextureDecoder_R32_G32_B32_A32_UINT::getInstance();
|
||||
else if (format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_SINT)
|
||||
texDecoder = TextureDecoder_R32_G32_B32_A32_UINT::getInstance(); // reuse the UINT decoder
|
||||
else if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT)
|
||||
texDecoder = TextureDecoder_R16_G16_B16_A16_UINT::getInstance();
|
||||
else if (format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UINT)
|
||||
|
||||
@@ -5,37 +5,41 @@ LatteTextureReadbackInfoGL::LatteTextureReadbackInfoGL(LatteTextureView* texture
|
||||
: LatteTextureReadbackInfo(textureView, textureView->firstMip)
|
||||
{
|
||||
LatteTexture* baseTexture = textureView->baseTexture;
|
||||
uint32 width = baseTexture->GetMipWidth(m_firstMip);
|
||||
// handle format
|
||||
if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM)
|
||||
{
|
||||
m_rowPitch = width * 4;
|
||||
m_texFormatGL = GL_RGBA;
|
||||
m_texDataTypeGL = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB)
|
||||
{
|
||||
m_rowPitch = width * 4;
|
||||
m_texFormatGL = GL_RGBA;
|
||||
m_texDataTypeGL = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT)
|
||||
{
|
||||
m_rowPitch = width * 16;
|
||||
m_texFormatGL = GL_RGBA;
|
||||
m_texDataTypeGL = GL_FLOAT;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT)
|
||||
{
|
||||
m_texFormatGL = GL_RGBA_INTEGER;
|
||||
m_texDataTypeGL = GL_UNSIGNED_INT;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_SINT)
|
||||
{
|
||||
m_texFormatGL = GL_RGBA_INTEGER;
|
||||
m_texDataTypeGL = GL_INT;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R32_FLOAT)
|
||||
{
|
||||
if (baseTexture->isDepth)
|
||||
{
|
||||
m_rowPitch = width * 4;
|
||||
m_texFormatGL = GL_DEPTH_COMPONENT;
|
||||
m_texDataTypeGL = GL_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rowPitch = width * 4;
|
||||
m_texFormatGL = GL_RED;
|
||||
m_texDataTypeGL = GL_FLOAT;
|
||||
}
|
||||
@@ -44,33 +48,28 @@ LatteTextureReadbackInfoGL::LatteTextureReadbackInfoGL(LatteTextureView* texture
|
||||
{
|
||||
if (baseTexture->isDepth)
|
||||
{
|
||||
m_rowPitch = width * 2;
|
||||
m_texFormatGL = GL_DEPTH_COMPONENT;
|
||||
m_texDataTypeGL = GL_UNSIGNED_SHORT;
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rowPitch = width * 2;
|
||||
m_texFormatGL = GL_RED;
|
||||
m_texDataTypeGL = GL_UNSIGNED_SHORT;
|
||||
}
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT)
|
||||
{
|
||||
m_rowPitch = width * 8;
|
||||
m_texFormatGL = GL_RGBA;
|
||||
m_texDataTypeGL = GL_HALF_FLOAT;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_UNORM)
|
||||
{
|
||||
m_rowPitch = width * 2;
|
||||
m_texFormatGL = GL_RG;
|
||||
m_texDataTypeGL = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM)
|
||||
{
|
||||
m_rowPitch = width * 8;
|
||||
m_texFormatGL = GL_RGBA;
|
||||
m_texDataTypeGL = GL_UNSIGNED_SHORT;
|
||||
}
|
||||
@@ -80,8 +79,8 @@ LatteTextureReadbackInfoGL::LatteTextureReadbackInfoGL(LatteTextureView* texture
|
||||
return;
|
||||
}
|
||||
// OpenGL uses the default 4 byte pack alignment because it gives us slightly better row copy performance
|
||||
m_rowPitch = (m_rowPitch + 3) & ~3u;
|
||||
m_image_size = m_rowPitch * baseTexture->GetMipHeight(m_firstMip);
|
||||
m_rowPitch = GetReadbackRowPitch(textureView, 4);
|
||||
m_image_size = GetReadbackImageSize(textureView, m_rowPitch);
|
||||
}
|
||||
|
||||
LatteTextureReadbackInfoGL::~LatteTextureReadbackInfoGL()
|
||||
|
||||
@@ -49,6 +49,7 @@ LatteTextureVk::LatteTextureVk(class VulkanRenderer* vkRenderer, Latte::E_DIM di
|
||||
cemu_assert_debug(hasStencil == ((texFormatInfo.vkImageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0));
|
||||
imageInfo.format = texFormatInfo.vkImageFormat;
|
||||
vkObjTex->m_imageAspect = texFormatInfo.vkImageAspect;
|
||||
m_isAlternateFormat = texFormatInfo.isAlternateFormat;
|
||||
|
||||
if (isDepth == false && texFormatInfo.isCompressed)
|
||||
{
|
||||
|
||||
@@ -87,8 +87,9 @@ public:
|
||||
uint32 m_selfDependencyCheckIndex{}; // used to track if texture is being both sampled and output to during drawcall
|
||||
VkImageAspectFlags m_selfDependencyCheckAspectMask{};
|
||||
|
||||
bool m_isAlternateFormat{}; // true if host pixel format does not 1:1 match the emulated guest texture pixel format
|
||||
private:
|
||||
class VulkanRenderer* m_vkr;
|
||||
class VulkanRenderer* m_vkr{};
|
||||
|
||||
VKRObjectTexture* vkObjTex{};
|
||||
VkImageLayout m_defaultLayout{ VK_IMAGE_LAYOUT_GENERAL }; // the targetted long term layout of the texture. Can be either VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT for potential rendertargets if supported
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h"
|
||||
|
||||
LatteTextureReadbackInfoVk::LatteTextureReadbackInfoVk(VkDevice device, LatteTextureView* textureView)
|
||||
: LatteTextureReadbackInfo(textureView), m_device(device)
|
||||
: LatteTextureReadbackInfo(textureView, textureView->firstMip), m_device(device)
|
||||
{
|
||||
m_image_size = GetImageSize(textureView);
|
||||
m_rowPitch = m_image_size / textureView->baseTexture->height;
|
||||
m_rowPitch = m_image_size / textureView->baseTexture->GetMipHeight(m_firstMip);
|
||||
}
|
||||
|
||||
LatteTextureReadbackInfoVk::~LatteTextureReadbackInfoVk()
|
||||
@@ -15,84 +15,13 @@ LatteTextureReadbackInfoVk::~LatteTextureReadbackInfoVk()
|
||||
|
||||
uint32 LatteTextureReadbackInfoVk::GetImageSize(LatteTextureView* textureView)
|
||||
{
|
||||
const auto* baseTexture = (LatteTextureVk*)textureView->baseTexture;
|
||||
// handle format
|
||||
const auto textureFormat = baseTexture->GetFormat();
|
||||
if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM)
|
||||
auto* baseTexture = (LatteTextureVk*)textureView->baseTexture;
|
||||
if (baseTexture->m_isAlternateFormat || baseTexture->IsCompressedFormat())
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_R8G8B8A8_UNORM);
|
||||
return baseTexture->width * baseTexture->height * 4;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R8_UNORM )
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_R8_UNORM);
|
||||
return baseTexture->width * baseTexture->height * 1;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB)
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_R8G8B8A8_SRGB);
|
||||
return baseTexture->width * baseTexture->height * 4;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT)
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_R32G32B32A32_SFLOAT);
|
||||
return baseTexture->width * baseTexture->height * 16;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R32_FLOAT)
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_R32_SFLOAT || textureFormat == VK_FORMAT_D32_SFLOAT);
|
||||
if (baseTexture->isDepth)
|
||||
return baseTexture->width * baseTexture->height * 4;
|
||||
else
|
||||
return baseTexture->width * baseTexture->height * 4;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R16_UNORM)
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_R16_UNORM);
|
||||
if (baseTexture->isDepth)
|
||||
{
|
||||
cemu_assert_debug(false);
|
||||
return baseTexture->width * baseTexture->height * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return baseTexture->width * baseTexture->height * 2;
|
||||
}
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT)
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_R16G16B16A16_SFLOAT);
|
||||
return baseTexture->width * baseTexture->height * 8;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_UNORM)
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_R8G8_UNORM);
|
||||
return baseTexture->width * baseTexture->height * 2;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM)
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_R16G16B16A16_UNORM);
|
||||
return baseTexture->width * baseTexture->height * 8;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::D24_S8_UNORM)
|
||||
{
|
||||
cemu_assert(textureFormat == VK_FORMAT_D24_UNORM_S8_UINT);
|
||||
// todo - if driver does not support VK_FORMAT_D24_UNORM_S8_UINT this is represented as VK_FORMAT_D32_SFLOAT_S8_UINT which is 8 bytes
|
||||
return baseTexture->width * baseTexture->height * 4;
|
||||
}
|
||||
else if (textureView->format == Latte::E_GX2SURFFMT::R5_G6_B5_UNORM )
|
||||
{
|
||||
if(textureFormat == VK_FORMAT_R5G6B5_UNORM_PACK16){
|
||||
return baseTexture->width * baseTexture->height * 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Unsupported texture readback format {:04x}", (uint32)textureView->format);
|
||||
cemu_assert_debug(false);
|
||||
cemuLog_logDebug(LogType::Force, "Vulkan does not support readback of texture format 0x{:x}", (uint32)baseTexture->format);
|
||||
return 0;
|
||||
}
|
||||
return LatteTextureReadbackInfo::GetReadbackImageSize(textureView, GetReadbackRowPitch(textureView));
|
||||
}
|
||||
|
||||
|
||||
@@ -103,21 +32,20 @@ void LatteTextureReadbackInfoVk::StartTransfer()
|
||||
auto* baseTexture = (LatteTextureVk*)m_textureView->baseTexture;
|
||||
baseTexture->GetImageObj()->flagForCurrentCommandBuffer();
|
||||
|
||||
cemu_assert_debug(m_textureView->firstMip == 0);
|
||||
cemu_assert_debug(m_textureView->baseTexture->dim != Latte::E_DIM::DIM_3D);
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.bufferOffset = m_buffer_offset;
|
||||
region.bufferRowLength = baseTexture->width;
|
||||
region.bufferImageHeight = baseTexture->height;
|
||||
region.bufferRowLength = baseTexture->GetMipWidth(m_firstMip);
|
||||
region.bufferImageHeight = baseTexture->GetMipHeight(m_firstMip);
|
||||
|
||||
region.imageSubresource.aspectMask = baseTexture->GetImageAspect();
|
||||
region.imageSubresource.baseArrayLayer = m_firstSlice;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.mipLevel = m_firstMip;
|
||||
|
||||
region.imageOffset = {0,0,0};
|
||||
region.imageExtent = {(uint32)baseTexture->width,(uint32)baseTexture->height,1};
|
||||
region.imageExtent = {region.bufferRowLength, region.bufferImageHeight, 1};
|
||||
|
||||
const auto renderer = VulkanRenderer::GetInstance();
|
||||
renderer->draw_endRenderPass();
|
||||
|
||||
@@ -2458,6 +2458,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
formatInfoOut->texelCountX = width;
|
||||
formatInfoOut->texelCountY = height;
|
||||
formatInfoOut->isCompressed = false;
|
||||
formatInfoOut->isAlternateFormat = false;
|
||||
if (isDepth)
|
||||
{
|
||||
switch (format)
|
||||
@@ -2468,6 +2469,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
formatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
formatInfoOut->decoder = TextureDecoder_NullData64::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2481,6 +2483,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
formatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
formatInfoOut->decoder = TextureDecoder_NullData64::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
break;
|
||||
case Latte::E_GX2SURFFMT::D32_FLOAT:
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_D32_SFLOAT;
|
||||
@@ -2503,6 +2506,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_D16_UNORM;
|
||||
formatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
formatInfoOut->decoder = nullptr;
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2586,19 +2590,24 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
case Latte::E_GX2SURFFMT::R4_G4_UNORM:
|
||||
if (m_supportedFormatInfo.fmt_r4g4_unorm_pack == false)
|
||||
{
|
||||
if (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false) {
|
||||
if (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false)
|
||||
{
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
formatInfoOut->decoder = TextureDecoder_R4G4_UNORM_To_RGBA8::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
|
||||
formatInfoOut->decoder = TextureDecoder_R4_G4_UNORM_To_ABGR4::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R4G4_UNORM_PACK8;
|
||||
formatInfoOut->decoder = TextureDecoder_R4_G4::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true; // R and G swapped?
|
||||
}
|
||||
break;
|
||||
// R formats
|
||||
@@ -2640,37 +2649,49 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
break;
|
||||
// special formats
|
||||
case Latte::E_GX2SURFFMT::R5_G6_B5_UNORM:
|
||||
if (m_supportedFormatInfo.fmt_r5g6b5_unorm_pack == false) {
|
||||
if (m_supportedFormatInfo.fmt_r5g6b5_unorm_pack == false)
|
||||
{
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
formatInfoOut->decoder = TextureDecoder_R5G6B5_UNORM_To_RGBA8::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
// Vulkan has R in MSB, GPU7 has it in LSB
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
|
||||
formatInfoOut->decoder = TextureDecoder_R5_G6_B5_swappedRB::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
break;
|
||||
case Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM:
|
||||
if (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false) {
|
||||
if (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false)
|
||||
{
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
formatInfoOut->decoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB_To_RGBA8::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
// used in Super Mario 3D World for the hidden Luigi sprites
|
||||
// since order of channels is reversed in Vulkan compared to GX2 the format we need is A1B5G5R5
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_A1R5G5B5_UNORM_PACK16;
|
||||
formatInfoOut->decoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
break;
|
||||
case Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM:
|
||||
if (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false) {
|
||||
if (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false)
|
||||
{
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
formatInfoOut->decoder = TextureDecoder_A1_B5_G5_R5_UNORM_vulkan_To_RGBA8::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
// used by VC64 (e.g. Ocarina of Time)
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_A1R5G5B5_UNORM_PACK16; // A 15 R 10..14, G 5..9 B 0..4
|
||||
formatInfoOut->decoder = TextureDecoder_A1_B5_G5_R5_UNORM_vulkan::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
break;
|
||||
case Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT:
|
||||
@@ -2678,13 +2699,17 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
formatInfoOut->decoder = TextureDecoder_R11_G11_B10_FLOAT::getInstance();
|
||||
break;
|
||||
case Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM:
|
||||
if (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false) {
|
||||
if (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false)
|
||||
{
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
formatInfoOut->decoder = TextureDecoder_R4G4B4A4_UNORM_To_RGBA8::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
|
||||
formatInfoOut->decoder = TextureDecoder_R4_G4_B4_A4_UNORM::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true; // channel order is different?
|
||||
}
|
||||
break;
|
||||
// special formats - R10G10B10_A2
|
||||
@@ -2695,6 +2720,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
case Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM:
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_SNORM; // Vulkan has VK_FORMAT_A2R10G10B10_SNORM_PACK32 but it doesnt work?
|
||||
formatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
break;
|
||||
case Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB:
|
||||
//formatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_SNORM; // Vulkan has no uncompressed SRGB format with more than 8 bits per channel
|
||||
@@ -2702,6 +2728,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
//break;
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32; // todo - verify
|
||||
formatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
break;
|
||||
// compressed formats
|
||||
case Latte::E_GX2SURFFMT::BC1_SRGB:
|
||||
@@ -2747,15 +2774,19 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD
|
||||
case Latte::E_GX2SURFFMT::R24_X8_UNORM:
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R32_SFLOAT;
|
||||
formatInfoOut->decoder = TextureDecoder_R24_X8::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
break;
|
||||
case Latte::E_GX2SURFFMT::X24_G8_UINT:
|
||||
// used by Color Splash and Resident Evil
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UINT; // todo - should we use ABGR format?
|
||||
formatInfoOut->decoder = TextureDecoder_X24_G8_UINT::getInstance(); // todo - verify
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
break;
|
||||
case Latte::E_GX2SURFFMT::R32_X8_FLOAT:
|
||||
// seen in Disney Infinity 3.0
|
||||
formatInfoOut->vkImageFormat = VK_FORMAT_R32_SFLOAT;
|
||||
formatInfoOut->decoder = TextureDecoder_NullData64::getInstance();
|
||||
formatInfoOut->isAlternateFormat = true;
|
||||
break;
|
||||
default:
|
||||
cemuLog_log(LogType::Force, "Unsupported color texture format {:04x}", (uint32)format);
|
||||
|
||||
@@ -165,6 +165,7 @@ public:
|
||||
VkFormat vkImageFormat;
|
||||
VkImageAspectFlags vkImageAspect;
|
||||
bool isCompressed;
|
||||
bool isAlternateFormat; // true if the host pixel format doesn't 1:1 match the emulated format
|
||||
|
||||
// texture decoder info
|
||||
TextureDecoder* decoder;
|
||||
|
||||
Reference in New Issue
Block a user