From 498c4daed829f0ceb25f02af89ebbcc62df41401 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sat, 6 Jul 2024 17:28:35 +0200 Subject: [PATCH 1/7] do clears as load ops if possible --- include/renderer_mtl/renderer_mtl.hpp | 133 ++++++++++++++++++++++++- src/core/renderer_mtl/renderer_mtl.cpp | 51 +++------- 2 files changed, 146 insertions(+), 38 deletions(-) diff --git a/include/renderer_mtl/renderer_mtl.hpp b/include/renderer_mtl/renderer_mtl.hpp index 3ec77ace..6de5c7d9 100644 --- a/include/renderer_mtl/renderer_mtl.hpp +++ b/include/renderer_mtl/renderer_mtl.hpp @@ -13,6 +13,25 @@ class GPU; +namespace Metal { + +struct ColorClearOp { + MTL::Texture* texture; + float r, g, b, a; +}; + +struct DepthClearOp { + MTL::Texture* texture; + float depth; +}; + +struct StencilClearOp { + MTL::Texture* texture; + u8 stencil; +}; + +} // namespace Metal + class RendererMTL final : public Renderer { public: RendererMTL(GPU& gpu, const std::array& internalRegs, const std::array& externalRegs); @@ -57,6 +76,11 @@ class RendererMTL final : public Renderer { MTL::RenderPipelineState* displayPipeline; MTL::RenderPipelineState* copyToLutTexturePipeline; + // Clears + std::vector colorClearOps; + std::vector depthClearOps; + std::vector stencilClearOps; + // Active state MTL::CommandBuffer* commandBuffer = nullptr; MTL::RenderCommandEncoder* renderCommandEncoder = nullptr; @@ -76,10 +100,10 @@ class RendererMTL final : public Renderer { } } - void beginRenderPassIfNeeded(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorTexture, MTL::Texture* depthTexture = nullptr) { + void beginRenderPassIfNeeded(MTL::RenderPassDescriptor* renderPassDescriptor, bool doesClears, MTL::Texture* colorTexture, MTL::Texture* depthTexture = nullptr) { createCommandBufferIfNeeded(); - if (!renderCommandEncoder || colorTexture != lastColorTexture || depthTexture != lastDepthTexture) { + if (doesClears || !renderCommandEncoder || colorTexture != lastColorTexture || (depthTexture != lastDepthTexture || depthTexture == nullptr)) { endRenderPass(); renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor); @@ -100,6 +124,111 @@ class RendererMTL final : public Renderer { } } + void clearColor(MTL::RenderPassDescriptor* renderPassDescriptor, Metal::ColorClearOp clearOp) { + bool beginRenderPass = (renderPassDescriptor == nullptr); + if (!renderPassDescriptor) { + renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); + } + MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0); + colorAttachment->setTexture(clearOp.texture); + colorAttachment->setClearColor(MTL::ClearColor(clearOp.r, clearOp.g, clearOp.b, clearOp.a)); + colorAttachment->setLoadAction(MTL::LoadActionClear); + colorAttachment->setStoreAction(MTL::StoreActionStore); + + if (beginRenderPass) { + beginRenderPassIfNeeded(renderPassDescriptor, true, clearOp.texture); + } + } + + bool clearColor(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { + for (int32_t i = colorClearOps.size() - 1; i >= 0; i--) { + if (colorClearOps[i].texture == texture) { + clearColor(renderPassDescriptor, colorClearOps[i]); + colorClearOps.erase(colorClearOps.begin() + i); + return true; + } + } + + if (renderPassDescriptor) { + MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0); + colorAttachment->setTexture(texture); + colorAttachment->setLoadAction(MTL::LoadActionLoad); + colorAttachment->setStoreAction(MTL::StoreActionStore); + } + + return false; + } + + void clearDepth(MTL::RenderPassDescriptor* renderPassDescriptor, Metal::DepthClearOp clearOp) { + bool beginRenderPass = (renderPassDescriptor == nullptr); + if (!renderPassDescriptor) { + renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); + } + MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment(); + depthAttachment->setTexture(clearOp.texture); + depthAttachment->setClearDepth(clearOp.depth); + depthAttachment->setLoadAction(MTL::LoadActionClear); + depthAttachment->setStoreAction(MTL::StoreActionStore); + + if (beginRenderPass) { + beginRenderPassIfNeeded(renderPassDescriptor, true, nullptr, clearOp.texture); + } + } + + bool clearDepth(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { + for (int32_t i = depthClearOps.size() - 1; i >= 0; i--) { + if (depthClearOps[i].texture == texture) { + clearDepth(renderPassDescriptor, depthClearOps[i]); + depthClearOps.erase(depthClearOps.begin() + i); + return true; + } + } + + if (renderPassDescriptor) { + MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment(); + depthAttachment->setTexture(texture); + depthAttachment->setLoadAction(MTL::LoadActionLoad); + depthAttachment->setStoreAction(MTL::StoreActionStore); + } + + return false; + } + + void clearStencil(MTL::RenderPassDescriptor* renderPassDescriptor, Metal::StencilClearOp clearOp) { + bool beginRenderPass = (renderPassDescriptor == nullptr); + if (!renderPassDescriptor) { + renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); + } + MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = renderPassDescriptor->stencilAttachment(); + stencilAttachment->setTexture(clearOp.texture); + stencilAttachment->setClearStencil(clearOp.stencil); + stencilAttachment->setLoadAction(MTL::LoadActionClear); + stencilAttachment->setStoreAction(MTL::StoreActionStore); + + if (beginRenderPass) { + beginRenderPassIfNeeded(renderPassDescriptor, true, nullptr, clearOp.texture); + } + } + + bool clearStencil(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { + for (int32_t i = stencilClearOps.size() - 1; i >= 0; i--) { + if (stencilClearOps[i].texture == texture) { + clearStencil(renderPassDescriptor, stencilClearOps[i]); + stencilClearOps.erase(stencilClearOps.begin() + i); + return true; + } + } + + if (renderPassDescriptor) { + MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = renderPassDescriptor->stencilAttachment(); + stencilAttachment->setTexture(texture); + stencilAttachment->setLoadAction(MTL::LoadActionLoad); + stencilAttachment->setStoreAction(MTL::StoreActionStore); + } + + return false; + } + std::optional getColorRenderTarget(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true); Metal::DepthStencilRenderTarget& getDepthRenderTarget(); Metal::Texture& getTexture(Metal::Texture& tex); diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index 6b9e5fcb..0fb38d7c 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -60,7 +60,7 @@ void RendererMTL::display() { colorAttachment->setClearColor(MTL::ClearColor{0.0f, 0.0f, 0.0f, 1.0f}); colorAttachment->setStoreAction(MTL::StoreActionStore); - beginRenderPassIfNeeded(renderPassDescriptor, drawable->texture()); + beginRenderPassIfNeeded(renderPassDescriptor, false, drawable->texture()); renderCommandEncoder->setRenderPipelineState(displayPipeline); renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0); @@ -73,6 +73,7 @@ void RendererMTL::display() { auto topScreen = colorRenderTargetCache.findFromAddress(topScreenAddr); if (topScreen) { + clearColor(nullptr, topScreen->get().texture); renderCommandEncoder->setViewport(MTL::Viewport{0, 0, 400, 240, 0.0f, 1.0f}); renderCommandEncoder->setFragmentTexture(topScreen->get().texture, 0); renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4)); @@ -86,6 +87,7 @@ void RendererMTL::display() { auto bottomScreen = colorRenderTargetCache.findFromAddress(bottomScreenAddr); if (bottomScreen) { + clearColor(nullptr, bottomScreen->get().texture); renderCommandEncoder->setViewport(MTL::Viewport{40, 240, 320, 240, 0.0f, 1.0f}); renderCommandEncoder->setFragmentTexture(bottomScreen->get().texture, 0); renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4)); @@ -264,14 +266,7 @@ void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 c const float b = Helpers::getBits<8, 8>(value) / 255.0f; const float a = (value & 0xff) / 255.0f; - MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); - MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0); - colorAttachment->setTexture(color->get().texture); - colorAttachment->setClearColor(MTL::ClearColor(r, g, b, a)); - colorAttachment->setLoadAction(MTL::LoadActionClear); - colorAttachment->setStoreAction(MTL::StoreActionStore); - - beginRenderPassIfNeeded(renderPassDescriptor, color->get().texture); + colorClearOps.push_back({color->get().texture, r, g, b, a}); return; } @@ -286,23 +281,13 @@ void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 c depthVal = (value & 0xffffff) / 16777215.0f; } - MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); - MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment(); - depthAttachment->setTexture(depth->get().texture); - depthAttachment->setClearDepth(depthVal); - depthAttachment->setLoadAction(MTL::LoadActionClear); - depthAttachment->setStoreAction(MTL::StoreActionStore); + depthClearOps.push_back({depth->get().texture, depthVal}); if (format == DepthFmt::Depth24Stencil8) { - MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = renderPassDescriptor->stencilAttachment(); - stencilAttachment->setTexture(depth->get().texture); - stencilAttachment->setClearStencil((value >> 24) & 0xff); - stencilAttachment->setLoadAction(MTL::LoadActionClear); - stencilAttachment->setStoreAction(MTL::StoreActionStore); + const u8 stencilVal = value >> 24; + stencilClearOps.push_back({depth->get().texture, stencilVal}); } - beginRenderPassIfNeeded(renderPassDescriptor, nullptr, depth->get().texture); - return; } @@ -321,6 +306,7 @@ void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputHeight = outputSize >> 16; auto srcFramebuffer = getColorRenderTarget(inputAddr, inputFormat, inputWidth, outputHeight); + clearColor(nullptr, srcFramebuffer->texture); Math::Rect srcRect = srcFramebuffer->getSubRect(inputAddr, outputWidth, outputHeight); if (verticalFlip) { @@ -355,7 +341,7 @@ void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, Metal::BlitPipelineHash hash{destFramebuffer->format, DepthFmt::Unknown1}; auto blitPipeline = blitPipelineCache.get(hash); - beginRenderPassIfNeeded(renderPassDescriptor, destFramebuffer->texture); + beginRenderPassIfNeeded(renderPassDescriptor, false, destFramebuffer->texture); renderCommandEncoder->setRenderPipelineState(blitPipeline); renderCommandEncoder->setFragmentTexture(srcFramebuffer->texture, 0); renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0); @@ -444,24 +430,17 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::spaninit(); - MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0); - colorAttachment->setTexture(colorRenderTarget->texture); - colorAttachment->setLoadAction(MTL::LoadActionLoad); - colorAttachment->setStoreAction(MTL::StoreActionStore); + bool doesClear = clearColor(renderPassDescriptor, colorRenderTarget->texture); if (depthStencilRenderTarget) { - MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment(); - depthAttachment->setTexture(depthStencilRenderTarget->texture); - depthAttachment->setLoadAction(MTL::LoadActionLoad); - depthAttachment->setStoreAction(MTL::StoreActionStore); + if (clearDepth(renderPassDescriptor, depthStencilRenderTarget->texture)) + doesClear = true; if (depthStencilRenderTarget->format == DepthFmt::Depth24Stencil8) { - MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = renderPassDescriptor->stencilAttachment(); - stencilAttachment->setTexture(depthStencilRenderTarget->texture); - stencilAttachment->setLoadAction(MTL::LoadActionLoad); - stencilAttachment->setStoreAction(MTL::StoreActionStore); + if (clearStencil(renderPassDescriptor, depthStencilRenderTarget->texture)) + doesClear = true; } } - beginRenderPassIfNeeded(renderPassDescriptor, colorRenderTarget->texture, (depthStencilRenderTarget ? depthStencilRenderTarget->texture : nullptr)); + beginRenderPassIfNeeded(renderPassDescriptor, doesClear, colorRenderTarget->texture, (depthStencilRenderTarget ? depthStencilRenderTarget->texture : nullptr)); // Update the LUT texture if necessary if (gpu.lightingLUTDirty) { From e33339b655991762dea46c8b08c66c941ff21785 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sat, 6 Jul 2024 21:47:56 +0200 Subject: [PATCH 2/7] clean up clear attachment code --- include/renderer_mtl/renderer_mtl.hpp | 105 +++++++------------------- 1 file changed, 28 insertions(+), 77 deletions(-) diff --git a/include/renderer_mtl/renderer_mtl.hpp b/include/renderer_mtl/renderer_mtl.hpp index 6de5c7d9..58ec6bae 100644 --- a/include/renderer_mtl/renderer_mtl.hpp +++ b/include/renderer_mtl/renderer_mtl.hpp @@ -124,109 +124,60 @@ class RendererMTL final : public Renderer { } } - void clearColor(MTL::RenderPassDescriptor* renderPassDescriptor, Metal::ColorClearOp clearOp) { + template + inline void clearAttachment(MTL::RenderPassDescriptor* renderPassDescriptor, ClearOpT clearOp, GetAttachmentT getAttachment, SetClearDataT setClearData) { bool beginRenderPass = (renderPassDescriptor == nullptr); if (!renderPassDescriptor) { renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); } - MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0); - colorAttachment->setTexture(clearOp.texture); - colorAttachment->setClearColor(MTL::ClearColor(clearOp.r, clearOp.g, clearOp.b, clearOp.a)); - colorAttachment->setLoadAction(MTL::LoadActionClear); - colorAttachment->setStoreAction(MTL::StoreActionStore); + + AttachmentT* attachment = getAttachment(); + attachment->setTexture(clearOp.texture); + setClearData(attachment, clearOp); + attachment->setLoadAction(MTL::LoadActionClear); + attachment->setStoreAction(MTL::StoreActionStore); if (beginRenderPass) { beginRenderPassIfNeeded(renderPassDescriptor, true, clearOp.texture); } } - bool clearColor(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { - for (int32_t i = colorClearOps.size() - 1; i >= 0; i--) { - if (colorClearOps[i].texture == texture) { - clearColor(renderPassDescriptor, colorClearOps[i]); - colorClearOps.erase(colorClearOps.begin() + i); + template + inline bool clearAttachment(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture, std::vector& clearOps, GetAttachmentT getAttachment, SetClearDataT setClearData) { + for (int32_t i = clearOps.size() - 1; i >= 0; i--) { + if (clearOps[i].texture == texture) { + clearAttachment(renderPassDescriptor, clearOps[i], getAttachment, setClearData); + clearOps.erase(clearOps.begin() + i); return true; } } if (renderPassDescriptor) { - MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0); - colorAttachment->setTexture(texture); - colorAttachment->setLoadAction(MTL::LoadActionLoad); - colorAttachment->setStoreAction(MTL::StoreActionStore); + AttachmentT* attachment = getAttachment(); + attachment->setTexture(texture); + attachment->setLoadAction(MTL::LoadActionLoad); + attachment->setStoreAction(MTL::StoreActionStore); } return false; } - void clearDepth(MTL::RenderPassDescriptor* renderPassDescriptor, Metal::DepthClearOp clearOp) { - bool beginRenderPass = (renderPassDescriptor == nullptr); - if (!renderPassDescriptor) { - renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); - } - MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment(); - depthAttachment->setTexture(clearOp.texture); - depthAttachment->setClearDepth(clearOp.depth); - depthAttachment->setLoadAction(MTL::LoadActionClear); - depthAttachment->setStoreAction(MTL::StoreActionStore); - - if (beginRenderPass) { - beginRenderPassIfNeeded(renderPassDescriptor, true, nullptr, clearOp.texture); - } + bool clearColor(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { + return clearAttachment(renderPassDescriptor, texture, colorClearOps, [&]() { return renderPassDescriptor->colorAttachments()->object(0); }, [&](auto attachment, auto& clearOp) { + attachment->setClearColor(MTL::ClearColor(clearOp.r, clearOp.g, clearOp.b, clearOp.a)); + }); } bool clearDepth(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { - for (int32_t i = depthClearOps.size() - 1; i >= 0; i--) { - if (depthClearOps[i].texture == texture) { - clearDepth(renderPassDescriptor, depthClearOps[i]); - depthClearOps.erase(depthClearOps.begin() + i); - return true; - } - } - - if (renderPassDescriptor) { - MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment(); - depthAttachment->setTexture(texture); - depthAttachment->setLoadAction(MTL::LoadActionLoad); - depthAttachment->setStoreAction(MTL::StoreActionStore); - } - - return false; - } - - void clearStencil(MTL::RenderPassDescriptor* renderPassDescriptor, Metal::StencilClearOp clearOp) { - bool beginRenderPass = (renderPassDescriptor == nullptr); - if (!renderPassDescriptor) { - renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); - } - MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = renderPassDescriptor->stencilAttachment(); - stencilAttachment->setTexture(clearOp.texture); - stencilAttachment->setClearStencil(clearOp.stencil); - stencilAttachment->setLoadAction(MTL::LoadActionClear); - stencilAttachment->setStoreAction(MTL::StoreActionStore); - - if (beginRenderPass) { - beginRenderPassIfNeeded(renderPassDescriptor, true, nullptr, clearOp.texture); - } + return clearAttachment(renderPassDescriptor, texture, depthClearOps, [&]() { return renderPassDescriptor->depthAttachment(); }, [&](auto attachment, auto& clearOp) { + attachment->setClearDepth(clearOp.depth); + }); } bool clearStencil(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { - for (int32_t i = stencilClearOps.size() - 1; i >= 0; i--) { - if (stencilClearOps[i].texture == texture) { - clearStencil(renderPassDescriptor, stencilClearOps[i]); - stencilClearOps.erase(stencilClearOps.begin() + i); - return true; - } - } - - if (renderPassDescriptor) { - MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = renderPassDescriptor->stencilAttachment(); - stencilAttachment->setTexture(texture); - stencilAttachment->setLoadAction(MTL::LoadActionLoad); - stencilAttachment->setStoreAction(MTL::StoreActionStore); - } - - return false; + return clearAttachment(renderPassDescriptor, texture, stencilClearOps, [&]() { return renderPassDescriptor->stencilAttachment(); }, [&](auto attachment, auto& clearOp) { + attachment->setClearStencil(clearOp.stencil); + }); } std::optional getColorRenderTarget(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true); From a9b4f64ca789ef9e69034045089b0ed8db76a405 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sat, 6 Jul 2024 22:08:15 +0200 Subject: [PATCH 3/7] use map instead of vector for clear ops --- include/renderer_mtl/renderer_mtl.hpp | 63 ++++++++++---------------- src/core/renderer_mtl/renderer_mtl.cpp | 6 +-- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/include/renderer_mtl/renderer_mtl.hpp b/include/renderer_mtl/renderer_mtl.hpp index 58ec6bae..2221f151 100644 --- a/include/renderer_mtl/renderer_mtl.hpp +++ b/include/renderer_mtl/renderer_mtl.hpp @@ -13,25 +13,10 @@ class GPU; -namespace Metal { - -struct ColorClearOp { - MTL::Texture* texture; +struct Color4 { float r, g, b, a; }; -struct DepthClearOp { - MTL::Texture* texture; - float depth; -}; - -struct StencilClearOp { - MTL::Texture* texture; - u8 stencil; -}; - -} // namespace Metal - class RendererMTL final : public Renderer { public: RendererMTL(GPU& gpu, const std::array& internalRegs, const std::array& externalRegs); @@ -77,9 +62,9 @@ class RendererMTL final : public Renderer { MTL::RenderPipelineState* copyToLutTexturePipeline; // Clears - std::vector colorClearOps; - std::vector depthClearOps; - std::vector stencilClearOps; + std::map colorClearOps; + std::map depthClearOps; + std::map stencilClearOps; // Active state MTL::CommandBuffer* commandBuffer = nullptr; @@ -124,32 +109,34 @@ class RendererMTL final : public Renderer { } } - template - inline void clearAttachment(MTL::RenderPassDescriptor* renderPassDescriptor, ClearOpT clearOp, GetAttachmentT getAttachment, SetClearDataT setClearData) { + template + inline void clearAttachment(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture, ClearDataT clearData, GetAttachmentT getAttachment, SetClearDataT setClearData) { bool beginRenderPass = (renderPassDescriptor == nullptr); if (!renderPassDescriptor) { renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); } AttachmentT* attachment = getAttachment(); - attachment->setTexture(clearOp.texture); - setClearData(attachment, clearOp); + attachment->setTexture(texture); + setClearData(attachment, clearData); attachment->setLoadAction(MTL::LoadActionClear); attachment->setStoreAction(MTL::StoreActionStore); if (beginRenderPass) { - beginRenderPassIfNeeded(renderPassDescriptor, true, clearOp.texture); + if (std::is_same::value) + beginRenderPassIfNeeded(renderPassDescriptor, true, texture); + else + beginRenderPassIfNeeded(renderPassDescriptor, true, nullptr, texture); } } - template - inline bool clearAttachment(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture, std::vector& clearOps, GetAttachmentT getAttachment, SetClearDataT setClearData) { - for (int32_t i = clearOps.size() - 1; i >= 0; i--) { - if (clearOps[i].texture == texture) { - clearAttachment(renderPassDescriptor, clearOps[i], getAttachment, setClearData); - clearOps.erase(clearOps.begin() + i); - return true; - } + template + inline bool clearAttachment(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture, std::map& clearOps, GetAttachmentT getAttachment, SetClearDataT setClearData) { + auto it = clearOps.find(texture); + if (it != clearOps.end()) { + clearAttachment(renderPassDescriptor, texture, it->second, getAttachment, setClearData); + clearOps.erase(it); + return true; } if (renderPassDescriptor) { @@ -163,20 +150,20 @@ class RendererMTL final : public Renderer { } bool clearColor(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { - return clearAttachment(renderPassDescriptor, texture, colorClearOps, [&]() { return renderPassDescriptor->colorAttachments()->object(0); }, [&](auto attachment, auto& clearOp) { - attachment->setClearColor(MTL::ClearColor(clearOp.r, clearOp.g, clearOp.b, clearOp.a)); + return clearAttachment(renderPassDescriptor, texture, colorClearOps, [&]() { return renderPassDescriptor->colorAttachments()->object(0); }, [&](auto attachment, auto& color) { + attachment->setClearColor(MTL::ClearColor(color.r, color.g, color.b, color.a)); }); } bool clearDepth(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { - return clearAttachment(renderPassDescriptor, texture, depthClearOps, [&]() { return renderPassDescriptor->depthAttachment(); }, [&](auto attachment, auto& clearOp) { - attachment->setClearDepth(clearOp.depth); + return clearAttachment(renderPassDescriptor, texture, depthClearOps, [&]() { return renderPassDescriptor->depthAttachment(); }, [&](auto attachment, auto& depth) { + attachment->setClearDepth(depth); }); } bool clearStencil(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { - return clearAttachment(renderPassDescriptor, texture, stencilClearOps, [&]() { return renderPassDescriptor->stencilAttachment(); }, [&](auto attachment, auto& clearOp) { - attachment->setClearStencil(clearOp.stencil); + return clearAttachment(renderPassDescriptor, texture, stencilClearOps, [&]() { return renderPassDescriptor->stencilAttachment(); }, [&](auto attachment, auto& stencil) { + attachment->setClearStencil(stencil); }); } diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index 0fb38d7c..bf34ad81 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -266,7 +266,7 @@ void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 c const float b = Helpers::getBits<8, 8>(value) / 255.0f; const float a = (value & 0xff) / 255.0f; - colorClearOps.push_back({color->get().texture, r, g, b, a}); + colorClearOps[color->get().texture] = {r, g, b, a}; return; } @@ -281,11 +281,11 @@ void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 c depthVal = (value & 0xffffff) / 16777215.0f; } - depthClearOps.push_back({depth->get().texture, depthVal}); + depthClearOps[depth->get().texture] = depthVal; if (format == DepthFmt::Depth24Stencil8) { const u8 stencilVal = value >> 24; - stencilClearOps.push_back({depth->get().texture, stencilVal}); + stencilClearOps[depth->get().texture] = stencilVal; } return; From d435b380185eeb90b183758522e36e08a73e750a Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sat, 6 Jul 2024 22:13:21 +0200 Subject: [PATCH 4/7] fix: command ordering --- src/core/renderer_mtl/renderer_mtl.cpp | 53 ++++++++++++++------------ 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index bf34ad81..20f78137 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -53,6 +53,27 @@ void RendererMTL::display() { return; } + using namespace PICA::ExternalRegs; + + // Top screen + const u32 topActiveFb = externalRegs[Framebuffer0Select] & 1; + const u32 topScreenAddr = externalRegs[topActiveFb == 0 ? Framebuffer0AFirstAddr : Framebuffer0ASecondAddr]; + auto topScreen = colorRenderTargetCache.findFromAddress(topScreenAddr); + + if (topScreen) { + clearColor(nullptr, topScreen->get().texture); + } + + // Bottom screen + const u32 bottomActiveFb = externalRegs[Framebuffer1Select] & 1; + const u32 bottomScreenAddr = externalRegs[bottomActiveFb == 0 ? Framebuffer1AFirstAddr : Framebuffer1ASecondAddr]; + auto bottomScreen = colorRenderTargetCache.findFromAddress(bottomScreenAddr); + + if (bottomScreen) { + clearColor(nullptr, bottomScreen->get().texture); + } + + // -------- Draw -------- MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0); colorAttachment->setTexture(drawable->texture()); @@ -64,34 +85,18 @@ void RendererMTL::display() { renderCommandEncoder->setRenderPipelineState(displayPipeline); renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0); - using namespace PICA::ExternalRegs; - // Top screen - { - const u32 topActiveFb = externalRegs[Framebuffer0Select] & 1; - const u32 topScreenAddr = externalRegs[topActiveFb == 0 ? Framebuffer0AFirstAddr : Framebuffer0ASecondAddr]; - auto topScreen = colorRenderTargetCache.findFromAddress(topScreenAddr); - - if (topScreen) { - clearColor(nullptr, topScreen->get().texture); - renderCommandEncoder->setViewport(MTL::Viewport{0, 0, 400, 240, 0.0f, 1.0f}); - renderCommandEncoder->setFragmentTexture(topScreen->get().texture, 0); - renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4)); - } + if (topScreen) { + renderCommandEncoder->setViewport(MTL::Viewport{0, 0, 400, 240, 0.0f, 1.0f}); + renderCommandEncoder->setFragmentTexture(topScreen->get().texture, 0); + renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4)); } // Bottom screen - { - const u32 bottomActiveFb = externalRegs[Framebuffer1Select] & 1; - const u32 bottomScreenAddr = externalRegs[bottomActiveFb == 0 ? Framebuffer1AFirstAddr : Framebuffer1ASecondAddr]; - auto bottomScreen = colorRenderTargetCache.findFromAddress(bottomScreenAddr); - - if (bottomScreen) { - clearColor(nullptr, bottomScreen->get().texture); - renderCommandEncoder->setViewport(MTL::Viewport{40, 240, 320, 240, 0.0f, 1.0f}); - renderCommandEncoder->setFragmentTexture(bottomScreen->get().texture, 0); - renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4)); - } + if (bottomScreen) { + renderCommandEncoder->setViewport(MTL::Viewport{40, 240, 320, 240, 0.0f, 1.0f}); + renderCommandEncoder->setFragmentTexture(bottomScreen->get().texture, 0); + renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4)); } endRenderPass(); From 7ca08004afe6244eaaddae90291c7b25167a4c08 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sat, 6 Jul 2024 22:17:16 +0200 Subject: [PATCH 5/7] fix: incorrect render pass end logic --- include/renderer_mtl/renderer_mtl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/renderer_mtl/renderer_mtl.hpp b/include/renderer_mtl/renderer_mtl.hpp index 2221f151..c374f828 100644 --- a/include/renderer_mtl/renderer_mtl.hpp +++ b/include/renderer_mtl/renderer_mtl.hpp @@ -88,7 +88,7 @@ class RendererMTL final : public Renderer { void beginRenderPassIfNeeded(MTL::RenderPassDescriptor* renderPassDescriptor, bool doesClears, MTL::Texture* colorTexture, MTL::Texture* depthTexture = nullptr) { createCommandBufferIfNeeded(); - if (doesClears || !renderCommandEncoder || colorTexture != lastColorTexture || (depthTexture != lastDepthTexture || depthTexture == nullptr)) { + if (doesClears || !renderCommandEncoder || colorTexture != lastColorTexture || (depthTexture != lastDepthTexture && !(lastDepthTexture && !depthTexture))) { endRenderPass(); renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor); From c7be657d06a073cd150085cc89581baacdc5e85b Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sat, 6 Jul 2024 22:21:57 +0200 Subject: [PATCH 6/7] add: todo notice --- src/core/renderer_mtl/renderer_mtl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index 20f78137..de882caa 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -328,6 +328,7 @@ void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, } auto destFramebuffer = getColorRenderTarget(outputAddr, outputFormat, outputWidth, outputHeight); + // TODO: clear if not blitting to the whole framebuffer Math::Rect destRect = destFramebuffer->getSubRect(outputAddr, outputWidth, outputHeight); if (inputWidth != outputWidth) { From 5f5cb02bf6e832d8696aa8dedb0947d35033e505 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sun, 7 Jul 2024 08:36:41 +0200 Subject: [PATCH 7/7] fix: clear ops not having the correct render pass --- include/renderer_mtl/renderer_mtl.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/renderer_mtl/renderer_mtl.hpp b/include/renderer_mtl/renderer_mtl.hpp index c374f828..13aa013c 100644 --- a/include/renderer_mtl/renderer_mtl.hpp +++ b/include/renderer_mtl/renderer_mtl.hpp @@ -116,7 +116,7 @@ class RendererMTL final : public Renderer { renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); } - AttachmentT* attachment = getAttachment(); + AttachmentT* attachment = getAttachment(renderPassDescriptor); attachment->setTexture(texture); setClearData(attachment, clearData); attachment->setLoadAction(MTL::LoadActionClear); @@ -140,7 +140,7 @@ class RendererMTL final : public Renderer { } if (renderPassDescriptor) { - AttachmentT* attachment = getAttachment(); + AttachmentT* attachment = getAttachment(renderPassDescriptor); attachment->setTexture(texture); attachment->setLoadAction(MTL::LoadActionLoad); attachment->setStoreAction(MTL::StoreActionStore); @@ -150,19 +150,19 @@ class RendererMTL final : public Renderer { } bool clearColor(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { - return clearAttachment(renderPassDescriptor, texture, colorClearOps, [&]() { return renderPassDescriptor->colorAttachments()->object(0); }, [&](auto attachment, auto& color) { + return clearAttachment(renderPassDescriptor, texture, colorClearOps, [](MTL::RenderPassDescriptor* renderPassDescriptor) { return renderPassDescriptor->colorAttachments()->object(0); }, [](auto attachment, auto& color) { attachment->setClearColor(MTL::ClearColor(color.r, color.g, color.b, color.a)); }); } bool clearDepth(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { - return clearAttachment(renderPassDescriptor, texture, depthClearOps, [&]() { return renderPassDescriptor->depthAttachment(); }, [&](auto attachment, auto& depth) { + return clearAttachment(renderPassDescriptor, texture, depthClearOps, [](MTL::RenderPassDescriptor* renderPassDescriptor) { return renderPassDescriptor->depthAttachment(); }, [](auto attachment, auto& depth) { attachment->setClearDepth(depth); }); } bool clearStencil(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* texture) { - return clearAttachment(renderPassDescriptor, texture, stencilClearOps, [&]() { return renderPassDescriptor->stencilAttachment(); }, [&](auto attachment, auto& stencil) { + return clearAttachment(renderPassDescriptor, texture, stencilClearOps, [](MTL::RenderPassDescriptor* renderPassDescriptor) { return renderPassDescriptor->stencilAttachment(); }, [](auto attachment, auto& stencil) { attachment->setClearStencil(stencil); }); }