mirror of https://github.com/PCSX2/pcsx2.git
User Interface:
* Console Log doesn't force itself into the focus anymore when it opens * Suspend/Resume menu item updates more reliably. * Changing plugin settings while suspended works nicer; less likely to crash/hang/etc (ironically, changing plugin settings while running was more reliable). git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2976 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
b552c1fdc2
commit
63f62bf737
|
@ -46,15 +46,8 @@ public:
|
|||
|
||||
virtual ~SynchronousActionState() throw() {}
|
||||
|
||||
void SetException( const BaseException& ex )
|
||||
{
|
||||
m_exception = ex.Clone();
|
||||
}
|
||||
|
||||
void SetException( BaseException* ex )
|
||||
{
|
||||
m_exception = ex;
|
||||
}
|
||||
void SetException( const BaseException& ex );
|
||||
void SetException( BaseException* ex );
|
||||
|
||||
Threading::Semaphore& GetSemaphore() { return m_sema; }
|
||||
const Threading::Semaphore& GetSemaphore() const { return m_sema; }
|
||||
|
|
|
@ -41,6 +41,30 @@ void BaseDeletableObject::DoDeletion()
|
|||
// SynchronousActionState Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
void SynchronousActionState::SetException( const BaseException& ex )
|
||||
{
|
||||
m_exception = ex.Clone();
|
||||
}
|
||||
|
||||
void SynchronousActionState::SetException( BaseException* ex )
|
||||
{
|
||||
if( !m_posted )
|
||||
{
|
||||
m_exception = ex;
|
||||
}
|
||||
else if( wxTheApp )
|
||||
{
|
||||
// transport the exception to the main thread, since the message is fully
|
||||
// asynchronous, or has already entered an asynchronous state. Message is sent
|
||||
// as a non-blocking action since proper handling of user errors on async messages
|
||||
// is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog
|
||||
// box to the user.
|
||||
|
||||
pxExceptionEvent ev( ex );
|
||||
wxTheApp->AddPendingEvent( ev );
|
||||
}
|
||||
}
|
||||
|
||||
void SynchronousActionState::RethrowException() const
|
||||
{
|
||||
if( m_exception ) m_exception->Rethrow();
|
||||
|
@ -67,7 +91,8 @@ void SynchronousActionState::PostResult( int res )
|
|||
|
||||
void SynchronousActionState::ClearResult()
|
||||
{
|
||||
m_posted = false;
|
||||
m_posted = false;
|
||||
m_exception = NULL;
|
||||
}
|
||||
|
||||
void SynchronousActionState::PostResult()
|
||||
|
|
|
@ -381,9 +381,6 @@ static void intExecute()
|
|||
{
|
||||
g_EEFreezeRegs = false;
|
||||
|
||||
// Mem protection should be handled by the caller here so that it can be
|
||||
// done in a more optimized fashion.
|
||||
|
||||
try {
|
||||
if (g_SkipBiosHack) {
|
||||
do
|
||||
|
|
|
@ -101,8 +101,6 @@ namespace Exception
|
|||
};
|
||||
}
|
||||
|
||||
typedef SafeArray<u8> VmStateBuffer;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SaveStateBase class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -26,6 +26,8 @@ static const int PCSX2_VersionLo = 7;
|
|||
class SysCoreThread;
|
||||
class CpuInitializerSet;
|
||||
|
||||
typedef SafeArray<u8> VmStateBuffer;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysCoreAllocations class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -31,8 +31,6 @@
|
|||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
static DeclareTls(SysCoreThread*) tls_coreThread( NULL );
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysCoreThread *External Thread* Implementations
|
||||
// (Called from outside the context of this thread)
|
||||
|
@ -45,7 +43,8 @@ SysCoreThread::SysCoreThread()
|
|||
m_resetProfilers = true;
|
||||
m_resetVsyncTimers = true;
|
||||
m_resetVirtualMachine = true;
|
||||
m_hasValidState = false;
|
||||
|
||||
m_hasActiveMachine = false;
|
||||
}
|
||||
|
||||
SysCoreThread::~SysCoreThread() throw()
|
||||
|
@ -55,13 +54,13 @@ SysCoreThread::~SysCoreThread() throw()
|
|||
|
||||
void SysCoreThread::Cancel( bool isBlocking )
|
||||
{
|
||||
m_CoreCancelDamnit = true;
|
||||
m_hasActiveMachine = false;
|
||||
_parent::Cancel();
|
||||
}
|
||||
|
||||
bool SysCoreThread::Cancel( const wxTimeSpan& span )
|
||||
{
|
||||
m_CoreCancelDamnit = true;
|
||||
m_hasActiveMachine = false;
|
||||
if( _parent::Cancel( span ) )
|
||||
return true;
|
||||
|
||||
|
@ -70,7 +69,6 @@ bool SysCoreThread::Cancel( const wxTimeSpan& span )
|
|||
|
||||
void SysCoreThread::OnStart()
|
||||
{
|
||||
m_CoreCancelDamnit = false;
|
||||
_parent::OnStart();
|
||||
}
|
||||
|
||||
|
@ -93,37 +91,27 @@ void SysCoreThread::Start()
|
|||
void SysCoreThread::OnResumeReady()
|
||||
{
|
||||
if( m_resetVirtualMachine )
|
||||
m_hasValidState = false;
|
||||
m_hasActiveMachine = false;
|
||||
|
||||
if( !m_hasValidState )
|
||||
if( !m_hasActiveMachine )
|
||||
m_resetRecompilers = true;
|
||||
}
|
||||
|
||||
// Tells the thread to recover from the in-memory state copy when it resumes. (thread must be
|
||||
// resumed manually).
|
||||
void SysCoreThread::RecoverState()
|
||||
{
|
||||
pxAssumeDev( IsPaused(), "Unsafe use of RecoverState function; Corethread is not paused/closed." );
|
||||
m_resetRecompilers = true;
|
||||
m_hasValidState = false;
|
||||
}
|
||||
|
||||
void SysCoreThread::Reset()
|
||||
{
|
||||
Suspend();
|
||||
m_resetVirtualMachine = true;
|
||||
m_hasValidState = false;
|
||||
}
|
||||
|
||||
// This function *will* reset the emulator in order to allow the specified elf file to
|
||||
// take effect. This is because it really doesn't make sense to change the elf file outside
|
||||
// the context of a reset/restart.
|
||||
void SysCoreThread::SetElfOverride( const wxString& elf )
|
||||
{
|
||||
pxAssertDev( !m_hasValidState, "Thread synchronization error while assigning ELF override." );
|
||||
//pxAssertDev( !m_hasValidMachine, "Thread synchronization error while assigning ELF override." );
|
||||
m_elf_override = elf;
|
||||
}
|
||||
|
||||
void SysCoreThread::Reset()
|
||||
{
|
||||
Suspend();
|
||||
m_resetVirtualMachine = true;
|
||||
m_hasActiveMachine = false;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -143,40 +131,24 @@ void SysCoreThread::ApplySettings( const Pcsx2Config& src )
|
|||
const_cast<Pcsx2Config&>(EmuConfig) = src;
|
||||
}
|
||||
|
||||
void SysCoreThread::UploadStateCopy( const VmStateBuffer& copy )
|
||||
{
|
||||
if( !pxAssertDev( IsPaused(), "CoreThread is not paused; new VM state cannot be uploaded." ) ) return;
|
||||
|
||||
SysClearExecutionCache();
|
||||
memLoadingState( copy ).FreezeAll();
|
||||
m_resetVirtualMachine = false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysCoreThread *Worker* Implementations
|
||||
// (Called from the context of this thread only)
|
||||
// --------------------------------------------------------------------------------------
|
||||
SysCoreThread& SysCoreThread::Get()
|
||||
{
|
||||
pxAssertMsg( tls_coreThread != NULL, L"This function must be called from the context of a running SysCoreThread." );
|
||||
return *tls_coreThread;
|
||||
}
|
||||
|
||||
bool SysCoreThread::HasPendingStateChangeRequest() const
|
||||
{
|
||||
return m_CoreCancelDamnit || GetMTGS().HasPendingException() || _parent::HasPendingStateChangeRequest();
|
||||
return !m_hasActiveMachine || GetMTGS().HasPendingException() || _parent::HasPendingStateChangeRequest();
|
||||
}
|
||||
|
||||
struct ScopedBool_ClearOnError
|
||||
{
|
||||
bool& m_target;
|
||||
bool m_success;
|
||||
|
||||
ScopedBool_ClearOnError( bool& target ) :
|
||||
m_target( target ), m_success( false )
|
||||
{
|
||||
m_target = true;
|
||||
}
|
||||
|
||||
virtual ~ScopedBool_ClearOnError()
|
||||
{
|
||||
m_target = m_success;
|
||||
}
|
||||
|
||||
void Success() { m_success = true; }
|
||||
};
|
||||
|
||||
void SysCoreThread::_reset_stuff_as_needed()
|
||||
{
|
||||
if( m_resetVirtualMachine || m_resetRecompilers || m_resetProfilers )
|
||||
|
@ -198,7 +170,7 @@ void SysCoreThread::_reset_stuff_as_needed()
|
|||
{
|
||||
UpdateVSyncRate();
|
||||
frameLimitReset();
|
||||
m_resetVsyncTimers = false;
|
||||
m_resetVsyncTimers = false;
|
||||
}
|
||||
|
||||
SetCPUState( EmuConfig.Cpu.sseMXCSR, EmuConfig.Cpu.sseVUMXCSR );
|
||||
|
@ -210,17 +182,6 @@ void SysCoreThread::DoCpuReset()
|
|||
cpuReset();
|
||||
}
|
||||
|
||||
void SysCoreThread::CpuInitializeMess()
|
||||
{
|
||||
if( m_hasValidState ) return;
|
||||
|
||||
_reset_stuff_as_needed();
|
||||
|
||||
ScopedBool_ClearOnError sbcoe( m_hasValidState );
|
||||
|
||||
sbcoe.Success();
|
||||
}
|
||||
|
||||
void SysCoreThread::PostVsyncToUI()
|
||||
{
|
||||
}
|
||||
|
@ -245,32 +206,30 @@ void SysCoreThread::StateCheckInThread()
|
|||
GetMTGS().RethrowException();
|
||||
_parent::StateCheckInThread();
|
||||
|
||||
if( !m_hasValidState )
|
||||
throw Exception::RuntimeError( "Invalid emulation state detected; Virtual machine threads have been cancelled." );
|
||||
|
||||
_reset_stuff_as_needed(); // kinda redundant but could catch unexpected threaded state changes...
|
||||
}
|
||||
|
||||
// Allows an override point and solves an SEH "exception-type boundary" problem (can't mix
|
||||
// SEH and C++ exceptions in the same function).
|
||||
// Runs CPU cycles indefinitely, until the user or another thread requests execution to break.
|
||||
// Rationale: This very short function allows an override point and solves an SEH
|
||||
// "exception-type boundary" problem (can't mix SEH and C++ exceptions in the same function).
|
||||
void SysCoreThread::DoCpuExecute()
|
||||
{
|
||||
m_hasActiveMachine = true;
|
||||
Cpu->Execute();
|
||||
}
|
||||
|
||||
void SysCoreThread::ExecuteTaskInThread()
|
||||
{
|
||||
Threading::EnableHiresScheduler();
|
||||
tls_coreThread = this;
|
||||
m_sem_event.WaitWithoutYield();
|
||||
|
||||
m_mxcsr_saved.bitmask = _mm_getcsr();
|
||||
|
||||
PCSX2_PAGEFAULT_PROTECT {
|
||||
do {
|
||||
while(true) {
|
||||
StateCheckInThread();
|
||||
DoCpuExecute();
|
||||
} while( true );
|
||||
}
|
||||
} PCSX2_PAGEFAULT_EXCEPT;
|
||||
}
|
||||
|
||||
|
@ -282,23 +241,19 @@ void SysCoreThread::OnSuspendInThread()
|
|||
void SysCoreThread::OnResumeInThread( bool isSuspended )
|
||||
{
|
||||
GetCorePlugins().Open();
|
||||
|
||||
CpuInitializeMess();
|
||||
}
|
||||
|
||||
|
||||
// Invoked by the pthread_exit or pthread_cancel.
|
||||
void SysCoreThread::OnCleanupInThread()
|
||||
{
|
||||
m_hasValidState = false;
|
||||
|
||||
_mm_setcsr( m_mxcsr_saved.bitmask );
|
||||
|
||||
Threading::DisableHiresScheduler();
|
||||
m_hasActiveMachine = false;
|
||||
|
||||
GetCorePlugins().Close();
|
||||
GetCorePlugins().Shutdown();
|
||||
|
||||
tls_coreThread = NULL;
|
||||
_mm_setcsr( m_mxcsr_saved.bitmask );
|
||||
Threading::DisableHiresScheduler();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,14 +15,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "System.h"
|
||||
|
||||
#include "Utilities/PersistentThread.h"
|
||||
#include "Utilities/RwMutex.h"
|
||||
#include "x86emitter/tools.h"
|
||||
|
||||
#include "CDVD/CDVDaccess.h"
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
typedef SafeArray<u8> VmStateBuffer;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysThreadBase
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -156,52 +158,47 @@ class SysCoreThread : public SysThreadBase
|
|||
typedef SysThreadBase _parent;
|
||||
|
||||
protected:
|
||||
s32 m_CloseTemporary;
|
||||
|
||||
bool m_resetRecompilers;
|
||||
bool m_resetProfilers;
|
||||
bool m_resetVsyncTimers;
|
||||
bool m_resetVirtualMachine;
|
||||
bool m_hasValidState;
|
||||
|
||||
// Used by SETJMP only, but ifdef'ing it out clutters up the code.
|
||||
bool m_CoreCancelDamnit;
|
||||
// Indicates if the system has an active virtual machine state. Pretty much always
|
||||
// true anytime between plugins being initialized and plugins being shutdown. Gets
|
||||
// set false when plugins are shutdown, the corethread is canceled, or when an error
|
||||
// occurs while trying to upload a new state into the VM.
|
||||
volatile bool m_hasActiveMachine;
|
||||
|
||||
wxString m_elf_override;
|
||||
|
||||
SSE_MXCSR m_mxcsr_saved;
|
||||
|
||||
public:
|
||||
static SysCoreThread& Get();
|
||||
|
||||
public:
|
||||
explicit SysCoreThread();
|
||||
virtual ~SysCoreThread() throw();
|
||||
|
||||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
bool HasPendingStateChangeRequest() const;
|
||||
|
||||
virtual void OnResumeReady();
|
||||
virtual void Reset();
|
||||
virtual void RecoverState();
|
||||
virtual void Cancel( bool isBlocking=true );
|
||||
virtual bool Cancel( const wxTimeSpan& timeout );
|
||||
|
||||
bool HasValidState()
|
||||
{
|
||||
return m_hasValidState;
|
||||
}
|
||||
|
||||
bool HasPendingStateChangeRequest() const;
|
||||
virtual void StateCheckInThread();
|
||||
virtual void VsyncInThread();
|
||||
virtual void PostVsyncToUI()=0;
|
||||
|
||||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
virtual void UploadStateCopy( const VmStateBuffer& copy );
|
||||
|
||||
virtual bool HasActiveMachine() const { return m_hasActiveMachine; }
|
||||
|
||||
virtual const wxString& GetElfOverride() const { return m_elf_override; }
|
||||
virtual void SetElfOverride( const wxString& elf );
|
||||
|
||||
protected:
|
||||
void _reset_stuff_as_needed();
|
||||
|
||||
virtual void CpuInitializeMess();
|
||||
virtual void Start();
|
||||
virtual void OnStart();
|
||||
virtual void OnSuspendInThread();
|
||||
|
|
|
@ -503,7 +503,7 @@ public:
|
|||
// --------------------------------------------------------------------------
|
||||
|
||||
void DetectCpuAndUserMode();
|
||||
void OpenConsoleLog();
|
||||
void OpenProgramLog();
|
||||
void OpenMainFrame();
|
||||
void PrepForExit();
|
||||
void CleanupRestartable();
|
||||
|
|
|
@ -245,6 +245,8 @@ void AppPluginManager::Unload()
|
|||
|
||||
void AppPluginManager::Init( PluginsEnum_t pid )
|
||||
{
|
||||
if( !wxTheApp ) return;
|
||||
|
||||
if( !wxThread::IsMain() )
|
||||
{
|
||||
SinglePluginMethodEvent evt(&AppPluginManager::Init, pid);
|
||||
|
@ -258,7 +260,7 @@ void AppPluginManager::Init( PluginsEnum_t pid )
|
|||
|
||||
void AppPluginManager::Shutdown( PluginsEnum_t pid )
|
||||
{
|
||||
if( !wxThread::IsMain() )
|
||||
if( !wxThread::IsMain() && wxTheApp )
|
||||
{
|
||||
SinglePluginMethodEvent evt( &AppPluginManager::Shutdown, pid );
|
||||
wxGetApp().ProcessAction( evt );
|
||||
|
@ -280,6 +282,9 @@ void AppPluginManager::Shutdown()
|
|||
{
|
||||
_parent::Shutdown();
|
||||
PostPluginStatus( CorePlugins_Shutdown );
|
||||
|
||||
// Precautionary, in case an error occurs during saving a single plugin.
|
||||
sApp.CloseGsPanel();
|
||||
}
|
||||
|
||||
void AppPluginManager::Close()
|
||||
|
@ -502,62 +507,39 @@ void ShutdownPlugins()
|
|||
GetSysExecutorThread().PostEvent( new SysExecEvent_ShutdownPlugins() );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SaveSinglePluginHelper (Implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
SaveSinglePluginHelper::SaveSinglePluginHelper( PluginsEnum_t pid )
|
||||
: m_plugstore( L"PluginConf Savestate" )
|
||||
void SysExecEvent_SaveSinglePlugin::InvokeEvent()
|
||||
{
|
||||
s_DisableGsWindow = true;
|
||||
|
||||
m_pid = pid;
|
||||
m_validstate = SysHasValidState();
|
||||
s_DisableGsWindow = true; // keeps the GS window smooth by avoiding closing the window
|
||||
|
||||
ScopedCoreThreadPause paused_core;
|
||||
_LoadPluginsImmediate();
|
||||
if( !CorePlugins.AreLoaded() ) return;
|
||||
|
||||
if( !m_validstate ) return;
|
||||
Console.WriteLn( Color_Green, L"Suspending single plugin: " + tbl_PluginInfo[m_pid].GetShortname() );
|
||||
ScopedPtr<VmStateBuffer> plugstore;
|
||||
|
||||
memSavingState save( m_plugstore );
|
||||
GetCorePlugins().Freeze( m_pid, save );
|
||||
GetCorePlugins().Close( pid );
|
||||
}
|
||||
|
||||
SaveSinglePluginHelper::~SaveSinglePluginHelper() throw()
|
||||
{
|
||||
bool allowResume = true;
|
||||
|
||||
try {
|
||||
if( m_validstate )
|
||||
{
|
||||
Console.WriteLn( Color_Green, L"Recovering single plugin: " + tbl_PluginInfo[m_pid].GetShortname() );
|
||||
memLoadingState load( m_plugstore );
|
||||
//if( m_plugstore.IsDisposed() ) load.SeekToSection( m_pid );
|
||||
GetCorePlugins().Open( m_pid );
|
||||
GetCorePlugins().Freeze( m_pid, load );
|
||||
}
|
||||
|
||||
s_DisableGsWindow = false;
|
||||
}
|
||||
catch( BaseException& ex )
|
||||
if( CoreThread.HasActiveMachine() )
|
||||
{
|
||||
allowResume = false;
|
||||
wxGetApp().PostEvent( pxExceptionEvent( ex ) );
|
||||
|
||||
//Console.Error( "Unhandled BaseException in %s (ignored!):", __pxFUNCTION__ );
|
||||
//Console.Error( ex.FormatDiagnosticMessage() );
|
||||
Console.WriteLn( Color_Green, L"Suspending single plugin: " + tbl_PluginInfo[m_pid].GetShortname() );
|
||||
memSavingState save( plugstore=new VmStateBuffer(L"StateCopy_SinglePlugin") );
|
||||
GetCorePlugins().Freeze( m_pid, save );
|
||||
}
|
||||
catch( std::exception& ex )
|
||||
{
|
||||
allowResume = false;
|
||||
wxGetApp().PostEvent( pxExceptionEvent(new Exception::RuntimeError( ex, L"SaveSinglePlugin" )) );
|
||||
|
||||
//Console.Error( "Unhandled std::exception in %s (ignored!):", __pxFUNCTION__ );
|
||||
//Console.Error( ex.what() );
|
||||
GetCorePlugins().Close( m_pid );
|
||||
_post_and_wait( paused_core );
|
||||
|
||||
if( plugstore )
|
||||
{
|
||||
Console.WriteLn( Color_Green, L"Recovering single plugin: " + tbl_PluginInfo[m_pid].GetShortname() );
|
||||
memLoadingState load( plugstore );
|
||||
GetCorePlugins().Freeze( m_pid, load );
|
||||
GetCorePlugins().Close( m_pid ); // hack for stupid GS plugins.
|
||||
}
|
||||
|
||||
s_DisableGsWindow = false;
|
||||
if( allowResume ) m_scoped_pause.AllowResume();
|
||||
paused_core.AllowResume();
|
||||
}
|
||||
|
||||
void SysExecEvent_SaveSinglePlugin::CleanupEvent()
|
||||
{
|
||||
s_DisableGsWindow = false;
|
||||
_parent::CleanupEvent();
|
||||
}
|
||||
|
|
|
@ -25,41 +25,6 @@
|
|||
__aligned16 SysMtgsThread mtgsThread;
|
||||
__aligned16 AppCoreThread CoreThread;
|
||||
|
||||
static void PostCoreStatus( CoreThreadStatus pevt )
|
||||
{
|
||||
sApp.PostAction( CoreThreadStatusEvent( pevt ) );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppCoreThread Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
AppCoreThread::AppCoreThread() : SysCoreThread()
|
||||
{
|
||||
}
|
||||
|
||||
AppCoreThread::~AppCoreThread() throw()
|
||||
{
|
||||
_parent::Cancel(); // use parent's, skips thread affinity check.
|
||||
}
|
||||
|
||||
void AppCoreThread::Cancel( bool isBlocking )
|
||||
{
|
||||
AffinityAssert_AllowFrom_SysExecutor();
|
||||
_parent::Cancel( wxTimeSpan(0, 0, 2, 0) );
|
||||
}
|
||||
|
||||
void AppCoreThread::Shutdown()
|
||||
{
|
||||
AffinityAssert_AllowFrom_SysExecutor();
|
||||
_parent::Reset();
|
||||
CorePlugins.Shutdown();
|
||||
}
|
||||
|
||||
ExecutorThread& GetSysExecutorThread()
|
||||
{
|
||||
return wxGetApp().SysExecutorThread;
|
||||
}
|
||||
|
||||
typedef void (AppCoreThread::*FnPtr_CoreThreadMethod)();
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -95,6 +60,41 @@ bool ProcessingMethodViaThread( FnPtr_CoreThreadMethod method )
|
|||
return false;
|
||||
}
|
||||
|
||||
static void PostCoreStatus( CoreThreadStatus pevt )
|
||||
{
|
||||
sApp.PostAction( CoreThreadStatusEvent( pevt ) );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppCoreThread Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
AppCoreThread::AppCoreThread() : SysCoreThread()
|
||||
{
|
||||
}
|
||||
|
||||
AppCoreThread::~AppCoreThread() throw()
|
||||
{
|
||||
_parent::Cancel(); // use parent's, skips thread affinity check.
|
||||
}
|
||||
|
||||
void AppCoreThread::Cancel( bool isBlocking )
|
||||
{
|
||||
AffinityAssert_AllowFrom_SysExecutor();
|
||||
_parent::Cancel( wxTimeSpan(0, 0, 2, 0) );
|
||||
}
|
||||
|
||||
void AppCoreThread::Shutdown()
|
||||
{
|
||||
AffinityAssert_AllowFrom_SysExecutor();
|
||||
_parent::Reset();
|
||||
CorePlugins.Shutdown();
|
||||
}
|
||||
|
||||
ExecutorThread& GetSysExecutorThread()
|
||||
{
|
||||
return wxGetApp().SysExecutorThread;
|
||||
}
|
||||
|
||||
static void _Suspend()
|
||||
{
|
||||
GetCoreThread().Suspend(true);
|
||||
|
@ -106,8 +106,6 @@ void AppCoreThread::Suspend( bool isBlocking )
|
|||
_parent::Suspend(true);
|
||||
}
|
||||
|
||||
static int resume_tries = 0;
|
||||
|
||||
void AppCoreThread::Resume()
|
||||
{
|
||||
//if( !AffinityAssert_AllowFrom_SysExecutor() ) return;
|
||||
|
@ -117,31 +115,11 @@ void AppCoreThread::Resume()
|
|||
return;
|
||||
}
|
||||
|
||||
if( m_ExecMode == ExecMode_Opened || (m_CloseTemporary > 0) ) return;
|
||||
|
||||
if( !pxAssert( CorePlugins.AreLoaded() ) ) return;
|
||||
//if( m_ExecMode == ExecMode_Opened ) return;
|
||||
//if( !pxAssert( CorePlugins.AreLoaded() ) ) return;
|
||||
|
||||
_parent::Resume();
|
||||
|
||||
if( m_ExecMode != ExecMode_Opened )
|
||||
{
|
||||
// Resume failed for some reason, so update GUI statuses and post a message to
|
||||
// try again on the resume.
|
||||
|
||||
PostCoreStatus( CoreThread_Suspended );
|
||||
|
||||
if( (m_ExecMode != ExecMode_Closing) || (m_ExecMode != ExecMode_Pausing) )
|
||||
{
|
||||
if( ++resume_tries <= 2 )
|
||||
{
|
||||
sApp.SysExecute();
|
||||
}
|
||||
else
|
||||
Console.WriteLn( Color_Orange, "SysResume: Multiple resume retries failed. Giving up..." );
|
||||
}
|
||||
}
|
||||
|
||||
resume_tries = 0;
|
||||
}
|
||||
|
||||
void AppCoreThread::ChangeCdvdSource()
|
||||
|
@ -247,151 +225,69 @@ void AppCoreThread::StateCheckInThread()
|
|||
_parent::StateCheckInThread();
|
||||
}
|
||||
|
||||
// Thread Affinity: This function is called from the SysCoreThread. :)
|
||||
void AppCoreThread::CpuInitializeMess()
|
||||
void AppCoreThread::UploadStateCopy( const VmStateBuffer& copy )
|
||||
{
|
||||
if( m_hasValidState ) return;
|
||||
|
||||
if( StateCopy_IsValid() )
|
||||
{
|
||||
// Automatic recovery system if a state exists in memory. This is executed here
|
||||
// in order to ensure the plugins are in the proper (loaded/opened) state.
|
||||
|
||||
SysClearExecutionCache();
|
||||
memLoadingState( StateCopy_GetBuffer() ).FreezeAll();
|
||||
StateCopy_Clear();
|
||||
|
||||
m_hasValidState = true;
|
||||
m_resetVirtualMachine = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_parent::CpuInitializeMess();
|
||||
ScopedCoreThreadPause paused_core;
|
||||
_parent::UploadStateCopy( copy );
|
||||
paused_core.AllowResume();
|
||||
}
|
||||
|
||||
|
||||
void AppCoreThread::ExecuteTaskInThread()
|
||||
{
|
||||
PostCoreStatus( CoreThread_Started );
|
||||
_parent::ExecuteTaskInThread();
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
FullStop_BlockingResume
|
||||
, FullStop_NonblockingResume
|
||||
, FullStop_SkipResume
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseSysExecEvent_ScopedCore
|
||||
// BaseSysExecEvent_ScopedCore / SysExecEvent_CoreThreadClose / SysExecEvent_CoreThreadPause
|
||||
// --------------------------------------------------------------------------------------
|
||||
class BaseSysExecEvent_ScopedCore : public SysExecEvent
|
||||
void BaseSysExecEvent_ScopedCore::_post_and_wait( IScopedCoreThread& core )
|
||||
{
|
||||
protected:
|
||||
SynchronousActionState* m_resume;
|
||||
Threading::Mutex* m_mtx_resume;
|
||||
DoScopedTask();
|
||||
|
||||
public:
|
||||
virtual ~BaseSysExecEvent_ScopedCore() throw() {}
|
||||
ScopedLock lock( m_mtx_resume );
|
||||
PostResult();
|
||||
|
||||
protected:
|
||||
BaseSysExecEvent_ScopedCore( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
: SysExecEvent( sync )
|
||||
if( m_resume )
|
||||
{
|
||||
m_resume = resume_sync;
|
||||
m_mtx_resume = mtx_resume;
|
||||
}
|
||||
|
||||
void _post_and_wait( IScopedCoreThread& core )
|
||||
{
|
||||
ScopedLock lock( m_mtx_resume );
|
||||
|
||||
PostResult();
|
||||
|
||||
if( m_resume )
|
||||
// If the sender of the message requests a non-blocking resume, then we need
|
||||
// to deallocate the m_sync object, since the sender will likely leave scope and
|
||||
// invalidate it.
|
||||
switch( m_resume->WaitForResult() )
|
||||
{
|
||||
// If the sender of the message requests a non-blocking resume, then we need
|
||||
// to deallocate the m_sync object, since the sender will likely leave scope and
|
||||
// invalidate it.
|
||||
switch( m_resume->WaitForResult() )
|
||||
{
|
||||
case FullStop_BlockingResume:
|
||||
if( m_sync ) m_sync->ClearResult();
|
||||
core.AllowResume();
|
||||
break;
|
||||
case ScopedCore_BlockingResume:
|
||||
if( m_sync ) m_sync->ClearResult();
|
||||
core.AllowResume();
|
||||
break;
|
||||
|
||||
case FullStop_NonblockingResume:
|
||||
m_sync = NULL;
|
||||
core.AllowResume();
|
||||
break;
|
||||
case ScopedCore_NonblockingResume:
|
||||
m_sync = NULL;
|
||||
core.AllowResume();
|
||||
break;
|
||||
|
||||
case FullStop_SkipResume:
|
||||
m_sync = NULL;
|
||||
break;
|
||||
}
|
||||
case ScopedCore_SkipResume:
|
||||
m_sync = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_CoreThreadClose
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysExecEvent_CoreThreadClose : public BaseSysExecEvent_ScopedCore
|
||||
void SysExecEvent_CoreThreadClose::InvokeEvent()
|
||||
{
|
||||
public:
|
||||
wxString GetEventName() const { return L"CloseCoreThread"; }
|
||||
ScopedCoreThreadClose closed_core;
|
||||
_post_and_wait(closed_core);
|
||||
closed_core.AllowResume();
|
||||
}
|
||||
|
||||
virtual ~SysExecEvent_CoreThreadClose() throw() {}
|
||||
SysExecEvent_CoreThreadClose* Clone() const
|
||||
{
|
||||
return new SysExecEvent_CoreThreadClose( *this );
|
||||
}
|
||||
|
||||
SysExecEvent_CoreThreadClose( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
: BaseSysExecEvent_ScopedCore( sync, resume_sync, mtx_resume ) { }
|
||||
|
||||
SysExecEvent_CoreThreadClose( SynchronousActionState& sync, SynchronousActionState& resume_sync, Threading::Mutex& mtx_resume )
|
||||
: BaseSysExecEvent_ScopedCore( &sync, &resume_sync, &mtx_resume ) { }
|
||||
|
||||
protected:
|
||||
void InvokeEvent()
|
||||
{
|
||||
ScopedCoreThreadClose closed_core;
|
||||
_post_and_wait(closed_core);
|
||||
closed_core.AllowResume();
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_CoreThreadPause
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysExecEvent_CoreThreadPause : public BaseSysExecEvent_ScopedCore
|
||||
void SysExecEvent_CoreThreadPause::InvokeEvent()
|
||||
{
|
||||
public:
|
||||
wxString GetEventName() const { return L"PauseCoreThread"; }
|
||||
ScopedCoreThreadPause paused_core;
|
||||
_post_and_wait(paused_core);
|
||||
paused_core.AllowResume();
|
||||
}
|
||||
|
||||
virtual ~SysExecEvent_CoreThreadPause() throw() {}
|
||||
SysExecEvent_CoreThreadPause* Clone() const
|
||||
{
|
||||
return new SysExecEvent_CoreThreadPause( *this );
|
||||
}
|
||||
|
||||
SysExecEvent_CoreThreadPause( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
: BaseSysExecEvent_ScopedCore( sync, resume_sync, mtx_resume ) { }
|
||||
|
||||
SysExecEvent_CoreThreadPause( SynchronousActionState& sync, SynchronousActionState& resume_sync, Threading::Mutex& mtx_resume )
|
||||
: BaseSysExecEvent_ScopedCore( &sync, &resume_sync, &mtx_resume ) { }
|
||||
|
||||
protected:
|
||||
void InvokeEvent()
|
||||
{
|
||||
ScopedCoreThreadPause paused_core;
|
||||
_post_and_wait(paused_core);
|
||||
paused_core.AllowResume();
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedCoreThreadClose / ScopedCoreThreadPause
|
||||
|
@ -432,13 +328,29 @@ void BaseScopedCoreThread::DoResume()
|
|||
if( !GetSysExecutorThread().IsSelf() )
|
||||
{
|
||||
//DbgCon.WriteLn("(ScopedCoreThreadPause) Threaded Scope Created!");
|
||||
m_sync_resume.PostResult( m_allowResume ? FullStop_NonblockingResume : FullStop_SkipResume );
|
||||
m_sync_resume.PostResult( m_allowResume ? ScopedCore_NonblockingResume : ScopedCore_SkipResume );
|
||||
m_mtx_resume.Wait();
|
||||
}
|
||||
else
|
||||
CoreThread.Resume();
|
||||
}
|
||||
|
||||
// Returns TRUE if the event is posted to the SysExecutor.
|
||||
// Returns FALSE if the thread *is* the SysExecutor (no message is posted, calling code should
|
||||
// handle the code directly).
|
||||
bool BaseScopedCoreThread::PostToSysExec( BaseSysExecEvent_ScopedCore* msg )
|
||||
{
|
||||
if( !msg || GetSysExecutorThread().IsSelf()) return false;
|
||||
|
||||
msg->SetSyncState(m_sync);
|
||||
msg->SetResumeStates(m_sync_resume, m_mtx_resume);
|
||||
|
||||
GetSysExecutorThread().PostEvent( msg );
|
||||
m_sync.WaitForResult();
|
||||
m_sync.RethrowException();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ScopedCoreThreadClose::ScopedCoreThreadClose()
|
||||
{
|
||||
|
@ -449,16 +361,11 @@ ScopedCoreThreadClose::ScopedCoreThreadClose()
|
|||
return;
|
||||
}
|
||||
|
||||
if( !GetSysExecutorThread().IsSelf() )
|
||||
if( !PostToSysExec(new SysExecEvent_CoreThreadClose()) )
|
||||
{
|
||||
//DbgCon.WriteLn("(ScopedCoreThreadClose) Threaded Scope Created!");
|
||||
|
||||
GetSysExecutorThread().PostEvent( SysExecEvent_CoreThreadClose(m_sync, m_sync_resume, m_mtx_resume) );
|
||||
m_sync.WaitForResult();
|
||||
m_sync.RethrowException();
|
||||
if( !(m_alreadyStopped = CoreThread.IsClosed()) )
|
||||
CoreThread.Suspend();
|
||||
}
|
||||
else if( !(m_alreadyStopped = CoreThread.IsClosed()) )
|
||||
CoreThread.Suspend();
|
||||
|
||||
ScopedCore_IsFullyClosed = true;
|
||||
}
|
||||
|
@ -470,7 +377,7 @@ ScopedCoreThreadClose::~ScopedCoreThreadClose() throw()
|
|||
ScopedCore_IsFullyClosed = false;
|
||||
}
|
||||
|
||||
ScopedCoreThreadPause::ScopedCoreThreadPause()
|
||||
ScopedCoreThreadPause::ScopedCoreThreadPause( BaseSysExecEvent_ScopedCore* abuse_me )
|
||||
{
|
||||
if( ScopedCore_IsFullyClosed || ScopedCore_IsPaused )
|
||||
{
|
||||
|
@ -479,16 +386,12 @@ ScopedCoreThreadPause::ScopedCoreThreadPause()
|
|||
return;
|
||||
}
|
||||
|
||||
if( !GetSysExecutorThread().IsSelf() )
|
||||
if( !abuse_me ) abuse_me = new SysExecEvent_CoreThreadPause();
|
||||
if( !PostToSysExec( abuse_me ) )
|
||||
{
|
||||
//DbgCon.WriteLn("(ScopedCoreThreadPause) Threaded Scope Created!");
|
||||
|
||||
GetSysExecutorThread().PostEvent( SysExecEvent_CoreThreadPause(m_sync, m_sync_resume, m_mtx_resume) );
|
||||
m_sync.WaitForResult();
|
||||
m_sync.RethrowException();
|
||||
if( !(m_alreadyStopped = CoreThread.IsPaused()) )
|
||||
CoreThread.Pause();
|
||||
}
|
||||
else if( !(m_alreadyStopped = CoreThread.IsPaused()) )
|
||||
CoreThread.Pause();
|
||||
|
||||
ScopedCore_IsPaused = true;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "System/SysThreads.h"
|
||||
#include "AppCommon.h"
|
||||
#include "AppCorePlugins.h"
|
||||
#include "SaveState.h"
|
||||
|
||||
#define AffinityAssert_AllowFrom_CoreThread() \
|
||||
pxAssertMsg( GetCoreThread().IsSelf(), "Thread affinity violation: Call allowed from SysCoreThread only." )
|
||||
|
@ -25,6 +26,93 @@
|
|||
#define AffinityAssert_DisallowFrom_CoreThread() \
|
||||
pxAssertMsg( !GetCoreThread().IsSelf(), "Thread affinity violation: Call is *not* allowed from SysCoreThread." )
|
||||
|
||||
class IScopedCoreThread;
|
||||
class BaseScopedCoreThread;
|
||||
|
||||
enum ScopedCoreResumeType
|
||||
{
|
||||
ScopedCore_BlockingResume
|
||||
, ScopedCore_NonblockingResume
|
||||
, ScopedCore_SkipResume
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseSysExecEvent_ScopedCore
|
||||
// --------------------------------------------------------------------------------------
|
||||
class BaseSysExecEvent_ScopedCore : public SysExecEvent
|
||||
{
|
||||
protected:
|
||||
SynchronousActionState* m_resume;
|
||||
Threading::Mutex* m_mtx_resume;
|
||||
|
||||
public:
|
||||
virtual ~BaseSysExecEvent_ScopedCore() throw() {}
|
||||
|
||||
BaseSysExecEvent_ScopedCore& SetResumeStates( SynchronousActionState* sync, Threading::Mutex* mutex )
|
||||
{
|
||||
m_resume = sync;
|
||||
m_mtx_resume = mutex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseSysExecEvent_ScopedCore& SetResumeStates( SynchronousActionState& sync, Threading::Mutex& mutex )
|
||||
{
|
||||
m_resume = &sync;
|
||||
m_mtx_resume = &mutex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
BaseSysExecEvent_ScopedCore( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
: SysExecEvent( sync )
|
||||
{
|
||||
m_resume = resume_sync;
|
||||
m_mtx_resume = mtx_resume;
|
||||
}
|
||||
|
||||
void _post_and_wait( IScopedCoreThread& core );
|
||||
|
||||
virtual void DoScopedTask() {}
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_CoreThreadClose
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysExecEvent_CoreThreadClose : public BaseSysExecEvent_ScopedCore
|
||||
{
|
||||
public:
|
||||
wxString GetEventName() const { return L"CloseCoreThread"; }
|
||||
|
||||
virtual ~SysExecEvent_CoreThreadClose() throw() {}
|
||||
SysExecEvent_CoreThreadClose* Clone() const { return new SysExecEvent_CoreThreadClose( *this ); }
|
||||
|
||||
SysExecEvent_CoreThreadClose( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
: BaseSysExecEvent_ScopedCore( sync, resume_sync, mtx_resume ) { }
|
||||
|
||||
protected:
|
||||
void InvokeEvent();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_CoreThreadPause
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysExecEvent_CoreThreadPause : public BaseSysExecEvent_ScopedCore
|
||||
{
|
||||
public:
|
||||
wxString GetEventName() const { return L"PauseCoreThread"; }
|
||||
|
||||
virtual ~SysExecEvent_CoreThreadPause() throw() {}
|
||||
SysExecEvent_CoreThreadPause* Clone() const { return new SysExecEvent_CoreThreadPause( *this ); }
|
||||
|
||||
SysExecEvent_CoreThreadPause( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
: BaseSysExecEvent_ScopedCore( sync, resume_sync, mtx_resume ) { }
|
||||
|
||||
protected:
|
||||
void InvokeEvent();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppCoreThread class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -41,9 +129,11 @@ public:
|
|||
virtual void Shutdown();
|
||||
virtual void Cancel( bool isBlocking=true );
|
||||
virtual void StateCheckInThread();
|
||||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
virtual void ChangeCdvdSource();
|
||||
|
||||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
virtual void UploadStateCopy( const VmStateBuffer& copy );
|
||||
|
||||
protected:
|
||||
virtual void OnResumeReady();
|
||||
virtual void OnResumeInThread( bool IsSuspended );
|
||||
|
@ -52,10 +142,11 @@ protected:
|
|||
virtual void PostVsyncToUI();
|
||||
virtual void ExecuteTaskInThread();
|
||||
virtual void DoCpuReset();
|
||||
virtual void CpuInitializeMess();
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IScopedCoreThread / BaseScopedCoreThread
|
||||
// --------------------------------------------------------------------------------------
|
||||
class IScopedCoreThread
|
||||
{
|
||||
protected:
|
||||
|
@ -67,7 +158,6 @@ public:
|
|||
virtual void DisallowResume()=0;
|
||||
};
|
||||
|
||||
|
||||
class BaseScopedCoreThread : public IScopedCoreThread
|
||||
{
|
||||
DeclareNoncopyableObject( BaseScopedCoreThread );
|
||||
|
@ -87,7 +177,10 @@ public:
|
|||
virtual void AllowResume();
|
||||
virtual void DisallowResume();
|
||||
|
||||
virtual bool PostToSysExec( BaseSysExecEvent_ScopedCore* msg );
|
||||
|
||||
protected:
|
||||
// Called from destructors -- do not make virtual!!
|
||||
void DoResume();
|
||||
};
|
||||
|
||||
|
@ -120,12 +213,12 @@ public:
|
|||
void LoadPlugins();
|
||||
};
|
||||
|
||||
struct ScopedCoreThreadPause : public BaseScopedCoreThread
|
||||
struct ScopedCoreThreadPause : public BaseScopedCoreThread
|
||||
{
|
||||
typedef BaseScopedCoreThread _parent;
|
||||
|
||||
public:
|
||||
ScopedCoreThreadPause();
|
||||
ScopedCoreThreadPause( BaseSysExecEvent_ScopedCore* abuse_me=NULL );
|
||||
virtual ~ScopedCoreThreadPause() throw();
|
||||
};
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ void Pcsx2App::DetectCpuAndUserMode()
|
|||
AppConfig_OnChangedSettingsFolder();
|
||||
|
||||
PostAppMethod( &Pcsx2App::OpenMainFrame );
|
||||
PostAppMethod( &Pcsx2App::OpenConsoleLog );
|
||||
PostAppMethod( &Pcsx2App::OpenProgramLog );
|
||||
PostAppMethod( &Pcsx2App::AllocateCoreStuffs );
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,7 @@ void Pcsx2App::OpenMainFrame()
|
|||
deleteme->Destroy();
|
||||
g_Conf->ProgLogBox.Visible = true;
|
||||
m_id_ProgramLogBox = wxID_ANY;
|
||||
PostIdleAppMethod( &Pcsx2App::OpenConsoleLog );
|
||||
PostIdleAppMethod( &Pcsx2App::OpenProgramLog );
|
||||
}
|
||||
|
||||
SetTopWindow( mainFrame ); // not really needed...
|
||||
|
@ -224,11 +224,14 @@ void Pcsx2App::OpenMainFrame()
|
|||
mainFrame->Show();
|
||||
}
|
||||
|
||||
void Pcsx2App::OpenConsoleLog()
|
||||
void Pcsx2App::OpenProgramLog()
|
||||
{
|
||||
if( GetProgramLog() != NULL ) return;
|
||||
wxWindow* m_current_focus = wxGetActiveWindow();
|
||||
m_id_ProgramLogBox = (new ConsoleLogFrame( GetMainFramePtr(), L"PCSX2 Program Log", g_Conf->ProgLogBox ))->GetId();
|
||||
EnableAllLogging();
|
||||
|
||||
if( m_current_focus ) m_current_focus->SetFocus();
|
||||
}
|
||||
|
||||
void Pcsx2App::AllocateCoreStuffs()
|
||||
|
|
|
@ -404,12 +404,20 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::SaveStateLoadError& ex)
|
||||
{
|
||||
// Saved state load failed.
|
||||
// Saved state load failed prior to the system getting corrupted (ie, file not found
|
||||
// or some zipfile error) -- so log it and resume emulation.
|
||||
Console.Warning( ex.FormatDiagnosticMessage() );
|
||||
StateCopy_Clear();
|
||||
CoreThread.Resume();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::PluginOpenError& ex )
|
||||
{
|
||||
// Should need to do much here -- all systems should be in an inert and (sorta safe!) state.
|
||||
|
||||
Console.Error( ex.FormatDiagnosticMessage() );
|
||||
AddIdleEvent( PluginInitErrorEvent(ex) );
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::PluginInitError& ex )
|
||||
{
|
||||
ShutdownPlugins();
|
||||
|
@ -417,6 +425,7 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
Console.Error( ex.FormatDiagnosticMessage() );
|
||||
AddIdleEvent( PluginInitErrorEvent(ex) );
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::PluginError& ex )
|
||||
{
|
||||
UnloadPlugins();
|
||||
|
@ -885,7 +894,7 @@ protected:
|
|||
else if( CDVD == NULL )
|
||||
CDVDsys_ChangeSource( CDVDsrc_NoDisc );
|
||||
|
||||
if( m_UseELFOverride && !CoreThread.HasValidState() )
|
||||
if( m_UseELFOverride && !CoreThread.HasActiveMachine() )
|
||||
CoreThread.SetElfOverride( m_elf_override );
|
||||
|
||||
CoreThread.Resume();
|
||||
|
@ -926,7 +935,6 @@ public:
|
|||
protected:
|
||||
void InvokeEvent()
|
||||
{
|
||||
StateCopy_Clear();
|
||||
CoreThread.Shutdown();
|
||||
}
|
||||
|
||||
|
@ -945,7 +953,7 @@ void Pcsx2App::SysShutdown()
|
|||
// state (such as saving it), you *must* suspend the Corethread first!
|
||||
__forceinline bool SysHasValidState()
|
||||
{
|
||||
return CoreThread.HasValidState() || StateCopy_IsValid();
|
||||
return CoreThread.HasActiveMachine();
|
||||
}
|
||||
|
||||
// Writes text to console and updates the window status bar and/or HUD or whateverness.
|
||||
|
|
|
@ -19,35 +19,44 @@
|
|||
#include "SaveState.h"
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SaveSinglePluginHelper
|
||||
// SysExecEvent_SaveSinglePlugin
|
||||
// --------------------------------------------------------------------------------------
|
||||
// A scoped convenience class for closing a single plugin and saving its state to memory.
|
||||
// Emulation is suspended as needed, and is restored when the object leaves scope. Within
|
||||
// the scope of the object, code is free to call plugin re-configurations or even unload
|
||||
// a plugin entirely and re-load a different plugin in its place.
|
||||
// fixme : Ideally this should use either Close or Pause depending on if the system is in
|
||||
// Fullscreen Exclusive mode or regular mode. But since we don't yet support Fullscreen
|
||||
// Exclusive mode, and since I'm too lazy to make some third suspend class for that, we're
|
||||
// just using CoreThreadPause. --air
|
||||
//
|
||||
class SaveSinglePluginHelper
|
||||
class SysExecEvent_SaveSinglePlugin : public BaseSysExecEvent_ScopedCore
|
||||
{
|
||||
typedef BaseSysExecEvent_ScopedCore _parent;
|
||||
|
||||
protected:
|
||||
VmStateBuffer m_plugstore;
|
||||
bool m_validstate;
|
||||
PluginsEnum_t m_pid;
|
||||
|
||||
ScopedCoreThreadPause m_scoped_pause;
|
||||
|
||||
public:
|
||||
SaveSinglePluginHelper( PluginsEnum_t pid );
|
||||
virtual ~SaveSinglePluginHelper() throw();
|
||||
wxString GetEventName() const { return L"SaveSinglePlugin"; }
|
||||
|
||||
virtual ~SysExecEvent_SaveSinglePlugin() throw() {}
|
||||
SysExecEvent_SaveSinglePlugin* Clone() const { return new SysExecEvent_SaveSinglePlugin( *this ); }
|
||||
|
||||
SysExecEvent_SaveSinglePlugin( PluginsEnum_t pid=PluginId_GS )
|
||||
{
|
||||
m_pid = pid;
|
||||
}
|
||||
|
||||
SysExecEvent_SaveSinglePlugin& SetPluginId( PluginsEnum_t pid )
|
||||
{
|
||||
m_pid = pid;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
void InvokeEvent();
|
||||
void CleanupEvent();
|
||||
};
|
||||
|
||||
|
||||
extern VmStateBuffer& StateCopy_GetBuffer();
|
||||
extern bool StateCopy_IsValid();
|
||||
|
||||
extern void StateCopy_FreezeToMem();
|
||||
|
||||
extern void StateCopy_SaveToFile( const wxString& file );
|
||||
extern void StateCopy_LoadFromFile( const wxString& file );
|
||||
extern void StateCopy_SaveToSlot( uint num );
|
||||
extern void StateCopy_LoadFromSlot( uint slot );
|
||||
extern void StateCopy_Clear();
|
||||
|
|
|
@ -283,13 +283,13 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
|
|||
_("When checked the log window will be visible over other foreground windows."), wxITEM_CHECK );
|
||||
//menuAppear.Append( wxID_ANY, _("Font Size"), &menuFontSizes );
|
||||
|
||||
menuLog.Append(wxID_SAVE, _("&Save..."), _("Save log contents to file"));
|
||||
menuLog.Append(wxID_CLEAR, _("C&lear"), _("Clear the log window contents"));
|
||||
menuLog.Append(wxID_SAVE, _("&Save..."), _("Save log contents to file"));
|
||||
menuLog.Append(wxID_CLEAR, _("C&lear"), _("Clear the log window contents"));
|
||||
menuLog.AppendSeparator();
|
||||
menuLog.AppendSubMenu( &menuAppear, _("Appearance") );
|
||||
menuLog.Append(wxID_ANY, _("Show Legend"), _("Displays the console color legend.") );
|
||||
menuLog.AppendSeparator();
|
||||
menuLog.Append(wxID_CLOSE, _("&Close"), _("Close this log window; contents are preserved"));
|
||||
menuLog.Append(wxID_CLOSE, _("&Close"), _("Close this log window; contents are preserved"));
|
||||
|
||||
// Source Selection/Toggle menu
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ FirstTimeWizard::~FirstTimeWizard() throw()
|
|||
static void _OpenConsole()
|
||||
{
|
||||
g_Conf->ProgLogBox.Visible = true;
|
||||
wxGetApp().OpenConsoleLog();
|
||||
wxGetApp().OpenProgramLog();
|
||||
}
|
||||
|
||||
int FirstTimeWizard::ShowModal()
|
||||
|
|
|
@ -37,7 +37,7 @@ void SysExecEvent::InvokeEvent()
|
|||
|
||||
// This is called by _DoInvokeEvent *always* -- even when exceptions occur during InvokeEvent(),
|
||||
// making this function a bit like a C# 'finally' block (try/catch/finally -- a nice feature lacking
|
||||
// from C++ prior to the new C++0x10 standard).
|
||||
// from C++ prior to the new C++0x standard).
|
||||
//
|
||||
// This function calls PostResult by default, and should be invoked by derived classes overriding
|
||||
// CleanupEvent(), unless you want to change the PostResult behavior.
|
||||
|
@ -53,8 +53,7 @@ void SysExecEvent::SetException( BaseException* ex )
|
|||
{
|
||||
if( !ex ) return;
|
||||
|
||||
const wxString& prefix( wxsFormat(L"(%s) ", GetEventName().c_str()) );
|
||||
ex->DiagMsg() = prefix + ex->DiagMsg();
|
||||
ex->DiagMsg() += wxsFormat(L"(%s) ", GetEventName().c_str());
|
||||
//ex->UserMsg() = prefix + ex->UserMsg();
|
||||
|
||||
if( m_sync )
|
||||
|
@ -66,9 +65,10 @@ void SysExecEvent::SetException( BaseException* ex )
|
|||
else
|
||||
{
|
||||
// transport the exception to the main thread, since the message is fully
|
||||
// asynchronous. Message is sent as a non-blocking action since proper handling
|
||||
// of user errors on async messages is *usually* to log/ignore it (hah), or to
|
||||
// suspend emulation and issue a dialog box to the user.
|
||||
// asynchronous, or has already entered an asynchronous state. Message is sent
|
||||
// as a non-blocking action since proper handling of user errors on async messages
|
||||
// is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog
|
||||
// box to the user.
|
||||
|
||||
wxGetApp().PostEvent( pxExceptionEvent( ex ) );
|
||||
}
|
||||
|
@ -85,8 +85,8 @@ void SysExecEvent::SetException( const BaseException& ex )
|
|||
// instead, which is the intended method of implementing derived class invocation.
|
||||
void SysExecEvent::_DoInvokeEvent()
|
||||
{
|
||||
//pxAssumeDev( !IsBeingDeleted(), "Attempted to process a deleted SysExecutor event." );
|
||||
AffinityAssert_AllowFrom_SysExecutor();
|
||||
|
||||
try {
|
||||
InvokeEvent();
|
||||
}
|
||||
|
@ -99,7 +99,18 @@ void SysExecEvent::_DoInvokeEvent()
|
|||
SetException( new Exception::RuntimeError(ex) );
|
||||
}
|
||||
|
||||
CleanupEvent();
|
||||
// Cleanup Execution -- performed regardless of exception or not above.
|
||||
try {
|
||||
CleanupEvent();
|
||||
}
|
||||
catch( BaseException& ex )
|
||||
{
|
||||
SetException( ex );
|
||||
}
|
||||
catch( std::runtime_error& ex )
|
||||
{
|
||||
SetException( new Exception::RuntimeError(ex) );
|
||||
}
|
||||
}
|
||||
|
||||
// Posts an empty result to the invoking context/thread of this message, if one exists.
|
||||
|
@ -399,8 +410,11 @@ ExecutorThread::ExecutorThread( pxEvtHandler* evthandler )
|
|||
// Exposes the internal pxEvtHandler::ShutdownQueue API. See pxEvtHandler for details.
|
||||
void ExecutorThread::ShutdownQueue()
|
||||
{
|
||||
if( !m_EvtHandler || m_EvtHandler->IsShuttingDown() ) return;
|
||||
m_EvtHandler->ShutdownQueue();
|
||||
if( !m_EvtHandler ) return;
|
||||
|
||||
if( !m_EvtHandler->IsShuttingDown() )
|
||||
m_EvtHandler->ShutdownQueue();
|
||||
|
||||
Block();
|
||||
}
|
||||
|
||||
|
|
|
@ -149,8 +149,9 @@ namespace Implementations
|
|||
|
||||
void Sys_RenderToggle()
|
||||
{
|
||||
SaveSinglePluginHelper helper( PluginId_GS );
|
||||
ScopedCoreThreadPause paused_core( new SysExecEvent_SaveSinglePlugin(PluginId_GS) );
|
||||
renderswitch = !renderswitch;
|
||||
paused_core.AllowResume();
|
||||
}
|
||||
|
||||
void Sys_LoggingToggle()
|
||||
|
|
|
@ -524,62 +524,80 @@ void MainEmuFrame::ApplyCoreStatus()
|
|||
{
|
||||
wxMenuBar& menubar( *GetMenuBar() );
|
||||
|
||||
wxMenuItem& susres (*menubar.FindItem( MenuId_Sys_SuspendResume ));
|
||||
wxMenuItem& cdvd (*menubar.FindItem( MenuId_Boot_CDVD ));
|
||||
wxMenuItem& cdvd2 (*menubar.FindItem( MenuId_Boot_CDVD2 ));
|
||||
|
||||
if( !pxAssertMsg( (&susres) && (&cdvd) && (&cdvd2), "Unexpected NULL Menubar Item!" ) ) return;
|
||||
|
||||
wxMenuItem* susres = menubar.FindItem( MenuId_Sys_SuspendResume );
|
||||
wxMenuItem* cdvd = menubar.FindItem( MenuId_Boot_CDVD );
|
||||
wxMenuItem* cdvd2 = menubar.FindItem( MenuId_Boot_CDVD2 );
|
||||
wxMenuItem* restart = menubar.FindItem( MenuId_Sys_Restart );
|
||||
|
||||
if( SysHasValidState() )
|
||||
// [TODO] : Ideally each of these items would bind a listener instance to the AppCoreThread
|
||||
// dispatcher, and modify their states accordingly. This is just a hack (for now) -- air
|
||||
|
||||
bool vm = SysHasValidState();
|
||||
|
||||
if( susres )
|
||||
{
|
||||
susres.Enable();
|
||||
if( CoreThread.IsOpen() )
|
||||
{
|
||||
susres.SetText(_("Suspend"));
|
||||
susres.SetHelp(_("Safely pauses emulation and preserves the PS2 state."));
|
||||
susres->Enable();
|
||||
susres->SetText(_("Suspend"));
|
||||
susres->SetHelp(_("Safely pauses emulation and preserves the PS2 state."));
|
||||
}
|
||||
else
|
||||
{
|
||||
susres.SetText(_("Resume"));
|
||||
susres.SetHelp(_("Resumes the suspended emulation state."));
|
||||
susres->Enable(vm);
|
||||
if( vm )
|
||||
{
|
||||
susres->SetText(_("Resume"));
|
||||
susres->SetHelp(_("Resumes the suspended emulation state."));
|
||||
}
|
||||
else
|
||||
{
|
||||
susres->SetText(_("Suspend/Resume"));
|
||||
susres->SetHelp(_("No emulation state is active; cannot suspend or resume."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( restart )
|
||||
if( restart )
|
||||
{
|
||||
if( vm )
|
||||
{
|
||||
restart->SetText(_("Restart"));
|
||||
restart->SetHelp(_("Simulates hardware reset of the PS2 virtual machine."));
|
||||
}
|
||||
|
||||
cdvd.SetText(_("Reboot CDVD (full)"));
|
||||
cdvd.SetHelp(_("Hard reset of the active VM."));
|
||||
|
||||
cdvd2.SetText(_("Reboot CDVD (fast)"));
|
||||
cdvd2.SetHelp(_("Reboot using BOOT2 injection (skips splash screens)"));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
susres.Enable( false );
|
||||
susres.SetText(_("Suspend/Resume"));
|
||||
susres.SetHelp( _("No emulation state is active; cannot suspend or resume.") );
|
||||
|
||||
if( restart )
|
||||
else
|
||||
{
|
||||
restart->Enable( false );
|
||||
restart->SetHelp( _("No emulation state is active; boot something first.") );
|
||||
restart->SetHelp(_("No emulation state is active; boot something first."));
|
||||
}
|
||||
}
|
||||
|
||||
cdvd.SetText(_("Boot CDVD (full)"));
|
||||
cdvd.SetHelp(_("Boot the VM using the current DVD or Iso source media"));
|
||||
if( cdvd )
|
||||
{
|
||||
if( vm )
|
||||
{
|
||||
cdvd->SetText(_("Reboot CDVD (full)"));
|
||||
cdvd->SetHelp(_("Hard reset of the active VM."));
|
||||
}
|
||||
else
|
||||
{
|
||||
cdvd->SetText(_("Boot CDVD (full)"));
|
||||
cdvd->SetHelp(_("Boot the VM using the current DVD or Iso source media"));
|
||||
}
|
||||
}
|
||||
|
||||
cdvd2.SetText(_("Boot CDVD (fast)"));
|
||||
cdvd2.SetHelp(_("Use BOOT2 injection to skip PS2 startup and splash screens"));
|
||||
|
||||
// Old style...
|
||||
//restart.SetHelp(_("Starts execution of the PS2 virtual machine."));
|
||||
//restart.SetText(_("Start"));
|
||||
if( cdvd2 )
|
||||
{
|
||||
if( vm )
|
||||
{
|
||||
cdvd2->SetText(_("Reboot CDVD (fast)"));
|
||||
cdvd2->SetHelp(_("Reboot using BOOT2 injection (skips splash screens)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
cdvd2->SetText(_("Boot CDVD (fast)"));
|
||||
cdvd2->SetHelp(_("Use BOOT2 injection to skip PS2 startup and splash screens"));
|
||||
}
|
||||
}
|
||||
|
||||
menubar.Enable( MenuId_Sys_Shutdown, SysHasValidState() || CorePlugins.AreAnyInitialized() );
|
||||
|
|
|
@ -498,12 +498,8 @@ void MainEmuFrame::Menu_ConfigPlugin_Click(wxCommandEvent &event)
|
|||
|
||||
if( !pxAssertDev( (eventId >= 0) || (pid < PluginId_Count), "Invalid plugin identifier passed to ConfigPlugin event handler." ) ) return;
|
||||
|
||||
// This could probably just load a single plugin as needed now, but for design safety
|
||||
// I'm leaving it force-load everything until the individual plugin management is
|
||||
// better tested.
|
||||
|
||||
wxWindowDisabler disabler;
|
||||
SaveSinglePluginHelper helper( pid );
|
||||
ScopedCoreThreadPause paused_core( new SysExecEvent_SaveSinglePlugin(pid) );
|
||||
GetCorePlugins().Configure( pid );
|
||||
}
|
||||
|
||||
|
|
|
@ -251,6 +251,8 @@ void SysExecEvent_ApplyPlugins::InvokeEvent()
|
|||
{
|
||||
ScopedCoreThreadPause paused_core;
|
||||
|
||||
ScopedPtr< VmStateBuffer > buffer;
|
||||
|
||||
if( SysHasValidState() )
|
||||
{
|
||||
paused_core.AllowResume();
|
||||
|
@ -261,7 +263,7 @@ void SysExecEvent_ApplyPlugins::InvokeEvent()
|
|||
// FIXME : We only actually have to save plugins here, except the recovery code
|
||||
// in SysCoreThread isn't quite set up yet to handle that (I think...) --air
|
||||
|
||||
memSavingState( StateCopy_GetBuffer() ).FreezeAll();
|
||||
memSavingState( *(buffer.Reassign(new VmStateBuffer(L"StateBuffer_ApplyNewPlugins"))) ).FreezeAll();
|
||||
}
|
||||
|
||||
ScopedCoreThreadClose closed_core;
|
||||
|
@ -269,7 +271,8 @@ void SysExecEvent_ApplyPlugins::InvokeEvent()
|
|||
CorePlugins.Shutdown();
|
||||
CorePlugins.Unload();
|
||||
LoadPluginsImmediate();
|
||||
CoreThread.RecoverState();
|
||||
|
||||
if( buffer ) CoreThread.UploadStateCopy( *buffer );
|
||||
|
||||
PostFinishToDialog();
|
||||
|
||||
|
@ -639,7 +642,7 @@ void Panels::PluginSelectorPanel::OnConfigure_Clicked( wxCommandEvent& evt )
|
|||
if( ConfigureFnptr configfunc = (ConfigureFnptr)dynlib.GetSymbol( tbl_PluginInfo[pid].GetShortname() + L"configure" ) )
|
||||
{
|
||||
wxWindowDisabler disabler;
|
||||
SaveSinglePluginHelper helper( pid );
|
||||
ScopedCoreThreadPause paused_core( new SysExecEvent_SaveSinglePlugin(pid) );
|
||||
configfunc();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "ZipTools/ThreadedZipTools.h"
|
||||
|
||||
// Used to hold the current state backup (fullcopy of PS2 memory and plugin states).
|
||||
static VmStateBuffer state_buffer( L"Public Savestate Buffer" );
|
||||
//static VmStateBuffer state_buffer( L"Public Savestate Buffer" );
|
||||
|
||||
static const char SavestateIdentString[] = "PCSX2 Savestate";
|
||||
static const uint SavestateIdentLen = sizeof(SavestateIdentString);
|
||||
|
@ -120,7 +120,7 @@ public:
|
|||
|
||||
virtual ~SysExecEvent_DownloadState() throw() {}
|
||||
SysExecEvent_DownloadState* Clone() const { return new SysExecEvent_DownloadState( *this ); }
|
||||
SysExecEvent_DownloadState( VmStateBuffer* dest=&state_buffer )
|
||||
SysExecEvent_DownloadState( VmStateBuffer* dest=NULL )
|
||||
{
|
||||
m_dest_buffer = dest;
|
||||
}
|
||||
|
@ -238,9 +238,9 @@ protected:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_UnzipFromDisk
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Note: Unzipping always goes directly into the state_buffer, and is always a blocking
|
||||
// action on the SysExecutor thread (the system cannot execute other commands while states
|
||||
// are unzipping or uplading into the system).
|
||||
// Note: Unzipping always goes directly into the SysCoreThread's static VM state, and is
|
||||
// always a blocking action on the SysExecutor thread (the system cannot execute other
|
||||
// commands while states are unzipping or uploading into the system).
|
||||
//
|
||||
class SysExecEvent_UnzipFromDisk : public SysExecEvent
|
||||
{
|
||||
|
@ -263,7 +263,6 @@ protected:
|
|||
void InvokeEvent()
|
||||
{
|
||||
ScopedLock lock( mtx_CompressToDisk );
|
||||
|
||||
gzipReader m_gzreader(m_filename );
|
||||
SaveStateFile_ReadHeader( m_gzreader );
|
||||
|
||||
|
@ -275,13 +274,14 @@ protected:
|
|||
// fixme: should start initially with the file size, and then grow from there.
|
||||
|
||||
static const int BlockSize = 0x100000;
|
||||
state_buffer.MakeRoomFor( 0x800000 ); // start with an 8 meg buffer to avoid frequent reallocation.
|
||||
|
||||
VmStateBuffer buffer( 0x800000, L"StateBuffer_UnzipFromDisk" ); // start with an 8 meg buffer to avoid frequent reallocation.
|
||||
int curidx = 0;
|
||||
|
||||
try {
|
||||
while(true) {
|
||||
state_buffer.MakeRoomFor( curidx+BlockSize );
|
||||
m_gzreader.Read( state_buffer.GetPtr(curidx), BlockSize );
|
||||
buffer.MakeRoomFor( curidx+BlockSize );
|
||||
m_gzreader.Read( buffer.GetPtr(curidx), BlockSize );
|
||||
curidx += BlockSize;
|
||||
Threading::pxTestCancel();
|
||||
}
|
||||
|
@ -295,9 +295,10 @@ protected:
|
|||
// Optional shutdown of plugins when loading states? I'm not implementing it yet because some
|
||||
// things, like the SPU2-recovery trick, rely on not resetting the plugins prior to loading
|
||||
// the new savestate data.
|
||||
|
||||
//if( ShutdownOnStateLoad ) GetCoreThread().Cancel();
|
||||
GetCoreThread().RecoverState();
|
||||
|
||||
|
||||
GetCoreThread().UploadStateCopy( buffer );
|
||||
GetCoreThread().Resume(); // force resume regardless of emulation state earlier.
|
||||
}
|
||||
};
|
||||
|
@ -306,21 +307,6 @@ protected:
|
|||
// StateCopy Public Interface
|
||||
// =====================================================================================================
|
||||
|
||||
VmStateBuffer& StateCopy_GetBuffer()
|
||||
{
|
||||
return state_buffer;
|
||||
}
|
||||
|
||||
bool StateCopy_IsValid()
|
||||
{
|
||||
return !state_buffer.IsDisposed();
|
||||
}
|
||||
|
||||
void StateCopy_FreezeToMem()
|
||||
{
|
||||
GetSysExecutorThread().PostEvent( new SysExecEvent_DownloadState() );
|
||||
}
|
||||
|
||||
void StateCopy_SaveToFile( const wxString& file )
|
||||
{
|
||||
UI_DisableStateActions();
|
||||
|
@ -365,9 +351,3 @@ void StateCopy_LoadFromSlot( uint slot )
|
|||
|
||||
StateCopy_LoadFromFile( file );
|
||||
}
|
||||
|
||||
void StateCopy_Clear()
|
||||
{
|
||||
state_buffer.Dispose();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,12 @@
|
|||
#include "MainFrame.h"
|
||||
#include "GSFrame.h"
|
||||
|
||||
// General Notes:
|
||||
// * It's very important that we re-discover menu items by ID every time we change them,
|
||||
// because the modern era of configurable GUIs means that we can't be assured the IDs
|
||||
// exist anymore.
|
||||
|
||||
|
||||
// This is necessary because this stupid wxWidgets thing has implicit debug errors
|
||||
// in the FindItem call that asserts if the menu options are missing. This is bad
|
||||
// mojo for configurable/dynamic menus. >_<
|
||||
|
|
|
@ -63,8 +63,8 @@ public:
|
|||
const SynchronousActionState* GetSyncState() const { return m_sync; }
|
||||
SynchronousActionState* GetSyncState() { return m_sync; }
|
||||
|
||||
void SetSyncState( SynchronousActionState* obj ) { m_sync = obj; }
|
||||
void SetSyncState( SynchronousActionState& obj ) { m_sync = &obj; }
|
||||
SysExecEvent& SetSyncState( SynchronousActionState* obj ) { m_sync = obj; return *this; }
|
||||
SysExecEvent& SetSyncState( SynchronousActionState& obj ) { m_sync = &obj; return *this; }
|
||||
|
||||
// Tells the Event Handler whether or not this event can be skipped when the system
|
||||
// is being quit or reset. Typically set this to true for events which shut down the
|
||||
|
|
Loading…
Reference in New Issue