mirror of https://github.com/PCSX2/pcsx2.git
MTVU: Improve compatibility with games that do GS SIGNAL/LABEL/FINISH
This commit is contained in:
parent
4ab7d78574
commit
3f4bb44310
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue