From ff9a910c1a65b4f9fdcd7cf65eb83e3bafdda9e6 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Tue, 16 May 2023 22:23:07 -0500 Subject: [PATCH] GS:MTL: Use GSTexture base class's clear tracking --- pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm | 48 ++++++++------ pcsx2/GS/Renderers/Metal/GSTextureMTL.h | 30 --------- pcsx2/GS/Renderers/Metal/GSTextureMTL.mm | 81 ++---------------------- 3 files changed, 36 insertions(+), 123 deletions(-) diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm index 5ef1442e24..b26debbdb6 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm @@ -395,23 +395,36 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio || stencil != m_current_render.stencil_target; GSVector4 color_clear; float depth_clear; - int stencil_clear; bool needs_color_clear = false; bool needs_depth_clear = false; - bool needs_stencil_clear = false; // Depth and stencil might be the same, so do all invalidation checks before resetting invalidation - if (mc && mc->IsInvalidated()) color_load = MTLLoadActionDontCare; - if (md && md->IsInvalidated()) depth_load = MTLLoadActionDontCare; - if (ms && ms->IsInvalidated()) stencil_load = MTLLoadActionDontCare; - if (mc) { mc->ResetInvalidation(); needs_color_clear = mc->GetResetNeedsColorClear(color_clear); } - if (md) { md->ResetInvalidation(); needs_depth_clear = md->GetResetNeedsDepthClear(depth_clear); } - if (ms) { ms->ResetInvalidation(); needs_stencil_clear = ms->GetResetNeedsStencilClear(stencil_clear); } - if (needs_color_clear && color_load != MTLLoadActionDontCare) color_load = MTLLoadActionClear; - if (needs_depth_clear && depth_load != MTLLoadActionDontCare) depth_load = MTLLoadActionClear; - if (needs_stencil_clear && stencil_load != MTLLoadActionDontCare) stencil_load = MTLLoadActionClear; +#define CHECK_CLEAR(tex, load_action, clear, ClearGetter) \ + if (tex) \ + { \ + if (tex->GetState() == GSTexture::State::Invalidated) \ + { \ + load_action = MTLLoadActionDontCare; \ + } \ + else if (tex->GetState() == GSTexture::State::Cleared && load_action != MTLLoadActionDontCare) \ + { \ + clear = tex->ClearGetter(); \ + load_action = MTLLoadActionClear; \ + } \ + } + + CHECK_CLEAR(mc, color_load, color_clear, GetClearColor) + CHECK_CLEAR(md, depth_load, depth_clear, GetClearDepth) +#undef CHECK_CLEAR + // Stencil and depth are one texture, stencil clears aren't supported + if (ms && ms->GetState() == GSTexture::State::Invalidated) + stencil_load = MTLLoadActionDontCare; needs_new |= mc && color_load == MTLLoadActionClear; needs_new |= md && depth_load == MTLLoadActionClear; - needs_new |= ms && stencil_load == MTLLoadActionClear; + + // Reset texture state + if (mc) mc->SetState(GSTexture::State::Dirty); + if (md) md->SetState(GSTexture::State::Dirty); + if (ms) ms->SetState(GSTexture::State::Dirty); if (!needs_new) { @@ -457,8 +470,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio { ms->m_last_write = m_current_draw; desc.stencilAttachment.texture = ms->GetTexture(); - if (stencil_load == MTLLoadActionClear) - desc.stencilAttachment.clearStencil = stencil_clear; + assert(stencil_load != MTLLoadActionClear); desc.stencilAttachment.loadAction = stencil_load; } @@ -1423,7 +1435,7 @@ void GSDeviceMTL::AccumulateCommandBufferTime(id buffer) void GSDeviceMTL::ClearRenderTarget(GSTexture* t, const GSVector4& c) { if (!t) return; - static_cast(t)->RequestColorClear(c); + t->SetClearColor(c); } void GSDeviceMTL::ClearRenderTarget(GSTexture* t, uint32 c) @@ -1435,13 +1447,13 @@ void GSDeviceMTL::ClearRenderTarget(GSTexture* t, uint32 c) void GSDeviceMTL::ClearDepth(GSTexture* t) { if (!t) return; - static_cast(t)->RequestDepthClear(0); + t->SetClearDepth(0); } void GSDeviceMTL::InvalidateRenderTarget(GSTexture* t) { if (!t) return; - static_cast(t)->Invalidate(); + t->SetState(GSTexture::State::Invalidated); } std::unique_ptr GSDeviceMTL::CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) @@ -1468,7 +1480,7 @@ void GSDeviceMTL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r if (r.width() < dsize.x || r.height() < dsize.y) dT->FlushClears(); else - dT->InvalidateClears(); + dT->SetState(GSTexture::State::Dirty); EndRenderPass(); diff --git a/pcsx2/GS/Renderers/Metal/GSTextureMTL.h b/pcsx2/GS/Renderers/Metal/GSTextureMTL.h index 82de77daeb..7294f1c2d9 100644 --- a/pcsx2/GS/Renderers/Metal/GSTextureMTL.h +++ b/pcsx2/GS/Renderers/Metal/GSTextureMTL.h @@ -33,16 +33,6 @@ class GSTextureMTL : public GSTexture MRCOwned> m_texture; bool m_has_mipmaps = false; - // In Metal clears happen as a part of render passes instead of as separate steps, but the GSDevice API has it as a separate step - // To deal with that, store the fact that a clear was requested here and it'll be applied on the next render pass - bool m_needs_color_clear = false; - bool m_needs_depth_clear = false; - bool m_needs_stencil_clear = false; - bool m_invalidated = false; - GSVector4 m_clear_color; - float m_clear_depth; - int m_clear_stencil; - public: u64 m_last_read = 0; ///< Last time this texture was read by a draw u64 m_last_write = 0; ///< Last time this texture was written by a draw @@ -52,28 +42,8 @@ public: /// For making fake backbuffers void SetSize(GSVector2i size) { m_size = size; } - /// Requests the texture be cleared the next time a color render is done - void RequestColorClear(GSVector4 color); - /// Requests the texture be cleared the next time a depth render is done - void RequestDepthClear(float depth); - /// Requests the texture be cleared the next time a stencil render is done - void RequestStencilClear(int stencil); - /// Reads whether a color clear was requested, then clears the request - bool GetResetNeedsColorClear(GSVector4& colorOut); - /// Reads whether a depth clear was requested, then clears the request - bool GetResetNeedsDepthClear(float& depthOut); - /// Reads whether a stencil clear was requested, then clears the request - bool GetResetNeedsStencilClear(int& stencilOut); /// Flushes requested clears to the texture void FlushClears(); - /// Marks pending clears as done (e.g. if the whole texture is about to be overwritten) - void InvalidateClears(); - /// Marks the texture as invalid (will load with DontCare) - void Invalidate(); - /// Reads whether the texture has been invalidated, then clears the invalidation - bool IsInvalidated() const { return m_invalidated; }; - /// Clears any invalidation requests - void ResetInvalidation() { m_invalidated = false; } void* GetNativeHandle() const override; bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override; diff --git a/pcsx2/GS/Renderers/Metal/GSTextureMTL.mm b/pcsx2/GS/Renderers/Metal/GSTextureMTL.mm index 1295cb8fd2..489408cb71 100644 --- a/pcsx2/GS/Renderers/Metal/GSTextureMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSTextureMTL.mm @@ -39,64 +39,14 @@ GSTextureMTL::~GSTextureMTL() { } -void GSTextureMTL::RequestColorClear(GSVector4 color) -{ - m_needs_color_clear = true; - m_invalidated = false; - m_clear_color = color; -} -void GSTextureMTL::RequestDepthClear(float depth) -{ - m_needs_depth_clear = true; - m_invalidated = false; - m_clear_depth = depth; -} -void GSTextureMTL::RequestStencilClear(int stencil) -{ - m_needs_stencil_clear = true; - m_invalidated = false; - m_clear_stencil = stencil; -} -bool GSTextureMTL::GetResetNeedsColorClear(GSVector4& colorOut) -{ - if (m_needs_color_clear) - { - m_needs_color_clear = false; - colorOut = m_clear_color; - return true; - } - return false; -} -bool GSTextureMTL::GetResetNeedsDepthClear(float& depthOut) -{ - if (m_needs_depth_clear) - { - m_needs_depth_clear = false; - depthOut = m_clear_depth; - return true; - } - return false; -} -bool GSTextureMTL::GetResetNeedsStencilClear(int& stencilOut) -{ - if (m_needs_stencil_clear) - { - m_needs_stencil_clear = false; - stencilOut = m_clear_stencil; - return true; - } - return false; -} - void GSTextureMTL::FlushClears() { - if (!m_needs_color_clear && !m_needs_depth_clear && !m_needs_stencil_clear) + if (m_state != GSTexture::State::Cleared) return; m_dev->BeginRenderPass(@"Clear", - m_needs_color_clear ? this : nullptr, MTLLoadActionLoad, - m_needs_depth_clear ? this : nullptr, MTLLoadActionLoad, - m_needs_stencil_clear ? this : nullptr, MTLLoadActionLoad); + !IsDepthStencil() ? this : nullptr, MTLLoadActionLoad, + IsDepthStencil() ? this : nullptr, MTLLoadActionLoad); } void* GSTextureMTL::GetNativeHandle() const @@ -104,19 +54,6 @@ void* GSTextureMTL::GetNativeHandle() const return (__bridge void*)m_texture; } -void GSTextureMTL::InvalidateClears() -{ - m_needs_color_clear = false; - m_needs_depth_clear = false; - m_needs_stencil_clear = false; -} - -void GSTextureMTL::Invalidate() -{ - InvalidateClears(); - m_invalidated = true; -} - bool GSTextureMTL::Update(const GSVector4i& r, const void* data, int pitch, int layer) { if (void* buffer = MapWithPitch(r, pitch, layer)) @@ -151,9 +88,9 @@ void* GSTextureMTL::MapWithPitch(const GSVector4i& r, int pitch, int layer) GSDeviceMTL::Map map; bool needs_clear = false; - if (m_needs_color_clear) + if (m_state == GSTexture::State::Cleared) { - m_needs_color_clear = false; + m_state = GSTexture::State::Dirty; // Not uploading to full texture needs_clear = r.left > 0 || r.top > 0 || r.right < m_size.x || r.bottom < m_size.y; } @@ -163,7 +100,7 @@ void* GSTextureMTL::MapWithPitch(const GSVector4i& r, int pitch, int layer) { if (needs_clear) { - m_needs_color_clear = true; + m_state = GSTexture::State::Cleared; m_dev->BeginRenderPass(@"Pre-Upload Clear", this, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare); } enc = m_dev->GetLateTextureUploadEncoder(); @@ -212,12 +149,6 @@ void GSTextureMTL::Swap(GSTexture* other) #define SWAP(x) std::swap(x, mtex->x) SWAP(m_texture); SWAP(m_has_mipmaps); - SWAP(m_needs_color_clear); - SWAP(m_needs_depth_clear); - SWAP(m_needs_stencil_clear); - SWAP(m_clear_color); - SWAP(m_clear_depth); - SWAP(m_clear_stencil); #undef SWAP }