mirror of https://github.com/PCSX2/pcsx2.git
Let's fix some major instabilities in the new MTGS design, shall we. :)
If this rev is nice and stable then I'll go ahead and break things again by implementing the planned synchronization speedups. ;) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2235 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
87b443a873
commit
4116c7d379
|
@ -160,13 +160,11 @@ protected:
|
||||||
void OnResumeInThread( bool IsSuspended );
|
void OnResumeInThread( bool IsSuspended );
|
||||||
void OnCleanupInThread();
|
void OnCleanupInThread();
|
||||||
|
|
||||||
// Saves MMX/XMM REGS, posts an event to the mtgsThread flag and releases a timeslice.
|
// Sets the Event flag and issues a timeslice on the EEcore thread (ie, an efficient
|
||||||
// For use in surrounding loops that wait on the mtgs.
|
// method of kicking the MTGS thread into action once there's a sizable chunk of work
|
||||||
|
// accumulated).
|
||||||
void PrepEventWait();
|
void PrepEventWait();
|
||||||
|
|
||||||
// Restores MMX/XMM REGS. For use in surrounding loops that wait on the mtgs.
|
|
||||||
void PostEventWait() const;
|
|
||||||
|
|
||||||
// Used internally by SendSimplePacket type functions
|
// Used internally by SendSimplePacket type functions
|
||||||
uint _PrepForSimplePacket();
|
uint _PrepForSimplePacket();
|
||||||
void _FinishSimplePacket( uint future_writepos );
|
void _FinishSimplePacket( uint future_writepos );
|
||||||
|
|
122
pcsx2/MTGS.cpp
122
pcsx2/MTGS.cpp
|
@ -154,9 +154,12 @@ static int alterFrameFlush = 0;
|
||||||
void mtgsThreadObject::PostVsyncEnd( bool updategs )
|
void mtgsThreadObject::PostVsyncEnd( bool updategs )
|
||||||
{
|
{
|
||||||
SendSimplePacket( GS_RINGTYPE_VSYNC, (*(u32*)(PS2MEM_GS+0x1000)&0x2000), updategs, 0 );
|
SendSimplePacket( GS_RINGTYPE_VSYNC, (*(u32*)(PS2MEM_GS+0x1000)&0x2000), updategs, 0 );
|
||||||
if( alterFrameFlush )
|
if( alterFrameFlush || (m_WritePos > (RingBufferSize/3)) )
|
||||||
RestartRingbuffer();
|
RestartRingbuffer();
|
||||||
alterFrameFlush ^= 2;
|
else
|
||||||
|
SetEvent();
|
||||||
|
|
||||||
|
alterFrameFlush ^= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PacketTagType
|
struct PacketTagType
|
||||||
|
@ -180,7 +183,7 @@ void mtgsThreadObject::OpenPlugin()
|
||||||
GSirqCallback( dummyIrqCallback );
|
GSirqCallback( dummyIrqCallback );
|
||||||
|
|
||||||
if( renderswitch )
|
if( renderswitch )
|
||||||
Console.WriteLn( "\t\tForced software switch enabled." );
|
Console.Indent(2).WriteLn( "Forced software switch enabled." );
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -439,9 +442,13 @@ void mtgsThreadObject::WaitGS()
|
||||||
if( m_ExecMode == ExecMode_NoThreadYet || !IsRunning() ) return;
|
if( m_ExecMode == ExecMode_NoThreadYet || !IsRunning() ) return;
|
||||||
if( !pxAssertDev( IsOpen(), "MTGS Warning! WaitGS issued on a closed thread." ) ) return;
|
if( !pxAssertDev( IsOpen(), "MTGS Warning! WaitGS issued on a closed thread." ) ) return;
|
||||||
|
|
||||||
SetEvent();
|
if( volatize(m_RingPos) != m_WritePos )
|
||||||
m_lock_RingBufferBusy.Wait();
|
{
|
||||||
//while( volatize(m_RingPos) != volatize(m_WritePos) ) Timeslice();
|
PrepEventWait();
|
||||||
|
do {
|
||||||
|
m_lock_RingBufferBusy.Wait();
|
||||||
|
} while( volatize(m_RingPos) != m_WritePos );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the gsEvent flag and releases a timeslice.
|
// Sets the gsEvent flag and releases a timeslice.
|
||||||
|
@ -460,10 +467,6 @@ void mtgsThreadObject::PrepEventWait()
|
||||||
Timeslice();
|
Timeslice();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtgsThreadObject::PostEventWait() const
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
u8* mtgsThreadObject::GetDataPacketPtr() const
|
u8* mtgsThreadObject::GetDataPacketPtr() const
|
||||||
{
|
{
|
||||||
return (u8*)&RingBuffer[m_packet_ringpos];
|
return (u8*)&RingBuffer[m_packet_ringpos];
|
||||||
|
@ -507,31 +510,6 @@ void mtgsThreadObject::SendDataPacket()
|
||||||
{
|
{
|
||||||
WaitGS();
|
WaitGS();
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
else if( m_lock_RingBufferBusy.TryAcquire() )
|
|
||||||
{
|
|
||||||
m_lock_RingBufferBusy.Release();
|
|
||||||
|
|
||||||
// The ringbuffer is current in a resting state, so if enough copies have
|
|
||||||
// queued up then go ahead and initiate the GS thread..
|
|
||||||
|
|
||||||
// Optimization notes: What we're doing here is initiating a "burst" mode on
|
|
||||||
// the thread, which improves its cache hit performance and makes it more friendly
|
|
||||||
// to other threads in Pcsx2 and such. Primary is the Command Tally, and then a
|
|
||||||
// secondary data size threshold for games that do lots of texture swizzling.
|
|
||||||
|
|
||||||
// 16 was the best value I found so far.
|
|
||||||
// tested values:
|
|
||||||
// 24 - very slow on HT machines (+5% drop in fps)
|
|
||||||
// 8 - roughly 2% slower on HT machines.
|
|
||||||
|
|
||||||
m_CopyDataTally += m_packet_size;
|
|
||||||
if( ( m_CopyDataTally > 0x8000 ) || ( ++m_CopyCommandTally > 16 ) )
|
|
||||||
{
|
|
||||||
//Console.Status( "MTGS Kick! DataSize : 0x%5.8x, CommandTally : %d", m_CopyDataTally, m_CopyCommandTally );
|
|
||||||
SetEvent();
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//m_PacketLocker.Release();
|
//m_PacketLocker.Release();
|
||||||
}
|
}
|
||||||
|
@ -642,7 +620,6 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s
|
||||||
if( writepos+size < readpos ) break;
|
if( writepos+size < readpos ) break;
|
||||||
SpinWait();
|
SpinWait();
|
||||||
}
|
}
|
||||||
PostEventWait();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( writepos + size > RingBufferSize )
|
else if( writepos + size > RingBufferSize )
|
||||||
|
@ -653,26 +630,6 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s
|
||||||
// the start of the ring buffer (it's a lot easier than trying
|
// the start of the ring buffer (it's a lot easier than trying
|
||||||
// to wrap the packet around the end of the buffer).
|
// to wrap the packet around the end of the buffer).
|
||||||
|
|
||||||
// We have to be careful not to leapfrog our read-position. If it's
|
|
||||||
// greater than the current write position then we need to stall
|
|
||||||
// until it loops around to the beginning of the buffer
|
|
||||||
|
|
||||||
PrepEventWait();
|
|
||||||
while( true )
|
|
||||||
{
|
|
||||||
uint readpos = volatize(m_RingPos);
|
|
||||||
|
|
||||||
// is the buffer empty?
|
|
||||||
if( readpos == writepos ) break;
|
|
||||||
|
|
||||||
// Also: Wait for the readpos to go past the start of the buffer
|
|
||||||
// Otherwise it'll stop dead in its tracks when we set the new write
|
|
||||||
// position below (bad!)
|
|
||||||
if( readpos < writepos && readpos != 0 ) break;
|
|
||||||
|
|
||||||
SpinWait();
|
|
||||||
}
|
|
||||||
|
|
||||||
RestartRingbuffer();
|
RestartRingbuffer();
|
||||||
writepos = m_WritePos;
|
writepos = m_WritePos;
|
||||||
|
|
||||||
|
@ -683,11 +640,10 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s
|
||||||
uint readpos = volatize(m_RingPos);
|
uint readpos = volatize(m_RingPos);
|
||||||
|
|
||||||
if( readpos == m_WritePos ) break;
|
if( readpos == m_WritePos ) break;
|
||||||
if( writepos+size < readpos ) break;
|
if( m_WritePos+size < readpos ) break;
|
||||||
|
|
||||||
SpinWait();
|
SpinWait();
|
||||||
}
|
}
|
||||||
PostEventWait();
|
|
||||||
}
|
}
|
||||||
else // always true - if( writepos + size == MTGS_RINGBUFFEREND )
|
else // always true - if( writepos + size == MTGS_RINGBUFFEREND )
|
||||||
{
|
{
|
||||||
|
@ -709,7 +665,6 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s
|
||||||
|
|
||||||
SpinWait();
|
SpinWait();
|
||||||
}
|
}
|
||||||
PostEventWait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RINGBUF_DEBUG_STACK
|
#ifdef RINGBUF_DEBUG_STACK
|
||||||
|
@ -747,11 +702,9 @@ __forceinline uint mtgsThreadObject::_PrepForSimplePacket()
|
||||||
if( future_writepos == volatize(m_RingPos) )
|
if( future_writepos == volatize(m_RingPos) )
|
||||||
{
|
{
|
||||||
PrepEventWait();
|
PrepEventWait();
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
SpinWait();
|
SpinWait();
|
||||||
} while( future_writepos == volatize(m_RingPos) );
|
} while( future_writepos == volatize(m_RingPos) );
|
||||||
PostEventWait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return future_writepos;
|
return future_writepos;
|
||||||
|
@ -766,22 +719,47 @@ __forceinline void mtgsThreadObject::_FinishSimplePacket( uint future_writepos )
|
||||||
WaitGS();
|
WaitGS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO : These will be moved to the mtgs class once I solidify the new synch method.
|
||||||
|
Semaphore m_sem_OnRingReset;
|
||||||
|
u32 m_SignalRingReset;
|
||||||
|
|
||||||
void mtgsThreadObject::RestartRingbuffer()
|
void mtgsThreadObject::RestartRingbuffer()
|
||||||
{
|
{
|
||||||
if( m_WritePos == 0 ) return;
|
if( m_WritePos == 0 ) return;
|
||||||
|
|
||||||
const uint thefuture = 0;
|
const uint thefuture = 0;
|
||||||
|
|
||||||
// The ringbuffer read pos is blocking the future write position, so stall out
|
// We have to be careful not to leapfrog our read-position, which would happen if
|
||||||
// until the read position has moved.
|
// it's greater than the current write position (since wrapping writepos to 0 would
|
||||||
if( thefuture == volatize(m_RingPos) )
|
// be the act of skipping PAST readpos). Stall until it loops around to the
|
||||||
|
// beginning of the buffer
|
||||||
|
|
||||||
|
// TODO : Implement this using a mutex/semaphore signal for when the ring buffer has
|
||||||
|
// wrapped around from 0. ...which should end up looking something like this:
|
||||||
|
|
||||||
|
// note: the boolean for signalling ring resets is to prevent both frivilous posting
|
||||||
|
// to the semapore in the MTGS thread, and to avoid having accumulations of large
|
||||||
|
// numbers of signals in the semaphore that would have to be unwound here.
|
||||||
|
|
||||||
|
/*AtomicExchange( m_SignalRingReset, true );
|
||||||
|
uint readpos = volatize(m_RingPos);
|
||||||
|
while( readpos >= m_WritePos || readpos == thefuture )
|
||||||
|
m_sem_OnRingReset().Wait();
|
||||||
|
AtomicExchange( m_SignalRingReset, false );*/
|
||||||
|
|
||||||
|
PrepEventWait();
|
||||||
|
while( true )
|
||||||
{
|
{
|
||||||
PrepEventWait();
|
uint readpos = volatize(m_RingPos);
|
||||||
do
|
|
||||||
{
|
// is the buffer empty?
|
||||||
SpinWait();
|
if( readpos == m_WritePos ) break;
|
||||||
} while( thefuture == volatize(m_RingPos) );
|
|
||||||
PostEventWait();
|
// Also: Wait for the readpos to go past the start of the buffer (which is our
|
||||||
|
// 'future' write position), otherwise it'll stop dead in its tracks when we set
|
||||||
|
// the new write position below. (readpos == writepos is a "stop" condition).
|
||||||
|
if( (readpos < m_WritePos) && (readpos != thefuture) ) break;
|
||||||
|
|
||||||
|
SpinWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketTagType& tag = (PacketTagType&)RingBuffer[m_WritePos];
|
PacketTagType& tag = (PacketTagType&)RingBuffer[m_WritePos];
|
||||||
|
|
Loading…
Reference in New Issue