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 Add( const ListenerType& listener );
|
||||||
virtual inline void RemoveObject( const void* object );
|
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 )
|
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();
|
// Have to make a complete copy of the list, because the event stack can change:
|
||||||
while( iter != m_listeners.end() )
|
|
||||||
|
ListenerList list( m_listeners );
|
||||||
|
|
||||||
|
typename ListenerList::const_iterator iter = list.begin();
|
||||||
|
while( iter != list.end() )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -108,7 +112,10 @@ public:
|
||||||
}
|
}
|
||||||
catch( Exception::BaseException& ex )
|
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
|
// To use this as a base class for your threaded procedure, overload the following virtual
|
||||||
// methods:
|
// methods:
|
||||||
// void OnStart();
|
// void OnStart();
|
||||||
// void ExecuteTask();
|
// void ExecuteTaskInThread();
|
||||||
// void OnThreadCleanup();
|
// void OnCleanupInThread();
|
||||||
//
|
//
|
||||||
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
|
// 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
|
// 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
|
// Start() once necessary locks have been obtained. Do not override Start() directly
|
||||||
// unless you're really sure that's what you need to do. ;)
|
// unless you're really sure that's what you need to do. ;)
|
||||||
virtual void OnStart()=0;
|
virtual void OnStart()=0;
|
||||||
virtual void OnThreadCleanup()=0;
|
virtual void OnCleanupInThread()=0;
|
||||||
|
|
||||||
// Implemented by derived class to handle threading actions!
|
// 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
|
// 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++
|
// 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.
|
// all your necessary processing work here.
|
||||||
virtual void Task()=0;
|
virtual void Task()=0;
|
||||||
|
|
||||||
virtual void ExecuteTask();
|
virtual void ExecuteTaskInThread();
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -122,7 +122,7 @@ namespace Threading
|
||||||
// Remarks:
|
// Remarks:
|
||||||
// Provision of non-blocking Cancel() is probably academic, since destroying a PersistentThread
|
// 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()
|
// 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.
|
// fire-and-forget behavior on threads, use pthreads directly for now.
|
||||||
//
|
//
|
||||||
// This function should not be called from the owner thread.
|
// 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
|
// 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()
|
void PersistentThread::_ThreadCleanup()
|
||||||
{
|
{
|
||||||
pxAssertMsg( IsSelf(), "Thread affinity error." ); // only allowed from our own thread, thanks.
|
pxAssertMsg( IsSelf(), "Thread affinity error." ); // only allowed from our own thread, thanks.
|
||||||
|
@ -273,7 +273,7 @@ namespace Threading
|
||||||
// derived class is implemented.
|
// derived class is implemented.
|
||||||
ScopedLock startlock( m_lock_start );
|
ScopedLock startlock( m_lock_start );
|
||||||
|
|
||||||
_try_virtual_invoke( &PersistentThread::OnThreadCleanup );
|
_try_virtual_invoke( &PersistentThread::OnCleanupInThread );
|
||||||
|
|
||||||
m_running = false;
|
m_running = false;
|
||||||
m_sem_finished.Post();
|
m_sem_finished.Post();
|
||||||
|
@ -288,11 +288,11 @@ namespace Threading
|
||||||
{
|
{
|
||||||
m_running = true;
|
m_running = true;
|
||||||
_DoSetThreadName( m_name );
|
_DoSetThreadName( m_name );
|
||||||
_try_virtual_invoke( &PersistentThread::ExecuteTask );
|
_try_virtual_invoke( &PersistentThread::ExecuteTaskInThread );
|
||||||
}
|
}
|
||||||
|
|
||||||
void PersistentThread::OnStart() {}
|
void PersistentThread::OnStart() {}
|
||||||
void PersistentThread::OnThreadCleanup() {}
|
void PersistentThread::OnCleanupInThread() {}
|
||||||
|
|
||||||
// passed into pthread_create, and is used to dispatch the thread's object oriented
|
// passed into pthread_create, and is used to dispatch the thread's object oriented
|
||||||
// callback function
|
// callback function
|
||||||
|
@ -391,7 +391,7 @@ namespace Threading
|
||||||
m_post_TaskComplete.Reset();
|
m_post_TaskComplete.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseTaskThread::ExecuteTask()
|
void BaseTaskThread::ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
while( !m_Done )
|
while( !m_Done )
|
||||||
{
|
{
|
||||||
|
|
|
@ -128,7 +128,7 @@ FILE *_cdvdOpenNVM()
|
||||||
fd = fopen(file.data(), "wb");
|
fd = fopen(file.data(), "wb");
|
||||||
if (fd == NULL)
|
if (fd == NULL)
|
||||||
{
|
{
|
||||||
Console.Error( "\tMEC File Creation failed!" );
|
Console.Error( "\tNVM File Creation failed!" );
|
||||||
throw Exception::CreateStream( file );
|
throw Exception::CreateStream( file );
|
||||||
}
|
}
|
||||||
for (int i=0; i<1024; i++) fputc(0, fd);
|
for (int i=0; i<1024; i++) fputc(0, fd);
|
||||||
|
|
|
@ -442,7 +442,7 @@ __forceinline void rcntUpdate_vSync()
|
||||||
if (vsyncCounter.Mode == MODE_VSYNC)
|
if (vsyncCounter.Mode == MODE_VSYNC)
|
||||||
{
|
{
|
||||||
eeRecIsReset = false;
|
eeRecIsReset = false;
|
||||||
mtgsThread.PollStatus();
|
mtgsThread.RethrowException();
|
||||||
SysCoreThread::Get().StateCheck();
|
SysCoreThread::Get().StateCheck();
|
||||||
if( eeRecIsReset )
|
if( eeRecIsReset )
|
||||||
{
|
{
|
||||||
|
|
|
@ -126,9 +126,7 @@ public:
|
||||||
mtgsThreadObject();
|
mtgsThreadObject();
|
||||||
virtual ~mtgsThreadObject() throw();
|
virtual ~mtgsThreadObject() throw();
|
||||||
|
|
||||||
void Start();
|
|
||||||
void OnStart();
|
void OnStart();
|
||||||
void PollStatus();
|
|
||||||
|
|
||||||
// Waits for the GS to empty out the entire ring buffer contents.
|
// Waits for the GS to empty out the entire ring buffer contents.
|
||||||
// Used primarily for plugin startup/shutdown.
|
// Used primarily for plugin startup/shutdown.
|
||||||
|
@ -167,7 +165,7 @@ protected:
|
||||||
// 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 );
|
||||||
void ExecuteTask();
|
void ExecuteTaskInThread();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern __aligned16 mtgsThreadObject mtgsThread;
|
extern __aligned16 mtgsThreadObject mtgsThread;
|
||||||
|
|
|
@ -110,13 +110,6 @@ mtgsThreadObject::mtgsThreadObject() :
|
||||||
m_name = L"MTGS";
|
m_name = L"MTGS";
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtgsThreadObject::Start()
|
|
||||||
{
|
|
||||||
_parent::Start();
|
|
||||||
m_ExecMode = ExecMode_Suspending;
|
|
||||||
SetEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
void mtgsThreadObject::OnStart()
|
void mtgsThreadObject::OnStart()
|
||||||
{
|
{
|
||||||
gsIsOpened = false;
|
gsIsOpened = false;
|
||||||
|
@ -130,12 +123,10 @@ void mtgsThreadObject::OnStart()
|
||||||
m_packet_size = 0;
|
m_packet_size = 0;
|
||||||
m_packet_ringpos = 0;
|
m_packet_ringpos = 0;
|
||||||
|
|
||||||
_parent::OnStart();
|
m_CopyCommandTally = 0;
|
||||||
}
|
m_CopyDataTally = 0;
|
||||||
|
|
||||||
void mtgsThreadObject::PollStatus()
|
_parent::OnStart();
|
||||||
{
|
|
||||||
RethrowException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mtgsThreadObject::~mtgsThreadObject() throw()
|
mtgsThreadObject::~mtgsThreadObject() throw()
|
||||||
|
@ -244,7 +235,7 @@ void mtgsThreadObject::OpenPlugin()
|
||||||
GSsetGameCRC( ElfCRC, 0 );
|
GSsetGameCRC( ElfCRC, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtgsThreadObject::ExecuteTask()
|
void mtgsThreadObject::ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
#ifdef RINGBUF_DEBUG_STACK
|
#ifdef RINGBUF_DEBUG_STACK
|
||||||
PacketTagType prevCmd;
|
PacketTagType prevCmd;
|
||||||
|
@ -444,7 +435,7 @@ void mtgsThreadObject::WaitGS()
|
||||||
{
|
{
|
||||||
pxAssertDev( !IsSelf(), "This method is only allowed from threads *not* named MTGS." );
|
pxAssertDev( !IsSelf(), "This method is only allowed from threads *not* named MTGS." );
|
||||||
|
|
||||||
if( IsSuspended() ) return;
|
if( !pxAssertDev( m_ExecMode == ExecMode_Running, "MTGS Warning! WaitGS issued on a suspended/paused thread." ) ) return;
|
||||||
|
|
||||||
// FIXME : Use semaphores instead of spinwaits.
|
// FIXME : Use semaphores instead of spinwaits.
|
||||||
SetEvent();
|
SetEvent();
|
||||||
|
|
|
@ -114,7 +114,7 @@ vtlbHandler tlb_fallback_8;
|
||||||
vtlbHandler vu0_micro_mem[2]; // 0 - dynarec, 1 - interpreter
|
vtlbHandler vu0_micro_mem[2]; // 0 - dynarec, 1 - interpreter
|
||||||
vtlbHandler vu1_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_0;
|
||||||
vtlbHandler gs_page_1;
|
vtlbHandler gs_page_1;
|
||||||
|
|
||||||
|
@ -599,6 +599,19 @@ void memShutdown()
|
||||||
vtlb_Term();
|
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.
|
// Resets memory mappings, unmaps TLBs, reloads bios roms, etc.
|
||||||
void memReset()
|
void memReset()
|
||||||
{
|
{
|
||||||
|
@ -724,13 +737,8 @@ void memReset()
|
||||||
_ext_memWrite8<1>, _ext_memWrite16<1>, hwWrite32_page_0E, hwWrite64_page_0E, hwWrite128_generic
|
_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 );
|
hw_by_page[0xf] = vtlb_NewHandler();
|
||||||
vtlbMemR64FP* page0F64( EmuConfig.Speedhacks.IntcStat ? hwRead64_generic_INTC_HACK : hwRead64_generic );
|
memBindConditionalHandlers();
|
||||||
|
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// GS Optimized Mappings
|
// GS Optimized Mappings
|
||||||
|
|
|
@ -127,6 +127,7 @@ extern void memSetSupervisorMode();
|
||||||
extern void memSetUserMode();
|
extern void memSetUserMode();
|
||||||
extern void memSetPageAddr(u32 vaddr, u32 paddr);
|
extern void memSetPageAddr(u32 vaddr, u32 paddr);
|
||||||
extern void memClearPageAddr(u32 vaddr);
|
extern void memClearPageAddr(u32 vaddr);
|
||||||
|
extern void memBindConditionalHandlers();
|
||||||
|
|
||||||
extern void memMapVUmicro();
|
extern void memMapVUmicro();
|
||||||
|
|
||||||
|
|
|
@ -915,7 +915,7 @@ void PluginManager::Open()
|
||||||
} while( ++pi, pi->shortname != NULL );
|
} while( ++pi, pi->shortname != NULL );
|
||||||
|
|
||||||
if (GSopen2) mtgsThread.WaitForOpen();
|
if (GSopen2) mtgsThread.WaitForOpen();
|
||||||
mtgsThread.PollStatus();
|
mtgsThread.RethrowException();
|
||||||
|
|
||||||
Console.Status( "Plugins opened successfully." );
|
Console.Status( "Plugins opened successfully." );
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,9 @@ R5900Exception::BaseExcept::~BaseExcept() throw (){}
|
||||||
|
|
||||||
void cpuReset()
|
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;
|
cpuIsInitialized = true;
|
||||||
|
|
||||||
memReset();
|
memReset();
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "zlib/zlib.h"
|
#include "zlib/zlib.h"
|
||||||
|
|
||||||
|
class _BaseStateThread;
|
||||||
|
|
||||||
static SafeArray<u8> state_buffer;
|
static SafeArray<u8> state_buffer;
|
||||||
|
|
||||||
|
@ -33,6 +34,12 @@ bool sys_resume_lock = false;
|
||||||
|
|
||||||
static FnType_OnThreadComplete* Callback_FreezeFinished = NULL;
|
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
|
enum
|
||||||
{
|
{
|
||||||
StateThreadAction_None = 0,
|
StateThreadAction_None = 0,
|
||||||
|
@ -46,6 +53,9 @@ class _BaseStateThread : public PersistentThread
|
||||||
{
|
{
|
||||||
typedef PersistentThread _parent;
|
typedef PersistentThread _parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
EventListenerBinding<AppStatusEvent> m_bind_OnExit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~_BaseStateThread() throw()
|
virtual ~_BaseStateThread() throw()
|
||||||
{
|
{
|
||||||
|
@ -53,7 +63,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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;
|
Callback_FreezeFinished = onFinished;
|
||||||
m_name = L"StateThread::" + fromUTF8(name);
|
m_name = L"StateThread::" + fromUTF8(name);
|
||||||
|
@ -94,18 +105,18 @@ protected:
|
||||||
{
|
{
|
||||||
_parent::OnStart();
|
_parent::OnStart();
|
||||||
sys_resume_lock = true;
|
sys_resume_lock = true;
|
||||||
sCoreThread.Pause();
|
CoreThread.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecuteTask()
|
void ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
memSavingState( state_buffer ).FreezeAll();
|
memSavingState( state_buffer ).FreezeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnThreadCleanup()
|
void OnCleanupInThread()
|
||||||
{
|
{
|
||||||
SendFinishEvent( StateThreadAction_Create );
|
SendFinishEvent( StateThreadAction_Create );
|
||||||
_parent::OnThreadCleanup();
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,18 +142,18 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
sys_resume_lock = true;
|
sys_resume_lock = true;
|
||||||
sCoreThread.Pause();
|
CoreThread.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecuteTask()
|
void ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
memLoadingState( state_buffer ).FreezeAll();
|
memLoadingState( state_buffer ).FreezeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnThreadCleanup()
|
void OnCleanupInThread()
|
||||||
{
|
{
|
||||||
SendFinishEvent( StateThreadAction_Restore );
|
SendFinishEvent( StateThreadAction_Restore );
|
||||||
_parent::OnThreadCleanup();
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -179,17 +190,28 @@ protected:
|
||||||
throw Exception::CreateStream( m_filename, "Cannot create savestate file for writing." );
|
throw Exception::CreateStream( m_filename, "Cannot create savestate file for writing." );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecuteTask()
|
void ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
Yield( 2 );
|
Yield( 3 );
|
||||||
if( gzwrite( (gzFile)m_gzfp, state_buffer.GetPtr(), state_buffer.GetSizeInBytes() ) < state_buffer.GetSizeInBytes() )
|
//if( gzwrite( m_gzfp, state_buffer.GetPtr(), state_buffer.GetSizeInBytes() ) < state_buffer.GetSizeInBytes() )
|
||||||
throw Exception::BadStream();
|
// 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 );
|
SendFinishEvent( StateThreadAction_ZipToDisk );
|
||||||
_parent::OnThreadCleanup();
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -233,7 +255,7 @@ protected:
|
||||||
throw Exception::CreateStream( m_filename, "Cannot open savestate file for reading." );
|
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.
|
// fixme: should start initially with the file size, and then grow from there.
|
||||||
|
|
||||||
|
@ -250,10 +272,10 @@ protected:
|
||||||
m_finished = true;
|
m_finished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnThreadCleanup()
|
void OnCleanupInThread()
|
||||||
{
|
{
|
||||||
SendFinishEvent( StateThreadAction_UnzipFromDisk );
|
SendFinishEvent( StateThreadAction_UnzipFromDisk );
|
||||||
_parent::OnThreadCleanup();
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -288,7 +310,7 @@ void OnFinished_Resume( const wxCommandEvent& evt )
|
||||||
SysClearExecutionCache();
|
SysClearExecutionCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
sCoreThread.Resume();
|
CoreThread.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
static wxString zip_dest_filename;
|
static wxString zip_dest_filename;
|
||||||
|
@ -304,7 +326,9 @@ void OnFinished_ZipToDisk( const wxCommandEvent& evt )
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 2: Record to disk!!
|
// 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 )
|
void OnFinished_Restore( const wxCommandEvent& evt )
|
||||||
|
@ -331,7 +355,7 @@ void StateCopy_SaveToFile( const wxString& file )
|
||||||
void StateCopy_LoadFromFile( const wxString& file )
|
void StateCopy_LoadFromFile( const wxString& file )
|
||||||
{
|
{
|
||||||
if( state_buffer_lock.IsLocked() ) return;
|
if( state_buffer_lock.IsLocked() ) return;
|
||||||
sCoreThread.Pause();
|
CoreThread.Pause();
|
||||||
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,6 +365,8 @@ void StateCopy_LoadFromFile( const wxString& file )
|
||||||
// the one in the memory save. :)
|
// the one in the memory save. :)
|
||||||
void StateCopy_SaveToSlot( uint num )
|
void StateCopy_SaveToSlot( uint num )
|
||||||
{
|
{
|
||||||
|
if( state_buffer_lock.IsLocked() ) return;
|
||||||
|
|
||||||
zip_dest_filename = SaveStateBase::GetFilename( num );
|
zip_dest_filename = SaveStateBase::GetFilename( num );
|
||||||
(new StateThread_Freeze( OnFinished_ZipToDisk ))->Start();
|
(new StateThread_Freeze( OnFinished_ZipToDisk ))->Start();
|
||||||
Console.Status( "Saving savestate to slot %d...", num );
|
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( "Loading savestate from slot %d...", slot );
|
||||||
Console.Status( wxsFormat(L"\tfilename: %s", file.c_str()) );
|
Console.Status( wxsFormat(L"\tfilename: %s", file.c_str()) );
|
||||||
|
|
||||||
sCoreThread.Pause();
|
CoreThread.Pause();
|
||||||
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,9 +418,21 @@ void StateCopy_ThawFromMem()
|
||||||
new StateThread_Thaw( OnFinished_Restore );
|
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()
|
void StateCopy_Clear()
|
||||||
{
|
{
|
||||||
if( state_buffer_lock.IsLocked() ) return;
|
if( state_buffer_lock.IsLocked() ) return;
|
||||||
state_buffer.Dispose();
|
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
|
// Saving of state data
|
||||||
void memSavingState::FreezeMem( void* data, int size )
|
void memSavingState::FreezeMem( void* data, int size )
|
||||||
{
|
{
|
||||||
const int end = m_idx+size;
|
u8* const dest = m_memory.GetPtr(m_idx);
|
||||||
m_memory.MakeRoomFor( end );
|
m_idx += size;
|
||||||
|
m_memory.MakeRoomFor( m_idx );
|
||||||
u8* dest = (u8*)m_memory.GetPtr();
|
memcpy_fast( dest, data, size );
|
||||||
const u8* src = (u8*)data;
|
|
||||||
|
|
||||||
for( ; m_idx<end; ++m_idx, ++src )
|
|
||||||
dest[m_idx] = *src;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memLoadingState::memLoadingState( const SafeArray<u8>& load_from ) :
|
memLoadingState::memLoadingState( const SafeArray<u8>& load_from ) :
|
||||||
|
@ -379,10 +375,7 @@ memLoadingState::~memLoadingState() { }
|
||||||
// Loading of state data
|
// Loading of state data
|
||||||
void memLoadingState::FreezeMem( void* data, int size )
|
void memLoadingState::FreezeMem( void* data, int size )
|
||||||
{
|
{
|
||||||
const int end = m_idx+size;
|
const u8* const src = m_memory.GetPtr(m_idx);
|
||||||
const u8* src = (u8*)m_memory.GetPtr();
|
m_idx += size;
|
||||||
u8* dest = (u8*)data;
|
memcpy_fast( data, src, size );
|
||||||
|
|
||||||
for( ; m_idx<end; ++m_idx, ++dest )
|
|
||||||
*dest = src[m_idx];
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,4 +204,4 @@ extern void StateCopy_LoadFromFile( const wxString& file );
|
||||||
extern void StateCopy_SaveToSlot( uint num );
|
extern void StateCopy_SaveToSlot( uint num );
|
||||||
extern void StateCopy_LoadFromSlot( uint slot );
|
extern void StateCopy_LoadFromSlot( uint slot );
|
||||||
extern void StateCopy_Clear();
|
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()
|
void SysSuspendableThread::OnStart()
|
||||||
{
|
{
|
||||||
if( !pxAssertDev( m_ExecMode == ExecMode_NoThreadYet, "SysSustainableThread:Start(): Invalid execution mode" ) ) return;
|
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
|
// is mostly useful for starting certain non-Emu related gui activities (improves gui
|
||||||
// responsiveness).
|
// responsiveness).
|
||||||
//
|
//
|
||||||
|
// Returns:
|
||||||
|
// The previous suspension state; true if the thread was running or false if it was
|
||||||
|
// suspended.
|
||||||
|
//
|
||||||
// Exceptions:
|
// Exceptions:
|
||||||
// CancelEvent - thrown if the thread is already in a Paused state. Because actions that
|
// 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
|
// pause emulation typically rely on plugins remaining loaded/active, Suspension must
|
||||||
// cansel itself forcefully or risk crashing whatever other action is in progress.
|
// 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 );
|
ScopedLock locker( m_lock_ExecMode );
|
||||||
|
|
||||||
if( m_ExecMode == ExecMode_Suspended )
|
if( m_ExecMode == ExecMode_Suspended )
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
if( m_ExecMode == ExecMode_Pausing || m_ExecMode == ExecMode_Paused )
|
if( m_ExecMode == ExecMode_Pausing || m_ExecMode == ExecMode_Paused )
|
||||||
throw Exception::CancelEvent( "Another thread is pausing the VM state." );
|
throw Exception::CancelEvent( "Another thread is pausing the VM state." );
|
||||||
|
|
||||||
if( m_ExecMode == ExecMode_Running )
|
if( m_ExecMode == ExecMode_Running )
|
||||||
|
{
|
||||||
m_ExecMode = ExecMode_Suspending;
|
m_ExecMode = ExecMode_Suspending;
|
||||||
|
retval = true;
|
||||||
|
}
|
||||||
|
|
||||||
pxAssertDev( m_ExecMode == ExecMode_Suspending, "ExecMode should be nothing other than Suspending..." );
|
pxAssertDev( m_ExecMode == ExecMode_Suspending, "ExecMode should be nothing other than Suspending..." );
|
||||||
}
|
}
|
||||||
m_SuspendEvent.Reset();
|
m_SuspendEvent.Reset();
|
||||||
m_sem_event.Post();
|
m_sem_event.Post();
|
||||||
if( isBlocking ) m_SuspendEvent.WaitGui();
|
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 );
|
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 )
|
if( m_ExecMode == ExecMode_Running )
|
||||||
|
{
|
||||||
m_ExecMode = ExecMode_Pausing;
|
m_ExecMode = ExecMode_Pausing;
|
||||||
|
retval = true;
|
||||||
|
}
|
||||||
|
|
||||||
pxAssertDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
|
pxAssertDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
|
||||||
}
|
}
|
||||||
m_SuspendEvent.Reset();
|
m_SuspendEvent.Reset();
|
||||||
m_sem_event.Post();
|
m_sem_event.Post();
|
||||||
m_SuspendEvent.WaitGui();
|
m_SuspendEvent.WaitGui();
|
||||||
|
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resumes the core execution state, or does nothing is the core is already running. If
|
// 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),
|
pxAssertDev( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Paused),
|
||||||
"SysSuspendableThread is not in a suspended/paused state? wtf!" );
|
"SysSuspendableThread is not in a suspended/paused state? wtf!" );
|
||||||
|
|
||||||
m_ExecMode = ExecMode_Running;
|
|
||||||
m_ResumeProtection = true;
|
m_ResumeProtection = true;
|
||||||
OnResumeReady();
|
OnResumeReady();
|
||||||
m_ResumeProtection = false;
|
m_ResumeProtection = false;
|
||||||
|
m_ExecMode = ExecMode_Running;
|
||||||
m_ResumeEvent.Post();
|
m_ResumeEvent.Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,11 +189,11 @@ void SysSuspendableThread::Resume()
|
||||||
// (Called from the context of this thread only)
|
// (Called from the context of this thread only)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void SysSuspendableThread::OnThreadCleanup()
|
void SysSuspendableThread::OnCleanupInThread()
|
||||||
{
|
{
|
||||||
ScopedLock locker( m_lock_ExecMode );
|
ScopedLock locker( m_lock_ExecMode );
|
||||||
m_ExecMode = ExecMode_NoThreadYet;
|
m_ExecMode = ExecMode_NoThreadYet;
|
||||||
_parent::OnThreadCleanup();
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysSuspendableThread::StateCheck( bool isCancelable )
|
void SysSuspendableThread::StateCheck( bool isCancelable )
|
||||||
|
@ -244,11 +269,11 @@ void SysSuspendableThread::StateCheck( bool isCancelable )
|
||||||
// (Called form outside the context of this thread)
|
// (Called form outside the context of this thread)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
SysCoreThread::SysCoreThread( PluginManager& plugins ) :
|
SysCoreThread::SysCoreThread() :
|
||||||
m_resetRecompilers( false )
|
m_resetRecompilers( true )
|
||||||
, m_resetProfilers( false )
|
, m_resetProfilers( true )
|
||||||
, m_shortSuspend( false )
|
, m_resetVirtualMachine( true )
|
||||||
, m_plugins( plugins )
|
, m_hasValidState( false )
|
||||||
{
|
{
|
||||||
m_name = L"EE Core";
|
m_name = L"EE Core";
|
||||||
}
|
}
|
||||||
|
@ -260,7 +285,8 @@ SysCoreThread::~SysCoreThread() throw()
|
||||||
|
|
||||||
void SysCoreThread::Start()
|
void SysCoreThread::Start()
|
||||||
{
|
{
|
||||||
m_plugins.Init();
|
if( g_plugins == NULL ) return;
|
||||||
|
g_plugins->Init();
|
||||||
_parent::Start();
|
_parent::Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,16 +301,28 @@ void SysCoreThread::Start()
|
||||||
//
|
//
|
||||||
void SysCoreThread::OnResumeReady()
|
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();
|
SysClearExecutionCache();
|
||||||
|
memBindConditionalHandlers();
|
||||||
m_resetRecompilers = false;
|
m_resetRecompilers = false;
|
||||||
m_resetProfilers = false;
|
m_resetProfilers = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SysCoreThread::Reset()
|
||||||
|
{
|
||||||
|
Suspend();
|
||||||
|
m_resetVirtualMachine = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Applies a full suite of new settings, which will automatically facilitate the necessary
|
// 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
|
// 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.
|
// 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;
|
if( src == EmuConfig ) return;
|
||||||
|
|
||||||
const bool resumeWhenDone = !m_ResumeProtection && !IsSuspended();
|
// Suspend only if ResumeProtection is false:
|
||||||
if( !m_ResumeProtection ) Suspend();
|
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;
|
const_cast<Pcsx2Config&>(EmuConfig) = src;
|
||||||
|
|
||||||
if( resumeWhenDone ) Resume();
|
if( resumeWhenDone ) Resume();
|
||||||
|
@ -314,55 +353,44 @@ SysCoreThread& SysCoreThread::Get()
|
||||||
|
|
||||||
void SysCoreThread::CpuInitializeMess()
|
void SysCoreThread::CpuInitializeMess()
|
||||||
{
|
{
|
||||||
cpuReset();
|
if( m_hasValidState ) return;
|
||||||
SysClearExecutionCache();
|
|
||||||
|
|
||||||
if( StateCopy_IsValid() )
|
wxString elf_file;
|
||||||
|
if( EmuConfig.SkipBiosSplash )
|
||||||
{
|
{
|
||||||
// no need to boot bios or detect CDs when loading savestates.
|
// Fetch the ELF filename and CD type from the CDVD provider.
|
||||||
// [TODO] : It might be useful to detect game SLUS/CRC and compare it against
|
wxString ename;
|
||||||
// the savestate info, and issue a warning to the user since, chances are, they
|
int result = GetPS2ElfName( ename );
|
||||||
// don't really want to run a game with the wrong ISO loaded into the emu.
|
switch( result )
|
||||||
StateCopy_ThawFromMem();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wxString elf_file;
|
|
||||||
if( EmuConfig.SkipBiosSplash )
|
|
||||||
{
|
{
|
||||||
// Fetch the ELF filename and CD type from the CDVD provider.
|
case 0:
|
||||||
wxString ename;
|
throw Exception::RuntimeError( wxLt("Fast Boot failed: CDVD image is not a PS1 or PS2 game.") );
|
||||||
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 1:
|
case 1:
|
||||||
throw Exception::RuntimeError( wxLt("Fast Boot failed: PCSX2 does not support emulation of PS1 games.") );
|
throw Exception::RuntimeError( wxLt("Fast Boot failed: PCSX2 does not support emulation of PS1 games.") );
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
// PS2 game. Valid!
|
// PS2 game. Valid!
|
||||||
elf_file = ename;
|
elf_file = ename;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
jNO_DEFAULT
|
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 );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
// special macro which disables inlining on functions that require their own function stackframe.
|
||||||
|
@ -384,33 +412,36 @@ void SysCoreThread::CpuExecute()
|
||||||
PCSX2_MEM_PROTECT_END();
|
PCSX2_MEM_PROTECT_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysCoreThread::ExecuteTask()
|
void SysCoreThread::ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
tls_coreThread = this;
|
tls_coreThread = this;
|
||||||
|
|
||||||
StateCheck();
|
m_sem_event.Wait();
|
||||||
CpuInitializeMess();
|
|
||||||
StateCheck();
|
StateCheck();
|
||||||
CpuExecute();
|
CpuExecute();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysCoreThread::OnSuspendInThread()
|
void SysCoreThread::OnSuspendInThread()
|
||||||
{
|
{
|
||||||
if( !m_shortSuspend )
|
if( g_plugins == NULL ) return;
|
||||||
m_plugins.Close();
|
g_plugins->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysCoreThread::OnResumeInThread( bool isSuspended )
|
void SysCoreThread::OnResumeInThread( bool isSuspended )
|
||||||
{
|
{
|
||||||
if( isSuspended )
|
if( isSuspended && g_plugins != NULL )
|
||||||
m_plugins.Open();
|
{
|
||||||
|
CpuInitializeMess();
|
||||||
|
g_plugins->Open();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Invoked by the pthread_exit or pthread_cancel
|
// Invoked by the pthread_exit or pthread_cancel
|
||||||
void SysCoreThread::OnThreadCleanup()
|
void SysCoreThread::OnCleanupInThread()
|
||||||
{
|
{
|
||||||
m_plugins.Shutdown();
|
//if( g_plugins != NULL )
|
||||||
_parent::OnThreadCleanup();
|
// g_plugins->Shutdown();
|
||||||
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ public:
|
||||||
ISysThread() {}
|
ISysThread() {}
|
||||||
virtual ~ISysThread() throw() {};
|
virtual ~ISysThread() throw() {};
|
||||||
|
|
||||||
virtual bool IsSuspended() const { return false; }
|
virtual bool Suspend( bool isBlocking = true ) { return false; }
|
||||||
virtual void Suspend( bool isBlocking = true ) { }
|
virtual bool Pause() { return false; }
|
||||||
virtual void Resume() {}
|
virtual void Resume() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,14 +57,14 @@ public:
|
||||||
explicit SysSuspendableThread();
|
explicit SysSuspendableThread();
|
||||||
virtual ~SysSuspendableThread() throw();
|
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 Resume();
|
||||||
virtual void Pause();
|
virtual bool Pause();
|
||||||
|
|
||||||
virtual void StateCheck( bool isCancelable = true );
|
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
|
// 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
|
// the core emulation thread. You should overload this rather than Resume(), since
|
||||||
|
@ -75,6 +75,9 @@ public:
|
||||||
|
|
||||||
protected:
|
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
|
// Extending classes should implement this, but should not call it. The parent class
|
||||||
// handles invocation by the following guidelines: Called *in thread* from StateCheck()
|
// 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
|
// prior to suspending the thread (ie, when Suspend() has been called on a separate
|
||||||
|
@ -108,19 +111,24 @@ class SysCoreThread : public SysSuspendableThread
|
||||||
protected:
|
protected:
|
||||||
bool m_resetRecompilers;
|
bool m_resetRecompilers;
|
||||||
bool m_resetProfilers;
|
bool m_resetProfilers;
|
||||||
bool m_shortSuspend;
|
bool m_resetVirtualMachine;
|
||||||
PluginManager& m_plugins;
|
bool m_hasValidState;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SysCoreThread& Get();
|
static SysCoreThread& Get();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SysCoreThread( PluginManager& plugins );
|
explicit SysCoreThread();
|
||||||
virtual ~SysCoreThread() throw();
|
virtual ~SysCoreThread() throw();
|
||||||
|
|
||||||
virtual void ApplySettings( const Pcsx2Config& src );
|
virtual void ApplySettings( const Pcsx2Config& src );
|
||||||
virtual void OnThreadCleanup();
|
|
||||||
virtual void OnResumeReady();
|
virtual void OnResumeReady();
|
||||||
|
virtual void Reset();
|
||||||
|
|
||||||
|
bool HasValidState()
|
||||||
|
{
|
||||||
|
return m_hasValidState;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CpuInitializeMess();
|
void CpuInitializeMess();
|
||||||
|
@ -130,5 +138,6 @@ protected:
|
||||||
virtual void OnSuspendInThread();
|
virtual void OnSuspendInThread();
|
||||||
virtual void OnPauseInThread() {}
|
virtual void OnPauseInThread() {}
|
||||||
virtual void OnResumeInThread( bool IsSuspended );
|
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_ReloadPlugins, -1 )
|
||||||
DECLARE_EVENT_TYPE( pxEVT_SysExecute, -1 )
|
DECLARE_EVENT_TYPE( pxEVT_SysExecute, -1 )
|
||||||
DECLARE_EVENT_TYPE( pxEVT_LoadPluginsComplete, -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 )
|
DECLARE_EVENT_TYPE( pxEVT_FreezeThreadFinished, -1 )
|
||||||
END_DECLARE_EVENT_TYPES()
|
END_DECLARE_EVENT_TYPES()
|
||||||
|
|
||||||
|
@ -159,6 +159,12 @@ enum DialogIdentifiers
|
||||||
DialogId_About,
|
DialogId_About,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AppStatusEvent
|
||||||
|
{
|
||||||
|
// Maybe this will be expanded upon later..?
|
||||||
|
AppStatus_Exiting
|
||||||
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// KeyAcceleratorCode
|
// KeyAcceleratorCode
|
||||||
// A custom keyboard accelerator that I like better than wx's wxAcceleratorEntry.
|
// A custom keyboard accelerator that I like better than wx's wxAcceleratorEntry.
|
||||||
|
@ -324,7 +330,6 @@ protected:
|
||||||
public:
|
public:
|
||||||
ScopedPtr<SysCoreAllocations> m_CoreAllocs;
|
ScopedPtr<SysCoreAllocations> m_CoreAllocs;
|
||||||
ScopedPtr<PluginManager> m_CorePlugins;
|
ScopedPtr<PluginManager> m_CorePlugins;
|
||||||
ScopedPtr<SysCoreThread> m_CoreThread;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
|
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
|
||||||
|
@ -345,7 +350,7 @@ public:
|
||||||
int ThreadedModalDialog( DialogIdentifiers dialogId );
|
int ThreadedModalDialog( DialogIdentifiers dialogId );
|
||||||
void Ping() const;
|
void Ping() const;
|
||||||
|
|
||||||
bool PrepForExit();
|
bool PrepForExit( bool canCancel );
|
||||||
|
|
||||||
void SysExecute();
|
void SysExecute();
|
||||||
void SysExecute( CDVD_SourceType cdvdsrc );
|
void SysExecute( CDVD_SourceType cdvdsrc );
|
||||||
|
@ -358,13 +363,8 @@ public:
|
||||||
const AppImageIds& GetImgId() const { return m_ImageId; }
|
const AppImageIds& GetImgId() const { return m_ImageId; }
|
||||||
|
|
||||||
MainEmuFrame& GetMainFrame() const;
|
MainEmuFrame& GetMainFrame() const;
|
||||||
SysCoreThread& GetCoreThread() const;
|
MainEmuFrame* GetMainFramePtr() const { return m_MainFrame; }
|
||||||
|
|
||||||
bool HasMainFrame() const { return m_MainFrame != NULL; }
|
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 OpenGsFrame();
|
||||||
void OnGsFrameClosed();
|
void OnGsFrameClosed();
|
||||||
|
@ -402,10 +402,12 @@ public:
|
||||||
protected:
|
protected:
|
||||||
CmdEvt_Source m_evtsrc_CorePluginStatus;
|
CmdEvt_Source m_evtsrc_CorePluginStatus;
|
||||||
CmdEvt_Source m_evtsrc_CoreThreadStatus;
|
CmdEvt_Source m_evtsrc_CoreThreadStatus;
|
||||||
|
EventSource<AppStatusEvent> m_evtsrc_AppStatus;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; }
|
CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; }
|
||||||
CmdEvt_Source& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; }
|
CmdEvt_Source& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; }
|
||||||
|
EventSource<AppStatusEvent>& Source_AppStatus() { return m_evtsrc_AppStatus; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InitDefaultGlobalAccelerators();
|
void InitDefaultGlobalAccelerators();
|
||||||
|
@ -422,7 +424,7 @@ protected:
|
||||||
void OnLoadPluginsComplete( wxCommandEvent& evt );
|
void OnLoadPluginsComplete( wxCommandEvent& evt );
|
||||||
void OnSemaphorePing( wxCommandEvent& evt );
|
void OnSemaphorePing( wxCommandEvent& evt );
|
||||||
void OnOpenModalDialog( wxCommandEvent& evt );
|
void OnOpenModalDialog( wxCommandEvent& evt );
|
||||||
void OnCoreThreadTerminated( wxCommandEvent& evt );
|
void OnCoreThreadStatus( wxCommandEvent& evt );
|
||||||
|
|
||||||
void OnFreezeThreadFinished( wxCommandEvent& evt );
|
void OnFreezeThreadFinished( wxCommandEvent& evt );
|
||||||
|
|
||||||
|
@ -449,6 +451,13 @@ protected:
|
||||||
// AppCoreThread class
|
// AppCoreThread class
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum CoreThreadStatus
|
||||||
|
{
|
||||||
|
CoreStatus_Resumed,
|
||||||
|
CoreStatus_Suspended,
|
||||||
|
CoreStatus_Stopped,
|
||||||
|
};
|
||||||
|
|
||||||
class AppCoreThread : public SysCoreThread
|
class AppCoreThread : public SysCoreThread
|
||||||
{
|
{
|
||||||
typedef SysCoreThread _parent;
|
typedef SysCoreThread _parent;
|
||||||
|
@ -457,18 +466,18 @@ protected:
|
||||||
wxKeyEvent m_kevt;
|
wxKeyEvent m_kevt;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AppCoreThread( PluginManager& plugins );
|
AppCoreThread();
|
||||||
virtual ~AppCoreThread() throw();
|
virtual ~AppCoreThread() throw();
|
||||||
|
|
||||||
virtual void Suspend( bool isBlocking=true );
|
virtual bool Suspend( bool isBlocking=true );
|
||||||
virtual void Resume();
|
virtual void Resume();
|
||||||
virtual void StateCheck( bool isCancelable=true );
|
virtual void StateCheck( bool isCancelable=true );
|
||||||
virtual void ApplySettings( const Pcsx2Config& src );
|
virtual void ApplySettings( const Pcsx2Config& src );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void OnResumeReady();
|
virtual void OnResumeReady();
|
||||||
virtual void OnThreadCleanup();
|
virtual void OnCleanupInThread();
|
||||||
virtual void ExecuteTask();
|
virtual void ExecuteTaskInThread();
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_APP(Pcsx2App)
|
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.
|
// not be invoked, and an optional "else" clause cn be affixed for handling the end case.
|
||||||
//
|
//
|
||||||
// Usage Examples:
|
// Usage Examples:
|
||||||
// sCoreThread.Suspend(); // Suspends the CoreThread, or does nothing if the CoreThread handle is NULL
|
// sMainFrame.ApplySettings();
|
||||||
// sCoreThread.Suspend(); else Console.WriteLn( "Judge Wapner" ); // 'else' clause for handling NULL scenarios.
|
// 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
|
// 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
|
// syntax errors in some situatins, and more importantly they cannot be used for invoking
|
||||||
|
@ -497,9 +506,6 @@ DECLARE_APP(Pcsx2App)
|
||||||
#define sApp \
|
#define sApp \
|
||||||
if( Pcsx2App* __app_ = (Pcsx2App*)wxApp::GetInstance() ) (*__app_)
|
if( Pcsx2App* __app_ = (Pcsx2App*)wxApp::GetInstance() ) (*__app_)
|
||||||
|
|
||||||
#define sCoreThread \
|
|
||||||
if( SysCoreThread* __thread_ = GetCoreThreadPtr() ) (*__thread_)
|
|
||||||
|
|
||||||
#define sMainFrame \
|
#define sMainFrame \
|
||||||
if( MainEmuFrame* __frame_ = GetMainFramePtr() ) (*__frame_)
|
if( MainEmuFrame* __frame_ = GetMainFramePtr() ) (*__frame_)
|
||||||
|
|
||||||
|
@ -523,11 +529,8 @@ extern bool SysHasValidState();
|
||||||
|
|
||||||
extern void SysStatus( const wxString& text );
|
extern void SysStatus( const wxString& text );
|
||||||
|
|
||||||
extern bool HasMainFrame();
|
extern bool HasMainFrame();
|
||||||
extern bool HasCoreThread();
|
|
||||||
|
|
||||||
extern MainEmuFrame& GetMainFrame();
|
extern MainEmuFrame& GetMainFrame();
|
||||||
extern SysCoreThread& GetCoreThread();
|
|
||||||
|
|
||||||
extern MainEmuFrame* GetMainFramePtr();
|
extern MainEmuFrame* GetMainFramePtr();
|
||||||
extern SysCoreThread* GetCoreThreadPtr();
|
|
||||||
|
extern AppCoreThread CoreThread;
|
|
@ -525,8 +525,7 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite )
|
||||||
AppLoadSettings();
|
AppLoadSettings();
|
||||||
|
|
||||||
AppApplySettings();
|
AppApplySettings();
|
||||||
if( HasMainFrame() )
|
sMainFrame.ReloadRecentLists();
|
||||||
GetMainFrame().ReloadRecentLists();
|
|
||||||
|
|
||||||
g_Conf->Folders.Logs.Mkdir();
|
g_Conf->Folders.Logs.Mkdir();
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,9 @@
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "MainFrame.h"
|
#include "MainFrame.h"
|
||||||
|
|
||||||
AppCoreThread::AppCoreThread( PluginManager& plugins ) :
|
AppCoreThread CoreThread;
|
||||||
SysCoreThread( plugins )
|
|
||||||
|
AppCoreThread::AppCoreThread() : SysCoreThread()
|
||||||
, m_kevt()
|
, m_kevt()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -26,11 +27,13 @@ AppCoreThread::~AppCoreThread() throw()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppCoreThread::Suspend( bool isBlocking )
|
bool AppCoreThread::Suspend( bool isBlocking )
|
||||||
{
|
{
|
||||||
_parent::Suspend( isBlocking );
|
bool retval = _parent::Suspend( isBlocking );
|
||||||
if( HasMainFrame() )
|
|
||||||
GetMainFrame().ApplySettings();
|
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
|
// Clear the sticky key statuses, because hell knows what'll change while the PAD
|
||||||
// plugin is suspended.
|
// plugin is suspended.
|
||||||
|
@ -38,6 +41,8 @@ void AppCoreThread::Suspend( bool isBlocking )
|
||||||
m_kevt.m_shiftDown = false;
|
m_kevt.m_shiftDown = false;
|
||||||
m_kevt.m_controlDown = false;
|
m_kevt.m_controlDown = false;
|
||||||
m_kevt.m_altDown = false;
|
m_kevt.m_altDown = false;
|
||||||
|
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppCoreThread::Resume()
|
void AppCoreThread::Resume()
|
||||||
|
@ -55,26 +60,28 @@ void AppCoreThread::Resume()
|
||||||
|
|
||||||
void AppCoreThread::OnResumeReady()
|
void AppCoreThread::OnResumeReady()
|
||||||
{
|
{
|
||||||
if( m_shortSuspend ) return;
|
|
||||||
|
|
||||||
ApplySettings( g_Conf->EmuOptions );
|
ApplySettings( g_Conf->EmuOptions );
|
||||||
|
|
||||||
if( GSopen2 != NULL )
|
if( GSopen2 != NULL )
|
||||||
wxGetApp().OpenGsFrame();
|
wxGetApp().OpenGsFrame();
|
||||||
|
|
||||||
if( HasMainFrame() )
|
wxCommandEvent evt( pxEVT_CoreThreadStatus );
|
||||||
GetMainFrame().ApplySettings();
|
evt.SetInt( CoreStatus_Resumed );
|
||||||
|
wxGetApp().AddPendingEvent( evt );
|
||||||
|
|
||||||
|
_parent::OnResumeReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called whenever the thread has terminated, for either regular or irregular reasons.
|
// 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
|
// 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
|
// 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.
|
// 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 );
|
wxGetApp().AddPendingEvent( evt );
|
||||||
_parent::OnThreadCleanup();
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __WXGTK__
|
#ifdef __WXGTK__
|
||||||
|
@ -84,11 +91,12 @@ void AppCoreThread::OnThreadCleanup()
|
||||||
void AppCoreThread::StateCheck( bool isCancelable )
|
void AppCoreThread::StateCheck( bool isCancelable )
|
||||||
{
|
{
|
||||||
_parent::StateCheck( isCancelable );
|
_parent::StateCheck( isCancelable );
|
||||||
|
if( !pxAssert(g_plugins!=NULL) ) return;
|
||||||
|
|
||||||
const keyEvent* ev = PADkeyEvent();
|
const keyEvent* ev = PADkeyEvent();
|
||||||
if( ev == NULL || (ev->key == 0) ) return;
|
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 );
|
m_kevt.SetEventType( ( ev->evt == KEYPRESS ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP );
|
||||||
const bool isDown = (ev->evt == KEYPRESS);
|
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*.
|
// suspended. If the thread has mot been suspended, this call will fail *silently*.
|
||||||
void AppCoreThread::ApplySettings( const Pcsx2Config& src )
|
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
|
// 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
|
// 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 );
|
SysCoreThread::ApplySettings( src );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppCoreThread::ExecuteTask()
|
void AppCoreThread::ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SysCoreThread::ExecuteTask();
|
SysCoreThread::ExecuteTaskInThread();
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
catch( Exception::FileNotFound& ex )
|
catch( Exception::FileNotFound& ex )
|
||||||
{
|
{
|
||||||
m_plugins.Close();
|
if( g_plugins != NULL ) g_plugins->Close();
|
||||||
if( ex.StreamName == g_Conf->FullpathToBios() )
|
if( ex.StreamName == g_Conf->FullpathToBios() )
|
||||||
{
|
{
|
||||||
m_plugins.Close();
|
|
||||||
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
||||||
_("\n\nPress Ok to go to the BIOS Configuration Panel.") );
|
_("\n\nPress Ok to go to the BIOS Configuration Panel.") );
|
||||||
|
|
||||||
|
@ -160,7 +168,7 @@ void AppCoreThread::ExecuteTask()
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
catch( Exception::PluginError& ex )
|
catch( Exception::PluginError& ex )
|
||||||
{
|
{
|
||||||
m_plugins.Close();
|
if( g_plugins != NULL ) g_plugins->Close();
|
||||||
Console.Error( ex.FormatDiagnosticMessage() );
|
Console.Error( ex.FormatDiagnosticMessage() );
|
||||||
Msgbox::Alert( ex.FormatDisplayMessage(), _("Plugin Open Error") );
|
Msgbox::Alert( ex.FormatDisplayMessage(), _("Plugin Open Error") );
|
||||||
|
|
||||||
|
@ -176,7 +184,7 @@ void AppCoreThread::ExecuteTask()
|
||||||
catch( Exception::BaseException& ex )
|
catch( Exception::BaseException& ex )
|
||||||
{
|
{
|
||||||
// Sent the exception back to the main gui thread?
|
// Sent the exception back to the main gui thread?
|
||||||
m_plugins.Close();
|
if( g_plugins != NULL ) g_plugins->Close();
|
||||||
Msgbox::Alert( ex.FormatDisplayMessage() );
|
Msgbox::Alert( ex.FormatDisplayMessage() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,7 @@ bool Pcsx2App::OnInit()
|
||||||
|
|
||||||
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
|
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( pxEVT_FreezeThreadFinished, wxCommandEventHandler( Pcsx2App::OnFreezeThreadFinished ) );
|
||||||
|
|
||||||
Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
|
Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
|
||||||
|
@ -335,11 +335,10 @@ bool Pcsx2App::OnInit()
|
||||||
|
|
||||||
void Pcsx2App::CleanupMess()
|
void Pcsx2App::CleanupMess()
|
||||||
{
|
{
|
||||||
|
CoreThread.Cancel();
|
||||||
|
|
||||||
if( m_CorePlugins )
|
if( m_CorePlugins )
|
||||||
{
|
|
||||||
m_CorePlugins->Close();
|
|
||||||
m_CorePlugins->Shutdown();
|
m_CorePlugins->Shutdown();
|
||||||
}
|
|
||||||
|
|
||||||
// Notice: deleting the plugin manager (unloading plugins) here causes Lilypad to crash,
|
// 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.
|
// 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_ReloadPlugins );
|
||||||
DEFINE_EVENT_TYPE( pxEVT_SysExecute );
|
DEFINE_EVENT_TYPE( pxEVT_SysExecute );
|
||||||
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
|
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
|
||||||
DEFINE_EVENT_TYPE( pxEVT_AppCoreThreadFinished );
|
DEFINE_EVENT_TYPE( pxEVT_CoreThreadStatus );
|
||||||
DEFINE_EVENT_TYPE( pxEVT_FreezeThreadFinished );
|
DEFINE_EVENT_TYPE( pxEVT_FreezeThreadFinished );
|
||||||
|
|
||||||
bool UseAdminMode = false;
|
bool UseAdminMode = false;
|
||||||
|
@ -118,13 +118,13 @@ void Pcsx2App::Ping() const
|
||||||
// Pcsx2App Event Handlers
|
// Pcsx2App Event Handlers
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Invoked by the AppCoreThread when the thread has terminated itself.
|
// Invoked by the AppCoreThread when it's internal status has changed.
|
||||||
void Pcsx2App::OnCoreThreadTerminated( wxCommandEvent& evt )
|
// 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 )
|
||||||
{
|
{
|
||||||
|
m_evtsrc_CoreThreadStatus.Dispatch( evt );
|
||||||
if( HasMainFrame() )
|
|
||||||
GetMainFrame().ApplySettings();
|
|
||||||
m_CoreThread = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt )
|
void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt )
|
||||||
|
@ -220,7 +220,7 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
|
||||||
{
|
{
|
||||||
// Saved state load failed.
|
// Saved state load failed.
|
||||||
Console.Notice( ex.FormatDiagnosticMessage() );
|
Console.Notice( ex.FormatDiagnosticMessage() );
|
||||||
sCoreThread.Resume();
|
CoreThread.Resume();
|
||||||
}
|
}
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
catch( Exception::PluginError& ex )
|
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
|
// 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
|
// 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
|
// 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.
|
// the glorious user, whomever (s)he-it might be.
|
||||||
bool Pcsx2App::PrepForExit()
|
bool Pcsx2App::PrepForExit( bool canCancel )
|
||||||
{
|
{
|
||||||
m_CoreThread = NULL;
|
// If a savestate is saving, we should wait until it finishes. Otherwise the user
|
||||||
CleanupMess();
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Pcsx2App::OnExit()
|
int Pcsx2App::OnExit()
|
||||||
{
|
{
|
||||||
PrepForExit();
|
CleanupMess();
|
||||||
|
|
||||||
if( g_Conf )
|
if( g_Conf )
|
||||||
AppSaveSettings();
|
AppSaveSettings();
|
||||||
|
@ -283,16 +311,6 @@ MainEmuFrame& Pcsx2App::GetMainFrame() const
|
||||||
return *m_MainFrame;
|
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 )
|
void AppApplySettings( const AppConfig* oldconf )
|
||||||
{
|
{
|
||||||
AllowFromMainThreadOnly();
|
AllowFromMainThreadOnly();
|
||||||
|
@ -306,6 +324,8 @@ void AppApplySettings( const AppConfig* oldconf )
|
||||||
|
|
||||||
g_Conf->EmuOptions.BiosFilename = g_Conf->FullpathToBios();
|
g_Conf->EmuOptions.BiosFilename = g_Conf->FullpathToBios();
|
||||||
|
|
||||||
|
bool resume = CoreThread.Suspend();
|
||||||
|
|
||||||
// Update the compression attribute on the Memcards folder.
|
// Update the compression attribute on the Memcards folder.
|
||||||
// Memcards generally compress very well via NTFS compression.
|
// Memcards generally compress very well via NTFS compression.
|
||||||
|
|
||||||
|
@ -323,10 +343,10 @@ void AppApplySettings( const AppConfig* oldconf )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( HasMainFrame() )
|
CoreThread.ApplySettings( g_Conf->EmuOptions );
|
||||||
GetMainFrame().ApplySettings();
|
|
||||||
if( HasCoreThread() )
|
if( resume )
|
||||||
GetCoreThread().ApplySettings( g_Conf->EmuOptions );
|
CoreThread.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppLoadSettings()
|
void AppLoadSettings()
|
||||||
|
@ -368,8 +388,7 @@ void Pcsx2App::OpenGsFrame()
|
||||||
|
|
||||||
void Pcsx2App::OnGsFrameClosed()
|
void Pcsx2App::OnGsFrameClosed()
|
||||||
{
|
{
|
||||||
if( m_CoreThread != NULL )
|
CoreThread.Suspend();
|
||||||
m_CoreThread->Suspend();
|
|
||||||
m_gsFrame = NULL;
|
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.
|
// it, because apparently too much stuff is going on and the emulation states are wonky.
|
||||||
if( !m_CorePlugins ) return;
|
if( !m_CorePlugins ) return;
|
||||||
|
|
||||||
if( evt.GetInt() != -1 ) SysReset();
|
if( evt.GetInt() != -1 ) SysReset(); else CoreThread.Suspend();
|
||||||
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
||||||
if( evt.GetInt() != -1 ) CDVDsys_ChangeSource( (CDVD_SourceType)evt.GetInt() );
|
if( evt.GetInt() != -1 ) CDVDsys_ChangeSource( (CDVD_SourceType)evt.GetInt() );
|
||||||
|
|
||||||
m_CoreThread = new AppCoreThread( *m_CorePlugins );
|
CoreThread.Resume();
|
||||||
m_CoreThread->Resume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pcsx2App::SysReset()
|
void Pcsx2App::SysReset()
|
||||||
{
|
{
|
||||||
m_CoreThread = NULL;
|
CoreThread.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if there is a "valid" virtual machine state from the user's perspective. This
|
// 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!
|
// state (such as saving it), you *must* suspend the Corethread first!
|
||||||
__forceinline bool SysHasValidState()
|
__forceinline bool SysHasValidState()
|
||||||
{
|
{
|
||||||
bool isRunning = HasCoreThread() ? GetCoreThread().IsRunning() : false;
|
return CoreThread.HasValidState() || StateCopy_HasFullState();
|
||||||
return isRunning || StateCopy_HasFullState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes text to console and updates the window status bar and/or HUD or whateverness.
|
// 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!
|
// mirror output to the console!
|
||||||
Console.Status( text.c_str() );
|
Console.Status( text.c_str() );
|
||||||
if( HasMainFrame() )
|
sMainFrame.SetStatusText( text );
|
||||||
GetMainFrame().SetStatusText( text );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasMainFrame()
|
bool HasMainFrame()
|
||||||
|
@ -485,11 +501,6 @@ bool HasMainFrame()
|
||||||
return wxTheApp && wxGetApp().HasMainFrame();
|
return wxTheApp && wxGetApp().HasMainFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasCoreThread()
|
|
||||||
{
|
|
||||||
return wxTheApp && wxGetApp().HasCoreThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method generates debug assertions if either the wxApp or MainFrame handles are
|
// 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
|
// 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
|
// frame has been closed). In most cases you'll want to use HasMainFrame() to test
|
||||||
|
@ -500,11 +511,6 @@ MainEmuFrame& GetMainFrame()
|
||||||
return wxGetApp().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
|
// 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
|
// 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.
|
// the wxApp is NULL then this will also return NULL.
|
||||||
|
@ -512,10 +518,3 @@ MainEmuFrame* GetMainFramePtr()
|
||||||
{
|
{
|
||||||
return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL;
|
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;
|
static int numtrack = 0;
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ class ConsoleTestThread : public Threading::PersistentThread
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
volatile bool m_done;
|
volatile bool m_done;
|
||||||
void ExecuteTask();
|
void ExecuteTaskInThread();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConsoleTestThread() :
|
ConsoleTestThread() :
|
||||||
|
@ -85,7 +85,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnStart() {}
|
void OnStart() {}
|
||||||
void OnThreadCleanup() {}
|
void OnCleanupInThread() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -54,8 +54,7 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title):
|
||||||
|
|
||||||
GSFrame::~GSFrame() throw()
|
GSFrame::~GSFrame() throw()
|
||||||
{
|
{
|
||||||
if( HasCoreThread() )
|
CoreThread.Suspend(); // Just in case...!
|
||||||
GetCoreThread().Suspend(); // Just in case...!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSFrame::OnCloseWindow(wxCloseEvent& evt)
|
void GSFrame::OnCloseWindow(wxCloseEvent& evt)
|
||||||
|
|
|
@ -71,14 +71,12 @@ namespace Implementations
|
||||||
|
|
||||||
void Sys_Suspend()
|
void Sys_Suspend()
|
||||||
{
|
{
|
||||||
if( HasCoreThread() )
|
CoreThread.Suspend();
|
||||||
GetCoreThread().Suspend();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sys_Resume()
|
void Sys_Resume()
|
||||||
{
|
{
|
||||||
if( HasCoreThread() )
|
CoreThread.Resume();
|
||||||
GetCoreThread().Resume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sys_TakeSnapshot()
|
void Sys_TakeSnapshot()
|
||||||
|
@ -88,10 +86,9 @@ namespace Implementations
|
||||||
|
|
||||||
void Sys_RenderToggle()
|
void Sys_RenderToggle()
|
||||||
{
|
{
|
||||||
if( !HasCoreThread() ) return;
|
bool resume = CoreThread.Suspend();
|
||||||
sCoreThread.Suspend();
|
|
||||||
renderswitch = !renderswitch;
|
renderswitch = !renderswitch;
|
||||||
sCoreThread.Resume();
|
if( resume ) CoreThread.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sys_LoggingToggle()
|
void Sys_LoggingToggle()
|
||||||
|
|
|
@ -149,7 +149,7 @@ void MainEmuFrame::OnCloseWindow(wxCloseEvent& evt)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
isClosing = wxGetApp().PrepForExit();
|
isClosing = wxGetApp().PrepForExit( evt.CanVeto() );
|
||||||
if( !isClosing ) evt.Veto( true );
|
if( !isClosing ) evt.Veto( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ void MainEmuFrame::ConnectMenus()
|
||||||
ConnectMenu( MenuId_Exit, Menu_Exit_Click );
|
ConnectMenu( MenuId_Exit, Menu_Exit_Click );
|
||||||
|
|
||||||
ConnectMenu( MenuId_Sys_SuspendResume, Menu_SuspendResume_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 );
|
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):
|
MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
|
||||||
wxFrame(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~(wxMAXIMIZE_BOX | wxRESIZE_BORDER) ),
|
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_LoadStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Load01 ) ),
|
||||||
m_SaveStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Save01 ) ),
|
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
|
// 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() );
|
GetMenuBar()->Enable( MenuId_Sys_SuspendResume, SysHasValidState() );
|
||||||
|
|
||||||
if( HasCoreThread() )
|
GetMenuBar()->SetLabel( MenuId_Sys_SuspendResume, CoreThread.IsExecMode_Running() ? _("Suspend") :_("Resume") );
|
||||||
GetMenuBar()->SetLabel( MenuId_Sys_SuspendResume, GetCoreThread().IsSuspended() ? _("Resume") :_("Suspend") );
|
|
||||||
|
|
||||||
if( m_RecentIsoList )
|
if( m_RecentIsoList )
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,22 +47,24 @@ protected:
|
||||||
wxStatusBar& m_statusbar;
|
wxStatusBar& m_statusbar;
|
||||||
wxStaticBitmap m_background;
|
wxStaticBitmap m_background;
|
||||||
|
|
||||||
wxMenuBar& m_menubar;
|
wxMenuBar& m_menubar;
|
||||||
|
|
||||||
wxMenu& m_menuBoot;
|
wxMenu& m_menuBoot;
|
||||||
wxMenu& m_menuEmu;
|
wxMenu& m_menuEmu;
|
||||||
wxMenu& m_menuConfig;
|
wxMenu& m_menuConfig;
|
||||||
wxMenu& m_menuMisc;
|
wxMenu& m_menuMisc;
|
||||||
wxMenu& m_menuDebug;
|
wxMenu& m_menuDebug;
|
||||||
|
|
||||||
wxMenu& m_menuVideo;
|
wxMenu& m_menuVideo;
|
||||||
wxMenu& m_menuAudio;
|
wxMenu& m_menuAudio;
|
||||||
wxMenu& m_menuPad;
|
wxMenu& m_menuPad;
|
||||||
|
|
||||||
wxMenu& m_LoadStatesSubmenu;
|
wxMenu& m_LoadStatesSubmenu;
|
||||||
wxMenu& m_SaveStatesSubmenu;
|
wxMenu& m_SaveStatesSubmenu;
|
||||||
|
|
||||||
wxMenuItem& m_MenuItem_Console;
|
wxMenuItem& m_MenuItem_Console;
|
||||||
|
|
||||||
|
CmdEvt_ListenerBinding m_Listener_CoreThreadStatus;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// MainEmuFrame Constructors and Member Methods
|
// MainEmuFrame Constructors and Member Methods
|
||||||
|
@ -107,7 +109,7 @@ protected:
|
||||||
void Menu_Exit_Click(wxCommandEvent &event);
|
void Menu_Exit_Click(wxCommandEvent &event);
|
||||||
|
|
||||||
void Menu_SuspendResume_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);
|
void Menu_ConfigPlugin_Click(wxCommandEvent &event);
|
||||||
|
|
||||||
|
|
|
@ -82,13 +82,13 @@ bool MainEmuFrame::_DoSelectIsoBrowser()
|
||||||
|
|
||||||
void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
||||||
{
|
{
|
||||||
sCoreThread.Suspend();
|
CoreThread.Suspend();
|
||||||
|
|
||||||
if( !wxFileExists( g_Conf->CurrentIso ) )
|
if( !wxFileExists( g_Conf->CurrentIso ) )
|
||||||
{
|
{
|
||||||
if( !_DoSelectIsoBrowser() )
|
if( !_DoSelectIsoBrowser() )
|
||||||
{
|
{
|
||||||
sCoreThread.Resume();
|
CoreThread.Resume();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
||||||
|
|
||||||
if( !result )
|
if( !result )
|
||||||
{
|
{
|
||||||
sCoreThread.Resume();
|
CoreThread.Resume();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,18 +113,18 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
||||||
|
|
||||||
void MainEmuFrame::Menu_IsoBrowse_Click( wxCommandEvent &event )
|
void MainEmuFrame::Menu_IsoBrowse_Click( wxCommandEvent &event )
|
||||||
{
|
{
|
||||||
sCoreThread.Suspend();
|
bool resume = CoreThread.Suspend();
|
||||||
_DoSelectIsoBrowser();
|
_DoSelectIsoBrowser();
|
||||||
sCoreThread.Resume();
|
if( resume ) CoreThread.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_RunIso_Click( wxCommandEvent &event )
|
void MainEmuFrame::Menu_RunIso_Click( wxCommandEvent &event )
|
||||||
{
|
{
|
||||||
sCoreThread.Suspend();
|
CoreThread.Suspend();
|
||||||
|
|
||||||
if( !_DoSelectIsoBrowser() )
|
if( !_DoSelectIsoBrowser() )
|
||||||
{
|
{
|
||||||
sCoreThread.Resume();
|
CoreThread.Resume();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,23 +190,19 @@ void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
|
||||||
void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
if( !SysHasValidState() ) return;
|
if( !SysHasValidState() ) return;
|
||||||
if( SysCoreThread* thr = GetCoreThreadPtr() )
|
|
||||||
{
|
if( !CoreThread.Suspend() )
|
||||||
if( thr->IsSuspended() )
|
CoreThread.Resume();
|
||||||
thr->Resume();
|
|
||||||
else
|
|
||||||
thr->Suspend();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_EmuReset_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_SysReset_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
if( !SysHasValidState() ) return;
|
if( !SysHasValidState() ) return;
|
||||||
bool wasSuspended = HasCoreThread() ? GetCoreThread().IsSuspended() : true;
|
bool resume = CoreThread.Suspend();
|
||||||
|
|
||||||
sApp.SysReset();
|
sApp.SysReset();
|
||||||
|
|
||||||
if( !wasSuspended )
|
if( resume )
|
||||||
sApp.SysExecute();
|
sApp.SysExecute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -412,8 +412,8 @@ namespace Panels
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnStart() {}
|
void OnStart() {}
|
||||||
void ExecuteTask();
|
void ExecuteTaskInThread();
|
||||||
void OnThreadCleanup() {}
|
void OnCleanupInThread() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This panel contains all of the plugin combo boxes. We stick them
|
// 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.
|
// If an exception is thrown above, this code below won't get run.
|
||||||
// (conveniently skipping any option application! :D)
|
// (conveniently skipping any option application! :D)
|
||||||
|
|
||||||
|
// Note: apply first, then save -- in case the apply fails.
|
||||||
|
|
||||||
AppApplySettings( &confcopy );
|
AppApplySettings( &confcopy );
|
||||||
if( saveOnSuccess )
|
if( saveOnSuccess ) AppSaveSettings();
|
||||||
AppSaveSettings();
|
|
||||||
}
|
}
|
||||||
catch( Exception::CannotApplySettings& ex )
|
catch( Exception::CannotApplySettings& ex )
|
||||||
{
|
{
|
||||||
|
|
|
@ -310,7 +310,7 @@ void Panels::PluginSelectorPanel::Apply()
|
||||||
|
|
||||||
if( pi->shortname != NULL )
|
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.
|
// [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 );
|
m_master.GetEventHandler()->AddPendingEvent( yay );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panels::PluginSelectorPanel::EnumThread::ExecuteTask()
|
void Panels::PluginSelectorPanel::EnumThread::ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
DevCon.Status( "Plugin Enumeration Thread started..." );
|
DevCon.Status( "Plugin Enumeration Thread started..." );
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnStart() {}
|
void OnStart() {}
|
||||||
void OnThreadCleanup();
|
void OnCleanupInThread();
|
||||||
void ExecuteTask();
|
void ExecuteTaskInThread();
|
||||||
};
|
};
|
||||||
|
|
||||||
LoadPluginsTask::~LoadPluginsTask() throw()
|
LoadPluginsTask::~LoadPluginsTask() throw()
|
||||||
|
@ -67,7 +67,7 @@ LoadPluginsTask::~LoadPluginsTask() throw()
|
||||||
PersistentThread::Cancel();
|
PersistentThread::Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadPluginsTask::ExecuteTask()
|
void LoadPluginsTask::ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
wxGetApp().Ping();
|
wxGetApp().Ping();
|
||||||
Yield(3);
|
Yield(3);
|
||||||
|
@ -78,13 +78,13 @@ void LoadPluginsTask::ExecuteTask()
|
||||||
Result = PluginManager_Create( m_folders );
|
Result = PluginManager_Create( m_folders );
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadPluginsTask::OnThreadCleanup()
|
void LoadPluginsTask::OnCleanupInThread()
|
||||||
{
|
{
|
||||||
wxCommandEvent evt( pxEVT_LoadPluginsComplete );
|
wxCommandEvent evt( pxEVT_LoadPluginsComplete );
|
||||||
evt.SetClientData( this );
|
evt.SetClientData( this );
|
||||||
wxGetApp().AddPendingEvent( evt );
|
wxGetApp().AddPendingEvent( evt );
|
||||||
|
|
||||||
_parent::OnThreadCleanup();
|
_parent::OnCleanupInThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -127,7 +127,7 @@ static bool plugin_load_lock = false;
|
||||||
void Pcsx2App::OnReloadPlugins( wxCommandEvent& evt )
|
void Pcsx2App::OnReloadPlugins( wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
if( plugin_load_lock ) return;
|
if( plugin_load_lock ) return;
|
||||||
m_CoreThread = NULL;
|
CoreThread.Cancel();
|
||||||
m_CorePlugins = NULL;
|
m_CorePlugins = NULL;
|
||||||
|
|
||||||
wxString passins[PluginId_Count];
|
wxString passins[PluginId_Count];
|
||||||
|
@ -203,7 +203,7 @@ void LoadPluginsImmediate()
|
||||||
{
|
{
|
||||||
if( g_plugins != NULL ) return;
|
if( g_plugins != NULL ) return;
|
||||||
|
|
||||||
wxGetApp().m_CoreThread = NULL;
|
CoreThread.Cancel();
|
||||||
|
|
||||||
wxString passins[PluginId_Count];
|
wxString passins[PluginId_Count];
|
||||||
ConvertPluginFilenames( passins );
|
ConvertPluginFilenames( passins );
|
||||||
|
@ -213,6 +213,6 @@ void LoadPluginsImmediate()
|
||||||
|
|
||||||
void UnloadPlugins()
|
void UnloadPlugins()
|
||||||
{
|
{
|
||||||
wxGetApp().m_CoreThread = NULL;
|
CoreThread.Cancel();
|
||||||
wxGetApp().m_CorePlugins = NULL;
|
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
|
// 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
|
// 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
|
// are NULL, the memory operations will be mapped to the BusError handler (thus generating BusError
|
||||||
// exceptions if the emulated app attempts to access them).
|
// 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()
|
// 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.
|
void vtlb_ReassignHandler( vtlbHandler rv,
|
||||||
vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128,
|
||||||
vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128)
|
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[0][0][rv] = (r8!=0) ? (void*)(r8): (void*)vtlbDefaultPhyRead8;
|
||||||
vtlbdata.RWFT[1][0][rv] = (r16!=0) ? (void*)r16: (void*)vtlbDefaultPhyRead16;
|
vtlbdata.RWFT[1][0][rv] = (r16!=0) ? (void*)r16: (void*)vtlbDefaultPhyRead16;
|
||||||
vtlbdata.RWFT[2][0][rv] = (r32!=0) ? (void*)r32: (void*)vtlbDefaultPhyRead32;
|
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[2][1][rv] = (void*)((w32!=0) ? w32:vtlbDefaultPhyWrite32);
|
||||||
vtlbdata.RWFT[3][1][rv] = (void*)((w64!=0) ? w64:vtlbDefaultPhyWrite64);
|
vtlbdata.RWFT[3][1][rv] = (void*)((w64!=0) ? w64:vtlbDefaultPhyWrite64);
|
||||||
vtlbdata.RWFT[4][1][rv] = (void*)((w128!=0) ? w128:vtlbDefaultPhyWrite128);
|
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;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Maps the given hander (created with vtlb_RegisterHandler) to the specified memory region.
|
// 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
|
// 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 );
|
extern void vtlb_free( void* pmem, uint size );
|
||||||
|
|
||||||
|
|
||||||
//physical stuff
|
extern vtlbHandler vtlb_NewHandler();
|
||||||
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_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_MapHandler(vtlbHandler handler,u32 start,u32 size);
|
||||||
extern void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize=0);
|
extern void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize=0);
|
||||||
|
|
|
@ -169,7 +169,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void OnStart() {}
|
void OnStart() {}
|
||||||
|
|
||||||
void ExecuteTask()
|
void ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -188,7 +188,7 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnThreadCleanup() { }
|
void OnCleanupInThread() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -309,6 +309,8 @@ EXPORT_C_(s32) SPU2open(void *pDsp)
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
IsOpened = true;
|
IsOpened = true;
|
||||||
|
lClocks = (cyclePtr!=NULL) ? *cyclePtr : 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SndBuffer::Init();
|
SndBuffer::Init();
|
||||||
|
|
|
@ -276,17 +276,23 @@ u32 TicksThread = 0;
|
||||||
|
|
||||||
__forceinline void TimeUpdate(u32 cClocks)
|
__forceinline void TimeUpdate(u32 cClocks)
|
||||||
{
|
{
|
||||||
s32 dClocks = cClocks-lClocks;
|
u32 dClocks = cClocks - lClocks;
|
||||||
|
|
||||||
// [Air]: Sanity Check
|
// Sanity Checks:
|
||||||
// If for some reason our clock value seems way off base, just mix
|
// It's not totally uncommon for the IOP's clock to jump backwards a cycle or two, and in
|
||||||
// out a little bit, skip the rest, and hope the ship "rights" itself later on.
|
// 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 )
|
if( dClocks > TickInterval*SanityInterval )
|
||||||
{
|
{
|
||||||
ConLog( " * SPU2 > TimeUpdate Sanity Check (Tick Delta: %d) (PS2 Ticks: %d)\n", dClocks/TickInterval, cClocks/TickInterval );
|
ConLog( " * SPU2 > TimeUpdate Sanity Check (Tick Delta: %d) (PS2 Ticks: %d)\n", dClocks/TickInterval, cClocks/TickInterval );
|
||||||
dClocks = TickInterval*SanityInterval;
|
dClocks = TickInterval * SanityInterval;
|
||||||
lClocks = cClocks-dClocks;
|
lClocks = cClocks - dClocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
//UpdateDebugDialog();
|
//UpdateDebugDialog();
|
||||||
|
@ -350,8 +356,8 @@ __forceinline void TimeUpdate(u32 cClocks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dClocks-=TickInterval;
|
dClocks -= TickInterval;
|
||||||
lClocks+=TickInterval;
|
lClocks += TickInterval;
|
||||||
Cycles++;
|
Cycles++;
|
||||||
|
|
||||||
// Note: IOP does not use MMX regs, so no need to save them.
|
// Note: IOP does not use MMX regs, so no need to save them.
|
||||||
|
|
Loading…
Reference in New Issue