diff --git a/pcsx2/Gif_Unit.cpp b/pcsx2/Gif_Unit.cpp index f6bfc4afb6..e9568648a1 100644 --- a/pcsx2/Gif_Unit.cpp +++ b/pcsx2/Gif_Unit.cpp @@ -81,6 +81,40 @@ bool Gif_HandlerAD(u8* pMem) { return false; } +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; + } + else { + GUNIT_WARN("GIF Handler - SIGNAL"); + vu1Thread.gsSignal = ((u64)data[1] << 32) | data[0]; + vu1Thread.gsInterrupts |= 2; + + } + } + else if (reg == 0x61) { // FINISH + GUNIT_WARN("GIF Handler - FINISH"); + vu1Thread.gsInterrupts |= 1; + } + 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) { + 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]; diff --git a/pcsx2/Gif_Unit.h b/pcsx2/Gif_Unit.h index 8c7000f43c..947b315c71 100644 --- a/pcsx2/Gif_Unit.h +++ b/pcsx2/Gif_Unit.h @@ -27,6 +27,7 @@ struct GS_Packet; extern void Gif_MTGS_Wait(bool isMTVU); extern void Gif_FinishIRQ(); 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); @@ -358,37 +359,29 @@ struct Gif_Path { if (curOffset > buffLimit) { RealignPacket(); } - if (IsDevBuild) { // We check the packet to see if it actually - for(;;) { // needed to be processed by pcsx2... - if (curOffset + 16 > curSize) break; - gifTag.setTag(&buffer[curOffset], 1); + 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; - incTag(curOffset, gsPack.size, 16); // Tag Size + 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) { - pxAssert(!Gif_HandlerAD_Debug(&buffer[curOffset])); - } - incTag(curOffset, gsPack.size, 16); // 1 QWC - gifTag.packedStep(); + 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; } - pxAssert(curOffset == curSize); - gifTag.isValid = false; - } - else { - // We assume every packet is a full GS Packet - // And we don't process anything on pcsx2 side - gsPack.size += curSize - curOffset; - curOffset = curSize; + 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 diff --git a/pcsx2/MTVU.cpp b/pcsx2/MTVU.cpp index bebd5f3a96..eeb1aafd6b 100644 --- a/pcsx2/MTVU.cpp +++ b/pcsx2/MTVU.cpp @@ -294,6 +294,63 @@ u32 VU_Thread::Get_vuCycles() vuCycles[3].load(std::memory_order_acquire)) >> 2; } +void VU_Thread::Get_GSChanges() +{ + u32 interrupts = gsInterrupts.load(std::memory_order_acquire); + + // If there's no interrupts, return early, just saves on waiting for some atomics and whatnot + if (!interrupts) + return; + + u32 clearedInterrupts = gsToClear.load(std::memory_order_acquire); + + if (interrupts == clearedInterrupts) + return; + + interrupts &= ~clearedInterrupts; + bool triggerInt = false; + u32 finalInterrupts = 0; + + if (interrupts & 2) + { + const u64 signal = gsSignal.load(std::memory_order_acquire); + const u32 signalMsk = (u32)(signal >> 32); + const u32 signalData = (u32)signal; + CSRreg.SIGNAL = true; + GSSIGLBLID.SIGID = (GSSIGLBLID.SIGID & ~signalMsk) | (signalData & signalMsk); + + if (!GSIMR.SIGMSK) + triggerInt = true; + + finalInterrupts |= 2; + } + if (interrupts & 1) + { + CSRreg.FINISH = true; + + if (!gifRegs.stat.APATH) + Gif_FinishIRQ(); + + finalInterrupts |= 1; + } + + if (interrupts & 4) + { + const u64 label = gsLabel.load(std::memory_order_acquire); + const u32 labelMsk = (u32)(label >> 32); + const u32 labelData = (u32)label; + GSSIGLBLID.LBLID = (GSSIGLBLID.LBLID & ~labelMsk) | (labelData & labelMsk); + + finalInterrupts |= 4; + } + + clearedInterrupts |= finalInterrupts; + gsToClear.store(clearedInterrupts); + + if (triggerInt) + gsIrq(); +} + void VU_Thread::KickStart(bool forceKick) { if ((forceKick && !semaEvent.Count()) @@ -321,7 +378,10 @@ void VU_Thread::WaitVU() void VU_Thread::ExecuteVU(u32 vu_addr, u32 vif_top, u32 vif_itop) { MTVU_LOG("MTVU - ExecuteVU!"); + Get_GSChanges(); // Clear any pending interrupts ReserveSpace(4); + gsToClear.store(0); + gsInterrupts.store(0); Write(MTVU_VU_EXECUTE); Write(vu_addr); Write(vif_top); @@ -332,6 +392,7 @@ void VU_Thread::ExecuteVU(u32 vu_addr, u32 vif_top, u32 vif_itop) u32 cycles = std::min(Get_vuCycles(), 3000u); cpuRegs.cycle += cycles * EmuConfig.Speedhacks.EECycleSkip; VU0.cycle += cycles * EmuConfig.Speedhacks.EECycleSkip; + Get_GSChanges(); } void VU_Thread::VifUnpack(vifStruct& _vif, VIFregisters& _vifRegs, u8* data, u32 size) diff --git a/pcsx2/MTVU.h b/pcsx2/MTVU.h index 4f4cecd68f..70c68f0613 100644 --- a/pcsx2/MTVU.h +++ b/pcsx2/MTVU.h @@ -47,6 +47,10 @@ public: __aligned(4) Semaphore semaXGkick; __aligned(4) std::atomic vuCycles[4]; // Used for VU cycle stealing hack __aligned(4) u32 vuCycleIdx; // Used for VU cycle stealing hack + __aligned(4) std::atomic gsInterrupts; // Used for GS Signal, Finish etc + __aligned(4) std::atomic gsToClear; // Used for GS Signal, Finish etc + __aligned(4) std::atomic gsLabel; // Used for GS Label command + __aligned(4) std::atomic gsSignal; // Used for GS Signal command VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs); virtual ~VU_Thread(); @@ -62,6 +66,8 @@ public: // Waits till MTVU is done processing void WaitVU(); + void Get_GSChanges(); + void ExecuteVU(u32 vu_addr, u32 vif_top, u32 vif_itop); void VifUnpack(vifStruct& _vif, VIFregisters& _vifRegs, u8* data, u32 size); diff --git a/pcsx2/VUmicro.cpp b/pcsx2/VUmicro.cpp index 2827530e7c..021a61f058 100644 --- a/pcsx2/VUmicro.cpp +++ b/pcsx2/VUmicro.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "Common.h" #include "VUmicro.h" +#include "MTVU.h" // Executes a Block based on EE delta time void BaseVUmicroCPU::ExecuteBlock(bool startUp) { @@ -23,6 +24,11 @@ void BaseVUmicroCPU::ExecuteBlock(bool startUp) { const int test = m_Idx ? 0x100 : 1; const int s = EmuConfig.Gamefixes.VU0KickstartHack ? 16 : 0; // Kick Start Cycles (Jak needs at least 4 due to writing values after they're read + if (m_Idx && THREAD_VU1) + { + vu1Thread.Get_GSChanges(); + } + if (!(stat & test)) return; if (startUp && s) { // Start Executing a microprogram