Couple more MTGS sync fixes, and some final optimizations.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2247 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-11-24 20:11:43 +00:00
parent 2beae92272
commit b288e82b95
3 changed files with 81 additions and 27 deletions

View File

@ -158,7 +158,8 @@ namespace Threading
extern u32 AtomicIncrement( volatile u32& Target ); extern u32 AtomicIncrement( volatile u32& Target );
extern u32 AtomicDecrement( volatile u32& Target ); extern u32 AtomicDecrement( volatile u32& Target );
extern s32 AtomicExchange( volatile s32& Target, s32 value ); extern s32 AtomicExchange( volatile s32& Target, s32 value );
extern s32 AtomicExchangeAdd( volatile s32& Target, u32 value ); extern s32 AtomicExchangeAdd( volatile s32& Target, s32 value );
extern s32 AtomicExchangeSub( volatile s32& Target, s32 value );
extern s32 AtomicIncrement( volatile s32& Target ); extern s32 AtomicIncrement( volatile s32& Target );
extern s32 AtomicDecrement( volatile s32& Target ); extern s32 AtomicDecrement( volatile s32& Target );

View File

@ -639,11 +639,16 @@ __forceinline s32 Threading::AtomicExchange( volatile s32& Target, s32 value )
return _InterlockedExchange( (volatile long*)&Target, value ); return _InterlockedExchange( (volatile long*)&Target, value );
} }
__forceinline s32 Threading::AtomicExchangeAdd( volatile s32& Target, u32 value ) __forceinline s32 Threading::AtomicExchangeAdd( volatile s32& Target, s32 value )
{ {
return _InterlockedExchangeAdd( (volatile long*)&Target, value ); return _InterlockedExchangeAdd( (volatile long*)&Target, value );
} }
__forceinline s32 Threading::AtomicExchangeSub( volatile s32& Target, s32 value )
{
return _InterlockedExchangeAdd( (volatile long*)&Target, -value );
}
__forceinline s32 Threading::AtomicIncrement( volatile s32& Target ) __forceinline s32 Threading::AtomicIncrement( volatile s32& Target )
{ {
return _InterlockedExchangeAdd( (volatile long*)&Target, 1 ); return _InterlockedExchangeAdd( (volatile long*)&Target, 1 );

View File

@ -157,7 +157,7 @@ void SysMtgsThread::PostVsyncEnd( bool updategs )
// (queued frames cause input lag and desynced audio -- bad!). // (queued frames cause input lag and desynced audio -- bad!).
m_alterFrameFlush ^= 1; m_alterFrameFlush ^= 1;
if( m_alterFrameFlush ) if( !m_alterFrameFlush )
RestartRingbuffer(); RestartRingbuffer();
else else
SetEvent(); SetEvent();
@ -242,6 +242,7 @@ void SysMtgsThread::ExecuteTaskInThread()
m_sem_event.WaitWithoutYield(); m_sem_event.WaitWithoutYield();
StateCheckInThread(); StateCheckInThread();
{
RingBufferLock busy( *this ); RingBufferLock busy( *this );
// note: m_RingPos is intentionally not volatile, because it should only // note: m_RingPos is intentionally not volatile, because it should only
@ -318,7 +319,7 @@ void SysMtgsThread::ExecuteTaskInThread()
switch( tag.command ) switch( tag.command )
{ {
case GS_RINGTYPE_RESTART: case GS_RINGTYPE_RESTART:
MTGS_LOG( "(MTGS Packet Read) ringtype=Restart" ); //MTGS_LOG( "(MTGS Packet Read) ringtype=Restart" );
m_RingPos = 0; m_RingPos = 0;
continue; continue;
@ -422,8 +423,7 @@ void SysMtgsThread::ExecuteTaskInThread()
if( m_SignalRingEnable != 0 ) if( m_SignalRingEnable != 0 )
{ {
// The EEcore has requested a signal after some amount of processed data. // The EEcore has requested a signal after some amount of processed data.
m_SignalRingPosition -= ringposinc; if( AtomicExchangeSub( m_SignalRingPosition, ringposinc ) <= 0 )
if( m_SignalRingPosition <= 0 )
{ {
// Make sure to post the signal after the m_RingPos has been updated... // Make sure to post the signal after the m_RingPos has been updated...
AtomicExchange( m_SignalRingEnable, 0 ); AtomicExchange( m_SignalRingEnable, 0 );
@ -432,14 +432,20 @@ void SysMtgsThread::ExecuteTaskInThread()
} }
} }
} }
}
// Safety valve in case standard signals fail for some reason -- this ensures the EEcore // Safety valve in case standard signals fail for some reason -- this ensures the EEcore
// won't sleep the eternity, even if SignalRingPosition didn't reach 0 for some reason. // 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( AtomicExchange( m_SignalRingEnable, 0 ) != 0 ) if( AtomicExchange( m_SignalRingEnable, 0 ) != 0 )
{ {
//Console.Warning( "(MTGS Thread) Dangling RingSignal on empty buffer! signalpos=0x%06x", AtomicExchange( m_SignalRingPosition, 0 ) );
AtomicExchange( m_SignalRingPosition, 0 ); AtomicExchange( m_SignalRingPosition, 0 );
m_sem_OnRingReset.Post(); m_sem_OnRingReset.Post();
} }
//Console.Warning( "(MTGS Thread) Nothing to do!!" );
} }
} }
@ -514,8 +520,6 @@ void SysMtgsThread::SendDataPacket()
uint temp = m_packet_ringpos + m_packet_size; uint temp = m_packet_ringpos + m_packet_size;
pxAssert( temp <= RingBufferSize ); pxAssert( temp <= RingBufferSize );
temp &= RingBufferMask; temp &= RingBufferMask;
if( temp == 0 )
m_RingWrapSpot = m_WritePos;
if( IsDebugBuild ) if( IsDebugBuild )
{ {
@ -647,8 +651,6 @@ int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size
uint readpos = volatize(m_RingPos); uint readpos = volatize(m_RingPos);
if( (writepos < readpos) && (writepos+size >= readpos) ) if( (writepos < readpos) && (writepos+size >= readpos) )
{ {
pxAssertDev( m_SignalRingEnable == 0, "MTGS Thread Synchronization Error" );
// writepos is behind the readpos and will overlap it if we commit the data, // writepos is behind the readpos and will overlap it if we commit the data,
// so we need to wait until readpos is out past the end of the future write pos, // so we need to wait until readpos is out past the end of the future write pos,
// or until it wraps around (in which case writepos will be >= readpos). // or until it wraps around (in which case writepos will be >= readpos).
@ -658,7 +660,7 @@ int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size
// thread to wake up the EE once there's a sizable chunk of the ringbuffer emptied. // thread to wake up the EE once there's a sizable chunk of the ringbuffer emptied.
uint totalAccum = (m_RingWrapSpot - readpos) + writepos; uint totalAccum = (m_RingWrapSpot - readpos) + writepos;
uint somedone = (totalAccum / 4); uint somedone = totalAccum / 4;
if( somedone < size+1 ) somedone = size + 1; if( somedone < size+1 ) somedone = size + 1;
// FMV Optimization: FMVs typically send *very* little data to the GS, in some cases // FMV Optimization: FMVs typically send *very* little data to the GS, in some cases
@ -667,6 +669,7 @@ int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size
if( somedone > 0x80 ) if( somedone > 0x80 )
{ {
pxAssertDev( m_SignalRingEnable == 0, "MTGS Thread Synchronization Error" );
m_SignalRingPosition = somedone; m_SignalRingPosition = somedone;
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Sleep!\twrapspot=0x%06x, ringpos=0x%06x, writepos=0x%06x, signalpos=0x%06x", m_RingWrapSpot, readpos, writepos, m_SignalRingPosition ); //Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Sleep!\twrapspot=0x%06x, ringpos=0x%06x, writepos=0x%06x, signalpos=0x%06x", m_RingWrapSpot, readpos, writepos, m_SignalRingPosition );
@ -702,6 +705,7 @@ int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size
//Console.WriteLn( "MTGS > Ringbuffer Got Filled!"); //Console.WriteLn( "MTGS > Ringbuffer Got Filled!");
RestartRingbuffer( size ); RestartRingbuffer( size );
writepos = m_WritePos; writepos = m_WritePos;
m_alterFrameFlush = 0;
} }
else // always true - if( writepos + size == MTGS_RINGBUFFEREND ) else // always true - if( writepos + size == MTGS_RINGBUFFEREND )
{ {
@ -732,7 +736,7 @@ int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size
SetEvent(); SetEvent();
m_sem_OnRingReset.WaitWithoutYield(); m_sem_OnRingReset.WaitWithoutYield();
readpos = volatize(m_RingPos); readpos = volatize(m_RingPos);
Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Perfect Post-sleep Report!\tringpos=0x%06x", readpos ); //Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Perfect Post-sleep Report!\tringpos=0x%06x", readpos );
} while( (writepos < readpos) || (readpos==0) ); } while( (writepos < readpos) || (readpos==0) );
pxAssertDev( m_SignalRingPosition <= 0, "MTGS Thread Synchronization Error" ); pxAssertDev( m_SignalRingPosition <= 0, "MTGS Thread Synchronization Error" );
@ -747,6 +751,9 @@ int SysMtgsThread::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 size
} while( (writepos < readpos) || (readpos==0) ); } while( (writepos < readpos) || (readpos==0) );
} }
} }
m_alterFrameFlush = 0;
m_RingWrapSpot = RingBufferSize;
} }
#ifdef RINGBUF_DEBUG_STACK #ifdef RINGBUF_DEBUG_STACK
@ -784,14 +791,29 @@ void SysMtgsThread::RestartRingbuffer( uint packsize )
// be the act of skipping PAST readpos). Stall until it loops around to the // be the act of skipping PAST readpos). Stall until it loops around to the
// beginning of the buffer, and past the size of our packet allocation. // beginning of the buffer, and past the size of our packet allocation.
m_SignalRingPosition = (readpos - m_WritePos) + packsize + 1; uint somedone = (m_RingWrapSpot - readpos) + packsize + 1;
do { if( somedone > 0x80 )
{
m_SignalRingPosition = somedone;
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Restart Sleep!\t\twrapspot=0x%06x, ringpos=0x%06x, writepos=0x%06x, signalpos=0x%06x", m_RingWrapSpot, readpos, m_WritePos, m_SignalRingPosition );
do {
AtomicExchange( m_SignalRingEnable, 1 );
SetEvent();
m_sem_OnRingReset.WaitWithoutYield();
readpos = volatize(m_RingPos);
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Restart Post-sleep Report!\tringpos=0x%06x", readpos );
} while( (readpos > m_WritePos) || (readpos <= thefuture) );
}
else
{
SetEvent(); SetEvent();
AtomicExchange( m_SignalRingEnable, 1 ); do {
m_sem_OnRingReset.WaitWithoutYield(); SpinWait();
readpos = volatize(m_RingPos); readpos = volatize(m_RingPos);
} while( (readpos > m_WritePos) || (readpos <= thefuture) ); } while( (readpos > m_WritePos) || (readpos <= thefuture) );
}
} }
PacketTagType& tag = (PacketTagType&)RingBuffer[m_WritePos]; PacketTagType& tag = (PacketTagType&)RingBuffer[m_WritePos];
@ -818,17 +840,43 @@ __forceinline uint SysMtgsThread::_PrepForSimplePacket()
future_writepos &= RingBufferMask; future_writepos &= RingBufferMask;
if( future_writepos == 0 ) if( future_writepos == 0 )
m_RingWrapSpot = m_WritePos; {
m_alterFrameFlush = 0;
m_RingWrapSpot = RingBufferSize;
}
// FIXME: Optimize this using m_SignalRingEnable and friends! uint readpos = volatize(m_RingPos);
// The ringbuffer read pos is blocking the future write position, so stall out if( future_writepos == readpos )
// until the read position has moved.
if( future_writepos == volatize(m_RingPos) )
{ {
SetEvent(); // The ringbuffer read pos is blocking the future write position, so stall out
do { // until the read position has moved.
SpinWait();
} while( future_writepos == volatize(m_RingPos) ); uint totalAccum = (m_RingWrapSpot - readpos) + future_writepos;
uint somedone = totalAccum / 4;
if( somedone > 0x80 )
{
m_SignalRingPosition = somedone;
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Simple Sleep!\t\twrapspot=0x%06x, ringpos=0x%06x, writepos=0x%06x, signalpos=0x%06x", m_RingWrapSpot, readpos, writepos, m_SignalRingPosition );
do {
AtomicExchange( m_SignalRingEnable, 1 );
SetEvent();
m_sem_OnRingReset.WaitWithoutYield();
readpos = volatize(m_RingPos);
//Console.WriteLn( Color_Blue, "(MTGS Sync) EEcore Simple Post-sleep Report!\tringpos=0x%06x", readpos );
} while( future_writepos == readpos );
pxAssertDev( m_SignalRingPosition <= 0, "MTGS Thread Synchronization Error" );
}
else
{
SetEvent();
do {
SpinWait();
} while( future_writepos == volatize(m_RingPos) );
}
} }
return future_writepos; return future_writepos;