MTVU: Improve compatibility with games that do GS SIGNAL/LABEL/FINISH

This commit is contained in:
refractionpcsx2 2020-12-22 10:47:19 +00:00
parent 4ab7d78574
commit 3f4bb44310
5 changed files with 125 additions and 25 deletions

View File

@ -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];

View File

@ -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

View File

@ -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)

View File

@ -47,6 +47,10 @@ public:
__aligned(4) Semaphore semaXGkick;
__aligned(4) std::atomic<unsigned int> vuCycles[4]; // Used for VU cycle stealing hack
__aligned(4) u32 vuCycleIdx; // Used for VU cycle stealing hack
__aligned(4) std::atomic<unsigned int> gsInterrupts; // Used for GS Signal, Finish etc
__aligned(4) std::atomic<unsigned int> gsToClear; // Used for GS Signal, Finish etc
__aligned(4) std::atomic<u64> gsLabel; // Used for GS Label command
__aligned(4) std::atomic<u64> 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);

View File

@ -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