From 9bb28d3feceab345bb658fdb3c756ddb0a938c3a Mon Sep 17 00:00:00 2001 From: refraction Date: Thu, 24 May 2012 18:46:00 +0000 Subject: [PATCH] Gif/VIF: -Path3 Masking Changes, Gif Unit now rolls the DMA back (Path3 only) if it is using the Masking and finishes mid DMA packet. -Vif modified to be simpler in the transfer loop and fixes issues where Flushes are called at the end of a DMA packet. Game fixes from changes: Outrun 2006 - Water textures and general flickering fixed, also SW mode not required for half screen issue. Caused by GIF Path 3 stopping in the wrong place. Star Wars Episode 3: Revenge of the Sith - DMA timeouts caused by Flush at end of packet. Had to break savestates (version change!), sorry :( git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5224 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/Gif.cpp | 2 +- pcsx2/Gif_Unit.h | 34 ++++++++++++--- pcsx2/SaveState.h | 2 +- pcsx2/Vif_Codes.cpp | 85 +++++++++++++++++++++++++------------ pcsx2/Vif_Dma.h | 1 + pcsx2/Vif_Transfer.cpp | 47 ++------------------ pcsx2/Vif_Unpack.cpp | 1 + pcsx2/x86/newVif_Unpack.cpp | 1 + 8 files changed, 94 insertions(+), 79 deletions(-) diff --git a/pcsx2/Gif.cpp b/pcsx2/Gif.cpp index 7c862641f4..c227e5fb71 100644 --- a/pcsx2/Gif.cpp +++ b/pcsx2/Gif.cpp @@ -249,7 +249,7 @@ void GIFdma() GIFchain(); //Transfers the data set by the switch CPU_INT(DMAC_GIF, gscycles); return; - } else if(gspath3done == false) GIFdma(); + } else if(gspath3done == false) GIFdma(); //Loop round if there was a blank tag, causes hell otherwise with P3 masking games. prevcycles = 0; CPU_INT(DMAC_GIF, gscycles); diff --git a/pcsx2/Gif_Unit.h b/pcsx2/Gif_Unit.h index f399de4b14..0b55f8c34d 100644 --- a/pcsx2/Gif_Unit.h +++ b/pcsx2/Gif_Unit.h @@ -145,6 +145,7 @@ struct Gif_Path { u32 buffLimit; // Cut off limit to wrap around u32 curSize; // Used buffer in bytes u32 curOffset; // Offset of current gifTag + u32 dmaRewind; // Used by path3 when only part of a DMA chain is used Gif_Tag gifTag; // Current GS Primitive tag GS_Packet gsPack; // Current GS Packet info GIF_PATH idx; // Gif Path Index @@ -296,14 +297,29 @@ struct Gif_Path { GS_Packet t = gsPack; t.done = 1; - //Path 3 Masking is timing sensitive, we need to simulate its length! (NFSU2) + + dmaRewind = 0; + + gsPack.Reset(); + gsPack.offset = curOffset; + + //Path 3 Masking is timing sensitive, we need to simulate its length! (NFSU2/Outrun 2006) + if((gifRegs.stat.APATH-1) == GIF_PATH_3) + { state = GIF_PATH_WAIT; + + if(curSize - curOffset > 0 && (gifRegs.stat.M3R || gifRegs.stat.M3P)) + { + //Including breaking packets early (Rewind DMA to pick up where left off) + //but only do this when the path is masked, else we're pointlessly slowing things down. + dmaRewind = curSize - curOffset; + curSize = curOffset; + } + } else state = GIF_PATH_IDLE; - gsPack.Reset(); - gsPack.offset = curOffset; return t; // Complete GS packet } } @@ -486,7 +502,7 @@ struct Gif_Unit { } gifPath[tranType&3].CopyGSPacketData(pMem, size, aligned); - Execute(); + size -= Execute(); return size; } @@ -524,10 +540,12 @@ struct Gif_Unit { // Processes gif packets and performs path arbitration // on EOPs or on Path 3 Images when IMT is set. - void Execute() { - if (!CanDoGif()) { DevCon.Error("Gif Unit - Signal or PSE Set or Dir = GS to EE"); return; } + int Execute() { + if (!CanDoGif()) { DevCon.Error("Gif Unit - Signal or PSE Set or Dir = GS to EE"); return 0; } bool didPath3 = false; + int curPath = stat.APATH-1; stat.OPH = 1; + gifPath[curPath].dmaRewind = 0; for(;;) { if (stat.APATH) { // Some Transfer is happening Gif_Path& path = gifPath[stat.APATH-1]; @@ -568,7 +586,9 @@ struct Gif_Unit { else { stat.APATH = 0; stat.OPH = 0; break; } } Gif_FinishIRQ(); - //DevCon.WriteLn("APATH = %d [%d,%d,%d]", stat.APATH, !!checkPaths(1,0,0,0),!!checkPaths(0,1,0,0),!!checkPaths(0,0,1,0)); + + //Path3 can rewind the DMA, so we send back the amount we go back! + return gifPath[curPath].dmaRewind; } // XGkick diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index 485176b32c..7a8a0f5db9 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -24,7 +24,7 @@ // the lower 16 bit value. IF the change is breaking of all compatibility with old // states, increment the upper 16 bit value, and clear the lower 16 bits to 0. -static const u32 g_SaveVersion = (0x9A07 << 16) | 0x0000; +static const u32 g_SaveVersion = (0x9A08 << 16) | 0x0000; // this function is meant to be used in the place of GSfreeze, and provides a safe layer // between the GS saving function and the MTGS's needs. :) diff --git a/pcsx2/Vif_Codes.cpp b/pcsx2/Vif_Codes.cpp index 4758eb31f5..e36a5b1541 100644 --- a/pcsx2/Vif_Codes.cpp +++ b/pcsx2/Vif_Codes.cpp @@ -92,11 +92,13 @@ void ExecuteVU(int idx) { vuExecMicro(idx, -1); vifX.cmd = 0; + vifX.pass = 0; } else if((vifX.cmd & 0x7f) == 0x14 || (vifX.cmd & 0x7f) == 0x15) { vuExecMicro(idx, (u16)(vifXRegs.code) << 3); vifX.cmd = 0; + vifX.pass = 0; } } @@ -106,9 +108,9 @@ void ExecuteVU(int idx) vifOp(vifCode_Base) { vif1Only(); - pass1 { vif1Regs.base = vif1Regs.code & 0x3ff; vif1.cmd = 0; } + pass1 { vif1Regs.base = vif1Regs.code & 0x3ff; vif1.cmd = 0; vif1.pass = 0; } pass3 { VifCodeLog("Base"); } - return 0; + return 1; } template __fi int _vifCode_Direct(int pass, const u8* data, bool isDirectHL) { @@ -116,7 +118,8 @@ template __fi int _vifCode_Direct(int pass, const u8* data, bool isDire pass1 { int vifImm = (u16)vif1Regs.code; vif1.tag.size = vifImm ? (vifImm*4) : (65536*4); - return 0; + vif1.pass = 1; + return 1; } pass2 { const char* name = isDirectHL ? "DirectHL" : "Direct"; @@ -134,9 +137,11 @@ template __fi int _vifCode_Direct(int pass, const u8* data, bool isDire //gifUnit.PrintInfo(); vif1.vifstalled = true; vif1Regs.stat.VGW = true; + return 0; } if (vif1.tag.size == 0) { vif1.cmd = 0; + vif1.pass = 0; } return ret / 4; } @@ -164,11 +169,13 @@ vifOp(vifCode_Flush) { //gifUnit.PrintInfo(); vif1Regs.stat.VGW = true; vifX.vifstalled = true; + return 0; } else vifX.cmd = 0; + vifX.pass = 0; } pass3 { VifCodeLog("Flush"); } - return 0; + return 1; } vifOp(vifCode_FlushA) { @@ -207,25 +214,27 @@ vifOp(vifCode_FlushA) { if (doStall) { vif1Regs.stat.VGW = true; vifX.vifstalled = true; + return 0; } else vifX.cmd = 0; + vifX.pass = 0; } pass3 { VifCodeLog("FlushA"); } - return 0; + return 1; } // ToDo: FixMe vifOp(vifCode_FlushE) { vifStruct& vifX = GetVifX; - pass1 { vifFlush(idx); vifX.cmd = 0; } + pass1 { vifFlush(idx); vifX.cmd = 0; vifX.pass = 0;} pass3 { VifCodeLog("FlushE"); } - return 0; + return 1; } vifOp(vifCode_ITop) { - pass1 { vifXRegs.itops = vifXRegs.code & 0x3ff; GetVifX.cmd = 0; } + pass1 { vifXRegs.itops = vifXRegs.code & 0x3ff; GetVifX.cmd = 0; GetVifX.pass = 0; } pass3 { VifCodeLog("ITop"); } - return 0; + return 1; } vifOp(vifCode_Mark) { @@ -234,9 +243,10 @@ vifOp(vifCode_Mark) { vifXRegs.mark = (u16)vifXRegs.code; vifXRegs.stat.MRK = true; vifX.cmd = 0; + vifX.pass = 0; } pass3 { VifCodeLog("Mark"); } - return 0; + return 1; } static __fi void _vifCode_MPG(int idx, u32 addr, const u32 *data, int size) { @@ -262,7 +272,12 @@ vifOp(vifCode_MPG) { vifX.tag.addr = (u16)(vifXRegs.code << 3) & (idx ? 0x3fff : 0xfff); vifX.tag.size = vifNum ? (vifNum*2) : 512; vifFlush(idx); - return 1; + if(vifX.vifstalled == true) return 0; + else + { + vifX.pass = 1; + return 1; + } } pass2 { if (vifX.vifpacketsize < vifX.tag.size) { // Partial Transfer @@ -282,6 +297,7 @@ vifOp(vifCode_MPG) { int ret = vifX.tag.size; vifX.tag.size = 0; vifX.cmd = 0; + vifX.pass = 0; return ret; } } @@ -298,10 +314,11 @@ vifOp(vifCode_MSCAL) { { vuExecMicro(idx, (u16)(vifXRegs.code) << 3); vifX.cmd = 0; - } + vifX.pass = 0; + } } pass3 { VifCodeLog("MSCAL"); } - return 0; + return 1; } vifOp(vifCode_MSCALF) { @@ -318,10 +335,11 @@ vifOp(vifCode_MSCALF) { { vuExecMicro(idx, (u16)(vifXRegs.code) << 3); vifX.cmd = 0; + vifX.pass = 0; } } pass3 { VifCodeLog("MSCALF"); } - return 0; + return 1; } vifOp(vifCode_MSCNT) { @@ -332,10 +350,11 @@ vifOp(vifCode_MSCNT) { { vuExecMicro(idx, -1); vifX.cmd = 0; + vifX.pass = 0; } } pass3 { VifCodeLog("MSCNT"); } - return 0; + return 1; } // ToDo: FixMe @@ -352,14 +371,16 @@ vifOp(vifCode_MskPath3) { //} } vif1.cmd = 0; + vif1.pass = 0; } pass3 { VifCodeLog("MskPath3"); } - return 0; + return 1; } vifOp(vifCode_Nop) { pass1 { GetVifX.cmd = 0; + GetVifX.pass = 0; /*if(idx && vif1ch.chcr.STR == true) { //Some games use a huge stream of NOPS to wait for a GIF packet to start, alas the way PCSX2 works it never starts @@ -370,7 +391,7 @@ vifOp(vifCode_Nop) { }*/ } pass3 { VifCodeLog("Nop"); } - return 0; + return 1; } // ToDo: Review Flags @@ -385,10 +406,11 @@ vifOp(vifCode_Null) { //vifX.irq++; } vifX.cmd = 0; + vifX.pass = 0; } pass2 { Console.Error("Vif%d bad vifcode! [CMD = %x]", idx, vifX.cmd); } pass3 { VifCodeLog("Null"); } - return 0; + return 1; } vifOp(vifCode_Offset) { @@ -398,9 +420,10 @@ vifOp(vifCode_Offset) { vif1Regs.ofst = vif1Regs.code & 0x3ff; vif1Regs.tops = vif1Regs.base; vif1.cmd = 0; + vif1.pass = 0; } pass3 { VifCodeLog("Offset"); } - return 0; + return 1; } template static __fi int _vifCode_STColRow(const u32* data, u32* pmem2) { @@ -421,7 +444,13 @@ template static __fi int _vifCode_STColRow(const u32* data, u32* pmem2) vifX.tag.addr += ret; vifX.tag.size -= ret; - if (!vifX.tag.size) vifX.cmd = 0; + if (!vifX.tag.size) + { + vifX.pass = 0; + vifX.cmd = 0; + } + + return ret; } @@ -431,6 +460,7 @@ vifOp(vifCode_STCol) { pass1 { vifX.tag.addr = 0; vifX.tag.size = 4; + vifX.pass = 1; return 1; } pass2 { @@ -447,6 +477,7 @@ vifOp(vifCode_STRow) { pass1 { vifX.tag.addr = 0; vifX.tag.size = 4; + vifX.pass = 1; return 1; } pass2 { @@ -455,7 +486,7 @@ vifOp(vifCode_STRow) { return ret; } pass3 { VifCodeLog("STRow"); } - return 0; + return 1; } vifOp(vifCode_STCycl) { @@ -464,23 +495,24 @@ vifOp(vifCode_STCycl) { vifXRegs.cycle.cl = (u8)(vifXRegs.code); vifXRegs.cycle.wl = (u8)(vifXRegs.code >> 8); vifX.cmd = 0; + vifX.pass = 0; } pass3 { VifCodeLog("STCycl"); } - return 0; + return 1; } vifOp(vifCode_STMask) { vifStruct& vifX = GetVifX; - pass1 { vifX.tag.size = 1; } - pass2 { vifXRegs.mask = data[0]; vifX.tag.size = 0; vifX.cmd = 0; } + pass1 { vifX.tag.size = 1; vifX.pass = 1; return 1; } + pass2 { vifXRegs.mask = data[0]; vifX.tag.size = 0; vifX.cmd = 0; vifX.pass = 0;} pass3 { VifCodeLog("STMask"); } return 1; } vifOp(vifCode_STMod) { - pass1 { vifXRegs.mode = vifXRegs.code & 0x3; GetVifX.cmd = 0; } + pass1 { vifXRegs.mode = vifXRegs.code & 0x3; GetVifX.cmd = 0; GetVifX.pass = 0;} pass3 { VifCodeLog("STMod"); } - return 0; + return 1; } template< uint idx > @@ -496,6 +528,7 @@ static uint calc_addr(bool flg) vifOp(vifCode_Unpack) { pass1 { vifUnpackSetup(data); + return 1; } pass2 { diff --git a/pcsx2/Vif_Dma.h b/pcsx2/Vif_Dma.h index b4797a299f..1adf48b298 100644 --- a/pcsx2/Vif_Dma.h +++ b/pcsx2/Vif_Dma.h @@ -62,6 +62,7 @@ struct vifStruct { struct { // These must be together for MTVU vifCode tag; int cmd; + int pass; int cl; u8 usn; u8 StructEnd; // Address of this is used to calculate end of struct diff --git a/pcsx2/Vif_Transfer.cpp b/pcsx2/Vif_Transfer.cpp index 90562af10f..d11472d12a 100644 --- a/pcsx2/Vif_Transfer.cpp +++ b/pcsx2/Vif_Transfer.cpp @@ -38,31 +38,6 @@ _vifT bool analyzeIbit(u32* &data, int iBit) { //DevCon.WriteLn("Vif I-Bit IRQ"); vifX.irq++; - // Okay did some testing with Max Payne, it does this: - // VifMark value = 0x666 (i know, evil!) - // NOP with I Bit - // VifMark value = 0 - // - // If you break after the 2nd Mark has run, the game reports invalid mark 0 and the game dies. - // So it has to occur here, testing a theory that it only doesn't stall if the command with - // the iBit IS mark, but still sends the IRQ to let the cpu know the mark is there. (Refraction) - // - // -------------------------- - // - // This is how it probably works: i-bit sets the IRQ flag, and VIF keeps running until it encounters - // a non-MARK instruction. This includes the *current* instruction. ie, execution only continues - // unimpeded if MARK[i] is specified, and keeps executing unimpeded until any non-MARK command. - // Any other command with an I bit should stall immediately. - // Example: - // - // VifMark[i] value = 0x321 (with I bit) - // VifMark value = 0 - // VifMark value = 0x333 - // NOP - // - // ... the VIF should not stall and raise the interrupt until after the NOP is processed. - // So the final value for MARK as the game sees it will be 0x333. --air - if(CHECK_VIF1STALLHACK) return 0; else return 1; } @@ -75,7 +50,8 @@ _vifT void vifTransferLoop(u32* &data) { u32& pSize = vifX.vifpacketsize; int iBit = vifX.cmd >> 7; - + int ret = 0; + vifXRegs.stat.VPS |= VPS_TRANSFERRING; vifXRegs.stat.ER1 = false; @@ -92,14 +68,9 @@ _vifT void vifTransferLoop(u32* &data) { // Pass 2 means "log it" vifCmdHandler[idx][vifX.cmd & 0x7f](2, data); } - - vifCmdHandler[idx][vifX.cmd & 0x7f](0, data); - data++; pSize--; - if (analyzeIbit(data, iBit)) break; - continue; } - int ret = vifCmdHandler[idx][vifX.cmd & 0x7f](1, data); + ret = vifCmdHandler[idx][vifX.cmd & 0x7f](vifX.pass, data); data += ret; pSize -= ret; if (analyzeIbit(data, iBit)) break; @@ -127,18 +98,6 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) { if (!idx) g_vif0Cycles += max(1, (int)((transferred * BIAS) >> 2)); else g_vif1Cycles += max(1, (int)((transferred * BIAS) >> 2)); - - /* - if(!idx && g_vu0Cycles > 0) { - if (g_vif0Cycles < g_vu0Cycles) g_vu0Cycles -= g_vif0Cycles; - elif(g_vif0Cycles >= g_vu0Cycles) g_vu0Cycles = 0; - } - if (idx && g_vu1Cycles > 0) { - if (g_vif1Cycles < g_vu1Cycles) g_vu1Cycles -= g_vif1Cycles; - elif(g_vif1Cycles >= g_vu1Cycles) g_vu1Cycles = 0; - } - */ - vifX.irqoffset = transferred % 4; // cannot lose the offset if (!TTE) {// *WARNING* - Tags CAN have interrupts! so lets just ignore the dma modifying stuffs (GT4) diff --git a/pcsx2/Vif_Unpack.cpp b/pcsx2/Vif_Unpack.cpp index a3719e3cb9..bf76364cc7 100644 --- a/pcsx2/Vif_Unpack.cpp +++ b/pcsx2/Vif_Unpack.cpp @@ -230,6 +230,7 @@ _vifT void vifUnpackSetup(const u32 *data) { vifX.cl = 0; vifX.tag.cmd = vifX.cmd; + GetVifX.pass = 1; } template void vifUnpackSetup<0>(const u32 *data); diff --git a/pcsx2/x86/newVif_Unpack.cpp b/pcsx2/x86/newVif_Unpack.cpp index c90843b0ee..bf5dc26094 100644 --- a/pcsx2/x86/newVif_Unpack.cpp +++ b/pcsx2/x86/newVif_Unpack.cpp @@ -133,6 +133,7 @@ _vifT int nVifUnpack(const u8* data) { } else vu1Thread.VifUnpack(vif, vifRegs, (u8*)data, size); + vif.pass = 0; vif.tag.size = 0; vif.cmd = 0; vifRegs.num = 0;