diff --git a/include/renderer_mtl/renderer_mtl.hpp b/include/renderer_mtl/renderer_mtl.hpp index 2c2f64b8..51e3f97e 100644 --- a/include/renderer_mtl/renderer_mtl.hpp +++ b/include/renderer_mtl/renderer_mtl.hpp @@ -52,6 +52,9 @@ class RendererMTL final : public Renderer { // Active state MTL::CommandBuffer* commandBuffer = nullptr; + MTL::RenderCommandEncoder* renderCommandEncoder = nullptr; + MTL::Texture* lastColorTexture = nullptr; + MTL::Texture* lastDepthTexture = nullptr; void createCommandBufferIfNeeded() { if (!commandBuffer) { @@ -59,6 +62,37 @@ class RendererMTL final : public Renderer { } } + void endRenderPass() { + if (renderCommandEncoder) { + renderCommandEncoder->endEncoding(); + renderCommandEncoder = nullptr; + } + } + + void beginRenderPassIfNeeded(MTL::RenderPassDescriptor* renderPassDescriptor, MTL::Texture* colorTexture, MTL::Texture* depthTexture) { + createCommandBufferIfNeeded(); + + if (!renderCommandEncoder || colorTexture != lastColorTexture || depthTexture != lastDepthTexture) { + endRenderPass(); + + renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor); + + lastColorTexture = colorTexture; + lastDepthTexture = depthTexture; + } + } + + void commitCommandBuffer() { + if (renderCommandEncoder) { + renderCommandEncoder->endEncoding(); + renderCommandEncoder = nullptr; + } + if (commandBuffer) { + commandBuffer->commit(); + commandBuffer = nullptr; + } + } + std::optional getColorRenderTarget(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true); Metal::DepthStencilRenderTarget& getDepthRenderTarget(); MTL::Texture* getTexture(Metal::Texture& tex); diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index 2edf0d89..c2fe9f1e 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -33,8 +33,6 @@ void RendererMTL::reset() { } void RendererMTL::display() { - createCommandBufferIfNeeded(); - CA::MetalDrawable* drawable = metalLayer->nextDrawable(); MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); @@ -44,7 +42,7 @@ void RendererMTL::display() { colorAttachment->setClearColor(MTL::ClearColor{0.0f, 0.0f, 0.0f, 1.0f}); colorAttachment->setStoreAction(MTL::StoreActionStore); - MTL::RenderCommandEncoder* renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor); + beginRenderPassIfNeeded(renderPassDescriptor, drawable->texture(), nullptr); renderCommandEncoder->setRenderPipelineState(displayPipeline); renderCommandEncoder->setFragmentSamplerState(basicSampler, 0); @@ -76,11 +74,10 @@ void RendererMTL::display() { } } - renderCommandEncoder->endEncoding(); + endRenderPass(); commandBuffer->presentDrawable(drawable); - commandBuffer->commit(); - commandBuffer = nullptr; + commitCommandBuffer(); } void RendererMTL::initGraphicsContext(SDL_Window* window) { @@ -197,8 +194,6 @@ void RendererMTL::initGraphicsContext(SDL_Window* window) { } void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { - createCommandBufferIfNeeded(); - const auto color = colorRenderTargetCache.findFromAddress(startAddress); if (color) { const float r = Helpers::getBits<24, 8>(value) / 255.0f; @@ -206,15 +201,14 @@ 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* passDescriptor = MTL::RenderPassDescriptor::alloc()->init(); - MTL::RenderPassColorAttachmentDescriptor* colorAttachment = passDescriptor->colorAttachments()->object(0); + 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); - MTL::RenderCommandEncoder* renderEncoder = commandBuffer->renderCommandEncoder(passDescriptor); - renderEncoder->endEncoding(); + beginRenderPassIfNeeded(renderPassDescriptor, color->get().texture, nullptr); return; } @@ -236,26 +230,23 @@ void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 c //OpenGL::setClearStencil(stencil); //OpenGL::clearDepthAndStencil(); } else { - MTL::RenderPassDescriptor* passDescriptor = MTL::RenderPassDescriptor::alloc()->init(); - MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = passDescriptor->depthAttachment(); + 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); - MTL::RenderCommandEncoder* renderEncoder = commandBuffer->renderCommandEncoder(passDescriptor); - renderEncoder->endEncoding(); + beginRenderPassIfNeeded(renderPassDescriptor, nullptr, depth->get().texture); } return; } - Helpers::warn("[RendererGL::ClearBuffer] No buffer found!\n"); + Helpers::warn("[RendererMTL::ClearBuffer] No buffer found!\n"); } void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) { - createCommandBufferIfNeeded(); - const u32 inputWidth = inputSize & 0xffff; const u32 inputHeight = inputSize >> 16; const auto inputFormat = ToColorFormat(Helpers::getBits<8, 3>(flags)); @@ -301,14 +292,12 @@ void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, Metal::PipelineHash hash{destFramebuffer->format, DepthFmt::Unknown1}; auto blitPipeline = blitPipelineCache.get(hash); - MTL::RenderCommandEncoder* renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor); + beginRenderPassIfNeeded(renderPassDescriptor, destFramebuffer->texture, nullptr); renderCommandEncoder->setRenderPipelineState(blitPipeline); renderCommandEncoder->setFragmentTexture(srcFramebuffer->texture, 0); renderCommandEncoder->setFragmentSamplerState(basicSampler, 0); renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4)); - - renderCommandEncoder->endEncoding(); } void RendererMTL::textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 inputSize, u32 outputSize, u32 flags) { @@ -317,8 +306,6 @@ void RendererMTL::textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 } void RendererMTL::drawVertices(PICA::PrimType primType, std::span vertices) { - createCommandBufferIfNeeded(); - // Color auto colorRenderTarget = getColorRenderTarget(colourBufferLoc, colourBufferFormat, fbSize[0], fbSize[1]); @@ -351,19 +338,6 @@ 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); - if (depthStencilRenderTarget) { - MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment(); - depthAttachment->setTexture(depthStencilRenderTarget->texture); - depthAttachment->setLoadAction(MTL::LoadActionLoad); - depthAttachment->setStoreAction(MTL::StoreActionStore); - } - // -------- Pipeline -------- Metal::PipelineHash pipelineHash{colorRenderTarget->format, DepthFmt::Unknown1}; if (depthStencilRenderTarget) { @@ -388,7 +362,20 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::spanrenderCommandEncoder(renderPassDescriptor); + // -------- Render -------- + MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); + MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0); + colorAttachment->setTexture(colorRenderTarget->texture); + colorAttachment->setLoadAction(MTL::LoadActionLoad); + colorAttachment->setStoreAction(MTL::StoreActionStore); + if (depthStencilRenderTarget) { + MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment(); + depthAttachment->setTexture(depthStencilRenderTarget->texture); + depthAttachment->setLoadAction(MTL::LoadActionLoad); + depthAttachment->setStoreAction(MTL::StoreActionStore); + } + + beginRenderPassIfNeeded(renderPassDescriptor, colorRenderTarget->texture, (depthStencilRenderTarget ? depthStencilRenderTarget->texture : nullptr)); renderCommandEncoder->setRenderPipelineState(pipeline); renderCommandEncoder->setDepthStencilState(depthStencilState); // If size is < 4KB, use inline vertex data, otherwise use a buffer @@ -408,8 +395,6 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::spandrawPrimitives(MTL::PrimitiveTypeTriangle, NS::UInteger(0), NS::UInteger(vertices.size())); - - renderCommandEncoder->endEncoding(); } void RendererMTL::screenshot(const std::string& name) {