diff --git a/common/include/PS2Edefs.h b/common/include/PS2Edefs.h index 3bf3731fe2..610cd3fb84 100644 --- a/common/include/PS2Edefs.h +++ b/common/include/PS2Edefs.h @@ -48,6 +48,29 @@ #include "Pcsx2Defs.h" +/////////////////////////////////////////////////////////////////////// + +// freeze modes: +#define FREEZE_LOAD 0 +#define FREEZE_SAVE 1 +#define FREEZE_SIZE 2 + +// event values: +#define KEYPRESS 1 +#define KEYRELEASE 2 + +typedef struct { + int size; + s8 *data; +} freezeData; + +typedef struct _keyEvent { + u32 key; + u32 evt; +} keyEvent; + +/////////////////////////////////////////////////////////////////////// + #if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \ defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \ defined(USBdefs) || defined(FWdefs) @@ -172,11 +195,6 @@ typedef int (*DEV9handler)(void); typedef void (*USBcallback)(int cycles); typedef int (*USBhandler)(void); -// freeze modes: -#define FREEZE_LOAD 0 -#define FREEZE_SAVE 1 -#define FREEZE_SIZE 2 - typedef struct _GSdriverInfo { char name[8]; void *common; diff --git a/common/include/Pcsx2Defs.h b/common/include/Pcsx2Defs.h index 0ea3cdcaba..4522dc8808 100644 --- a/common/include/Pcsx2Defs.h +++ b/common/include/Pcsx2Defs.h @@ -287,20 +287,4 @@ static const int __pagesize = PCSX2_PAGESIZE; #endif -/////////////////////////////////////////////////////////////////////////////////////// - -typedef struct { - int size; - s8 *data; -} freezeData; - -// event values: -#define KEYPRESS 1 -#define KEYRELEASE 2 - -typedef struct _keyEvent { - u32 key; - u32 evt; -} keyEvent; - #endif diff --git a/common/include/Utilities/Exceptions.h b/common/include/Utilities/Exceptions.h index df2f2fec9a..015cf1f08f 100644 --- a/common/include/Utilities/Exceptions.h +++ b/common/include/Utilities/Exceptions.h @@ -337,62 +337,4 @@ namespace Exception public: DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file or stream.") ); }; - - // --------------------------------------------------------------------------------------- - // Savestate Exceptions: - // BadSavedState / FreezePluginFailure / StateLoadError / UnsupportedStateVersion / - // StateCrcMismatch - // --------------------------------------------------------------------------------------- - - // Exception thrown when a corrupted or truncated savestate is encountered. - // - class BadSavedState : public virtual BadStream - { - public: - DEFINE_STREAM_EXCEPTION( BadSavedState, wxLt("Savestate data is corrupted or incomplete.") ) - }; - - // thrown when the savestate being loaded isn't supported. - // - class UnsupportedStateVersion : public virtual BadSavedState - { - public: - u32 Version; // version number of the unsupported state. - - public: - DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion ) - - explicit UnsupportedStateVersion( int version, const wxString& objname=wxEmptyString ) - { - StreamName = objname; - Version = version; - } - - virtual wxString FormatDiagnosticMessage() const; - virtual wxString FormatDisplayMessage() const; - }; - - // A recoverable exception thrown when the CRC of the savestate does not match the - // CRC returned by the Cdvd driver. - // [feature not implemented yet] - // - class StateCrcMismatch : public virtual BadSavedState - { - public: - u32 Crc_Savestate; - u32 Crc_Cdvd; - - public: - DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch ) - - explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const wxString& objname=wxEmptyString ) - { - StreamName = objname; - Crc_Savestate = crc_save; - Crc_Cdvd = crc_cdvd; - } - - virtual wxString FormatDiagnosticMessage() const; - virtual wxString FormatDisplayMessage() const; - }; } diff --git a/common/src/Utilities/Exceptions.cpp b/common/src/Utilities/Exceptions.cpp index e838e6294b..e72ecfee62 100644 --- a/common/src/Utilities/Exceptions.cpp +++ b/common/src/Utilities/Exceptions.cpp @@ -190,41 +190,3 @@ wxString Exception::Stream::FormatDisplayMessage() const wxsFormat( _("Name: %s"), StreamName.c_str() ); } -// ------------------------------------------------------------------------ -wxString Exception::UnsupportedStateVersion::FormatDiagnosticMessage() const -{ - // Note: no stacktrace needed for this one... - return wxsFormat( L"Unknown or unsupported savestate version: 0x%x", Version ); -} - -wxString Exception::UnsupportedStateVersion::FormatDisplayMessage() const -{ - // m_message_user contains a recoverable savestate error which is helpful to the user. - return wxsFormat( - m_message_user + L"\n\n" + - wxsFormat( _("Cannot load savestate. It is of an unknown or unsupported version."), Version ) - ); -} - -// ------------------------------------------------------------------------ -wxString Exception::StateCrcMismatch::FormatDiagnosticMessage() const -{ - // Note: no stacktrace needed for this one... - return wxsFormat( - L"Game/CDVD does not match the savestate CRC.\n" - L"\tCdvd CRC: 0x%X\n\tGame CRC: 0x%X\n", - Crc_Savestate, Crc_Cdvd - ); -} - -wxString Exception::StateCrcMismatch::FormatDisplayMessage() const -{ - return wxsFormat( - m_message_user + L"\n\n" + - wxsFormat( - L"Savestate game/crc mismatch. Cdvd CRC: 0x%X Game CRC: 0x%X\n", - Crc_Savestate, Crc_Cdvd - ) - ); -} - diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index f30e297913..ff35e9b715 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -370,6 +370,11 @@ void SysMtgsThread::ExecuteTaskInThread() GSvsync(tag.data[0]); gsFrameSkip(); + // if we're not using GSOpen2, then the GS window is on this thread (MTGS thread), + // so we need to call PADupdate from here. + if( (GSopen2 == NULL) && (PADupdate != NULL) ) + PADupdate(0); + StateCheckInThread(); } break; diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index 2bb9b1baf6..b38d753e9f 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -123,7 +123,12 @@ struct LegacyApi_OptMethod }; -static s32 CALLBACK fallback_freeze(int mode, freezeData *data) { data->size = 0; return 0; } +static s32 CALLBACK fallback_freeze(int mode, freezeData *data) +{ + if( mode == FREEZE_SIZE ) data->size = 0; + return 0; +} + static void CALLBACK fallback_keyEvent(keyEvent *ev) {} static void CALLBACK fallback_setSettingsDir(const char* dir) {} static void CALLBACK fallback_configure() {} diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index bd21b530ea..71062d2b6c 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -23,6 +23,17 @@ #include +#ifdef _MSC_VER + +// Disabling C4673: throwing 'Exception::Blah' the following types will not be considered at the catch site +// The warning is bugged, and happens even though we're properly inheriting classes with +// 'virtual' qualifiers. But since the warning is potentially useful elsewhere, I disable +// it only for the scope of these exceptions. + +# pragma warning(push) +# pragma warning(disable:4673) +#endif + struct PluginInfo { const char* shortname; @@ -36,22 +47,18 @@ struct PluginInfo } }; -#ifdef _MSC_VER - -// Disabling C4673: throwing 'Exception::Blah' the following types will not be considered at the catch site -// The warning is bugged, and happens even though we're properly inheriting classes with -// 'virtual' qualifiers. But since the warning is potentially useful elsewhere, I disable -// it only for the scope of these exceptions. - -# pragma warning(push) -# pragma warning(disable:4673) -#endif - // -------------------------------------------------------------------------------------- // Plugin-related Exceptions // -------------------------------------------------------------------------------------- namespace Exception { + // Exception thrown when a corrupted or truncated savestate is encountered. + class SaveStateLoadError : public virtual BadStream + { + public: + DEFINE_STREAM_EXCEPTION( SaveStateLoadError, wxLt("Savestate data is corrupted or incomplete.") ) + }; + class PluginError : public virtual RuntimeError { public: @@ -137,7 +144,7 @@ namespace Exception virtual wxString FormatDisplayMessage() const; }; - class ThawPluginFailure : public virtual PluginError, public virtual BadSavedState + class ThawPluginFailure : public virtual PluginError, public virtual SaveStateLoadError { public: DEFINE_EXCEPTION_COPYTORS( ThawPluginFailure ) diff --git a/pcsx2/RecoverySystem.cpp b/pcsx2/RecoverySystem.cpp index b79088be68..32e781061c 100644 --- a/pcsx2/RecoverySystem.cpp +++ b/pcsx2/RecoverySystem.cpp @@ -37,6 +37,13 @@ int sys_resume_lock = 0; static FnType_OnThreadComplete* Callback_FreezeFinished = NULL; +static bool StateCopy_ForceClear() +{ + sys_resume_lock = 0; + state_buffer_lock.Release(); + state_buffer.Dispose(); +} + static void __evt_fastcall StateThread_OnAppStatus( void* thr, AppEventType& stat ) { if( (thr == NULL) || (stat != AppStatus_Exiting) ) return; @@ -378,43 +385,58 @@ void StateCopy_FreezeToMem() (new StateThread_Freeze( OnFinished_Resume ))->Start(); } -static void _acquire_and_block() +class Acquire_And_Block { - if( state_buffer_lock.TryAcquire() ) return; +protected: + bool m_DisposeWhenFinished; + bool m_Acquired; - /* - // If the state buffer is locked and we're being called from the main thread then we need - // to cancel the current action. This is needed because state_buffer_lock is only updated - // from events handled on the main thread. - - if( wxThread::IsMain() ) - throw Exception::CancelEvent( "Blocking ThawFromMem canceled due to existing state buffer lock." ); - else*/ +public: + Acquire_And_Block( bool dispose ) { - pxAssume( current_state_thread != NULL ); - do { + m_DisposeWhenFinished = dispose; + m_Acquired = false; + + /* + // If the state buffer is locked and we're being called from the main thread then we need + // to cancel the current action. This is needed because state_buffer_lock is only updated + // from events handled on the main thread. + + if( wxThread::IsMain() ) + throw Exception::CancelEvent( "Blocking ThawFromMem canceled due to existing state buffer lock." ); + else*/ + + while ( !state_buffer_lock.TryAcquire() ) + { + pxAssume( current_state_thread != NULL ); current_state_thread->Block(); wxGetApp().ProcessPendingEvents(); // Trying this for now, may or may not work due to recursive pitfalls (see above) - } while ( !state_buffer_lock.TryAcquire() ); + }; + + m_Acquired = true; } -} + + virtual ~Acquire_And_Block() throw() + { + if( m_DisposeWhenFinished ) + state_buffer.Dispose(); + + if( m_Acquired ) + state_buffer_lock.Release(); + } +}; void StateCopy_FreezeToMem_Blocking() { - _acquire_and_block(); - + Acquire_And_Block blocker( false ); memSavingState( state_buffer ).FreezeAll(); - state_buffer_lock.Release(); } // Copies the saved state into the active VM, and automatically free's the saved state data. void StateCopy_ThawFromMem_Blocking() { - _acquire_and_block(); - + Acquire_And_Block blocker( true ); memLoadingState( state_buffer ).FreezeAll(); - state_buffer.Dispose(); - state_buffer_lock.Release(); } void StateCopy_Clear() @@ -427,4 +449,3 @@ bool StateCopy_IsBusy() { return state_buffer_lock.IsLocked(); } - \ No newline at end of file diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index a76f3c2a6a..f306549846 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -27,6 +27,7 @@ using namespace R5900; + static void PreLoadPrep() { SysClearExecutionCache(); @@ -45,14 +46,14 @@ wxString SaveStateBase::GetFilename( int slot ) wxsFormat( L"%8.8X.%3.3d", ElfCRC, slot )).GetFullPath(); } -SaveStateBase::SaveStateBase( SafeArray& memblock ) : - m_memory( memblock ) -, m_version( g_SaveVersion ) -, m_idx( 0 ) -, m_sectid( FreezeId_Unknown ) -, m_pid( PluginId_GS ) -, m_DidBios( false ) +SaveStateBase::SaveStateBase( SafeArray& memblock ) + : m_memory( memblock ) { + m_version = g_SaveVersion; + m_idx = 0; + m_sectid = FreezeId_Unknown; + m_pid = PluginId_GS; + m_DidBios = false; } void SaveStateBase::PrepBlock( int size ) @@ -63,7 +64,7 @@ void SaveStateBase::PrepBlock( int size ) else { if( m_memory.GetSizeInBytes() < end ) - throw Exception::BadSavedState(); + throw Exception::SaveStateLoadError(); } } @@ -79,7 +80,7 @@ void SaveStateBase::FreezeTag( const char* src ) if( strcmp( m_tagspace, src ) != 0 ) { pxFail( "Savestate data corruption detected while reading tag" ); - throw Exception::BadSavedState( + throw Exception::SaveStateLoadError( // Untranslated diagnostic msg (use default msg for translation) L"Savestate data corruption detected while reading tag: " + fromUTF8(src) ); @@ -205,7 +206,7 @@ void SaveStateBase::WritebackSectionLength( int seekpos, int sectlen, const wxCh { if( sectlen != realsectsize ) // if they don't match then we have a problem, jim. { - throw Exception::BadSavedState( wxEmptyString, + throw Exception::SaveStateLoadError( wxEmptyString, wxsFormat( L"Invalid size encountered on section '%s'.", sectname ), _("The savestate data is invalid or corrupted.") ); @@ -234,7 +235,7 @@ bool SaveStateBase::FreezeSection( int seek_section ) if( sectlen != 128 ) { - throw Exception::BadSavedState( wxEmptyString, + throw Exception::SaveStateLoadError( wxEmptyString, L"Invalid size encountered on BiosVersion section.", _("The savestate data is invalid or corrupted.") ); @@ -257,7 +258,7 @@ bool SaveStateBase::FreezeSection( int seek_section ) Freeze( sectlen ); if( sectlen != MainMemorySizeInBytes ) { - throw Exception::BadSavedState( wxEmptyString, + throw Exception::SaveStateLoadError( wxEmptyString, L"Invalid size encountered on MainMemory section.", _("The savestate data is invalid or corrupted.") ); @@ -302,7 +303,7 @@ bool SaveStateBase::FreezeSection( int seek_section ) else g_plugins->Freeze( (PluginsEnum_t)m_pid, *this ); - WritebackSectionLength( seekpos, sectlen, L"HardwareRegisters" ); + WritebackSectionLength( seekpos, sectlen, L"Plugins" ); // following increments only affect Saving mode, which needs to be sure to save all // plugins (order doesn't matter but sequential is easy enough. (ignored by Loading mode) @@ -411,3 +412,42 @@ bool memLoadingState::SeekToSection( PluginsEnum_t pid ) return true; } +// -------------------------------------------------------------------------------------- +// SaveState Exception Messages +// -------------------------------------------------------------------------------------- + +wxString Exception::UnsupportedStateVersion::FormatDiagnosticMessage() const +{ + // Note: no stacktrace needed for this one... + return wxsFormat( L"Unknown or unsupported savestate version: 0x%x", Version ); +} + +wxString Exception::UnsupportedStateVersion::FormatDisplayMessage() const +{ + // m_message_user contains a recoverable savestate error which is helpful to the user. + return wxsFormat( + m_message_user + L"\n\n" + + wxsFormat( _("Cannot load savestate. It is of an unknown or unsupported version."), Version ) + ); +} + +wxString Exception::StateCrcMismatch::FormatDiagnosticMessage() const +{ + // Note: no stacktrace needed for this one... + return wxsFormat( + L"Game/CDVD does not match the savestate CRC.\n" + L"\tCdvd CRC: 0x%X\n\tGame CRC: 0x%X\n", + Crc_Savestate, Crc_Cdvd + ); +} + +wxString Exception::StateCrcMismatch::FormatDisplayMessage() const +{ + return wxsFormat( + m_message_user + L"\n\n" + + wxsFormat( + L"Savestate game/crc mismatch. Cdvd CRC: 0x%X Game CRC: 0x%X\n", + Crc_Savestate, Crc_Cdvd + ) + ); +} diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index 85e27c6a9d..a861889124 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -50,6 +50,58 @@ enum FreezeSectionId FreezeId_Unknown, }; +namespace Exception +{ + // --------------------------------------------------------------------------------------- + // Savestate Exceptions: + // UnsupportedStateVersion / StateCrcMismatch + // --------------------------------------------------------------------------------------- + + // thrown when the savestate being loaded isn't supported. + // + class UnsupportedStateVersion : public virtual SaveStateLoadError + { + public: + u32 Version; // version number of the unsupported state. + + public: + DEFINE_EXCEPTION_COPYTORS( UnsupportedStateVersion ) + + explicit UnsupportedStateVersion( int version, const wxString& objname=wxEmptyString ) + { + StreamName = objname; + Version = version; + } + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; + }; + + // A recoverable exception thrown when the CRC of the savestate does not match the + // CRC returned by the Cdvd driver. + // [feature not implemented yet] + // + class StateCrcMismatch : public virtual SaveStateLoadError + { + public: + u32 Crc_Savestate; + u32 Crc_Cdvd; + + public: + DEFINE_EXCEPTION_COPYTORS( StateCrcMismatch ) + + explicit StateCrcMismatch( u32 crc_save, u32 crc_cdvd, const wxString& objname=wxEmptyString ) + { + StreamName = objname; + Crc_Savestate = crc_save; + Crc_Cdvd = crc_cdvd; + } + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; + }; +} + // -------------------------------------------------------------------------------------- // SaveStateBase class // -------------------------------------------------------------------------------------- diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index 23cbf7612e..4d0608bcb1 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -207,7 +207,11 @@ void Pcsx2App::OnLogicalVsync( wxCommandEvent& evt ) { if( !SysHasValidState() || g_plugins == NULL ) return; - if( PADupdate != NULL ) PADupdate(0); + // Only call PADupdate here if we're using GSopen2. Legacy GSopen plugins have the + // GS window belonging to the MTGS thread. + if( (PADupdate != NULL) && (GSopen2 != NULL) && (m_gsFrame != NULL) ) + PADupdate(0); + const keyEvent* ev = PADkeyEvent(); if( (ev != NULL) && (ev->key != 0) ) @@ -369,6 +373,12 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& Console.Warning( "User canceled BIOS configuration." ); } // ---------------------------------------------------------------------------- + catch( Exception::SaveStateLoadError& ex) + { + // Saved state load failed. + Console.Warning( ex.FormatDiagnosticMessage() ); + CoreThread.Resume(); + } catch( Exception::PluginInitError& ex ) { if( m_CorePlugins ) m_CorePlugins->Shutdown(); @@ -430,14 +440,6 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& { Console.Warning( ex.FormatDiagnosticMessage() ); } - // ---------------------------------------------------------------------------- - catch( Exception::BadSavedState& ex) - { - // Saved state load failed. - Console.Warning( ex.FormatDiagnosticMessage() ); - CoreThread.Resume(); - } - // ---------------------------------------------------------------------------- catch( Exception::RuntimeError& ex ) { // Runtime errors which have been unhandled should still be safe to recover from,