mirror of https://github.com/PCSX2/pcsx2.git
MTVU: Cleaned up GS SIGNAL/LABEL/FINISH communication
This commit is contained in:
parent
527ba52dec
commit
3c2f7983a5
|
@ -105,6 +105,7 @@ bool Gif_HandlerAD(u8* pMem)
|
|||
|
||||
bool Gif_HandlerAD_MTVU(u8* pMem)
|
||||
{
|
||||
// Note: Atomic communication is with MTVU.cpp Get_GSChanges
|
||||
u32 reg = pMem[8];
|
||||
u32* data = (u32*)pMem;
|
||||
|
||||
|
@ -125,29 +126,26 @@ bool Gif_HandlerAD_MTVU(u8* pMem)
|
|||
}
|
||||
else if (reg == 0x60)
|
||||
{ // SIGNAL
|
||||
|
||||
if (CSRreg.SIGNAL)
|
||||
{ // Time to ignore all subsequent drawing operations.
|
||||
GUNIT_WARN("GIF Handler - SIGNAL");
|
||||
if (vu1Thread.gsInterrupts.load(std::memory_order_acquire) & VU_Thread::InterruptFlagSignal)
|
||||
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.gsSignalCnt++;
|
||||
}
|
||||
vu1Thread.gsSignal.store(((u64)data[1] << 32) | data[0], std::memory_order_relaxed);
|
||||
vu1Thread.gsInterrupts.fetch_or(VU_Thread::InterruptFlagSignal, std::memory_order_release);
|
||||
}
|
||||
else if (reg == 0x61)
|
||||
{ // FINISH
|
||||
GUNIT_WARN("GIF Handler - FINISH");
|
||||
vu1Thread.gsFinish = 1;
|
||||
u32 old = vu1Thread.gsInterrupts.fetch_or(VU_Thread::InterruptFlagFinish, std::memory_order_relaxed);
|
||||
if (old & VU_Thread::InterruptFlagFinish)
|
||||
Console.Error("GIF Handler MTVU - Double FINISH Not Handled");
|
||||
}
|
||||
else if (reg == 0x62)
|
||||
{ // LABEL
|
||||
GUNIT_WARN("GIF Handler - LABEL");
|
||||
vu1Thread.gsLabel = ((u64)data[1] << 32) | data[0];
|
||||
vu1Thread.gsLabelCnt++;
|
||||
if (vu1Thread.gsLabel.load(std::memory_order_acquire) & VU_Thread::InterruptFlagLabel)
|
||||
Console.Error("GIF Handler MTVU - Double LABEL Not Handled");
|
||||
vu1Thread.gsLabel.store(((u64)data[1] << 32) | data[0], std::memory_order_relaxed);
|
||||
vu1Thread.gsInterrupts.fetch_or(VU_Thread::InterruptFlagLabel, std::memory_order_release);
|
||||
}
|
||||
else if (reg >= 0x63 && reg != 0x7f)
|
||||
{
|
||||
|
|
|
@ -62,29 +62,18 @@ void SaveStateBase::mtvuFreeze()
|
|||
unsigned int v = vu1Thread.vuCycles[i].load();
|
||||
Freeze(v);
|
||||
}
|
||||
u32 gsFinishInt;
|
||||
u64 gsSignals;
|
||||
u32 gsSignalsCnt;
|
||||
|
||||
gsFinishInt = vu1Thread.gsFinish.load();
|
||||
Freeze(gsFinishInt);
|
||||
vu1Thread.gsFinish.store(gsFinishInt);
|
||||
gsSignals = vu1Thread.gsSignal.load();
|
||||
Freeze(gsSignals);
|
||||
vu1Thread.gsSignal.store(gsSignals);
|
||||
gsSignalsCnt = vu1Thread.gsSignalCnt.load();
|
||||
Freeze(gsSignalsCnt);
|
||||
vu1Thread.gsSignalCnt.store(gsSignalsCnt);
|
||||
gsSignals = vu1Thread.gsLabel.load();
|
||||
Freeze(gsSignals);
|
||||
vu1Thread.gsLabel.store(gsSignals);
|
||||
gsSignalsCnt = vu1Thread.gsLabelCnt.load();
|
||||
Freeze(gsSignalsCnt);
|
||||
vu1Thread.gsLabelCnt.store(gsSignalsCnt);
|
||||
u32 gsInterrupts = vu1Thread.gsInterrupts.load();
|
||||
Freeze(gsInterrupts);
|
||||
vu1Thread.gsInterrupts.store(gsInterrupts);
|
||||
u64 gsSignal = vu1Thread.gsSignal.load();
|
||||
Freeze(gsSignal);
|
||||
vu1Thread.gsSignal.store(gsSignal);
|
||||
u64 gsLabel = vu1Thread.gsLabel.load();
|
||||
Freeze(gsLabel);
|
||||
vu1Thread.gsLabel.store(gsLabel);
|
||||
|
||||
Freeze(vu1Thread.vuCycleIdx);
|
||||
Freeze(vu1Thread.lastLabel);
|
||||
Freeze(vu1Thread.lastSignal);
|
||||
}
|
||||
|
||||
VU_Thread::VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs)
|
||||
|
@ -109,8 +98,6 @@ void VU_Thread::Reset()
|
|||
ScopedLock lock(mtxBusy);
|
||||
|
||||
vuCycleIdx = 0;
|
||||
lastLabel = 0;
|
||||
lastSignal = 0;
|
||||
isBusy = false;
|
||||
m_ato_write_pos = 0;
|
||||
m_write_pos = 0;
|
||||
|
@ -120,8 +107,7 @@ void VU_Thread::Reset()
|
|||
memzero(vifRegs);
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
vu1Thread.vuCycles[i] = 0;
|
||||
vu1Thread.gsSignal = 0;
|
||||
vu1Thread.gsLabel = 0;
|
||||
vu1Thread.gsInterrupts = 0;
|
||||
}
|
||||
|
||||
void VU_Thread::ExecuteTaskInThread()
|
||||
|
@ -346,17 +332,32 @@ u32 VU_Thread::Get_vuCycles()
|
|||
|
||||
void VU_Thread::Get_GSChanges()
|
||||
{
|
||||
u32 finishInt = gsFinish.load(std::memory_order_acquire);
|
||||
u64 signalCnt = gsSignalCnt.load(std::memory_order_acquire);
|
||||
u64 labelCnt = gsLabelCnt.load(std::memory_order_acquire);
|
||||
// Note: Atomic communication is with Gif_Unit.cpp Gif_HandlerAD_MTVU
|
||||
u32 interrupts = gsInterrupts.load(std::memory_order_relaxed);
|
||||
if (!interrupts)
|
||||
return;
|
||||
|
||||
// We don't support stacking multiple of the same type of interrupt, so the faster we read the required data and clear the flag the less likely we'll run into issues with that
|
||||
u64 signal, label;
|
||||
if (interrupts & (InterruptFlagSignal | InterruptFlagLabel))
|
||||
{
|
||||
// label and signal access other variables so the load must have acquire semantics
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
signal = gsSignal.load(std::memory_order_relaxed);
|
||||
label = gsLabel.load(std::memory_order_relaxed);
|
||||
// Also need release semantics on the clear
|
||||
gsInterrupts.fetch_and(~interrupts, std::memory_order_release);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsInterrupts.fetch_and(~interrupts, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
if (signalCnt != lastSignal)
|
||||
if (interrupts & InterruptFlagSignal)
|
||||
{
|
||||
GUNIT_WARN("SIGNAL firing");
|
||||
const u64 signal = gsSignal.load(std::memory_order_acquire);
|
||||
const u32 signalMsk = (u32)(signal >> 32);
|
||||
const u32 signalData = (u32)signal;
|
||||
lastSignal = signalCnt;
|
||||
if (CSRreg.SIGNAL)
|
||||
{
|
||||
GUNIT_WARN("Queue SIGNAL");
|
||||
|
@ -374,7 +375,7 @@ void VU_Thread::Get_GSChanges()
|
|||
gsIrq();
|
||||
}
|
||||
}
|
||||
if (finishInt)
|
||||
if (interrupts & InterruptFlagFinish)
|
||||
{
|
||||
GUNIT_WARN("Finish firing");
|
||||
CSRreg.FINISH = true;
|
||||
|
@ -382,16 +383,12 @@ void VU_Thread::Get_GSChanges()
|
|||
|
||||
if (!gifRegs.stat.APATH)
|
||||
Gif_FinishIRQ();
|
||||
|
||||
gsFinish.store(0);
|
||||
}
|
||||
if (labelCnt != lastLabel)
|
||||
if (interrupts & InterruptFlagLabel)
|
||||
{
|
||||
GUNIT_WARN("LABEL firing");
|
||||
const u64 label = gsLabel.load(std::memory_order_acquire);
|
||||
const u32 labelMsk = (u32)(label >> 32);
|
||||
const u32 labelData = (u32)label;
|
||||
lastLabel = labelCnt;
|
||||
GSSIGLBLID.LBLID = (GSSIGLBLID.LBLID & ~labelMsk) | (labelData & labelMsk);
|
||||
}
|
||||
}
|
||||
|
|
23
pcsx2/MTVU.h
23
pcsx2/MTVU.h
|
@ -44,16 +44,19 @@ class VU_Thread : public pxThread {
|
|||
public:
|
||||
__aligned16 vifStruct vif;
|
||||
__aligned16 VIFregisters vifRegs;
|
||||
__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) u32 lastSignal;
|
||||
__aligned(4) u32 lastLabel;
|
||||
__aligned(4) std::atomic<unsigned int> gsFinish; // Used for GS Signal, Finish etc
|
||||
__aligned(4) std::atomic<u32> gsLabelCnt; // Used for GS Label command
|
||||
__aligned(4) std::atomic<u32> gsSignalCnt; // Used for GS Signal command
|
||||
__aligned(4) std::atomic<u64> gsLabel; // Used for GS Label command
|
||||
__aligned(4) std::atomic<u64> gsSignal; // Used for GS Signal command
|
||||
Semaphore semaXGkick;
|
||||
std::atomic<unsigned int> vuCycles[4]; // Used for VU cycle stealing hack
|
||||
u32 vuCycleIdx; // Used for VU cycle stealing hack
|
||||
|
||||
enum InterruptFlag {
|
||||
InterruptFlagFinish = 1 << 0,
|
||||
InterruptFlagSignal = 1 << 1,
|
||||
InterruptFlagLabel = 1 << 2,
|
||||
};
|
||||
|
||||
std::atomic<u32> gsInterrupts; // Used for GS Signal, Finish etc
|
||||
std::atomic<u64> gsLabel; // Used for GS Label command
|
||||
std::atomic<u64> gsSignal; // Used for GS Signal command
|
||||
|
||||
VU_Thread(BaseVUmicroCPU*& _vuCPU, VURegs& _vuRegs);
|
||||
virtual ~VU_Thread();
|
||||
|
|
|
@ -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 = (0x9A14 << 16) | 0x0000;
|
||||
static const u32 g_SaveVersion = (0x9A15 << 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. :)
|
||||
|
|
Loading…
Reference in New Issue