diff --git a/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp index 85adbfb9..a7e87c79 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp @@ -7,6 +7,7 @@ CachedFBOMtl::CachedFBOMtl(class MetalRenderer* metalRenderer, uint64 key) : Lat { m_renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); + bool hasAttachment = false; for (int i = 0; i < 8; ++i) { const auto& buffer = colorBuffer[i]; @@ -19,6 +20,8 @@ CachedFBOMtl::CachedFBOMtl(class MetalRenderer* metalRenderer, uint64 key) : Lat colorAttachment->setTexture(textureView->GetRGBAView()); colorAttachment->setLoadAction(MTL::LoadActionLoad); colorAttachment->setStoreAction(MTL::StoreActionStore); + + hasAttachment = true; } // setup depth attachment @@ -38,6 +41,17 @@ CachedFBOMtl::CachedFBOMtl(class MetalRenderer* metalRenderer, uint64 key) : Lat stencilAttachment->setLoadAction(MTL::LoadActionLoad); stencilAttachment->setStoreAction(MTL::StoreActionStore); } + + hasAttachment = true; + } + + // HACK: setup a dummy color attachment to prevent Metal from discarding draws for stremout draws in Super Smash Bros. for Wii U (works fine on MoltenVK without this hack though) + if (!hasAttachment) + { + auto colorAttachment = m_renderPassDescriptor->colorAttachments()->object(0); + colorAttachment->setTexture(metalRenderer->GetNullTexture2D()); + colorAttachment->setLoadAction(MTL::LoadActionDontCare); + colorAttachment->setStoreAction(MTL::StoreActionDontCare); } // Visibility buffer diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp index ee855135..436ef99c 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp @@ -10,6 +10,7 @@ #include "Cafe/HW/Latte/Core/FetchShader.h" #include "Cafe/HW/Latte/ISA/RegDefines.h" #include "Cemu/Logging/CemuLogging.h" +#include "HW/Latte/Core/LatteConst.h" #include "config/ActiveSettings.h" static void rectsEmulationGS_outputSingleVertex(std::string& gsSrc, const LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 vIdx, const LatteContextRegister& latteRegister) @@ -206,20 +207,21 @@ void SetFragmentState(T* desc, CachedFBOMtl* lastUsedFBO, CachedFBOMtl* activeFB if (cullFront && cullBack) rasterizationEnabled = false; - if (!rasterizationEnabled) + auto pixelShaderMtl = static_cast(pixelShader->shader); + + if (!rasterizationEnabled || !pixelShaderMtl) { desc->setRasterizationEnabled(false); return; } - auto pixelShaderMtl = static_cast(pixelShader->shader); - desc->setFragmentFunction(pixelShaderMtl->GetFunction()); + desc->setFragmentFunction(pixelShaderMtl->GetFunction()); // Color attachments const Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = lcr.CB_COLOR_CONTROL; uint32 blendEnableMask = colorControlReg.get_BLEND_MASK(); uint32 renderTargetMask = lcr.CB_TARGET_MASK.get_MASK(); - for (uint8 i = 0; i < 8; i++) + for (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++) { const auto& colorBuffer = lastUsedFBO->colorBuffer[i]; auto texture = static_cast(colorBuffer.texture); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 3b809100..9a88c249 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -863,7 +863,6 @@ void MetalRenderer::draw_beginSequence() return; // no render target } - // TODO: not checking for !streamoutEnable fixes Super Smash Bros. for Wii U, investigate why if (!hasValidFramebufferAttached && !streamoutEnable) { debug_printf("Drawcall with no color buffer or depth buffer attached\n"); @@ -1476,10 +1475,6 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecr auto commandBuffer = GetCommandBuffer(); - // Update state - m_state.m_lastUsedFBO = m_state.m_activeFBO; - m_state.m_isFirstDrawInRenderPass = true; - auto renderCommandEncoder = commandBuffer->renderCommandEncoder(m_state.m_activeFBO->GetRenderPassDescriptor()); #ifdef CEMU_DEBUG_ASSERT renderCommandEncoder->setLabel(GetLabel("Render command encoder", renderCommandEncoder)); @@ -1487,6 +1482,10 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecr m_commandEncoder = renderCommandEncoder; m_encoderType = MetalEncoderType::Render; + // Update state + m_state.m_lastUsedFBO = m_state.m_activeFBO; + m_state.m_isFirstDrawInRenderPass = true; + ResetEncoderState(); // Debug diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index abb7f7e5..5b8406d2 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -380,6 +380,11 @@ public: return (m_hasUnifiedMemory ? MTL::ResourceStorageModeShared : MTL::ResourceStorageModeManaged); } + MTL::Texture* GetNullTexture2D() const + { + return m_nullTexture2D; + } + MTL::Buffer* GetTextureReadbackBuffer() { if (!m_readbackBuffer)