From 06491baafa134a88379136656352c03788bb70bf Mon Sep 17 00:00:00 2001 From: Samuliak Date: Tue, 11 Feb 2025 18:09:42 +0100 Subject: [PATCH] check for mesh shaders support --- src/Cafe/HW/Latte/Core/LatteShader.cpp | 8 +++++--- .../LatteDecompilerAnalyzer.cpp | 7 +++++-- .../LatteDecompilerEmitMSL.cpp | 8 ++++---- .../LatteDecompilerEmitMSLHeader.hpp | 20 +++++++++---------- .../HW/Latte/Renderer/Metal/MetalCommon.h | 9 +++++++++ .../Renderer/Metal/MetalPipelineCompiler.cpp | 16 ++++++++------- .../Renderer/Metal/MetalPipelineCompiler.h | 2 +- .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 12 ++++++----- .../HW/Latte/Renderer/Metal/MetalRenderer.h | 7 ++++++- 9 files changed, 56 insertions(+), 33 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteShader.cpp b/src/Cafe/HW/Latte/Core/LatteShader.cpp index 3091e079..77ea3819 100644 --- a/src/Cafe/HW/Latte/Core/LatteShader.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShader.cpp @@ -510,7 +510,7 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize, vsHash += tmp; auto primitiveType = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE(); - // TODO: include always in the hash in case of geometry shader or rect shader + // TODO: include always in the hash in case of geometry shader or rect shader on Metal if (primitiveType == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS) { vsHash += 13ULL; @@ -528,7 +528,9 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize, #if ENABLE_METAL if (g_renderer->GetType() == RendererAPI::Metal) { - if (usesGeometryShader || _activeFetchShader->mtlFetchVertexManually) + bool isRectVertexShader = (primitiveType == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); + + if ((usesGeometryShader || isRectVertexShader) || _activeFetchShader->mtlFetchVertexManually) { for (sint32 g = 0; g < _activeFetchShader->bufferGroups.size(); g++) { @@ -542,7 +544,7 @@ void LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize, } } - if (!usesGeometryShader) + if (!(usesGeometryShader || isRectVertexShader)) { if (LatteGPUState.contextNew.IsRasterizationEnabled()) vsHash += 51ULL; diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp index ce320316..fe0caed8 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp @@ -10,6 +10,9 @@ #include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Common/MemPtr.h" #include "HW/Latte/ISA/LatteReg.h" +#if ENABLE_METAL +#include "HW/Latte/Renderer/Metal/MetalCommon.h" +#endif // Defined in LatteTextureLegacy.cpp Latte::E_GX2SURFFMT LatteTexture_ReconstructGX2Format(const Latte::LATTE_SQ_TEX_RESOURCE_WORD1_N& texUnitWord1, const Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N& texUnitWord4); @@ -557,9 +560,9 @@ namespace LatteDecompiler } if (g_renderer->GetType() == RendererAPI::Metal) { - bool isRectVertexShader = (static_cast(decompilerContext->contextRegisters[mmVGT_PRIMITIVE_TYPE]) == LattePrimitiveMode::RECTS); + bool usesGeometryShader = UseGeometryShader(*decompilerContext->contextRegistersNew, decompilerContext->options->usesGeometryShader); - if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && (decompilerContext->options->usesGeometryShader || isRectVertexShader)) + if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && usesGeometryShader) decompilerContext->hasUniformVarBlock = true; // uf_verticesPerInstance } } diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp index a2b0bc2d..a9f682a6 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp @@ -3933,8 +3933,8 @@ static void LatteDecompiler_emitAttributeImport(LatteDecompilerShaderContext* sh void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader) { - bool isRectVertexShader = (static_cast(shaderContext->contextRegisters[mmVGT_PRIMITIVE_TYPE]) == LattePrimitiveMode::RECTS); - bool usesGeometryShader = (shaderContext->options->usesGeometryShader || isRectVertexShader); + bool isRectVertexShader = UseRectEmulation(*shaderContext->contextRegistersNew); + bool usesGeometryShader = UseGeometryShader(*shaderContext->contextRegistersNew, shaderContext->options->usesGeometryShader); bool fetchVertexManually = (usesGeometryShader || (shaderContext->fetchShader && shaderContext->fetchShader->mtlFetchVertexManually)); // Rasterization @@ -3953,7 +3953,7 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, src->add("#include " _CRLF); src->add("using namespace metal;" _CRLF); // header part (definitions for inputs and outputs) - LatteDecompiler::emitHeader(shaderContext, isRectVertexShader, fetchVertexManually, rasterizationEnabled); + LatteDecompiler::emitHeader(shaderContext, isRectVertexShader, usesGeometryShader, fetchVertexManually, rasterizationEnabled); // helper functions LatteDecompiler_emitHelperFunctions(shaderContext, src); const char* functionType = ""; @@ -4131,7 +4131,7 @@ void LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, } // start of main src->addFmt("{} {} main0(", functionType, outputTypeName); - LatteDecompiler::emitInputs(shaderContext, isRectVertexShader, fetchVertexManually); + LatteDecompiler::emitInputs(shaderContext, isRectVertexShader, usesGeometryShader, fetchVertexManually); src->add(") {" _CRLF); if (fetchVertexManually && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry)) { diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp index 96797699..475ec0da 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp @@ -6,7 +6,7 @@ namespace LatteDecompiler { - static void _emitUniformVariables(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader) + static void _emitUniformVariables(LatteDecompilerShaderContext* decompilerContext, bool usesGeometryShader) { auto src = decompilerContext->shaderSource; @@ -87,7 +87,7 @@ namespace LatteDecompiler } // define verticesPerInstance + streamoutBufferBaseX if ((shader->shaderType == LatteConst::ShaderType::Vertex && - (decompilerContext->options->usesGeometryShader || isRectVertexShader)) || + usesGeometryShader) || (decompilerContext->analyzer.useSSBOForStreamout && (shader->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) || (shader->shaderType == LatteConst::ShaderType::Geometry))) @@ -270,7 +270,7 @@ namespace LatteDecompiler src->add("};" _CRLF _CRLF); } - static void _emitInputsAndOutputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool fetchVertexManually, bool rasterizationEnabled) + static void _emitInputsAndOutputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool usesGeometryShader, bool fetchVertexManually, bool rasterizationEnabled) { auto src = decompilerContext->shaderSource; @@ -304,7 +304,7 @@ namespace LatteDecompiler src->add("};" _CRLF _CRLF); } - if (!decompilerContext->options->usesGeometryShader) + if (!usesGeometryShader || isRectVertexShader) { if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && rasterizationEnabled) _emitVSOutputs(decompilerContext, isRectVertexShader); @@ -357,11 +357,11 @@ namespace LatteDecompiler } } - static void emitHeader(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool fetchVertexManually, bool rasterizationEnabled) + static void emitHeader(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool usesGeometryShader, bool fetchVertexManually, bool rasterizationEnabled) { auto src = decompilerContext->shaderSource; - if ((decompilerContext->options->usesGeometryShader || isRectVertexShader) && (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)) + if (usesGeometryShader && (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)) { LattePrimitiveMode vsOutPrimType = decompilerContext->contextRegistersNew->VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE(); src->addFmt("#define VERTICES_PER_VERTEX_PRIMITIVE {}" _CRLF, GetVerticesPerPrimitive(vsOutPrimType)); @@ -399,11 +399,11 @@ namespace LatteDecompiler if(dump_shaders_enabled) decompilerContext->shaderSource->add("// start of shader inputs/outputs, predetermined by Cemu. Do not touch" _CRLF); // uniform variables - _emitUniformVariables(decompilerContext, isRectVertexShader); + _emitUniformVariables(decompilerContext, usesGeometryShader); // uniform buffers _emitUniformBuffers(decompilerContext); // inputs and outputs - _emitInputsAndOutputs(decompilerContext, isRectVertexShader, fetchVertexManually, rasterizationEnabled); + _emitInputsAndOutputs(decompilerContext, isRectVertexShader, usesGeometryShader, fetchVertexManually, rasterizationEnabled); if (dump_shaders_enabled) decompilerContext->shaderSource->add("// end of shader inputs/outputs" _CRLF); @@ -491,14 +491,14 @@ namespace LatteDecompiler } } - static void emitInputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool fetchVertexManually) + static void emitInputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool usesGeometryShader, bool fetchVertexManually) { auto src = decompilerContext->shaderSource; switch (decompilerContext->shaderType) { case LatteConst::ShaderType::Vertex: - if (decompilerContext->options->usesGeometryShader || isRectVertexShader) + if (usesGeometryShader) { src->add("object_data ObjectPayload& objectPayload [[payload]]"); src->add(", mesh_grid_properties meshGridProperties"); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h index b46978ec..d16c5597 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h @@ -210,3 +210,12 @@ inline bool PrimitiveRequiresConnection(LattePrimitiveMode primitiveMode) else return false; } + +inline bool UseRectEmulation(const LatteContextRegister& lcr) { + const LattePrimitiveMode primitiveMode = lcr.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE(); + return (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); +} + +inline bool UseGeometryShader(const LatteContextRegister& lcr, bool hasGeometryShader) { + return hasGeometryShader || UseRectEmulation(lcr); +} diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp index 1892c257..6193ab10 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp @@ -283,16 +283,15 @@ MetalPipelineCompiler::~MetalPipelineCompiler() m_binaryArchiveURL->release(); */ - m_pipelineDescriptor->release(); + if (m_pipelineDescriptor) + m_pipelineDescriptor->release(); } void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr) { - // Check if the pipeline uses a geometry shader - const LattePrimitiveMode primitiveMode = static_cast(lcr.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE()); - bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); - - m_usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect); + m_usesGeometryShader = UseGeometryShader(lcr, geometryShader != nullptr); + if (m_usesGeometryShader && !m_mtlr->SupportsMeshShaders()) + return; // Rasterization m_rasterizationEnabled = lcr.IsRasterizationEnabled(); @@ -301,7 +300,7 @@ void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, c m_vertexShaderMtl = static_cast(vertexShader->shader); if (geometryShader) m_geometryShaderMtl = static_cast(geometryShader->shader); - else if (isPrimitiveRect) + else if (UseRectEmulation(lcr)) m_geometryShaderMtl = rectsEmulationGS_generate(m_mtlr, vertexShader, lcr); else m_geometryShaderMtl = nullptr; @@ -315,6 +314,9 @@ void MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, c bool MetalPipelineCompiler::Compile(bool forceCompile, bool isRenderThread, bool showInOverlay) { + if (m_usesGeometryShader && !m_mtlr->SupportsMeshShaders()) + return false; + if (forceCompile) { // if some shader stages are not compiled yet, compile them now diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h index 5006ed59..4d21e53d 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h @@ -30,7 +30,7 @@ private: bool m_usesGeometryShader; bool m_rasterizationEnabled; - NS::Object* m_pipelineDescriptor; + NS::Object* m_pipelineDescriptor = nullptr; void InitFromStateRender(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 02bf91f8..0982c8a4 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -21,7 +21,6 @@ #include "Cemu/Logging/CemuLogging.h" #include "Cafe/HW/Latte/Core/FetchShader.h" #include "Cafe/HW/Latte/Core/LatteConst.h" -#include "HW/Latte/Renderer/Metal/MetalCommon.h" #include "config/CemuConfig.h" #include "gui/guiWrapper.h" @@ -171,6 +170,7 @@ MetalRenderer::MetalRenderer() m_supportsFramebufferFetch = GetConfig().framebuffer_fetch.GetValue() ? m_device->supportsFamily(MTL::GPUFamilyApple2) : false; m_hasUnifiedMemory = m_device->hasUnifiedMemory(); m_supportsMetal3 = m_device->supportsFamily(MTL::GPUFamilyMetal3); + m_supportsMeshShaders = (m_supportsMetal3 && m_vendor != GfxVendor::Intel); // Intel GPUs have issues with mesh shaders m_recommendedMaxVRAMUsage = m_device->recommendedMaxWorkingSetSize(); m_pixelFormatSupport = MetalPixelFormatSupport(m_device); @@ -1134,9 +1134,11 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 // Primitive type const LattePrimitiveMode primitiveMode = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE(); auto mtlPrimitiveType = GetMtlPrimitiveType(primitiveMode); - bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); - bool usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect); + bool usesGeometryShader = UseGeometryShader(LatteGPUState.contextNew, geometryShader != nullptr); + if (usesGeometryShader && !m_supportsMeshShaders) + return; + bool fetchVertexManually = (usesGeometryShader || fetchShader->mtlFetchVertexManually); // Index buffer @@ -1293,7 +1295,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 // todo - how does culling behave with rects? // right now we just assume that their winding is always CW - if (isPrimitiveRect) + if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS) { if (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CW) cullFront = cullBack; @@ -1380,7 +1382,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 // Uniform buffers, textures and samplers BindStageResources(renderCommandEncoder, vertexShader, usesGeometryShader); - if (geometryShader) + if (usesGeometryShader && geometryShader) BindStageResources(renderCommandEncoder, geometryShader, usesGeometryShader); BindStageResources(renderCommandEncoder, pixelShader, usesGeometryShader); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index 6dc780d8..428284f2 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -6,7 +6,6 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h" -#include "Foundation/NSAutoreleasePool.hpp" enum MetalGeneralShaderType { @@ -385,6 +384,11 @@ public: return m_supportsMetal3; } + bool SupportsMeshShaders() const + { + return m_supportsMeshShaders; + } + //MTL::StorageMode GetOptimalTextureStorageMode() const //{ // return (m_isAppleGPU ? MTL::StorageModeShared : MTL::StorageModePrivate); @@ -483,6 +487,7 @@ private: bool m_supportsFramebufferFetch; bool m_hasUnifiedMemory; bool m_supportsMetal3; + bool m_supportsMeshShaders; uint32 m_recommendedMaxVRAMUsage; MetalPixelFormatSupport m_pixelFormatSupport;