gsdx hw: group the double half clear with gs mem clear hack

It avoid redundant check of the GS context

You can disable the extra clear with UserHacks_DisableGsMemClear = 1
This commit is contained in:
Gregory Hainaut 2016-09-20 18:57:07 +02:00
parent 6c6ed5f443
commit 1e343084e2
3 changed files with 27 additions and 35 deletions

View File

@ -692,7 +692,18 @@ void GSRendererHW::Draw()
}
if (!m_userhacks_disable_gs_mem_clear) {
OI_GsMemClear();
// Constant Direct Write without texture/test/blending (aka a GS mem clear)
if ((m_vt.m_primclass == GS_SPRITE_CLASS) && !PRIM->TME && !PRIM->ABE // Direct write
&& (m_context->FRAME.FBMSK == 0) // no color mask
&& !m_context->TEST.ATE // no alpha test
&& (!m_context->TEST.ZTE || m_context->TEST.ZTST == ZTST_ALWAYS) // no depth test
&& (m_vt.m_eq.rgba == 0xFFFF) // constant color write
&& r.x == 0 && r.y == 0) { // Likely full buffer write
OI_GsMemClear();
OI_DoubleHalfClear(rt_tex, ds_tex);
}
}
// skip alpha test if possible
@ -875,11 +886,6 @@ GSRendererHW::Hacks::Hacks()
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::SuperManReturns, CRC::RegionCount, &GSRendererHW::OI_SuperManReturns));
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::ArTonelico2, CRC::RegionCount, &GSRendererHW::OI_ArTonelico2));
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::ItadakiStreet, CRC::RegionCount, &GSRendererHW::OI_ItadakiStreet));
// Enable it by default in the future (hack ought to be safe enough)
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::SimpsonsGame, CRC::RegionCount, &GSRendererHW::OI_DoubleHalfClear));
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::TyTasmanianTiger, CRC::RegionCount, &GSRendererHW::OI_DoubleHalfClear));
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::TyTasmanianTiger2, CRC::RegionCount, &GSRendererHW::OI_DoubleHalfClear));
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::FFVIIDoC, CRC::RegionCount, &GSRendererHW::OI_DoubleHalfClear));
if (!can_handle_depth)
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::SMTNocturne, CRC::RegionCount, &GSRendererHW::OI_SMTNocturne));
@ -905,34 +911,28 @@ void GSRendererHW::Hacks::SetGameCRC(const CRC::Game& game)
m_oi = &GSRendererHW::OI_PointListPalette;
}
bool hack = theApp.GetConfigB("UserHacks_ColorDepthClearOverlap") && theApp.GetConfigB("UserHacks");
if (hack && !m_oi) {
// FIXME: Enable this code in the future. I think it could replace
// most of the "old" OI hack. So far code was tested on GoW2 & SimpsonsGame with
// success
m_oi = &GSRendererHW::OI_DoubleHalfClear;
}
}
// Handle case where the frame buffer and the Z buffer overlap
bool GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
// Trick to do a fast clear on the GS
// Set frame buffer pointer on the start of the buffer. Set depth buffer pointer on the half buffer
// FB + depth write will fill the full buffer.
void GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds)
{
// Trick to do a fast clear on the GS
// Set frame buffer pointer on the start of the buffer. Set depth buffer pointer on the half buffer
// FB + depth write will fill the full buffer.
if ((m_vt.m_primclass == GS_SPRITE_CLASS) && !PRIM->TME && !m_context->ZBUF.ZMSK && rt && ds) {
// Note gs mem clear must be tested before calling this function
// Limit further to unmask Z write
if (!m_context->ZBUF.ZMSK && rt && ds) {
const GSVertex* v = &m_vertex.buff[0];
const GSLocalMemory::psm_t& frame_psm = GSLocalMemory::m_psm[m_context->FRAME.PSM];
const GSLocalMemory::psm_t& depth_psm = GSLocalMemory::m_psm[m_context->ZBUF.PSM];
// Z and color must be constant and the same
if (m_vt.m_eq.rgba != 0xFFFF || !m_vt.m_eq.z || v[1].XYZ.Z != v[1].RGBAQ.u32[0])
return true;
return;
// Format doesn't have the same size. It smells fishy
if (frame_psm.trbpp != depth_psm.trbpp)
return true;
return;
// Size of the current draw
uint32 w_pages = roundf(m_vt.m_max.p.x / frame_psm.pgs.x);
@ -963,24 +963,17 @@ bool GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds, GSTextureCac
} else {
m_dev->ClearRenderTarget(rt, color);
}
// warning: draw call mustn't be skipped to keep correct invalidation. Don't return false
}
}
return true;
}
// Note: hack is safe, but it could impact the perf a little (normally games do only a couple of clear by frame)
void GSRendererHW::OI_GsMemClear()
{
// Rectangle draw without texture
if ((m_vt.m_primclass == GS_SPRITE_CLASS) && (m_vertex.next == 2) && !PRIM->TME && !PRIM->ABE // Direct write
&& (m_context->FRAME.FBMSK == 0)
&& !m_context->TEST.ATE // no alpha test
&& (!m_context->TEST.ZTE || m_context->TEST.ZTST == ZTST_ALWAYS) // no depth test
&& (m_vt.m_eq.rgba == 0xFFFF && m_vt.m_min.c.eq(GSVector4i(0))) // Constant 0 write
) {
// Note gs mem clear must be tested before calling this function
// Limit it further to a full screen 0 write
if ((m_vertex.next == 2) && m_vt.m_min.c.eq(GSVector4i(0))) {
GSOffset* off = m_context->offset.fb;
GSVector4i r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(m_context->scissor.in));
// Limit the hack to a single fullscreen clear. Some games might use severals column to clear a screen

View File

@ -50,8 +50,8 @@ private:
// Require special argument
bool OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Source* t, const GSVector4i& r_draw);
void OI_GsMemClear(); // always on
void OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds); // always on
bool OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
bool OI_DoubleHalfClear_Vertical(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
bool OI_FFXII(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
bool OI_FFX(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);

View File

@ -337,7 +337,6 @@ void GSdxApp::Init()
m_default_configuration["UserHacks_AlphaHack"] = "0";
m_default_configuration["UserHacks_AlphaStencil"] = "0";
m_default_configuration["UserHacks_AutoFlush"] = "0";
m_default_configuration["UserHacks_ColorDepthClearOverlap"] = "0";
m_default_configuration["UserHacks_DisableDepthSupport"] = "0";
m_default_configuration["UserHacks_DisableGsMemClear"] = "0";
m_default_configuration["UserHacks_DisablePartialInvalidation"] = "0";