mirror of https://github.com/PCSX2/pcsx2.git
Settings work again!
* Switched the SysCoreThread to a static (fully persistent) thread. * Added some listeners for when the CoreThread status changes * fixed some slowness in savestates, and the emu will now stall until savestates complete, if you try to exit too quick (avoids savestate corruption) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1993 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
2a69c92067
commit
e8e61a5cf8
|
@ -83,20 +83,24 @@ public:
|
|||
virtual inline void Add( const ListenerType& listener );
|
||||
virtual inline void RemoveObject( const void* object );
|
||||
|
||||
Handle Add( void* objhandle, typename ListenerType::FuncType* fnptr )
|
||||
void Add( void* objhandle, typename ListenerType::FuncType* fnptr )
|
||||
{
|
||||
return Add( Handle( objhandle, fnptr ) );
|
||||
Add( ListenerType( objhandle, fnptr ) );
|
||||
}
|
||||
|
||||
void Remove( void* objhandle, typename ListenerType::FuncType* fnptr )
|
||||
{
|
||||
Remove( Handle( objhandle, fnptr ) );
|
||||
Remove( ListenerType( objhandle, fnptr ) );
|
||||
}
|
||||
|
||||
void Dispatch( const wxCommandEvent& evt ) const
|
||||
void Dispatch( const EvtType& evt ) const
|
||||
{
|
||||
Handle iter = m_listeners.begin();
|
||||
while( iter != m_listeners.end() )
|
||||
// Have to make a complete copy of the list, because the event stack can change:
|
||||
|
||||
ListenerList list( m_listeners );
|
||||
|
||||
typename ListenerList::const_iterator iter = list.begin();
|
||||
while( iter != list.end() )
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -108,7 +112,10 @@ public:
|
|||
}
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
if( IsDevBuild ) throw;
|
||||
Console.Error( L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage() );
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -175,8 +175,8 @@ namespace Threading
|
|||
// To use this as a base class for your threaded procedure, overload the following virtual
|
||||
// methods:
|
||||
// void OnStart();
|
||||
// void ExecuteTask();
|
||||
// void OnThreadCleanup();
|
||||
// void ExecuteTaskInThread();
|
||||
// void OnCleanupInThread();
|
||||
//
|
||||
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
|
||||
// m_sem_event internally to post/receive events for the thread (make a public accessor for
|
||||
|
@ -229,10 +229,10 @@ namespace Threading
|
|||
// Start() once necessary locks have been obtained. Do not override Start() directly
|
||||
// unless you're really sure that's what you need to do. ;)
|
||||
virtual void OnStart()=0;
|
||||
virtual void OnThreadCleanup()=0;
|
||||
virtual void OnCleanupInThread()=0;
|
||||
|
||||
// Implemented by derived class to handle threading actions!
|
||||
virtual void ExecuteTask()=0;
|
||||
virtual void ExecuteTaskInThread()=0;
|
||||
|
||||
// Inserts a thread cancellation point. If the thread has received a cancel request, this
|
||||
// function will throw an SEH exception designed to exit the thread (so make sure to use C++
|
||||
|
@ -372,7 +372,7 @@ namespace Threading
|
|||
// all your necessary processing work here.
|
||||
virtual void Task()=0;
|
||||
|
||||
virtual void ExecuteTask();
|
||||
virtual void ExecuteTaskInThread();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace Threading
|
|||
// Remarks:
|
||||
// Provision of non-blocking Cancel() is probably academic, since destroying a PersistentThread
|
||||
// object performs a blocking Cancel regardless of if you explicitly do a non-blocking Cancel()
|
||||
// prior, since the ExecuteTask() method requires a valid object state. If you really need
|
||||
// prior, since the ExecuteTaskInThread() method requires a valid object state. If you really need
|
||||
// fire-and-forget behavior on threads, use pthreads directly for now.
|
||||
//
|
||||
// This function should not be called from the owner thread.
|
||||
|
@ -263,7 +263,7 @@ namespace Threading
|
|||
}
|
||||
|
||||
// invoked internally when canceling or exiting the thread. Extending classes should implement
|
||||
// OnThreadCleanup() to extend cleanup functionality.
|
||||
// OnCleanupInThread() to extend cleanup functionality.
|
||||
void PersistentThread::_ThreadCleanup()
|
||||
{
|
||||
pxAssertMsg( IsSelf(), "Thread affinity error." ); // only allowed from our own thread, thanks.
|
||||
|
@ -273,7 +273,7 @@ namespace Threading
|
|||
// derived class is implemented.
|
||||
ScopedLock startlock( m_lock_start );
|
||||
|
||||
_try_virtual_invoke( &PersistentThread::OnThreadCleanup );
|
||||
_try_virtual_invoke( &PersistentThread::OnCleanupInThread );
|
||||
|
||||
m_running = false;
|
||||
m_sem_finished.Post();
|
||||
|
@ -288,11 +288,11 @@ namespace Threading
|
|||
{
|
||||
m_running = true;
|
||||
_DoSetThreadName( m_name );
|
||||
_try_virtual_invoke( &PersistentThread::ExecuteTask );
|
||||
_try_virtual_invoke( &PersistentThread::ExecuteTaskInThread );
|
||||
}
|
||||
|
||||
void PersistentThread::OnStart() {}
|
||||
void PersistentThread::OnThreadCleanup() {}
|
||||
void PersistentThread::OnCleanupInThread() {}
|
||||
|
||||
// passed into pthread_create, and is used to dispatch the thread's object oriented
|
||||
// callback function
|
||||
|
@ -391,7 +391,7 @@ namespace Threading
|
|||
m_post_TaskComplete.Reset();
|
||||
}
|
||||
|
||||
void BaseTaskThread::ExecuteTask()
|
||||
void BaseTaskThread::ExecuteTaskInThread()
|
||||
{
|
||||
while( !m_Done )
|
||||
{
|
||||
|
|
|
@ -128,7 +128,7 @@ FILE *_cdvdOpenNVM()
|
|||
fd = fopen(file.data(), "wb");
|
||||
if (fd == NULL)
|
||||
{
|
||||
Console.Error( "\tMEC File Creation failed!" );
|
||||
Console.Error( "\tNVM File Creation failed!" );
|
||||
throw Exception::CreateStream( file );
|
||||
}
|
||||
for (int i=0; i<1024; i++) fputc(0, fd);
|
||||
|
|
|
@ -442,7 +442,7 @@ __forceinline void rcntUpdate_vSync()
|
|||
if (vsyncCounter.Mode == MODE_VSYNC)
|
||||
{
|
||||
eeRecIsReset = false;
|
||||
mtgsThread.PollStatus();
|
||||
mtgsThread.RethrowException();
|
||||
SysCoreThread::Get().StateCheck();
|
||||
if( eeRecIsReset )
|
||||
{
|
||||
|
|
|
@ -126,9 +126,7 @@ public:
|
|||
mtgsThreadObject();
|
||||
virtual ~mtgsThreadObject() throw();
|
||||
|
||||
void Start();
|
||||
void OnStart();
|
||||
void PollStatus();
|
||||
|
||||
// Waits for the GS to empty out the entire ring buffer contents.
|
||||
// Used primarily for plugin startup/shutdown.
|
||||
|
@ -167,7 +165,7 @@ protected:
|
|||
// Used internally by SendSimplePacket type functions
|
||||
uint _PrepForSimplePacket();
|
||||
void _FinishSimplePacket( uint future_writepos );
|
||||
void ExecuteTask();
|
||||
void ExecuteTaskInThread();
|
||||
};
|
||||
|
||||
extern __aligned16 mtgsThreadObject mtgsThread;
|
||||
|
|
|
@ -110,13 +110,6 @@ mtgsThreadObject::mtgsThreadObject() :
|
|||
m_name = L"MTGS";
|
||||
}
|
||||
|
||||
void mtgsThreadObject::Start()
|
||||
{
|
||||
_parent::Start();
|
||||
m_ExecMode = ExecMode_Suspending;
|
||||
SetEvent();
|
||||
}
|
||||
|
||||
void mtgsThreadObject::OnStart()
|
||||
{
|
||||
gsIsOpened = false;
|
||||
|
@ -130,12 +123,10 @@ void mtgsThreadObject::OnStart()
|
|||
m_packet_size = 0;
|
||||
m_packet_ringpos = 0;
|
||||
|
||||
_parent::OnStart();
|
||||
}
|
||||
m_CopyCommandTally = 0;
|
||||
m_CopyDataTally = 0;
|
||||
|
||||
void mtgsThreadObject::PollStatus()
|
||||
{
|
||||
RethrowException();
|
||||
_parent::OnStart();
|
||||
}
|
||||
|
||||
mtgsThreadObject::~mtgsThreadObject() throw()
|
||||
|
@ -244,7 +235,7 @@ void mtgsThreadObject::OpenPlugin()
|
|||
GSsetGameCRC( ElfCRC, 0 );
|
||||
}
|
||||
|
||||
void mtgsThreadObject::ExecuteTask()
|
||||
void mtgsThreadObject::ExecuteTaskInThread()
|
||||
{
|
||||
#ifdef RINGBUF_DEBUG_STACK
|
||||
PacketTagType prevCmd;
|
||||
|
@ -444,7 +435,7 @@ void mtgsThreadObject::WaitGS()
|
|||
{
|
||||
pxAssertDev( !IsSelf(), "This method is only allowed from threads *not* named MTGS." );
|
||||
|
||||
if( IsSuspended() ) return;
|
||||
if( !pxAssertDev( m_ExecMode == ExecMode_Running, "MTGS Warning! WaitGS issued on a suspended/paused thread." ) ) return;
|
||||
|
||||
// FIXME : Use semaphores instead of spinwaits.
|
||||
SetEvent();
|
||||
|
|
|
@ -114,7 +114,7 @@ vtlbHandler tlb_fallback_8;
|
|||
vtlbHandler vu0_micro_mem[2]; // 0 - dynarec, 1 - interpreter
|
||||
vtlbHandler vu1_micro_mem[2]; // 0 - dynarec, 1 - interpreter
|
||||
|
||||
vtlbHandler hw_by_page[0x10];
|
||||
vtlbHandler hw_by_page[0x10] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
vtlbHandler gs_page_0;
|
||||
vtlbHandler gs_page_1;
|
||||
|
||||
|
@ -599,6 +599,19 @@ void memShutdown()
|
|||
vtlb_Term();
|
||||
}
|
||||
|
||||
void memBindConditionalHandlers()
|
||||
{
|
||||
if( hw_by_page[0xf] == -1 ) return;
|
||||
|
||||
vtlbMemR32FP* page0F32( EmuConfig.Speedhacks.IntcStat ? hwRead32_page_0F_INTC_HACK : hwRead32_page_0F );
|
||||
vtlbMemR64FP* page0F64( EmuConfig.Speedhacks.IntcStat ? hwRead64_generic_INTC_HACK : hwRead64_generic );
|
||||
|
||||
vtlb_ReassignHandler( hw_by_page[0xf],
|
||||
_ext_memRead8<1>, _ext_memRead16<1>, page0F32, page0F64, hwRead128_generic,
|
||||
_ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0F, hwWrite64_generic, hwWrite128_generic
|
||||
);
|
||||
}
|
||||
|
||||
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
|
||||
void memReset()
|
||||
{
|
||||
|
@ -724,13 +737,8 @@ void memReset()
|
|||
_ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0E, hwWrite64_page_0E, hwWrite128_generic
|
||||
);
|
||||
|
||||
vtlbMemR32FP* page0F32( EmuConfig.Speedhacks.IntcStat ? hwRead32_page_0F_INTC_HACK : hwRead32_page_0F );
|
||||
vtlbMemR64FP* page0F64( EmuConfig.Speedhacks.IntcStat ? hwRead64_generic_INTC_HACK : hwRead64_generic );
|
||||
|
||||
hw_by_page[0xf] = vtlb_RegisterHandler(
|
||||
_ext_memRead8<1>, _ext_memRead16<1>, page0F32, page0F64, hwRead128_generic,
|
||||
_ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0F, hwWrite64_generic, hwWrite128_generic
|
||||
);
|
||||
hw_by_page[0xf] = vtlb_NewHandler();
|
||||
memBindConditionalHandlers();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// GS Optimized Mappings
|
||||
|
|
|
@ -127,6 +127,7 @@ extern void memSetSupervisorMode();
|
|||
extern void memSetUserMode();
|
||||
extern void memSetPageAddr(u32 vaddr, u32 paddr);
|
||||
extern void memClearPageAddr(u32 vaddr);
|
||||
extern void memBindConditionalHandlers();
|
||||
|
||||
extern void memMapVUmicro();
|
||||
|
||||
|
|
|
@ -915,7 +915,7 @@ void PluginManager::Open()
|
|||
} while( ++pi, pi->shortname != NULL );
|
||||
|
||||
if (GSopen2) mtgsThread.WaitForOpen();
|
||||
mtgsThread.PollStatus();
|
||||
mtgsThread.RethrowException();
|
||||
|
||||
Console.Status( "Plugins opened successfully." );
|
||||
}
|
||||
|
|
|
@ -58,7 +58,9 @@ R5900Exception::BaseExcept::~BaseExcept() throw (){}
|
|||
|
||||
void cpuReset()
|
||||
{
|
||||
mtgsWaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||
if( mtgsThread.IsExecMode_Running() )
|
||||
mtgsWaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||
|
||||
cpuIsInitialized = true;
|
||||
|
||||
memReset();
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "zlib/zlib.h"
|
||||
|
||||
class _BaseStateThread;
|
||||
|
||||
static SafeArray<u8> state_buffer;
|
||||
|
||||
|
@ -33,6 +34,12 @@ bool sys_resume_lock = false;
|
|||
|
||||
static FnType_OnThreadComplete* Callback_FreezeFinished = NULL;
|
||||
|
||||
static void StateThread_OnAppStatus( void* thr, const enum AppStatusEvent& stat )
|
||||
{
|
||||
if( (thr == NULL) || (stat != AppStatus_Exiting) ) return;
|
||||
((PersistentThread*)thr)->Cancel();
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
StateThreadAction_None = 0,
|
||||
|
@ -46,6 +53,9 @@ class _BaseStateThread : public PersistentThread
|
|||
{
|
||||
typedef PersistentThread _parent;
|
||||
|
||||
protected:
|
||||
EventListenerBinding<AppStatusEvent> m_bind_OnExit;
|
||||
|
||||
public:
|
||||
virtual ~_BaseStateThread() throw()
|
||||
{
|
||||
|
@ -53,7 +63,8 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
_BaseStateThread( const char* name, FnType_OnThreadComplete* onFinished )
|
||||
_BaseStateThread( const char* name, FnType_OnThreadComplete* onFinished ) :
|
||||
m_bind_OnExit( wxGetApp().Source_AppStatus(), EventListener<AppStatusEvent>( this, StateThread_OnAppStatus ) )
|
||||
{
|
||||
Callback_FreezeFinished = onFinished;
|
||||
m_name = L"StateThread::" + fromUTF8(name);
|
||||
|
@ -94,18 +105,18 @@ protected:
|
|||
{
|
||||
_parent::OnStart();
|
||||
sys_resume_lock = true;
|
||||
sCoreThread.Pause();
|
||||
CoreThread.Pause();
|
||||
}
|
||||
|
||||
void ExecuteTask()
|
||||
void ExecuteTaskInThread()
|
||||
{
|
||||
memSavingState( state_buffer ).FreezeAll();
|
||||
}
|
||||
|
||||
void OnThreadCleanup()
|
||||
void OnCleanupInThread()
|
||||
{
|
||||
SendFinishEvent( StateThreadAction_Create );
|
||||
_parent::OnThreadCleanup();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -131,18 +142,18 @@ protected:
|
|||
}
|
||||
|
||||
sys_resume_lock = true;
|
||||
sCoreThread.Pause();
|
||||
CoreThread.Pause();
|
||||
}
|
||||
|
||||
void ExecuteTask()
|
||||
void ExecuteTaskInThread()
|
||||
{
|
||||
memLoadingState( state_buffer ).FreezeAll();
|
||||
}
|
||||
|
||||
void OnThreadCleanup()
|
||||
void OnCleanupInThread()
|
||||
{
|
||||
SendFinishEvent( StateThreadAction_Restore );
|
||||
_parent::OnThreadCleanup();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -179,17 +190,28 @@ protected:
|
|||
throw Exception::CreateStream( m_filename, "Cannot create savestate file for writing." );
|
||||
}
|
||||
|
||||
void ExecuteTask()
|
||||
void ExecuteTaskInThread()
|
||||
{
|
||||
Yield( 2 );
|
||||
if( gzwrite( (gzFile)m_gzfp, state_buffer.GetPtr(), state_buffer.GetSizeInBytes() ) < state_buffer.GetSizeInBytes() )
|
||||
throw Exception::BadStream();
|
||||
Yield( 3 );
|
||||
//if( gzwrite( m_gzfp, state_buffer.GetPtr(), state_buffer.GetSizeInBytes() ) < state_buffer.GetSizeInBytes() )
|
||||
// throw Exception::BadStream();
|
||||
|
||||
static const int BlockSize = 0x10000;
|
||||
int curidx = 0;
|
||||
do
|
||||
{
|
||||
int thisBlockSize = std::min( BlockSize, state_buffer.GetSizeInBytes() - curidx );
|
||||
if( gzwrite( m_gzfp, state_buffer.GetPtr(curidx), thisBlockSize ) < thisBlockSize )
|
||||
throw Exception::BadStream( m_filename );
|
||||
curidx += BlockSize;
|
||||
Yield( 1 );
|
||||
} while( curidx < state_buffer.GetSizeInBytes() );
|
||||
}
|
||||
|
||||
void OnThreadCleanup()
|
||||
void OnCleanupInThread()
|
||||
{
|
||||
SendFinishEvent( StateThreadAction_ZipToDisk );
|
||||
_parent::OnThreadCleanup();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -233,7 +255,7 @@ protected:
|
|||
throw Exception::CreateStream( m_filename, "Cannot open savestate file for reading." );
|
||||
}
|
||||
|
||||
void ExecuteTask()
|
||||
void ExecuteTaskInThread()
|
||||
{
|
||||
// fixme: should start initially with the file size, and then grow from there.
|
||||
|
||||
|
@ -250,10 +272,10 @@ protected:
|
|||
m_finished = true;
|
||||
}
|
||||
|
||||
void OnThreadCleanup()
|
||||
void OnCleanupInThread()
|
||||
{
|
||||
SendFinishEvent( StateThreadAction_UnzipFromDisk );
|
||||
_parent::OnThreadCleanup();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -288,7 +310,7 @@ void OnFinished_Resume( const wxCommandEvent& evt )
|
|||
SysClearExecutionCache();
|
||||
}
|
||||
|
||||
sCoreThread.Resume();
|
||||
CoreThread.Resume();
|
||||
}
|
||||
|
||||
static wxString zip_dest_filename;
|
||||
|
@ -304,7 +326,9 @@ void OnFinished_ZipToDisk( const wxCommandEvent& evt )
|
|||
}
|
||||
|
||||
// Phase 2: Record to disk!!
|
||||
(new StateThread_ZipToDisk( OnFinished_Resume, zip_dest_filename ))->Start();
|
||||
(new StateThread_ZipToDisk( NULL, zip_dest_filename ))->Start();
|
||||
|
||||
CoreThread.Resume();
|
||||
}
|
||||
|
||||
void OnFinished_Restore( const wxCommandEvent& evt )
|
||||
|
@ -331,7 +355,7 @@ void StateCopy_SaveToFile( const wxString& file )
|
|||
void StateCopy_LoadFromFile( const wxString& file )
|
||||
{
|
||||
if( state_buffer_lock.IsLocked() ) return;
|
||||
sCoreThread.Pause();
|
||||
CoreThread.Pause();
|
||||
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
||||
}
|
||||
|
||||
|
@ -341,6 +365,8 @@ void StateCopy_LoadFromFile( const wxString& file )
|
|||
// the one in the memory save. :)
|
||||
void StateCopy_SaveToSlot( uint num )
|
||||
{
|
||||
if( state_buffer_lock.IsLocked() ) return;
|
||||
|
||||
zip_dest_filename = SaveStateBase::GetFilename( num );
|
||||
(new StateThread_Freeze( OnFinished_ZipToDisk ))->Start();
|
||||
Console.Status( "Saving savestate to slot %d...", num );
|
||||
|
@ -361,7 +387,7 @@ void StateCopy_LoadFromSlot( uint slot )
|
|||
Console.Status( "Loading savestate from slot %d...", slot );
|
||||
Console.Status( wxsFormat(L"\tfilename: %s", file.c_str()) );
|
||||
|
||||
sCoreThread.Pause();
|
||||
CoreThread.Pause();
|
||||
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
||||
}
|
||||
|
||||
|
@ -392,9 +418,21 @@ void StateCopy_ThawFromMem()
|
|||
new StateThread_Thaw( OnFinished_Restore );
|
||||
}
|
||||
|
||||
void State_ThawFromMem_Blocking()
|
||||
{
|
||||
if( !state_buffer_lock.TryLock() )
|
||||
|
||||
memLoadingState( state_buffer ).FreezeAll();
|
||||
state_buffer_lock.Release();
|
||||
}
|
||||
|
||||
void StateCopy_Clear()
|
||||
{
|
||||
if( state_buffer_lock.IsLocked() ) return;
|
||||
state_buffer.Dispose();
|
||||
}
|
||||
|
||||
bool StateCopy_IsBusy()
|
||||
{
|
||||
return state_buffer_lock.IsLocked();
|
||||
}
|
|
@ -359,14 +359,10 @@ memSavingState::memSavingState( SafeArray<u8>& save_to ) :
|
|||
// Saving of state data
|
||||
void memSavingState::FreezeMem( void* data, int size )
|
||||
{
|
||||
const int end = m_idx+size;
|
||||
m_memory.MakeRoomFor( end );
|
||||
|
||||
u8* dest = (u8*)m_memory.GetPtr();
|
||||
const u8* src = (u8*)data;
|
||||
|
||||
for( ; m_idx<end; ++m_idx, ++src )
|
||||
dest[m_idx] = *src;
|
||||
u8* const dest = m_memory.GetPtr(m_idx);
|
||||
m_idx += size;
|
||||
m_memory.MakeRoomFor( m_idx );
|
||||
memcpy_fast( dest, data, size );
|
||||
}
|
||||
|
||||
memLoadingState::memLoadingState( const SafeArray<u8>& load_from ) :
|
||||
|
@ -379,10 +375,7 @@ memLoadingState::~memLoadingState() { }
|
|||
// Loading of state data
|
||||
void memLoadingState::FreezeMem( void* data, int size )
|
||||
{
|
||||
const int end = m_idx+size;
|
||||
const u8* src = (u8*)m_memory.GetPtr();
|
||||
u8* dest = (u8*)data;
|
||||
|
||||
for( ; m_idx<end; ++m_idx, ++dest )
|
||||
*dest = src[m_idx];
|
||||
const u8* const src = m_memory.GetPtr(m_idx);
|
||||
m_idx += size;
|
||||
memcpy_fast( data, src, size );
|
||||
}
|
||||
|
|
|
@ -204,4 +204,4 @@ extern void StateCopy_LoadFromFile( const wxString& file );
|
|||
extern void StateCopy_SaveToSlot( uint num );
|
||||
extern void StateCopy_LoadFromSlot( uint slot );
|
||||
extern void StateCopy_Clear();
|
||||
|
||||
extern bool StateCopy_IsBusy();
|
||||
|
|
|
@ -45,6 +45,14 @@ SysSuspendableThread::~SysSuspendableThread() throw()
|
|||
{
|
||||
}
|
||||
|
||||
void SysSuspendableThread::Start()
|
||||
{
|
||||
_parent::Start();
|
||||
m_ExecMode = ExecMode_Suspending;
|
||||
m_sem_event.Post();
|
||||
}
|
||||
|
||||
|
||||
void SysSuspendableThread::OnStart()
|
||||
{
|
||||
if( !pxAssertDev( m_ExecMode == ExecMode_NoThreadYet, "SysSustainableThread:Start(): Invalid execution mode" ) ) return;
|
||||
|
@ -65,51 +73,68 @@ void SysSuspendableThread::OnStart()
|
|||
// is mostly useful for starting certain non-Emu related gui activities (improves gui
|
||||
// responsiveness).
|
||||
//
|
||||
// Returns:
|
||||
// The previous suspension state; true if the thread was running or false if it was
|
||||
// suspended.
|
||||
//
|
||||
// Exceptions:
|
||||
// CancelEvent - thrown if the thread is already in a Paused state. Because actions that
|
||||
// pause emulation typically rely on plugins remaining loaded/active, Suspension must
|
||||
// cansel itself forcefully or risk crashing whatever other action is in progress.
|
||||
//
|
||||
void SysSuspendableThread::Suspend( bool isBlocking )
|
||||
bool SysSuspendableThread::Suspend( bool isBlocking )
|
||||
{
|
||||
if( IsSelf() || !IsRunning() ) return;
|
||||
if( IsSelf() || !IsRunning() ) return false;
|
||||
|
||||
bool retval = false;
|
||||
|
||||
{
|
||||
ScopedLock locker( m_lock_ExecMode );
|
||||
|
||||
if( m_ExecMode == ExecMode_Suspended )
|
||||
return;
|
||||
return false;
|
||||
|
||||
if( m_ExecMode == ExecMode_Pausing || m_ExecMode == ExecMode_Paused )
|
||||
throw Exception::CancelEvent( "Another thread is pausing the VM state." );
|
||||
|
||||
if( m_ExecMode == ExecMode_Running )
|
||||
{
|
||||
m_ExecMode = ExecMode_Suspending;
|
||||
retval = true;
|
||||
}
|
||||
|
||||
pxAssertDev( m_ExecMode == ExecMode_Suspending, "ExecMode should be nothing other than Suspending..." );
|
||||
}
|
||||
m_SuspendEvent.Reset();
|
||||
m_sem_event.Post();
|
||||
if( isBlocking ) m_SuspendEvent.WaitGui();
|
||||
return retval;
|
||||
}
|
||||
|
||||
void SysSuspendableThread::Pause()
|
||||
bool SysSuspendableThread::Pause()
|
||||
{
|
||||
if( IsSelf() || !IsRunning() ) return;
|
||||
if( IsSelf() || !IsRunning() ) return false;
|
||||
|
||||
bool retval = false;
|
||||
|
||||
{
|
||||
ScopedLock locker( m_lock_ExecMode );
|
||||
|
||||
if( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Paused) ) return;
|
||||
if( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Paused) ) return false;
|
||||
|
||||
if( m_ExecMode == ExecMode_Running )
|
||||
{
|
||||
m_ExecMode = ExecMode_Pausing;
|
||||
retval = true;
|
||||
}
|
||||
|
||||
pxAssertDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
|
||||
}
|
||||
m_SuspendEvent.Reset();
|
||||
m_sem_event.Post();
|
||||
m_SuspendEvent.WaitGui();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Resumes the core execution state, or does nothing is the core is already running. If
|
||||
|
@ -151,10 +176,10 @@ void SysSuspendableThread::Resume()
|
|||
pxAssertDev( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Paused),
|
||||
"SysSuspendableThread is not in a suspended/paused state? wtf!" );
|
||||
|
||||
m_ExecMode = ExecMode_Running;
|
||||
m_ResumeProtection = true;
|
||||
OnResumeReady();
|
||||
m_ResumeProtection = false;
|
||||
m_ExecMode = ExecMode_Running;
|
||||
m_ResumeEvent.Post();
|
||||
}
|
||||
|
||||
|
@ -164,11 +189,11 @@ void SysSuspendableThread::Resume()
|
|||
// (Called from the context of this thread only)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
void SysSuspendableThread::OnThreadCleanup()
|
||||
void SysSuspendableThread::OnCleanupInThread()
|
||||
{
|
||||
ScopedLock locker( m_lock_ExecMode );
|
||||
m_ExecMode = ExecMode_NoThreadYet;
|
||||
_parent::OnThreadCleanup();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
|
||||
void SysSuspendableThread::StateCheck( bool isCancelable )
|
||||
|
@ -244,11 +269,11 @@ void SysSuspendableThread::StateCheck( bool isCancelable )
|
|||
// (Called form outside the context of this thread)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
SysCoreThread::SysCoreThread( PluginManager& plugins ) :
|
||||
m_resetRecompilers( false )
|
||||
, m_resetProfilers( false )
|
||||
, m_shortSuspend( false )
|
||||
, m_plugins( plugins )
|
||||
SysCoreThread::SysCoreThread() :
|
||||
m_resetRecompilers( true )
|
||||
, m_resetProfilers( true )
|
||||
, m_resetVirtualMachine( true )
|
||||
, m_hasValidState( false )
|
||||
{
|
||||
m_name = L"EE Core";
|
||||
}
|
||||
|
@ -260,7 +285,8 @@ SysCoreThread::~SysCoreThread() throw()
|
|||
|
||||
void SysCoreThread::Start()
|
||||
{
|
||||
m_plugins.Init();
|
||||
if( g_plugins == NULL ) return;
|
||||
g_plugins->Init();
|
||||
_parent::Start();
|
||||
}
|
||||
|
||||
|
@ -275,16 +301,28 @@ void SysCoreThread::Start()
|
|||
//
|
||||
void SysCoreThread::OnResumeReady()
|
||||
{
|
||||
if( m_shortSuspend ) return;
|
||||
if( m_resetVirtualMachine )
|
||||
{
|
||||
cpuReset();
|
||||
m_resetVirtualMachine = false;
|
||||
m_hasValidState = false;
|
||||
}
|
||||
|
||||
if( m_resetRecompilers || m_resetProfilers )
|
||||
if( m_resetRecompilers || m_resetProfilers || !m_hasValidState )
|
||||
{
|
||||
SysClearExecutionCache();
|
||||
memBindConditionalHandlers();
|
||||
m_resetRecompilers = false;
|
||||
m_resetProfilers = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SysCoreThread::Reset()
|
||||
{
|
||||
Suspend();
|
||||
m_resetVirtualMachine = true;
|
||||
}
|
||||
|
||||
// Applies a full suite of new settings, which will automatically facilitate the necessary
|
||||
// resets of the core and components (including plugins, if needed). The scope of resetting
|
||||
// is determined by comparing the current settings against the new settings.
|
||||
|
@ -292,11 +330,12 @@ void SysCoreThread::ApplySettings( const Pcsx2Config& src )
|
|||
{
|
||||
if( src == EmuConfig ) return;
|
||||
|
||||
const bool resumeWhenDone = !m_ResumeProtection && !IsSuspended();
|
||||
if( !m_ResumeProtection ) Suspend();
|
||||
// Suspend only if ResumeProtection is false:
|
||||
const bool resumeWhenDone = !m_ResumeProtection && Suspend();
|
||||
|
||||
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
|
||||
m_resetProfilers = (src.Profiler != EmuConfig.Profiler );
|
||||
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
|
||||
m_resetProfilers = (src.Profiler != EmuConfig.Profiler );
|
||||
|
||||
const_cast<Pcsx2Config&>(EmuConfig) = src;
|
||||
|
||||
if( resumeWhenDone ) Resume();
|
||||
|
@ -314,55 +353,44 @@ SysCoreThread& SysCoreThread::Get()
|
|||
|
||||
void SysCoreThread::CpuInitializeMess()
|
||||
{
|
||||
cpuReset();
|
||||
SysClearExecutionCache();
|
||||
|
||||
if( StateCopy_IsValid() )
|
||||
if( m_hasValidState ) return;
|
||||
|
||||
wxString elf_file;
|
||||
if( EmuConfig.SkipBiosSplash )
|
||||
{
|
||||
// no need to boot bios or detect CDs when loading savestates.
|
||||
// [TODO] : It might be useful to detect game SLUS/CRC and compare it against
|
||||
// the savestate info, and issue a warning to the user since, chances are, they
|
||||
// don't really want to run a game with the wrong ISO loaded into the emu.
|
||||
StateCopy_ThawFromMem();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxString elf_file;
|
||||
if( EmuConfig.SkipBiosSplash )
|
||||
// Fetch the ELF filename and CD type from the CDVD provider.
|
||||
wxString ename;
|
||||
int result = GetPS2ElfName( ename );
|
||||
switch( result )
|
||||
{
|
||||
// Fetch the ELF filename and CD type from the CDVD provider.
|
||||
wxString ename;
|
||||
int result = GetPS2ElfName( ename );
|
||||
switch( result )
|
||||
{
|
||||
case 0:
|
||||
throw Exception::RuntimeError( wxLt("Fast Boot failed: CDVD image is not a PS1 or PS2 game.") );
|
||||
case 0:
|
||||
throw Exception::RuntimeError( wxLt("Fast Boot failed: CDVD image is not a PS1 or PS2 game.") );
|
||||
|
||||
case 1:
|
||||
throw Exception::RuntimeError( wxLt("Fast Boot failed: PCSX2 does not support emulation of PS1 games.") );
|
||||
case 1:
|
||||
throw Exception::RuntimeError( wxLt("Fast Boot failed: PCSX2 does not support emulation of PS1 games.") );
|
||||
|
||||
case 2:
|
||||
// PS2 game. Valid!
|
||||
elf_file = ename;
|
||||
break;
|
||||
case 2:
|
||||
// PS2 game. Valid!
|
||||
elf_file = ename;
|
||||
break;
|
||||
|
||||
jNO_DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
if( !elf_file.IsEmpty() )
|
||||
{
|
||||
// Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF
|
||||
// executable data, and injects the cpuRegs.pc with the address of the
|
||||
// execution start point.
|
||||
//
|
||||
// This hack is necessary for non-CD ELF files, and is optional for game CDs
|
||||
// (though not recommended for games because of rare ill side effects).
|
||||
|
||||
cpuExecuteBios();
|
||||
loadElfFile( elf_file );
|
||||
jNO_DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
if( !elf_file.IsEmpty() )
|
||||
{
|
||||
// Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF
|
||||
// executable data, and injects the cpuRegs.pc with the address of the
|
||||
// execution start point.
|
||||
//
|
||||
// This hack is necessary for non-CD ELF files, and is optional for game CDs
|
||||
// (though not recommended for games because of rare ill side effects).
|
||||
|
||||
cpuExecuteBios();
|
||||
loadElfFile( elf_file );
|
||||
}
|
||||
m_hasValidState = true;
|
||||
}
|
||||
|
||||
// special macro which disables inlining on functions that require their own function stackframe.
|
||||
|
@ -384,33 +412,36 @@ void SysCoreThread::CpuExecute()
|
|||
PCSX2_MEM_PROTECT_END();
|
||||
}
|
||||
|
||||
void SysCoreThread::ExecuteTask()
|
||||
void SysCoreThread::ExecuteTaskInThread()
|
||||
{
|
||||
tls_coreThread = this;
|
||||
|
||||
StateCheck();
|
||||
CpuInitializeMess();
|
||||
m_sem_event.Wait();
|
||||
StateCheck();
|
||||
CpuExecute();
|
||||
}
|
||||
|
||||
void SysCoreThread::OnSuspendInThread()
|
||||
{
|
||||
if( !m_shortSuspend )
|
||||
m_plugins.Close();
|
||||
if( g_plugins == NULL ) return;
|
||||
g_plugins->Close();
|
||||
}
|
||||
|
||||
void SysCoreThread::OnResumeInThread( bool isSuspended )
|
||||
{
|
||||
if( isSuspended )
|
||||
m_plugins.Open();
|
||||
if( isSuspended && g_plugins != NULL )
|
||||
{
|
||||
CpuInitializeMess();
|
||||
g_plugins->Open();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Invoked by the pthread_exit or pthread_cancel
|
||||
void SysCoreThread::OnThreadCleanup()
|
||||
void SysCoreThread::OnCleanupInThread()
|
||||
{
|
||||
m_plugins.Shutdown();
|
||||
_parent::OnThreadCleanup();
|
||||
//if( g_plugins != NULL )
|
||||
// g_plugins->Shutdown();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ public:
|
|||
ISysThread() {}
|
||||
virtual ~ISysThread() throw() {};
|
||||
|
||||
virtual bool IsSuspended() const { return false; }
|
||||
virtual void Suspend( bool isBlocking = true ) { }
|
||||
virtual bool Suspend( bool isBlocking = true ) { return false; }
|
||||
virtual bool Pause() { return false; }
|
||||
virtual void Resume() {}
|
||||
};
|
||||
|
||||
|
@ -57,14 +57,14 @@ public:
|
|||
explicit SysSuspendableThread();
|
||||
virtual ~SysSuspendableThread() throw();
|
||||
|
||||
bool IsSuspended() const { return (m_ExecMode == ExecMode_Suspended); }
|
||||
bool IsExecMode_Running() const { return m_ExecMode == ExecMode_Running; }
|
||||
|
||||
virtual void Suspend( bool isBlocking = true );
|
||||
virtual bool Suspend( bool isBlocking = true );
|
||||
virtual void Resume();
|
||||
virtual void Pause();
|
||||
|
||||
virtual bool Pause();
|
||||
|
||||
virtual void StateCheck( bool isCancelable = true );
|
||||
virtual void OnThreadCleanup();
|
||||
virtual void OnCleanupInThread();
|
||||
|
||||
// This function is called by Resume immediately prior to releasing the suspension of
|
||||
// the core emulation thread. You should overload this rather than Resume(), since
|
||||
|
@ -74,7 +74,10 @@ public:
|
|||
virtual void OnStart();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
// Used internally from Resume(), so let's make it private here.
|
||||
virtual void Start();
|
||||
|
||||
// Extending classes should implement this, but should not call it. The parent class
|
||||
// handles invocation by the following guidelines: Called *in thread* from StateCheck()
|
||||
// prior to suspending the thread (ie, when Suspend() has been called on a separate
|
||||
|
@ -108,19 +111,24 @@ class SysCoreThread : public SysSuspendableThread
|
|||
protected:
|
||||
bool m_resetRecompilers;
|
||||
bool m_resetProfilers;
|
||||
bool m_shortSuspend;
|
||||
PluginManager& m_plugins;
|
||||
bool m_resetVirtualMachine;
|
||||
bool m_hasValidState;
|
||||
|
||||
public:
|
||||
static SysCoreThread& Get();
|
||||
|
||||
public:
|
||||
explicit SysCoreThread( PluginManager& plugins );
|
||||
explicit SysCoreThread();
|
||||
virtual ~SysCoreThread() throw();
|
||||
|
||||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
virtual void OnThreadCleanup();
|
||||
virtual void OnResumeReady();
|
||||
virtual void Reset();
|
||||
|
||||
bool HasValidState()
|
||||
{
|
||||
return m_hasValidState;
|
||||
}
|
||||
|
||||
protected:
|
||||
void CpuInitializeMess();
|
||||
|
@ -130,5 +138,6 @@ protected:
|
|||
virtual void OnSuspendInThread();
|
||||
virtual void OnPauseInThread() {}
|
||||
virtual void OnResumeInThread( bool IsSuspended );
|
||||
virtual void ExecuteTask();
|
||||
virtual void OnCleanupInThread();
|
||||
virtual void ExecuteTaskInThread();
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ BEGIN_DECLARE_EVENT_TYPES()
|
|||
DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_SysExecute, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_LoadPluginsComplete, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_AppCoreThreadFinished, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_CoreThreadStatus, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_FreezeThreadFinished, -1 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
|
@ -159,6 +159,12 @@ enum DialogIdentifiers
|
|||
DialogId_About,
|
||||
};
|
||||
|
||||
enum AppStatusEvent
|
||||
{
|
||||
// Maybe this will be expanded upon later..?
|
||||
AppStatus_Exiting
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// KeyAcceleratorCode
|
||||
// A custom keyboard accelerator that I like better than wx's wxAcceleratorEntry.
|
||||
|
@ -324,7 +330,6 @@ protected:
|
|||
public:
|
||||
ScopedPtr<SysCoreAllocations> m_CoreAllocs;
|
||||
ScopedPtr<PluginManager> m_CorePlugins;
|
||||
ScopedPtr<SysCoreThread> m_CoreThread;
|
||||
|
||||
protected:
|
||||
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
|
||||
|
@ -345,7 +350,7 @@ public:
|
|||
int ThreadedModalDialog( DialogIdentifiers dialogId );
|
||||
void Ping() const;
|
||||
|
||||
bool PrepForExit();
|
||||
bool PrepForExit( bool canCancel );
|
||||
|
||||
void SysExecute();
|
||||
void SysExecute( CDVD_SourceType cdvdsrc );
|
||||
|
@ -358,13 +363,8 @@ public:
|
|||
const AppImageIds& GetImgId() const { return m_ImageId; }
|
||||
|
||||
MainEmuFrame& GetMainFrame() const;
|
||||
SysCoreThread& GetCoreThread() const;
|
||||
|
||||
MainEmuFrame* GetMainFramePtr() const { return m_MainFrame; }
|
||||
bool HasMainFrame() const { return m_MainFrame != NULL; }
|
||||
bool HasCoreThread() const { return m_CoreThread != NULL; }
|
||||
|
||||
MainEmuFrame* GetMainFramePtr() const { return m_MainFrame; }
|
||||
SysCoreThread* GetCoreThreadPtr() const { return m_CoreThread; }
|
||||
|
||||
void OpenGsFrame();
|
||||
void OnGsFrameClosed();
|
||||
|
@ -402,10 +402,12 @@ public:
|
|||
protected:
|
||||
CmdEvt_Source m_evtsrc_CorePluginStatus;
|
||||
CmdEvt_Source m_evtsrc_CoreThreadStatus;
|
||||
EventSource<AppStatusEvent> m_evtsrc_AppStatus;
|
||||
|
||||
public:
|
||||
CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; }
|
||||
CmdEvt_Source& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; }
|
||||
EventSource<AppStatusEvent>& Source_AppStatus() { return m_evtsrc_AppStatus; }
|
||||
|
||||
protected:
|
||||
void InitDefaultGlobalAccelerators();
|
||||
|
@ -422,7 +424,7 @@ protected:
|
|||
void OnLoadPluginsComplete( wxCommandEvent& evt );
|
||||
void OnSemaphorePing( wxCommandEvent& evt );
|
||||
void OnOpenModalDialog( wxCommandEvent& evt );
|
||||
void OnCoreThreadTerminated( wxCommandEvent& evt );
|
||||
void OnCoreThreadStatus( wxCommandEvent& evt );
|
||||
|
||||
void OnFreezeThreadFinished( wxCommandEvent& evt );
|
||||
|
||||
|
@ -449,6 +451,13 @@ protected:
|
|||
// AppCoreThread class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
enum CoreThreadStatus
|
||||
{
|
||||
CoreStatus_Resumed,
|
||||
CoreStatus_Suspended,
|
||||
CoreStatus_Stopped,
|
||||
};
|
||||
|
||||
class AppCoreThread : public SysCoreThread
|
||||
{
|
||||
typedef SysCoreThread _parent;
|
||||
|
@ -457,18 +466,18 @@ protected:
|
|||
wxKeyEvent m_kevt;
|
||||
|
||||
public:
|
||||
AppCoreThread( PluginManager& plugins );
|
||||
AppCoreThread();
|
||||
virtual ~AppCoreThread() throw();
|
||||
|
||||
virtual void Suspend( bool isBlocking=true );
|
||||
virtual bool Suspend( bool isBlocking=true );
|
||||
virtual void Resume();
|
||||
virtual void StateCheck( bool isCancelable=true );
|
||||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
|
||||
protected:
|
||||
virtual void OnResumeReady();
|
||||
virtual void OnThreadCleanup();
|
||||
virtual void ExecuteTask();
|
||||
virtual void OnCleanupInThread();
|
||||
virtual void ExecuteTaskInThread();
|
||||
};
|
||||
|
||||
DECLARE_APP(Pcsx2App)
|
||||
|
@ -481,8 +490,8 @@ DECLARE_APP(Pcsx2App)
|
|||
// not be invoked, and an optional "else" clause cn be affixed for handling the end case.
|
||||
//
|
||||
// Usage Examples:
|
||||
// sCoreThread.Suspend(); // Suspends the CoreThread, or does nothing if the CoreThread handle is NULL
|
||||
// sCoreThread.Suspend(); else Console.WriteLn( "Judge Wapner" ); // 'else' clause for handling NULL scenarios.
|
||||
// sMainFrame.ApplySettings();
|
||||
// sMainFrame.ApplySettings(); else Console.WriteLn( "Judge Wapner" ); // 'else' clause for handling NULL scenarios.
|
||||
//
|
||||
// Note! These macros are not "syntax complete", which means they could generat unexpected
|
||||
// syntax errors in some situatins, and more importantly they cannot be used for invoking
|
||||
|
@ -497,9 +506,6 @@ DECLARE_APP(Pcsx2App)
|
|||
#define sApp \
|
||||
if( Pcsx2App* __app_ = (Pcsx2App*)wxApp::GetInstance() ) (*__app_)
|
||||
|
||||
#define sCoreThread \
|
||||
if( SysCoreThread* __thread_ = GetCoreThreadPtr() ) (*__thread_)
|
||||
|
||||
#define sMainFrame \
|
||||
if( MainEmuFrame* __frame_ = GetMainFramePtr() ) (*__frame_)
|
||||
|
||||
|
@ -523,11 +529,8 @@ extern bool SysHasValidState();
|
|||
|
||||
extern void SysStatus( const wxString& text );
|
||||
|
||||
extern bool HasMainFrame();
|
||||
extern bool HasCoreThread();
|
||||
|
||||
extern bool HasMainFrame();
|
||||
extern MainEmuFrame& GetMainFrame();
|
||||
extern SysCoreThread& GetCoreThread();
|
||||
|
||||
extern MainEmuFrame* GetMainFramePtr();
|
||||
extern SysCoreThread* GetCoreThreadPtr();
|
||||
|
||||
extern AppCoreThread CoreThread;
|
|
@ -525,8 +525,7 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite )
|
|||
AppLoadSettings();
|
||||
|
||||
AppApplySettings();
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ReloadRecentLists();
|
||||
sMainFrame.ReloadRecentLists();
|
||||
|
||||
g_Conf->Folders.Logs.Mkdir();
|
||||
|
||||
|
|
|
@ -16,8 +16,9 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "MainFrame.h"
|
||||
|
||||
AppCoreThread::AppCoreThread( PluginManager& plugins ) :
|
||||
SysCoreThread( plugins )
|
||||
AppCoreThread CoreThread;
|
||||
|
||||
AppCoreThread::AppCoreThread() : SysCoreThread()
|
||||
, m_kevt()
|
||||
{
|
||||
}
|
||||
|
@ -26,11 +27,13 @@ AppCoreThread::~AppCoreThread() throw()
|
|||
{
|
||||
}
|
||||
|
||||
void AppCoreThread::Suspend( bool isBlocking )
|
||||
bool AppCoreThread::Suspend( bool isBlocking )
|
||||
{
|
||||
_parent::Suspend( isBlocking );
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ApplySettings();
|
||||
bool retval = _parent::Suspend( isBlocking );
|
||||
|
||||
wxCommandEvent evt( pxEVT_CoreThreadStatus );
|
||||
evt.SetInt( CoreStatus_Suspended );
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
|
||||
// Clear the sticky key statuses, because hell knows what'll change while the PAD
|
||||
// plugin is suspended.
|
||||
|
@ -38,6 +41,8 @@ void AppCoreThread::Suspend( bool isBlocking )
|
|||
m_kevt.m_shiftDown = false;
|
||||
m_kevt.m_controlDown = false;
|
||||
m_kevt.m_altDown = false;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void AppCoreThread::Resume()
|
||||
|
@ -55,26 +60,28 @@ void AppCoreThread::Resume()
|
|||
|
||||
void AppCoreThread::OnResumeReady()
|
||||
{
|
||||
if( m_shortSuspend ) return;
|
||||
|
||||
ApplySettings( g_Conf->EmuOptions );
|
||||
|
||||
if( GSopen2 != NULL )
|
||||
wxGetApp().OpenGsFrame();
|
||||
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ApplySettings();
|
||||
wxCommandEvent evt( pxEVT_CoreThreadStatus );
|
||||
evt.SetInt( CoreStatus_Resumed );
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
|
||||
_parent::OnResumeReady();
|
||||
}
|
||||
|
||||
// Called whenever the thread has terminated, for either regular or irregular reasons.
|
||||
// Typically the thread handles all its own errors, so there's no need to have error
|
||||
// handling here. However it's a good idea to update the status of the GUI to reflect
|
||||
// the new (lack of) thread status, so this posts a message to the App to do so.
|
||||
void AppCoreThread::OnThreadCleanup()
|
||||
void AppCoreThread::OnCleanupInThread()
|
||||
{
|
||||
wxCommandEvent evt( pxEVT_AppCoreThreadFinished );
|
||||
wxCommandEvent evt( pxEVT_CoreThreadStatus );
|
||||
evt.SetInt( CoreStatus_Stopped );
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
_parent::OnThreadCleanup();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
|
||||
#ifdef __WXGTK__
|
||||
|
@ -84,11 +91,12 @@ void AppCoreThread::OnThreadCleanup()
|
|||
void AppCoreThread::StateCheck( bool isCancelable )
|
||||
{
|
||||
_parent::StateCheck( isCancelable );
|
||||
if( !pxAssert(g_plugins!=NULL) ) return;
|
||||
|
||||
const keyEvent* ev = PADkeyEvent();
|
||||
if( ev == NULL || (ev->key == 0) ) return;
|
||||
|
||||
m_plugins.KeyEvent( *ev );
|
||||
g_plugins->KeyEvent( *ev );
|
||||
m_kevt.SetEventType( ( ev->evt == KEYPRESS ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP );
|
||||
const bool isDown = (ev->evt == KEYPRESS);
|
||||
|
||||
|
@ -116,7 +124,8 @@ void AppCoreThread::StateCheck( bool isCancelable )
|
|||
// suspended. If the thread has mot been suspended, this call will fail *silently*.
|
||||
void AppCoreThread::ApplySettings( const Pcsx2Config& src )
|
||||
{
|
||||
if( !IsSuspended() ) return;
|
||||
if( m_ExecMode != ExecMode_Suspended ) return;
|
||||
if( src == EmuConfig ) return;
|
||||
|
||||
// Re-entry guard protects against cases where code wants to manually set core settings
|
||||
// which are not part of g_Conf. The subsequent call to apply g_Conf settings (which is
|
||||
|
@ -128,19 +137,18 @@ void AppCoreThread::ApplySettings( const Pcsx2Config& src )
|
|||
SysCoreThread::ApplySettings( src );
|
||||
}
|
||||
|
||||
void AppCoreThread::ExecuteTask()
|
||||
void AppCoreThread::ExecuteTaskInThread()
|
||||
{
|
||||
try
|
||||
{
|
||||
SysCoreThread::ExecuteTask();
|
||||
SysCoreThread::ExecuteTaskInThread();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::FileNotFound& ex )
|
||||
{
|
||||
m_plugins.Close();
|
||||
if( g_plugins != NULL ) g_plugins->Close();
|
||||
if( ex.StreamName == g_Conf->FullpathToBios() )
|
||||
{
|
||||
m_plugins.Close();
|
||||
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
||||
_("\n\nPress Ok to go to the BIOS Configuration Panel.") );
|
||||
|
||||
|
@ -160,7 +168,7 @@ void AppCoreThread::ExecuteTask()
|
|||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::PluginError& ex )
|
||||
{
|
||||
m_plugins.Close();
|
||||
if( g_plugins != NULL ) g_plugins->Close();
|
||||
Console.Error( ex.FormatDiagnosticMessage() );
|
||||
Msgbox::Alert( ex.FormatDisplayMessage(), _("Plugin Open Error") );
|
||||
|
||||
|
@ -176,7 +184,7 @@ void AppCoreThread::ExecuteTask()
|
|||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
// Sent the exception back to the main gui thread?
|
||||
m_plugins.Close();
|
||||
if( g_plugins != NULL ) g_plugins->Close();
|
||||
Msgbox::Alert( ex.FormatDisplayMessage() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ bool Pcsx2App::OnInit()
|
|||
|
||||
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
|
||||
|
||||
Connect( pxEVT_AppCoreThreadFinished, wxCommandEventHandler( Pcsx2App::OnCoreThreadTerminated ) );
|
||||
Connect( pxEVT_CoreThreadStatus, wxCommandEventHandler( Pcsx2App::OnCoreThreadStatus ) );
|
||||
Connect( pxEVT_FreezeThreadFinished, wxCommandEventHandler( Pcsx2App::OnFreezeThreadFinished ) );
|
||||
|
||||
Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
|
||||
|
@ -335,11 +335,10 @@ bool Pcsx2App::OnInit()
|
|||
|
||||
void Pcsx2App::CleanupMess()
|
||||
{
|
||||
CoreThread.Cancel();
|
||||
|
||||
if( m_CorePlugins )
|
||||
{
|
||||
m_CorePlugins->Close();
|
||||
m_CorePlugins->Shutdown();
|
||||
}
|
||||
|
||||
// Notice: deleting the plugin manager (unloading plugins) here causes Lilypad to crash,
|
||||
// likely due to some pending message in the queue that references lilypad procs.
|
||||
|
|
|
@ -32,7 +32,7 @@ DEFINE_EVENT_TYPE( pxEVT_OpenModalDialog );
|
|||
DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins );
|
||||
DEFINE_EVENT_TYPE( pxEVT_SysExecute );
|
||||
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
|
||||
DEFINE_EVENT_TYPE( pxEVT_AppCoreThreadFinished );
|
||||
DEFINE_EVENT_TYPE( pxEVT_CoreThreadStatus );
|
||||
DEFINE_EVENT_TYPE( pxEVT_FreezeThreadFinished );
|
||||
|
||||
bool UseAdminMode = false;
|
||||
|
@ -118,13 +118,13 @@ void Pcsx2App::Ping() const
|
|||
// Pcsx2App Event Handlers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Invoked by the AppCoreThread when the thread has terminated itself.
|
||||
void Pcsx2App::OnCoreThreadTerminated( wxCommandEvent& evt )
|
||||
// Invoked by the AppCoreThread when it's internal status has changed.
|
||||
// evt.GetInt() reflects the status at the time the message was sent, which may differ
|
||||
// from the actual status. Typically listeners bound to this will want to use direct
|
||||
// polling of the CoreThread rather than the belated status.
|
||||
void Pcsx2App::OnCoreThreadStatus( wxCommandEvent& evt )
|
||||
{
|
||||
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ApplySettings();
|
||||
m_CoreThread = NULL;
|
||||
m_evtsrc_CoreThreadStatus.Dispatch( evt );
|
||||
}
|
||||
|
||||
void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt )
|
||||
|
@ -220,7 +220,7 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
|
|||
{
|
||||
// Saved state load failed.
|
||||
Console.Notice( ex.FormatDiagnosticMessage() );
|
||||
sCoreThread.Resume();
|
||||
CoreThread.Resume();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::PluginError& ex )
|
||||
|
@ -243,6 +243,14 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
|
|||
}
|
||||
}
|
||||
|
||||
static void OnStateSaveFinished( void* obj, const wxCommandEvent& evt )
|
||||
{
|
||||
if( evt.GetInt() == CoreStatus_Resumed )
|
||||
{
|
||||
wxGetApp().PostMenuAction( MenuId_Exit );
|
||||
wxGetApp().Source_CoreThreadStatus().Remove( NULL, OnStateSaveFinished );
|
||||
}
|
||||
}
|
||||
|
||||
// Common exit handler which can be called from any event (though really it should
|
||||
// be called only from CloseWindow handlers since that's the more appropriate way
|
||||
|
@ -250,17 +258,37 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
|
|||
//
|
||||
// returns true if the app can close, or false if the close event was canceled by
|
||||
// the glorious user, whomever (s)he-it might be.
|
||||
bool Pcsx2App::PrepForExit()
|
||||
bool Pcsx2App::PrepForExit( bool canCancel )
|
||||
{
|
||||
m_CoreThread = NULL;
|
||||
CleanupMess();
|
||||
// If a savestate is saving, we should wait until it finishes. Otherwise the user
|
||||
// might lose data.
|
||||
|
||||
if( StateCopy_IsBusy() )
|
||||
{
|
||||
Source_CoreThreadStatus().Add( NULL, OnStateSaveFinished );
|
||||
throw Exception::CancelEvent( "Savestate in progress, cannot close program (close event delayed)" );
|
||||
}
|
||||
|
||||
if( canCancel )
|
||||
{
|
||||
bool resume = CoreThread.Suspend();
|
||||
if( /* TODO: Confirm with the user? */ false )
|
||||
{
|
||||
if(resume) CoreThread.Resume();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_evtsrc_AppStatus.Dispatch( AppStatus_Exiting );
|
||||
CleanupMess();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int Pcsx2App::OnExit()
|
||||
{
|
||||
PrepForExit();
|
||||
CleanupMess();
|
||||
|
||||
if( g_Conf )
|
||||
AppSaveSettings();
|
||||
|
@ -283,16 +311,6 @@ MainEmuFrame& Pcsx2App::GetMainFrame() const
|
|||
return *m_MainFrame;
|
||||
}
|
||||
|
||||
// This method generates debug assertions if the CoreThread handle is NULL (typically
|
||||
// indicating that there is no active emulation session). In most cases you'll want
|
||||
// to use HasCoreThread() to test for thread validity first, or use GetCoreThreadPtr()
|
||||
// and manually check for NULL (choice is a matter of programmer preference).
|
||||
SysCoreThread& Pcsx2App::GetCoreThread() const
|
||||
{
|
||||
pxAssert( m_CoreThread != NULL );
|
||||
return *m_CoreThread;
|
||||
}
|
||||
|
||||
void AppApplySettings( const AppConfig* oldconf )
|
||||
{
|
||||
AllowFromMainThreadOnly();
|
||||
|
@ -306,6 +324,8 @@ void AppApplySettings( const AppConfig* oldconf )
|
|||
|
||||
g_Conf->EmuOptions.BiosFilename = g_Conf->FullpathToBios();
|
||||
|
||||
bool resume = CoreThread.Suspend();
|
||||
|
||||
// Update the compression attribute on the Memcards folder.
|
||||
// Memcards generally compress very well via NTFS compression.
|
||||
|
||||
|
@ -323,10 +343,10 @@ void AppApplySettings( const AppConfig* oldconf )
|
|||
}
|
||||
}
|
||||
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ApplySettings();
|
||||
if( HasCoreThread() )
|
||||
GetCoreThread().ApplySettings( g_Conf->EmuOptions );
|
||||
CoreThread.ApplySettings( g_Conf->EmuOptions );
|
||||
|
||||
if( resume )
|
||||
CoreThread.Resume();
|
||||
}
|
||||
|
||||
void AppLoadSettings()
|
||||
|
@ -368,8 +388,7 @@ void Pcsx2App::OpenGsFrame()
|
|||
|
||||
void Pcsx2App::OnGsFrameClosed()
|
||||
{
|
||||
if( m_CoreThread != NULL )
|
||||
m_CoreThread->Suspend();
|
||||
CoreThread.Suspend();
|
||||
m_gsFrame = NULL;
|
||||
}
|
||||
|
||||
|
@ -446,17 +465,16 @@ void Pcsx2App::OnSysExecute( wxCommandEvent& evt )
|
|||
// it, because apparently too much stuff is going on and the emulation states are wonky.
|
||||
if( !m_CorePlugins ) return;
|
||||
|
||||
if( evt.GetInt() != -1 ) SysReset();
|
||||
if( evt.GetInt() != -1 ) SysReset(); else CoreThread.Suspend();
|
||||
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
||||
if( evt.GetInt() != -1 ) CDVDsys_ChangeSource( (CDVD_SourceType)evt.GetInt() );
|
||||
|
||||
m_CoreThread = new AppCoreThread( *m_CorePlugins );
|
||||
m_CoreThread->Resume();
|
||||
CoreThread.Resume();
|
||||
}
|
||||
|
||||
void Pcsx2App::SysReset()
|
||||
{
|
||||
m_CoreThread = NULL;
|
||||
CoreThread.Reset();
|
||||
}
|
||||
|
||||
// Returns true if there is a "valid" virtual machine state from the user's perspective. This
|
||||
|
@ -466,8 +484,7 @@ void Pcsx2App::SysReset()
|
|||
// state (such as saving it), you *must* suspend the Corethread first!
|
||||
__forceinline bool SysHasValidState()
|
||||
{
|
||||
bool isRunning = HasCoreThread() ? GetCoreThread().IsRunning() : false;
|
||||
return isRunning || StateCopy_HasFullState();
|
||||
return CoreThread.HasValidState() || StateCopy_HasFullState();
|
||||
}
|
||||
|
||||
// Writes text to console and updates the window status bar and/or HUD or whateverness.
|
||||
|
@ -476,8 +493,7 @@ void SysStatus( const wxString& text )
|
|||
{
|
||||
// mirror output to the console!
|
||||
Console.Status( text.c_str() );
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().SetStatusText( text );
|
||||
sMainFrame.SetStatusText( text );
|
||||
}
|
||||
|
||||
bool HasMainFrame()
|
||||
|
@ -485,11 +501,6 @@ bool HasMainFrame()
|
|||
return wxTheApp && wxGetApp().HasMainFrame();
|
||||
}
|
||||
|
||||
bool HasCoreThread()
|
||||
{
|
||||
return wxTheApp && wxGetApp().HasCoreThread();
|
||||
}
|
||||
|
||||
// This method generates debug assertions if either the wxApp or MainFrame handles are
|
||||
// NULL (typically indicating that PCSX2 is running in NoGUI mode, or that the main
|
||||
// frame has been closed). In most cases you'll want to use HasMainFrame() to test
|
||||
|
@ -500,11 +511,6 @@ MainEmuFrame& GetMainFrame()
|
|||
return wxGetApp().GetMainFrame();
|
||||
}
|
||||
|
||||
SysCoreThread& GetCoreThread()
|
||||
{
|
||||
return wxGetApp().GetCoreThread();
|
||||
}
|
||||
|
||||
// Returns a pointer to the main frame of the GUI (frame may be hidden from view), or
|
||||
// NULL if no main frame exists (NoGUI mode and/or the frame has been destroyed). If
|
||||
// the wxApp is NULL then this will also return NULL.
|
||||
|
@ -512,10 +518,3 @@ MainEmuFrame* GetMainFramePtr()
|
|||
{
|
||||
return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL;
|
||||
}
|
||||
|
||||
// Returns a pointer to the CoreThread of the GUI (thread may be stopped or suspended),
|
||||
// or NULL if no core thread exists, or if the wxApp is also NULL.
|
||||
SysCoreThread* GetCoreThreadPtr()
|
||||
{
|
||||
return wxTheApp ? wxGetApp().GetCoreThreadPtr() : NULL;
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ void pxLogConsole::DoLog( wxLogLevel level, const wxChar *szString, time_t t )
|
|||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void ConsoleTestThread::ExecuteTask()
|
||||
void ConsoleTestThread::ExecuteTaskInThread()
|
||||
{
|
||||
static int numtrack = 0;
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class ConsoleTestThread : public Threading::PersistentThread
|
|||
{
|
||||
protected:
|
||||
volatile bool m_done;
|
||||
void ExecuteTask();
|
||||
void ExecuteTaskInThread();
|
||||
|
||||
public:
|
||||
ConsoleTestThread() :
|
||||
|
@ -85,7 +85,7 @@ public:
|
|||
|
||||
protected:
|
||||
void OnStart() {}
|
||||
void OnThreadCleanup() {}
|
||||
void OnCleanupInThread() {}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -54,8 +54,7 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title):
|
|||
|
||||
GSFrame::~GSFrame() throw()
|
||||
{
|
||||
if( HasCoreThread() )
|
||||
GetCoreThread().Suspend(); // Just in case...!
|
||||
CoreThread.Suspend(); // Just in case...!
|
||||
}
|
||||
|
||||
void GSFrame::OnCloseWindow(wxCloseEvent& evt)
|
||||
|
|
|
@ -71,14 +71,12 @@ namespace Implementations
|
|||
|
||||
void Sys_Suspend()
|
||||
{
|
||||
if( HasCoreThread() )
|
||||
GetCoreThread().Suspend();
|
||||
CoreThread.Suspend();
|
||||
}
|
||||
|
||||
void Sys_Resume()
|
||||
{
|
||||
if( HasCoreThread() )
|
||||
GetCoreThread().Resume();
|
||||
CoreThread.Resume();
|
||||
}
|
||||
|
||||
void Sys_TakeSnapshot()
|
||||
|
@ -88,10 +86,9 @@ namespace Implementations
|
|||
|
||||
void Sys_RenderToggle()
|
||||
{
|
||||
if( !HasCoreThread() ) return;
|
||||
sCoreThread.Suspend();
|
||||
bool resume = CoreThread.Suspend();
|
||||
renderswitch = !renderswitch;
|
||||
sCoreThread.Resume();
|
||||
if( resume ) CoreThread.Resume();
|
||||
}
|
||||
|
||||
void Sys_LoggingToggle()
|
||||
|
|
|
@ -149,7 +149,7 @@ void MainEmuFrame::OnCloseWindow(wxCloseEvent& evt)
|
|||
}
|
||||
else
|
||||
{
|
||||
isClosing = wxGetApp().PrepForExit();
|
||||
isClosing = wxGetApp().PrepForExit( evt.CanVeto() );
|
||||
if( !isClosing ) evt.Veto( true );
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,7 @@ void MainEmuFrame::ConnectMenus()
|
|||
ConnectMenu( MenuId_Exit, Menu_Exit_Click );
|
||||
|
||||
ConnectMenu( MenuId_Sys_SuspendResume, Menu_SuspendResume_Click );
|
||||
ConnectMenu( MenuId_Sys_Reset, Menu_EmuReset_Click );
|
||||
ConnectMenu( MenuId_Sys_Reset, Menu_SysReset_Click );
|
||||
|
||||
ConnectMenu( MenuId_State_LoadOther, Menu_LoadStateOther_Click );
|
||||
|
||||
|
@ -260,6 +260,13 @@ void MainEmuFrame::InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf )
|
|||
}
|
||||
}
|
||||
|
||||
static void OnCoreThreadStatusChanged( void* obj, const wxCommandEvent& evt )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||
mframe->ApplySettings();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
|
||||
wxFrame(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~(wxMAXIMIZE_BOX | wxRESIZE_BORDER) ),
|
||||
|
@ -286,7 +293,9 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
|
|||
m_LoadStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Load01 ) ),
|
||||
m_SaveStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Save01 ) ),
|
||||
|
||||
m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, MenuId_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) )
|
||||
m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, MenuId_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) ),
|
||||
|
||||
m_Listener_CoreThreadStatus( wxGetApp().Source_CoreThreadStatus(), CmdEvt_Listener( this, OnCoreThreadStatusChanged ) )
|
||||
{
|
||||
// ------------------------------------------------------------------------
|
||||
// Initial menubar setup. This needs to be done first so that the menu bar's visible size
|
||||
|
@ -495,8 +504,7 @@ void MainEmuFrame::ApplySettings()
|
|||
|
||||
GetMenuBar()->Enable( MenuId_Sys_SuspendResume, SysHasValidState() );
|
||||
|
||||
if( HasCoreThread() )
|
||||
GetMenuBar()->SetLabel( MenuId_Sys_SuspendResume, GetCoreThread().IsSuspended() ? _("Resume") :_("Suspend") );
|
||||
GetMenuBar()->SetLabel( MenuId_Sys_SuspendResume, CoreThread.IsExecMode_Running() ? _("Suspend") :_("Resume") );
|
||||
|
||||
if( m_RecentIsoList )
|
||||
{
|
||||
|
|
|
@ -47,22 +47,24 @@ protected:
|
|||
wxStatusBar& m_statusbar;
|
||||
wxStaticBitmap m_background;
|
||||
|
||||
wxMenuBar& m_menubar;
|
||||
wxMenuBar& m_menubar;
|
||||
|
||||
wxMenu& m_menuBoot;
|
||||
wxMenu& m_menuEmu;
|
||||
wxMenu& m_menuConfig;
|
||||
wxMenu& m_menuMisc;
|
||||
wxMenu& m_menuDebug;
|
||||
wxMenu& m_menuBoot;
|
||||
wxMenu& m_menuEmu;
|
||||
wxMenu& m_menuConfig;
|
||||
wxMenu& m_menuMisc;
|
||||
wxMenu& m_menuDebug;
|
||||
|
||||
wxMenu& m_menuVideo;
|
||||
wxMenu& m_menuAudio;
|
||||
wxMenu& m_menuPad;
|
||||
wxMenu& m_menuVideo;
|
||||
wxMenu& m_menuAudio;
|
||||
wxMenu& m_menuPad;
|
||||
|
||||
wxMenu& m_LoadStatesSubmenu;
|
||||
wxMenu& m_SaveStatesSubmenu;
|
||||
wxMenu& m_LoadStatesSubmenu;
|
||||
wxMenu& m_SaveStatesSubmenu;
|
||||
|
||||
wxMenuItem& m_MenuItem_Console;
|
||||
wxMenuItem& m_MenuItem_Console;
|
||||
|
||||
CmdEvt_ListenerBinding m_Listener_CoreThreadStatus;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// MainEmuFrame Constructors and Member Methods
|
||||
|
@ -107,7 +109,7 @@ protected:
|
|||
void Menu_Exit_Click(wxCommandEvent &event);
|
||||
|
||||
void Menu_SuspendResume_Click(wxCommandEvent &event);
|
||||
void Menu_EmuReset_Click(wxCommandEvent &event);
|
||||
void Menu_SysReset_Click(wxCommandEvent &event);
|
||||
|
||||
void Menu_ConfigPlugin_Click(wxCommandEvent &event);
|
||||
|
||||
|
|
|
@ -82,13 +82,13 @@ bool MainEmuFrame::_DoSelectIsoBrowser()
|
|||
|
||||
void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
||||
{
|
||||
sCoreThread.Suspend();
|
||||
CoreThread.Suspend();
|
||||
|
||||
if( !wxFileExists( g_Conf->CurrentIso ) )
|
||||
{
|
||||
if( !_DoSelectIsoBrowser() )
|
||||
{
|
||||
sCoreThread.Resume();
|
||||
CoreThread.Resume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
|||
|
||||
if( !result )
|
||||
{
|
||||
sCoreThread.Resume();
|
||||
CoreThread.Resume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -113,18 +113,18 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
|||
|
||||
void MainEmuFrame::Menu_IsoBrowse_Click( wxCommandEvent &event )
|
||||
{
|
||||
sCoreThread.Suspend();
|
||||
bool resume = CoreThread.Suspend();
|
||||
_DoSelectIsoBrowser();
|
||||
sCoreThread.Resume();
|
||||
if( resume ) CoreThread.Resume();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_RunIso_Click( wxCommandEvent &event )
|
||||
{
|
||||
sCoreThread.Suspend();
|
||||
CoreThread.Suspend();
|
||||
|
||||
if( !_DoSelectIsoBrowser() )
|
||||
{
|
||||
sCoreThread.Resume();
|
||||
CoreThread.Resume();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -190,23 +190,19 @@ void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
|
|||
void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event)
|
||||
{
|
||||
if( !SysHasValidState() ) return;
|
||||
if( SysCoreThread* thr = GetCoreThreadPtr() )
|
||||
{
|
||||
if( thr->IsSuspended() )
|
||||
thr->Resume();
|
||||
else
|
||||
thr->Suspend();
|
||||
}
|
||||
|
||||
if( !CoreThread.Suspend() )
|
||||
CoreThread.Resume();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_EmuReset_Click(wxCommandEvent &event)
|
||||
void MainEmuFrame::Menu_SysReset_Click(wxCommandEvent &event)
|
||||
{
|
||||
if( !SysHasValidState() ) return;
|
||||
bool wasSuspended = HasCoreThread() ? GetCoreThread().IsSuspended() : true;
|
||||
bool resume = CoreThread.Suspend();
|
||||
|
||||
sApp.SysReset();
|
||||
|
||||
if( !wasSuspended )
|
||||
if( resume )
|
||||
sApp.SysExecute();
|
||||
}
|
||||
|
||||
|
|
|
@ -412,8 +412,8 @@ namespace Panels
|
|||
|
||||
protected:
|
||||
void OnStart() {}
|
||||
void ExecuteTask();
|
||||
void OnThreadCleanup() {}
|
||||
void ExecuteTaskInThread();
|
||||
void OnCleanupInThread() {}
|
||||
};
|
||||
|
||||
// This panel contains all of the plugin combo boxes. We stick them
|
||||
|
|
|
@ -83,9 +83,10 @@ bool Panels::StaticApplyState::ApplyPage( int pageid, bool saveOnSuccess )
|
|||
// If an exception is thrown above, this code below won't get run.
|
||||
// (conveniently skipping any option application! :D)
|
||||
|
||||
// Note: apply first, then save -- in case the apply fails.
|
||||
|
||||
AppApplySettings( &confcopy );
|
||||
if( saveOnSuccess )
|
||||
AppSaveSettings();
|
||||
if( saveOnSuccess ) AppSaveSettings();
|
||||
}
|
||||
catch( Exception::CannotApplySettings& ex )
|
||||
{
|
||||
|
|
|
@ -310,7 +310,7 @@ void Panels::PluginSelectorPanel::Apply()
|
|||
|
||||
if( pi->shortname != NULL )
|
||||
{
|
||||
if( wxGetApp().m_CoreThread )
|
||||
if( CoreThread.IsRunning() )
|
||||
{
|
||||
// [TODO] : Post notice that this shuts down existing emulation, and may not safely recover.
|
||||
}
|
||||
|
@ -554,7 +554,7 @@ void Panels::PluginSelectorPanel::EnumThread::DoNextPlugin( int curidx )
|
|||
m_master.GetEventHandler()->AddPendingEvent( yay );
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::EnumThread::ExecuteTask()
|
||||
void Panels::PluginSelectorPanel::EnumThread::ExecuteTaskInThread()
|
||||
{
|
||||
DevCon.Status( "Plugin Enumeration Thread started..." );
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ public:
|
|||
|
||||
protected:
|
||||
void OnStart() {}
|
||||
void OnThreadCleanup();
|
||||
void ExecuteTask();
|
||||
void OnCleanupInThread();
|
||||
void ExecuteTaskInThread();
|
||||
};
|
||||
|
||||
LoadPluginsTask::~LoadPluginsTask() throw()
|
||||
|
@ -67,7 +67,7 @@ LoadPluginsTask::~LoadPluginsTask() throw()
|
|||
PersistentThread::Cancel();
|
||||
}
|
||||
|
||||
void LoadPluginsTask::ExecuteTask()
|
||||
void LoadPluginsTask::ExecuteTaskInThread()
|
||||
{
|
||||
wxGetApp().Ping();
|
||||
Yield(3);
|
||||
|
@ -78,13 +78,13 @@ void LoadPluginsTask::ExecuteTask()
|
|||
Result = PluginManager_Create( m_folders );
|
||||
}
|
||||
|
||||
void LoadPluginsTask::OnThreadCleanup()
|
||||
void LoadPluginsTask::OnCleanupInThread()
|
||||
{
|
||||
wxCommandEvent evt( pxEVT_LoadPluginsComplete );
|
||||
evt.SetClientData( this );
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
|
||||
_parent::OnThreadCleanup();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -127,7 +127,7 @@ static bool plugin_load_lock = false;
|
|||
void Pcsx2App::OnReloadPlugins( wxCommandEvent& evt )
|
||||
{
|
||||
if( plugin_load_lock ) return;
|
||||
m_CoreThread = NULL;
|
||||
CoreThread.Cancel();
|
||||
m_CorePlugins = NULL;
|
||||
|
||||
wxString passins[PluginId_Count];
|
||||
|
@ -203,7 +203,7 @@ void LoadPluginsImmediate()
|
|||
{
|
||||
if( g_plugins != NULL ) return;
|
||||
|
||||
wxGetApp().m_CoreThread = NULL;
|
||||
CoreThread.Cancel();
|
||||
|
||||
wxString passins[PluginId_Count];
|
||||
ConvertPluginFilenames( passins );
|
||||
|
@ -213,6 +213,6 @@ void LoadPluginsImmediate()
|
|||
|
||||
void UnloadPlugins()
|
||||
{
|
||||
wxGetApp().m_CoreThread = NULL;
|
||||
CoreThread.Cancel();
|
||||
wxGetApp().m_CorePlugins = NULL;
|
||||
}
|
||||
|
|
|
@ -309,20 +309,17 @@ void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { Console.
|
|||
// VTLB Public API -- Init/Term/RegisterHandler stuff
|
||||
//
|
||||
|
||||
// Registers a handler into the VTLB's internal handler array. The handler defines specific behavior
|
||||
// Assigns or re-assigns the callbacks for a VTLB memory handler. The handler defines specific behavior
|
||||
// for how memory pages bound to the handler are read from / written to. If any of the handler pointers
|
||||
// are NULL, the memory operations will be mapped to the BusError handler (thus generating BusError
|
||||
// exceptions if the emulated app attempts to access them).
|
||||
//
|
||||
// Note: All handlers persist across calls to vtlb_Reset(), but are wiped/invalidated by calls to vtlb_Init()
|
||||
//
|
||||
// Returns a handle for the newly created handler See .vtlb_MapHandler for use of the return value.
|
||||
vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128)
|
||||
void vtlb_ReassignHandler( vtlbHandler rv,
|
||||
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128 )
|
||||
{
|
||||
//write the code :p
|
||||
vtlbHandler rv=vtlbHandlerCount++;
|
||||
|
||||
vtlbdata.RWFT[0][0][rv] = (r8!=0) ? (void*)(r8): (void*)vtlbDefaultPhyRead8;
|
||||
vtlbdata.RWFT[1][0][rv] = (r16!=0) ? (void*)r16: (void*)vtlbDefaultPhyRead16;
|
||||
vtlbdata.RWFT[2][0][rv] = (r32!=0) ? (void*)r32: (void*)vtlbDefaultPhyRead32;
|
||||
|
@ -340,10 +337,32 @@ vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP
|
|||
vtlbdata.RWFT[2][1][rv] = (void*)((w32!=0) ? w32:vtlbDefaultPhyWrite32);
|
||||
vtlbdata.RWFT[3][1][rv] = (void*)((w64!=0) ? w64:vtlbDefaultPhyWrite64);
|
||||
vtlbdata.RWFT[4][1][rv] = (void*)((w128!=0) ? w128:vtlbDefaultPhyWrite128);
|
||||
}
|
||||
|
||||
vtlbHandler vtlb_NewHandler()
|
||||
{
|
||||
pxAssertDev( vtlbHandlerCount < 127, "VTLB allowed handler count exceeded!" );
|
||||
return vtlbHandlerCount++;
|
||||
}
|
||||
|
||||
// Registers a handler into the VTLB's internal handler array. The handler defines specific behavior
|
||||
// for how memory pages bound to the handler are read from / written to. If any of the handler pointers
|
||||
// are NULL, the memory operations will be mapped to the BusError handler (thus generating BusError
|
||||
// exceptions if the emulated app attempts to access them).
|
||||
//
|
||||
// Note: All handlers persist across calls to vtlb_Reset(), but are wiped/invalidated by calls to vtlb_Init()
|
||||
//
|
||||
// Returns a handle for the newly created handler See vtlb_MapHandler for use of the return value.
|
||||
//
|
||||
vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128)
|
||||
{
|
||||
vtlbHandler rv = vtlb_NewHandler();
|
||||
vtlb_ReassignHandler( rv, r8, r16, r32, r64, r128, w8, w16, w32, w64, w128 );
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Maps the given hander (created with vtlb_RegisterHandler) to the specified memory region.
|
||||
// New mappings always assume priority over previous mappings, so place "generic" mappings for
|
||||
|
|
15
pcsx2/vtlb.h
15
pcsx2/vtlb.h
|
@ -26,9 +26,18 @@ extern u8* vtlb_malloc( uint size, uint align );
|
|||
extern void vtlb_free( void* pmem, uint size );
|
||||
|
||||
|
||||
//physical stuff
|
||||
vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128);
|
||||
extern vtlbHandler vtlb_NewHandler();
|
||||
|
||||
extern vtlbHandler vtlb_RegisterHandler(
|
||||
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128
|
||||
);
|
||||
|
||||
extern void vtlb_ReassignHandler( vtlbHandler rv,
|
||||
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128
|
||||
);
|
||||
|
||||
|
||||
extern void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size);
|
||||
extern void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize=0);
|
||||
|
|
|
@ -169,7 +169,7 @@ public:
|
|||
protected:
|
||||
void OnStart() {}
|
||||
|
||||
void ExecuteTask()
|
||||
void ExecuteTaskInThread()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -188,7 +188,7 @@ protected:
|
|||
}
|
||||
}
|
||||
|
||||
void OnThreadCleanup() { }
|
||||
void OnCleanupInThread() { }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -309,6 +309,8 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
|
|||
}*/
|
||||
|
||||
IsOpened = true;
|
||||
lClocks = (cyclePtr!=NULL) ? *cyclePtr : 0;
|
||||
|
||||
try
|
||||
{
|
||||
SndBuffer::Init();
|
||||
|
|
|
@ -276,17 +276,23 @@ u32 TicksThread = 0;
|
|||
|
||||
__forceinline void TimeUpdate(u32 cClocks)
|
||||
{
|
||||
s32 dClocks = cClocks-lClocks;
|
||||
u32 dClocks = cClocks - lClocks;
|
||||
|
||||
// [Air]: Sanity Check
|
||||
// If for some reason our clock value seems way off base, just mix
|
||||
// out a little bit, skip the rest, and hope the ship "rights" itself later on.
|
||||
// Sanity Checks:
|
||||
// It's not totally uncommon for the IOP's clock to jump backwards a cycle or two, and in
|
||||
// such cases we just want to ignore the TimeUpdate call.
|
||||
|
||||
if( dClocks > (u32)-15 ) return;
|
||||
|
||||
// But if for some reason our clock value seems way off base (typically due to bad dma
|
||||
// timings from PCSX2), just mix out a little bit, skip the rest, and hope the ship
|
||||
// "rights" itself later on.
|
||||
|
||||
if( dClocks > TickInterval*SanityInterval )
|
||||
{
|
||||
ConLog( " * SPU2 > TimeUpdate Sanity Check (Tick Delta: %d) (PS2 Ticks: %d)\n", dClocks/TickInterval, cClocks/TickInterval );
|
||||
dClocks = TickInterval*SanityInterval;
|
||||
lClocks = cClocks-dClocks;
|
||||
dClocks = TickInterval * SanityInterval;
|
||||
lClocks = cClocks - dClocks;
|
||||
}
|
||||
|
||||
//UpdateDebugDialog();
|
||||
|
@ -350,8 +356,8 @@ __forceinline void TimeUpdate(u32 cClocks)
|
|||
}
|
||||
}
|
||||
|
||||
dClocks-=TickInterval;
|
||||
lClocks+=TickInterval;
|
||||
dClocks -= TickInterval;
|
||||
lClocks += TickInterval;
|
||||
Cycles++;
|
||||
|
||||
// Note: IOP does not use MMX regs, so no need to save them.
|
||||
|
|
Loading…
Reference in New Issue