GS: Store clear colour as RGBA32

And defer clears until draw time for DX11 and OpenGL.
This commit is contained in:
Stenzek 2023-06-17 16:50:21 +10:00 committed by Connor McLaughlin
parent f6bcfc3abd
commit 350037fc75
20 changed files with 256 additions and 313 deletions

View File

@ -243,6 +243,11 @@ public:
return GSVector4(GSVector4i::load((int)rgba).u8to32() << shift);
}
__forceinline static GSVector4 unorm8(u32 rgba)
{
return rgba32(rgba) * GSVector4::cxpr(1.0f / 255.0f);
}
__forceinline GSVector4 abs() const
{
return *this & cast(GSVector4i::x7fffffff());

View File

@ -470,7 +470,7 @@ void GSDevice::ClearCurrent()
m_cas = nullptr;
}
void GSDevice::Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c)
void GSDevice::Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c)
{
if (ResizeRenderTarget(&m_merge, fs.x, fs.y, false, false))
DoMerge(sTex, sRect, m_merge, dRect, PMODE, EXTBUF, c, GSConfig.PCRTCOffsets);

View File

@ -786,7 +786,7 @@ protected:
virtual GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) = 0;
GSTexture* FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_reuse);
virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) = 0;
virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) = 0;
virtual void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) = 0;
virtual void DoFXAA(GSTexture* sTex, GSTexture* dTex) = 0;
virtual void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) = 0;
@ -877,7 +877,6 @@ public:
/// Returns the amount of GPU time utilized since the last time this method was called.
virtual float GetAndResetAccumulatedGPUTime() = 0;
virtual void ClearRenderTarget(GSTexture* t, const GSVector4& c) = 0;
virtual void ClearRenderTarget(GSTexture* t, u32 c) = 0;
virtual void InvalidateRenderTarget(GSTexture* t) = 0;
virtual void ClearDepth(GSTexture* t, float d) = 0;
@ -919,7 +918,7 @@ public:
virtual void ClearSamplerCache() = 0;
void ClearCurrent();
void Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c);
void Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c);
void Interlace(const GSVector2i& ds, int field, int mode, float yoffset);
void FXAA();
void ShadeBoost();

View File

@ -220,13 +220,7 @@ bool GSRenderer::Merge(int field)
tex[0] = nullptr;
}
const GSVector4 c = GSVector4(
static_cast<int>(m_regs->BGCOLOR.R),
static_cast<int>(m_regs->BGCOLOR.G),
static_cast<int>(m_regs->BGCOLOR.B),
static_cast<int>(m_regs->PMODE.ALP)) /
255;
const u32 c = (m_regs->BGCOLOR.U32[0] & 0x00FFFFFFu) | (m_regs->PMODE.ALP << 24);
g_gs_device->Merge(tex, src_gs_read, dst, fs, m_regs->PMODE, m_regs->EXTBUF, c);
if (isReallyInterlaced() && GSConfig.InterlaceMode != GSInterlaceMode::Off)

View File

@ -60,7 +60,7 @@ public:
union alignas(16) ClearValue
{
float color[4];
u32 color;
float depth;
};
@ -139,13 +139,14 @@ public:
__fi u32 GetLastFrameUsed() const { return m_last_frame_used; }
void SetLastFrameUsed(u32 frame) { m_last_frame_used = frame; }
__fi GSVector4 GetClearColor() const { return GSVector4::load<false>(m_clear_value.color); }
__fi u32 GetClearColor() const { return m_clear_value.color; }
__fi float GetClearDepth() const { return m_clear_value.depth; }
__fi GSVector4 GetUNormClearColor() const { return GSVector4::unorm8(m_clear_value.color); }
__fi void SetClearColor(const GSVector4& color)
__fi void SetClearColor(u32 color)
{
m_state = State::Cleared;
GSVector4::store<false>(m_clear_value.color, color);
m_clear_value.color = color;
}
__fi void SetClearDepth(float depth)
{

View File

@ -1057,38 +1057,43 @@ void GSDevice11::DrawIndexedPrimitive(int offset, int count)
m_ctx->DrawIndexed(count, m_index.start + offset, m_vertex.start);
}
void GSDevice11::ClearRenderTarget(GSTexture* t, const GSVector4& c)
{
if (!t)
return;
m_ctx->ClearRenderTargetView(*(GSTexture11*)t, c.v);
}
void GSDevice11::ClearRenderTarget(GSTexture* t, u32 c)
{
if (!t)
return;
const GSVector4 color = GSVector4::rgba32(c) * (1.0f / 255);
m_ctx->ClearRenderTargetView(*(GSTexture11*)t, color.v);
t->SetClearColor(c);
}
void GSDevice11::InvalidateRenderTarget(GSTexture* t)
{
if (t->IsDepthStencil())
m_ctx->DiscardView(static_cast<ID3D11DepthStencilView*>(*static_cast<GSTexture11*>(t)));
else
m_ctx->DiscardView(static_cast<ID3D11RenderTargetView*>(*static_cast<GSTexture11*>(t)));
t->SetState(GSTexture::State::Invalidated);
}
void GSDevice11::ClearDepth(GSTexture* t, float d)
{
m_ctx->ClearDepthStencilView(*(GSTexture11*)t, D3D11_CLEAR_DEPTH, d, 0);
t->SetClearDepth(d);
}
void GSDevice11::ClearStencil(GSTexture* t, u8 c)
void GSDevice11::CommitClear(GSTexture* t)
{
m_ctx->ClearDepthStencilView(*(GSTexture11*)t, D3D11_CLEAR_STENCIL, 0, c);
GSTexture11* T = static_cast<GSTexture11*>(t);
if (!T->IsRenderTargetOrDepthStencil() || T->GetState() == GSTexture::State::Dirty)
return;
if (T->IsDepthStencil())
{
if (T->GetState() == GSTexture::State::Invalidated)
m_ctx->DiscardView(static_cast<ID3D11DepthStencilView*>(*T));
else
m_ctx->ClearDepthStencilView(*T, D3D11_CLEAR_DEPTH, T->GetClearDepth(), 0);
}
else
{
if (T->GetState() == GSTexture::State::Invalidated)
m_ctx->DiscardView(static_cast<ID3D11RenderTargetView*>(*T));
else
m_ctx->ClearRenderTargetView(*T, T->GetUNormClearColor().F32);
}
T->SetState(GSTexture::State::Dirty);
}
void GSDevice11::PushDebugGroup(const char* fmt, ...)
@ -1176,6 +1181,9 @@ std::unique_ptr<GSDownloadTexture> GSDevice11::CreateDownloadTexture(u32 width,
void GSDevice11::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY)
{
CommitClear(sTex);
CommitClear(dTex);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
D3D11_BOX box = {(UINT)r.left, (UINT)r.top, 0U, (UINT)r.right, (UINT)r.bottom, 1U};
@ -1192,6 +1200,7 @@ void GSDevice11::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
void GSDevice11::CloneTexture(GSTexture* src, GSTexture** dest, const GSVector4i& rect)
{
pxAssertMsg(src->GetType() == GSTexture::Type::DepthStencil || src->GetType() == GSTexture::Type::RenderTarget, "Source is RT or DS.");
CommitClear(src);
const int w = src->GetWidth();
const int h = src->GetHeight();
@ -1231,7 +1240,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, bool linear)
{
ASSERT(sTex);
CommitClear(sTex);
const bool draw_in_depth = dTex && dTex->IsDepthStencil();
@ -1303,7 +1312,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear)
{
ASSERT(sTex);
CommitClear(sTex);
GSVector2i ds;
if (dTex)
@ -1480,6 +1489,7 @@ void GSDevice11::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rect
IAUnmapIndexBuffer(icount);
IASetIndexBuffer(m_ib.get());
CommitClear(rects[0].src);
PSSetShaderResource(0, rects[0].src);
PSSetSamplerState(rects[0].linear ? m_convert.ln.get() : m_convert.pt.get());
@ -1489,7 +1499,7 @@ void GSDevice11::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rect
}
void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
{
const GSVector4 full_r(0.0f, 0.0f, 1.0f, 1.0f);
const bool feedback_write_2 = PMODE.EN2 && sTex[2] != nullptr && EXTBUF.FBIN == 1;
@ -1504,7 +1514,7 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
// Upload constant to select YUV algo, but skip constant buffer update if we don't need it
if (feedback_write_2 || feedback_write_1 || sTex[0])
{
const MergeConstantBuffer cb = {c, EXTBUF.EMODA, EXTBUF.EMODC};
const MergeConstantBuffer cb = {GSVector4::unorm8(c), EXTBUF.EMODA, EXTBUF.EMODC};
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
}
@ -1799,7 +1809,7 @@ void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vert
{
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
ClearStencil(ds, 0);
m_ctx->ClearDepthStencilView(*static_cast<GSTexture11*>(ds), D3D11_CLEAR_STENCIL, 0.0f, 0);
// om
@ -2067,8 +2077,16 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
ID3D11RenderTargetView* rtv = nullptr;
ID3D11DepthStencilView* dsv = nullptr;
if (rt) rtv = *(GSTexture11*)rt;
if (ds) dsv = *(GSTexture11*)ds;
if (rt)
{
CommitClear(rt);
rtv = *static_cast<GSTexture11*>(rt);
}
if (ds)
{
CommitClear(ds);
dsv = *static_cast<GSTexture11*>(ds);
}
const bool changed = (m_state.rt_view != rtv || m_state.dsv != dsv);
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(changed));

View File

@ -129,7 +129,7 @@ private:
void PopTimestampQuery();
void KickTimestampQuery();
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) override;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) override;
void DoFXAA(GSTexture* sTex, GSTexture* dTex) override;
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) override;
@ -309,11 +309,9 @@ public:
void DrawIndexedPrimitive();
void DrawIndexedPrimitive(int offset, int count);
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
void ClearRenderTarget(GSTexture* t, u32 c) override;
void InvalidateRenderTarget(GSTexture* t) override;
void ClearDepth(GSTexture* t, float v) override;
void ClearStencil(GSTexture* t, u8 c);
void PushDebugGroup(const char* fmt, ...) override;
void PopDebugGroup() override;
@ -322,6 +320,7 @@ public:
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;
void CommitClear(GSTexture* t);
void CloneTexture(GSTexture* src, GSTexture** dest, const GSVector4i& rect);
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) override;

View File

@ -67,6 +67,7 @@ bool GSTexture11::Update(const GSVector4i& r, const void* data, int pitch, int l
if (layer >= m_mipmap_levels)
return false;
GSDevice11::GetInstance()->CommitClear(this);
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
const u32 bs = GetCompressedBlockSize();
@ -82,41 +83,19 @@ bool GSTexture11::Update(const GSVector4i& r, const void* data, int pitch, int l
bool GSTexture11::Map(GSMap& m, const GSVector4i* r, int layer)
{
if (r != NULL)
{
// ASSERT(0); // not implemented
return false;
}
if (layer >= m_mipmap_levels)
return false;
if (m_texture && m_desc.Usage == D3D11_USAGE_STAGING)
{
D3D11_MAPPED_SUBRESOURCE map;
UINT subresource = layer;
if (SUCCEEDED(GSDevice11::GetInstance()->GetD3DContext()->Map(m_texture.get(), subresource, D3D11_MAP_READ_WRITE, 0, &map)))
{
m.bits = (u8*)map.pData;
m.pitch = (int)map.RowPitch;
m_mapped_subresource = layer;
return true;
}
}
// Not supported
return false;
}
void GSTexture11::Unmap()
{
const UINT subresource = m_mapped_subresource;
m_needs_mipmaps_generated |= (m_mapped_subresource == 0);
GSDevice11::GetInstance()->GetD3DContext()->Unmap(m_texture.get(), subresource);
pxFailRel("Should not be called.");
}
bool GSTexture11::Save(const std::string& fn)
{
GSDevice11::GetInstance()->CommitClear(this);
D3D11_TEXTURE2D_DESC desc = m_desc;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
@ -342,6 +321,9 @@ void GSDownloadTexture11::CopyFromTexture(
pxAssert(src.z <= stex->GetWidth() && src.w <= stex->GetHeight());
pxAssert(static_cast<u32>(drc.z) <= m_width && static_cast<u32>(drc.w) <= m_height);
pxAssert(src_level < static_cast<u32>(stex->GetMipmapLevels()));
GSDevice11::GetInstance()->CommitClear(stex);
g_perfmon.Put(GSPerfMon::Readbacks, 1);
if (IsMapped())

View File

@ -639,27 +639,16 @@ void GSDevice12::DrawIndexedPrimitive(int offset, int count)
g_d3d12_context->GetCommandList()->DrawIndexedInstanced(count, 1, m_index.start + offset, m_vertex.start, 0);
}
void GSDevice12::ClearRenderTarget(GSTexture* t, const GSVector4& c)
void GSDevice12::ClearRenderTarget(GSTexture* t, u32 c)
{
if (!t)
return;
if (m_current_render_target == t)
EndRenderPass();
static_cast<GSTexture12*>(t)->SetClearColor(c);
}
void GSDevice12::ClearRenderTarget(GSTexture* t, u32 c)
{
ClearRenderTarget(t, GSVector4::rgba32(c) * (1.0f / 255));
t->SetClearColor(c);
}
void GSDevice12::InvalidateRenderTarget(GSTexture* t)
{
if (!t)
return;
if (m_current_render_target == t || m_current_depth_target == t)
EndRenderPass();
@ -668,13 +657,10 @@ void GSDevice12::InvalidateRenderTarget(GSTexture* t)
void GSDevice12::ClearDepth(GSTexture* t, float d)
{
if (!t)
return;
if (m_current_depth_target == t)
EndRenderPass();
static_cast<GSTexture12*>(t)->SetClearDepth(d);
t->SetClearDepth(d);
}
void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format,
@ -771,7 +757,7 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
{
dTexVK->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
g_d3d12_context->GetCommandList()->ClearRenderTargetView(
dTexVK->GetWriteDescriptor(), sTexVK->GetClearColor().v, 0, nullptr);
dTexVK->GetWriteDescriptor(), sTexVK->GetUNormClearColor().v, 0, nullptr);
}
else
{
@ -1027,19 +1013,17 @@ void GSDevice12::BeginRenderPassForStretchRect(
if (dTex->GetType() != GSTexture::Type::DepthStencil)
{
const GSVector4 clear_color(dTex->GetClearColor());
BeginRenderPass(load_op, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
clear_color);
dTex->GetClearColor());
}
else
{
const float clear_depth = dTex->GetClearDepth();
BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, load_op, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
GSVector4::zero(), clear_depth);
0, dTex->GetClearDepth());
}
}
@ -1103,7 +1087,7 @@ void GSDevice12::DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect,
}
void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect,
const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
{
GL_PUSH("DoMerge");
@ -1126,7 +1110,7 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
if (feedback_write_2 || feedback_write_1 || sTex[0])
{
SetUtilityRootSignature();
const MergeConstantBuffer uniforms = {c, EXTBUF.EMODA, EXTBUF.EMODC};
const MergeConstantBuffer uniforms = {GSVector4::unorm8(c), EXTBUF.EMODA, EXTBUF.EMODC};
SetUtilityPushConstants(&uniforms, sizeof(uniforms));
}
@ -2711,8 +2695,7 @@ bool GSDevice12::InRenderPass()
void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_begin,
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE color_end, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE depth_begin,
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE depth_end, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE stencil_begin,
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE stencil_end, const GSVector4& clear_color /* = GSVector4::zero() */,
float clear_depth /* = 0.0f */, u8 clear_stencil /* = 0 */)
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE stencil_end, u32 clear_color, float clear_depth, u8 clear_stencil)
{
if (m_in_render_pass)
EndRenderPass();
@ -2731,7 +2714,8 @@ void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_b
{
LookupNativeFormat(m_current_render_target->GetFormat(), nullptr,
&rt.BeginningAccess.Clear.ClearValue.Format, nullptr, nullptr);
GSVector4::store<false>(rt.BeginningAccess.Clear.ClearValue.Color, clear_color);
GSVector4::store<false>(rt.BeginningAccess.Clear.ClearValue.Color,
GSVector4::unorm8(clear_color));
}
}
@ -3026,8 +3010,7 @@ void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVect
SetStencilRef(1);
BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, GSVector4::zero(),
0.0f, 0);
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, 0, 0.0f, 0);
if (ApplyUtilityState())
DrawPrimitive();
@ -3062,7 +3045,7 @@ GSTexture12* GSDevice12::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, Pipe
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
config.ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
GSVector4::zero(), config.ds ? static_cast<GSTexture12*>(config.ds)->GetClearDepth() : 0.0f);
0, config.ds ? config.ds->GetClearDepth() : 0.0f);
// draw the quad to prefill the image
const GSVector4 src = GSVector4(config.drawarea) / GSVector4(rtsize).xyxy();
@ -3252,7 +3235,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
stencil_DATE ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD :
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
draw_rt ? draw_rt->GetClearColor() : GSVector4::zero(), draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
draw_rt ? draw_rt->GetClearColor() : 0, draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
}
// rt -> hdr blit if enabled

View File

@ -204,7 +204,7 @@ private:
GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) final;
const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) final;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final;
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
@ -279,7 +279,6 @@ public:
void DrawIndexedPrimitive();
void DrawIndexedPrimitive(int offset, int count);
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
void ClearRenderTarget(GSTexture* t, u32 c) override;
void InvalidateRenderTarget(GSTexture* t) override;
void ClearDepth(GSTexture* t, float d) override;
@ -369,7 +368,7 @@ public:
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE depth_end = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE stencil_begin = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE stencil_end = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
const GSVector4& clear_color = GSVector4::zero(), float clear_depth = 0.0f, u8 clear_stencil = 0);
const u32 clear_color = 0, float clear_depth = 0.0f, u8 clear_stencil = 0);
void EndRenderPass();
void SetViewport(const D3D12_VIEWPORT& viewport);

View File

@ -670,7 +670,7 @@ void GSTexture12::CommitClear(ID3D12GraphicsCommandList* cmdlist)
else
{
TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
cmdlist->ClearRenderTargetView(GetWriteDescriptor(), m_clear_value.color, 0, nullptr);
cmdlist->ClearRenderTargetView(GetWriteDescriptor(), GSVector4::unorm8(m_clear_value.color).v, 0, nullptr);
}
SetState(GSTexture::State::Dirty);

View File

@ -367,7 +367,7 @@ public:
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) override;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) override;
void DoFXAA(GSTexture* sTex, GSTexture* dTex) override;
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) override;
@ -404,7 +404,6 @@ public:
float GetAndResetAccumulatedGPUTime() override;
void AccumulateCommandBufferTime(id<MTLCommandBuffer> buffer);
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
void ClearRenderTarget(GSTexture* t, u32 c) override;
void ClearDepth(GSTexture* t, float d) override;
void InvalidateRenderTarget(GSTexture* t) override;

View File

@ -410,7 +410,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
} \
}
CHECK_CLEAR(mc, color_load, color_clear, GetClearColor)
CHECK_CLEAR(mc, color_load, color_clear, GetUNormClearColor)
CHECK_CLEAR(md, depth_load, depth_clear, GetClearDepth)
#undef CHECK_CLEAR
// Stencil and depth are one texture, stencil clears aren't supported
@ -567,7 +567,7 @@ GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int heigh
}
}}
void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
{ @autoreleasepool {
id<MTLCommandBuffer> cmdbuf = GetRenderCmdBuf();
GSScopedDebugGroupMTL dbg(cmdbuf, @"DoMerge");
@ -579,7 +579,8 @@ void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
ClearRenderTarget(dTex, c);
vector_float4 cb_c = { c.r, c.g, c.b, c.a };
const GSVector4 unorm_c = GSVector4::unorm8(c);
vector_float4 cb_c = { unorm_c.r, unorm_c.g, unorm_c.b, unorm_c.a };
GSMTLConvertPSUniform cb_yuv = {};
cb_yuv.emoda = EXTBUF.EMODA;
cb_yuv.emodc = EXTBUF.EMODC;
@ -1430,27 +1431,18 @@ void GSDeviceMTL::AccumulateCommandBufferTime(id<MTLCommandBuffer> buffer)
#pragma clang diagnostic pop
}
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, const GSVector4& c)
{
if (!t) return;
t->SetClearColor(c);
}
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, uint32 c)
{
GSVector4 color = GSVector4::rgba32(c) * (1.f / 255.f);
ClearRenderTarget(t, color);
t->SetClearColor(c);
}
void GSDeviceMTL::ClearDepth(GSTexture* t, float d)
{
if (!t) return;
t->SetClearDepth(d);
}
void GSDeviceMTL::InvalidateRenderTarget(GSTexture* t)
{
if (!t) return;
t->SetState(GSTexture::State::Invalidated);
}

View File

@ -859,132 +859,121 @@ void GSDeviceOGL::DrawIndexedPrimitive(int offset, int count)
static_cast<GLint>(m_vertex.start));
}
void GSDeviceOGL::ClearRenderTarget(GSTexture* t, const GSVector4& c)
void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
{
if (!t)
return;
GSTextureOGL* T = static_cast<GSTextureOGL*>(t);
if (T->HasBeenCleaned())
if (!T->IsRenderTargetOrDepthStencil() || T->GetState() == GSTexture::State::Dirty)
return;
// Performance note: potentially T->Clear() could be used. Main purpose of
// Clear() is to avoid the framebuffer setup cost. However, in this context,
// the texture 't' will be set as the render target of the framebuffer and
// therefore will require a framebuffer setup.
// So using the old/standard path is faster/better albeit verbose.
GL_PUSH("Clear RT %d", T->GetID());
// TODO: check size of scissor before toggling it
glDisable(GL_SCISSOR_TEST);
const u32 old_color_mask = GLState::wrgba;
OMSetColorMaskState();
OMSetFBO(m_fbo);
OMAttachRt(T);
if (T->IsIntegerFormat())
if (use_write_fbo)
{
if (T->IsUnsignedFormat())
glClearBufferuiv(GL_COLOR, 0, c.U32);
else
glClearBufferiv(GL_COLOR, 0, c.I32);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_write);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
(t->GetType() == GSTexture::Type::RenderTarget) ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, (t->GetType() == GSTexture::Type::DepthStencil) ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
}
else
{
glClearBufferfv(GL_COLOR, 0, c.v);
OMSetFBO(m_fbo);
if (T->GetType() == GSTexture::Type::DepthStencil)
{
if (GLState::rt && GLState::rt->GetSize() != T->GetSize())
OMAttachRt(nullptr);
OMAttachDs(T);
}
else
{
if (GLState::ds && GLState::ds->GetSize() != T->GetSize())
OMAttachDs(nullptr);
OMAttachRt(T);
}
}
OMSetColorMaskState(OMColorMaskSelector(old_color_mask));
if (T->GetState() == GSTexture::State::Invalidated)
{
if (GLAD_GL_VERSION_4_3)
{
if (T->GetType() == GSTexture::Type::DepthStencil)
{
const GLenum attachments[] = {GL_DEPTH_STENCIL_ATTACHMENT};
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
}
else
{
const GLenum attachments[] = {GL_COLOR_ATTACHMENT0};
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
}
}
}
else
{
glDisable(GL_SCISSOR_TEST);
glEnable(GL_SCISSOR_TEST);
if (T->GetType() == GSTexture::Type::DepthStencil)
{
const float d = T->GetClearDepth();
if (GLState::depth_mask)
{
glClearBufferfv(GL_DEPTH, 0, &d);
}
else
{
glDepthMask(true);
glClearBufferfv(GL_DEPTH, 0, &d);
glDepthMask(false);
}
}
else
{
const u32 old_color_mask = GLState::wrgba;
OMSetColorMaskState();
T->WasCleaned();
const GSVector4 c_unorm = T->GetUNormClearColor();
if (T->IsIntegerFormat())
{
if (T->IsUnsignedFormat())
glClearBufferuiv(GL_COLOR, 0, c_unorm.U32);
else
glClearBufferiv(GL_COLOR, 0, c_unorm.I32);
}
else
{
glClearBufferfv(GL_COLOR, 0, c_unorm.v);
}
OMSetColorMaskState(OMColorMaskSelector(old_color_mask));
}
glEnable(GL_SCISSOR_TEST);
}
T->SetState(GSTexture::State::Dirty);
if (use_write_fbo)
{
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
(t->GetType() == GSTexture::Type::RenderTarget) ? GL_COLOR_ATTACHMENT0 :
(m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT),
GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLState::fbo);
}
}
void GSDeviceOGL::ClearRenderTarget(GSTexture* t, u32 c)
{
if (!t)
return;
const GSVector4 color = GSVector4::rgba32(c) * (1.0f / 255);
ClearRenderTarget(t, color);
t->SetClearColor(c);
}
void GSDeviceOGL::InvalidateRenderTarget(GSTexture* t)
{
GSTextureOGL* T = static_cast<GSTextureOGL*>(t);
if (!T || T->HasBeenCleaned())
return;
if (GLAD_GL_VERSION_4_3 || GLAD_GL_ES_VERSION_3_0)
{
OMSetFBO(m_fbo);
if (T->GetType() == GSTexture::Type::DepthStencil)
{
OMAttachDs(T);
const GLenum attachments[] = {GL_DEPTH_STENCIL_ATTACHMENT};
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
}
else
{
OMAttachRt(T);
const GLenum attachments[] = {GL_COLOR_ATTACHMENT0};
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
}
}
t->SetState(GSTexture::State::Invalidated);
}
void GSDeviceOGL::ClearDepth(GSTexture* t, float d)
{
if (!t)
return;
GSTextureOGL* T = static_cast<GSTextureOGL*>(t);
GL_PUSH("Clear Depth %d", T->GetID());
OMSetFBO(m_fbo);
// RT must be detached, if RT is too small, depth won't be fully cleared
// AT tolenico 2 map clip bug
OMAttachRt(NULL);
OMAttachDs(T);
// TODO: check size of scissor before toggling it
glDisable(GL_SCISSOR_TEST);
if (GLState::depth_mask)
{
glClearBufferfv(GL_DEPTH, 0, &d);
}
else
{
glDepthMask(true);
glClearBufferfv(GL_DEPTH, 0, &d);
glDepthMask(false);
}
glEnable(GL_SCISSOR_TEST);
}
void GSDeviceOGL::ClearStencil(GSTexture* t, u8 c)
{
if (!t)
return;
GSTextureOGL* T = static_cast<GSTextureOGL*>(t);
GL_PUSH("Clear Stencil %d", T->GetID());
// Keep SCISSOR_TEST enabled on purpose to reduce the size
// of clean in DATE (impact big upscaling)
OMSetFBO(m_fbo);
OMAttachDs(T);
const GLint color = c;
glClearBufferiv(GL_STENCIL, 0, &color);
t->SetClearDepth(d);
}
std::unique_ptr<GSDownloadTexture> GSDeviceOGL::CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format)
@ -1229,6 +1218,8 @@ std::string GSDeviceOGL::GetPSSource(const PSSelector& sel)
// Copy a sub part of texture (same as below but force a conversion)
void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, bool linear)
{
CommitClear(sTex, true);
GL_PUSH(fmt::format("CopyRectConv from {}", static_cast<GSTextureOGL*>(sTex)->GetID()).c_str());
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
@ -1258,6 +1249,8 @@ void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r
const GLuint& sid = static_cast<GSTextureOGL*>(sTex)->GetID();
const GLuint& did = static_cast<GSTextureOGL*>(dTex)->GetID();
CommitClear(sTex, false);
CommitClear(dTex, false);
GL_PUSH("CopyRect from %d to %d", sid, did);
@ -1321,7 +1314,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear)
{
ASSERT(sTex);
CommitClear(sTex, true);
const bool draw_in_depth = dTex->IsDepthStencil();
@ -1364,7 +1357,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
void GSDeviceOGL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear)
{
ASSERT(sTex);
CommitClear(sTex, true);
const GSVector2i ds(dTex ? dTex->GetSize() : GSVector2i(GetWindowWidth(), GetWindowHeight()));
DisplayConstantBuffer cb;
@ -1402,6 +1395,8 @@ void GSDeviceOGL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
void GSDeviceOGL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize)
{
CommitClear(sTex, false);
const ShaderConvert shader = (dSize == 16) ? ShaderConvert::CLUT_4 : ShaderConvert::CLUT_8;
GLProgram& prog = m_convert.ps[static_cast<int>(shader)];
prog.Bind();
@ -1422,6 +1417,8 @@ void GSDeviceOGL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX,
void GSDeviceOGL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM)
{
CommitClear(sTex, false);
const ShaderConvert shader = ShaderConvert::RGBA_TO_8I;
GLProgram& prog = m_convert.ps[static_cast<int>(shader)];
prog.Bind();
@ -1561,7 +1558,7 @@ void GSDeviceOGL::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rec
DrawIndexedPrimitive();
}
void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
{
GL_PUSH("DoMerge");
@ -1609,7 +1606,7 @@ void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
{
// Blend with a constant alpha
m_merge_obj.ps[1].Bind();
m_merge_obj.ps[1].Uniform4fv(0, c.v);
m_merge_obj.ps[1].Uniform4fv(0, GSVector4::unorm8(c).v);
StretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[1], true, OMColorMaskSelector(), linear);
}
else
@ -1719,7 +1716,10 @@ void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* ver
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
ClearStencil(ds, 0);
OMSetRenderTargets(nullptr, ds, &GLState::scissor);
const GLint clear_color = 0;
glClearBufferiv(GL_STENCIL, 0, &clear_color);
m_convert.ps[static_cast<int>(datm ? ShaderConvert::DATM_1 : ShaderConvert::DATM_0)].Bind();
@ -1730,7 +1730,6 @@ void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* ver
{
glDisable(GL_BLEND);
}
OMSetRenderTargets(NULL, ds, &GLState::scissor);
// ia
@ -2014,30 +2013,24 @@ void GSDeviceOGL::RenderBlankFrame()
glEnable(GL_SCISSOR_TEST);
}
void GSDeviceOGL::OMAttachRt(GSTextureOGL* rt)
void GSDeviceOGL::OMAttachRt(GSTexture* rt)
{
if (rt)
rt->WasAttached();
if (GLState::rt == rt)
return;
if (GLState::rt != rt)
{
GLState::rt = rt;
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt ? rt->GetID() : 0, 0);
}
GLState::rt = static_cast<GSTextureOGL*>(rt);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt ? static_cast<GSTextureOGL*>(rt)->GetID() : 0, 0);
}
void GSDeviceOGL::OMAttachDs(GSTextureOGL* ds)
void GSDeviceOGL::OMAttachDs(GSTexture* ds)
{
if (ds)
ds->WasAttached();
if (GLState::ds == ds)
return;
if (GLState::ds != ds)
{
GLState::ds = ds;
GLState::ds = static_cast<GSTextureOGL*>(ds);
const GLenum target = m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT;
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, target, GL_TEXTURE_2D, ds ? ds->GetID() : 0, 0);
}
const GLenum target = m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT;
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, target, GL_TEXTURE_2D, ds ? static_cast<GSTextureOGL*>(ds)->GetID() : 0, 0);
}
void GSDeviceOGL::OMSetFBO(GLuint fbo)
@ -2128,27 +2121,26 @@ void GSDeviceOGL::OMSetBlendState(bool enable, GLenum src_factor, GLenum dst_fac
void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor)
{
GSTextureOGL* RT = static_cast<GSTextureOGL*>(rt);
GSTextureOGL* DS = static_cast<GSTextureOGL*>(ds);
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(GLState::rt != rt || GLState::ds != ds));
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(GLState::rt != RT || GLState::ds != DS));
// Split up to avoid unbind/bind calls when clearing.
OMSetFBO(m_fbo);
if (rt)
{
OMAttachRt(RT);
}
OMAttachRt(rt);
else
{
OMAttachRt();
}
// Note: it must be done after OMSetFBO
if (ds)
OMAttachDs(DS);
OMAttachDs(ds);
else
OMAttachDs();
if (rt)
CommitClear(rt, false);
if (ds)
CommitClear(ds, false);
if (rt || ds)
{
const GSVector2i size = rt ? rt->GetSize() : ds->GetSize();
@ -2253,7 +2245,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
case GSHWDrawConfig::DestinationAlphaMode::StencilOne:
if (m_features.texture_barrier)
{
ClearStencil(config.ds, 1);
// Cleared after RT bind.
break;
}
[[fallthrough]];
@ -2418,6 +2410,13 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
OMSetColorMaskState(config.colormask);
SetupOM(config.depth);
// Clear stencil as close as possible to the RT bind, to avoid framebuffer swaps.
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && m_features.texture_barrier)
{
constexpr GLint clear_color = 1;
glClearBufferiv(GL_STENCIL, 0, &clear_color);
}
SendHWDraw(config, psel.ps.IsFeedbackLoop());
if (config.separate_alpha_pass)

View File

@ -250,7 +250,7 @@ private:
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) override;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) override;
bool CompileFXAAProgram();
@ -266,8 +266,8 @@ private:
void RenderImGui();
void RenderBlankFrame();
void OMAttachRt(GSTextureOGL* rt = nullptr);
void OMAttachDs(GSTextureOGL* ds = nullptr);
void OMAttachRt(GSTexture* rt = nullptr);
void OMAttachDs(GSTexture* ds = nullptr);
void OMSetFBO(GLuint fbo);
void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds);
@ -285,6 +285,7 @@ public:
__fi u32 GetFBORead() const { return m_fbo_read; }
__fi u32 GetFBOWrite() const { return m_fbo_write; }
void CommitClear(GSTexture* t, bool use_write_fbo);
RenderAPI GetRenderAPI() const override;
bool HasSurface() const override;
@ -310,11 +311,9 @@ public:
void DrawIndexedPrimitive();
void DrawIndexedPrimitive(int offset, int count);
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
void ClearRenderTarget(GSTexture* t, u32 c) override;
void InvalidateRenderTarget(GSTexture* t) override;
void ClearDepth(GSTexture* t, float d) override;
void ClearStencil(GSTexture* t, u8 c);
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;

View File

@ -183,16 +183,6 @@ void* GSTextureOGL::GetNativeHandle() const
return reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture_id));
}
void GSTextureOGL::Clear(const void* data)
{
glClearTexImage(m_texture_id, 0, m_int_format, m_int_type, data);
}
void GSTextureOGL::Clear(const void* data, const GSVector4i& area)
{
glClearTexSubImage(m_texture_id, 0, area.x, area.y, 0, area.width(), area.height(), 1, m_int_format, m_int_type, data);
}
bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int layer)
{
ASSERT(m_type != Type::DepthStencil);
@ -205,8 +195,7 @@ bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int
// overflow the pbo buffer
// Data upload is rather small typically 64B or 1024B. So don't bother with PBO
// and directly send the data to the GL synchronously
m_clean = false;
GSDeviceOGL::GetInstance()->CommitClear(this, true);
const u32 preferred_pitch = Common::AlignUpPow2(r.width() << m_int_shift, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
const u32 map_size = r.height() * preferred_pitch;
@ -269,6 +258,8 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
if (layer >= m_mipmap_levels || IsCompressedFormat())
return false;
GSDeviceOGL::GetInstance()->CommitClear(this, true);
GSVector4i r = _r ? *_r : GSVector4i(0, 0, m_size.x, m_size.y);
// Will need some investigation
ASSERT(r.width() != 0);
@ -286,8 +277,6 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
GL_PUSH_("Upload Texture %d", m_texture_id); // POP is in Unmap
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
m_clean = false;
const auto map = GSDeviceOGL::GetTextureUploadBuffer()->Map(TEXTURE_UPLOAD_ALIGNMENT, upload_size);
m.bits = static_cast<u8*>(map.pointer);
@ -309,6 +298,8 @@ void GSTextureOGL::Unmap()
{
if (m_type == Type::Texture || m_type == Type::RenderTarget)
{
GSDeviceOGL::GetInstance()->CommitClear(this, true);
const u32 pitch = Common::AlignUpPow2(m_r_w << m_int_shift, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
const u32 upload_size = pitch * m_r_h;
GLStreamBuffer* sb = GSDeviceOGL::GetTextureUploadBuffer();
@ -334,11 +325,14 @@ void GSTextureOGL::Unmap()
void GSTextureOGL::GenerateMipmap()
{
ASSERT(m_mipmap_levels > 1);
GSDeviceOGL::GetInstance()->CommitClear(this, true);
glGenerateTextureMipmap(m_texture_id);
}
bool GSTextureOGL::Save(const std::string& fn)
{
GSDeviceOGL::GetInstance()->CommitClear(this, true);
// Collect the texture data
u32 pitch = 4 * m_size.x;
u32 buf_size = pitch * m_size.y * 2; // Note *2 for security (depth/stencil)
@ -351,7 +345,7 @@ bool GSTextureOGL::Save(const std::string& fn)
if (IsDepthStencil())
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
glBindFramebuffer(GL_READ_FRAMEBUFFER, GSDeviceOGL::GetInstance()->GetFBORead());
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_texture_id, 0);
glReadPixels(0, 0, m_size.x, m_size.y, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image.get());
@ -369,7 +363,7 @@ bool GSTextureOGL::Save(const std::string& fn)
}
else
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
glBindFramebuffer(GL_READ_FRAMEBUFFER, GSDeviceOGL::GetInstance()->GetFBORead());
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0);
@ -399,8 +393,6 @@ void GSTextureOGL::Swap(GSTexture* tex)
GSTexture::Swap(tex);
std::swap(m_texture_id, static_cast<GSTextureOGL*>(tex)->m_texture_id);
std::swap(m_fbo_read, static_cast<GSTextureOGL*>(tex)->m_fbo_read);
std::swap(m_clean, static_cast<GSTextureOGL*>(tex)->m_clean);
std::swap(m_r_x, static_cast<GSTextureOGL*>(tex)->m_r_x);
std::swap(m_r_x, static_cast<GSTextureOGL*>(tex)->m_r_y);
std::swap(m_r_w, static_cast<GSTextureOGL*>(tex)->m_r_w);
@ -491,6 +483,7 @@ void GSDownloadTextureOGL::CopyFromTexture(
const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch)
{
GSTextureOGL* const glTex = static_cast<GSTextureOGL*>(stex);
GSDeviceOGL::GetInstance()->CommitClear(glTex, true);
pxAssert(glTex->GetFormat() == m_format);
pxAssert(drc.width() == src.width() && drc.height() == src.height());

View File

@ -22,8 +22,6 @@ class GSTextureOGL final : public GSTexture
{
private:
GLuint m_texture_id = 0; // the texture id
GLuint m_fbo_read = 0;
bool m_clean = false;
// Avoid alignment constrain
//GSVector4i m_r;
@ -66,13 +64,7 @@ public:
return (m_int_type == GL_UNSIGNED_BYTE || m_int_type == GL_UNSIGNED_SHORT || m_int_type == GL_UNSIGNED_INT);
}
u32 GetID() { return m_texture_id; }
bool HasBeenCleaned() { return m_clean; }
void WasAttached() { m_clean = false; }
void WasCleaned() { m_clean = true; }
void Clear(const void* data);
void Clear(const void* data, const GSVector4i& area);
__fi u32 GetID() { return m_texture_id; }
};
class GSDownloadTextureOGL final : public GSDownloadTexture

View File

@ -790,24 +790,16 @@ void GSDeviceVK::DrawIndexedPrimitive(int offset, int count)
vkCmdDrawIndexed(g_vulkan_context->GetCurrentCommandBuffer(), count, 1, m_index.start + offset, m_vertex.start, 0);
}
void GSDeviceVK::ClearRenderTarget(GSTexture* t, const GSVector4& c)
void GSDeviceVK::ClearRenderTarget(GSTexture* t, u32 c)
{
if (!t)
return;
if (m_current_render_target == t)
EndRenderPass();
static_cast<GSTextureVK*>(t)->SetClearColor(c);
t->SetClearColor(c);
}
void GSDeviceVK::ClearRenderTarget(GSTexture* t, u32 c) { ClearRenderTarget(t, GSVector4::rgba32(c) * (1.0f / 255)); }
void GSDeviceVK::InvalidateRenderTarget(GSTexture* t)
{
if (!t)
return;
if (m_current_render_target == t || m_current_depth_target == t)
EndRenderPass();
@ -816,9 +808,6 @@ void GSDeviceVK::InvalidateRenderTarget(GSTexture* t)
void GSDeviceVK::ClearDepth(GSTexture* t, float d)
{
if (!t)
return;
if (m_current_depth_target == t)
EndRenderPass();
@ -903,7 +892,7 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
}
else
{
if ((dTexVK->GetClearColor() == (sTexVK->GetClearColor())).alltrue())
if (dTexVK->GetClearColor() == sTexVK->GetClearColor())
return;
}
}
@ -916,7 +905,7 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
// so use an attachment clear
VkClearAttachment ca;
ca.aspectMask = depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
GSVector4::store<false>(ca.clearValue.color.float32, sTexVK->GetClearColor());
GSVector4::store<false>(ca.clearValue.color.float32, sTexVK->GetUNormClearColor());
ca.clearValue.depthStencil.depth = sTexVK->GetClearDepth();
ca.clearValue.depthStencil.stencil = 0;
ca.colorAttachment = 0;
@ -1277,12 +1266,13 @@ void GSDeviceVK::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offs
}
void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect,
const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
{
GL_PUSH("DoMerge");
const GSVector4 full_r(0.0f, 0.0f, 1.0f, 1.0f);
const u32 yuv_constants[4] = {EXTBUF.EMODA, EXTBUF.EMODC};
const GSVector4 bg_color = GSVector4::unorm8(c);
const bool feedback_write_2 = PMODE.EN2 && sTex[2] != nullptr && EXTBUF.FBIN == 1;
const bool feedback_write_1 = PMODE.EN1 && sTex[2] != nullptr && EXTBUF.FBIN == 0;
const bool feedback_write_2_but_blend_bg = feedback_write_2 && PMODE.SLBG == 1;
@ -1362,7 +1352,7 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
// 1st output is enabled. It must be blended
SetUtilityTexture(sTex[0], sampler);
SetPipeline(m_merge[PMODE.MMOD]);
SetUtilityPushConstants(&c, sizeof(c));
SetUtilityPushConstants(&bg_color, sizeof(bg_color));
DrawStretchRect(sRect[0], dRect[0], dTex->GetSize());
}
@ -3136,10 +3126,10 @@ void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, c
vkCmdBeginRenderPass(g_vulkan_context->GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE);
}
void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const GSVector4& clear_color)
void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, u32 clear_color)
{
alignas(16) VkClearValue cv;
GSVector4::store<true>((void*)cv.color.float32, clear_color);
GSVector4::store<true>((void*)cv.color.float32, GSVector4::unorm8(clear_color));
BeginClearRenderPass(rp, rect, &cv, 1);
}
@ -3742,7 +3732,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
alignas(16) VkClearValue cvs[2];
u32 cv_count = 0;
if (draw_rt)
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetClearColor());
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
// the only time the stencil value is used here is DATE_one, so setting it to 1 is fine (not used otherwise)
if (draw_ds)
@ -3834,7 +3824,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
{
alignas(16) VkClearValue cvs[2];
u32 cv_count = 0;
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetClearColor());
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
if (draw_ds)
cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1};

View File

@ -180,7 +180,7 @@ private:
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) final;
const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) final;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final;
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
@ -265,7 +265,6 @@ public:
void DrawIndexedPrimitive();
void DrawIndexedPrimitive(int offset, int count);
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
void ClearRenderTarget(GSTexture* t, u32 c) override;
void InvalidateRenderTarget(GSTexture* t) override;
void ClearDepth(GSTexture* t, float d) override;
@ -352,7 +351,7 @@ public:
bool InRenderPass();
void BeginRenderPass(VkRenderPass rp, const GSVector4i& rect);
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const VkClearValue* cv, u32 cv_count);
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const GSVector4& clear_color);
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, u32 clear_color);
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, float depth, u8 stencil);
void EndRenderPass();

View File

@ -547,7 +547,7 @@ void GSTextureVK::CommitClear(VkCommandBuffer cmdbuf)
else
{
alignas(16) VkClearColorValue cv;
GSVector4::store<true>(cv.float32, GetClearColor());
GSVector4::store<true>(cv.float32, GetUNormClearColor());
const VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u};
vkCmdClearColorImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cv, 1, &srr);
}