mirror of https://github.com/PCSX2/pcsx2.git
GS:MTL: Use GSTexture base class's clear tracking
This commit is contained in:
parent
d88921bb58
commit
ff9a910c1a
|
@ -395,23 +395,36 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
|
||||||
|| stencil != m_current_render.stencil_target;
|
|| stencil != m_current_render.stencil_target;
|
||||||
GSVector4 color_clear;
|
GSVector4 color_clear;
|
||||||
float depth_clear;
|
float depth_clear;
|
||||||
int stencil_clear;
|
|
||||||
bool needs_color_clear = false;
|
bool needs_color_clear = false;
|
||||||
bool needs_depth_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
|
// Depth and stencil might be the same, so do all invalidation checks before resetting invalidation
|
||||||
if (mc && mc->IsInvalidated()) color_load = MTLLoadActionDontCare;
|
#define CHECK_CLEAR(tex, load_action, clear, ClearGetter) \
|
||||||
if (md && md->IsInvalidated()) depth_load = MTLLoadActionDontCare;
|
if (tex) \
|
||||||
if (ms && ms->IsInvalidated()) stencil_load = MTLLoadActionDontCare;
|
{ \
|
||||||
if (mc) { mc->ResetInvalidation(); needs_color_clear = mc->GetResetNeedsColorClear(color_clear); }
|
if (tex->GetState() == GSTexture::State::Invalidated) \
|
||||||
if (md) { md->ResetInvalidation(); needs_depth_clear = md->GetResetNeedsDepthClear(depth_clear); }
|
{ \
|
||||||
if (ms) { ms->ResetInvalidation(); needs_stencil_clear = ms->GetResetNeedsStencilClear(stencil_clear); }
|
load_action = MTLLoadActionDontCare; \
|
||||||
if (needs_color_clear && color_load != MTLLoadActionDontCare) color_load = MTLLoadActionClear;
|
} \
|
||||||
if (needs_depth_clear && depth_load != MTLLoadActionDontCare) depth_load = MTLLoadActionClear;
|
else if (tex->GetState() == GSTexture::State::Cleared && load_action != MTLLoadActionDontCare) \
|
||||||
if (needs_stencil_clear && stencil_load != MTLLoadActionDontCare) stencil_load = MTLLoadActionClear;
|
{ \
|
||||||
|
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 |= mc && color_load == MTLLoadActionClear;
|
||||||
needs_new |= md && depth_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)
|
if (!needs_new)
|
||||||
{
|
{
|
||||||
|
@ -457,8 +470,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
|
||||||
{
|
{
|
||||||
ms->m_last_write = m_current_draw;
|
ms->m_last_write = m_current_draw;
|
||||||
desc.stencilAttachment.texture = ms->GetTexture();
|
desc.stencilAttachment.texture = ms->GetTexture();
|
||||||
if (stencil_load == MTLLoadActionClear)
|
assert(stencil_load != MTLLoadActionClear);
|
||||||
desc.stencilAttachment.clearStencil = stencil_clear;
|
|
||||||
desc.stencilAttachment.loadAction = stencil_load;
|
desc.stencilAttachment.loadAction = stencil_load;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1423,7 +1435,7 @@ void GSDeviceMTL::AccumulateCommandBufferTime(id<MTLCommandBuffer> buffer)
|
||||||
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, const GSVector4& c)
|
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, const GSVector4& c)
|
||||||
{
|
{
|
||||||
if (!t) return;
|
if (!t) return;
|
||||||
static_cast<GSTextureMTL*>(t)->RequestColorClear(c);
|
t->SetClearColor(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, uint32 c)
|
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, uint32 c)
|
||||||
|
@ -1435,13 +1447,13 @@ void GSDeviceMTL::ClearRenderTarget(GSTexture* t, uint32 c)
|
||||||
void GSDeviceMTL::ClearDepth(GSTexture* t)
|
void GSDeviceMTL::ClearDepth(GSTexture* t)
|
||||||
{
|
{
|
||||||
if (!t) return;
|
if (!t) return;
|
||||||
static_cast<GSTextureMTL*>(t)->RequestDepthClear(0);
|
t->SetClearDepth(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSDeviceMTL::InvalidateRenderTarget(GSTexture* t)
|
void GSDeviceMTL::InvalidateRenderTarget(GSTexture* t)
|
||||||
{
|
{
|
||||||
if (!t) return;
|
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)
|
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)
|
if (r.width() < dsize.x || r.height() < dsize.y)
|
||||||
dT->FlushClears();
|
dT->FlushClears();
|
||||||
else
|
else
|
||||||
dT->InvalidateClears();
|
dT->SetState(GSTexture::State::Dirty);
|
||||||
|
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
|
||||||
|
|
|
@ -33,16 +33,6 @@ class GSTextureMTL : public GSTexture
|
||||||
MRCOwned<id<MTLTexture>> m_texture;
|
MRCOwned<id<MTLTexture>> m_texture;
|
||||||
bool m_has_mipmaps = false;
|
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:
|
public:
|
||||||
u64 m_last_read = 0; ///< Last time this texture was read by a draw
|
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
|
u64 m_last_write = 0; ///< Last time this texture was written by a draw
|
||||||
|
@ -52,28 +42,8 @@ public:
|
||||||
/// For making fake backbuffers
|
/// For making fake backbuffers
|
||||||
void SetSize(GSVector2i size) { m_size = size; }
|
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
|
/// Flushes requested clears to the texture
|
||||||
void FlushClears();
|
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;
|
void* GetNativeHandle() const override;
|
||||||
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
|
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
|
||||||
|
|
|
@ -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()
|
void GSTextureMTL::FlushClears()
|
||||||
{
|
{
|
||||||
if (!m_needs_color_clear && !m_needs_depth_clear && !m_needs_stencil_clear)
|
if (m_state != GSTexture::State::Cleared)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_dev->BeginRenderPass(@"Clear",
|
m_dev->BeginRenderPass(@"Clear",
|
||||||
m_needs_color_clear ? this : nullptr, MTLLoadActionLoad,
|
!IsDepthStencil() ? this : nullptr, MTLLoadActionLoad,
|
||||||
m_needs_depth_clear ? this : nullptr, MTLLoadActionLoad,
|
IsDepthStencil() ? this : nullptr, MTLLoadActionLoad);
|
||||||
m_needs_stencil_clear ? this : nullptr, MTLLoadActionLoad);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* GSTextureMTL::GetNativeHandle() const
|
void* GSTextureMTL::GetNativeHandle() const
|
||||||
|
@ -104,19 +54,6 @@ void* GSTextureMTL::GetNativeHandle() const
|
||||||
return (__bridge void*)m_texture;
|
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)
|
bool GSTextureMTL::Update(const GSVector4i& r, const void* data, int pitch, int layer)
|
||||||
{
|
{
|
||||||
if (void* buffer = MapWithPitch(r, pitch, 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;
|
GSDeviceMTL::Map map;
|
||||||
|
|
||||||
bool needs_clear = false;
|
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
|
// Not uploading to full texture
|
||||||
needs_clear = r.left > 0 || r.top > 0 || r.right < m_size.x || r.bottom < m_size.y;
|
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)
|
if (needs_clear)
|
||||||
{
|
{
|
||||||
m_needs_color_clear = true;
|
m_state = GSTexture::State::Cleared;
|
||||||
m_dev->BeginRenderPass(@"Pre-Upload Clear", this, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
|
m_dev->BeginRenderPass(@"Pre-Upload Clear", this, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
|
||||||
}
|
}
|
||||||
enc = m_dev->GetLateTextureUploadEncoder();
|
enc = m_dev->GetLateTextureUploadEncoder();
|
||||||
|
@ -212,12 +149,6 @@ void GSTextureMTL::Swap(GSTexture* other)
|
||||||
#define SWAP(x) std::swap(x, mtex->x)
|
#define SWAP(x) std::swap(x, mtex->x)
|
||||||
SWAP(m_texture);
|
SWAP(m_texture);
|
||||||
SWAP(m_has_mipmaps);
|
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
|
#undef SWAP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue