From c9a1558c601242b8a080617744d8b213b19bedf6 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Mon, 29 Aug 2016 23:56:15 +0200 Subject: [PATCH] gsdx: save the blit buffer register when a transfer is started Fix motocross mania missing texture. Close #1319 As far as I understand, transfer is initialized in DIR. But the real write only occured later so the blit buffer could have been overwritten by a new value. BLIT 0 13700 TREG 40 40 DIR 0 0 BLIT 0 13f00 <=== the bad guy Write! ... => 0x3f00 W:1 F:C_32 (DIR 00), dPos(0 0) size(64 64) v2: set a value in m_tr.m_blit for load state --- plugins/GSdx/GSState.cpp | 32 ++++++++++++++++++++------------ plugins/GSdx/GSState.h | 3 ++- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/plugins/GSdx/GSState.cpp b/plugins/GSdx/GSState.cpp index d8dd1467cf..14dc9e9dd8 100644 --- a/plugins/GSdx/GSState.cpp +++ b/plugins/GSdx/GSState.cpp @@ -1343,10 +1343,10 @@ void GSState::GIFRegHandlerTRXDIR(const GIFReg* RESTRICT r) switch(m_env.TRXDIR.XDIR) { case 0: // host -> local - m_tr.Init(m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY); + m_tr.Init(m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_env.BITBLTBUF); break; case 1: // local -> host - m_tr.Init(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY); + m_tr.Init(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY, m_env.BITBLTBUF); break; case 2: // local -> local Move(); @@ -1524,7 +1524,8 @@ void GSState::Write(const uint8* mem, int len) int w = m_env.TRXREG.RRW; int h = m_env.TRXREG.RRH; - const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM]; + GIFRegBITBLTBUF& blit = m_tr.m_blit; + const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[blit.DPSM]; /* * The game uses a resolution of 512x244. RT is located at 0x700 and depth at 0x0 @@ -1542,13 +1543,13 @@ void GSState::Write(const uint8* mem, int len) * depth buffer. Let's reduce the size of the transfer */ if (m_game.title == CRC::SMTNocturne) { - if (m_env.BITBLTBUF.DBP == 0 && m_env.BITBLTBUF.DPSM == PSM_PSMZ32 && w == 512 && h > 224) { + if (blit.DBP == 0 && blit.DPSM == PSM_PSMZ32 && w == 512 && h > 224) { h = 224; m_env.TRXREG.RRH = 224; } } - // printf("Write len=%d DBP=%05x DBW=%d DPSM=%d DSAX=%d DSAY=%d RRW=%d RRH=%d\n", len, m_env.BITBLTBUF.DBP, m_env.BITBLTBUF.DBW, m_env.BITBLTBUF.DPSM, m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_env.TRXREG.RRW, m_env.TRXREG.RRH); + // printf("Write len=%d DBP=%05x DBW=%d DPSM=%d DSAX=%d DSAY=%d RRW=%d RRH=%d\n", len, blit.DBP, blit.DBW, blit.DPSM, m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_env.TRXREG.RRW, m_env.TRXREG.RRH); if(!m_tr.Update(w, h, psm.trbpp, len)) { @@ -1556,11 +1557,11 @@ void GSState::Write(const uint8* mem, int len) } GL_CACHE("Write! ... => 0x%x W:%d F:%s (DIR %d%d), dPos(%d %d) size(%d %d)", - m_env.BITBLTBUF.DBP, m_env.BITBLTBUF.DBW, psm_str(m_env.BITBLTBUF.DPSM), + blit.DBP, blit.DBW, psm_str(blit.DPSM), m_env.TRXPOS.DIRX, m_env.TRXPOS.DIRY, m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, w, h); - if(PRIM->TME && (m_env.BITBLTBUF.DBP == m_context->TEX0.TBP0 || m_env.BITBLTBUF.DBP == m_context->TEX0.CBP)) // TODO: hmmmm + if(PRIM->TME && (blit.DBP == m_context->TEX0.TBP0 || blit.DBP == m_context->TEX0.CBP)) // TODO: hmmmm { FlushPrim(); } @@ -1578,9 +1579,9 @@ void GSState::Write(const uint8* mem, int len) r.right = r.left + m_env.TRXREG.RRW; r.bottom = r.top + m_env.TRXREG.RRH; - InvalidateVideoMem(m_env.BITBLTBUF, r); + InvalidateVideoMem(blit, r); - (m_mem.*psm.wi)(m_tr.x, m_tr.y, mem, m_tr.total, m_env.BITBLTBUF, m_env.TRXPOS, m_env.TRXREG); + (m_mem.*psm.wi)(m_tr.x, m_tr.y, mem, m_tr.total, blit, m_env.TRXPOS, m_env.TRXREG); m_tr.start = m_tr.end = m_tr.total; @@ -1590,9 +1591,9 @@ void GSState::Write(const uint8* mem, int len) static int n = 0; string s; s = format("c:\\temp1\\[%04d]_%05x_%d_%d_%d_%d_%d_%d.bmp", - n++, (int)m_env.BITBLTBUF.DBP, (int)m_env.BITBLTBUF.DBW, (int)m_env.BITBLTBUF.DPSM, + n++, (int)blit.DBP, (int)blit.DBW, (int)blit.DPSM, r.left, r.top, r.right, r.bottom); - m_mem.SaveBMP(s, m_env.BITBLTBUF.DBP, m_env.BITBLTBUF.DBW, m_env.BITBLTBUF.DPSM, r.right, r.bottom); + m_mem.SaveBMP(s, blit.DBP, blit.DBW, blit.DPSM, r.right, r.bottom); */ } else @@ -2299,6 +2300,12 @@ int GSState::Defrost(const GSFreezeData* fd) ReadState(&m_env.TRXPOS, data); ReadState(&m_env.TRXREG, data); ReadState(&m_env.TRXREG, data); // obsolete + // Technically this value ought to be saved like m_tr.x/y (break + // compatibility) but so far only a single game (Motocross Mania) really + // depends on this value (i.e != BITBLTBUF) Savestates are likely done at + // VSYNC, so not in the middle of a texture transfer, therefore register + // will be set again properly + m_tr.m_blit = m_env.BITBLTBUF; for(int i = 0; i < 2; i++) { @@ -3050,11 +3057,12 @@ GSState::GSTransferBuffer::~GSTransferBuffer() _aligned_free(buff); } -void GSState::GSTransferBuffer::Init(int tx, int ty) +void GSState::GSTransferBuffer::Init(int tx, int ty, const GIFRegBITBLTBUF& blit) { x = tx; y = ty; total = 0; + m_blit = blit; } bool GSState::GSTransferBuffer::Update(int tw, int th, int bpp, int& len) diff --git a/plugins/GSdx/GSState.h b/plugins/GSdx/GSState.h index af61aa9d96..90d8206bb5 100644 --- a/plugins/GSdx/GSState.h +++ b/plugins/GSdx/GSState.h @@ -143,11 +143,12 @@ class GSState : public GSAlignedClass<32> int start, end, total; bool overflow; uint8* buff; + GIFRegBITBLTBUF m_blit; GSTransferBuffer(); virtual ~GSTransferBuffer(); - void Init(int tx, int ty); + void Init(int tx, int ty, const GIFRegBITBLTBUF& blit); bool Update(int tw, int th, int bpp, int& len); } m_tr;