mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-06-03 12:27:21 +12:00
do clears as load ops if possible
This commit is contained in:
parent
2a9da80ff5
commit
498c4daed8
2 changed files with 146 additions and 38 deletions
|
@ -13,6 +13,25 @@
|
||||||
|
|
||||||
class GPU;
|
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 {
|
class RendererMTL final : public Renderer {
|
||||||
public:
|
public:
|
||||||
RendererMTL(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs);
|
RendererMTL(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs);
|
||||||
|
@ -57,6 +76,11 @@ class RendererMTL final : public Renderer {
|
||||||
MTL::RenderPipelineState* displayPipeline;
|
MTL::RenderPipelineState* displayPipeline;
|
||||||
MTL::RenderPipelineState* copyToLutTexturePipeline;
|
MTL::RenderPipelineState* copyToLutTexturePipeline;
|
||||||
|
|
||||||
|
// Clears
|
||||||
|
std::vector<Metal::ColorClearOp> colorClearOps;
|
||||||
|
std::vector<Metal::DepthClearOp> depthClearOps;
|
||||||
|
std::vector<Metal::StencilClearOp> stencilClearOps;
|
||||||
|
|
||||||
// Active state
|
// Active state
|
||||||
MTL::CommandBuffer* commandBuffer = nullptr;
|
MTL::CommandBuffer* commandBuffer = nullptr;
|
||||||
MTL::RenderCommandEncoder* renderCommandEncoder = 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();
|
createCommandBufferIfNeeded();
|
||||||
|
|
||||||
if (!renderCommandEncoder || colorTexture != lastColorTexture || depthTexture != lastDepthTexture) {
|
if (doesClears || !renderCommandEncoder || colorTexture != lastColorTexture || (depthTexture != lastDepthTexture || depthTexture == nullptr)) {
|
||||||
endRenderPass();
|
endRenderPass();
|
||||||
|
|
||||||
renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor);
|
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<Metal::ColorRenderTarget> getColorRenderTarget(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true);
|
std::optional<Metal::ColorRenderTarget> getColorRenderTarget(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true);
|
||||||
Metal::DepthStencilRenderTarget& getDepthRenderTarget();
|
Metal::DepthStencilRenderTarget& getDepthRenderTarget();
|
||||||
Metal::Texture& getTexture(Metal::Texture& tex);
|
Metal::Texture& getTexture(Metal::Texture& tex);
|
||||||
|
|
|
@ -60,7 +60,7 @@ void RendererMTL::display() {
|
||||||
colorAttachment->setClearColor(MTL::ClearColor{0.0f, 0.0f, 0.0f, 1.0f});
|
colorAttachment->setClearColor(MTL::ClearColor{0.0f, 0.0f, 0.0f, 1.0f});
|
||||||
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
||||||
|
|
||||||
beginRenderPassIfNeeded(renderPassDescriptor, drawable->texture());
|
beginRenderPassIfNeeded(renderPassDescriptor, false, drawable->texture());
|
||||||
renderCommandEncoder->setRenderPipelineState(displayPipeline);
|
renderCommandEncoder->setRenderPipelineState(displayPipeline);
|
||||||
renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0);
|
renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0);
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ void RendererMTL::display() {
|
||||||
auto topScreen = colorRenderTargetCache.findFromAddress(topScreenAddr);
|
auto topScreen = colorRenderTargetCache.findFromAddress(topScreenAddr);
|
||||||
|
|
||||||
if (topScreen) {
|
if (topScreen) {
|
||||||
|
clearColor(nullptr, topScreen->get().texture);
|
||||||
renderCommandEncoder->setViewport(MTL::Viewport{0, 0, 400, 240, 0.0f, 1.0f});
|
renderCommandEncoder->setViewport(MTL::Viewport{0, 0, 400, 240, 0.0f, 1.0f});
|
||||||
renderCommandEncoder->setFragmentTexture(topScreen->get().texture, 0);
|
renderCommandEncoder->setFragmentTexture(topScreen->get().texture, 0);
|
||||||
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
||||||
|
@ -86,6 +87,7 @@ void RendererMTL::display() {
|
||||||
auto bottomScreen = colorRenderTargetCache.findFromAddress(bottomScreenAddr);
|
auto bottomScreen = colorRenderTargetCache.findFromAddress(bottomScreenAddr);
|
||||||
|
|
||||||
if (bottomScreen) {
|
if (bottomScreen) {
|
||||||
|
clearColor(nullptr, bottomScreen->get().texture);
|
||||||
renderCommandEncoder->setViewport(MTL::Viewport{40, 240, 320, 240, 0.0f, 1.0f});
|
renderCommandEncoder->setViewport(MTL::Viewport{40, 240, 320, 240, 0.0f, 1.0f});
|
||||||
renderCommandEncoder->setFragmentTexture(bottomScreen->get().texture, 0);
|
renderCommandEncoder->setFragmentTexture(bottomScreen->get().texture, 0);
|
||||||
renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangleStrip, NS::UInteger(0), NS::UInteger(4));
|
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 b = Helpers::getBits<8, 8>(value) / 255.0f;
|
||||||
const float a = (value & 0xff) / 255.0f;
|
const float a = (value & 0xff) / 255.0f;
|
||||||
|
|
||||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
colorClearOps.push_back({color->get().texture, r, g, b, a});
|
||||||
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);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -286,23 +281,13 @@ void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 c
|
||||||
depthVal = (value & 0xffffff) / 16777215.0f;
|
depthVal = (value & 0xffffff) / 16777215.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
depthClearOps.push_back({depth->get().texture, depthVal});
|
||||||
MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment();
|
|
||||||
depthAttachment->setTexture(depth->get().texture);
|
|
||||||
depthAttachment->setClearDepth(depthVal);
|
|
||||||
depthAttachment->setLoadAction(MTL::LoadActionClear);
|
|
||||||
depthAttachment->setStoreAction(MTL::StoreActionStore);
|
|
||||||
|
|
||||||
if (format == DepthFmt::Depth24Stencil8) {
|
if (format == DepthFmt::Depth24Stencil8) {
|
||||||
MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = renderPassDescriptor->stencilAttachment();
|
const u8 stencilVal = value >> 24;
|
||||||
stencilAttachment->setTexture(depth->get().texture);
|
stencilClearOps.push_back({depth->get().texture, stencilVal});
|
||||||
stencilAttachment->setClearStencil((value >> 24) & 0xff);
|
|
||||||
stencilAttachment->setLoadAction(MTL::LoadActionClear);
|
|
||||||
stencilAttachment->setStoreAction(MTL::StoreActionStore);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
beginRenderPassIfNeeded(renderPassDescriptor, nullptr, depth->get().texture);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,6 +306,7 @@ void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize,
|
||||||
u32 outputHeight = outputSize >> 16;
|
u32 outputHeight = outputSize >> 16;
|
||||||
|
|
||||||
auto srcFramebuffer = getColorRenderTarget(inputAddr, inputFormat, inputWidth, outputHeight);
|
auto srcFramebuffer = getColorRenderTarget(inputAddr, inputFormat, inputWidth, outputHeight);
|
||||||
|
clearColor(nullptr, srcFramebuffer->texture);
|
||||||
Math::Rect<u32> srcRect = srcFramebuffer->getSubRect(inputAddr, outputWidth, outputHeight);
|
Math::Rect<u32> srcRect = srcFramebuffer->getSubRect(inputAddr, outputWidth, outputHeight);
|
||||||
|
|
||||||
if (verticalFlip) {
|
if (verticalFlip) {
|
||||||
|
@ -355,7 +341,7 @@ void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize,
|
||||||
Metal::BlitPipelineHash hash{destFramebuffer->format, DepthFmt::Unknown1};
|
Metal::BlitPipelineHash hash{destFramebuffer->format, DepthFmt::Unknown1};
|
||||||
auto blitPipeline = blitPipelineCache.get(hash);
|
auto blitPipeline = blitPipelineCache.get(hash);
|
||||||
|
|
||||||
beginRenderPassIfNeeded(renderPassDescriptor, destFramebuffer->texture);
|
beginRenderPassIfNeeded(renderPassDescriptor, false, destFramebuffer->texture);
|
||||||
renderCommandEncoder->setRenderPipelineState(blitPipeline);
|
renderCommandEncoder->setRenderPipelineState(blitPipeline);
|
||||||
renderCommandEncoder->setFragmentTexture(srcFramebuffer->texture, 0);
|
renderCommandEncoder->setFragmentTexture(srcFramebuffer->texture, 0);
|
||||||
renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0);
|
renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0);
|
||||||
|
@ -444,24 +430,17 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::span<const PICA::Ve
|
||||||
|
|
||||||
// -------- Render --------
|
// -------- Render --------
|
||||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||||
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0);
|
bool doesClear = clearColor(renderPassDescriptor, colorRenderTarget->texture);
|
||||||
colorAttachment->setTexture(colorRenderTarget->texture);
|
|
||||||
colorAttachment->setLoadAction(MTL::LoadActionLoad);
|
|
||||||
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
|
||||||
if (depthStencilRenderTarget) {
|
if (depthStencilRenderTarget) {
|
||||||
MTL::RenderPassDepthAttachmentDescriptor* depthAttachment = renderPassDescriptor->depthAttachment();
|
if (clearDepth(renderPassDescriptor, depthStencilRenderTarget->texture))
|
||||||
depthAttachment->setTexture(depthStencilRenderTarget->texture);
|
doesClear = true;
|
||||||
depthAttachment->setLoadAction(MTL::LoadActionLoad);
|
|
||||||
depthAttachment->setStoreAction(MTL::StoreActionStore);
|
|
||||||
if (depthStencilRenderTarget->format == DepthFmt::Depth24Stencil8) {
|
if (depthStencilRenderTarget->format == DepthFmt::Depth24Stencil8) {
|
||||||
MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment = renderPassDescriptor->stencilAttachment();
|
if (clearStencil(renderPassDescriptor, depthStencilRenderTarget->texture))
|
||||||
stencilAttachment->setTexture(depthStencilRenderTarget->texture);
|
doesClear = true;
|
||||||
stencilAttachment->setLoadAction(MTL::LoadActionLoad);
|
|
||||||
stencilAttachment->setStoreAction(MTL::StoreActionStore);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
beginRenderPassIfNeeded(renderPassDescriptor, colorRenderTarget->texture, (depthStencilRenderTarget ? depthStencilRenderTarget->texture : nullptr));
|
beginRenderPassIfNeeded(renderPassDescriptor, doesClear, colorRenderTarget->texture, (depthStencilRenderTarget ? depthStencilRenderTarget->texture : nullptr));
|
||||||
|
|
||||||
// Update the LUT texture if necessary
|
// Update the LUT texture if necessary
|
||||||
if (gpu.lightingLUTDirty) {
|
if (gpu.lightingLUTDirty) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue