diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp index 6a696e11..0b23fecd 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp @@ -221,7 +221,7 @@ namespace LatteDecompiler { auto* src = shaderContext->shaderSource; - src->add("#define GET_FRAGCOORD() vec4(in.position.xy * supportBuffer.fragCoordScale.xy, in.position.z, 1.0 / in.position.w)" _CRLF); + src->add("#define GET_FRAGCOORD() float4(in.position.xy * supportBuffer.fragCoordScale.xy, in.position.z, 1.0 / in.position.w)" _CRLF); src->add("struct FragmentIn {" _CRLF); src->add("float4 position [[position]];" _CRLF); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp index 933752eb..63cd69f6 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp @@ -67,7 +67,7 @@ LatteTextureMtl::LatteTextureMtl(class MetalRenderer* mtlRenderer, Latte::E_DIM auto formatInfo = GetMtlPixelFormatInfo(format, isDepth); desc->setPixelFormat(formatInfo.pixelFormat); - // TODO: is write needed? + // HACK: even though the textures are never written to from a shader, we still need to use `ShaderWrite` usage to prevent pink lines over the screen MTL::TextureUsage usage = MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite; // TODO: add more conditions if (!Latte::IsCompressedFormat(format)) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 5d35baa3..cb71f90b 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -16,6 +16,7 @@ #include "Cemu/Logging/CemuDebugLogging.h" #include "HW/Latte/Core/Latte.h" #include "HW/Latte/ISA/LatteReg.h" +#include "Metal/MTLRenderCommandEncoder.hpp" #include "Metal/MTLResource.hpp" #include "Metal/MTLTypes.hpp" #include "gui/guiWrapper.h" @@ -600,7 +601,7 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 const auto fetchShader = LatteSHRC_GetActiveFetchShader(); // Render pipeline state - MTL::RenderPipelineState* renderPipelineState = m_pipelineCache->GetPipelineState(fetchShader, vertexShader, pixelShader, m_state.activeFBO, LatteGPUState.contextNew); + MTL::RenderPipelineState* renderPipelineState = m_pipelineCache->GetPipelineState(fetchShader, vertexShader, pixelShader, m_state.lastUsedFBO, LatteGPUState.contextNew); renderCommandEncoder->setRenderPipelineState(renderPipelineState); // Depth stencil state @@ -620,9 +621,54 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 renderCommandEncoder->setStencilReferenceValue(stencilRefFront); } - // Primitive type - const LattePrimitiveMode primitiveMode = static_cast(LatteGPUState.contextRegister[mmVGT_PRIMITIVE_TYPE]); - auto mtlPrimitiveType = GetMtlPrimitiveType(primitiveMode); + // Primitive type + const LattePrimitiveMode primitiveMode = static_cast(LatteGPUState.contextRegister[mmVGT_PRIMITIVE_TYPE]); + auto mtlPrimitiveType = GetMtlPrimitiveType(primitiveMode); + bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS); + + // Blend color + float* blendColorConstant = (float*)LatteGPUState.contextRegister + Latte::REGADDR::CB_BLEND_RED; + renderCommandEncoder->setBlendColor(blendColorConstant[0], blendColorConstant[1], blendColorConstant[2], blendColorConstant[3]); + + // polygon control + const auto& polygonControlReg = LatteGPUState.contextNew.PA_SU_SC_MODE_CNTL; + const auto frontFace = polygonControlReg.get_FRONT_FACE(); + uint32 cullFront = polygonControlReg.get_CULL_FRONT(); + uint32 cullBack = polygonControlReg.get_CULL_BACK(); + uint32 polyOffsetFrontEnable = polygonControlReg.get_OFFSET_FRONT_ENABLED(); + + // TODO + //cemu_assert_debug(LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_NEAR_DISABLE() == LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_FAR_DISABLE()); // near or far clipping can be disabled individually + //bool zClipEnable = LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_FAR_DISABLE() == false; + + if (polyOffsetFrontEnable) + { + // TODO: set depth bias + } + + // todo - how does culling behave with rects? + // right now we just assume that their winding is always CW + if (isPrimitiveRect) + { + if (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CW) + cullFront = cullBack; + else + cullBack = cullFront; + } + + if (cullFront && cullBack) + return; // We can just skip the draw (TODO: can we?) + else if (cullFront) + renderCommandEncoder->setCullMode(MTL::CullModeFront); + else if (cullBack) + renderCommandEncoder->setCullMode(MTL::CullModeBack); + else + renderCommandEncoder->setCullMode(MTL::CullModeNone); + + if (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CCW) + renderCommandEncoder->setFrontFacingWinding(MTL::WindingCounterClockwise); + else + renderCommandEncoder->setFrontFacingWinding(MTL::WindingClockwise); // Resources @@ -708,7 +754,7 @@ void MetalRenderer::EnsureCommandBuffer() if (!m_commandBuffer) { // Debug - m_commandQueue->insertDebugCaptureBoundary(); + //m_commandQueue->insertDebugCaptureBoundary(); m_commandBuffer = m_commandQueue->commandBuffer(); } @@ -755,6 +801,7 @@ MTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(MTL::RenderPas } // Update state + m_state.lastUsedFBO = m_state.activeFBO; for (uint8 i = 0; i < 8; i++) { m_state.colorRenderTargets[i] = colorRenderTargets[i]; @@ -836,7 +883,7 @@ void MetalRenderer::CommitCommandBuffer() LatteTextureReadback_UpdateFinishedTransfers(false); // Debug - m_commandQueue->insertDebugCaptureBoundary(); + //m_commandQueue->insertDebugCaptureBoundary(); } } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index ef33c95d..f70eec2c 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -31,6 +31,8 @@ struct MetalState { bool skipDrawSequence = false; class CachedFBOMtl* activeFBO = nullptr; + // If the FBO changes, but it's the same FBO as the last one with some omitted attachments, this FBO doesn't change' + class CachedFBOMtl* lastUsedFBO = nullptr; MetalBoundBuffer vertexBuffers[MAX_MTL_BUFFERS] = {{}}; // TODO: find out what is the max number of bound textures on the Wii U class LatteTextureViewMtl* textures[64] = {nullptr}; @@ -58,7 +60,7 @@ public: bool getResult(uint64& numSamplesPassed) override { cemuLog_log(LogType::MetalLogging, "LatteQueryObjectMtl::getResult: occlusion queries are not yet supported on Metal"); - return false; + return true; } void begin() override