mirror of https://github.com/PCSX2/pcsx2.git
GS: Ignore 24bit on DATE and Handle Reversed Color and Z
Clamp Framebuffer width to 1-32
This commit is contained in:
parent
753da789a0
commit
a0bbdcefb3
|
@ -1230,18 +1230,28 @@ void GSState::GIFRegHandlerFRAME(const GIFReg* RESTRICT r)
|
|||
{
|
||||
GL_REG("FRAME_%d = 0x%x_%x", i, r->U32[1], r->U32[0]);
|
||||
|
||||
if (PRIM->CTXT == i && r->FRAME != m_env.CTXT[i].FRAME)
|
||||
GIFRegFRAME NewFrame = r->FRAME;
|
||||
// FBW is clamped between 1 and 32, however this is wrong, FBW of 0 *should* work and does on Dobiestation
|
||||
// However there is some issues so even software mode is incorrect on PCSX2, but this works better..
|
||||
NewFrame.FBW = std::clamp(NewFrame.FBW, 1U, 32U);
|
||||
|
||||
if (PRIM->CTXT == i && NewFrame != m_env.CTXT[i].FRAME)
|
||||
Flush();
|
||||
|
||||
if ((m_env.CTXT[i].FRAME.U32[0] ^ r->FRAME.U32[0]) & 0x3f3f01ff) // FBP FBW PSM
|
||||
if ((NewFrame.PSM & 0x30) == 0x30)
|
||||
m_env.CTXT[i].ZBUF.PSM &= ~0x30;
|
||||
else
|
||||
m_env.CTXT[i].ZBUF.PSM |= 0x30;
|
||||
|
||||
if ((m_env.CTXT[i].FRAME.U32[0] ^ NewFrame.U32[0]) & 0x3f3f01ff) // FBP FBW PSM
|
||||
{
|
||||
m_env.CTXT[i].offset.fb = m_mem.GetOffset(r->FRAME.Block(), r->FRAME.FBW, r->FRAME.PSM);
|
||||
m_env.CTXT[i].offset.zb = m_mem.GetOffset(m_env.CTXT[i].ZBUF.Block(), r->FRAME.FBW, m_env.CTXT[i].ZBUF.PSM);
|
||||
m_env.CTXT[i].offset.fzb = m_mem.GetPixelOffset(r->FRAME, m_env.CTXT[i].ZBUF);
|
||||
m_env.CTXT[i].offset.fzb4 = m_mem.GetPixelOffset4(r->FRAME, m_env.CTXT[i].ZBUF);
|
||||
m_env.CTXT[i].offset.fb = m_mem.GetOffset(NewFrame.Block(), NewFrame.FBW, NewFrame.PSM);
|
||||
m_env.CTXT[i].offset.zb = m_mem.GetOffset(m_env.CTXT[i].ZBUF.Block(), NewFrame.FBW, m_env.CTXT[i].ZBUF.PSM);
|
||||
m_env.CTXT[i].offset.fzb = m_mem.GetPixelOffset(NewFrame, m_env.CTXT[i].ZBUF);
|
||||
m_env.CTXT[i].offset.fzb4 = m_mem.GetPixelOffset4(NewFrame, m_env.CTXT[i].ZBUF);
|
||||
}
|
||||
|
||||
m_env.CTXT[i].FRAME = (GSVector4i)r->FRAME;
|
||||
m_env.CTXT[i].FRAME = (GSVector4i)NewFrame;
|
||||
|
||||
switch (m_env.CTXT[i].FRAME.PSM)
|
||||
{
|
||||
|
@ -1273,11 +1283,16 @@ void GSState::GIFRegHandlerZBUF(const GIFReg* RESTRICT r)
|
|||
|
||||
GIFRegZBUF ZBUF = r->ZBUF;
|
||||
|
||||
// TODO: I tested this and I believe it is possible to set zbuf to a color format
|
||||
// Powerdrome relies on this behavior to clear the z buffer
|
||||
// the undocumented formats do have behavior (they mess with the swizzling)
|
||||
// we don't emulate this yet (and maybe we wont need to)
|
||||
ZBUF.PSM |= 0x30;
|
||||
// We tested this on the PS2 and it seems to be that when the FRAME is a Z format,
|
||||
// the Z buffer is forced to use color swizzling.
|
||||
// Powerdrome relies on this behavior to clear the z buffer by drawing 32 pixel wide strips, skipping 32,
|
||||
// causing the FRAME to do one strip and the Z to do the other 32 due to the block arrangement.
|
||||
// Other games listed here also hit this Color/Z swap behaviour without masking Z so could be problematic:
|
||||
// Black, Driver Parallel Lines, Driv3r, Dropship, DT Racer, Scarface, The Simpsons, THP8
|
||||
if ((m_env.CTXT[i].FRAME.PSM & 0x30) == 0x30)
|
||||
ZBUF.PSM &= ~0x30;
|
||||
else
|
||||
ZBUF.PSM |= 0x30;
|
||||
|
||||
if (PRIM->CTXT == i && ZBUF != m_env.CTXT[i].ZBUF)
|
||||
Flush();
|
||||
|
|
|
@ -1266,6 +1266,15 @@ void GSRendererHW::Draw()
|
|||
return;
|
||||
}
|
||||
|
||||
// When the format is 24bit (Z or C), DATE ceases to function.
|
||||
// It was believed that in 24bit mode all pixels pass because alpha doesn't exist
|
||||
// however after testing this on a PS2 it turns out nothing passes, it ignores the draw.
|
||||
if ((m_context->FRAME.PSM & 0xF) == PSM_PSMCT24 && m_context->TEST.DATE)
|
||||
{
|
||||
GL_CACHE("DATE on a 24bit format, Frame PSM %x", m_context->FRAME.PSM);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fix TEX0 size
|
||||
if (PRIM->TME && !IsMipMapActive())
|
||||
m_context->ComputeFixedTEX0(m_vt.m_min.t.xyxy(m_vt.m_max.t));
|
||||
|
@ -1953,6 +1962,24 @@ void GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds)
|
|||
}
|
||||
}
|
||||
}
|
||||
// Striped double clear done by Powerdrome and Snoopy Vs Red Baron, it will clear in 32 pixel stripes half done by the Z and half done by the FRAME
|
||||
else if (rt && !ds && m_context->FRAME.FBP == m_context->ZBUF.ZBP && (m_context->FRAME.PSM & 0x30) != (m_context->ZBUF.PSM & 0x30)
|
||||
&& (m_context->FRAME.PSM & 0xF) == (m_context->ZBUF.PSM & 0xF) && (u32)(GSVector4i(m_vt.m_max.p).z) == 0)
|
||||
{
|
||||
const GSVertex* v = &m_vertex.buff[0];
|
||||
const GSLocalMemory::psm_t& frame_psm = GSLocalMemory::m_psm[m_context->FRAME.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;
|
||||
|
||||
// If both buffers are side by side we can expect a fast clear in on-going
|
||||
const u32 color = v[1].RGBAQ.U32[0];
|
||||
const GSVector4i commitRect = ComputeBoundingBox(rt->GetScale(), rt->GetSize());
|
||||
rt->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
|
||||
|
||||
g_gs_device->ClearRenderTarget(rt, color);
|
||||
}
|
||||
}
|
||||
|
||||
// Note: hack is safe, but it could impact the perf a little (normally games do only a couple of clear by frame)
|
||||
|
@ -1960,8 +1987,12 @@ void GSRendererHW::OI_GsMemClear()
|
|||
{
|
||||
// Note gs mem clear must be tested before calling this function
|
||||
|
||||
// Striped double clear done by Powerdrome and Snoopy Vs Red Baron, it will clear in 32 pixel stripes half done by the Z and half done by the FRAME
|
||||
const bool ZisFrame = m_context->FRAME.FBP == m_context->ZBUF.ZBP && (m_context->FRAME.PSM & 0x30) != (m_context->ZBUF.PSM & 0x30)
|
||||
&& (m_context->FRAME.PSM & 0xF) == (m_context->ZBUF.PSM & 0xF) && (u32)(GSVector4i(m_vt.m_max.p).z) == 0;
|
||||
|
||||
// Limit it further to a full screen 0 write
|
||||
if ((m_vertex.next == 2) && m_vt.m_min.c.eq(GSVector4i(0)))
|
||||
if (((m_vertex.next == 2) || ZisFrame) && m_vt.m_min.c.eq(GSVector4i(0)))
|
||||
{
|
||||
const GSOffset& off = m_context->offset.fb;
|
||||
const GSVector4i r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(m_context->scissor.in));
|
||||
|
@ -2007,11 +2038,11 @@ void GSRendererHW::OI_GsMemClear()
|
|||
; // Hack is used for FMV which are likely 24/32 bits. Let's keep the for reference
|
||||
#if 0
|
||||
// Based on WritePixel16
|
||||
for(int y = r.top; y < r.bottom; y++)
|
||||
for (int y = r.top; y < r.bottom; y++)
|
||||
{
|
||||
auto pa = off.assertSizesMatch(GSLocalMemory::swizzle16).paMulti(m_mem.m_vm16, 0, y);
|
||||
|
||||
for(int x = r.left; x < r.right; x++)
|
||||
for (int x = r.left; x < r.right; x++)
|
||||
{
|
||||
*pa.value(x) = 0; // Here the constant color
|
||||
}
|
||||
|
|
|
@ -964,6 +964,15 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
|||
u32 fm = context->FRAME.FBMSK;
|
||||
u32 zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0;
|
||||
|
||||
// When the format is 24bit (Z or C), DATE ceases to function.
|
||||
// It was believed that in 24bit mode all pixels pass because alpha doesn't exist
|
||||
// however after testing this on a PS2 it turns out nothing passes, it ignores the draw.
|
||||
if ((m_context->FRAME.PSM & 0xF) == PSM_PSMCT24 && m_context->TEST.DATE)
|
||||
{
|
||||
//DevCon.Warning("DATE on a 24bit format, Frame PSM %x", m_context->FRAME.PSM);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->TEST.ZTE && context->TEST.ZTST == ZTST_NEVER)
|
||||
{
|
||||
fm = 0xffffffff;
|
||||
|
|
Loading…
Reference in New Issue