* Call PADupdate from MTGS thread when using legacy GSopen -- Should fix Linux Pad instabilities.

* Fixed a savestate loading bug, when loading states made with different sets/versions of plugins.

DevNote:
 * Moved some old PS2E types to PS2Edefs, since the new v2 plugin API won't use them (freezeData, keyEvent).

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2380 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-12-22 03:15:30 +00:00
parent 203979c16b
commit 408dbd7256
11 changed files with 212 additions and 174 deletions

View File

@ -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;

View File

@ -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

View File

@ -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;
};
}

View File

@ -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
)
);
}

View File

@ -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;

View File

@ -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() {}

View File

@ -23,6 +23,17 @@
#include <wx/dynlib.h>
#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 )

View File

@ -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();
}

View File

@ -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<u8>& 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<u8>& 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
)
);
}

View File

@ -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
// --------------------------------------------------------------------------------------

View File

@ -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,