GS/GL: Only issue barriers for framebuffer optimizations if needed.

Check if the state changed previous draw/pass and if not then we
need to issue a barrier or render pass then to ensure writes.
This commit is contained in:
lightningterror 2025-12-06 05:23:12 +01:00
parent e07f02d9bc
commit 51947f8f93
3 changed files with 39 additions and 14 deletions

View File

@ -36,6 +36,10 @@ namespace GLState
GSTextureOGL* rt = nullptr;
GSTextureOGL* ds = nullptr;
bool rt_written;
bool ds_written;
GLuint tex_unit[8];
GLuint64 tex_handle[8];
@ -67,6 +71,10 @@ namespace GLState
rt = nullptr;
ds = nullptr;
rt_written = false;
ds_written = false;
std::fill(std::begin(tex_unit), std::end(tex_unit), 0);
std::fill(std::begin(tex_handle), std::end(tex_handle), 0);
}

View File

@ -40,6 +40,10 @@ namespace GLState
extern GSTextureOGL* rt; // render target
extern GSTextureOGL* ds; // Depth-Stencil
extern bool rt_written; // Render Target written
extern bool ds_written; // Depth Stencil written
extern GLuint tex_unit[8]; // shader input texture
extern GLuint64 tex_handle[8]; // shader input texture

View File

@ -2305,26 +2305,35 @@ void GSDeviceOGL::OMSetBlendState(bool enable, GLenum src_factor, GLenum dst_fac
void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor)
{
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(GLState::rt != rt || GLState::ds != ds));
const bool rt_changed = (rt != GLState::rt);
const bool ds_changed = (ds != GLState::ds);
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(rt_changed || ds_changed));
// Split up to avoid unbind/bind calls when clearing.
OMSetFBO(m_fbo);
GLState::rt_written = false;
GLState::ds_written = false;
if (rt)
{
OMAttachRt(rt);
CommitClear(rt, false);
GLState::rt_written = rt_changed;
}
else
OMAttachRt();
if (ds)
{
OMAttachDs(ds);
CommitClear(ds, false);
GLState::ds_written = ds_changed;
}
else
OMAttachDs();
if (rt)
CommitClear(rt, false);
if (ds)
CommitClear(ds, false);
if (rt || ds)
{
const GSVector2i size = rt ? rt->GetSize() : ds->GetSize();
@ -2578,14 +2587,6 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
if (config.require_one_barrier || !m_features.texture_barrier)
rt_hazard_barrier = false; // Already in place or not available
// Be careful of the rt already being bound and the blend using the RT without a barrier.
if (rt_hazard_barrier)
{
// Ensure all depth writes are finished before sampling
GL_INS("GL: Texture barrier to flush depth or rt before reading");
g_perfmon.Put(GSPerfMon::Barriers, 1);
glTextureBarrier();
}
// additional non-pipeline config stuff
const bool point_size_enabled = config.vs.point_size;
if (GLState::point_size != point_size_enabled)
@ -2644,15 +2645,27 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
// avoid changing framebuffer just to switch from rt+depth to rt and vice versa
GSTexture* draw_rt = colclip_rt ? colclip_rt : config.rt;
GSTexture* draw_ds = config.ds;
bool fb_optimization_needs_barrier = false;
if (!draw_rt && GLState::rt && GLState::ds == draw_ds && config.tex != GLState::rt &&
GLState::rt->GetSize() == draw_ds->GetSize())
{
draw_rt = GLState::rt;
fb_optimization_needs_barrier = !GLState::rt_written;
}
else if (!draw_ds && GLState::ds && GLState::rt == draw_rt && config.tex != GLState::ds &&
GLState::ds->GetSize() == draw_rt->GetSize())
{
draw_ds = GLState::ds;
fb_optimization_needs_barrier = !GLState::ds_written;
}
// Be careful of the rt already being bound and the blend using the RT without a barrier.
if (fb_optimization_needs_barrier && rt_hazard_barrier)
{
// Ensure all depth writes are finished before sampling
GL_INS("GL: Texture barrier to flush depth or rt before reading");
g_perfmon.Put(GSPerfMon::Barriers, 1);
glTextureBarrier();
}
OMSetRenderTargets(draw_rt, draw_ds, &config.scissor);