MTGS: Remove old DXGI fullscreen overrides code, run clang.

This commit is contained in:
lightningterror 2020-10-29 15:41:48 +01:00
parent 05f20fa664
commit fca9f7a458
1 changed files with 221 additions and 200 deletions

View File

@ -31,9 +31,12 @@
using namespace Threading;
#if 0 //PCSX2_DEBUG
# define MTGS_LOG Console.WriteLn
#define MTGS_LOG Console.WriteLn
#else
# define MTGS_LOG(...) do {} while (0)
#define MTGS_LOG(...) \
do \
{ \
} while (0)
#endif
// =====================================================================================================
@ -49,10 +52,10 @@ extern bool renderswitch;
std::list<uint> ringposStack;
#endif
SysMtgsThread::SysMtgsThread() :
SysThreadBase()
SysMtgsThread::SysMtgsThread()
: SysThreadBase()
#ifdef RINGBUF_DEBUG_STACK
, m_lock_Stack()
, m_lock_Stack()
#endif
{
m_name = L"MTGS";
@ -62,27 +65,28 @@ SysMtgsThread::SysMtgsThread() :
void SysMtgsThread::OnStart()
{
m_PluginOpened = false;
m_PluginOpened = false;
m_ReadPos = 0;
m_WritePos = 0;
m_RingBufferIsBusy = false;
m_packet_size = 0;
m_packet_writepos = 0;
m_ReadPos = 0;
m_WritePos = 0;
m_RingBufferIsBusy = false;
m_packet_size = 0;
m_packet_writepos = 0;
m_QueuedFrameCount = 0;
m_QueuedFrameCount = 0;
m_VsyncSignalListener = false;
m_SignalRingEnable = false;
m_SignalRingPosition = 0;
m_SignalRingEnable = false;
m_SignalRingPosition = 0;
m_CopyDataTally = 0;
m_CopyDataTally = 0;
_parent::OnStart();
}
SysMtgsThread::~SysMtgsThread()
{
try {
try
{
_parent::Cancel();
}
DESTRUCTOR_CATCHALL
@ -95,29 +99,29 @@ void SysMtgsThread::OnResumeReady()
void SysMtgsThread::ResetGS()
{
pxAssertDev( !IsOpen() || (m_ReadPos == m_WritePos), "Must close or terminate the GS thread prior to gsReset." );
pxAssertDev(!IsOpen() || (m_ReadPos == m_WritePos), "Must close or terminate the GS thread prior to gsReset.");
// MTGS Reset process:
// * clear the ringbuffer.
// * Signal a reset.
// * clear the path and byRegs structs (used by GIFtagDummy)
m_ReadPos = m_WritePos.load();
m_QueuedFrameCount = 0;
m_ReadPos = m_WritePos.load();
m_QueuedFrameCount = 0;
m_VsyncSignalListener = 0;
MTGS_LOG( "MTGS: Sending Reset..." );
SendSimplePacket( GS_RINGTYPE_RESET, 0, 0, 0 );
SendSimplePacket( GS_RINGTYPE_FRAMESKIP, 0, 0, 0 );
MTGS_LOG("MTGS: Sending Reset...");
SendSimplePacket(GS_RINGTYPE_RESET, 0, 0, 0);
SendSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0);
SetEvent();
}
struct RingCmdPacket_Vsync
{
u8 regset1[0x0f0];
u32 csr;
u32 imr;
GSRegSIGBLID siglblid;
u8 regset1[0x0f0];
u32 csr;
u32 imr;
GSRegSIGBLID siglblid;
};
void SysMtgsThread::PostVsyncStart()
@ -129,7 +133,7 @@ void SysMtgsThread::PostVsyncStart()
uint packsize = sizeof(RingCmdPacket_Vsync) / 16;
PrepDataPacket(GS_RINGTYPE_VSYNC, packsize);
MemCopy_WrappedDest( (u128*)PS2MEM_GS, RingBuffer.m_Ring, m_packet_writepos, RingBufferSize, 0xf );
MemCopy_WrappedDest((u128*)PS2MEM_GS, RingBuffer.m_Ring, m_packet_writepos, RingBufferSize, 0xf);
u32* remainder = (u32*)GetDataPacketPtr();
remainder[0] = GSCSRr;
@ -140,7 +144,8 @@ void SysMtgsThread::PostVsyncStart()
SendDataPacket();
// Vsyncs should always start the GS thread, regardless of how little has actually be queued.
if (m_CopyDataTally != 0) SetEvent();
if (m_CopyDataTally != 0)
SetEvent();
// If the MTGS is allowed to queue a lot of frames in advance, it creates input lag.
// Use the Queued FrameCount to stall the EE if another vsync (or two) are already queued
@ -153,7 +158,8 @@ void SysMtgsThread::PostVsyncStart()
// If those are needed back, it's better to increase the VsyncQueueSize via PCSX_vm.ini.
// (The Xenosaga engine is known to run into this, due to it throwing bulks of data in one frame followed by 2 empty frames.)
if ((m_QueuedFrameCount.fetch_add(1) < EmuConfig.GS.VsyncQueueSize) /*|| (!EmuConfig.GS.VsyncEnable && !EmuConfig.GS.FrameLimitEnable)*/) return;
if ((m_QueuedFrameCount.fetch_add(1) < EmuConfig.GS.VsyncQueueSize) /*|| (!EmuConfig.GS.VsyncEnable && !EmuConfig.GS.FrameLimitEnable)*/)
return;
m_VsyncSignalListener.store(true, std::memory_order_release);
//Console.WriteLn( Color_Blue, "(EEcore Sleep) Vsync\t\tringpos=0x%06x, writepos=0x%06x", m_ReadPos.load(), m_WritePos.load() );
@ -169,11 +175,13 @@ void SysMtgsThread::PostVsyncStart()
union PacketTagType
{
struct {
struct
{
u32 command;
u32 data[3];
};
struct {
struct
{
u32 _command;
u32 _data[1];
uptr pointer;
@ -189,84 +197,71 @@ static void dummyIrqCallback()
void SysMtgsThread::OpenPlugin()
{
if( m_PluginOpened ) return;
if (m_PluginOpened)
return;
memcpy( RingBuffer.Regs, PS2MEM_GS, sizeof(PS2MEM_GS) );
GSsetBaseMem( RingBuffer.Regs );
GSirqCallback( dummyIrqCallback );
memcpy(RingBuffer.Regs, PS2MEM_GS, sizeof(PS2MEM_GS));
GSsetBaseMem(RingBuffer.Regs);
GSirqCallback(dummyIrqCallback);
int result;
if( GSopen2 != NULL )
result = GSopen2( (void*)pDsp, 1 | (renderswitch ? 4 : 0) );
if (GSopen2 != NULL)
result = GSopen2((void*)pDsp, 1 | (renderswitch ? 4 : 0));
else
result = GSopen( (void*)pDsp, "PCSX2", renderswitch ? 2 : 1 );
result = GSopen((void*)pDsp, "PCSX2", renderswitch ? 2 : 1);
GSsetVsync(EmuConfig.GS.GetVsync());
if( result != 0 )
if (result != 0)
{
DevCon.WriteLn( "GSopen Failed: return code: 0x%x", result );
throw Exception::PluginOpenError( PluginId_GS );
DevCon.WriteLn("GSopen Failed: return code: 0x%x", result);
throw Exception::PluginOpenError(PluginId_GS);
}
// This is the preferred place to implement DXGI fullscreen overrides, using LoadLibrary.
// But I hate COM, I don't know to make this work, and I don't have DX10, so I give up
// and enjoy my working DX9 alt-enter instead. Someone else can fix this mess. --air
// Also: Prolly needs some DX10 header includes? Which ones? Too many, I gave up.
#if 0 // defined(__WXMSW__) && defined(_MSC_VER)
wxDynamicLibrary dynlib( L"dxgi.dll" );
SomeFuncTypeIDunno isThisEvenTheRightFunctionNameIDunno = dynlib.GetSymbol("CreateDXGIFactory");
if( isThisEvenTheRightFunctionNameIDunno )
{
// Is this how LoadLibrary for COM works? I dunno. I dont care.
IDXGIFactory* pFactory;
hr = isThisEvenTheRightFunctionNameIDunno(__uuidof(IDXGIFactory), (void**)(&pFactory) );
pFactory->MakeWindowAssociation((HWND)&pDsp, DXGI_MWA_NO_WINDOW_CHANGES);
pFactory->Release();
}
#endif
m_PluginOpened = true;
m_sem_OpenDone.Post();
GSsetGameCRC( ElfCRC, 0 );
GSsetGameCRC(ElfCRC, 0);
}
class RingBufferLock {
ScopedLock m_lock1;
ScopedLock m_lock2;
class RingBufferLock
{
ScopedLock m_lock1;
ScopedLock m_lock2;
SysMtgsThread& m_mtgs;
public:
public:
RingBufferLock(SysMtgsThread& mtgs)
: m_lock1(mtgs.m_mtx_RingBufferBusy),
m_lock2(mtgs.m_mtx_RingBufferBusy2),
m_mtgs(mtgs) {
: m_lock1(mtgs.m_mtx_RingBufferBusy)
, m_lock2(mtgs.m_mtx_RingBufferBusy2)
, m_mtgs(mtgs)
{
m_mtgs.m_RingBufferIsBusy.store(true, std::memory_order_relaxed);
}
virtual ~RingBufferLock() {
virtual ~RingBufferLock()
{
m_mtgs.m_RingBufferIsBusy.store(false, std::memory_order_relaxed);
}
void Acquire() {
void Acquire()
{
m_lock1.Acquire();
m_lock2.Acquire();
m_mtgs.m_RingBufferIsBusy.store(true, std::memory_order_relaxed);
}
void Release() {
void Release()
{
m_mtgs.m_RingBufferIsBusy.store(false, std::memory_order_relaxed);
m_lock2.Release();
m_lock1.Release();
}
void PartialAcquire() {
void PartialAcquire()
{
m_lock2.Acquire();
}
void PartialRelease() {
void PartialRelease()
{
m_lock2.Release();
}
};
@ -280,9 +275,10 @@ void SysMtgsThread::ExecuteTaskInThread()
PacketTagType prevCmd;
#endif
RingBufferLock busy (*this);
RingBufferLock busy(*this);
while(true) {
while (true)
{
busy.Release();
// Performance note: Both of these perform cancellation tests, but pthread_testcancel
@ -295,11 +291,11 @@ void SysMtgsThread::ExecuteTaskInThread()
// note: m_ReadPos is intentionally not volatile, because it should only
// ever be modified by this thread.
while( m_ReadPos.load(std::memory_order_relaxed) != m_WritePos.load(std::memory_order_acquire))
while (m_ReadPos.load(std::memory_order_relaxed) != m_WritePos.load(std::memory_order_acquire))
{
const unsigned int local_ReadPos = m_ReadPos.load(std::memory_order_relaxed);
pxAssert( local_ReadPos < RingBufferSize );
pxAssert(local_ReadPos < RingBufferSize);
const PacketTagType& tag = (PacketTagType&)RingBuffer[local_ReadPos];
u32 ringposinc = 1;
@ -309,38 +305,38 @@ void SysMtgsThread::ExecuteTaskInThread()
m_lock_Stack.Lock();
uptr stackpos = ringposStack.back();
if( stackpos != local_ReadPos )
if (stackpos != local_ReadPos)
{
Console.Error( "MTGS Ringbuffer Critical Failure ---> %x to %x (prevCmd: %x)\n", stackpos, local_ReadPos, prevCmd.command );
Console.Error("MTGS Ringbuffer Critical Failure ---> %x to %x (prevCmd: %x)\n", stackpos, local_ReadPos, prevCmd.command);
}
pxAssert( stackpos == local_ReadPos );
pxAssert(stackpos == local_ReadPos);
prevCmd = tag;
ringposStack.pop_back();
m_lock_Stack.Release();
#endif
switch( tag.command )
switch (tag.command)
{
#if COPY_GS_PACKET_TO_MTGS == 1
case GS_RINGTYPE_P1:
{
uint datapos = (local_ReadPos+1) & RingBufferMask;
uint datapos = (local_ReadPos + 1) & RingBufferMask;
const int qsize = tag.data[0];
const u128* data = &RingBuffer[datapos];
MTGS_LOG( "(MTGS Packet Read) ringtype=P1, qwc=%u", qsize );
MTGS_LOG("(MTGS Packet Read) ringtype=P1, qwc=%u", qsize);
uint endpos = datapos + qsize;
if( endpos >= RingBufferSize )
if (endpos >= RingBufferSize)
{
uint firstcopylen = RingBufferSize - datapos;
GSgifTransfer( (u32*)data, firstcopylen );
GSgifTransfer((u32*)data, firstcopylen);
datapos = endpos & RingBufferMask;
GSgifTransfer( (u32*)RingBuffer.m_Ring, datapos );
GSgifTransfer((u32*)RingBuffer.m_Ring, datapos);
}
else
{
GSgifTransfer( (u32*)data, qsize );
GSgifTransfer((u32*)data, qsize);
}
ringposinc += qsize;
@ -349,23 +345,23 @@ void SysMtgsThread::ExecuteTaskInThread()
case GS_RINGTYPE_P2:
{
uint datapos = (local_ReadPos+1) & RingBufferMask;
uint datapos = (local_ReadPos + 1) & RingBufferMask;
const int qsize = tag.data[0];
const u128* data = &RingBuffer[datapos];
MTGS_LOG( "(MTGS Packet Read) ringtype=P2, qwc=%u", qsize );
MTGS_LOG("(MTGS Packet Read) ringtype=P2, qwc=%u", qsize);
uint endpos = datapos + qsize;
if( endpos >= RingBufferSize )
if (endpos >= RingBufferSize)
{
uint firstcopylen = RingBufferSize - datapos;
GSgifTransfer2( (u32*)data, firstcopylen );
GSgifTransfer2((u32*)data, firstcopylen);
datapos = endpos & RingBufferMask;
GSgifTransfer2( (u32*)RingBuffer.m_Ring, datapos );
GSgifTransfer2((u32*)RingBuffer.m_Ring, datapos);
}
else
{
GSgifTransfer2( (u32*)data, qsize );
GSgifTransfer2((u32*)data, qsize);
}
ringposinc += qsize;
@ -374,48 +370,52 @@ void SysMtgsThread::ExecuteTaskInThread()
case GS_RINGTYPE_P3:
{
uint datapos = (local_ReadPos+1) & RingBufferMask;
uint datapos = (local_ReadPos + 1) & RingBufferMask;
const int qsize = tag.data[0];
const u128* data = &RingBuffer[datapos];
MTGS_LOG( "(MTGS Packet Read) ringtype=P3, qwc=%u", qsize );
MTGS_LOG("(MTGS Packet Read) ringtype=P3, qwc=%u", qsize);
uint endpos = datapos + qsize;
if( endpos >= RingBufferSize )
if (endpos >= RingBufferSize)
{
uint firstcopylen = RingBufferSize - datapos;
GSgifTransfer3( (u32*)data, firstcopylen );
GSgifTransfer3((u32*)data, firstcopylen);
datapos = endpos & RingBufferMask;
GSgifTransfer3( (u32*)RingBuffer.m_Ring, datapos );
GSgifTransfer3((u32*)RingBuffer.m_Ring, datapos);
}
else
{
GSgifTransfer3( (u32*)data, qsize );
GSgifTransfer3((u32*)data, qsize);
}
ringposinc += qsize;
}
break;
#endif
case GS_RINGTYPE_GSPACKET: {
Gif_Path& path = gifUnit.gifPath[tag.data[2]];
u32 offset = tag.data[0];
u32 size = tag.data[1];
if (offset != ~0u) GSgifTransfer((u32*)&path.buffer[offset], size/16);
case GS_RINGTYPE_GSPACKET:
{
Gif_Path& path = gifUnit.gifPath[tag.data[2]];
u32 offset = tag.data[0];
u32 size = tag.data[1];
if (offset != ~0u)
GSgifTransfer((u32*)&path.buffer[offset], size / 16);
path.readAmount.fetch_sub(size, std::memory_order_acq_rel);
break;
}
case GS_RINGTYPE_MTVU_GSPACKET: {
case GS_RINGTYPE_MTVU_GSPACKET:
{
MTVU_LOG("MTGS - Waiting on semaXGkick!");
vu1Thread.KickStart(true);
busy.PartialRelease();
// Wait for MTVU to complete vu1 program
vu1Thread.semaXGkick.WaitWithoutYield();
busy.PartialAcquire();
Gif_Path& path = gifUnit.gifPath[GIF_PATH_1];
Gif_Path& path = gifUnit.gifPath[GIF_PATH_1];
GS_Packet gsPack = path.GetGSPacketMTVU(); // Get vu1 program's xgkick packet(s)
if (gsPack.size) GSgifTransfer((u32*)&path.buffer[gsPack.offset], gsPack.size/16);
if (gsPack.size)
GSgifTransfer((u32*)&path.buffer[gsPack.offset], gsPack.size / 16);
path.readAmount.fetch_sub(gsPack.size + gsPack.readAmount, std::memory_order_acq_rel);
path.PopGSPacketMTVU(); // Should be done last, for proper Gif_MTGS_Wait()
break;
@ -423,26 +423,26 @@ void SysMtgsThread::ExecuteTaskInThread()
default:
{
switch( tag.command )
switch (tag.command)
{
case GS_RINGTYPE_VSYNC:
{
const int qsize = tag.data[0];
ringposinc += qsize;
MTGS_LOG( "(MTGS Packet Read) ringtype=Vsync, field=%u, skip=%s", !!(((u32&)RingBuffer.Regs[0x1000]) & 0x2000) ? 0 : 1, tag.data[1] ? "true" : "false" );
MTGS_LOG("(MTGS Packet Read) ringtype=Vsync, field=%u, skip=%s", !!(((u32&)RingBuffer.Regs[0x1000]) & 0x2000) ? 0 : 1, tag.data[1] ? "true" : "false");
// Mail in the important GS registers.
// This seemingly obtuse system is needed in order to handle cases where the vsync data wraps
// around the edge of the ringbuffer. If not for that I'd just use a struct. >_<
uint datapos = (local_ReadPos+1) & RingBufferMask;
MemCopy_WrappedSrc( RingBuffer.m_Ring, datapos, RingBufferSize, (u128*)RingBuffer.Regs, 0xf );
uint datapos = (local_ReadPos + 1) & RingBufferMask;
MemCopy_WrappedSrc(RingBuffer.m_Ring, datapos, RingBufferSize, (u128*)RingBuffer.Regs, 0xf);
u32* remainder = (u32*)&RingBuffer[datapos];
((u32&)RingBuffer.Regs[0x1000]) = remainder[0];
((u32&)RingBuffer.Regs[0x1010]) = remainder[1];
((GSRegSIGBLID&)RingBuffer.Regs[0x1080]) = (GSRegSIGBLID&)remainder[2];
((u32&)RingBuffer.Regs[0x1000]) = remainder[0];
((u32&)RingBuffer.Regs[0x1010]) = remainder[1];
((GSRegSIGBLID&)RingBuffer.Regs[0x1080]) = (GSRegSIGBLID&)remainder[2];
// CSR & 0x2000; is the pageflip id.
GSvsync(((u32&)RingBuffer.Regs[0x1000]) & 0x2000);
@ -450,7 +450,7 @@ void SysMtgsThread::ExecuteTaskInThread()
// if we're not using GSOpen2, then the GS window is on this thread (MTGS thread),
// so we need to call PADupdate from here.
if( (GSopen2 == NULL) && (PADupdate != NULL) )
if ((GSopen2 == NULL) && (PADupdate != NULL))
PADupdate(0);
m_QueuedFrameCount.fetch_sub(1);
@ -464,60 +464,61 @@ void SysMtgsThread::ExecuteTaskInThread()
break;
case GS_RINGTYPE_FRAMESKIP:
MTGS_LOG( "(MTGS Packet Read) ringtype=Frameskip" );
MTGS_LOG("(MTGS Packet Read) ringtype=Frameskip");
_gs_ResetFrameskip();
break;
break;
case GS_RINGTYPE_FREEZE:
{
MTGS_FreezeData* data = (MTGS_FreezeData*)tag.pointer;
int mode = tag.data[0];
data->retval = GetCorePlugins().DoFreeze( PluginId_GS, mode, data->fdata );
data->retval = GetCorePlugins().DoFreeze(PluginId_GS, mode, data->fdata);
}
break;
case GS_RINGTYPE_RESET:
MTGS_LOG( "(MTGS Packet Read) ringtype=Reset" );
if( GSreset != NULL ) GSreset();
break;
MTGS_LOG("(MTGS Packet Read) ringtype=Reset");
if (GSreset != NULL)
GSreset();
break;
case GS_RINGTYPE_SOFTRESET:
{
int mask = tag.data[0];
MTGS_LOG( "(MTGS Packet Read) ringtype=SoftReset" );
GSgifSoftReset( mask );
MTGS_LOG("(MTGS Packet Read) ringtype=SoftReset");
GSgifSoftReset(mask);
}
break;
case GS_RINGTYPE_MODECHANGE:
// [TODO] some frameskip sync logic might be needed here!
break;
break;
case GS_RINGTYPE_CRC:
GSsetGameCRC( tag.data[0], 0 );
break;
GSsetGameCRC(tag.data[0], 0);
break;
case GS_RINGTYPE_INIT_READ_FIFO1:
MTGS_LOG( "(MTGS Packet Read) ringtype=Fifo1" );
MTGS_LOG("(MTGS Packet Read) ringtype=Fifo1");
if (GSinitReadFIFO)
GSinitReadFIFO( (u64*)tag.pointer);
break;
GSinitReadFIFO((u64*)tag.pointer);
break;
case GS_RINGTYPE_INIT_READ_FIFO2:
MTGS_LOG( "(MTGS Packet Read) ringtype=Fifo2, size=%d", tag.data[0] );
MTGS_LOG("(MTGS Packet Read) ringtype=Fifo2, size=%d", tag.data[0]);
if (GSinitReadFIFO2)
GSinitReadFIFO2( (u64*)tag.pointer, tag.data[0]);
break;
GSinitReadFIFO2((u64*)tag.pointer, tag.data[0]);
break;
#ifdef PCSX2_DEVBUILD
default:
Console.Error("GSThreadProc, bad packet (%x) at m_ReadPos: %x, m_WritePos: %x", tag.command, local_ReadPos, m_WritePos.load());
pxFail( "Bad packet encountered in the MTGS Ringbuffer." );
pxFail("Bad packet encountered in the MTGS Ringbuffer.");
m_ReadPos.store(m_WritePos.load(std::memory_order_acquire), std::memory_order_release);
continue;
continue;
#else
// Optimized performance in non-Dev builds.
jNO_DEFAULT;
// Optimized performance in non-Dev builds.
jNO_DEFAULT;
#endif
}
}
@ -525,17 +526,17 @@ void SysMtgsThread::ExecuteTaskInThread()
uint newringpos = (m_ReadPos.load(std::memory_order_relaxed) + ringposinc) & RingBufferMask;
if( EmuConfig.GS.SynchronousMTGS )
if (EmuConfig.GS.SynchronousMTGS)
{
pxAssert( m_WritePos == newringpos );
pxAssert(m_WritePos == newringpos);
}
m_ReadPos.store(newringpos, std::memory_order_release);
if(m_SignalRingEnable.load(std::memory_order_acquire))
if (m_SignalRingEnable.load(std::memory_order_acquire))
{
// The EEcore has requested a signal after some amount of processed data.
if( m_SignalRingPosition.fetch_sub( ringposinc ) <= 0 )
if (m_SignalRingPosition.fetch_sub(ringposinc) <= 0)
{
// Make sure to post the signal after the m_ReadPos has been updated...
m_SignalRingEnable.store(false, std::memory_order_release);
@ -551,7 +552,7 @@ void SysMtgsThread::ExecuteTaskInThread()
// won't sleep the eternity, even if SignalRingPosition didn't reach 0 for some reason.
// Important: Need to unlock the MTGS busy signal PRIOR, so that EEcore SetEvent() calls
// parallel to this handler aren't accidentally blocked.
if( m_SignalRingEnable.exchange(false) )
if (m_SignalRingEnable.exchange(false))
{
//Console.Warning( "(MTGS Thread) Dangling RingSignal on empty buffer! signalpos=0x%06x", m_SignalRingPosition.exchange(0) ) );
m_SignalRingPosition.store(0, std::memory_order_release);
@ -567,9 +568,10 @@ void SysMtgsThread::ExecuteTaskInThread()
void SysMtgsThread::ClosePlugin()
{
if( !m_PluginOpened ) return;
if (!m_PluginOpened)
return;
m_PluginOpened = false;
GetCorePlugins().Close( PluginId_GS );
GetCorePlugins().Close(PluginId_GS);
}
void SysMtgsThread::OnSuspendInThread()
@ -578,12 +580,12 @@ void SysMtgsThread::OnSuspendInThread()
_parent::OnSuspendInThread();
}
void SysMtgsThread::OnResumeInThread( bool isSuspended )
void SysMtgsThread::OnResumeInThread(bool isSuspended)
{
if( isSuspended )
if (isSuspended)
OpenPlugin();
_parent::OnResumeInThread( isSuspended );
_parent::OnResumeInThread(isSuspended);
}
void SysMtgsThread::OnCleanupInThread()
@ -598,27 +600,35 @@ void SysMtgsThread::OnCleanupInThread()
// If isMTVU, then this implies this function is being called from the MTVU thread...
void SysMtgsThread::WaitGS(bool syncRegs, bool weakWait, bool isMTVU)
{
pxAssertDev( !IsSelf(), "This method is only allowed from threads *not* named MTGS." );
pxAssertDev(!IsSelf(), "This method is only allowed from threads *not* named MTGS.");
if( m_ExecMode == ExecMode_NoThreadYet || !IsRunning() ) return;
if( !pxAssertDev( IsOpen(), "MTGS Warning! WaitGS issued on a closed thread." ) ) return;
if (m_ExecMode == ExecMode_NoThreadYet || !IsRunning())
return;
if (!pxAssertDev(IsOpen(), "MTGS Warning! WaitGS issued on a closed thread."))
return;
Gif_Path& path = gifUnit.gifPath[GIF_PATH_1];
Gif_Path& path = gifUnit.gifPath[GIF_PATH_1];
u32 startP1Packs = weakWait ? path.GetPendingGSPackets() : 0;
// Both m_ReadPos and m_WritePos can be relaxed as we only want to test if the queue is empty but
// we don't want to access the content of the queue
if (isMTVU || m_ReadPos.load(std::memory_order_relaxed) != m_WritePos.load(std::memory_order_relaxed)) {
if (isMTVU || m_ReadPos.load(std::memory_order_relaxed) != m_WritePos.load(std::memory_order_relaxed))
{
SetEvent();
RethrowException();
for(;;) {
if (weakWait) m_mtx_RingBufferBusy2.Wait();
else m_mtx_RingBufferBusy .Wait();
for (;;)
{
if (weakWait)
m_mtx_RingBufferBusy2.Wait();
else
m_mtx_RingBufferBusy.Wait();
RethrowException();
if(!isMTVU && m_ReadPos.load(std::memory_order_relaxed) == m_WritePos.load(std::memory_order_relaxed)) break;
if (!isMTVU && m_ReadPos.load(std::memory_order_relaxed) == m_WritePos.load(std::memory_order_relaxed))
break;
u32 curP1Packs = weakWait ? path.GetPendingGSPackets() : 0;
if (weakWait && ((startP1Packs-curP1Packs) || !curP1Packs)) break;
if (weakWait && ((startP1Packs - curP1Packs) || !curP1Packs))
break;
// On weakWait we will stop waiting on the MTGS thread if the
// MTGS thread has processed a vu1 xgkick packet, or is pending on
// its final vu1 xgkick packet (!curP1Packs)...
@ -628,7 +638,8 @@ void SysMtgsThread::WaitGS(bool syncRegs, bool weakWait, bool isMTVU)
}
}
if (syncRegs) {
if (syncRegs)
{
ScopedLock lock(m_mtx_WaitGS);
// Completely synchronize GS and MTGS register states.
memcpy(RingBuffer.Regs, PS2MEM_GS, sizeof(RingBuffer.Regs));
@ -639,7 +650,7 @@ void SysMtgsThread::WaitGS(bool syncRegs, bool weakWait, bool isMTVU)
// For use in loops that wait on the GS thread to do certain things.
void SysMtgsThread::SetEvent()
{
if(!m_RingBufferIsBusy.load(std::memory_order_relaxed))
if (!m_RingBufferIsBusy.load(std::memory_order_relaxed))
m_sem_event.Post();
m_CopyDataTally = 0;
@ -654,25 +665,26 @@ u8* SysMtgsThread::GetDataPacketPtr() const
void SysMtgsThread::SendDataPacket()
{
// make sure a previous copy block has been started somewhere.
pxAssert( m_packet_size != 0 );
pxAssert(m_packet_size != 0);
uint actualSize = ((m_packet_writepos - m_packet_startpos) & RingBufferMask)-1;
pxAssert( actualSize <= m_packet_size );
pxAssert( m_packet_writepos < RingBufferSize );
uint actualSize = ((m_packet_writepos - m_packet_startpos) & RingBufferMask) - 1;
pxAssert(actualSize <= m_packet_size);
pxAssert(m_packet_writepos < RingBufferSize);
PacketTagType& tag = (PacketTagType&)RingBuffer[m_packet_startpos];
tag.data[0] = actualSize;
m_WritePos.store(m_packet_writepos, std::memory_order_release);
if(EmuConfig.GS.SynchronousMTGS)
if (EmuConfig.GS.SynchronousMTGS)
{
WaitGS();
}
else if(!m_RingBufferIsBusy.load(std::memory_order_relaxed))
else if (!m_RingBufferIsBusy.load(std::memory_order_relaxed))
{
m_CopyDataTally += m_packet_size;
if( m_CopyDataTally > 0x2000 ) SetEvent();
if (m_CopyDataTally > 0x2000)
SetEvent();
}
m_packet_size = 0;
@ -680,7 +692,7 @@ void SysMtgsThread::SendDataPacket()
//m_PacketLocker.Release();
}
void SysMtgsThread::GenericStall( uint size )
void SysMtgsThread::GenericStall(uint size)
{
// Note on volatiles: m_WritePos is not modified by the GS thread, so there's no need
// to use volatile reads here. We do cache it though, since we know it never changes,
@ -688,8 +700,8 @@ void SysMtgsThread::GenericStall( uint size )
const uint writepos = m_WritePos.load(std::memory_order_relaxed);
// Sanity checks! (within the confines of our ringbuffer please!)
pxAssert( size < RingBufferSize );
pxAssert( writepos < RingBufferSize );
pxAssert(size < RingBufferSize);
pxAssert(writepos < RingBufferSize);
// generic gs wait/stall.
// if the writepos is past the readpos then we're safe.
@ -714,21 +726,23 @@ void SysMtgsThread::GenericStall( uint size )
// the next packet will likely stall up too. So lets set a condition for the MTGS
// thread to wake up the EE once there's a sizable chunk of the ringbuffer emptied.
uint somedone = (RingBufferSize - freeroom) / 4;
if( somedone < size+1 ) somedone = size + 1;
uint somedone = (RingBufferSize - freeroom) / 4;
if (somedone < size + 1)
somedone = size + 1;
// FMV Optimization: FMVs typically send *very* little data to the GS, in some cases
// every other frame is nothing more than a page swap. Sleeping the EEcore is a
// waste of time, and we get better results using a spinwait.
if( somedone > 0x80 )
if (somedone > 0x80)
{
pxAssertDev( m_SignalRingEnable == 0, "MTGS Thread Synchronization Error" );
pxAssertDev(m_SignalRingEnable == 0, "MTGS Thread Synchronization Error");
m_SignalRingPosition.store(somedone, std::memory_order_release);
//Console.WriteLn( Color_Blue, "(EEcore Sleep) PrepDataPacker \tringpos=0x%06x, writepos=0x%06x, signalpos=0x%06x", readpos, writepos, m_SignalRingPosition );
while(true) {
while (true)
{
m_SignalRingEnable.store(true, std::memory_order_release);
SetEvent();
m_sem_OnRingReset.WaitWithoutYield();
@ -740,16 +754,18 @@ void SysMtgsThread::GenericStall( uint size )
else
freeroom = RingBufferSize - (writepos - readpos);
if (freeroom > size) break;
if (freeroom > size)
break;
}
pxAssertDev( m_SignalRingPosition <= 0, "MTGS Thread Synchronization Error" );
pxAssertDev(m_SignalRingPosition <= 0, "MTGS Thread Synchronization Error");
}
else
{
//Console.WriteLn( Color_StrongGray, "(EEcore Spin) PrepDataPacket!" );
SetEvent();
while(true) {
while (true)
{
SpinWait();
readpos = m_ReadPos.load(std::memory_order_acquire);
@ -758,16 +774,17 @@ void SysMtgsThread::GenericStall( uint size )
else
freeroom = RingBufferSize - (writepos - readpos);
if (freeroom > size) break;
if (freeroom > size)
break;
}
}
}
}
void SysMtgsThread::PrepDataPacket( MTGS_RingCommand cmd, u32 size )
void SysMtgsThread::PrepDataPacket(MTGS_RingCommand cmd, u32 size)
{
m_packet_size = size;
++size; // takes into account our RingCommand QWC.
++size; // takes into account our RingCommand QWC.
GenericStall(size);
// Command qword: Low word is the command, and the high word is the packet
@ -786,26 +803,26 @@ void SysMtgsThread::PrepDataPacket( MTGS_RingCommand cmd, u32 size )
// around VU memory instead of having buffer overflow...
// Parameters:
// size - size of the packet data, in smd128's
void SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, u32 size )
void SysMtgsThread::PrepDataPacket(GIF_PATH pathidx, u32 size)
{
//m_PacketLocker.Acquire();
PrepDataPacket( (MTGS_RingCommand)pathidx, size );
PrepDataPacket((MTGS_RingCommand)pathidx, size);
}
__fi void SysMtgsThread::_FinishSimplePacket()
{
uint future_writepos = (m_WritePos.load(std::memory_order_relaxed) +1) & RingBufferMask;
pxAssert( future_writepos != m_ReadPos.load(std::memory_order_acquire) );
uint future_writepos = (m_WritePos.load(std::memory_order_relaxed) + 1) & RingBufferMask;
pxAssert(future_writepos != m_ReadPos.load(std::memory_order_acquire));
m_WritePos.store(future_writepos, std::memory_order_release);
if( EmuConfig.GS.SynchronousMTGS )
if (EmuConfig.GS.SynchronousMTGS)
WaitGS();
else
++m_CopyDataTally;
}
void SysMtgsThread::SendSimplePacket( MTGS_RingCommand type, int data0, int data1, int data2 )
void SysMtgsThread::SendSimplePacket(MTGS_RingCommand type, int data0, int data1, int data2)
{
//ScopedLock locker( m_PacketLocker );
@ -824,15 +841,18 @@ void SysMtgsThread::SendSimpleGSPacket(MTGS_RingCommand type, u32 offset, u32 si
{
SendSimplePacket(type, (int)offset, (int)size, (int)path);
if(!EmuConfig.GS.SynchronousMTGS) {
if(!m_RingBufferIsBusy.load(std::memory_order_relaxed)) {
if (!EmuConfig.GS.SynchronousMTGS)
{
if (!m_RingBufferIsBusy.load(std::memory_order_relaxed))
{
m_CopyDataTally += size / 16;
if (m_CopyDataTally > 0x2000) SetEvent();
if (m_CopyDataTally > 0x2000)
SetEvent();
}
}
}
void SysMtgsThread::SendPointerPacket( MTGS_RingCommand type, u32 data0, void* data1 )
void SysMtgsThread::SendPointerPacket(MTGS_RingCommand type, u32 data0, void* data1)
{
//ScopedLock locker( m_PacketLocker );
@ -846,14 +866,15 @@ void SysMtgsThread::SendPointerPacket( MTGS_RingCommand type, u32 data0, void* d
_FinishSimplePacket();
}
void SysMtgsThread::SendGameCRC( u32 crc )
void SysMtgsThread::SendGameCRC(u32 crc)
{
SendSimplePacket( GS_RINGTYPE_CRC, crc, 0, 0 );
SendSimplePacket(GS_RINGTYPE_CRC, crc, 0, 0);
}
void SysMtgsThread::WaitForOpen()
{
if( m_PluginOpened ) return;
if (m_PluginOpened)
return;
Resume();
// Two-phase timeout on MTGS opening, so that possible errors are handled
@ -861,11 +882,11 @@ void SysMtgsThread::WaitForOpen()
// another 12 seconds if no errors occurred (this might seem long, but sometimes a
// GS plugin can be very stubborned, especially in debug mode builds).
if( !m_sem_OpenDone.Wait( wxTimeSpan(0, 0, 2, 0) ) )
if (!m_sem_OpenDone.Wait(wxTimeSpan(0, 0, 2, 0)))
{
RethrowException();
if( !m_sem_OpenDone.Wait( wxTimeSpan(0, 0, 12, 0) ) )
if (!m_sem_OpenDone.Wait(wxTimeSpan(0, 0, 12, 0)))
{
RethrowException();
@ -873,7 +894,7 @@ void SysMtgsThread::WaitForOpen()
// [TODO] : implement a user confirmation to cancel the action and exit the
// emulator forcefully, or to continue waiting on the GS.
throw Exception::PluginOpenError( PluginId_GS )
throw Exception::PluginOpenError(PluginId_GS)
.SetBothMsgs(pxLt("The MTGS thread has become unresponsive while waiting for the GS plugin to open."));
}
}
@ -881,10 +902,10 @@ void SysMtgsThread::WaitForOpen()
RethrowException();
}
void SysMtgsThread::Freeze( int mode, MTGS_FreezeData& data )
void SysMtgsThread::Freeze(int mode, MTGS_FreezeData& data)
{
GetCorePlugins().Open( PluginId_GS );
SendPointerPacket( GS_RINGTYPE_FREEZE, mode, &data );
GetCorePlugins().Open(PluginId_GS);
SendPointerPacket(GS_RINGTYPE_FREEZE, mode, &data);
Resume();
WaitGS();
}