GS:MTL: Use GSTexture base class's clear tracking

This commit is contained in:
TellowKrinkle 2023-05-16 22:23:07 -05:00 committed by lightningterror
parent d88921bb58
commit ff9a910c1a
3 changed files with 36 additions and 123 deletions

View File

@ -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<MTLCommandBuffer> buffer)
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, const GSVector4& c)
{
if (!t) return;
static_cast<GSTextureMTL*>(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<GSTextureMTL*>(t)->RequestDepthClear(0);
t->SetClearDepth(0);
}
void GSDeviceMTL::InvalidateRenderTarget(GSTexture* t)
{
if (!t) return;
static_cast<GSTextureMTL*>(t)->Invalidate();
t->SetState(GSTexture::State::Invalidated);
}
std::unique_ptr<GSDownloadTexture> 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();

View File

@ -33,16 +33,6 @@ class GSTextureMTL : public GSTexture
MRCOwned<id<MTLTexture>> 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;

View File

@ -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
}