diff --git a/pcsx2/Gif_Unit.cpp b/pcsx2/Gif_Unit.cpp index e9568648a1..ad3e7ff026 100644 --- a/pcsx2/Gif_Unit.cpp +++ b/pcsx2/Gif_Unit.cpp @@ -24,23 +24,37 @@ Gif_Unit gifUnit; // Returns true on stalling SIGNAL -bool Gif_HandlerAD(u8* pMem) { - u32 reg = pMem[8]; +bool Gif_HandlerAD(u8* pMem) +{ + u32 reg = pMem[8]; u32* data = (u32*)pMem; - if (reg == 0x50) { + if (reg == 0x50) + { vif1.BITBLTBUF._u64 = *(u64*)pMem; } - else if (reg == 0x52) { + else if (reg == 0x52) + { vif1.TRXREG._u64 = *(u64*)pMem; } - else if (reg == 0x53) { // TRXDIR - if ((pMem[0] & 3) == 1) { // local -> host + else if (reg == 0x53) + { // TRXDIR + if ((pMem[0] & 3) == 1) + { // local -> host u8 bpp = 32; // Onimusha does TRXDIR without BLTDIVIDE first, assume 32bit - switch(vif1.BITBLTBUF.SPSM & 7) { - case 0: bpp = 32; break; - case 1: bpp = 24; break; - case 2: bpp = 16; break; - case 3: bpp = 8; break; + switch (vif1.BITBLTBUF.SPSM & 7) + { + case 0: + bpp = 32; + break; + case 1: + bpp = 24; + break; + case 2: + bpp = 16; + break; + case 3: + bpp = 8; + break; default: // 4 is 4 bit but this is forbidden Console.Error("Illegal format for GS upload: SPSM=0%02o", vif1.BITBLTBUF.SPSM); break; @@ -50,147 +64,213 @@ bool Gif_HandlerAD(u8* pMem) { vif1.GSLastDownloadSize = vif1.TRXREG.RRW * vif1.TRXREG.RRH * bpp >> 7; } } - else if (reg == 0x60) { // SIGNAL - if (CSRreg.SIGNAL) { // Time to ignore all subsequent drawing operations. + else if (reg == 0x60) + { // SIGNAL + if (CSRreg.SIGNAL) + { // Time to ignore all subsequent drawing operations. GUNIT_WARN(Color_Orange, "GIF Handler - Stalling SIGNAL"); - if(!gifUnit.gsSIGNAL.queued) { - gifUnit.gsSIGNAL.queued = true; + if (!gifUnit.gsSIGNAL.queued) + { + gifUnit.gsSIGNAL.queued = true; gifUnit.gsSIGNAL.data[0] = data[0]; gifUnit.gsSIGNAL.data[1] = data[1]; return true; // Stalling SIGNAL } } - else { + else + { GUNIT_WARN("GIF Handler - SIGNAL"); - GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID&~data[1])|(data[0]&data[1]); - if (!GSIMR.SIGMSK) gsIrq(); + GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID & ~data[1]) | (data[0] & data[1]); + if (!GSIMR.SIGMSK) + gsIrq(); CSRreg.SIGNAL = true; } } - else if (reg == 0x61) { // FINISH + else if (reg == 0x61) + { // FINISH GUNIT_WARN("GIF Handler - FINISH"); CSRreg.FINISH = true; } - else if (reg == 0x62) { // LABEL + else if (reg == 0x62) + { // LABEL GUNIT_WARN("GIF Handler - LABEL"); - GSSIGLBLID.LBLID = (GSSIGLBLID.LBLID&~data[1])|(data[0]&data[1]); + GSSIGLBLID.LBLID = (GSSIGLBLID.LBLID & ~data[1]) | (data[0] & data[1]); } - else if (reg >= 0x63 && reg != 0x7f) { + else if (reg >= 0x63 && reg != 0x7f) + { //DevCon.Warning("GIF Handler - Write to unknown register! [reg=%x]", reg); } return false; } -bool Gif_HandlerAD_MTVU(u8* pMem) { - u32 reg = pMem[8]; +bool Gif_HandlerAD_MTVU(u8* pMem) +{ + u32 reg = pMem[8]; u32* data = (u32*)pMem; vu1Thread.gsInterrupts &= ~vu1Thread.gsToClear; vu1Thread.gsToClear = 0; - if (reg == 0x50) { Console.Error("GIF Handler Debug - BITBLTBUF"); return 1; } - else if (reg == 0x52) { Console.Error("GIF Handler Debug - TRXREG"); return 1; } - else if (reg == 0x53) { Console.Error("GIF Handler Debug - TRXDIR"); return 1; } - else if (reg == 0x60) { // SIGNAL - if (CSRreg.SIGNAL) { // Time to ignore all subsequent drawing operations. - Console.Error("GIF Handler MTVU - Double SIGNAL Not Handled"); return 1; + if (reg == 0x50) + { + Console.Error("GIF Handler Debug - BITBLTBUF"); + return 1; + } + else if (reg == 0x52) + { + Console.Error("GIF Handler Debug - TRXREG"); + return 1; + } + else if (reg == 0x53) + { + Console.Error("GIF Handler Debug - TRXDIR"); + return 1; + } + else if (reg == 0x60) + { // SIGNAL + if (CSRreg.SIGNAL) + { // Time to ignore all subsequent drawing operations. + Console.Error("GIF Handler MTVU - Double SIGNAL Not Handled"); + return 1; } - else { + else + { GUNIT_WARN("GIF Handler - SIGNAL"); vu1Thread.gsSignal = ((u64)data[1] << 32) | data[0]; vu1Thread.gsInterrupts |= 2; - } } - else if (reg == 0x61) { // FINISH + else if (reg == 0x61) + { // FINISH GUNIT_WARN("GIF Handler - FINISH"); vu1Thread.gsInterrupts |= 1; } - else if (reg == 0x62) { // LABEL + else if (reg == 0x62) + { // LABEL GUNIT_WARN("GIF Handler - LABEL"); vu1Thread.gsLabel = ((u64)data[1] << 32) | data[0]; vu1Thread.gsInterrupts |= 4; } - else if (reg >= 0x63 && reg != 0x7f) { + else if (reg >= 0x63 && reg != 0x7f) + { DevCon.Warning("GIF Handler Debug - Write to unknown register! [reg=%x]", reg); } return 0; } // Returns true if pcsx2 needed to process the packet... -bool Gif_HandlerAD_Debug(u8* pMem) { - u32 reg = pMem[8]; - if (reg == 0x50) { Console.Error("GIF Handler Debug - BITBLTBUF"); return 1; } - else if (reg == 0x52) { Console.Error("GIF Handler Debug - TRXREG"); return 1; } - else if (reg == 0x53) { Console.Error("GIF Handler Debug - TRXDIR"); return 1; } - else if (reg == 0x60) { Console.Error("GIF Handler Debug - SIGNAL"); return 1; } - else if (reg == 0x61) { Console.Error("GIF Handler Debug - FINISH"); return 1; } - else if (reg == 0x62) { Console.Error("GIF Handler Debug - LABEL"); return 1; } - else if (reg >= 0x63 && reg != 0x7f) { +bool Gif_HandlerAD_Debug(u8* pMem) +{ + u32 reg = pMem[8]; + if (reg == 0x50) + { + Console.Error("GIF Handler Debug - BITBLTBUF"); + return 1; + } + else if (reg == 0x52) + { + Console.Error("GIF Handler Debug - TRXREG"); + return 1; + } + else if (reg == 0x53) + { + Console.Error("GIF Handler Debug - TRXDIR"); + return 1; + } + else if (reg == 0x60) + { + Console.Error("GIF Handler Debug - SIGNAL"); + return 1; + } + else if (reg == 0x61) + { + Console.Error("GIF Handler Debug - FINISH"); + return 1; + } + else if (reg == 0x62) + { + Console.Error("GIF Handler Debug - LABEL"); + return 1; + } + else if (reg >= 0x63 && reg != 0x7f) + { DevCon.Warning("GIF Handler Debug - Write to unknown register! [reg=%x]", reg); } return 0; } -void Gif_FinishIRQ() { - if (CSRreg.FINISH && !GSIMR.FINISHMSK && !gifUnit.gsFINISH.gsFINISHFired) { +void Gif_FinishIRQ() +{ + if (CSRreg.FINISH && !GSIMR.FINISHMSK && !gifUnit.gsFINISH.gsFINISHFired) + { gsIrq(); gifUnit.gsFINISH.gsFINISHFired = true; } } // Used in MTVU mode... MTVU will later complete a real packet -void Gif_AddGSPacketMTVU(GS_Packet& gsPack, GIF_PATH path) { +void Gif_AddGSPacketMTVU(GS_Packet& gsPack, GIF_PATH path) +{ GetMTGS().SendSimpleGSPacket(GS_RINGTYPE_MTVU_GSPACKET, 0, 0, path); } -void Gif_AddCompletedGSPacket(GS_Packet& gsPack, GIF_PATH path) { +void Gif_AddCompletedGSPacket(GS_Packet& gsPack, GIF_PATH path) +{ //DevCon.WriteLn("Adding Completed Gif Packet [size=%x]", gsPack.size); - if (COPY_GS_PACKET_TO_MTGS) { - GetMTGS().PrepDataPacket(path, gsPack.size/16); - MemCopy_WrappedDest((u128*)&gifUnit.gifPath[path].buffer[gsPack.offset], RingBuffer.m_Ring, - GetMTGS().m_packet_writepos, RingBufferSize, gsPack.size/16); + if (COPY_GS_PACKET_TO_MTGS) + { + GetMTGS().PrepDataPacket(path, gsPack.size / 16); + MemCopy_WrappedDest((u128*)&gifUnit.gifPath[path].buffer[gsPack.offset], RingBuffer.m_Ring, + GetMTGS().m_packet_writepos, RingBufferSize, gsPack.size / 16); GetMTGS().SendDataPacket(); } - else { + else + { pxAssertDev(!gsPack.readAmount, "Gif Unit - gsPack.readAmount only valid for MTVU path 1!"); gifUnit.gifPath[path].readAmount.fetch_add(gsPack.size); - GetMTGS().SendSimpleGSPacket(GS_RINGTYPE_GSPACKET, gsPack.offset, gsPack.size, path); + GetMTGS().SendSimpleGSPacket(GS_RINGTYPE_GSPACKET, gsPack.offset, gsPack.size, path); } } -void Gif_AddBlankGSPacket(u32 size, GIF_PATH path) { +void Gif_AddBlankGSPacket(u32 size, GIF_PATH path) +{ //DevCon.WriteLn("Adding Blank Gif Packet [size=%x]", size); gifUnit.gifPath[path].readAmount.fetch_add(size); GetMTGS().SendSimpleGSPacket(GS_RINGTYPE_GSPACKET, ~0u, size, path); } -void Gif_MTGS_Wait(bool isMTVU) { +void Gif_MTGS_Wait(bool isMTVU) +{ GetMTGS().WaitGS(false, true, isMTVU); } -void SaveStateBase::gifPathFreeze(u32 path) { +void SaveStateBase::gifPathFreeze(u32 path) +{ Gif_Path& gifPath = gifUnit.gifPath[path]; - pxAssertDev(!gifPath.readAmount, "Gif Path readAmount should be 0!"); - pxAssertDev(!gifPath.gsPack.readAmount, "GS Pack readAmount should be 0!"); + pxAssertDev(!gifPath.readAmount, "Gif Path readAmount should be 0!"); + pxAssertDev(!gifPath.gsPack.readAmount, "GS Pack readAmount should be 0!"); pxAssertDev(!gifPath.GetPendingGSPackets(), "MTVU GS Pack Queue should be 0!"); - if (!gifPath.isMTVU()) { // FixMe: savestate freeze bug (Gust games) with MTVU enabled - if (IsSaving()) { // Move all the buffered data to the start of buffer + if (!gifPath.isMTVU()) + { // FixMe: savestate freeze bug (Gust games) with MTVU enabled + if (IsSaving()) + { // Move all the buffered data to the start of buffer gifPath.RealignPacket(); // May add readAmount which we need to clear on load } } u8* bufferPtr = gifPath.buffer; // Backup current buffer ptr Freeze(gifPath.mtvu.fakePackets); - FreezeMem(&gifPath, sizeof(gifPath) - sizeof(gifPath.mtvu)); + FreezeMem(&gifPath, sizeof(gifPath) - sizeof(gifPath.mtvu)); FreezeMem(bufferPtr, gifPath.curSize); gifPath.buffer = bufferPtr; - if(!IsSaving()) { - gifPath.readAmount = 0; + if (!IsSaving()) + { + gifPath.readAmount = 0; gifPath.gsPack.readAmount = 0; } } -void SaveStateBase::gifFreeze() { +void SaveStateBase::gifFreeze() +{ bool mtvuMode = THREAD_VU1; pxAssert(vu1Thread.IsDone()); GetMTGS().WaitGS(); @@ -203,8 +283,10 @@ void SaveStateBase::gifFreeze() { gifPathFreeze(GIF_PATH_1); gifPathFreeze(GIF_PATH_2); gifPathFreeze(GIF_PATH_3); - if (!IsSaving()) { - if (mtvuMode != THREAD_VU1) { + if (!IsSaving()) + { + if (mtvuMode != THREAD_VU1) + { DevCon.Warning("gifUnit: MTVU Mode has switched between save/load state"); // ToDo: gifUnit.SwitchMTVU(mtvuMode); } diff --git a/pcsx2/Gif_Unit.h b/pcsx2/Gif_Unit.h index 947b315c71..e0ebc8f4d6 100644 --- a/pcsx2/Gif_Unit.h +++ b/pcsx2/Gif_Unit.h @@ -30,94 +30,106 @@ extern bool Gif_HandlerAD(u8* pMem); extern bool Gif_HandlerAD_MTVU(u8* pMem); extern bool Gif_HandlerAD_Debug(u8* pMem); extern void Gif_AddBlankGSPacket(u32 size, GIF_PATH path); -extern void Gif_AddGSPacketMTVU (GS_Packet& gsPack, GIF_PATH path); +extern void Gif_AddGSPacketMTVU(GS_Packet& gsPack, GIF_PATH path); extern void Gif_AddCompletedGSPacket(GS_Packet& gsPack, GIF_PATH path); extern void Gif_ParsePacket(u8* data, u32 size, GIF_PATH path); extern void Gif_ParsePacket(GS_Packet& gsPack, GIF_PATH path); -struct Gif_Tag { - struct HW_Gif_Tag { - u16 NLOOP : 15; - u16 EOP : 1; - u16 _dummy0 : 16; - u32 _dummy1 : 14; - u32 PRE : 1; - u32 PRIM : 11; - u32 FLG : 2; - u32 NREG : 4; +struct Gif_Tag +{ + struct HW_Gif_Tag + { + u16 NLOOP : 15; + u16 EOP : 1; + u16 _dummy0 : 16; + u32 _dummy1 : 14; + u32 PRE : 1; + u32 PRIM : 11; + u32 FLG : 2; + u32 NREG : 4; u32 REGS[2]; } tag; - u32 nLoop; // NLOOP left to process - u32 nRegs; // NREG (1~16) - u32 nRegIdx; // Current nReg Index (packed mode processing) - u32 len; // Packet Length in Bytes (not including tag) - u32 cycles; // Time needed to process packet data in ee-cycles - u8 regs[16]; // Regs - bool hasAD; // Has an A+D Write - bool isValid; // Tag is valid - + u32 nLoop; // NLOOP left to process + u32 nRegs; // NREG (1~16) + u32 nRegIdx; // Current nReg Index (packed mode processing) + u32 len; // Packet Length in Bytes (not including tag) + u32 cycles; // Time needed to process packet data in ee-cycles + u8 regs[16]; // Regs + bool hasAD; // Has an A+D Write + bool isValid; // Tag is valid + Gif_Tag() { Reset(); } - Gif_Tag(u8* pMem, bool analyze = false) { - setTag (pMem, analyze); + Gif_Tag(u8* pMem, bool analyze = false) + { + setTag(pMem, analyze); } - void Reset() { memzero(*this); } - u8 curReg() { return regs[nRegIdx&0xf]; } + void Reset() { memzero(*this); } + u8 curReg() { return regs[nRegIdx & 0xf]; } - void packedStep() { - if (nLoop > 0) { + void packedStep() + { + if (nLoop > 0) + { nRegIdx++; - if (nRegIdx >= nRegs) { + if (nRegIdx >= nRegs) + { nRegIdx = 0; nLoop--; } } } - void setTag(u8* pMem, bool analyze = false) { - tag = *(HW_Gif_Tag*)pMem; + void setTag(u8* pMem, bool analyze = false) + { + tag = *(HW_Gif_Tag*)pMem; nLoop = tag.NLOOP; hasAD = false; nRegIdx = 0; isValid = 1; len = 0; // avoid uninitialized compiler warning - switch(tag.FLG) { + switch (tag.FLG) + { case GIF_FLG_PACKED: - nRegs = ((tag.NREG-1)&0xf) + 1; - len = (nRegs * tag.NLOOP)* 16; + nRegs = ((tag.NREG - 1) & 0xf) + 1; + len = (nRegs * tag.NLOOP) * 16; cycles = len << 1; // Packed Mode takes 2 ee-cycles - if (analyze) analyzeTag(); + if (analyze) + analyzeTag(); break; case GIF_FLG_REGLIST: - nRegs = ((tag.NREG-1)&0xf) + 1; - len =((nRegs * tag.NLOOP + 1) >> 1) * 16; + nRegs = ((tag.NREG - 1) & 0xf) + 1; + len = ((nRegs * tag.NLOOP + 1) >> 1) * 16; cycles = len << 2; // Reg-list Mode takes 4 ee-cycles break; case GIF_FLG_IMAGE: case GIF_FLG_IMAGE2: - nRegs = 0; - len = tag.NLOOP * 16; + nRegs = 0; + len = tag.NLOOP * 16; cycles = len << 2; // Image Mode takes 4 ee-cycles tag.FLG = GIF_FLG_IMAGE; break; - jNO_DEFAULT; + jNO_DEFAULT; } } - void analyzeTag() { + void analyzeTag() + { hasAD = false; u32 t = tag.REGS[0]; u32 i = 0; u32 j = std::min(nRegs, 8); - for(; i < j; i++) { + for (; i < j; i++) + { regs[i] = t & 0xf; hasAD |= (regs[i] == GIF_REG_A_D); t >>= 4; } t = tag.REGS[1]; j = nRegs; - for(; i < j; i++) { + for (; i < j; i++) + { regs[i] = t & 0xf; hasAD |= (regs[i] == GIF_REG_A_D); t >>= 4; @@ -125,78 +137,89 @@ struct Gif_Tag { } }; -struct GS_Packet { +struct GS_Packet +{ // PERF note: this struct is copied various time in hot path. Don't add // new field - u32 offset; // Path buffer offset for start of packet - u32 size; // Full size of GS-Packet - s32 cycles; // EE Cycles taken to process this GS packet - s32 readAmount; // Dummy read-amount data needed for proper buffer calculations - GS_Packet() { Reset(); } + u32 offset; // Path buffer offset for start of packet + u32 size; // Full size of GS-Packet + s32 cycles; // EE Cycles taken to process this GS packet + s32 readAmount; // Dummy read-amount data needed for proper buffer calculations + GS_Packet() { Reset(); } void Reset() { memzero(*this); } }; -struct GS_SIGNAL { - u32 data[2]; +struct GS_SIGNAL +{ + u32 data[2]; bool queued; void Reset() { memzero(*this); } }; -struct GS_FINISH { +struct GS_FINISH +{ bool gsFINISHFired; void Reset() { memzero(*this); } }; -static __fi void incTag(u32& offset, u32& size, u32 incAmount) { - size += incAmount; +static __fi void incTag(u32& offset, u32& size, u32 incAmount) +{ + size += incAmount; offset += incAmount; } -struct Gif_Path_MTVU { - u32 fakePackets; // Fake packets pending to be sent to MTGS +struct Gif_Path_MTVU +{ + u32 fakePackets; // Fake packets pending to be sent to MTGS GS_Packet fakePacket; // Set a size based on MTGS but keep a factor 2 to avoid too waste to much // memory overhead. Note the struct is instantied 3 times (for each gif // path) ringbuffer_base gsPackQueue; Gif_Path_MTVU() { Reset(); } - void Reset() { fakePackets = 0; + void Reset() + { + fakePackets = 0; gsPackQueue.reset(); fakePacket.Reset(); - fakePacket.size =~0u; // Used to indicate that its a fake packet + fakePacket.size = ~0u; // Used to indicate that its a fake packet } }; -struct Gif_Path { +struct Gif_Path +{ std::atomic readAmount; // Amount of data MTGS still needs to read - u8* buffer; // Path packet buffer - u32 buffSize; // Full size of buffer - 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 - GIF_PATH_STATE state; // Path State - Gif_Path_MTVU mtvu; // Must be last for saved states + u8* buffer; // Path packet buffer + u32 buffSize; // Full size of buffer + 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 + GIF_PATH_STATE state; // Path State + Gif_Path_MTVU mtvu; // Must be last for saved states - Gif_Path() { Reset(); } + Gif_Path() { Reset(); } ~Gif_Path() { _aligned_free(buffer); } - void Init(GIF_PATH _idx, u32 _buffSize, u32 _buffSafeZone) { - idx = _idx; - buffSize = _buffSize; + void Init(GIF_PATH _idx, u32 _buffSize, u32 _buffSafeZone) + { + idx = _idx; + buffSize = _buffSize; buffLimit = _buffSize - _buffSafeZone; - buffer = (u8*)_aligned_malloc(buffSize, 16); + buffer = (u8*)_aligned_malloc(buffSize, 16); Reset(); } - void Reset(bool softReset = false) { + void Reset(bool softReset = false) + { state = GIF_PATH_IDLE; - if (softReset) { + if (softReset) + { if (!isMTVU()) // MTVU Freaks out if you try to reset it, so let's just let it transfer { GUNIT_WARN("Gif Path %d - Soft Reset", idx + 1); @@ -212,82 +235,104 @@ struct Gif_Path { gsPack.Reset(); } - bool isMTVU() const { return !idx && THREAD_VU1; } - s32 getReadAmount() { return readAmount.load(std::memory_order_acquire) + gsPack.readAmount; } + bool isMTVU() const { return !idx && THREAD_VU1; } + s32 getReadAmount() { return readAmount.load(std::memory_order_acquire) + gsPack.readAmount; } bool hasDataRemaining() const { return curOffset < curSize; } - bool isDone() const { return isMTVU() ? !mtvu.fakePackets : (!hasDataRemaining() && (state == GIF_PATH_IDLE || state == GIF_PATH_WAIT)); } + bool isDone() const { return isMTVU() ? !mtvu.fakePackets : (!hasDataRemaining() && (state == GIF_PATH_IDLE || state == GIF_PATH_WAIT)); } // Waits on the MTGS to process gs packets - void mtgsReadWait() { - if (IsDevBuild) { - DevCon.WriteLn(Color_Red, "Gif Path[%d] - MTGS Wait! [r=0x%x]", idx+1, getReadAmount()); + void mtgsReadWait() + { + if (IsDevBuild) + { + DevCon.WriteLn(Color_Red, "Gif Path[%d] - MTGS Wait! [r=0x%x]", idx + 1, getReadAmount()); Gif_MTGS_Wait(isMTVU()); - DevCon.WriteLn(Color_Green, "Gif Path[%d] - MTGS Wait! [r=0x%x]", idx+1, getReadAmount()); + DevCon.WriteLn(Color_Green, "Gif Path[%d] - MTGS Wait! [r=0x%x]", idx + 1, getReadAmount()); return; } Gif_MTGS_Wait(isMTVU()); } // Moves packet data to start of buffer - void RealignPacket() { + void RealignPacket() + { GUNIT_LOG("Path Buffer: Realigning packet!"); - s32 offset = curOffset - gsPack.size; - s32 sizeToAdd = curSize - offset; + s32 offset = curOffset - gsPack.size; + s32 sizeToAdd = curSize - offset; s32 intersect = sizeToAdd - offset; - if (intersect < 0) intersect = 0; - for(;;) { - s32 frontFree = offset - getReadAmount(); - if (frontFree >= sizeToAdd - intersect) break; + if (intersect < 0) + intersect = 0; + for (;;) + { + s32 frontFree = offset - getReadAmount(); + if (frontFree >= sizeToAdd - intersect) + break; mtgsReadWait(); } - if (offset < (s32)buffLimit) { // Needed for correct readAmount values - if (isMTVU()) gsPack.readAmount += buffLimit - offset; - else Gif_AddBlankGSPacket(buffLimit - offset, idx); + if (offset < (s32)buffLimit) + { // Needed for correct readAmount values + if (isMTVU()) + gsPack.readAmount += buffLimit - offset; + else + Gif_AddBlankGSPacket(buffLimit - offset, idx); } //DevCon.WriteLn("Realign Packet [%d]", curSize - offset); - if (intersect) memmove(buffer, &buffer[offset], curSize - offset); - else memcpy(buffer, &buffer[offset], curSize - offset); - curSize -= offset; - curOffset = gsPack.size; + if (intersect) + memmove(buffer, &buffer[offset], curSize - offset); + else + memcpy(buffer, &buffer[offset], curSize - offset); + curSize -= offset; + curOffset = gsPack.size; gsPack.offset = 0; } - void CopyGSPacketData(u8* pMem, u32 size, bool aligned = false) { - if (curSize + size > buffSize) { // Move gsPack to front of buffer + void CopyGSPacketData(u8* pMem, u32 size, bool aligned = false) + { + if (curSize + size > buffSize) + { // Move gsPack to front of buffer GUNIT_LOG("CopyGSPacketData: Realigning packet!"); RealignPacket(); } - for(;;) { - s32 offset = curOffset - gsPack.size; - s32 readPos = offset - getReadAmount(); - if (readPos >= 0) break; // MTGS is reading in back of curOffset - if ((s32)buffLimit + readPos > (s32)curSize + (s32)size) break; // Enough free front space + for (;;) + { + s32 offset = curOffset - gsPack.size; + s32 readPos = offset - getReadAmount(); + if (readPos >= 0) + break; // MTGS is reading in back of curOffset + if ((s32)buffLimit + readPos > (s32)curSize + (s32)size) + break; // Enough free front space mtgsReadWait(); // Let MTGS run to free up buffer space } - pxAssertDev(curSize+size<=buffSize, "Gif Path Buffer Overflow!"); - memcpy (&buffer[curSize], pMem, size); - curSize += size; + pxAssertDev(curSize + size <= buffSize, "Gif Path Buffer Overflow!"); + memcpy(&buffer[curSize], pMem, size); + curSize += size; } // If completed a GS packet (with EOP) then set done to true // MTVU: This function only should be called called on EE thread - GS_Packet ExecuteGSPacket(bool &done) { - if (mtvu.fakePackets) { // For MTVU mode... + GS_Packet ExecuteGSPacket(bool& done) + { + if (mtvu.fakePackets) + { // For MTVU mode... mtvu.fakePackets--; done = true; return mtvu.fakePacket; } pxAssert(!isMTVU()); - for(;;) { - if (!gifTag.isValid) { // Need new Gif Tag + for (;;) + { + if (!gifTag.isValid) + { // Need new Gif Tag // We don't have enough data for a Gif Tag - if (curOffset + 16 > curSize) { + if (curOffset + 16 > curSize) + { //GUNIT_LOG("Path Buffer: Not enough data for gif tag! [%d]", curSize-curOffset); return gsPack; } // Move packet to start of buffer - if (curOffset > buffLimit) { + if (curOffset > buffLimit) + { RealignPacket(); } @@ -296,7 +341,8 @@ struct Gif_Path { state = (GIF_PATH_STATE)(gifTag.tag.FLG + 1); // We don't have enough data for a complete GS packet - if(!gifTag.hasAD && curOffset + 16 + gifTag.len > curSize) { + if (!gifTag.hasAD && curOffset + 16 + gifTag.len > curSize) + { gifTag.isValid = false; // So next time we test again return gsPack; } @@ -305,48 +351,56 @@ struct Gif_Path { gsPack.cycles += 2 + gifTag.cycles; // Tag + Len ee-cycles } - if (gifTag.hasAD) { // Only can be true if GIF_FLG_PACKED + if (gifTag.hasAD) + { // Only can be true if GIF_FLG_PACKED bool dblSIGNAL = false; - while(gifTag.nLoop && !dblSIGNAL) { - if (curOffset + 16 > curSize) return gsPack; // Exit Early - if (gifTag.curReg() == GIF_REG_A_D) { - if (!isMTVU()) dblSIGNAL = Gif_HandlerAD(&buffer[curOffset]); + while (gifTag.nLoop && !dblSIGNAL) + { + if (curOffset + 16 > curSize) + return gsPack; // Exit Early + if (gifTag.curReg() == GIF_REG_A_D) + { + if (!isMTVU()) + dblSIGNAL = Gif_HandlerAD(&buffer[curOffset]); } incTag(curOffset, gsPack.size, 16); // 1 QWC gifTag.packedStep(); } - if (dblSIGNAL && !(gifTag.tag.EOP && !gifTag.nLoop)) return gsPack; // Exit Early + if (dblSIGNAL && !(gifTag.tag.EOP && !gifTag.nLoop)) + return gsPack; // Exit Early } - else incTag(curOffset, gsPack.size, gifTag.len); // Data length + else + incTag(curOffset, gsPack.size, gifTag.len); // Data length // Reload gif tag next loop gifTag.isValid = false; - if (gifTag.tag.EOP) { + if (gifTag.tag.EOP) + { GS_Packet t = gsPack; done = true; 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) + + if ((gifRegs.stat.APATH - 1) == GIF_PATH_3) { state = GIF_PATH_WAIT; - if(curSize - curOffset > 0 && (gifRegs.stat.M3R || gifRegs.stat.M3P)) + 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; + else + state = GIF_PATH_IDLE; return t; // Complete GS packet } @@ -354,38 +408,51 @@ struct Gif_Path { } // MTVU: Gets called on VU XGkicks on MTVU thread - void ExecuteGSPacketMTVU() { + void ExecuteGSPacketMTVU() + { // Move packet to start of buffer - if (curOffset > buffLimit) { + if (curOffset > buffLimit) + { RealignPacket(); } - for(;;) { // needed to be processed by pcsx2... - if (curOffset + 16 > curSize) break; + for (;;) + { // needed to be processed by pcsx2... + if (curOffset + 16 > curSize) + break; gifTag.setTag(&buffer[curOffset], 1); - - if(!gifTag.hasAD && curOffset + 16 + gifTag.len > curSize) break; + + if (!gifTag.hasAD && curOffset + 16 + gifTag.len > curSize) + break; incTag(curOffset, gsPack.size, 16); // Tag Size - - if (gifTag.hasAD) { // Only can be true if GIF_FLG_PACKED - while(gifTag.nLoop) { - if (curOffset + 16 > curSize) break; // Exit Early - if (gifTag.curReg() == GIF_REG_A_D) { + + if (gifTag.hasAD) + { // Only can be true if GIF_FLG_PACKED + while (gifTag.nLoop) + { + if (curOffset + 16 > curSize) + break; // Exit Early + if (gifTag.curReg() == GIF_REG_A_D) + { pxAssert(!Gif_HandlerAD_MTVU(&buffer[curOffset])); } incTag(curOffset, gsPack.size, 16); // 1 QWC gifTag.packedStep(); } } - else incTag(curOffset, gsPack.size, gifTag.len); // Data length - if (curOffset >= curSize) break; - if (gifTag.tag.EOP) break; + else + incTag(curOffset, gsPack.size, gifTag.len); // Data length + if (curOffset >= curSize) + break; + if (gifTag.tag.EOP) + break; } pxAssert(curOffset == curSize); gifTag.isValid = false; } // MTVU: Gets called after VU1 execution on MTVU thread - void FinishGSPacketMTVU() { + void FinishGSPacketMTVU() + { // Performance note: fetch_add atomic operation might create some stall for atomic // operation in gsPack.push readAmount.fetch_add(gsPack.size + gsPack.readAmount, std::memory_order_acq_rel); @@ -397,9 +464,11 @@ struct Gif_Path { } // MTVU: Gets called by MTGS thread - GS_Packet GetGSPacketMTVU() { + GS_Packet GetGSPacketMTVU() + { // FIXME is the error path useful ? - if (!mtvu.gsPackQueue.empty()) { + if (!mtvu.gsPackQueue.empty()) + { return mtvu.gsPackQueue.front(); } @@ -409,32 +478,41 @@ struct Gif_Path { } // MTVU: Gets called by MTGS thread - void PopGSPacketMTVU() { + void PopGSPacketMTVU() + { mtvu.gsPackQueue.pop(); } // MTVU: Returns the amount of pending // GS Packets that MTGS hasn't yet processed - u32 GetPendingGSPackets() { + u32 GetPendingGSPackets() + { return mtvu.gsPackQueue.size(); } }; -struct Gif_Unit { - Gif_Path gifPath[3]; - GS_SIGNAL gsSIGNAL; // Stalling Signal - GS_FINISH gsFINISH; // Finish Signal +struct Gif_Unit +{ + Gif_Path gifPath[3]; + GS_SIGNAL gsSIGNAL; // Stalling Signal + GS_FINISH gsFINISH; // Finish Signal tGIF_STAT& stat; GIF_TRANSFER_TYPE lastTranType; // Last Transfer Type - Gif_Unit() : gsSIGNAL(), gsFINISH(), stat(gifRegs.stat), lastTranType(GIF_TRANS_INVALID) { - gifPath[0].Init(GIF_PATH_1, _1mb*9, _1mb + _1kb); - gifPath[1].Init(GIF_PATH_2, _1mb*9, _1mb + _1kb); - gifPath[2].Init(GIF_PATH_3, _1mb*9, _1mb + _1kb); + Gif_Unit() + : gsSIGNAL() + , gsFINISH() + , stat(gifRegs.stat) + , lastTranType(GIF_TRANS_INVALID) + { + gifPath[0].Init(GIF_PATH_1, _1mb * 9, _1mb + _1kb); + gifPath[1].Init(GIF_PATH_2, _1mb * 9, _1mb + _1kb); + gifPath[2].Init(GIF_PATH_3, _1mb * 9, _1mb + _1kb); } // Enable softReset when resetting during game emulation - void Reset(bool softReset = false) { + void Reset(bool softReset = false) + { GUNIT_WARN(Color_Red, "Gif Unit Reset!!! [soft=%d]", softReset); ResetRegs(); gsSIGNAL.Reset(); @@ -442,89 +520,135 @@ struct Gif_Unit { gifPath[0].Reset(softReset); gifPath[1].Reset(softReset); gifPath[2].Reset(softReset); - if(!softReset) { + if (!softReset) + { lastTranType = GIF_TRANS_INVALID; } //If the VIF has paused waiting for PATH3, recheck it after the reset has occurred (Eragon) - if (vif1Regs.stat.VGW) { + if (vif1Regs.stat.VGW) + { if (!(cpuRegs.interrupt & (1 << DMAC_VIF1))) CPU_INT(DMAC_VIF1, 1); } } // Resets Gif HW Regs - void ResetRegs() { + void ResetRegs() + { gifRegs.stat.reset(); gifRegs.ctrl.reset(); gifRegs.mode.reset(); } // Adds a finished GS Packet to the MTGS ring buffer - __fi void AddCompletedGSPacket(GS_Packet& gsPack, GIF_PATH path) { - if (gsPack.size==~0u) Gif_AddGSPacketMTVU (gsPack, path); - else Gif_AddCompletedGSPacket(gsPack, path); - if (PRINT_GIF_PACKET) Gif_ParsePacket(gsPack, path); + __fi void AddCompletedGSPacket(GS_Packet& gsPack, GIF_PATH path) + { + if (gsPack.size == ~0u) + Gif_AddGSPacketMTVU(gsPack, path); + else + Gif_AddCompletedGSPacket(gsPack, path); + if (PRINT_GIF_PACKET) + Gif_ParsePacket(gsPack, path); } // Returns GS Packet Size in bytes - u32 GetGSPacketSize(GIF_PATH pathIdx, u8* pMem, u32 offset = 0, u32 size = ~0u) { + u32 GetGSPacketSize(GIF_PATH pathIdx, u8* pMem, u32 offset = 0, u32 size = ~0u) + { u32 memMask = pathIdx ? ~0u : 0x3fffu; u32 curSize = 0; - for(;;) { + for (;;) + { Gif_Tag gifTag(&pMem[offset & memMask]); incTag(offset, curSize, 16 + gifTag.len); // Tag + Data length - if (pathIdx == GIF_PATH_1 && curSize >= 0x4000) { + if (pathIdx == GIF_PATH_1 && curSize >= 0x4000) + { DevCon.Warning("Gif Unit - GS packet size exceeded VU memory size!"); return 0; // Bios does this... (Fixed if you delay vu1's xgkick by 103 vu cycles) } - if (curSize >= size) return size; - if (gifTag.tag.EOP) return curSize; + if (curSize >= size) + return size; + if (gifTag.tag.EOP) + return curSize; } } // Specify the transfer type you are initiating // The return value is the amount of data (in bytes) that was processed // If transfer cannot take place at this moment the return value is 0 - u32 TransferGSPacketData(GIF_TRANSFER_TYPE tranType, u8* pMem, u32 size, bool aligned=false) { + u32 TransferGSPacketData(GIF_TRANSFER_TYPE tranType, u8* pMem, u32 size, bool aligned = false) + { - if (THREAD_VU1) { + if (THREAD_VU1) + { Gif_Path& path1 = gifPath[GIF_PATH_1]; - if (tranType == GIF_TRANS_XGKICK) { // This is on the MTVU thread + if (tranType == GIF_TRANS_XGKICK) + { // This is on the MTVU thread path1.CopyGSPacketData(pMem, size, aligned); path1.ExecuteGSPacketMTVU(); return size; } - if (tranType == GIF_TRANS_MTVU) { // This is on the EE thread + if (tranType == GIF_TRANS_MTVU) + { // This is on the EE thread path1.mtvu.fakePackets++; - if (CanDoGif()) Execute(false, true); + if (CanDoGif()) + Execute(false, true); return 0; } } - GUNIT_LOG("%s - [path=%d][size=%d]", Gif_TransferStr[(tranType>>8)&0xf], (tranType&3)+1, size); - if (size == 0) { GUNIT_WARN("Gif Unit - Size == 0"); return 0; } - if(!CanDoGif()) { GUNIT_WARN("Gif Unit - Signal or PSE Set or Dir = GS to EE"); } + GUNIT_LOG("%s - [path=%d][size=%d]", Gif_TransferStr[(tranType >> 8) & 0xf], (tranType & 3) + 1, size); + if (size == 0) + { + GUNIT_WARN("Gif Unit - Size == 0"); + return 0; + } + if (!CanDoGif()) + { + GUNIT_WARN("Gif Unit - Signal or PSE Set or Dir = GS to EE"); + } //pxAssertDev((stat.APATH==0) || checkPaths(1,1,1), "Gif Unit - APATH wasn't cleared?"); lastTranType = tranType; - if (tranType == GIF_TRANS_FIFO) { - if(!CanDoPath3()) DevCon.Warning("Gif Unit - Path 3 FIFO transfer while !CanDoPath3()"); + if (tranType == GIF_TRANS_FIFO) + { + if (!CanDoPath3()) + DevCon.Warning("Gif Unit - Path 3 FIFO transfer while !CanDoPath3()"); } - if (tranType == GIF_TRANS_DMA) { - if(!CanDoPath3()) { if (!Path3Masked()) stat.P3Q = 1; return 0; } // DMA Stall - //if (stat.P2Q) DevCon.WriteLn("P2Q while path 3"); + if (tranType == GIF_TRANS_DMA) + { + if (!CanDoPath3()) + { + if (!Path3Masked()) + stat.P3Q = 1; + return 0; + } // DMA Stall + //if (stat.P2Q) DevCon.WriteLn("P2Q while path 3"); } - if (tranType == GIF_TRANS_XGKICK) { - if(!CanDoPath1()) { stat.P1Q = 1; } // We always buffer path1 packets + if (tranType == GIF_TRANS_XGKICK) + { + if (!CanDoPath1()) + { + stat.P1Q = 1; + } // We always buffer path1 packets } - if (tranType == GIF_TRANS_DIRECT) { - if(!CanDoPath2()) { stat.P2Q = 1; return 0; } // Direct Stall + if (tranType == GIF_TRANS_DIRECT) + { + if (!CanDoPath2()) + { + stat.P2Q = 1; + return 0; + } // Direct Stall } - if (tranType == GIF_TRANS_DIRECTHL) { - if(!CanDoPath2HL()) { stat.P2Q = 1; return 0; } // DirectHL Stall + if (tranType == GIF_TRANS_DIRECTHL) + { + if (!CanDoPath2HL()) + { + stat.P2Q = 1; + return 0; + } // DirectHL Stall } - gifPath[tranType&3].CopyGSPacketData(pMem, size, aligned); + gifPath[tranType & 3].CopyGSPacketData(pMem, size, aligned); size -= Execute(tranType == GIF_TRANS_DMA, false); return size; } @@ -532,15 +656,17 @@ struct Gif_Unit { // Checks path activity for the given paths // Returns an int with a bit enabled if the corresponding // path is not finished (needs more data/processing for an EOP) - __fi int checkPaths(bool p1, bool p2, bool p3, bool checkQ=false) { + __fi int checkPaths(bool p1, bool p2, bool p3, bool checkQ = false) + { int ret = 0; ret |= (p1 && !gifPath[GIF_PATH_1].isDone()) << 0; ret |= (p2 && !gifPath[GIF_PATH_2].isDone()) << 1; ret |= (p3 && !gifPath[GIF_PATH_3].isDone()) << 2; - return ret | (checkQ ? checkQueued(p1,p2,p3) : 0); + return ret | (checkQ ? checkQueued(p1, p2, p3) : 0); } - __fi int checkQueued(bool p1, bool p2, bool p3) { + __fi int checkQueued(bool p1, bool p2, bool p3) + { int ret = 0; ret |= (p1 && stat.P1Q) << 0; ret |= (p2 && stat.P2Q) << 1; @@ -551,45 +677,59 @@ struct Gif_Unit { // Send processed GS Primitive(s) to the MTGS thread // Note: Only does so if current path fully completed all // of its given gs primitives (but didn't upload them yet) - void FlushToMTGS() { - if (!stat.APATH) return; - Gif_Path& path = gifPath[stat.APATH-1]; - if (path.gsPack.size && !path.gifTag.isValid) { - AddCompletedGSPacket(path.gsPack, (GIF_PATH)(stat.APATH-1)); + void FlushToMTGS() + { + if (!stat.APATH) + return; + Gif_Path& path = gifPath[stat.APATH - 1]; + if (path.gsPack.size && !path.gifTag.isValid) + { + AddCompletedGSPacket(path.gsPack, (GIF_PATH)(stat.APATH - 1)); path.gsPack.offset = path.curOffset; - path.gsPack.size = 0; + path.gsPack.size = 0; } } // Processes gif packets and performs path arbitration // on EOPs or on Path 3 Images when IMT is set. - int Execute(bool isPath3, bool isResume) { - if (!CanDoGif()) { DevCon.Error("Gif Unit - Signal or PSE Set or Dir = GS to EE"); return 0; } + int Execute(bool isPath3, bool isResume) + { + if (!CanDoGif()) + { + DevCon.Error("Gif Unit - Signal or PSE Set or Dir = GS to EE"); + return 0; + } bool didPath3 = false; - int curPath = stat.APATH > 0 ? stat.APATH-1 : 0; //Init to zero if no path is already set. + int curPath = stat.APATH > 0 ? stat.APATH - 1 : 0; //Init to zero if no path is already set. gifPath[2].dmaRewind = 0; stat.OPH = 1; - - for(;;) { - if (stat.APATH) { // Some Transfer is happening - Gif_Path& path = gifPath[stat.APATH-1]; + + for (;;) + { + if (stat.APATH) + { // Some Transfer is happening + Gif_Path& path = gifPath[stat.APATH - 1]; bool done = false; GS_Packet gsPack = path.ExecuteGSPacket(done); - if(!done) { - if (stat.APATH == 3 && CanDoP3Slice() && !gsSIGNAL.queued) { - if(!didPath3 && /*!Path3Masked() &&*/ checkPaths(1,1,0)) { // Path3 slicing + if (!done) + { + if (stat.APATH == 3 && CanDoP3Slice() && !gsSIGNAL.queued) + { + if (!didPath3 && /*!Path3Masked() &&*/ checkPaths(1, 1, 0)) + { // Path3 slicing didPath3 = true; stat.APATH = 0; - stat.IP3 = 1; + stat.IP3 = 1; GUNIT_LOG(Color_Magenta, "Gif Unit - Path 3 slicing arbitration"); - if (gsPack.size > 16) { // Packet had other tags which we already processed + if (gsPack.size > 16) + { // Packet had other tags which we already processed u32 subOffset = path.gifTag.isValid ? 16 : 0; // if isValid, image-primitive not finished - gsPack.size -= subOffset; // Remove the image-tag (should be last thing read) - AddCompletedGSPacket(gsPack, GIF_PATH_3); // Consider current packet complete - path.gsPack.Reset(); // Reset gs packet info - path.curOffset -= subOffset; // Start the next GS packet at the image-tag - path.gsPack.offset = path.curOffset; // Set to image-tag - path.gifTag.isValid = false; // Reload tag next ExecuteGSPacket() + gsPack.size -= subOffset; // Remove the image-tag (should be last thing read) + AddCompletedGSPacket(gsPack, GIF_PATH_3); // Consider current packet complete + path.gsPack.Reset(); // Reset gs packet info + path.curOffset -= subOffset; // Start the next GS packet at the image-tag + path.gsPack.offset = path.curOffset; // Set to image-tag + path.gifTag.isValid = false; // Reload tag next ExecuteGSPacket() pxAssert((s32)path.curOffset >= 0); pxAssert(path.state == GIF_PATH_IMAGE); GUNIT_LOG(Color_Magenta, "Gif Unit - Sending path 3 sliced gs packet!"); @@ -602,29 +742,34 @@ struct Gif_Unit { break; // Not finished with GS packet } //DevCon.WriteLn("Adding GS Packet for path %d", stat.APATH); - if (gifPath[curPath].state == GIF_PATH_WAIT || gifPath[curPath].state == GIF_PATH_IDLE) { + if (gifPath[curPath].state == GIF_PATH_WAIT || gifPath[curPath].state == GIF_PATH_IDLE) + { AddCompletedGSPacket(gsPack, (GIF_PATH)(stat.APATH - 1)); } - } - if (!gsSIGNAL.queued && !gifPath[0].isDone()) { + if (!gsSIGNAL.queued && !gifPath[0].isDone()) + { stat.APATH = 1; stat.P1Q = 0; curPath = 0; } - else if (!gsSIGNAL.queued && !gifPath[1].isDone()) { + else if (!gsSIGNAL.queued && !gifPath[1].isDone()) + { stat.APATH = 2; stat.P2Q = 0; curPath = 1; } - else if (!gsSIGNAL.queued && !gifPath[2].isDone() && !Path3Masked()) { + else if (!gsSIGNAL.queued && !gifPath[2].isDone() && !Path3Masked()) + { stat.APATH = 3; stat.P3Q = 0; stat.IP3 = 0; curPath = 2; } - else { - if(isResume || curPath == 0) { + else + { + if (isResume || curPath == 0) + { stat.APATH = 0; stat.OPH = 0; } @@ -635,7 +780,7 @@ struct Gif_Unit { //Some loaders/Refresh Rate selectors and things dont issue "End of Packet" commands //So we look and see if the end of the last tag is all there, if so, stick it in the buffer for the GS :) //(Invisible Screens on Terminator 3 and Growlanser 2/3) - if(gifPath[curPath].curOffset == gifPath[curPath].curSize) + if (gifPath[curPath].curOffset == gifPath[curPath].curSize) { FlushToMTGS(); } @@ -643,53 +788,62 @@ struct Gif_Unit { Gif_FinishIRQ(); //Path3 can rewind the DMA, so we send back the amount we go back! - if(isPath3) + if (isPath3) return gifPath[2].dmaRewind; else return 0; } // XGkick - bool CanDoPath1() const { + bool CanDoPath1() const + { return (stat.APATH == 0 || stat.APATH == 1 || (stat.APATH == 3 && CanDoP3Slice())) && CanDoGif(); } // Direct - bool CanDoPath2() const { + bool CanDoPath2() const + { return (stat.APATH == 0 || stat.APATH == 2 || (stat.APATH == 3 && CanDoP3Slice())) && CanDoGif(); } // DirectHL - bool CanDoPath2HL() const { + bool CanDoPath2HL() const + { return (stat.APATH == 0 || stat.APATH == 2) && CanDoGif(); } // Gif DMA - bool CanDoPath3() const { - return((stat.APATH == 0 && !Path3Masked()) || stat.APATH == 3) && CanDoGif(); + bool CanDoPath3() const + { + return ((stat.APATH == 0 && !Path3Masked()) || stat.APATH == 3) && CanDoGif(); } - bool CanDoP3Slice()const { return stat.IMT == 1 && gifPath[GIF_PATH_3].state == GIF_PATH_IMAGE; } - bool CanDoGif() const { return stat.PSE == 0 && stat.DIR == 0 && gsSIGNAL.queued == 0; } + bool CanDoP3Slice() const { return stat.IMT == 1 && gifPath[GIF_PATH_3].state == GIF_PATH_IMAGE; } + bool CanDoGif() const { return stat.PSE == 0 && stat.DIR == 0 && gsSIGNAL.queued == 0; } //Mask stops the next packet which hasnt started from transferring bool Path3Masked() const { return ((stat.M3R || stat.M3P) && (gifPath[GIF_PATH_3].state == GIF_PATH_IDLE || gifPath[GIF_PATH_3].state == GIF_PATH_WAIT)); } - void PrintInfo(bool printP1=1, bool printP2=1, bool printP3=1) { - u32 a = checkPaths(1,1,1), b = checkQueued(1,1,1); + void PrintInfo(bool printP1 = 1, bool printP2 = 1, bool printP3 = 1) + { + u32 a = checkPaths(1, 1, 1), b = checkQueued(1, 1, 1); (void)a; // Don't warn about unused variable (void)b; GUNIT_LOG("Gif Unit - LastTransfer = %s, Paths = [%d,%d,%d], Queued = [%d,%d,%d]", - Gif_TransferStr[(lastTranType>>8)&0xf], - !!(a&1),!!(a&2),!!(a&4),!!(b&1),!!(b&2),!!(b&4)); + Gif_TransferStr[(lastTranType >> 8) & 0xf], + !!(a & 1), !!(a & 2), !!(a & 4), !!(b & 1), !!(b & 2), !!(b & 4)); GUNIT_LOG("Gif Unit - [APATH = %d][Signal = %d][PSE = %d][DIR = %d]", - stat.APATH, gsSIGNAL.queued, stat.PSE, stat.DIR); + stat.APATH, gsSIGNAL.queued, stat.PSE, stat.DIR); GUNIT_LOG("Gif Unit - [CanDoGif = %d][CanDoPath3 = %d][CanDoP3Slice = %d]", - CanDoGif(), CanDoPath3(), CanDoP3Slice()); - if (printP1) PrintPathInfo(GIF_PATH_1); - if (printP2) PrintPathInfo(GIF_PATH_2); - if (printP3) PrintPathInfo(GIF_PATH_3); + CanDoGif(), CanDoPath3(), CanDoP3Slice()); + if (printP1) + PrintPathInfo(GIF_PATH_1); + if (printP2) + PrintPathInfo(GIF_PATH_2); + if (printP3) + PrintPathInfo(GIF_PATH_3); } - void PrintPathInfo(GIF_PATH path) { + void PrintPathInfo(GIF_PATH path) + { GUNIT_LOG("Gif Path %d - [hasData = %d][state = %d]", path, - gifPath[path].hasDataRemaining(), gifPath[path].state); + gifPath[path].hasDataRemaining(), gifPath[path].state); } }; diff --git a/pcsx2/MTVU.cpp b/pcsx2/MTVU.cpp index e86be012e5..c51ef2100b 100644 --- a/pcsx2/MTVU.cpp +++ b/pcsx2/MTVU.cpp @@ -22,12 +22,13 @@ __aligned16 VU_Thread vu1Thread(CpuVU1, VU1); #define MTVU_ALWAYS_KICK 0 -#define MTVU_SYNC_MODE 0 +#define MTVU_SYNC_MODE 0 // Rounds up a size in bytes for size in u32's static __fi u32 size_u32(u32 x) { return (x + 3) >> 2; } -enum MTVU_EVENT { +enum MTVU_EVENT +{ MTVU_VU_EXECUTE, // Execute VU program MTVU_VU_WRITE_MICRO, // Write to VU micro-mem MTVU_VU_WRITE_DATA, // Write to VU data-mem @@ -43,8 +44,10 @@ static void MTVU_Unpack(void* data, VIFregisters& vifRegs) { u16 wl = vifRegs.cycle.wl > 0 ? vifRegs.cycle.wl : 256; bool isFill = vifRegs.cycle.cl < wl; - if (newVifDynaRec) dVifUnpack<1>((u8*)data, isFill); - else _nVifUnpack(1, (u8*)data, vifRegs.mode, isFill); + if (newVifDynaRec) + dVifUnpack<1>((u8*)data, isFill); + else + _nVifUnpack(1, (u8*)data, vifRegs.mode, isFill); } // Called on Saving/Loading states... @@ -52,8 +55,10 @@ void SaveStateBase::mtvuFreeze() { FreezeTag("MTVU"); pxAssert(vu1Thread.IsDone()); - if (!IsSaving()) vu1Thread.Reset(); - for (size_t i = 0; i < 4; ++i) { + if (!IsSaving()) + vu1Thread.Reset(); + for (size_t i = 0; i < 4; ++i) + { unsigned int v = vu1Thread.vuCycles[i].load(); Freeze(v); } @@ -76,8 +81,9 @@ void SaveStateBase::mtvuFreeze() Freeze(vu1Thread.vuCycleIdx); } -VU_Thread::VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs) : - vuCPU(_vuCPU), vuRegs(_vuRegs) +VU_Thread::VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs) + : vuCPU(_vuCPU) + , vuRegs(_vuRegs) { m_name = L"MTVU"; Reset(); @@ -85,7 +91,8 @@ VU_Thread::VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs) : VU_Thread::~VU_Thread() { - try { + try + { pxThread::Cancel(); } DESTRUCTOR_CATCHALL @@ -95,12 +102,12 @@ void VU_Thread::Reset() { ScopedLock lock(mtxBusy); - vuCycleIdx = 0; - isBusy = false; + vuCycleIdx = 0; + isBusy = false; m_ato_write_pos = 0; - m_write_pos = 0; - m_ato_read_pos = 0; - m_read_pos = 0; + m_write_pos = 0; + m_ato_read_pos = 0; + m_read_pos = 0; memzero(vif); memzero(vifRegs); for (size_t i = 0; i < 4; ++i) @@ -109,42 +116,51 @@ void VU_Thread::Reset() void VU_Thread::ExecuteTaskInThread() { - PCSX2_PAGEFAULT_PROTECT { + PCSX2_PAGEFAULT_PROTECT + { ExecuteRingBuffer(); - } PCSX2_PAGEFAULT_EXCEPT; + } + PCSX2_PAGEFAULT_EXCEPT; } void VU_Thread::ExecuteRingBuffer() { - for(;;) { + for (;;) + { semaEvent.WaitWithoutYield(); ScopedLockBool lock(mtxBusy, isBusy); - while (m_ato_read_pos.load(std::memory_order_relaxed) != GetWritePos()) { + while (m_ato_read_pos.load(std::memory_order_relaxed) != GetWritePos()) + { u32 tag = Read(); - switch (tag) { - case MTVU_VU_EXECUTE: { + switch (tag) + { + case MTVU_VU_EXECUTE: + { vuRegs.cycle = 0; - s32 addr = Read(); - vifRegs.top = Read(); + s32 addr = Read(); + vifRegs.top = Read(); vifRegs.itop = Read(); - if (addr != -1) vuRegs.VI[REG_TPC].UL = addr; + if (addr != -1) + vuRegs.VI[REG_TPC].UL = addr; vuCPU->SetStartPC(vuRegs.VI[REG_TPC].UL << 3); vuCPU->Execute(vu1RunCycles); gifUnit.gifPath[GIF_PATH_1].FinishGSPacketMTVU(); semaXGkick.Post(); // Tell MTGS a path1 packet is complete vuCycles[vuCycleIdx].store(vuRegs.cycle, std::memory_order_release); - vuCycleIdx = (vuCycleIdx + 1) & 3; + vuCycleIdx = (vuCycleIdx + 1) & 3; break; } - case MTVU_VU_WRITE_MICRO: { + case MTVU_VU_WRITE_MICRO: + { u32 vu_micro_addr = Read(); u32 size = Read(); vuCPU->Clear(vu_micro_addr, size); Read(&vuRegs.Micro[vu_micro_addr], size); break; } - case MTVU_VU_WRITE_DATA: { + case MTVU_VU_WRITE_DATA: + { u32 vu_data_addr = Read(); u32 size = Read(); Read(&vuRegs.Mem[vu_data_addr], size); @@ -156,7 +172,8 @@ void VU_Thread::ExecuteRingBuffer() case MTVU_VIF_WRITE_ROW: Read(&vif.MaskRow, sizeof(vif.MaskRow)); break; - case MTVU_VIF_UNPACK: { + case MTVU_VIF_UNPACK: + { u32 vif_copy_size = (uptr)&vif.StructEnd - (uptr)&vif.tag; Read(&vif.tag, vif_copy_size); ReadRegs(&vifRegs); @@ -168,7 +185,7 @@ void VU_Thread::ExecuteRingBuffer() case MTVU_NULL_PACKET: m_read_pos = 0; break; - jNO_DEFAULT; + jNO_DEFAULT; } CommitReadPos(); @@ -180,16 +197,19 @@ void VU_Thread::ExecuteRingBuffer() // Should only be called by ReserveSpace() __ri void VU_Thread::WaitOnSize(s32 size) { - for(;;) { - s32 readPos = GetReadPos(); - if (readPos <= m_write_pos) break; // MTVU is reading in back of write_pos + for (;;) + { + s32 readPos = GetReadPos(); + if (readPos <= m_write_pos) + break; // MTVU is reading in back of write_pos // FIXME greg: there is a bug somewhere in the queue pointer // management. It creates a deadlock/corruption in SotC intro (before // the first menu). I added a 4KB safety net which seem to avoid to // trigger the bug. // Note: a wait lock instead of a yield also helps to avoid the bug. - if (readPos > m_write_pos + size + _4kb) break; // Enough free front space - { // Let MTVU run to free up buffer space + if (readPos > m_write_pos + size + _4kb) + break; // Enough free front space + { // Let MTVU run to free up buffer space KickStart(); // Locking might trigger a full flush of the ring buffer. Yield // will be more aggressive, and only flush the minimal size. @@ -205,10 +225,11 @@ __ri void VU_Thread::WaitOnSize(s32 size) void VU_Thread::ReserveSpace(s32 size) { pxAssert(m_write_pos < buffer_size); - pxAssert(size < buffer_size); + pxAssert(size < buffer_size); pxAssert(size > 0); - if (m_write_pos + size > (buffer_size - 1)) { + if (m_write_pos + size > (buffer_size - 1)) + { WaitOnSize(1); // Size of MTVU_NULL_PACKET Write(MTVU_NULL_PACKET); // Reset local write pointer/position @@ -242,8 +263,10 @@ __fi void VU_Thread::CommitWritePos() { m_ato_write_pos.store(m_write_pos, std::memory_order_release); - if (MTVU_ALWAYS_KICK) KickStart(); - if (MTVU_SYNC_MODE) WaitVU(); + if (MTVU_ALWAYS_KICK) + KickStart(); + if (MTVU_SYNC_MODE) + WaitVU(); } __fi void VU_Thread::CommitReadPos() @@ -307,7 +330,8 @@ u32 VU_Thread::Get_vuCycles() return (vuCycles[0].load(std::memory_order_acquire) + vuCycles[1].load(std::memory_order_acquire) + vuCycles[2].load(std::memory_order_acquire) + - vuCycles[3].load(std::memory_order_acquire)) >> 2; + vuCycles[3].load(std::memory_order_acquire)) >> + 2; } void VU_Thread::Get_GSChanges() @@ -369,8 +393,8 @@ void VU_Thread::Get_GSChanges() void VU_Thread::KickStart(bool forceKick) { - if ((forceKick && !semaEvent.Count()) - || (!isBusy.load(std::memory_order_acquire) && GetReadPos() != m_ato_write_pos.load(std::memory_order_relaxed))) semaEvent.Post(); + if ((forceKick && !semaEvent.Count()) || (!isBusy.load(std::memory_order_acquire) && GetReadPos() != m_ato_write_pos.load(std::memory_order_relaxed))) + semaEvent.Post(); } bool VU_Thread::IsDone() @@ -381,8 +405,10 @@ bool VU_Thread::IsDone() void VU_Thread::WaitVU() { MTVU_LOG("MTVU - WaitVU!"); - for(;;) { - if (IsDone()) break; + for (;;) + { + if (IsDone()) + break; //DevCon.WriteLn("WaitVU()"); pxAssert(THREAD_VU1); KickStart();