Backend: Exclude more Metal only logic on non-Apple platforms

This commit is contained in:
RedBlackAka 2026-01-13 16:20:33 +01:00 committed by RedBlackAka
parent e376b15075
commit 39424eb734
13 changed files with 125 additions and 62 deletions

View File

@ -115,22 +115,24 @@ void LatteShader_calculateFSKey(LatteFetchShader* fetchShader)
}
else
{
key += (uint64)(attrib->offset & 3);
key = std::rotl<uint64>(key, 2);
key += (uint64)(attrib->offset & 3);
key = std::rotl<uint64>(key, 2);
}
}
}
// todo - also hash invalid buffer groups?
if (g_renderer->GetType() == RendererAPI::Metal)
{
for (sint32 g = 0; g < fetchShader->bufferGroups.size(); g++)
{
LatteParsedFetchShaderBufferGroup_t& group = fetchShader->bufferGroups[g];
key += (uint64)group.attributeBufferIndex;
key = std::rotl<uint64>(key, 5);
}
}
#if ENABLE_METAL
if (g_renderer->GetType() == RendererAPI::Metal)
{
for (sint32 g = 0; g < fetchShader->bufferGroups.size(); g++)
{
LatteParsedFetchShaderBufferGroup_t& group = fetchShader->bufferGroups[g];
key += (uint64)group.attributeBufferIndex;
key = std::rotl<uint64>(key, 5);
}
}
#endif
fetchShader->key = key;
}
@ -169,9 +171,9 @@ void LatteFetchShader::CalculateFetchShaderVkHash()
this->vkPipelineHashFragment = h;
}
#if ENABLE_METAL
void LatteFetchShader::CheckIfVerticesNeedManualFetchMtl(uint32* contextRegister)
{
#if ENABLE_METAL
for (sint32 g = 0; g < bufferGroups.size(); g++)
{
LatteParsedFetchShaderBufferGroup_t& group = bufferGroups[g];
@ -189,8 +191,8 @@ void LatteFetchShader::CheckIfVerticesNeedManualFetchMtl(uint32* contextRegister
mtlFetchVertexManually = true;
}
}
#endif
}
#endif
void _fetchShaderDecompiler_parseInstruction_VTX_SEMANTIC(LatteFetchShader* parsedFetchShader, uint32* contextRegister, const LatteClauseInstruction_VTX* instr)
{
@ -374,7 +376,9 @@ LatteFetchShader* LatteShaderRecompiler_createFetchShader(LatteFetchShader::Cach
// these only make sense when vertex shader does not call FS?
LatteShader_calculateFSKey(newFetchShader);
newFetchShader->CalculateFetchShaderVkHash();
#if ENABLE_METAL
newFetchShader->CheckIfVerticesNeedManualFetchMtl(contextRegister);
#endif
return newFetchShader;
}
@ -434,7 +438,9 @@ LatteFetchShader* LatteShaderRecompiler_createFetchShader(LatteFetchShader::Cach
}
LatteShader_calculateFSKey(newFetchShader);
newFetchShader->CalculateFetchShaderVkHash();
#if ENABLE_METAL
newFetchShader->CheckIfVerticesNeedManualFetchMtl(contextRegister);
#endif
// register in cache
// its possible that during multi-threaded shader cache loading, two identical (same hash) fetch shaders get created simultaneously

View File

@ -46,8 +46,10 @@ struct LatteFetchShader
// Vulkan
uint64 vkPipelineHashFragment{}; // hash of all fetch shader state that influences the Vulkan graphics pipeline
#if ENABLE_METAL
// Metal
bool mtlFetchVertexManually{};
#endif
// cache info
CacheHash m_cacheHash{};
@ -55,7 +57,9 @@ struct LatteFetchShader
void CalculateFetchShaderVkHash();
#if ENABLE_METAL
void CheckIfVerticesNeedManualFetchMtl(uint32* contextRegister);
#endif
uint64 getVkPipelineHashFragment() const { return vkPipelineHashFragment; };

View File

@ -689,12 +689,14 @@ LatteDecompilerShader* LatteShader_CreateShaderFromDecompilerOutput(LatteDecompi
shader->baseHash = baseHash;
// copy resource mapping
// HACK
if (g_renderer->GetType() == RendererAPI::Vulkan)
shader->resourceMapping = decompilerOutput.resourceMappingVK;
else if (g_renderer->GetType() == RendererAPI::OpenGL)
if (g_renderer->GetType() == RendererAPI::OpenGL)
shader->resourceMapping = decompilerOutput.resourceMappingGL;
else if (g_renderer->GetType() == RendererAPI::Vulkan)
shader->resourceMapping = decompilerOutput.resourceMappingVK;
#if ENABLE_METAL
else
shader->resourceMapping = decompilerOutput.resourceMappingMTL;
#endif
// copy texture info
shader->textureUnitMask2 = decompilerOutput.textureUnitMask;
// copy streamout info

View File

@ -63,10 +63,12 @@ struct LatteDecompilerShaderResourceMapping
sint8 tfStorageBindingPoint{-1};
// attributes (vertex shader only)
sint8 attributeMapping[LATTE_NUM_MAX_ATTRIBUTE_LOCATIONS];
#if ENABLE_METAL
// Metal exclusive
sint8 verticesPerInstanceBinding{-1};
sint8 indexBufferBinding{-1};
sint8 indexTypeBinding{-1};
#endif
sint32 getTextureCount()
{
@ -293,7 +295,9 @@ struct LatteDecompilerOutput_t
// mapping and binding information
LatteDecompilerShaderResourceMapping resourceMappingGL;
LatteDecompilerShaderResourceMapping resourceMappingVK;
#if ENABLE_METAL
LatteDecompilerShaderResourceMapping resourceMappingMTL;
#endif
};
struct LatteDecompilerSubroutineInfo;

View File

@ -403,9 +403,11 @@ void LatteDecompiler_analyzeExport(LatteDecompilerShaderContext* shaderContext,
}
else if (cfInstruction->exportType == 0 && cfInstruction->exportArrayBase == 61)
{
// Only check for depth buffer mask on Metal, as its not in the PS hash on other backends
if (g_renderer->GetType() != RendererAPI::Metal || LatteMRT::GetActiveDepthBufferMask(*shaderContext->contextRegistersNew))
#if ENABLE_METAL
// Only check for depth buffer mask on Metal, as its not in the PS hash on other backends
if (g_renderer->GetType() != RendererAPI::Metal || LatteMRT::GetActiveDepthBufferMask(*shaderContext->contextRegistersNew))
shader->depthMask = true;
#endif
}
else
debugBreakpoint();
@ -510,6 +512,7 @@ namespace LatteDecompiler
}
}
#if ENABLE_METAL
void _initTextureBindingPointsMTL(LatteDecompilerShaderContext* decompilerContext)
{
// for Vulkan we use consecutive indices
@ -521,6 +524,7 @@ namespace LatteDecompiler
decompilerContext->currentTextureBindingPointMTL++;
}
}
#endif
void _initHasUniformVarBlock(LatteDecompilerShaderContext* decompilerContext)
{
@ -589,8 +593,10 @@ namespace LatteDecompiler
{
decompilerContext->output->resourceMappingVK.uniformVarsBufferBindingPoint = decompilerContext->currentBindingPointVK;
decompilerContext->currentBindingPointVK++;
#if ENABLE_METAL
decompilerContext->output->resourceMappingMTL.uniformVarsBufferBindingPoint = decompilerContext->currentBufferBindingPointMTL;
decompilerContext->currentBufferBindingPointMTL++;
#endif
}
// assign binding points to uniform buffers
if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)
@ -610,8 +616,10 @@ namespace LatteDecompiler
decompilerContext->output->resourceMappingVK.uniformBuffersBindingPoint[i] = decompilerContext->currentBindingPointVK;
decompilerContext->currentBindingPointVK++;
#if ENABLE_METAL
decompilerContext->output->resourceMappingMTL.uniformBuffersBindingPoint[i] = decompilerContext->currentBufferBindingPointMTL;
decompilerContext->currentBufferBindingPointMTL++;
#endif
}
// for OpenGL we use the relative buffer index
for (uint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)
@ -633,8 +641,10 @@ namespace LatteDecompiler
{
decompilerContext->output->resourceMappingVK.tfStorageBindingPoint = decompilerContext->currentBindingPointVK;
decompilerContext->currentBindingPointVK++;
#if ENABLE_METAL
decompilerContext->output->resourceMappingMTL.tfStorageBindingPoint = decompilerContext->currentBufferBindingPointMTL;
decompilerContext->currentBufferBindingPointMTL++;
#endif
}
}
@ -651,7 +661,9 @@ namespace LatteDecompiler
{
decompilerContext->output->resourceMappingGL.attributeMapping[i] = bindingIndex;
decompilerContext->output->resourceMappingVK.attributeMapping[i] = bindingIndex;
#if ENABLE_METAL
decompilerContext->output->resourceMappingMTL.attributeMapping[i] = bindingIndex;
#endif
bindingIndex++;
}
}
@ -1109,10 +1121,14 @@ void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteD
shaderContext->output->resourceMappingVK.setIndex = 2;
LatteDecompiler::_initTextureBindingPointsGL(shaderContext);
LatteDecompiler::_initTextureBindingPointsVK(shaderContext);
#if ENABLE_METAL
LatteDecompiler::_initTextureBindingPointsMTL(shaderContext);
#endif
LatteDecompiler::_initUniformBindingPoints(shaderContext);
LatteDecompiler::_initAttributeBindingPoints(shaderContext);
#if ENABLE_METAL
shaderContext->output->resourceMappingMTL.verticesPerInstanceBinding = shaderContext->currentBufferBindingPointMTL++;
shaderContext->output->resourceMappingMTL.indexBufferBinding = shaderContext->currentBufferBindingPointMTL++;
shaderContext->output->resourceMappingMTL.indexTypeBinding = shaderContext->currentBufferBindingPointMTL++;
#endif
}

View File

@ -117,11 +117,10 @@ struct LatteDecompilerCFInstruction
#if BOOST_OS_WINDOWS
LatteDecompilerCFInstruction(LatteDecompilerCFInstruction& mE) = default;
LatteDecompilerCFInstruction(LatteDecompilerCFInstruction&& mE) = default;
#else
LatteDecompilerCFInstruction(const LatteDecompilerCFInstruction& mE) = default;
LatteDecompilerCFInstruction(LatteDecompilerCFInstruction&& mE) = default;
#endif
LatteDecompilerCFInstruction(LatteDecompilerCFInstruction&& mE) = default;
LatteDecompilerCFInstruction& operator=(LatteDecompilerCFInstruction&& mE) = default;
};
@ -260,8 +259,10 @@ struct LatteDecompilerShaderContext
// emitter
bool hasUniformVarBlock;
sint32 currentBindingPointVK{};
#if ENABLE_METAL
sint32 currentBufferBindingPointMTL{};
sint32 currentTextureBindingPointMTL{};
#endif
struct ALUClauseTemporariesState* aluPVPSState{nullptr};
// misc
std::vector<LatteDecompilerSubroutineInfo> list_subroutines;
@ -270,7 +271,9 @@ struct LatteDecompilerShaderContext
void LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader);
void LatteDecompiler_analyzeDataTypes(LatteDecompilerShaderContext* shaderContext);
void LatteDecompiler_emitGLSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader);
#if ENABLE_METAL
void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader);
#endif
void LatteDecompiler_cleanup(LatteDecompilerShaderContext* shaderContext);

View File

@ -10,6 +10,7 @@ void outputShader()
}
)";
#if ENABLE_METAL
const std::string RendererOutputShader::s_copy_shader_source_mtl =
R"(#include <metal_stdlib>
using namespace metal;
@ -22,6 +23,7 @@ fragment float4 main0(VertexOut in [[stage_in]], texture2d<float> textureSrc [[t
return float4(textureSrc.sample(samplr, in.uv).rgb, 1.0);
}
)";
#endif
const std::string RendererOutputShader::s_bicubic_shader_source =
R"(
@ -69,6 +71,7 @@ void outputShader(){
}
)";
#if ENABLE_METAL
const std::string RendererOutputShader::s_bicubic_shader_source_mtl =
R"(#include <metal_stdlib>
using namespace metal;
@ -119,6 +122,7 @@ fragment float4 main0(VertexOut in [[stage_in]], texture2d<float> textureSrc [[t
return float4(bcFilter(textureSrc, samplr, in.uv * textureSrcResolution, float2(1.0, 1.0) / textureSrcResolution).rgb, 1.0);
}
)";
#endif
const std::string RendererOutputShader::s_hermite_shader_source =
R"(
@ -179,6 +183,7 @@ void outputShader(){
}
)";
#if ENABLE_METAL
const std::string RendererOutputShader::s_hermite_shader_source_mtl =
R"(#include <metal_stdlib>
using namespace metal;
@ -242,14 +247,15 @@ fragment float4 main0(VertexOut in [[stage_in]], texture2d<float> textureSrc [[t
return float4(BicubicHermiteTexture(textureSrc, samplr, in.uv, texelSize), 1.0);
}
)";
#endif
RendererOutputShader::RendererOutputShader(const std::string& vertex_source, const std::string& fragment_source)
{
std::string finalFragmentSrc;
if (g_renderer->GetType() == RendererAPI::Metal)
finalFragmentSrc = fragment_source;
else
finalFragmentSrc = PrependFragmentPreamble(fragment_source);
std::string finalFragmentSrc;
if (g_renderer->GetType() == RendererAPI::Metal)
finalFragmentSrc = fragment_source;
else
finalFragmentSrc = PrependFragmentPreamble(fragment_source);
m_vertex_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kVertex, 0, 0, vertex_source, false, false));
m_fragment_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kFragment, 0, 0, finalFragmentSrc, false, false));
@ -397,7 +403,7 @@ layout(location = 0) out vec2 passUV;
out gl_PerVertex
{
vec4 gl_Position;
vec4 gl_Position;
};
void main(){
@ -437,6 +443,7 @@ void main(){
return vertex_source.str();
}
#if ENABLE_METAL
std::string RendererOutputShader::GetMetalVertexSource(bool render_upside_down)
{
// vertex shader
@ -446,8 +453,8 @@ std::string RendererOutputShader::GetMetalVertexSource(bool render_upside_down)
using namespace metal;
struct VertexOut {
float4 position [[position]];
float2 uv;
float4 position [[position]];
float2 uv;
};
vertex VertexOut main0(ushort vid [[vertex_id]]) {
@ -474,6 +481,7 @@ vertex VertexOut main0(ushort vid [[vertex_id]]) {
)";
return vertex_source.str();
}
#endif
std::string RendererOutputShader::PrependFragmentPreamble(const std::string& shaderSrc)
{
@ -533,43 +541,45 @@ void main()
}
void RendererOutputShader::InitializeStatic()
{
if (g_renderer->GetType() == RendererAPI::Metal)
{
std::string vertex_source = GetMetalVertexSource(false);
std::string vertex_source_ud = GetMetalVertexSource(true);
if (g_renderer->GetType() == RendererAPI::Metal)
{
#if ENABLE_METAL
std::string vertex_source = GetMetalVertexSource(false);
std::string vertex_source_ud = GetMetalVertexSource(true);
s_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source_mtl);
s_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source_mtl);
s_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source_mtl);
s_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source_mtl);
s_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source_mtl);
s_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source_mtl);
s_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source_mtl);
s_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source_mtl);
s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source_mtl);
s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source_mtl);
}
else
{
std::string vertex_source, vertex_source_ud;
// vertex shader
if (g_renderer->GetType() == RendererAPI::OpenGL)
{
vertex_source = GetOpenGlVertexSource(false);
vertex_source_ud = GetOpenGlVertexSource(true);
}
else if (g_renderer->GetType() == RendererAPI::Vulkan)
{
vertex_source = GetVulkanVertexSource(false);
vertex_source_ud = GetVulkanVertexSource(true);
}
s_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source);
s_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source);
s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source_mtl);
s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source_mtl);
#endif
}
else
{
std::string vertex_source, vertex_source_ud;
// vertex shader
if (g_renderer->GetType() == RendererAPI::OpenGL)
{
vertex_source = GetOpenGlVertexSource(false);
vertex_source_ud = GetOpenGlVertexSource(true);
}
else if (g_renderer->GetType() == RendererAPI::Vulkan)
{
vertex_source = GetVulkanVertexSource(false);
vertex_source_ud = GetVulkanVertexSource(true);
}
s_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source);
s_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source);
s_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source);
s_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source);
s_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source);
s_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source);
s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source);
s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source);
}
s_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source);
s_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source);
}
}
void RendererOutputShader::ShutdownStatic()

View File

@ -43,7 +43,9 @@ public:
static std::string GetOpenGlVertexSource(bool render_upside_down);
static std::string GetVulkanVertexSource(bool render_upside_down);
#if ENABLE_METAL
static std::string GetMetalVertexSource(bool render_upside_down);
#endif
static std::string PrependFragmentPreamble(const std::string& shaderSrc);
@ -69,7 +71,9 @@ private:
static const std::string s_bicubic_shader_source_vk;
static const std::string s_hermite_shader_source_vk;
#if ENABLE_METAL
static const std::string s_copy_shader_source_mtl;
static const std::string s_bicubic_shader_source_mtl;
static const std::string s_hermite_shader_source_mtl;
#endif
};

View File

@ -128,7 +128,9 @@ XMLConfigParser CemuConfig::Load(XMLConfigParser& parser)
auto graphic = parser.get("Graphic");
graphic_api = graphic.get("api", kOpenGL);
graphic.get("vkDevice", vk_graphic_device_uuid);
#if ENABLE_METAL
mtl_graphic_device_uuid = graphic.get("mtlDevice", 0);
#endif
vsync = graphic.get("VSync", 0);
overrideAppGammaPreference = graphic.get("OverrideAppGammaPreference", false);
overrideGammaValue = graphic.get("OverrideGammaValue", 2.2f);
@ -360,7 +362,9 @@ XMLConfigParser CemuConfig::Save(XMLConfigParser& parser)
auto graphic = config.set("Graphic");
graphic.set("api", graphic_api);
graphic.set("vkDevice", vk_graphic_device_uuid);
#if ENABLE_METAL
graphic.set("mtlDevice", mtl_graphic_device_uuid);
#endif
graphic.set("VSync", vsync);
graphic.set("OverrideAppGammaPreference", overrideAppGammaPreference);
graphic.set("OverrideGammaValue", overrideGammaValue);

View File

@ -121,6 +121,7 @@ enum class AccurateShaderMulOption
};
ENABLE_ENUM_ITERATORS(AccurateShaderMulOption, AccurateShaderMulOption::False, AccurateShaderMulOption::True);
#if ENABLE_METAL
enum class MetalBufferCacheMode
{
Auto,
@ -129,6 +130,7 @@ enum class MetalBufferCacheMode
Host,
};
ENABLE_ENUM_ITERATORS(MetalBufferCacheMode, MetalBufferCacheMode::Auto, MetalBufferCacheMode::Host);
#endif
enum class PositionInvariance
{
@ -235,6 +237,7 @@ struct fmt::formatter<AccurateShaderMulOption> : formatter<string_view> {
return formatter<string_view>::format(name, ctx);
}
};
#if ENABLE_METAL
template <>
struct fmt::formatter<MetalBufferCacheMode> : formatter<string_view> {
template <typename FormatContext>
@ -251,6 +254,7 @@ struct fmt::formatter<MetalBufferCacheMode> : formatter<string_view> {
return formatter<string_view>::format(name, ctx);
}
};
#endif
template <>
struct fmt::formatter<PositionInvariance> : formatter<string_view> {
template <typename FormatContext>
@ -433,7 +437,9 @@ struct CemuConfig
// graphics
ConfigValue<GraphicAPI> graphic_api{ kVulkan };
std::array<uint8, 16> vk_graphic_device_uuid;
#if ENABLE_METAL
uint64 mtl_graphic_device_uuid{ 0 };
#endif
ConfigValue<int> vsync{ 0 }; // 0 = off, 1+ = depending on render backend
ConfigValue<bool> gx2drawdone_sync { true };
ConfigValue<bool> render_upside_down{ false };

View File

@ -1206,21 +1206,21 @@ void GeneralSettings2::StoreConfig()
else
config.vk_graphic_device_uuid = {};
}
#if ENABLE_METAL
else if (config.graphic_api == GraphicAPI::kMetal)
{
if (selection != wxNOT_FOUND)
{
#if ENABLE_METAL
const auto* info = (wxMetalUUID*)m_graphic_device->GetClientObject(selection);
if (info)
config.mtl_graphic_device_uuid = info->GetDeviceInfo().uuid;
else
config.mtl_graphic_device_uuid = {};
#endif
}
else
config.mtl_graphic_device_uuid = {};
}
#endif
config.vsync = m_vsync->GetSelection();

View File

@ -13,7 +13,9 @@
#include "AudioDebuggerWindow.h"
#include "wxgui/canvas/OpenGLCanvas.h"
#include "wxgui/canvas/VulkanCanvas.h"
#if ENABLE_METAL
#include "wxgui/canvas/MetalCanvas.h"
#endif
#include "Cafe/OS/libs/nfc/nfc.h"
#include "Cafe/OS/libs/swkbd/swkbd.h"
#include "wxgui/debugger/DebuggerWindow2.h"

View File

@ -8,7 +8,9 @@
#include "Cafe/OS/libs/swkbd/swkbd.h"
#include "wxgui/canvas/OpenGLCanvas.h"
#include "wxgui/canvas/VulkanCanvas.h"
#if ENABLE_METAL
#include "wxgui/canvas/MetalCanvas.h"
#endif
#include "config/CemuConfig.h"
#include "wxgui/MainWindow.h"
#include "wxgui/helpers/wxHelpers.h"