Skip to content

Commit

Permalink
GSRendererHW: Jak games OI hack CPU palette render
Browse files Browse the repository at this point in the history
Fixes Jak and Daxter colors in Jak games (old hack yielded wrong colors and
clashed with texture in RT TC hack)

- Remove OO_JakGames hack for palette readback from framebuffer (slow,
clashes with texture in RT TC hack, clashes with Target readback logic)
- Add OI_JakGames hack for CPU palette rendering (fast, does not clash with
texture in RT TC hack, no readback required)
  • Loading branch information
iMineLink committed Jun 29, 2019
1 parent ba2efec commit ad81719
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 25 deletions.
190 changes: 166 additions & 24 deletions plugins/GSdx/Renderers/HW/GSRendererHW.cpp
Expand Up @@ -1278,12 +1278,12 @@ 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));
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::Jak2, CRC::RegionCount, &GSRendererHW::OI_JakGames));
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::Jak3, CRC::RegionCount, &GSRendererHW::OI_JakGames));
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::JakX, CRC::RegionCount, &GSRendererHW::OI_JakGames));

m_oo_list.push_back(HackEntry<OO_Ptr>(CRC::DBZBT2, CRC::RegionCount, &GSRendererHW::OO_DBZBT2));
m_oo_list.push_back(HackEntry<OO_Ptr>(CRC::MajokkoALaMode2, CRC::RegionCount, &GSRendererHW::OO_MajokkoALaMode2));
m_oo_list.push_back(HackEntry<OO_Ptr>(CRC::Jak2, CRC::RegionCount, &GSRendererHW::OO_JakGames));
m_oo_list.push_back(HackEntry<OO_Ptr>(CRC::Jak3, CRC::RegionCount, &GSRendererHW::OO_JakGames));
m_oo_list.push_back(HackEntry<OO_Ptr>(CRC::JakX, CRC::RegionCount, &GSRendererHW::OO_JakGames));

m_cu_list.push_back(HackEntry<CU_Ptr>(CRC::DBZBT2, CRC::RegionCount, &GSRendererHW::CU_DBZBT2));
m_cu_list.push_back(HackEntry<CU_Ptr>(CRC::MajokkoALaMode2, CRC::RegionCount, &GSRendererHW::CU_MajokkoALaMode2));
Expand Down Expand Up @@ -1863,6 +1863,169 @@ bool GSRendererHW::OI_ItadakiStreet(GSTexture* rt, GSTexture* ds, GSTextureCache
return true;
}

bool GSRendererHW::OI_JakGames(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
{
// Jak hair, beard and eyebrows are being rendered to palette.
// Cannot perform GPU render to FB as reading back is both slow
// and clashes with texture inside FB reading needed for correct eye rendering.
// So do CPU rendering instead, which consists in copying palette data from source
// buffer to destination buffer, without any blending/tfx.

GSVector4i r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(m_context->scissor.in));
GSVector4i r_p = GSVector4i(0, 0, 16, 16);

if (!PRIM->FST && PRIM->TME && (r == r_p).alltrue() && m_context->TEX0.TBW == 1 && m_context->TEX0.TW == 4 && m_context->TEX0.TH == 4 && m_context->TEX0.PSM == PSM_PSMCT32)
{
// No rasterization required
ASSERT(m_vt.m_eq.rgba == 0xffff);
ASSERT(m_vt.m_eq.z == 0x1);
ASSERT(m_vt.m_eq.q == 0x1);

// Game will render a texture directly into a palette.
uint32 FBP = m_context->FRAME.Block();

// Setup registers for SW rendering
GIFRegBITBLTBUF bitbltbuf;

bitbltbuf.SBP = m_context->TEX0.TBP0;
bitbltbuf.SBW = 1;
bitbltbuf.SPSM = PSM_PSMCT32;

bitbltbuf.DBP = FBP;
bitbltbuf.DBW = 1;
bitbltbuf.DPSM = PSM_PSMCT32;

GIFRegTRXPOS trxpos;

trxpos.DIRX = 0;
trxpos.DIRY = 0;
trxpos.DSAX = 0;
trxpos.DSAY = 0;
trxpos.SSAX = 0;
trxpos.SSAY = 0;

GIFRegTRXREG trxreg;

trxreg.RRH = 16;
trxreg.RRW = 16;

// SW rendering code, mainly taken from GSState::Move()

int sx = trxpos.SSAX;
int sy = trxpos.SSAY;
int dx = trxpos.DSAX;
int dy = trxpos.DSAY;
int w = trxreg.RRW;
int h = trxreg.RRH;

GL_INS("OI_JakGames CPU palette rendering: 0x%x W:%d F:%s => 0x%x W:%d F:%s (DIR %d%d), sPos(%d %d) dPos(%d %d) size(%d %d)",
bitbltbuf.SBP, bitbltbuf.SBW, psm_str(bitbltbuf.SPSM),
bitbltbuf.DBP, bitbltbuf.DBW, psm_str(bitbltbuf.DPSM),
trxpos.DIRX, trxpos.DIRY,
sx, sy, dx, dy, w, h);

InvalidateLocalMem(bitbltbuf, GSVector4i(sx, sy, sx + w, sy + h));
InvalidateVideoMem(bitbltbuf, GSVector4i(dx, dy, dx + w, dy + h));

int xinc = 1;
int yinc = 1;

if (trxpos.DIRX) { sx += w - 1; dx += w - 1; xinc = -1; }
if (trxpos.DIRY) { sy += h - 1; dy += h - 1; yinc = -1; }

GSOffset* RESTRICT spo = m_mem.GetOffset(bitbltbuf.SBP, bitbltbuf.SBW, bitbltbuf.SPSM);
GSOffset* RESTRICT dpo = m_mem.GetOffset(bitbltbuf.DBP, bitbltbuf.DBW, bitbltbuf.DPSM);

int* RESTRICT scol = &spo->pixel.col[0][sx];
int* RESTRICT dcol = &dpo->pixel.col[0][dx];

GSVector4i vc = m_vt.m_min.c;

uint8 tex0_tcc = m_context->TEX0.TCC;
uint8 alpha_b = m_context->ALPHA.B;

for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
{
uint32* RESTRICT s = &m_mem.m_vm32[spo->pixel.row[sy]];
uint32* RESTRICT d = &m_mem.m_vm32[dpo->pixel.row[dy]];

for (int x = 0; x < w; x++)
{
// Read source pixel color
GSVector4i sc;
uint32 sc_packed = s[scol[x]];
sc.r = sc_packed & 0xff;
sc.g = (sc_packed >> 8) & 0xff;
sc.b = (sc_packed >> 16) & 0xff;
sc.a = (sc_packed >> 24) & 0xff;

// Apply TFX
ASSERT(m_context->TEX0.TFX == 0);
sc.r = ((sc.r * vc.r) >> 7) & 0xff;
sc.g = ((sc.g * vc.g) >> 7) & 0xff;
sc.b = ((sc.b * vc.b) >> 7) & 0xff;
sc.a = tex0_tcc == 0 ? vc.a : ((sc.a * vc.a) >> 7) & 0xff;

// No FOG
ASSERT(m_env.PRIM.FGE == 0);

// Read destination pixel color
GSVector4i dc;
uint32 dc_packed = d[dcol[x]];
dc.r = dc_packed & 0xff;
dc.g = (dc_packed >> 8) & 0xff;
dc.b = (dc_packed >> 16) & 0xff;
dc.a = (dc_packed >> 24) & 0xff;

// Blending
ASSERT(m_context->ALPHA.A == 0);
ASSERT(alpha_b == 1 || alpha_b == 2);
ASSERT(m_context->ALPHA.C == 0);
ASSERT(m_context->ALPHA.D == 1);
ASSERT(m_context->ALPHA.FIX == 0);

if (alpha_b == 1)
{
// (Cs - Cd) * As + Cd
dc.r = (((sc.r - dc.r) * sc.a) >> 7) + dc.r;
dc.g = (((sc.g - dc.g) * sc.a) >> 7) + dc.g;
dc.b = (((sc.b - dc.b) * sc.a) >> 7) + dc.b;
}
else if (alpha_b == 2)
{
// (Cs - 0) * As + Cd
dc.r = ((sc.r * sc.a) >> 7) + dc.r;
dc.g = ((sc.g * sc.a) >> 7) + dc.g;
dc.b = ((sc.b * sc.a) >> 7) + dc.b;
}
else
{
GL_INS("OI_JakGames CPU palette rendering: ERROR Unsupported blending ALPHA.B == %d\n", alpha_b);
ASSERT(false);
}

// Clamping
ASSERT(m_env.COLCLAMP.CLAMP == 1);
dc.r = dc.r & 0xff;
dc.g = dc.g & 0xff;
dc.b = dc.b & 0xff;

// No Alpha Correction
ASSERT(m_context->FBA.FBA == 0);
dc.a = sc.a;

dc_packed = (dc.a << 24) | (dc.b << 16) | (dc.g << 8) | dc.r;

d[dcol[x]] = dc_packed;
}
}

return false; // skip current draw
}

return true;
}

// OO (others output?) hacks: invalidate extra local memory after the draw call

void GSRendererHW::OO_DBZBT2()
Expand Down Expand Up @@ -1902,27 +2065,6 @@ void GSRendererHW::OO_MajokkoALaMode2()
}
}

void GSRendererHW::OO_JakGames()
{
// FIXME might need a CU_Jak too
GSVector4i r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(m_context->scissor.in));
GSVector4i r_p = GSVector4i(0, 0, 16, 16);

if(!PRIM->FST && PRIM->TME && (r == r_p).alltrue() && m_context->TEX0.TW == 4 && m_context->TEX0.TH == 4 && m_context->TEX0.PSM == PSM_PSMCT32) {
// Game will render a texture directly into a palette.
uint32 FBP = m_context->FRAME.Block();
GL_INS("OO_JakGames read back 0x%x", FBP);

GIFRegBITBLTBUF BITBLTBUF;

BITBLTBUF.SBP = FBP;
BITBLTBUF.SBW = 1;
BITBLTBUF.SPSM = PSM_PSMCT32;

InvalidateLocalMem(BITBLTBUF, GSVector4i(0, 0, 16, 16));
}
}

// Can Upscale hacks: disable upscaling for some draw calls

bool GSRendererHW::CU_DBZBT2()
Expand Down
2 changes: 1 addition & 1 deletion plugins/GSdx/Renderers/HW/GSRendererHW.h
Expand Up @@ -62,10 +62,10 @@ class GSRendererHW : public GSRenderer
bool OI_SuperManReturns(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
bool OI_ArTonelico2(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
bool OI_ItadakiStreet(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
bool OI_JakGames(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);

void OO_DBZBT2();
void OO_MajokkoALaMode2();
void OO_JakGames();

bool CU_DBZBT2();
bool CU_MajokkoALaMode2();
Expand Down

0 comments on commit ad81719

Please sign in to comment.