mirror of https://github.com/PCSX2/pcsx2.git
Yay, craploads of fixups for the new gui:
* Lots of crashfixes and threading rules compliance (like using wxYield instead of ProcessPendingEvents) * Killed off some memory corruption * Better error handling and reporting * Much speedier suspend/resume during emulation * Revamped entire savestate system to use a RIFF-style file format (untested, will work on it soon) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1832 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
7593072214
commit
c9c924fe35
|
@ -300,7 +300,7 @@ namespace Exception
|
|||
class BadStream : public virtual Stream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( BadStream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly") )
|
||||
DEFINE_STREAM_EXCEPTION( BadStream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") )
|
||||
};
|
||||
|
||||
// A generic exception for odd-ball stream creation errors.
|
||||
|
@ -308,7 +308,7 @@ namespace Exception
|
|||
class CreateStream : public virtual Stream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( CreateStream, wxLt("File could not be created or opened") )
|
||||
DEFINE_STREAM_EXCEPTION( CreateStream, wxLt("File could not be created or opened.") )
|
||||
};
|
||||
|
||||
// Exception thrown when an attempt to open a non-existent file is made.
|
||||
|
@ -317,13 +317,13 @@ namespace Exception
|
|||
class FileNotFound : public virtual CreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( FileNotFound, wxLt("File not found") )
|
||||
DEFINE_STREAM_EXCEPTION( FileNotFound, wxLt("File not found.") )
|
||||
};
|
||||
|
||||
class AccessDenied : public virtual CreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( AccessDenied, wxLt("Permission denied to file") )
|
||||
DEFINE_STREAM_EXCEPTION( AccessDenied, wxLt("Permission denied to file.") )
|
||||
};
|
||||
|
||||
// EndOfStream can be used either as an error, or used just as a shortcut for manual
|
||||
|
@ -332,7 +332,7 @@ namespace Exception
|
|||
class EndOfStream : public virtual Stream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file") );
|
||||
DEFINE_STREAM_EXCEPTION( EndOfStream, wxLt("Unexpected end of file or stream.") );
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
@ -346,29 +346,7 @@ namespace Exception
|
|||
class BadSavedState : public virtual BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( BadSavedState, wxLt("Savestate data is corrupted or incomplete") )
|
||||
};
|
||||
|
||||
// Exception thrown by SaveState class when a plugin returns an error during state
|
||||
// load or save.
|
||||
//
|
||||
class FreezePluginFailure : public virtual RuntimeError
|
||||
{
|
||||
public:
|
||||
wxString PluginName; // name of the plugin
|
||||
wxString FreezeAction;
|
||||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( FreezePluginFailure )
|
||||
|
||||
explicit FreezePluginFailure( const char* plugin, const char* action )
|
||||
{
|
||||
PluginName = wxString::FromUTF8( plugin );
|
||||
FreezeAction = wxString::FromUTF8( action );
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
DEFINE_STREAM_EXCEPTION( BadSavedState, wxLt("Savestate data is corrupted or incomplete.") )
|
||||
};
|
||||
|
||||
// thrown when the savestate being loaded isn't supported.
|
||||
|
|
|
@ -550,6 +550,9 @@ template< class Key, class T >
|
|||
class HashMap : public google::dense_hash_map<Key, T, CommonHashClass>
|
||||
{
|
||||
public:
|
||||
using dense_hash_map<Key, T, CommonHashClass>::operator[];
|
||||
using dense_hash_map<Key, T, CommonHashClass>::const_iterator;
|
||||
|
||||
virtual ~HashMap() {}
|
||||
|
||||
/// <summary>
|
||||
|
@ -574,13 +577,13 @@ public:
|
|||
/// parameter. This is a more favorable alternative to the indexer operator since the
|
||||
/// indexer implementation can and will create new entries for every request that
|
||||
/// </remarks>
|
||||
/*void TryGetValue( const Key& key, T& outval ) const
|
||||
void TryGetValue( const Key& key, T& outval ) const
|
||||
{
|
||||
// See above class for notes on why this is commented out.
|
||||
const_iterator iter = find( key );
|
||||
if( iter != end() )
|
||||
outval = iter->second;
|
||||
}*/
|
||||
}
|
||||
|
||||
const T& GetValue( Key key ) const
|
||||
{
|
||||
|
|
|
@ -248,7 +248,7 @@ protected:
|
|||
}
|
||||
|
||||
public:
|
||||
virtual ~SafeList()
|
||||
virtual ~SafeList() throw()
|
||||
{
|
||||
safe_free( m_ptr );
|
||||
}
|
||||
|
@ -287,6 +287,11 @@ public:
|
|||
// The actual size of the allocation may differ.
|
||||
int GetSizeInBytes() const { return m_length * sizeof(T); }
|
||||
|
||||
void MatchLengthToAllocatedSize()
|
||||
{
|
||||
m_length = m_allocsize;
|
||||
}
|
||||
|
||||
// Ensures that the allocation is large enough to fit data of the
|
||||
// amount requested. The memory allocation is not resized smaller.
|
||||
void MakeRoomFor( int blockSize )
|
||||
|
@ -398,7 +403,9 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SafeAlignedArray class
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Handy little class for allocating a resizable memory block, complete with
|
||||
// exception-based error handling and automatic cleanup.
|
||||
// This one supports aligned data allocations too!
|
||||
|
|
|
@ -29,6 +29,9 @@ extern const wxRect wxDefaultRect;
|
|||
// This should prove useful....
|
||||
#define wxsFormat wxString::Format
|
||||
|
||||
extern void SplitString( wxArrayString& dest, const wxString& src, const wxString& delims );
|
||||
extern void JoinString( wxString& dest, const wxArrayString& src, const wxString& separator );
|
||||
|
||||
extern wxString ToString( const wxPoint& src, const wxString& separator=L"," );
|
||||
extern wxString ToString( const wxSize& src, const wxString& separator=L"," );
|
||||
extern wxString ToString( const wxRect& src, const wxString& separator=L"," );
|
||||
|
|
|
@ -130,7 +130,7 @@ namespace Threading
|
|||
volatile long m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
|
||||
|
||||
public:
|
||||
virtual ~PersistentThread();
|
||||
virtual ~PersistentThread() throw();
|
||||
PersistentThread();
|
||||
|
||||
virtual void Start();
|
||||
|
@ -172,7 +172,7 @@ namespace Threading
|
|||
bool m_IsLocked;
|
||||
|
||||
public:
|
||||
virtual ~ScopedLock()
|
||||
virtual ~ScopedLock() throw()
|
||||
{
|
||||
if( m_IsLocked )
|
||||
m_lock.Unlock();
|
||||
|
@ -239,77 +239,35 @@ namespace Threading
|
|||
{
|
||||
protected:
|
||||
volatile bool m_Done;
|
||||
volatile bool m_TaskComplete;
|
||||
volatile bool m_TaskPending;
|
||||
Semaphore m_post_TaskComplete;
|
||||
MutexLock m_lock_TaskComplete;
|
||||
|
||||
public:
|
||||
virtual ~BaseTaskThread() {}
|
||||
virtual ~BaseTaskThread() throw() {}
|
||||
BaseTaskThread() :
|
||||
m_Done( false )
|
||||
, m_TaskComplete( false )
|
||||
, m_TaskPending( false )
|
||||
, m_post_TaskComplete()
|
||||
{
|
||||
}
|
||||
|
||||
// Tells the thread to exit and then waits for thread termination.
|
||||
sptr Block()
|
||||
{
|
||||
if( !m_running ) return m_returncode;
|
||||
m_Done = true;
|
||||
m_sem_event.Post();
|
||||
return PersistentThread::Block();
|
||||
}
|
||||
|
||||
// Initiates the new task. This should be called after your own StartTask has
|
||||
// initialized internal variables / preparations for task execution.
|
||||
void PostTask()
|
||||
{
|
||||
jASSUME( m_running );
|
||||
m_TaskComplete = false;
|
||||
m_post_TaskComplete.Reset();
|
||||
m_sem_event.Post();
|
||||
}
|
||||
|
||||
// Blocks current thread execution pending the completion of the parallel task.
|
||||
void WaitForResult()
|
||||
{
|
||||
if( !m_running ) return;
|
||||
if( !m_TaskComplete )
|
||||
m_post_TaskComplete.Wait();
|
||||
else
|
||||
m_post_TaskComplete.Reset();
|
||||
}
|
||||
sptr Block();
|
||||
void PostTask();
|
||||
void WaitForResult();
|
||||
|
||||
protected:
|
||||
// Abstract method run when a task has been posted. Implementing classes should do
|
||||
// all your necessary processing work here.
|
||||
virtual void Task()=0;
|
||||
|
||||
sptr ExecuteTask()
|
||||
{
|
||||
do
|
||||
{
|
||||
// Wait for a job!
|
||||
m_sem_event.Wait();
|
||||
|
||||
if( m_Done ) break;
|
||||
Task();
|
||||
m_TaskComplete = true;
|
||||
m_post_TaskComplete.Post();
|
||||
} while( !m_Done );
|
||||
|
||||
return 0;
|
||||
}
|
||||
sptr ExecuteTask();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Our fundamental interlocking functions. All other useful interlocks can be derived
|
||||
// from these little beasties!
|
||||
|
||||
extern long pcsx2_InterlockedExchange(volatile long* Target, long srcval);
|
||||
extern long pcsx2_InterlockedCompareExchange( volatile long* target, long srcval, long comp );
|
||||
extern long pcsx2_InterlockedExchangeAdd( volatile long* target, long addval );
|
||||
|
||||
extern void AtomicExchange( volatile u32& Target, u32 value );
|
||||
extern void AtomicExchangeAdd( volatile u32& Target, u32 value );
|
||||
extern void AtomicIncrement( volatile u32& Target );
|
||||
|
|
|
@ -52,8 +52,7 @@ namespace Console
|
|||
{
|
||||
std::string m_format_buffer;
|
||||
vssprintf( m_format_buffer, fmt, args );
|
||||
m_format_buffer += "\n";
|
||||
Write( wxString::FromUTF8( m_format_buffer.c_str() ) );
|
||||
WriteLn( wxString::FromUTF8( m_format_buffer.c_str() ) );
|
||||
}
|
||||
|
||||
__forceinline void __fastcall _WriteLn( Colors color, const char* fmt, va_list args )
|
||||
|
|
|
@ -104,29 +104,15 @@ namespace Exception
|
|||
wxString Stream::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
L"Stream exception: %s\n\tObject name: %s",
|
||||
L"Stream exception: %s\n\tFile/Object: %s",
|
||||
m_message_diag.c_str(), StreamName.c_str()
|
||||
) + m_stacktrace;
|
||||
}
|
||||
|
||||
wxString Stream::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user + L"\n\n" + StreamName;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
wxString FreezePluginFailure::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
L"%s plugin returned an error while %s the state.\n\n",
|
||||
PluginName.c_str(),
|
||||
FreezeAction.c_str()
|
||||
) + m_stacktrace;
|
||||
}
|
||||
|
||||
wxString FreezePluginFailure::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user;
|
||||
return m_message_user + L"\n\n" +
|
||||
wxsFormat( _("Name: %s"), StreamName.c_str() );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
const wxRect wxDefaultRect( wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, wxDefaultCoord );
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Splits a string into parts and adds the parts into the given SafeList.
|
||||
// This list is not cleared, so concatenating many splits into a single large list is
|
||||
// the 'default' behavior, unless you manually clear the SafeList prior to subsequent calls.
|
||||
|
@ -31,7 +30,13 @@ void SplitString( SafeList<wxString>& dest, const wxString& src, const wxString&
|
|||
dest.Add( parts.GetNextToken() );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
void SplitString( wxArrayString& dest, const wxString& src, const wxString& delims )
|
||||
{
|
||||
wxStringTokenizer parts( src, delims );
|
||||
while( parts.HasMoreTokens() )
|
||||
dest.Add( parts.GetNextToken() );
|
||||
}
|
||||
|
||||
// Joins a list of strings into one larger string, using the given string concatenation
|
||||
// character as a separator. If you want to be able to split the string later then the
|
||||
// concatenation string needs to be a single character.
|
||||
|
@ -48,7 +53,16 @@ void JoinString( wxString& dest, const SafeList<wxString>& src, const wxString&
|
|||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
void JoinString( wxString& dest, const wxArrayString& src, const wxString& separator )
|
||||
{
|
||||
for( int i=0, len=src.GetCount(); i<len; ++i )
|
||||
{
|
||||
if( i != 0 )
|
||||
dest += separator;
|
||||
dest += src[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to parse and return a value for the given template type, and throws a ParseError
|
||||
// exception if the parse fails. The template type can be anything that is supported/
|
||||
// implemented via one of the TryParse() method overloads.
|
||||
|
@ -65,9 +79,9 @@ T Parse( const wxString& src, const wxString& separators=L",")
|
|||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ToString helpers for wxString!
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ToString helpers for wxString!
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Converts a wxPoint into a comma-delimited string!
|
||||
wxString ToString( const wxPoint& src, const wxString& separator )
|
||||
|
@ -87,9 +101,9 @@ wxString ToString( const wxRect& src, const wxString& separator )
|
|||
return ToString( src.GetLeftTop(), separator ) << separator << ToString( src.GetSize(), separator );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Parse helpers for wxString!
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Parse helpers for wxString!
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
bool TryParse( wxPoint& dest, wxStringTokenizer& parts )
|
||||
{
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace Threading
|
|||
// Extending classes should always implement their own thread closure process.
|
||||
// This class must not be deleted from its own thread. That would be like marrying
|
||||
// your sister, and then cheating on her with your daughter.
|
||||
PersistentThread::~PersistentThread()
|
||||
PersistentThread::~PersistentThread() throw()
|
||||
{
|
||||
if( !m_running ) return;
|
||||
|
||||
|
@ -202,8 +202,67 @@ namespace Threading
|
|||
return (void*)owner.m_returncode;
|
||||
}
|
||||
|
||||
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
||||
// Let's not use it. (Air)
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseTaskThread Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Tells the thread to exit and then waits for thread termination.
|
||||
sptr BaseTaskThread::Block()
|
||||
{
|
||||
if( !IsRunning() ) return m_returncode;
|
||||
m_Done = true;
|
||||
m_sem_event.Post();
|
||||
return PersistentThread::Block();
|
||||
}
|
||||
|
||||
// Initiates the new task. This should be called after your own StartTask has
|
||||
// initialized internal variables / preparations for task execution.
|
||||
void BaseTaskThread::PostTask()
|
||||
{
|
||||
wxASSERT( !m_detached );
|
||||
|
||||
ScopedLock locker( m_lock_TaskComplete );
|
||||
m_TaskPending = true;
|
||||
m_post_TaskComplete.Reset();
|
||||
m_sem_event.Post();
|
||||
}
|
||||
|
||||
// Blocks current thread execution pending the completion of the parallel task.
|
||||
void BaseTaskThread::WaitForResult()
|
||||
{
|
||||
if( m_detached || !m_running ) return;
|
||||
if( m_TaskPending )
|
||||
#ifdef wxUSE_GUI
|
||||
m_post_TaskComplete.WaitGui();
|
||||
#else
|
||||
m_post_TaskComplete.Wait();
|
||||
#endif
|
||||
|
||||
m_post_TaskComplete.Reset();
|
||||
}
|
||||
|
||||
sptr BaseTaskThread::ExecuteTask()
|
||||
{
|
||||
while( !m_Done )
|
||||
{
|
||||
// Wait for a job -- or get a pthread_cancel. I'm easy.
|
||||
m_sem_event.Wait();
|
||||
|
||||
Task();
|
||||
m_lock_TaskComplete.Lock();
|
||||
m_TaskPending = false;
|
||||
m_post_TaskComplete.Post();
|
||||
m_lock_TaskComplete.Unlock();
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
|
||||
// Let's not use it. (Air)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
#if 0
|
||||
WaitEvent::WaitEvent()
|
||||
{
|
||||
|
@ -234,6 +293,10 @@ namespace Threading
|
|||
}
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Semaphore Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
Semaphore::Semaphore()
|
||||
{
|
||||
sem_init( &sema, false, 0 );
|
||||
|
@ -257,12 +320,19 @@ namespace Threading
|
|||
|
||||
// Valid on Win32 builds only!! Attempts to use it on Linux will result in unresolved
|
||||
// external linker errors.
|
||||
#if defined(_MSC_VER)
|
||||
void Semaphore::Post( int multiple )
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
sem_post_multiple( &sema, multiple );
|
||||
}
|
||||
#else
|
||||
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
|
||||
while( multiple > 0 )
|
||||
{
|
||||
multiple--;
|
||||
sem_post( &sema );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if wxUSE_GUI
|
||||
// This is a wxApp-safe implementation of Wait, which makes sure and executes the App's
|
||||
|
@ -278,7 +348,7 @@ namespace Threading
|
|||
// to handle messages.
|
||||
|
||||
do {
|
||||
wxTheApp->ProcessPendingEvents();
|
||||
wxTheApp->Yield();
|
||||
} while( !Wait( ts_msec_250 ) );
|
||||
}
|
||||
}
|
||||
|
@ -297,7 +367,7 @@ namespace Threading
|
|||
// to handle messages.
|
||||
|
||||
do {
|
||||
wxTheApp->ProcessPendingEvents();
|
||||
wxTheApp->Yield();
|
||||
if( Wait( ts_msec_250 ) ) break;
|
||||
countdown -= ts_msec_250;
|
||||
} while( countdown.GetMilliseconds() > 0 );
|
||||
|
@ -342,6 +412,10 @@ namespace Threading
|
|||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MutexLock Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
MutexLock::MutexLock()
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -383,74 +457,58 @@ namespace Threading
|
|||
pthread_mutex_unlock( &mutex );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// define some overloads for InterlockedExchanges
|
||||
// for commonly used types, like u32 and s32.
|
||||
|
||||
__forceinline long pcsx2_InterlockedExchange( volatile long* target, long srcval )
|
||||
{
|
||||
return _InterlockedExchange( target, srcval );
|
||||
}
|
||||
|
||||
__forceinline long pcsx2_InterlockedCompareExchange( volatile long* target, long srcval, long comp )
|
||||
{
|
||||
// Use the pthreads-win32 implementation...
|
||||
return _InterlockedCompareExchange( target, srcval, comp );
|
||||
}
|
||||
|
||||
__forceinline long pcsx2_InterlockedExchangeAdd( volatile long* target, long srcval )
|
||||
{
|
||||
return _InterlockedExchangeAdd( target, srcval );
|
||||
}
|
||||
// --------------------------------------------------------------------------------------
|
||||
// InterlockedExchanges / AtomicExchanges (PCSX2's Helper versions)
|
||||
// --------------------------------------------------------------------------------------
|
||||
// define some overloads for InterlockedExchanges for commonly used types, like u32 and s32.
|
||||
|
||||
__forceinline void AtomicExchange( volatile u32& Target, u32 value )
|
||||
{
|
||||
pcsx2_InterlockedExchange( (volatile long*)&Target, value );
|
||||
_InterlockedExchange( (volatile long*)&Target, value );
|
||||
}
|
||||
|
||||
__forceinline void AtomicExchangeAdd( volatile u32& Target, u32 value )
|
||||
{
|
||||
pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, value );
|
||||
_InterlockedExchangeAdd( (volatile long*)&Target, value );
|
||||
}
|
||||
|
||||
__forceinline void AtomicIncrement( volatile u32& Target )
|
||||
{
|
||||
pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, 1 );
|
||||
_InterlockedExchangeAdd( (volatile long*)&Target, 1 );
|
||||
}
|
||||
|
||||
__forceinline void AtomicDecrement( volatile u32& Target )
|
||||
{
|
||||
pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, -1 );
|
||||
_InterlockedExchangeAdd( (volatile long*)&Target, -1 );
|
||||
}
|
||||
|
||||
__forceinline void AtomicExchange( volatile s32& Target, s32 value )
|
||||
{
|
||||
pcsx2_InterlockedExchange( (volatile long*)&Target, value );
|
||||
_InterlockedExchange( (volatile long*)&Target, value );
|
||||
}
|
||||
|
||||
__forceinline void AtomicExchangeAdd( s32& Target, u32 value )
|
||||
{
|
||||
pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, value );
|
||||
_InterlockedExchangeAdd( (volatile long*)&Target, value );
|
||||
}
|
||||
|
||||
__forceinline void AtomicIncrement( volatile s32& Target )
|
||||
{
|
||||
pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, 1 );
|
||||
_InterlockedExchangeAdd( (volatile long*)&Target, 1 );
|
||||
}
|
||||
|
||||
__forceinline void AtomicDecrement( volatile s32& Target )
|
||||
{
|
||||
pcsx2_InterlockedExchangeAdd( (volatile long*)&Target, -1 );
|
||||
_InterlockedExchangeAdd( (volatile long*)&Target, -1 );
|
||||
}
|
||||
|
||||
__forceinline void _AtomicExchangePointer( const void ** target, const void* value )
|
||||
{
|
||||
pcsx2_InterlockedExchange( (volatile long*)target, (long)value );
|
||||
_InterlockedExchange( (volatile long*)target, (long)value );
|
||||
}
|
||||
|
||||
__forceinline void _AtomicCompareExchangePointer( const void ** target, const void* value, const void* comparand )
|
||||
{
|
||||
pcsx2_InterlockedCompareExchange( (volatile long*)target, (long)value, (long)comparand );
|
||||
_InterlockedCompareExchange( (volatile long*)target, (long)value, (long)comparand );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -483,7 +483,7 @@ struct Freeze_v10Compat
|
|||
bool Spinning;
|
||||
};
|
||||
|
||||
void SaveState::cdvdFreeze()
|
||||
void SaveStateBase::cdvdFreeze()
|
||||
{
|
||||
FreezeTag( "cdvd" );
|
||||
Freeze( cdvd );
|
||||
|
|
|
@ -961,7 +961,7 @@ void cdrReset() {
|
|||
cdReadTime = (PSXCLK / 1757) * BIAS;
|
||||
}
|
||||
|
||||
void SaveState::cdrFreeze()
|
||||
void SaveStateBase::cdrFreeze()
|
||||
{
|
||||
FreezeTag( "cdrom" );
|
||||
Freeze(cdr);
|
||||
|
|
|
@ -40,6 +40,5 @@
|
|||
// Some homeless externs. This is as good a spot as any for now...
|
||||
|
||||
|
||||
extern bool EmulationInProgress();
|
||||
extern void SetCPUState(u32 sseMXCSR, u32 sseVUMXCSR);
|
||||
extern u32 g_sseVUMXCSR, g_sseMXCSR;
|
||||
|
|
|
@ -46,13 +46,15 @@ enum PluginsEnum_t
|
|||
u32 bitset; \
|
||||
struct {
|
||||
|
||||
#define BITFIELD_END }; };
|
||||
|
||||
//------------ DEFAULT sseMXCSR VALUES ---------------
|
||||
#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop"
|
||||
#define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Pcsx2Config
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Pcsx2Config class
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This is intended to be a public class library between the core emulator and GUI only.
|
||||
// It is *not* meant to be shared data between core emulation and plugins, due to issues
|
||||
// with version incompatibilities if the structure formats are changed.
|
||||
|
@ -75,7 +77,7 @@ public:
|
|||
RecBlocks_IOP:1, // Enables per-block profiling for the IOP recompiler [unimplemented]
|
||||
RecBlocks_VU0:1, // Enables per-block profiling for the VU0 recompiler [unimplemented]
|
||||
RecBlocks_VU1:1; // Enables per-block profiling for the VU1 recompiler [unimplemented]
|
||||
}; };
|
||||
BITFIELD_END
|
||||
|
||||
// Default is Disabled, with all recs enabled underneath.
|
||||
ProfilerOptions() : bitset( 0xfffffffe ) {}
|
||||
|
@ -105,7 +107,7 @@ public:
|
|||
bool
|
||||
UseMicroVU0:1,
|
||||
UseMicroVU1:1;
|
||||
}; };
|
||||
BITFIELD_END
|
||||
|
||||
// All recs are enabled by default.
|
||||
RecompilerOptions() : bitset( 0xffffffff ) { }
|
||||
|
@ -142,7 +144,7 @@ public:
|
|||
fpuOverflow:1,
|
||||
fpuExtraOverflow:1,
|
||||
fpuFullMode:1;
|
||||
}; };
|
||||
BITFIELD_END
|
||||
|
||||
CpuOptions();
|
||||
void LoadSave( IniInterface& conf );
|
||||
|
@ -213,7 +215,7 @@ public:
|
|||
DMAExeHack:1, // Fix for Fatal Frame; breaks Gust and Tri-Ace games.
|
||||
XgKickHack:1, // Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others.
|
||||
MpegHack:1; // Fix for Mana Khemia 1, breaks Digital Devil Saga.
|
||||
}; };
|
||||
BITFIELD_END
|
||||
|
||||
// all gamefixes are disabled by default.
|
||||
GamefixOptions() : bitset( 0 ) {}
|
||||
|
@ -240,7 +242,7 @@ public:
|
|||
BIFC0:1, // enables BIFC0 detection and fast-forwarding
|
||||
vuFlagHack:1, // microVU specific flag hack; Can cause Infinite loops, SPS, etc...
|
||||
vuMinMax:1; // microVU specific MinMax hack; Can cause SPS, Black Screens, etc...
|
||||
}; };
|
||||
BITFIELD_END
|
||||
|
||||
u8 EECycleRate; // EE cycle rate selector (1.0, 1.5, 2.0)
|
||||
u8 VUCycleSteal; // VU Cycle Stealer factor (0, 1, 2, or 3)
|
||||
|
@ -275,7 +277,7 @@ public:
|
|||
|
||||
MultitapPort0_Enabled:1,
|
||||
MultitapPort1_Enabled:1;
|
||||
}; };
|
||||
BITFIELD_END
|
||||
|
||||
CpuOptions Cpu;
|
||||
VideoOptions Video;
|
||||
|
|
|
@ -798,7 +798,7 @@ __forceinline u32 rcntCycle(int index)
|
|||
return counters[index].count;
|
||||
}
|
||||
|
||||
void SaveState::rcntFreeze()
|
||||
void SaveStateBase::rcntFreeze()
|
||||
{
|
||||
Freeze( counters );
|
||||
Freeze( hsyncCounter );
|
||||
|
|
53
pcsx2/GS.cpp
53
pcsx2/GS.cpp
|
@ -40,57 +40,6 @@ static s64 m_iSlowTicks=0;
|
|||
static bool m_justSkipped = false;
|
||||
static bool m_StrictSkipping = false;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
|
||||
// GS Playback
|
||||
int g_SaveGSStream = 0; // save GS stream; 1 - prepare, 2 - save
|
||||
int g_nLeftGSFrames = 0; // when saving, number of frames left
|
||||
gzSavingState* g_fGSSave;
|
||||
|
||||
// fixme - need to take this concept and make it MTGS friendly.
|
||||
#ifdef _STGS_GSSTATE_CODE
|
||||
void GSGIFTRANSFER1(u32 *pMem, u32 addr) {
|
||||
if( g_SaveGSStream == 2) {
|
||||
u32 type = GSRUN_TRANS1;
|
||||
u32 size = (0x4000-(addr))/16;
|
||||
g_fGSSave->Freeze( type );
|
||||
g_fGSSave->Freeze( size );
|
||||
g_fGSSave->FreezeMem( ((u8*)pMem)+(addr), size*16 );
|
||||
}
|
||||
GSgifTransfer1(pMem, addr);
|
||||
}
|
||||
|
||||
void GSGIFTRANSFER2(u32 *pMem, u32 size) {
|
||||
if( g_SaveGSStream == 2) {
|
||||
u32 type = GSRUN_TRANS2;
|
||||
u32 _size = size;
|
||||
g_fGSSave->Freeze( type );
|
||||
g_fGSSave->Freeze( size );
|
||||
g_fGSSave->FreezeMem( pMem, _size*16 );
|
||||
}
|
||||
GSgifTransfer2(pMem, size);
|
||||
}
|
||||
|
||||
void GSGIFTRANSFER3(u32 *pMem, u32 size) {
|
||||
if( g_SaveGSStream == 2 ) {
|
||||
u32 type = GSRUN_TRANS3;
|
||||
u32 _size = size;
|
||||
g_fGSSave->Freeze( type );
|
||||
g_fGSSave->Freeze( size );
|
||||
g_fGSSave->FreezeMem( pMem, _size*16 );
|
||||
}
|
||||
GSgifTransfer3(pMem, size);
|
||||
}
|
||||
|
||||
__forceinline void GSVSYNC(void) {
|
||||
if( g_SaveGSStream == 2 ) {
|
||||
u32 type = GSRUN_VSYNC;
|
||||
g_fGSSave->Freeze( type );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void _gs_ChangeTimings( u32 framerate, u32 iTicks )
|
||||
{
|
||||
m_iSlowStart = GetCPUTicks();
|
||||
|
@ -615,7 +564,7 @@ void gsDynamicSkipEnable()
|
|||
frameLimitReset();
|
||||
}
|
||||
|
||||
void SaveState::gsFreeze()
|
||||
void SaveStateBase::gsFreeze()
|
||||
{
|
||||
FreezeMem(PS2MEM_GS, 0x2000);
|
||||
Freeze(CSRw);
|
||||
|
|
22
pcsx2/GS.h
22
pcsx2/GS.h
|
@ -135,9 +135,16 @@ enum GS_RINGTYPE
|
|||
, GS_RINGTYPE_QUIT
|
||||
};
|
||||
|
||||
|
||||
struct MTGS_FreezeData
|
||||
{
|
||||
freezeData* fdata;
|
||||
s32 retval; // value returned from the call, valid only after an mtgsWaitGS()
|
||||
};
|
||||
|
||||
class mtgsThreadObject : public Threading::PersistentThread
|
||||
{
|
||||
friend class SaveState;
|
||||
friend class SaveStateBase;
|
||||
|
||||
protected:
|
||||
// Size of the ringbuffer as a power of 2 -- size is a multiple of simd128s.
|
||||
|
@ -192,6 +199,10 @@ protected:
|
|||
#endif
|
||||
|
||||
// the MTGS "dummy" GIFtag info!
|
||||
// fixme: The real PS2 has a single internal PATH and 3 logical sources, not 3 entirely
|
||||
// separate paths. But for that to work properly we need also interlocked path sources.
|
||||
// That is, when the GIF selects a source, it sticks to that source until an EOP. Currently
|
||||
// this is not emulated!
|
||||
GIFPath m_path[3];
|
||||
|
||||
// contains aligned memory allocations for gs and Ringbuffer.
|
||||
|
@ -203,7 +214,7 @@ protected:
|
|||
|
||||
public:
|
||||
mtgsThreadObject();
|
||||
virtual ~mtgsThreadObject();
|
||||
virtual ~mtgsThreadObject() throw();
|
||||
|
||||
void Start();
|
||||
void Cancel();
|
||||
|
@ -222,13 +233,11 @@ public:
|
|||
void SendPointerPacket( GS_RINGTYPE type, u32 data0, void* data1 );
|
||||
|
||||
u8* GetDataPacketPtr() const;
|
||||
void Freeze( SaveState& state );
|
||||
void Freeze( SaveStateBase& state );
|
||||
void SetEvent();
|
||||
|
||||
void PostVsyncEnd( bool updategs );
|
||||
|
||||
void _close_gs();
|
||||
|
||||
protected:
|
||||
// Saves MMX/XMM regs, posts an event to the mtgsThread flag and releases a timeslice.
|
||||
// For use in surrounding loops that wait on the mtgs.
|
||||
|
@ -331,11 +340,10 @@ enum gsrun
|
|||
|
||||
extern int g_SaveGSStream;
|
||||
extern int g_nLeftGSFrames;
|
||||
extern gzSavingState* g_fGSSave;
|
||||
|
||||
#endif
|
||||
|
||||
extern void SaveGSState(const wxString& file);
|
||||
extern void LoadGSState(const wxString& file);
|
||||
extern void RunGSState(gzLoadingState& f);
|
||||
extern void RunGSState( memLoadingState& f );
|
||||
|
||||
|
|
|
@ -19,6 +19,55 @@
|
|||
#include <list>
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
|
||||
// GS Playback
|
||||
int g_SaveGSStream = 0; // save GS stream; 1 - prepare, 2 - save
|
||||
int g_nLeftGSFrames = 0; // when saving, number of frames left
|
||||
static wxScopedPtr<memSavingState> g_fGSSave;
|
||||
|
||||
// fixme - need to take this concept and make it MTGS friendly.
|
||||
#ifdef _STGS_GSSTATE_CODE
|
||||
void GSGIFTRANSFER1(u32 *pMem, u32 addr) {
|
||||
if( g_SaveGSStream == 2) {
|
||||
u32 type = GSRUN_TRANS1;
|
||||
u32 size = (0x4000-(addr))/16;
|
||||
g_fGSSave->Freeze( type );
|
||||
g_fGSSave->Freeze( size );
|
||||
g_fGSSave->FreezeMem( ((u8*)pMem)+(addr), size*16 );
|
||||
}
|
||||
GSgifTransfer1(pMem, addr);
|
||||
}
|
||||
|
||||
void GSGIFTRANSFER2(u32 *pMem, u32 size) {
|
||||
if( g_SaveGSStream == 2) {
|
||||
u32 type = GSRUN_TRANS2;
|
||||
u32 _size = size;
|
||||
g_fGSSave->Freeze( type );
|
||||
g_fGSSave->Freeze( size );
|
||||
g_fGSSave->FreezeMem( pMem, _size*16 );
|
||||
}
|
||||
GSgifTransfer2(pMem, size);
|
||||
}
|
||||
|
||||
void GSGIFTRANSFER3(u32 *pMem, u32 size) {
|
||||
if( g_SaveGSStream == 2 ) {
|
||||
u32 type = GSRUN_TRANS3;
|
||||
u32 _size = size;
|
||||
g_fGSSave->Freeze( type );
|
||||
g_fGSSave->Freeze( size );
|
||||
g_fGSSave->FreezeMem( pMem, _size*16 );
|
||||
}
|
||||
GSgifTransfer3(pMem, size);
|
||||
}
|
||||
|
||||
__forceinline void GSVSYNC(void) {
|
||||
if( g_SaveGSStream == 2 ) {
|
||||
u32 type = GSRUN_VSYNC;
|
||||
g_fGSSave->Freeze( type );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void SaveGSState(const wxString& file)
|
||||
{
|
||||
if( g_SaveGSStream ) return;
|
||||
|
@ -26,7 +75,8 @@ void SaveGSState(const wxString& file)
|
|||
Console::WriteLn( "Saving GS State..." );
|
||||
Console::WriteLn( wxsFormat( L"\t%s", file.c_str() ) );
|
||||
|
||||
g_fGSSave = new gzSavingState( file );
|
||||
SafeArray<u8> buf;
|
||||
g_fGSSave.reset( new memSavingState( buf ) );
|
||||
|
||||
g_SaveGSStream = 1;
|
||||
g_nLeftGSFrames = 2;
|
||||
|
@ -37,46 +87,35 @@ void SaveGSState(const wxString& file)
|
|||
void LoadGSState(const wxString& file)
|
||||
{
|
||||
int ret;
|
||||
gzLoadingState* f;
|
||||
|
||||
Console::Status( "Loading GS State..." );
|
||||
|
||||
try
|
||||
{
|
||||
f = new gzLoadingState( file );
|
||||
}
|
||||
catch( Exception::FileNotFound& )
|
||||
{
|
||||
// file not found? try prefixing with sstates folder:
|
||||
if( !Path::IsRelative( file ) )
|
||||
{
|
||||
//f = new gzLoadingState( Path::Combine( g_Conf->Folders.Savestates, file ) );
|
||||
wxString src( file );
|
||||
|
||||
// If this load attempt fails, then let the exception bubble up to
|
||||
// the caller to deal with...
|
||||
}
|
||||
}
|
||||
/*if( !wxFileName::FileExists( src ) )
|
||||
src = Path::Combine( g_Conf->Folders.Savestates, src );*/
|
||||
|
||||
if( !wxFileName::FileExists( src ) )
|
||||
return;
|
||||
|
||||
SafeArray<u8> buf;
|
||||
memLoadingState f( buf );
|
||||
|
||||
// Always set gsIrq callback -- GS States are always exclusionary of MTGS mode
|
||||
GSirqCallback( gsIrq );
|
||||
|
||||
ret = GSopen(&pDsp, "PCSX2", 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
delete f;
|
||||
throw Exception::PluginOpenError( PluginId_GS );
|
||||
}
|
||||
|
||||
ret = PADopen((void *)&pDsp);
|
||||
|
||||
f->Freeze(g_nLeftGSFrames);
|
||||
f->gsFreeze();
|
||||
f.Freeze(g_nLeftGSFrames);
|
||||
f.gsFreeze();
|
||||
|
||||
f->FreezePlugin( "GS", gsSafeFreeze );
|
||||
GetPluginManager().Freeze( PluginId_GS, f );
|
||||
|
||||
RunGSState( *f );
|
||||
|
||||
delete( f );
|
||||
RunGSState( f );
|
||||
|
||||
g_plugins->Close( PluginId_GS );
|
||||
g_plugins->Close( PluginId_PAD );
|
||||
|
@ -90,12 +129,12 @@ struct GSStatePacket
|
|||
|
||||
// runs the GS
|
||||
// (this should really be part of the AppGui)
|
||||
void RunGSState( gzLoadingState& f )
|
||||
void RunGSState( memLoadingState& f )
|
||||
{
|
||||
u32 newfield;
|
||||
std::list< GSStatePacket > packets;
|
||||
|
||||
while( !f.Finished() )
|
||||
while( !f.IsFinished() )
|
||||
{
|
||||
int type, size;
|
||||
f.Freeze( type );
|
||||
|
@ -152,3 +191,77 @@ void RunGSState( gzLoadingState& f )
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void vSyncDebugStuff( uint frame )
|
||||
{
|
||||
#ifdef OLD_TESTBUILD_STUFF
|
||||
if( g_TestRun.enabled && g_TestRun.frame > 0 ) {
|
||||
if( frame > g_TestRun.frame ) {
|
||||
// take a snapshot
|
||||
if( g_TestRun.pimagename != NULL && GSmakeSnapshot2 != NULL ) {
|
||||
if( g_TestRun.snapdone ) {
|
||||
g_TestRun.curimage++;
|
||||
g_TestRun.snapdone = 0;
|
||||
g_TestRun.frame += 20;
|
||||
if( g_TestRun.curimage >= g_TestRun.numimages ) {
|
||||
// exit
|
||||
g_EmuThread->Cancel();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// query for the image
|
||||
GSmakeSnapshot2(g_TestRun.pimagename, &g_TestRun.snapdone, g_TestRun.jpgcapture);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// exit
|
||||
g_EmuThread->Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GSVSYNC();
|
||||
|
||||
if( g_SaveGSStream == 1 ) {
|
||||
freezeData fP;
|
||||
|
||||
g_SaveGSStream = 2;
|
||||
g_fGSSave->gsFreeze();
|
||||
|
||||
if (GSfreeze(FREEZE_SIZE, &fP) == -1) {
|
||||
safe_delete( g_fGSSave );
|
||||
g_SaveGSStream = 0;
|
||||
}
|
||||
else {
|
||||
fP.data = (s8*)malloc(fP.size);
|
||||
if (fP.data == NULL) {
|
||||
safe_delete( g_fGSSave );
|
||||
g_SaveGSStream = 0;
|
||||
}
|
||||
else {
|
||||
if (GSfreeze(FREEZE_SAVE, &fP) == -1) {
|
||||
safe_delete( g_fGSSave );
|
||||
g_SaveGSStream = 0;
|
||||
}
|
||||
else {
|
||||
g_fGSSave->Freeze( fP.size );
|
||||
if (fP.size) {
|
||||
g_fGSSave->FreezeMem( fP.data, fP.size );
|
||||
free(fP.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( g_SaveGSStream == 2 ) {
|
||||
|
||||
if( --g_nLeftGSFrames <= 0 ) {
|
||||
safe_delete( g_fGSSave );
|
||||
g_SaveGSStream = 0;
|
||||
Console::WriteLn("Done saving GS stream");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -101,15 +101,6 @@ static u32 WRITERING_DMA(u32 *pMem, u32 qwc)
|
|||
int size = mtgsThread->PrepDataPacket(GIF_PATH_3, pMem, qwc);
|
||||
u8* pgsmem = mtgsThread->GetDataPacketPtr();
|
||||
|
||||
/* check if page of endmem is valid (dark cloud2) */
|
||||
// fixme: this hack makes no sense, because the giftagDummy will
|
||||
// process the full length of bytes regardess of how much we copy.
|
||||
// So you'd think if we're truncating the copy to prevent DEPs, we
|
||||
// should truncate the gif packet size too.. (air)
|
||||
|
||||
// fixed? PrepDataPacket now returns the actual size of the packet.
|
||||
// VIF handles scratchpad wrapping also, so this code shouldn't be needed anymore.
|
||||
|
||||
memcpy_aligned(pgsmem, pMem, size<<4);
|
||||
|
||||
mtgsThread->SendDataPacket();
|
||||
|
@ -572,7 +563,7 @@ void gifMFIFOInterrupt()
|
|||
clearFIFOstuff(false);
|
||||
}
|
||||
|
||||
void SaveState::gifFreeze()
|
||||
void SaveStateBase::gifFreeze()
|
||||
{
|
||||
FreezeTag( "GIFdma" );
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ void ReportIPU()
|
|||
}
|
||||
// fixme - ipuFreeze looks fairly broken. Should probably take a closer look at some point.
|
||||
|
||||
void SaveState::ipuFreeze()
|
||||
void SaveStateBase::ipuFreeze()
|
||||
{
|
||||
IPUProcessInterrupt();
|
||||
|
||||
|
|
|
@ -748,7 +748,7 @@ void psxRcntSetGates()
|
|||
psxvblankgate &= ~(1<<3);
|
||||
}
|
||||
|
||||
void SaveState::psxRcntFreeze()
|
||||
void SaveStateBase::psxRcntFreeze()
|
||||
{
|
||||
FreezeTag( "iopCounters" );
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ u8 sio2_fifoOut(){
|
|||
return 0; // No Data
|
||||
}
|
||||
|
||||
void SaveState::sio2Freeze()
|
||||
void SaveStateBase::sio2Freeze()
|
||||
{
|
||||
FreezeTag( "sio2" );
|
||||
Freeze(sio2);
|
||||
|
|
|
@ -78,7 +78,7 @@ __forceinline void GIFPath::SetTag(const void* mem)
|
|||
curreg = 0;
|
||||
}
|
||||
|
||||
static void _mtgsFreezeGIF( SaveState& state, GIFPath (&paths)[3] )
|
||||
static void _mtgsFreezeGIF( SaveStateBase& state, GIFPath (&paths)[3] )
|
||||
{
|
||||
for(int i=0; i<3; i++ )
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ static void _mtgsFreezeGIF( SaveState& state, GIFPath (&paths)[3] )
|
|||
}
|
||||
}
|
||||
|
||||
void SaveState::mtgsFreeze()
|
||||
void SaveStateBase::mtgsFreeze()
|
||||
{
|
||||
FreezeTag( "mtgs" );
|
||||
mtgsThread->Freeze( *this );
|
||||
|
@ -388,17 +388,12 @@ struct PacketTagType
|
|||
|
||||
extern bool renderswitch;
|
||||
|
||||
void mtgsThreadObject::_close_gs()
|
||||
static void _clean_close_gs( void* obj )
|
||||
{
|
||||
if( g_plugins != NULL )
|
||||
g_plugins->m_info[PluginId_GS].CommonBindings.Close();
|
||||
}
|
||||
|
||||
static void _clean_close_gs( void* obj )
|
||||
{
|
||||
((mtgsThreadObject*)obj)->_close_gs();
|
||||
}
|
||||
|
||||
void mtgsThreadObject::_RingbufferLoop()
|
||||
{
|
||||
pthread_cleanup_push( _clean_close_gs, this );
|
||||
|
@ -510,9 +505,9 @@ void mtgsThreadObject::_RingbufferLoop()
|
|||
|
||||
case GS_RINGTYPE_FREEZE:
|
||||
{
|
||||
freezeData* data = (freezeData*)(*(uptr*)&tag.data[1]);
|
||||
MTGS_FreezeData* data = (MTGS_FreezeData*)(*(uptr*)&tag.data[1]);
|
||||
int mode = tag.data[0];
|
||||
GetPluginManager().Freeze( PluginId_GS, mode, data );
|
||||
data->retval = GetPluginManager().DoFreeze( PluginId_GS, mode, data->fdata );
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -576,11 +571,17 @@ void mtgsThreadObject::_RingbufferLoop()
|
|||
pthread_cleanup_pop( true );
|
||||
}
|
||||
|
||||
static void dummyIrqCallback()
|
||||
{
|
||||
// dummy, because MTGS doesn't need this mess!
|
||||
// (and zerogs does >_<)
|
||||
}
|
||||
|
||||
sptr mtgsThreadObject::ExecuteTask()
|
||||
{
|
||||
memcpy_aligned( m_gsMem, PS2MEM_GS, sizeof(PS2MEM_GS) );
|
||||
GSsetBaseMem( m_gsMem );
|
||||
GSirqCallback( NULL );
|
||||
GSirqCallback( dummyIrqCallback );
|
||||
|
||||
Console::WriteLn( (wxString)L"\t\tForced software switch: " + (renderswitch ? L"Enabled" : L"Disabled") );
|
||||
m_returncode = GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 );
|
||||
|
@ -781,14 +782,6 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s
|
|||
jASSUME( size < m_RingBufferSize );
|
||||
jASSUME( writepos < m_RingBufferSize );
|
||||
|
||||
//fixme: Vif sometimes screws up and size is unaligned, try this then (rama)
|
||||
//Is this still a problem? It should be fixed on the specific VIF command now. (air)
|
||||
//It seems to be fixed in Fatal Frame, leaving the code here still in case we get that again (rama)
|
||||
/*if( (size&15) != 0){
|
||||
Console::Error( "MTGS problem, size unaligned");
|
||||
size = (size+15)&(~15);
|
||||
}*/
|
||||
|
||||
m_packet_size = gifTransferDummy(pathidx, srcdata, size);
|
||||
size = m_packet_size + 1; // takes into account our command qword.
|
||||
|
||||
|
@ -1009,7 +1002,7 @@ void mtgsThreadObject::GIFSoftReset( int mask )
|
|||
mtgsThread->SendSimplePacket( GS_RINGTYPE_SOFTRESET, mask, 0, 0 );
|
||||
}
|
||||
|
||||
void mtgsThreadObject::Freeze( SaveState& state )
|
||||
void mtgsThreadObject::Freeze( SaveStateBase& state )
|
||||
{
|
||||
_mtgsFreezeGIF( state, this->m_path );
|
||||
}
|
||||
|
|
|
@ -593,6 +593,34 @@ wxString Exception::PluginError::FormatDisplayMessage() const
|
|||
return wxsFormat( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() );
|
||||
}
|
||||
|
||||
wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
L"%s plugin returned an error while saving the state.\n\n",
|
||||
tbl_PluginInfo[PluginId].shortname
|
||||
) + m_stacktrace;
|
||||
}
|
||||
|
||||
wxString Exception::FreezePluginFailure::FormatDisplayMessage() const
|
||||
{
|
||||
// [TODO]
|
||||
return m_message_user;
|
||||
}
|
||||
|
||||
wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const
|
||||
{
|
||||
return wxsFormat(
|
||||
L"%s plugin returned an error while loading the state.\n\n",
|
||||
tbl_PluginInfo[PluginId].shortname
|
||||
) + m_stacktrace;
|
||||
}
|
||||
|
||||
wxString Exception::ThawPluginFailure::FormatDisplayMessage() const
|
||||
{
|
||||
// [TODO]
|
||||
return m_message_user;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PCSX2 Callbacks passed to Plugins
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -702,6 +730,8 @@ PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] )
|
|||
// fixme: use plugin's GetLastError (not implemented yet!)
|
||||
throw Exception::PluginLoadError( PluginId_Mcd, wxEmptyString, "Internal Memorycard Plugin failed to load." );
|
||||
}
|
||||
|
||||
g_plugins = this;
|
||||
}
|
||||
|
||||
PluginManager::~PluginManager()
|
||||
|
@ -713,6 +743,9 @@ PluginManager::~PluginManager()
|
|||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
// All library unloading done automatically.
|
||||
|
||||
if( g_plugins == this )
|
||||
g_plugins = NULL;
|
||||
}
|
||||
|
||||
void PluginManager::BindCommon( PluginsEnum_t pid )
|
||||
|
@ -890,7 +923,7 @@ void PluginManager::Open()
|
|||
void PluginManager::Close( PluginsEnum_t pid )
|
||||
{
|
||||
if( !m_info[pid].IsOpened ) return;
|
||||
DevCon::Status( "\tClosing %s", tbl_PluginInfo[pid].shortname );
|
||||
Console::Status( "\tClosing %s", tbl_PluginInfo[pid].shortname );
|
||||
|
||||
if( pid == PluginId_GS )
|
||||
{
|
||||
|
@ -910,7 +943,7 @@ void PluginManager::Close( PluginsEnum_t pid )
|
|||
|
||||
void PluginManager::Close( bool closegs )
|
||||
{
|
||||
Console::Status( "Closing plugins..." );
|
||||
DbgCon::Status( "Closing plugins..." );
|
||||
|
||||
// Close plugins in reverse order of the initialization procedure.
|
||||
|
||||
|
@ -920,7 +953,7 @@ void PluginManager::Close( bool closegs )
|
|||
Close( tbl_PluginInfo[i].id );
|
||||
}
|
||||
|
||||
Console::Status( "Plugins closed successfully." );
|
||||
DbgCon::Status( "Plugins closed successfully." );
|
||||
}
|
||||
|
||||
// Initializes all plugins. Plugin initialization should be done once for every new emulation
|
||||
|
@ -974,8 +1007,8 @@ void PluginManager::Init()
|
|||
void PluginManager::Shutdown()
|
||||
{
|
||||
Close();
|
||||
DbgCon::Status( "Shutting down plugins..." );
|
||||
|
||||
Console::Status( "Shutting down plugins..." );
|
||||
// Shutdown plugins in reverse order (probably doesn't matter...
|
||||
// ... but what the heck, right?)
|
||||
|
||||
|
@ -990,52 +1023,82 @@ void PluginManager::Shutdown()
|
|||
|
||||
// More memorycard hacks!!
|
||||
|
||||
if( EmuPlugins.Mcd != NULL && m_mcdPlugin != NULL )
|
||||
if( (EmuPlugins.Mcd != NULL) && (m_mcdPlugin != NULL) )
|
||||
{
|
||||
m_mcdPlugin->DeleteComponentInstance( (PS2E_THISPTR)EmuPlugins.Mcd );
|
||||
EmuPlugins.Mcd = NULL;
|
||||
}
|
||||
|
||||
Console::Status( "Plugins shutdown successfully." );
|
||||
DbgCon::Status( "Plugins shutdown successfully." );
|
||||
}
|
||||
|
||||
void PluginManager::Freeze( PluginsEnum_t pid, int mode, freezeData* data )
|
||||
// For internal use only, unless you're the MTGS. Then it's for you too!
|
||||
// Returns false if the plugin returned an error.
|
||||
bool PluginManager::DoFreeze( PluginsEnum_t pid, int mode, freezeData* data )
|
||||
{
|
||||
m_info[pid].CommonBindings.Freeze( mode, data );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Thread Safety:
|
||||
// This function should only be called by the Main GUI thread and the GS thread (for GS states only),
|
||||
// as it has special handlers to ensure that GS freeze commands are executed appropriately on the
|
||||
// GS thread.
|
||||
//
|
||||
void PluginManager::Freeze( PluginsEnum_t pid, SaveState& state )
|
||||
{
|
||||
if( pid == PluginId_GS && wxThread::IsMain() )
|
||||
if( (pid == PluginId_GS) && wxThread::IsMain() )
|
||||
{
|
||||
// Need to send the GS freeze request on the GS thread.
|
||||
MTGS_FreezeData woot = { data, 0 };
|
||||
// GS needs some thread safety love...
|
||||
mtgsThread->SendPointerPacket( GS_RINGTYPE_FREEZE, mode, &woot );
|
||||
mtgsWaitGS();
|
||||
return woot.retval != -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.FreezePlugin( tbl_PluginInfo[pid].shortname, m_info[pid].CommonBindings.Freeze );
|
||||
return m_info[pid].CommonBindings.Freeze( mode, data ) != -1;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// This overload of Freeze performs savestate freeze operation on *all* plugins,
|
||||
// as according to the order in PluignsEnum_t.
|
||||
//
|
||||
// Thread Safety:
|
||||
// This function should only be called by the Main GUI thread and the GS thread (for GS states only),
|
||||
// as it has special handlers to ensure that GS freeze commands are executed appropriately on the
|
||||
// GS thread.
|
||||
//
|
||||
void PluginManager::Freeze( SaveState& state )
|
||||
void PluginManager::Freeze( PluginsEnum_t pid, SaveStateBase& state )
|
||||
{
|
||||
const PluginInfo* pi = tbl_PluginInfo-1;
|
||||
while( ++pi, pi->shortname != NULL )
|
||||
Freeze( pi->id, state );
|
||||
Console::WriteLn( "\t%s %s", state.IsSaving() ? "Saving" : "Loading",
|
||||
tbl_PluginInfo[pid].shortname );
|
||||
|
||||
freezeData fP = { 0, NULL };
|
||||
if( !DoFreeze( pid, FREEZE_SIZE, &fP ) )
|
||||
fP.size = 0;
|
||||
|
||||
int fsize = fP.size;
|
||||
state.Freeze( fsize );
|
||||
|
||||
if( state.IsLoading() && (fsize == 0) )
|
||||
{
|
||||
// no state data to read, but the plugin expects some state data.
|
||||
// Issue a warning to console...
|
||||
if( fP.size != 0 )
|
||||
Console::Notice( "\tWarning: No data for this plugin was found. Plugin status may be unpredictable." );
|
||||
return;
|
||||
|
||||
// Note: Size mismatch check could also be done here on loading, but
|
||||
// some plugins may have built-in version support for non-native formats or
|
||||
// older versions of a different size... or could give different sizes depending
|
||||
// on the status of the plugin when loading, so let's ignore it.
|
||||
}
|
||||
|
||||
fP.size = fsize;
|
||||
if( fP.size == 0 ) return;
|
||||
|
||||
state.PrepBlock( fP.size );
|
||||
fP.data = (s8*)state.GetBlockPtr();
|
||||
|
||||
if( state.IsSaving() )
|
||||
{
|
||||
if( !DoFreeze(pid, FREEZE_SAVE, &fP) )
|
||||
throw Exception::FreezePluginFailure( pid );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !DoFreeze(pid, FREEZE_LOAD, &fP) )
|
||||
throw Exception::ThawPluginFailure( pid );
|
||||
}
|
||||
|
||||
state.CommitBlock( fP.size );
|
||||
}
|
||||
|
||||
bool PluginManager::KeyEvent( const keyEvent& evt )
|
||||
|
@ -1062,9 +1125,7 @@ void PluginManager::Configure( PluginsEnum_t pid )
|
|||
//
|
||||
PluginManager* PluginManager_Create( const wxString (&folders)[PluginId_Count] )
|
||||
{
|
||||
PluginManager* retval = new PluginManager( folders );
|
||||
retval->Init();
|
||||
return retval;
|
||||
return new PluginManager( folders );
|
||||
}
|
||||
|
||||
PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] )
|
||||
|
|
|
@ -106,6 +106,39 @@ namespace Exception
|
|||
PluginId = pid;
|
||||
}
|
||||
};
|
||||
|
||||
// This exception is thrown when a plugin returns an error while trying to save itself.
|
||||
// Typically this should be a very rare occurance since a plugin typically shoudn't
|
||||
// be doing memory allocations or file access during state saving.
|
||||
//
|
||||
class FreezePluginFailure : public virtual PluginError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( FreezePluginFailure )
|
||||
|
||||
explicit FreezePluginFailure( PluginsEnum_t pid)
|
||||
{
|
||||
PluginId = pid;
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
class ThawPluginFailure : public virtual PluginError, public virtual BadSavedState
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( ThawPluginFailure )
|
||||
|
||||
explicit ThawPluginFailure( PluginsEnum_t pid )
|
||||
{
|
||||
PluginId = pid;
|
||||
}
|
||||
|
||||
virtual wxString FormatDiagnosticMessage() const;
|
||||
virtual wxString FormatDisplayMessage() const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -140,7 +173,7 @@ struct LegacyPluginAPI_Common
|
|||
}
|
||||
};
|
||||
|
||||
class SaveState;
|
||||
class SaveStateBase;
|
||||
class mtgsThreadObject;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -201,9 +234,12 @@ public:
|
|||
virtual void Close( PluginsEnum_t pid ) {}
|
||||
virtual void Close( bool closegs=true ) {}
|
||||
|
||||
virtual void Freeze( PluginsEnum_t pid, int mode, freezeData* data ) { wxASSERT_MSG( false, L"Null PluginManager!" ); }
|
||||
virtual void Freeze( PluginsEnum_t pid, SaveState& state ) { wxASSERT_MSG( false, L"Null PluginManager!" ); }
|
||||
virtual void Freeze( SaveState& state ) { wxASSERT_MSG( false, L"Null PluginManager!" ); }
|
||||
virtual void Freeze( PluginsEnum_t pid, SaveStateBase& state ) { wxASSERT_MSG( false, L"Null PluginManager!" ); }
|
||||
virtual bool DoFreeze( PluginsEnum_t pid, int mode, freezeData* data )
|
||||
{
|
||||
wxASSERT_MSG( false, L"Null PluginManager!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool KeyEvent( const keyEvent& evt ) { return false; }
|
||||
};
|
||||
|
@ -238,9 +274,11 @@ protected:
|
|||
|
||||
bool m_initialized;
|
||||
|
||||
PluginStatus_t m_info[PluginId_Count];
|
||||
const PS2E_LibraryAPI* m_mcdPlugin;
|
||||
|
||||
public: // hack until we unsuck plugins...
|
||||
PluginStatus_t m_info[PluginId_Count];
|
||||
|
||||
public:
|
||||
virtual ~PluginManager();
|
||||
|
||||
|
@ -251,9 +289,8 @@ public:
|
|||
void Close( PluginsEnum_t pid );
|
||||
void Close( bool closegs=true );
|
||||
|
||||
void Freeze( PluginsEnum_t pid, int mode, freezeData* data );
|
||||
void Freeze( PluginsEnum_t pid, SaveState& state );
|
||||
void Freeze( SaveState& state );
|
||||
void Freeze( PluginsEnum_t pid, SaveStateBase& state );
|
||||
bool DoFreeze( PluginsEnum_t pid, int mode, freezeData* data );
|
||||
|
||||
bool KeyEvent( const keyEvent& evt );
|
||||
void Configure( PluginsEnum_t pid );
|
||||
|
|
|
@ -83,6 +83,7 @@ typedef int BOOL;
|
|||
#include "i18n.h"
|
||||
#include "Config.h"
|
||||
#include "Utilities/wxBaseTools.h"
|
||||
#include "Utilities/ScopedPtr.h"
|
||||
#include "Utilities/Path.h"
|
||||
#include "Utilities/Console.h"
|
||||
#include "Utilities/Exceptions.h"
|
||||
|
|
|
@ -16,128 +16,33 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "ps2/CoreEmuThread.h"
|
||||
#include "App.h"
|
||||
#include "HostGui.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RecoverySystem.cpp -- houses code for recovering from on-the-fly changes to the emu
|
||||
// configuration, and for saving/restoring the GS state (for more seamless exiting of
|
||||
// fullscreen GS operation).
|
||||
//
|
||||
// The following handful of local classes are implemented att he bottom of this file.
|
||||
|
||||
static SafeArray<u8>* g_RecoveryState = NULL;
|
||||
static SafeArray<u8>* g_gsRecoveryState = NULL;
|
||||
|
||||
// This class type creates a memory savestate using the existing Recovery information
|
||||
// (if present) to generate the savestate material. If no recovery data is present,
|
||||
// the current emulation state is used instead.
|
||||
class RecoveryMemSavingState : public memSavingState, Sealed
|
||||
{
|
||||
public:
|
||||
virtual ~RecoveryMemSavingState() { }
|
||||
RecoveryMemSavingState();
|
||||
|
||||
void gsFreeze();
|
||||
void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) );
|
||||
};
|
||||
|
||||
// This class type creates an on-disk (zipped) savestate using the existing Recovery
|
||||
// information (if present) to generate the savestate material. If no recovery data is
|
||||
// present, the current emulation state is used instead.
|
||||
class RecoveryZipSavingState : public gzSavingState, Sealed
|
||||
{
|
||||
public:
|
||||
virtual ~RecoveryZipSavingState() { }
|
||||
RecoveryZipSavingState( const wxString& filename );
|
||||
|
||||
void gsFreeze();
|
||||
void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) );
|
||||
};
|
||||
|
||||
// Special helper class used to save *just* the GS-relevant state information.
|
||||
class JustGsSavingState : public memSavingState, Sealed
|
||||
{
|
||||
public:
|
||||
virtual ~JustGsSavingState() { }
|
||||
JustGsSavingState();
|
||||
|
||||
// This special override saves the gs info to m_idx+4, and then goes back and
|
||||
// writes in the length of data saved.
|
||||
void gsFreeze();
|
||||
};
|
||||
static wxScopedPtr<SafeArray<u8>> g_RecoveryState;
|
||||
|
||||
namespace StateRecovery {
|
||||
|
||||
bool HasState()
|
||||
{
|
||||
return g_RecoveryState != NULL || g_gsRecoveryState != NULL;
|
||||
return g_RecoveryState;
|
||||
}
|
||||
|
||||
void Recover()
|
||||
{
|
||||
wxASSERT( g_EmuThread != NULL );
|
||||
wxASSERT( g_EmuThread->IsSelf() );
|
||||
if( !g_RecoveryState ) return;
|
||||
|
||||
if( g_RecoveryState != NULL )
|
||||
{
|
||||
Console::Status( "Resuming execution from full memory state..." );
|
||||
memLoadingState( *g_RecoveryState ).FreezeAll();
|
||||
}
|
||||
else if( g_gsRecoveryState != NULL )
|
||||
{
|
||||
s32 dummylen;
|
||||
|
||||
Console::Status( "Resuming execution from gsState..." );
|
||||
memLoadingState eddie( *g_gsRecoveryState );
|
||||
eddie.FreezePlugin( "GS", gsSafeFreeze );
|
||||
eddie.Freeze( dummylen ); // reads the length value recorded earlier.
|
||||
eddie.gsFreeze();
|
||||
}
|
||||
Console::Status( "Resuming execution from full memory state..." );
|
||||
memLoadingState( *g_RecoveryState ).FreezeAll();
|
||||
|
||||
StateRecovery::Clear();
|
||||
SysClearExecutionCache();
|
||||
|
||||
if( GSsetGameCRC != NULL )
|
||||
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
|
||||
}
|
||||
|
||||
// Saves recovery state info to the given filename, or saves the active emulation state
|
||||
// (if one exists) and no recovery data was found. This is needed because when a recovery
|
||||
// state is made, the emulation state is usually reset so the only persisting state is
|
||||
// the one in the memory save. :)
|
||||
//
|
||||
// Threading Notes:
|
||||
// This function can be invoked by any thread. However, if it is run outside the context
|
||||
// of a CoreEmuThred then it
|
||||
void SaveToFile( const wxString& file )
|
||||
{
|
||||
SysSuspend();
|
||||
if( g_RecoveryState == NULL )
|
||||
{
|
||||
RecoveryMemSavingState().FreezeAll();
|
||||
}
|
||||
|
||||
SysResume();
|
||||
|
||||
if( g_RecoveryState != NULL )
|
||||
{
|
||||
gzFile fileptr = gzopen( file.ToAscii().data(), "wb" );
|
||||
if( fileptr == NULL )
|
||||
throw Exception::CreateStream( file, "General savestate file creation error." );
|
||||
|
||||
gzwrite( fileptr, &g_SaveVersion, sizeof( u32 ) );
|
||||
gzwrite( fileptr, g_RecoveryState->GetPtr(), g_RecoveryState->GetSizeInBytes() );
|
||||
gzclose( fileptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !EmulationInProgress() ) return;
|
||||
|
||||
RecoveryZipSavingState( file ).FreezeAll();
|
||||
}
|
||||
SafeArray<u8> buf;
|
||||
memSavingState( buf ).FreezeAll();
|
||||
}
|
||||
|
||||
// Saves recovery state info to the given saveslot, or saves the active emulation state
|
||||
|
@ -146,40 +51,22 @@ namespace StateRecovery {
|
|||
// the one in the memory save. :)
|
||||
void SaveToSlot( uint num )
|
||||
{
|
||||
SaveToFile( SaveState::GetFilename( num ) );
|
||||
SaveToFile( SaveStateBase::GetFilename( num ) );
|
||||
}
|
||||
|
||||
// This method will override any existing recovery states, so call it with caution, if you
|
||||
// think that there could be existing important state info in the recovery buffers (but
|
||||
// really there shouldn't be, unless you're calling this function when it's not intended
|
||||
// to be called).
|
||||
void MakeGsOnly()
|
||||
{
|
||||
StateRecovery::Clear();
|
||||
if( !EmulationInProgress() ) return;
|
||||
|
||||
g_gsRecoveryState = new SafeArray<u8>();
|
||||
JustGsSavingState eddie;
|
||||
eddie.FreezePlugin( "GS", gsSafeFreeze ) ;
|
||||
eddie.gsFreeze();
|
||||
}
|
||||
|
||||
// Creates a full recovery of the entire emulation state (CPU and all plugins).
|
||||
// If a current recovery state is already present, then nothing is done (the
|
||||
// existing recovery state takes precedence since if it were out-of-date it'd be
|
||||
// deleted!).
|
||||
void MakeFull()
|
||||
{
|
||||
if( g_RecoveryState != NULL ) return;
|
||||
if( g_RecoveryState ) return;
|
||||
if( !EmulationInProgress() ) return;
|
||||
|
||||
SysSuspend();
|
||||
|
||||
try
|
||||
{
|
||||
g_RecoveryState = new SafeArray<u8>( L"Memory Savestate Recovery" );
|
||||
RecoveryMemSavingState().FreezeAll();
|
||||
safe_delete( g_gsRecoveryState );
|
||||
g_RecoveryState.reset( new SafeArray<u8>( L"Memory Savestate Recovery" ) );
|
||||
memSavingState( *g_RecoveryState ).FreezeAll();
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
|
@ -189,101 +76,13 @@ namespace StateRecovery {
|
|||
L"able to recover if you make changes to your PCSX2 configuration.\n\n"
|
||||
L"Details: %s", ex.FormatDisplayMessage().c_str() )
|
||||
);
|
||||
safe_delete( g_RecoveryState );
|
||||
g_RecoveryState.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Clears and deallocates any recovery states.
|
||||
void Clear()
|
||||
{
|
||||
safe_delete( g_RecoveryState );
|
||||
safe_delete( g_gsRecoveryState );
|
||||
}
|
||||
}
|
||||
|
||||
RecoveryMemSavingState::RecoveryMemSavingState() : memSavingState( *g_RecoveryState )
|
||||
{
|
||||
}
|
||||
|
||||
void RecoveryMemSavingState::gsFreeze()
|
||||
{
|
||||
if( g_gsRecoveryState != NULL )
|
||||
{
|
||||
// just copy the data from src to dst.
|
||||
// the normal savestate doesn't expect a length prefix for internal structures,
|
||||
// so don't copy that part.
|
||||
const u32 pluginlen = *((u32*)g_gsRecoveryState->GetPtr());
|
||||
const u32 gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4));
|
||||
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(pluginlen+8), gslen );
|
||||
m_idx += gslen;
|
||||
}
|
||||
else
|
||||
memSavingState::gsFreeze();
|
||||
}
|
||||
|
||||
void RecoveryMemSavingState::FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )
|
||||
{
|
||||
if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) )
|
||||
{
|
||||
// Gs data is already in memory, so just copy from src to dest:
|
||||
// length of the GS data is stored as the first u32, so use that to run the copy:
|
||||
const u32 len = *((u32*)g_gsRecoveryState->GetPtr());
|
||||
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(), len+4 );
|
||||
m_idx += len+4;
|
||||
}
|
||||
else
|
||||
memSavingState::FreezePlugin( name, freezer );
|
||||
}
|
||||
|
||||
RecoveryZipSavingState::RecoveryZipSavingState( const wxString& filename ) : gzSavingState( filename )
|
||||
{
|
||||
}
|
||||
|
||||
void RecoveryZipSavingState::gsFreeze()
|
||||
{
|
||||
if( g_gsRecoveryState != NULL )
|
||||
{
|
||||
// read data from the gsRecoveryState allocation instead of the GS, since the gs
|
||||
// info was invalidated when the plugin was shut down.
|
||||
|
||||
// the normal savestate doesn't expect a length prefix for internal structures,
|
||||
// so don't copy that part.
|
||||
|
||||
u32& pluginlen = *((u32*)g_gsRecoveryState->GetPtr(0));
|
||||
u32& gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4));
|
||||
gzwrite( m_file, g_gsRecoveryState->GetPtr(pluginlen+4), gslen );
|
||||
}
|
||||
else
|
||||
gzSavingState::gsFreeze();
|
||||
}
|
||||
|
||||
void RecoveryZipSavingState::FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )
|
||||
{
|
||||
if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) )
|
||||
{
|
||||
// Gs data is already in memory, so just copy from there into the gzip file.
|
||||
// length of the GS data is stored as the first u32, so use that to run the copy:
|
||||
u32& len = *((u32*)g_gsRecoveryState->GetPtr());
|
||||
gzwrite( m_file, g_gsRecoveryState->GetPtr(), len+4 );
|
||||
}
|
||||
else
|
||||
gzSavingState::FreezePlugin( name, freezer );
|
||||
}
|
||||
|
||||
JustGsSavingState::JustGsSavingState() : memSavingState( *g_gsRecoveryState )
|
||||
{
|
||||
}
|
||||
|
||||
// This special override saves the gs info to m_idx+4, and then goes back and
|
||||
// writes in the length of data saved.
|
||||
void JustGsSavingState::gsFreeze()
|
||||
{
|
||||
int oldmidx = m_idx;
|
||||
m_idx += 4;
|
||||
memSavingState::gsFreeze();
|
||||
if( IsSaving() )
|
||||
{
|
||||
s32& len = *((s32*)m_memory.GetPtr( oldmidx ));
|
||||
len = (m_idx - oldmidx)-4;
|
||||
g_RecoveryState.reset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -437,7 +437,7 @@ void SPRTOinterrupt()
|
|||
hwDmacIrq(DMAC_TO_SPR);
|
||||
}
|
||||
|
||||
void SaveState::sprFreeze()
|
||||
void SaveStateBase::sprFreeze()
|
||||
{
|
||||
FreezeTag("SPRdma");
|
||||
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
|
||||
using namespace R5900;
|
||||
|
||||
extern void recResetEE();
|
||||
extern void recResetIOP();
|
||||
|
||||
static void PreLoadPrep()
|
||||
{
|
||||
SysClearExecutionCache();
|
||||
|
@ -49,38 +46,45 @@ static void PostLoadPrep()
|
|||
for(int i=0; i<48; i++) MapTLB(i);
|
||||
}
|
||||
|
||||
wxString SaveState::GetFilename( int slot )
|
||||
wxString SaveStateBase::GetFilename( int slot )
|
||||
{
|
||||
return (g_Conf->Folders.Savestates +
|
||||
wxsFormat( L"%8.8X.%3.3d", ElfCRC, slot )).GetFullPath();
|
||||
}
|
||||
|
||||
SaveState::SaveState( const char* msg, const wxString& destination ) :
|
||||
m_version( g_SaveVersion )
|
||||
, m_tagspace( 128 )
|
||||
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 )
|
||||
{
|
||||
Console::WriteLn( "%s %s", msg, destination.ToAscii().data() );
|
||||
}
|
||||
|
||||
s32 CALLBACK gsSafeFreeze( int mode, freezeData *data )
|
||||
void SaveStateBase::PrepBlock( int size )
|
||||
{
|
||||
// have to call in the GS thread, otherwise weird stuff will start happening
|
||||
mtgsThread->SendPointerPacket( GS_RINGTYPE_FREEZE, mode, data );
|
||||
mtgsWaitGS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SaveState::FreezeTag( const char* src )
|
||||
{
|
||||
const int length = strlen( src );
|
||||
m_tagspace.MakeRoomFor( length+1 );
|
||||
|
||||
strcpy( m_tagspace.GetPtr(), src );
|
||||
FreezeMem( m_tagspace.GetPtr(), length );
|
||||
|
||||
if( strcmp( m_tagspace.GetPtr(), src ) != 0 )
|
||||
const int end = m_idx+size;
|
||||
if( IsSaving() )
|
||||
m_memory.MakeRoomFor( end );
|
||||
else
|
||||
{
|
||||
assert( 0 );
|
||||
if( m_memory.GetSizeInBytes() <= end )
|
||||
throw Exception::BadSavedState();
|
||||
}
|
||||
}
|
||||
|
||||
void SaveStateBase::FreezeTag( const char* src )
|
||||
{
|
||||
wxASSERT( strlen(src) < (sizeof( m_tagspace )-1) );
|
||||
|
||||
memzero_obj( m_tagspace );
|
||||
strcpy( m_tagspace, src );
|
||||
Freeze( m_tagspace );
|
||||
|
||||
if( strcmp( m_tagspace, src ) != 0 )
|
||||
{
|
||||
wxASSERT_MSG( false, L"Savestate data corruption detected while reading tag" );
|
||||
throw Exception::BadSavedState(
|
||||
// Untranslated diagnostic msg (use default msg for translation)
|
||||
L"Savestate data corruption detected while reading tag: " + wxString::FromAscii(src)
|
||||
|
@ -88,48 +92,68 @@ void SaveState::FreezeTag( const char* src )
|
|||
}
|
||||
}
|
||||
|
||||
void SaveState::FreezeAll()
|
||||
void SaveStateBase::FreezeBios()
|
||||
{
|
||||
if( IsLoading() )
|
||||
PreLoadPrep();
|
||||
|
||||
// Check the BIOS, and issue a warning if the bios for this state
|
||||
// doesn't match the bios currently being used (chances are it'll still
|
||||
// work fine, but some games are very picky).
|
||||
|
||||
|
||||
char descin[128];
|
||||
wxString descout;
|
||||
IsBIOS( g_Conf->FullpathToBios(), descout );
|
||||
memcpy_fast( descin, descout.ToAscii().data(), 128 );
|
||||
Freeze( descin );
|
||||
|
||||
if( memcmp( descin, descout, 128 ) != 0 )
|
||||
{
|
||||
Console::Error(
|
||||
"\n\tWarning: BIOS Version Mismatch, savestate may be unstable!\n"
|
||||
"\t\tCurrent BIOS: %s\n"
|
||||
"\t\tSavestate BIOS: %s\n",
|
||||
descout.ToAscii().data(), descin
|
||||
);
|
||||
}
|
||||
|
||||
// ... and only freeze bios info once per state, since the user msg could
|
||||
// become really annoying on a corrupted state or something. (have to always
|
||||
// load though, so that we advance past the duplicated info, if present)
|
||||
|
||||
if( IsLoading() || !m_DidBios )
|
||||
Freeze( descin );
|
||||
|
||||
if( !m_DidBios )
|
||||
{
|
||||
if( memcmp( descin, descout, 128 ) != 0 )
|
||||
{
|
||||
Console::Error(
|
||||
"\n\tWarning: BIOS Version Mismatch, savestate may be unstable!\n"
|
||||
"\t\tCurrent Version: %s\n"
|
||||
"\t\tSavestate Version: %s\n",
|
||||
descout.ToAscii().data(), descin
|
||||
);
|
||||
}
|
||||
}
|
||||
m_DidBios = true;
|
||||
}
|
||||
|
||||
static const int MainMemorySizeInBytes =
|
||||
Ps2MemSize::Base + Ps2MemSize::Scratch + Ps2MemSize::Hardware +
|
||||
Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x0100;
|
||||
|
||||
void SaveStateBase::FreezeMainMemory()
|
||||
{
|
||||
// First Block - Memory Dumps
|
||||
// ---------------------------
|
||||
FreezeMem(PS2MEM_BASE, Ps2MemSize::Base); // 32 MB main memory
|
||||
FreezeMem(PS2MEM_SCRATCH, Ps2MemSize::Scratch); // scratch pad
|
||||
FreezeMem(PS2MEM_HW, Ps2MemSize::Hardware); // hardware memory
|
||||
FreezeMem(PS2MEM_BASE, Ps2MemSize::Base); // 32 MB main memory
|
||||
FreezeMem(PS2MEM_SCRATCH, Ps2MemSize::Scratch); // scratch pad
|
||||
FreezeMem(PS2MEM_HW, Ps2MemSize::Hardware); // hardware memory
|
||||
|
||||
FreezeMem(psxM, Ps2MemSize::IopRam); // 2 MB main memory
|
||||
FreezeMem(psxH, Ps2MemSize::IopHardware); // hardware memory
|
||||
FreezeMem(psxS, 0x000100); // iop's sif memory
|
||||
}
|
||||
|
||||
void SaveStateBase::FreezeRegisters()
|
||||
{
|
||||
if( IsLoading() )
|
||||
PreLoadPrep();
|
||||
|
||||
// Second Block - Various CPU Registers and States
|
||||
// -----------------------------------------------
|
||||
FreezeTag( "cpuRegs" );
|
||||
Freeze(cpuRegs); // cpu regs + COP0
|
||||
Freeze(psxRegs); // iop regs
|
||||
Freeze(cpuRegs); // cpu regs + COP0
|
||||
Freeze(psxRegs); // iop regs
|
||||
Freeze(fpuRegs);
|
||||
Freeze(tlb); // tlbs
|
||||
Freeze(tlb); // tlbs
|
||||
|
||||
// Third Block - Cycle Timers and Events
|
||||
// -------------------------------------
|
||||
|
@ -143,6 +167,7 @@ void SaveState::FreezeAll()
|
|||
|
||||
// Fourth Block - EE-related systems
|
||||
// ---------------------------------
|
||||
FreezeTag( "EE-Subsystems" );
|
||||
rcntFreeze();
|
||||
gsFreeze();
|
||||
vuMicroFreeze();
|
||||
|
@ -155,154 +180,172 @@ void SaveState::FreezeAll()
|
|||
|
||||
// Fifth Block - iop-related systems
|
||||
// ---------------------------------
|
||||
FreezeTag( "IOP-Subsystems" );
|
||||
psxRcntFreeze();
|
||||
sioFreeze();
|
||||
sio2Freeze();
|
||||
cdrFreeze();
|
||||
cdvdFreeze();
|
||||
|
||||
// Sixth Block - Plugins Galore!
|
||||
// -----------------------------
|
||||
FreezePlugin( "GS", gsSafeFreeze );
|
||||
|
||||
g_plugins->Freeze( *this );
|
||||
|
||||
if( IsLoading() )
|
||||
PostLoadPrep();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// gzipped to/from disk state saves implementation
|
||||
|
||||
gzBaseStateInfo::gzBaseStateInfo( const char* msg, const wxString& filename ) :
|
||||
SaveState( msg, filename )
|
||||
, m_filename( filename )
|
||||
, m_file( NULL )
|
||||
bool SaveStateBase::FreezeSection()
|
||||
{
|
||||
}
|
||||
Freeze( m_sectid );
|
||||
|
||||
gzBaseStateInfo::~gzBaseStateInfo()
|
||||
{
|
||||
if( m_file != NULL )
|
||||
switch( m_sectid )
|
||||
{
|
||||
gzclose( m_file );
|
||||
m_file = NULL;
|
||||
case FreezeId_End:
|
||||
return false;
|
||||
|
||||
case FreezeId_Bios:
|
||||
{
|
||||
int sectlen = 128;
|
||||
FreezeTag( "BiosVersion" );
|
||||
Freeze( sectlen );
|
||||
|
||||
if( sectlen != MainMemorySizeInBytes )
|
||||
{
|
||||
throw Exception::BadSavedState( wxEmptyString,
|
||||
L"Invalid size encountered on BiosVersion section.",
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
}
|
||||
|
||||
FreezeBios();
|
||||
m_sectid++;
|
||||
}
|
||||
break;
|
||||
|
||||
case FreezeId_Memory:
|
||||
{
|
||||
FreezeTag( "MainMemory" );
|
||||
|
||||
int sectlen = MainMemorySizeInBytes;
|
||||
Freeze( sectlen );
|
||||
if( sectlen != MainMemorySizeInBytes )
|
||||
{
|
||||
throw Exception::BadSavedState( wxEmptyString,
|
||||
L"Invalid size encountered on MainMemory section.",
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
}
|
||||
|
||||
FreezeMainMemory();
|
||||
m_sectid++;
|
||||
}
|
||||
break;
|
||||
|
||||
case FreezeId_Registers:
|
||||
{
|
||||
FreezeTag( "HardwareRegisters" );
|
||||
int seekpos = m_idx;
|
||||
int sectsize;
|
||||
Freeze( sectsize );
|
||||
|
||||
FreezeRegisters();
|
||||
|
||||
int realsectsize = m_idx - seekpos;
|
||||
if( IsSaving() )
|
||||
{
|
||||
// write back the section length...
|
||||
*((u32*)m_memory.GetPtr(seekpos)) = realsectsize - 4;
|
||||
}
|
||||
else // IsLoading!!
|
||||
{
|
||||
if( sectsize != realsectsize ) // if they don't match then we have a problem, jim.
|
||||
{
|
||||
throw Exception::BadSavedState( wxEmptyString,
|
||||
L"Invalid size encountered on HardwareRegisters section.",
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FreezeId_Plugin:
|
||||
{
|
||||
FreezeTag( "Plugin" );
|
||||
int seekpos = m_idx;
|
||||
int sectsize;
|
||||
Freeze( sectsize );
|
||||
|
||||
Freeze( m_pid );
|
||||
g_plugins->Freeze( (PluginsEnum_t)m_pid, *this );
|
||||
|
||||
int realsectsize = m_idx - seekpos;
|
||||
if( IsSaving() )
|
||||
{
|
||||
// write back the section length...
|
||||
*((u32*)m_memory.GetPtr(seekpos)) = realsectsize - 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( sectsize != realsectsize ) // if they don't match then we have a problem, jim.
|
||||
{
|
||||
throw Exception::BadSavedState( wxEmptyString,
|
||||
L"Invalid size encountered on Plugin section.",
|
||||
_("The savestate data is invalid or corrupted.")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// following increments only affect Saving mode, are ignored by Loading mode.
|
||||
m_pid++;
|
||||
if( m_pid > PluginId_Count )
|
||||
m_sectid++;
|
||||
}
|
||||
break;
|
||||
|
||||
case FreezeId_Unknown:
|
||||
default:
|
||||
if( IsSaving() )
|
||||
m_sectid = FreezeId_End;
|
||||
else
|
||||
{
|
||||
// Skip unknown sections with a warning log.
|
||||
// Maybe it'll work! (haha?)
|
||||
|
||||
int size;
|
||||
Freeze( m_tagspace );
|
||||
Freeze( size );
|
||||
m_tagspace[sizeof(m_tagspace)-1] = 0;
|
||||
|
||||
Console::Notice(
|
||||
"Warning: Unknown tag encountered while loading savestate; going to ignore it!\n"
|
||||
"\tTagname: %s, Size: %d", m_tagspace, size
|
||||
);
|
||||
m_idx += size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
gzSavingState::gzSavingState( const wxString& filename ) :
|
||||
gzBaseStateInfo( "Saving state to: ", filename )
|
||||
void SaveStateBase::FreezeAll()
|
||||
{
|
||||
m_file = gzopen(filename.ToAscii().data(), "wb");
|
||||
if( m_file == NULL )
|
||||
throw Exception::FileNotFound();
|
||||
m_sectid = (int)FreezeId_End+1;
|
||||
m_pid = PluginId_GS;
|
||||
|
||||
gzsetparams( m_file, Z_BEST_SPEED, Z_DEFAULT_STRATEGY );
|
||||
Freeze( m_version );
|
||||
}
|
||||
|
||||
|
||||
gzLoadingState::gzLoadingState( const wxString& filename ) :
|
||||
gzBaseStateInfo( "Loading state from: ", filename )
|
||||
{
|
||||
m_file = gzopen(filename.ToAscii().data(), "rb");
|
||||
if( m_file == NULL )
|
||||
throw Exception::FileNotFound();
|
||||
|
||||
gzread( m_file, &m_version, 4 );
|
||||
|
||||
if( (m_version >> 16) != (g_SaveVersion >> 16) )
|
||||
{
|
||||
Console::Error(
|
||||
"Savestate load aborted:\n"
|
||||
"\tUnknown or invalid savestate identifier, either from a (very!) old version of\n"
|
||||
"\tPcsx2, or the file is corrupted"
|
||||
);
|
||||
throw Exception::UnsupportedStateVersion( m_version );
|
||||
}
|
||||
else if( m_version > g_SaveVersion )
|
||||
{
|
||||
Console::Error(
|
||||
"Savestate load aborted:\n"
|
||||
"\tThe savestate was created with a newer version of Pcsx2. I don't know how to load it!" );
|
||||
throw Exception::UnsupportedStateVersion( m_version );
|
||||
}
|
||||
}
|
||||
|
||||
gzLoadingState::~gzLoadingState() { }
|
||||
|
||||
|
||||
void gzSavingState::FreezeMem( void* data, int size )
|
||||
{
|
||||
gzwrite( m_file, data, size );
|
||||
}
|
||||
|
||||
void gzLoadingState::FreezeMem( void* data, int size )
|
||||
{
|
||||
if( gzread( m_file, data, size ) != size )
|
||||
throw Exception::BadSavedState( m_filename );
|
||||
}
|
||||
|
||||
void gzSavingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) )
|
||||
{
|
||||
freezeData fP = { 0, NULL };
|
||||
Console::WriteLn( "\tSaving %s", name );
|
||||
|
||||
FreezeTag( name );
|
||||
|
||||
if (freezer(FREEZE_SIZE, &fP) == -1)
|
||||
throw Exception::FreezePluginFailure( name, "saving" );
|
||||
|
||||
Freeze( fP.size );
|
||||
if( fP.size == 0 ) return;
|
||||
|
||||
SafeArray<s8> buffer( fP.size );
|
||||
fP.data = buffer.GetPtr();
|
||||
|
||||
if(freezer(FREEZE_SAVE, &fP) == -1)
|
||||
throw Exception::FreezePluginFailure( name, "saving" );
|
||||
|
||||
FreezeMem( fP.data, fP.size );
|
||||
}
|
||||
|
||||
void gzLoadingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) )
|
||||
{
|
||||
freezeData fP = { 0, NULL };
|
||||
Console::WriteLn( "\tLoading %s", name );
|
||||
|
||||
FreezeTag( name );
|
||||
Freeze( fP.size );
|
||||
if( fP.size == 0 ) return;
|
||||
|
||||
SafeArray<s8> buffer( fP.size );
|
||||
fP.data = buffer.GetPtr();
|
||||
|
||||
FreezeMem( fP.data, fP.size );
|
||||
|
||||
if(freezer(FREEZE_LOAD, &fP) == -1)
|
||||
throw Exception::FreezePluginFailure( name, "loading" );
|
||||
while( FreezeSection() ) ;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// uncompressed to/from memory state saves implementation
|
||||
|
||||
memBaseStateInfo::memBaseStateInfo( SafeArray<u8>& memblock, const char* msg ) :
|
||||
SaveState( msg, L"Memory")
|
||||
, m_memory( memblock )
|
||||
, m_idx( 0 )
|
||||
{
|
||||
// Always clear the MTGS thread state.
|
||||
mtgsWaitGS();
|
||||
}
|
||||
|
||||
memSavingState::memSavingState( SafeArray<u8>& save_to ) : memBaseStateInfo( save_to, "Saving state to: " )
|
||||
memSavingState::memSavingState( SafeArray<u8>& save_to ) :
|
||||
SaveStateBase( save_to )
|
||||
{
|
||||
save_to.ChunkSize = ReallocThreshold;
|
||||
save_to.MakeRoomFor( MemoryBaseAllocSize );
|
||||
}
|
||||
|
||||
// Saving of state data to a memory buffer
|
||||
// Saving of state data
|
||||
void memSavingState::FreezeMem( void* data, int size )
|
||||
{
|
||||
const int end = m_idx+size;
|
||||
|
@ -315,14 +358,14 @@ void memSavingState::FreezeMem( void* data, int size )
|
|||
dest[m_idx] = *src;
|
||||
}
|
||||
|
||||
memLoadingState::memLoadingState(SafeArray<u8>& load_from ) :
|
||||
memBaseStateInfo( load_from, "Loading state from: " )
|
||||
memLoadingState::memLoadingState( const SafeArray<u8>& load_from ) :
|
||||
SaveStateBase( const_cast<SafeArray<u8>&>(load_from) )
|
||||
{
|
||||
}
|
||||
|
||||
memLoadingState::~memLoadingState() { }
|
||||
|
||||
// Loading of state data from a memory buffer...
|
||||
// Loading of state data
|
||||
void memLoadingState::FreezeMem( void* data, int size )
|
||||
{
|
||||
const int end = m_idx+size;
|
||||
|
@ -332,45 +375,3 @@ void memLoadingState::FreezeMem( void* data, int size )
|
|||
for( ; m_idx<end; ++m_idx, ++dest )
|
||||
*dest = src[m_idx];
|
||||
}
|
||||
|
||||
void memSavingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) )
|
||||
{
|
||||
freezeData fP = { 0, NULL };
|
||||
Console::WriteLn( "\tSaving %s", name );
|
||||
|
||||
if( freezer(FREEZE_SIZE, &fP) == -1 )
|
||||
throw Exception::FreezePluginFailure( name, "saving" );
|
||||
|
||||
Freeze( fP.size );
|
||||
if( fP.size == 0 ) return;
|
||||
|
||||
const int end = m_idx+fP.size;
|
||||
m_memory.MakeRoomFor( end );
|
||||
|
||||
fP.data = ((s8*)m_memory.GetPtr()) + m_idx;
|
||||
if(freezer(FREEZE_SAVE, &fP) == -1)
|
||||
throw Exception::FreezePluginFailure( name, "saving" );
|
||||
|
||||
m_idx += fP.size;
|
||||
}
|
||||
|
||||
void memLoadingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) )
|
||||
{
|
||||
freezeData fP;
|
||||
Console::WriteLn( "\tLoading %s", name );
|
||||
|
||||
Freeze( fP.size );
|
||||
if( fP.size == 0 ) return;
|
||||
|
||||
if( ( fP.size + m_idx ) > m_memory.GetSizeInBytes() )
|
||||
{
|
||||
assert(0);
|
||||
throw Exception::BadSavedState( L"memory");
|
||||
}
|
||||
|
||||
fP.data = ((s8*)m_memory.GetPtr()) + m_idx;
|
||||
if(freezer(FREEZE_LOAD, &fP) == -1)
|
||||
throw Exception::FreezePluginFailure( name, "loading" );
|
||||
|
||||
m_idx += fP.size;
|
||||
}
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SAVESTATE_H_
|
||||
#define _SAVESTATE_H_
|
||||
#pragma once
|
||||
|
||||
// This shouldn't break Win compiles, but it does.
|
||||
#ifdef __LINUX__
|
||||
|
@ -28,25 +27,53 @@
|
|||
// the lower 16 bit value. IF the change is breaking of all compatibility with old
|
||||
// states, increment the upper 16 bit value, and clear the lower 16 bits to 0.
|
||||
|
||||
static const u32 g_SaveVersion = 0x8b410001;
|
||||
static const u32 g_SaveVersion = 0x8b410002;
|
||||
|
||||
// this function is meant to be used in the place of GSfreeze, and provides a safe layer
|
||||
// between the GS saving function and the MTGS's needs. :)
|
||||
extern s32 CALLBACK gsSafeFreeze( int mode, freezeData *data );
|
||||
|
||||
// This class provides the base API for both loading and saving savestates.
|
||||
// Normally you'll want to use one of the four "functional" derived classes rather
|
||||
// than this class directly: gzLoadingState, gzSavingState (gzipped disk-saved
|
||||
|
||||
enum FreezeSectionId
|
||||
{
|
||||
FreezeId_End,
|
||||
|
||||
FreezeId_Memory,
|
||||
FreezeId_Registers,
|
||||
|
||||
// A BIOS tag should always be saved in conjunction with Memory or Registers tags,
|
||||
// but can be skipped if the savestate has only plugins.
|
||||
FreezeId_Bios,
|
||||
|
||||
FreezeId_Plugin,
|
||||
|
||||
// anything here and beyond we can skip, with a warning
|
||||
FreezeId_Unknown,
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SaveStateBase class
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Provides the base API for both loading and saving savestates. Normally you'll want to
|
||||
// use one of the four "functional" derived classes rather than this class directly: gzLoadingState, gzSavingState (gzipped disk-saved
|
||||
// states), and memLoadingState, memSavingState (uncompressed memory states).
|
||||
class SaveState
|
||||
class SaveStateBase
|
||||
{
|
||||
protected:
|
||||
SafeArray<u8>& m_memory;
|
||||
char m_tagspace[32];
|
||||
|
||||
u32 m_version; // version of the savestate being loaded.
|
||||
SafeArray<char> m_tagspace;
|
||||
|
||||
int m_idx; // current read/write index of the allocation
|
||||
int m_sectid;
|
||||
int m_pid;
|
||||
|
||||
bool m_DidBios;
|
||||
|
||||
public:
|
||||
SaveState( const char* msg, const wxString& destination );
|
||||
virtual ~SaveState() { }
|
||||
SaveStateBase( SafeArray<u8>& memblock );
|
||||
virtual ~SaveStateBase() { }
|
||||
|
||||
static wxString GetFilename( int slot );
|
||||
|
||||
|
@ -78,14 +105,28 @@ public:
|
|||
FreezeMem( &data, sizeof( T ) - sizeOfNewStuff );
|
||||
}
|
||||
|
||||
void PrepBlock( int size );
|
||||
|
||||
u8* GetBlockPtr()
|
||||
{
|
||||
return &m_memory[m_idx];
|
||||
}
|
||||
|
||||
void CommitBlock( int size )
|
||||
{
|
||||
m_idx += size;
|
||||
}
|
||||
|
||||
bool FreezeSection();
|
||||
|
||||
// Freezes an identifier value into the savestate for troubleshooting purposes.
|
||||
// Identifiers can be used to determine where in a savestate that data has become
|
||||
// skewed (if the value does not match then the error occurs somewhere prior to that
|
||||
// position).
|
||||
void FreezeTag( const char* src );
|
||||
|
||||
// Loads or saves a plugin. Plugin name is for console logging purposes.
|
||||
virtual void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )=0;
|
||||
// Returns true if this object is a StateLoading type object.
|
||||
bool IsLoading() const { return !IsSaving(); }
|
||||
|
||||
// Loads or saves a memory block.
|
||||
virtual void FreezeMem( void* data, int size )=0;
|
||||
|
@ -93,18 +134,18 @@ public:
|
|||
// Returns true if this object is a StateSaving type object.
|
||||
virtual bool IsSaving() const=0;
|
||||
|
||||
// Returns true if this object is a StateLoading type object.
|
||||
bool IsLoading() const { return !IsSaving(); }
|
||||
|
||||
// note: gsFreeze() needs to be public because of the GSState recorder.
|
||||
|
||||
public:
|
||||
virtual void gsFreeze();
|
||||
// note: gsFreeze() needs to be public because of the GSState recorder.
|
||||
void gsFreeze();
|
||||
|
||||
protected:
|
||||
|
||||
// Load/Save functions for the various components of our glorious emulator!
|
||||
|
||||
void FreezeBios();
|
||||
void FreezeMainMemory();
|
||||
void FreezeRegisters();
|
||||
|
||||
void rcntFreeze();
|
||||
void vuMicroFreeze();
|
||||
void vif0Freeze();
|
||||
|
@ -125,57 +166,11 @@ protected:
|
|||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Class Declarations for Savestates using zlib
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Saving and Loading Specialized Implementations...
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
class gzBaseStateInfo : public SaveState
|
||||
{
|
||||
protected:
|
||||
const wxString m_filename;
|
||||
gzFile m_file; // used for reading/writing disk saves
|
||||
|
||||
public:
|
||||
gzBaseStateInfo( const char* msg, const wxString& filename );
|
||||
|
||||
virtual ~gzBaseStateInfo();
|
||||
};
|
||||
|
||||
class gzSavingState : public gzBaseStateInfo
|
||||
{
|
||||
public:
|
||||
virtual ~gzSavingState() {}
|
||||
gzSavingState( const wxString& filename ) ;
|
||||
void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) );
|
||||
void FreezeMem( void* data, int size );
|
||||
bool IsSaving() const { return true; }
|
||||
};
|
||||
|
||||
class gzLoadingState : public gzBaseStateInfo
|
||||
{
|
||||
public:
|
||||
virtual ~gzLoadingState();
|
||||
gzLoadingState( const wxString& filename );
|
||||
|
||||
void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) );
|
||||
void FreezeMem( void* data, int size );
|
||||
bool IsSaving() const { return false; }
|
||||
bool Finished() const { return !!gzeof( m_file ); }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class memBaseStateInfo : public SaveState
|
||||
{
|
||||
protected:
|
||||
SafeArray<u8>& m_memory;
|
||||
int m_idx; // current read/write index of the allocation
|
||||
|
||||
public:
|
||||
virtual ~memBaseStateInfo() { }
|
||||
memBaseStateInfo( SafeArray<u8>& memblock, const char* msg );
|
||||
};
|
||||
|
||||
class memSavingState : public memBaseStateInfo
|
||||
class memSavingState : public SaveStateBase
|
||||
{
|
||||
protected:
|
||||
static const int ReallocThreshold = 0x200000; // 256k reallocation block size.
|
||||
|
@ -185,22 +180,21 @@ public:
|
|||
virtual ~memSavingState() { }
|
||||
memSavingState( SafeArray<u8>& save_to );
|
||||
|
||||
void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) );
|
||||
// Saving of state data to a memory buffer
|
||||
void FreezeMem( void* data, int size );
|
||||
bool IsSaving() const { return true; }
|
||||
};
|
||||
|
||||
class memLoadingState : public memBaseStateInfo
|
||||
class memLoadingState : public SaveStateBase
|
||||
{
|
||||
public:
|
||||
virtual ~memLoadingState();
|
||||
memLoadingState(SafeArray<u8>& load_from );
|
||||
memLoadingState( const SafeArray<u8>& load_from );
|
||||
|
||||
void FreezePlugin( const char* name, s32(CALLBACK *freezer)(int mode, freezeData *data) );
|
||||
// Loading of state data from a memory buffer...
|
||||
void FreezeMem( void* data, int size );
|
||||
bool IsSaving() const { return false; }
|
||||
bool IsFinished() const { return m_idx >= m_memory.GetSizeInBytes(); }
|
||||
};
|
||||
|
||||
namespace StateRecovery
|
||||
|
@ -209,10 +203,7 @@ namespace StateRecovery
|
|||
extern void Recover();
|
||||
extern void SaveToFile( const wxString& file );
|
||||
extern void SaveToSlot( uint num );
|
||||
extern void MakeGsOnly();
|
||||
extern void MakeFull();
|
||||
extern void Clear();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -499,7 +499,7 @@ __forceinline void dmaSIF2()
|
|||
}
|
||||
|
||||
|
||||
void SaveState::sifFreeze()
|
||||
void SaveStateBase::sifFreeze()
|
||||
{
|
||||
FreezeTag("SIFdma");
|
||||
|
||||
|
|
|
@ -645,7 +645,7 @@ void SIO_FORCEINLINE sioInterrupt() {
|
|||
psxHu32(0x1070)|=0x80;
|
||||
}
|
||||
|
||||
void SaveState::sioFreeze()
|
||||
void SaveStateBase::sioFreeze()
|
||||
{
|
||||
// CRCs for memory cards.
|
||||
u64 m_mcdCRCs[2][8];
|
||||
|
|
365
pcsx2/System.cpp
365
pcsx2/System.cpp
|
@ -39,25 +39,16 @@ Pcsx2Config EmuConfig;
|
|||
|
||||
// disable all session overrides by default...
|
||||
SessionOverrideFlags g_Session = {false};
|
||||
CoreEmuThread* g_EmuThread;
|
||||
|
||||
bool sysInitialized = false;
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// This function should be called once during program execution.
|
||||
//
|
||||
void SysDetect()
|
||||
{
|
||||
using namespace Console;
|
||||
|
||||
#ifdef __LINUX__
|
||||
// Haven't rigged up getting the svn version yet... --arcum42
|
||||
Notice("PCSX2 %d.%d.%d - compiled on " __DATE__, PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo);
|
||||
#else
|
||||
Notice("PCSX2 %d.%d.%d.r%d %s - compiled on " __DATE__, PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo,
|
||||
SVN_REV, SVN_MODS ? "(modded)" : ""
|
||||
);
|
||||
#endif
|
||||
|
||||
Notice("Savestate version: %x", g_SaveVersion);
|
||||
|
||||
cpudetectInit();
|
||||
|
@ -82,49 +73,51 @@ void SysDetect()
|
|||
x86caps.Flags, x86caps.Flags2,
|
||||
x86caps.EFlags
|
||||
) );
|
||||
|
||||
wxArrayString features[2]; // 2 lines, for readability!
|
||||
|
||||
if( x86caps.hasMultimediaExtensions ) features[0].Add( L"MMX" );
|
||||
if( x86caps.hasStreamingSIMDExtensions ) features[0].Add( L"SSE" );
|
||||
if( x86caps.hasStreamingSIMD2Extensions ) features[0].Add( L"SSE2" );
|
||||
if( x86caps.hasStreamingSIMD3Extensions ) features[0].Add( L"SSE3" );
|
||||
if( x86caps.hasSupplementalStreamingSIMD3Extensions ) features[0].Add( L"SSSE3" );
|
||||
if( x86caps.hasStreamingSIMD4Extensions ) features[0].Add( L"SSE4.1" );
|
||||
if( x86caps.hasStreamingSIMD4Extensions2 ) features[0].Add( L"SSE4.2" );
|
||||
|
||||
WriteLn( "Features:" );
|
||||
WriteLn(
|
||||
"\t%sDetected MMX\n"
|
||||
"\t%sDetected SSE\n"
|
||||
"\t%sDetected SSE2\n"
|
||||
"\t%sDetected SSE3\n"
|
||||
"\t%sDetected SSSE3\n"
|
||||
"\t%sDetected SSE4.1\n"
|
||||
"\t%sDetected SSE4.2\n",
|
||||
x86caps.hasMultimediaExtensions ? "" : "Not ",
|
||||
x86caps.hasStreamingSIMDExtensions ? "" : "Not ",
|
||||
x86caps.hasStreamingSIMD2Extensions ? "" : "Not ",
|
||||
x86caps.hasStreamingSIMD3Extensions ? "" : "Not ",
|
||||
x86caps.hasSupplementalStreamingSIMD3Extensions ? "" : "Not ",
|
||||
x86caps.hasStreamingSIMD4Extensions ? "" : "Not ",
|
||||
x86caps.hasStreamingSIMD4Extensions2 ? "" : "Not "
|
||||
);
|
||||
if( x86caps.hasMultimediaExtensionsExt ) features[1].Add( L"MMX2 " );
|
||||
if( x86caps.has3DNOWInstructionExtensions ) features[1].Add( L"3DNOW " );
|
||||
if( x86caps.has3DNOWInstructionExtensionsExt ) features[1].Add( L"3DNOW2" );
|
||||
if( x86caps.hasStreamingSIMD4ExtensionsA ) features[1].Add( L"SSE4a " );
|
||||
|
||||
if ( x86caps.VendorName[0] == 'A' ) //AMD cpu
|
||||
{
|
||||
WriteLn( " Extended AMD Features:" );
|
||||
WriteLn(
|
||||
"\t%sDetected MMX2\n"
|
||||
"\t%sDetected 3DNOW\n"
|
||||
"\t%sDetected 3DNOW2\n"
|
||||
"\t%sDetected SSE4a\n",
|
||||
x86caps.hasMultimediaExtensionsExt ? "" : "Not ",
|
||||
x86caps.has3DNOWInstructionExtensions ? "" : "Not ",
|
||||
x86caps.has3DNOWInstructionExtensionsExt ? "" : "Not ",
|
||||
x86caps.hasStreamingSIMD4ExtensionsA ? "" : "Not "
|
||||
);
|
||||
}
|
||||
wxString result[2];
|
||||
JoinString( result[0], features[0], L".. " );
|
||||
JoinString( result[1], features[1], L".. " );
|
||||
|
||||
WriteLn( L"Features Detected:\n\t" + result[0] + (result[1].IsEmpty() ? wxEmptyString : (L"\n\t" + result[1])) + L"\n" );
|
||||
|
||||
//if ( x86caps.VendorName[0] == 'A' ) //AMD cpu
|
||||
|
||||
Console::ClearColor();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Allocates memory for all PS2 systems.
|
||||
bool SysAllocateMem()
|
||||
// returns the translated error message for the Virtual Machine failing to allocate!
|
||||
static wxString GetMemoryErrorVM()
|
||||
{
|
||||
// Allocate PS2 system ram space (required by interpreters and recompilers both)
|
||||
return pxE( ".Popup Error:EmuCore::MemoryForVM",
|
||||
L"PCSX2 is unable to allocate memory needed for the PS2 virtual machine. "
|
||||
L"Close out some memory hogging background tasks and try again."
|
||||
);
|
||||
}
|
||||
|
||||
EmuCoreAllocations::EmuCoreAllocations()
|
||||
{
|
||||
Console::Status( "Initializing PS2 virtual machine..." );
|
||||
|
||||
RecSuccess_EE = false;
|
||||
RecSuccess_IOP = false;
|
||||
RecSuccess_VU0 = false;
|
||||
RecSuccess_VU1 = false;
|
||||
|
||||
try
|
||||
{
|
||||
vtlb_Core_Alloc();
|
||||
|
@ -132,147 +125,116 @@ bool SysAllocateMem()
|
|||
psxMemAlloc();
|
||||
vuMicroMemAlloc();
|
||||
}
|
||||
catch( Exception::OutOfMemory& )
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::OutOfMemory& ex )
|
||||
{
|
||||
// TODO : Should this error be handled here or allowed to be handled by the main
|
||||
// exception handler?
|
||||
wxString newmsg( ex.UserMsg() + L"\n\n" + GetMemoryErrorVM() );
|
||||
ex.UserMsg() = newmsg;
|
||||
CleanupMess();
|
||||
throw;
|
||||
}
|
||||
catch( std::bad_alloc& ex )
|
||||
{
|
||||
CleanupMess();
|
||||
|
||||
// Failures on the core initialization of memory is bad, since it means the emulator is
|
||||
// completely non-functional.
|
||||
// re-throw std::bad_alloc as something more friendly.
|
||||
|
||||
//Msgbox::Alert( "Failed to allocate memory needed to run pcsx2.\n\nError: %s", ex.cMessage() );
|
||||
SysShutdownMem();
|
||||
return false;
|
||||
throw Exception::OutOfMemory(
|
||||
wxsFormat( // Diagnostic (english)
|
||||
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
|
||||
L"Error Details: " + wxString::FromUTF8( ex.what() )
|
||||
),
|
||||
|
||||
GetMemoryErrorVM() // translated
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Allocates memory for all recompilers, and force-disables any recs that fail to initialize.
|
||||
// This should be done asap, since the recompilers tend to demand a lot of system resources,
|
||||
// and prefer to have those resources at specific address ranges. The sooner memory is
|
||||
// allocated, the better.
|
||||
//
|
||||
// Returns FALSE on *critical* failure (GUI should issue a msg and exit).
|
||||
void SysAllocateDynarecs()
|
||||
{
|
||||
// Attempt to initialize the recompilers.
|
||||
// Most users want to use recs anyway, and if they are using interpreters I don't think the
|
||||
// extra few megs of allocation is going to be an issue.
|
||||
Console::Status( "Allocating memory for recompilers..." );
|
||||
|
||||
try
|
||||
{
|
||||
// R5900 and R3000a must be rec-enabled together for now so if either fails they both fail.
|
||||
recCpu.Allocate();
|
||||
psxRec.Allocate();
|
||||
RecSuccess_EE = true;
|
||||
}
|
||||
catch( Exception::BaseException& )
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
// TODO : Fix this message. It should respond according to the user's
|
||||
// currently configured recompiler.interpreter options, for example.
|
||||
|
||||
/*Msgbox::Alert(
|
||||
"The EE/IOP recompiler failed to initialize with the following error:\n\n"
|
||||
"%s"
|
||||
"\n\nThe EE/IOP interpreter will be used instead (slow!).", params
|
||||
ex.cMessage()
|
||||
);*/
|
||||
|
||||
g_Session.ForceDisableEErec = true;
|
||||
|
||||
Console::Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
recCpu.Shutdown();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
psxRec.Allocate();
|
||||
RecSuccess_IOP = true;
|
||||
}
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
Console::Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
psxRec.Shutdown();
|
||||
}
|
||||
|
||||
// hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :(
|
||||
|
||||
try
|
||||
{
|
||||
VU0micro::recAlloc();
|
||||
RecSuccess_VU0 = true;
|
||||
}
|
||||
catch( Exception::BaseException& )
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
|
||||
// TODO : Fix this message. It should respond according to the user's
|
||||
// currently configured recompiler.interpreter options, for example.
|
||||
/*
|
||||
Msgbox::Alert(
|
||||
"The VU0 recompiler failed to initialize with the following error:\n\n"
|
||||
"%s"
|
||||
"\n\nThe VU0 interpreter will be used for this session (may slow down some games).", params
|
||||
ex.cMessage()
|
||||
);
|
||||
*/
|
||||
|
||||
g_Session.ForceDisableVU0rec = true;
|
||||
Console::Error( L"VU0 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
VU0micro::recShutdown();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
VU1micro::recAlloc();
|
||||
RecSuccess_VU1 = true;
|
||||
}
|
||||
catch( Exception::BaseException& )
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
|
||||
// TODO : Fix this message. It should respond according to the user's
|
||||
// currently configured recompiler.interpreter options, for example.
|
||||
/*
|
||||
Msgbox::Alert(
|
||||
"The VU1 recompiler failed to initialize with the following error:\n\n"
|
||||
"%s"
|
||||
"\n\nThe VU1 interpreter will be used for this session (will slow down most games).", params
|
||||
ex.cMessage()
|
||||
);
|
||||
*/
|
||||
|
||||
g_Session.ForceDisableVU1rec = true;
|
||||
Console::Error( L"VU1 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
VU1micro::recShutdown();
|
||||
}
|
||||
|
||||
// If both VUrecs failed, then make sure the SuperVU is totally closed out:
|
||||
if( !CHECK_VU0REC && !CHECK_VU1REC)
|
||||
// If both VUrecs failed, then make sure the SuperVU is totally closed out, because it
|
||||
// actually initializes everything once and then shares it between both VU recs.
|
||||
if( !RecSuccess_VU0 && !RecSuccess_VU1 )
|
||||
SuperVUDestroy( -1 );
|
||||
}
|
||||
|
||||
void EmuCoreAllocations::CleanupMess() throw()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Special SuperVU "complete" terminator.
|
||||
SuperVUDestroy( -1 );
|
||||
|
||||
VU1micro::recShutdown();
|
||||
VU0micro::recShutdown();
|
||||
|
||||
psxRec.Shutdown();
|
||||
recCpu.Shutdown();
|
||||
|
||||
vuMicroMemShutdown();
|
||||
psxMemShutdown();
|
||||
memShutdown();
|
||||
vtlb_Core_Shutdown();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
|
||||
// This should be called last thing before PCSX2 exits.
|
||||
//
|
||||
void SysShutdownMem()
|
||||
EmuCoreAllocations::~EmuCoreAllocations() throw()
|
||||
{
|
||||
if( sysInitialized )
|
||||
SysShutdown();
|
||||
|
||||
vuMicroMemShutdown();
|
||||
psxMemShutdown();
|
||||
memShutdown();
|
||||
vtlb_Core_Shutdown();
|
||||
CleanupMess();
|
||||
}
|
||||
|
||||
// This should generally be called right before calling SysShutdownMem(), although you can optionally
|
||||
// use it in conjunction with SysAllocDynarecs to allocate/free the dynarec resources on the fly (as
|
||||
// risky as it might be, since dynarecs could very well fail on the second attempt).
|
||||
void SysShutdownDynarecs()
|
||||
bool EmuCoreAllocations::HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const
|
||||
{
|
||||
// Special SuperVU "complete" terminator.
|
||||
SuperVUDestroy( -1 );
|
||||
|
||||
VU0micro::recShutdown();
|
||||
VU1micro::recShutdown();
|
||||
|
||||
psxRec.Shutdown();
|
||||
recCpu.Shutdown();
|
||||
}
|
||||
|
||||
void SysShutdown()
|
||||
{
|
||||
sysInitialized = false;
|
||||
|
||||
Console::Status( "Shutting down PS2 virtual machine..." );
|
||||
SysEndExecution();
|
||||
safe_delete( g_plugins );
|
||||
|
||||
SysShutdownDynarecs();
|
||||
SysShutdownMem();
|
||||
return (recOpts.EnableEE && !RecSuccess_EE) ||
|
||||
(recOpts.EnableIOP && !RecSuccess_IOP) ||
|
||||
(recOpts.EnableVU0 && !RecSuccess_VU0) ||
|
||||
(recOpts.EnableVU1 && !RecSuccess_VU1);
|
||||
}
|
||||
|
||||
// Resets all PS2 cpu execution caches, which does not affect that actual PS2 state/condition.
|
||||
|
@ -291,63 +253,6 @@ void SysClearExecutionCache()
|
|||
vuMicroCpuReset();
|
||||
}
|
||||
|
||||
bool EmulationInProgress()
|
||||
{
|
||||
return (g_EmuThread != NULL) && g_EmuThread->IsRunning();
|
||||
}
|
||||
|
||||
// Executes the specified cdvd source and optional elf file. This command performs a
|
||||
// full closure of any existing VM state and starts a fresh VM with the requested
|
||||
// sources.
|
||||
void SysExecute( CoreEmuThread* newThread, CDVD_SourceType cdvdsrc )
|
||||
{
|
||||
wxASSERT( newThread != NULL );
|
||||
safe_delete( g_EmuThread );
|
||||
|
||||
CDVDsys_ChangeSource( cdvdsrc );
|
||||
g_EmuThread = newThread;
|
||||
g_EmuThread->Resume();
|
||||
}
|
||||
|
||||
// Executes the emulator using a saved/existing virtual machine state and currently
|
||||
// configured CDVD source device.
|
||||
// Debug assertions:
|
||||
void SysExecute( CoreEmuThread* newThread )
|
||||
{
|
||||
wxASSERT( newThread != NULL );
|
||||
safe_delete( g_EmuThread );
|
||||
|
||||
g_EmuThread = newThread;
|
||||
g_EmuThread->Resume();
|
||||
}
|
||||
|
||||
// Once execution has been ended no action can be taken on the Virtual Machine (such as
|
||||
// saving states). No assertions or exceptions.
|
||||
void SysEndExecution()
|
||||
{
|
||||
safe_delete( g_EmuThread );
|
||||
GetPluginManager().Shutdown();
|
||||
}
|
||||
|
||||
void SysSuspend()
|
||||
{
|
||||
if( g_EmuThread != NULL )
|
||||
g_EmuThread->Suspend();
|
||||
}
|
||||
|
||||
void SysResume()
|
||||
{
|
||||
if( g_EmuThread != NULL )
|
||||
g_EmuThread->Resume();
|
||||
}
|
||||
|
||||
|
||||
void SysRestorableReset()
|
||||
{
|
||||
if( !EmulationInProgress() ) return;
|
||||
StateRecovery::MakeFull();
|
||||
}
|
||||
|
||||
// The calling function should trap and handle exceptions as needed.
|
||||
// Exceptions:
|
||||
// Exception::StateLoadError - thrown when a fully recoverable exception ocurred. The
|
||||
|
@ -355,35 +260,19 @@ void SysRestorableReset()
|
|||
//
|
||||
// Any other exception means the Virtual Memory state is indeterminate and probably
|
||||
// invalid.
|
||||
void SysLoadState( const wxString& file )
|
||||
void SysLoadState( const wxString& srcfile )
|
||||
{
|
||||
SafeArray<u8> buf;
|
||||
memLoadingState joe( buf ); // this could throw n StateLoadError.
|
||||
|
||||
// we perform a full backup to memory first so that we can restore later if the
|
||||
// load fails. fixme: should this be made optional? It could have significant
|
||||
// speed impact on state loads on slower machines with low ram. >_<
|
||||
StateRecovery::MakeFull();
|
||||
|
||||
gzLoadingState joe( file ); // this'll throw an StateLoadError.
|
||||
|
||||
GetPluginManager().Open();
|
||||
cpuReset();
|
||||
SysClearExecutionCache();
|
||||
|
||||
cpuReset();
|
||||
joe.FreezeAll();
|
||||
|
||||
if( GSsetGameCRC != NULL )
|
||||
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
|
||||
}
|
||||
|
||||
void SysReset()
|
||||
{
|
||||
Console::Status( "Resetting PS2 virtual machine..." );
|
||||
|
||||
SysEndExecution();
|
||||
StateRecovery::Clear();
|
||||
ElfCRC = 0;
|
||||
|
||||
// Note : No need to call cpuReset() here. It gets called automatically before the
|
||||
// emulator resumes execution.
|
||||
}
|
||||
|
||||
// Maps a block of memory for use as a recompiled code buffer, and ensures that the
|
||||
|
@ -414,29 +303,3 @@ u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
|
|||
}
|
||||
return Mem;
|
||||
}
|
||||
|
||||
// Ensures existence of necessary folders, and performs error handling if the
|
||||
// folders fail to create.
|
||||
static void InitFolderStructure()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Returns FALSE if the core/recompiler memory allocations failed.
|
||||
bool SysInit()
|
||||
{
|
||||
if( sysInitialized ) return true;
|
||||
sysInitialized = true;
|
||||
|
||||
SysDetect();
|
||||
|
||||
PCSX2_MEM_PROTECT_BEGIN();
|
||||
Console::Status( "Initializing PS2 virtual machine..." );
|
||||
if( !SysAllocateMem() )
|
||||
return false; // critical memory allocation failure;
|
||||
|
||||
SysAllocateDynarecs();
|
||||
PCSX2_MEM_PROTECT_END();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -23,36 +23,46 @@ static const int PCSX2_VersionHi = 0;
|
|||
static const int PCSX2_VersionMid = 9;
|
||||
static const int PCSX2_VersionLo = 7;
|
||||
|
||||
|
||||
class CoreEmuThread;
|
||||
|
||||
extern bool SysInit();
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EmuCoreAllocations class
|
||||
// --------------------------------------------------------------------------------------
|
||||
class EmuCoreAllocations
|
||||
{
|
||||
public:
|
||||
// This set of booleans defaults to false and are only set TRUE if the corresponding
|
||||
// recompilers succeeded to initialize/allocate. The host application should honor
|
||||
// these booleans when selecting between recompiler or interpreter, since recompilers
|
||||
// will fail to operate if these are "false."
|
||||
|
||||
bool RecSuccess_EE:1,
|
||||
RecSuccess_IOP:1,
|
||||
RecSuccess_VU0:1,
|
||||
RecSuccess_VU1:1;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
EmuCoreAllocations();
|
||||
virtual ~EmuCoreAllocations() throw();
|
||||
|
||||
bool HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const;
|
||||
|
||||
protected:
|
||||
void CleanupMess() throw();
|
||||
};
|
||||
|
||||
|
||||
extern void SysDetect(); // Detects cpu type and fills cpuInfo structs.
|
||||
extern void SysReset(); // Resets the various PS2 cpus, sub-systems, and recompilers.
|
||||
|
||||
extern void SysExecute( CoreEmuThread* newThread );
|
||||
extern void SysExecute( CoreEmuThread* newThread, CDVD_SourceType cdvdsrc );
|
||||
extern void SysEndExecution();
|
||||
|
||||
extern void SysSuspend();
|
||||
extern void SysResume();
|
||||
|
||||
extern bool SysAllocateMem(); // allocates memory for all PS2 systems; returns FALSe on critical error.
|
||||
extern void SysAllocateDynarecs(); // allocates memory for all dynarecs, and force-disables any failures.
|
||||
extern void SysShutdownDynarecs();
|
||||
extern void SysShutdownMem();
|
||||
extern void SysShutdown();
|
||||
|
||||
extern void SysLoadState( const wxString& file );
|
||||
extern void SysRestorableReset(); // Saves the current emulation state prior to spu reset.
|
||||
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
||||
|
||||
|
||||
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
|
||||
extern void vSyncDebugStuff( uint frame );
|
||||
|
||||
extern CoreEmuThread* g_EmuThread;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
#ifdef __LINUX__
|
||||
|
|
|
@ -138,7 +138,7 @@ void vuMicroMemReset()
|
|||
VU1.vifRegs = vif1Regs;
|
||||
}
|
||||
|
||||
void SaveState::vuMicroFreeze()
|
||||
void SaveStateBase::vuMicroFreeze()
|
||||
{
|
||||
FreezeTag( "vuMicro" );
|
||||
|
||||
|
|
|
@ -1658,7 +1658,7 @@ void vif0Reset()
|
|||
vif0Regs->stat &= ~VIF0_STAT_FQC; // FQC=0
|
||||
}
|
||||
|
||||
void SaveState::vif0Freeze()
|
||||
void SaveStateBase::vif0Freeze()
|
||||
{
|
||||
FreezeTag("VIFdma");
|
||||
|
||||
|
@ -2803,7 +2803,7 @@ void vif1Reset()
|
|||
vif1Regs->stat &= ~VIF1_STAT_FQC; // FQC=0
|
||||
}
|
||||
|
||||
void SaveState::vif1Freeze()
|
||||
void SaveStateBase::vif1Freeze()
|
||||
{
|
||||
Freeze(vif1);
|
||||
|
||||
|
|
160
pcsx2/gui/App.h
160
pcsx2/gui/App.h
|
@ -30,6 +30,12 @@
|
|||
class IniInterface;
|
||||
|
||||
|
||||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
DECLARE_EVENT_TYPE( pxEVT_SemaphorePing, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_OpenModalDialog, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// All Menu Options for the Main Window! :D
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -119,6 +125,14 @@ enum MenuIdentifiers
|
|||
MenuId_Debug_Usermode,
|
||||
};
|
||||
|
||||
enum DialogIdentifiers
|
||||
{
|
||||
DialogId_CoreSettings = 0x800,
|
||||
DialogId_BiosSelector,
|
||||
DialogId_LogOptions,
|
||||
DialogId_About,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ScopedWindowDisable
|
||||
//
|
||||
|
@ -197,53 +211,89 @@ struct AppImageIds
|
|||
} Toolbars;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
class pxAppTraits : public wxGUIAppTraits
|
||||
|
||||
struct MsgboxEventResult
|
||||
{
|
||||
#ifdef __WXDEBUG__
|
||||
public:
|
||||
virtual bool ShowAssertDialog(const wxString& msg);
|
||||
|
||||
protected:
|
||||
virtual wxString GetAssertStackTrace();
|
||||
#endif
|
||||
Semaphore WaitForMe;
|
||||
int result;
|
||||
|
||||
MsgboxEventResult() :
|
||||
WaitForMe(), result( 0 )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Pcsx2App - main wxApp class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
class Pcsx2App : public wxApp
|
||||
{
|
||||
protected:
|
||||
wxImageList m_ConfigImages;
|
||||
|
||||
wxScopedPtr<wxImageList> m_ToolbarImages;
|
||||
wxScopedPtr<wxBitmap> m_Bitmap_Logo;
|
||||
|
||||
wxScopedPtr<EmuCoreAllocations> m_CoreAllocs;
|
||||
|
||||
public:
|
||||
wxScopedPtr<PluginManager> m_CorePlugins;
|
||||
wxScopedPtr<CoreEmuThread> m_CoreThread;
|
||||
|
||||
protected:
|
||||
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
|
||||
// of these objects internally.
|
||||
MainEmuFrame* m_MainFrame;
|
||||
ConsoleLogFrame* m_ProgramLogBox;
|
||||
wxBitmap* m_Bitmap_Logo;
|
||||
|
||||
wxImageList m_ConfigImages;
|
||||
bool m_ConfigImagesAreLoaded;
|
||||
|
||||
wxImageList* m_ToolbarImages; // dynamic (pointer) to allow for large/small redefinition.
|
||||
AppImageIds m_ImageId;
|
||||
bool m_ConfigImagesAreLoaded;
|
||||
AppImageIds m_ImageId;
|
||||
|
||||
public:
|
||||
Pcsx2App();
|
||||
virtual ~Pcsx2App();
|
||||
|
||||
wxFrame* GetMainWindow() const;
|
||||
void ReloadPlugins();
|
||||
|
||||
bool OnInit();
|
||||
int OnExit();
|
||||
void CleanUp();
|
||||
void ApplySettings( const AppConfig* oldconf = NULL );
|
||||
void LoadSettings();
|
||||
void SaveSettings();
|
||||
|
||||
void PostMenuAction( MenuIdentifiers menu_id ) const;
|
||||
int ThreadedModalDialog( DialogIdentifiers dialogId );
|
||||
void Ping() const;
|
||||
|
||||
void OnInitCmdLine( wxCmdLineParser& parser );
|
||||
bool OnCmdLineParsed( wxCmdLineParser& parser );
|
||||
bool OnCmdLineError( wxCmdLineParser& parser );
|
||||
bool PrepForExit();
|
||||
|
||||
// Executes the emulator using a saved/existing virtual machine state and currently
|
||||
// configured CDVD source device.
|
||||
// Debug assertions:
|
||||
void SysExecute();
|
||||
void SysExecute( CDVD_SourceType cdvdsrc );
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
void OnAssertFailure( const wxChar *file, int line, const wxChar *func, const wxChar *cond, const wxChar *msg );
|
||||
#endif
|
||||
void SysResume()
|
||||
{
|
||||
if( !m_CoreThread ) return;
|
||||
m_CoreThread->Resume();
|
||||
}
|
||||
|
||||
void SysSuspend()
|
||||
{
|
||||
if( !m_CoreThread ) return;
|
||||
m_CoreThread->Suspend();
|
||||
}
|
||||
|
||||
void SysReset()
|
||||
{
|
||||
m_CoreThread.reset();
|
||||
m_CorePlugins.reset();
|
||||
}
|
||||
|
||||
bool EmuInProgress() const
|
||||
{
|
||||
return m_CoreThread && m_CoreThread->IsRunning();
|
||||
}
|
||||
|
||||
const wxBitmap& GetLogoBitmap();
|
||||
wxImageList& GetImgList_Config();
|
||||
|
@ -253,16 +303,24 @@ public:
|
|||
|
||||
MainEmuFrame& GetMainFrame() const
|
||||
{
|
||||
wxASSERT( ((uptr)GetTopWindow()) == ((uptr)m_MainFrame) );
|
||||
wxASSERT( m_MainFrame != NULL );
|
||||
return *m_MainFrame;
|
||||
}
|
||||
|
||||
void PostMenuAction( MenuIdentifiers menu_id ) const;
|
||||
void Ping() const;
|
||||
// --------------------------------------------------------------------------
|
||||
// Overrides of wxApp virtuals:
|
||||
// --------------------------------------------------------------------------
|
||||
bool OnInit();
|
||||
int OnExit();
|
||||
|
||||
void ApplySettings( const AppConfig& newconf );
|
||||
void LoadSettings();
|
||||
void SaveSettings();
|
||||
void OnInitCmdLine( wxCmdLineParser& parser );
|
||||
bool OnCmdLineParsed( wxCmdLineParser& parser );
|
||||
bool OnCmdLineError( wxCmdLineParser& parser );
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
void OnAssertFailure( const wxChar *file, int line, const wxChar *func, const wxChar *cond, const wxChar *msg );
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Console / Program Logging Helpers
|
||||
|
@ -303,7 +361,9 @@ protected:
|
|||
|
||||
void HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent& event) const;
|
||||
|
||||
void OnReloadPlugins( wxCommandEvent& evt );
|
||||
void OnSemaphorePing( wxCommandEvent& evt );
|
||||
void OnOpenModalDialog( wxCommandEvent& evt );
|
||||
void OnMessageBox( pxMessageBoxEvent& evt );
|
||||
void OnEmuKeyDown( wxKeyEvent& evt );
|
||||
|
||||
|
@ -322,15 +382,18 @@ protected:
|
|||
void OnUnhandledException() { throw; }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppEmuThread class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
class AppEmuThread : public CoreEmuThread
|
||||
{
|
||||
protected:
|
||||
wxKeyEvent m_kevt;
|
||||
|
||||
public:
|
||||
AppEmuThread();
|
||||
AppEmuThread( PluginManager& plugins );
|
||||
virtual ~AppEmuThread() { }
|
||||
|
||||
virtual void Resume();
|
||||
|
@ -340,14 +403,29 @@ protected:
|
|||
sptr ExecuteTask();
|
||||
};
|
||||
|
||||
|
||||
|
||||
DECLARE_APP(Pcsx2App)
|
||||
|
||||
class EntryGuard
|
||||
{
|
||||
public:
|
||||
int& Counter;
|
||||
EntryGuard( int& counter ) : Counter( counter )
|
||||
{ ++Counter; }
|
||||
|
||||
virtual ~EntryGuard() throw()
|
||||
{ --Counter; }
|
||||
|
||||
bool IsReentrant() const { return Counter > 1; }
|
||||
};
|
||||
|
||||
extern int EnumeratePluginsInFolder( const wxDirName& searchPath, wxArrayString* dest );
|
||||
extern void LoadPlugins();
|
||||
extern void InitPlugins();
|
||||
extern void OpenPlugins();
|
||||
extern void LoadPluginsPassive();
|
||||
extern void LoadPluginsImmediate();
|
||||
extern void UnloadPlugins();
|
||||
|
||||
extern wxRect wxGetDisplayArea();
|
||||
extern bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos );
|
||||
|
||||
extern bool HandlePluginError( Exception::PluginError& ex );
|
||||
extern bool EmulationInProgress();
|
||||
|
||||
|
|
|
@ -68,10 +68,6 @@ static wxString pxGetStackTrace()
|
|||
static __threadlocal bool _reentrant_lock = false;
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
wxString pxAppTraits::GetAssertStackTrace()
|
||||
{
|
||||
return pxGetStackTrace();
|
||||
}
|
||||
|
||||
// This override of wx's implementation provides thread safe assertion message reporting. If we aren't
|
||||
// on the main gui thread then the assertion message box needs to be passed off to the main gui thread
|
||||
|
@ -101,8 +97,8 @@ void Pcsx2App::OnAssertFailure( const wxChar *file, int line, const wxChar *func
|
|||
// make life easier for people using VC++ IDE by using this format, which allows double-click
|
||||
// response times from the Output window...
|
||||
dbgmsg.Printf( L"%s(%d) : assertion failed%s%s: %s", file, line,
|
||||
(func==NULL) ? L"" : L" in ",
|
||||
(func==NULL) ? L"" : func,
|
||||
(func==NULL) ? wxEmptyString : L" in ",
|
||||
(func==NULL) ? wxEmptyString : func,
|
||||
message.c_str()
|
||||
);
|
||||
|
||||
|
|
|
@ -94,7 +94,10 @@ namespace PathDefs
|
|||
// share with other programs: screenshots, memory cards, and savestates.
|
||||
wxDirName GetDocuments()
|
||||
{
|
||||
return (wxDirName)g_Conf->GetDefaultDocumentsFolder();
|
||||
if( UseAdminMode )
|
||||
return (wxDirName)wxGetCwd();
|
||||
else
|
||||
return (wxDirName)Path::Combine( wxStandardPaths::Get().GetDocumentsDir(), wxGetApp().GetAppName() );
|
||||
}
|
||||
|
||||
wxDirName GetSnapshots()
|
||||
|
@ -155,20 +158,12 @@ namespace PathDefs
|
|||
}
|
||||
};
|
||||
|
||||
wxString AppConfig::GetDefaultDocumentsFolder()
|
||||
{
|
||||
if( UseAdminMode )
|
||||
return wxGetCwd();
|
||||
else
|
||||
return Path::Combine( wxStandardPaths::Get().GetDocumentsDir(), wxGetApp().GetAppName() );
|
||||
}
|
||||
|
||||
const wxDirName& AppConfig::FolderOptions::operator[]( FoldersEnum_t folderidx ) const
|
||||
{
|
||||
switch( folderidx )
|
||||
{
|
||||
case FolderId_Plugins: return Plugins;
|
||||
case FolderId_Settings: return Settings;
|
||||
case FolderId_Settings: return SettingsFolder;
|
||||
case FolderId_Bios: return Bios;
|
||||
case FolderId_Snapshots: return Snapshots;
|
||||
case FolderId_Savestates: return Savestates;
|
||||
|
@ -185,7 +180,7 @@ const bool AppConfig::FolderOptions::IsDefault( FoldersEnum_t folderidx ) const
|
|||
switch( folderidx )
|
||||
{
|
||||
case FolderId_Plugins: return UseDefaultPlugins;
|
||||
case FolderId_Settings: return UseDefaultSettings;
|
||||
case FolderId_Settings: return UseDefaultSettingsFolder;
|
||||
case FolderId_Bios: return UseDefaultBios;
|
||||
case FolderId_Snapshots: return UseDefaultSnapshots;
|
||||
case FolderId_Savestates: return UseDefaultSavestates;
|
||||
|
@ -207,8 +202,8 @@ void AppConfig::FolderOptions::Set( FoldersEnum_t folderidx, const wxString& src
|
|||
break;
|
||||
|
||||
case FolderId_Settings:
|
||||
Settings = src;
|
||||
UseDefaultSettings = useDefault;
|
||||
SettingsFolder = src;
|
||||
UseDefaultSettingsFolder = useDefault;
|
||||
break;
|
||||
|
||||
case FolderId_Bios:
|
||||
|
@ -240,8 +235,9 @@ void AppConfig::FolderOptions::Set( FoldersEnum_t folderidx, const wxString& src
|
|||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Default Filenames
|
||||
// --------------------------------------------------------------------------------------
|
||||
namespace FilenameDefs
|
||||
{
|
||||
wxFileName GetConfig()
|
||||
|
@ -290,9 +286,14 @@ wxString AppConfig::FullpathTo( PluginsEnum_t pluginidx ) const
|
|||
return Path::Combine( Folders.Plugins, BaseFilenames[pluginidx] );
|
||||
}
|
||||
|
||||
wxString AppConfig::FullPathToConfig() const
|
||||
wxDirName GetSettingsFolder()
|
||||
{
|
||||
return g_Conf->Folders.Settings.Combine( FilenameDefs::GetConfig() ).GetFullPath();
|
||||
return UseDefaultSettingsFolder ? PathDefs::GetSettings() : SettingsFolder;
|
||||
}
|
||||
|
||||
wxString GetSettingsFilename()
|
||||
{
|
||||
return GetSettingsFolder().Combine( FilenameDefs::GetConfig() ).GetFullPath();
|
||||
}
|
||||
|
||||
|
||||
|
@ -349,7 +350,8 @@ void AppConfig::LoadSaveUserMode( IniInterface& ini, const wxString& cwdhash )
|
|||
ini.GetConfig().Write( L"Timestamp", timestamp_now );*/
|
||||
|
||||
ini.Entry( L"UseAdminMode", UseAdminMode, false );
|
||||
ini.Entry( L"SettingsPath", Folders.Settings, PathDefs::GetSettings() );
|
||||
ini.Entry( L"UseDefaultSettingsFolder", UseDefaultSettingsFolder, true );
|
||||
ini.Entry( L"SettingsFolder", SettingsFolder, PathDefs::GetSettings() );
|
||||
|
||||
ini.Flush();
|
||||
}
|
||||
|
@ -404,40 +406,6 @@ void AppConfig::LoadSave( IniInterface& ini )
|
|||
ini.Flush();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Performs necessary operations to ensure that the current g_Conf settings (and other config-stored
|
||||
// globals) are applied to the pcsx2 main window and primary emulation subsystems (if active).
|
||||
//
|
||||
void AppConfig::Apply()
|
||||
{
|
||||
Folders.ApplyDefaults();
|
||||
|
||||
// Ensure existence of necessary documents folders. Plugins and other parts
|
||||
// of PCSX2 rely on them.
|
||||
|
||||
Folders.MemoryCards.Mkdir();
|
||||
Folders.Savestates.Mkdir();
|
||||
Folders.Snapshots.Mkdir();
|
||||
|
||||
EmuOptions.BiosFilename = FullpathToBios();
|
||||
|
||||
// Update the compression attribute on the Memcards folder.
|
||||
// Memcards generally compress very well via NTFS compression.
|
||||
|
||||
NTFS_CompressFile( Folders.MemoryCards.ToString(), McdEnableNTFS );
|
||||
|
||||
{
|
||||
wxDoNotLogInThisScope please;
|
||||
if( !i18n_SetLanguage( LanguageId ) )
|
||||
{
|
||||
if( !i18n_SetLanguage( wxLANGUAGE_DEFAULT ) )
|
||||
{
|
||||
i18n_SetLanguage( wxLANGUAGE_ENGLISH );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
AppConfig::ConsoleLogOptions::ConsoleLogOptions() :
|
||||
Visible( false )
|
||||
|
@ -463,7 +431,6 @@ void AppConfig::ConsoleLogOptions::LoadSave( IniInterface& ini, const wxChar* lo
|
|||
void AppConfig::FolderOptions::ApplyDefaults()
|
||||
{
|
||||
if( UseDefaultPlugins ) Plugins = PathDefs::GetPlugins();
|
||||
if( UseDefaultSettings ) Settings = PathDefs::GetSettings();
|
||||
if( UseDefaultBios ) Bios = PathDefs::GetBios();
|
||||
if( UseDefaultSnapshots ) Snapshots = PathDefs::GetSnapshots();
|
||||
if( UseDefaultSavestates ) Savestates = PathDefs::GetSavestates();
|
||||
|
@ -475,7 +442,6 @@ void AppConfig::FolderOptions::ApplyDefaults()
|
|||
AppConfig::FolderOptions::FolderOptions() :
|
||||
bitset( 0xffffffff )
|
||||
, Plugins( PathDefs::GetPlugins() )
|
||||
, Settings( PathDefs::GetSettings() )
|
||||
, Bios( PathDefs::GetBios() )
|
||||
, Snapshots( PathDefs::GetSnapshots() )
|
||||
, Savestates( PathDefs::GetSavestates() )
|
||||
|
@ -503,7 +469,6 @@ void AppConfig::FolderOptions::LoadSave( IniInterface& ini )
|
|||
IniBitBool( UseDefaultLogs );
|
||||
|
||||
IniEntry( Plugins );
|
||||
IniEntry( Settings );
|
||||
IniEntry( Bios );
|
||||
IniEntry( Snapshots );
|
||||
IniEntry( Savestates );
|
||||
|
@ -552,13 +517,13 @@ void AppConfig_ReloadGlobalSettings( bool overwrite )
|
|||
PathDefs::GetSettings().Mkdir();
|
||||
|
||||
// Allow wx to use our config, and enforces auto-cleanup as well
|
||||
delete wxConfigBase::Set( OpenFileConfig( g_Conf->FullPathToConfig() ) );
|
||||
delete wxConfigBase::Set( OpenFileConfig( GetSettingsFilename() ) );
|
||||
wxConfigBase::Get()->SetRecordDefaults();
|
||||
|
||||
if( !overwrite )
|
||||
wxGetApp().LoadSettings();
|
||||
|
||||
wxGetApp().ApplySettings( *g_Conf );
|
||||
wxGetApp().ApplySettings();
|
||||
g_Conf->Folders.Logs.Mkdir();
|
||||
|
||||
wxString newlogname( Path::Combine( g_Conf->Folders.Logs.ToString(), L"emuLog.txt" ) );
|
||||
|
|
|
@ -21,7 +21,12 @@
|
|||
class IniInterface;
|
||||
class wxFileConfig;
|
||||
|
||||
extern bool UseAdminMode; // dictates if the program uses /home/user or /cwd for the program data
|
||||
extern bool UseAdminMode; // dictates if the program uses /home/user or /cwd for the program data
|
||||
extern wxDirName SettingsFolder; // dictates where the settings folder comes from, *if* UseDefaultSettingsFolder is FALSE.
|
||||
extern bool UseDefaultSettingsFolder; // when TRUE, pcsx2 derives the settings folder from the UseAdminMode
|
||||
|
||||
wxDirName GetSettingsFolder();
|
||||
wxString GetSettingsFilename();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Pcsx2 Application Configuration.
|
||||
|
@ -33,15 +38,15 @@ public:
|
|||
// ------------------------------------------------------------------------
|
||||
struct ConsoleLogOptions
|
||||
{
|
||||
bool Visible;
|
||||
bool Visible;
|
||||
// if true, DisplayPos is ignored and the console is automatically docked to the main window.
|
||||
bool AutoDock;
|
||||
bool AutoDock;
|
||||
// Display position used if AutoDock is false (ignored otherwise)
|
||||
wxPoint DisplayPosition;
|
||||
wxSize DisplaySize;
|
||||
wxPoint DisplayPosition;
|
||||
wxSize DisplaySize;
|
||||
|
||||
// Size of the font in points.
|
||||
int FontSize;
|
||||
int FontSize;
|
||||
|
||||
ConsoleLogOptions();
|
||||
void LoadSave( IniInterface& conf, const wxChar* title );
|
||||
|
@ -59,11 +64,10 @@ public:
|
|||
UseDefaultSavestates:1,
|
||||
UseDefaultMemoryCards:1,
|
||||
UseDefaultLogs:1;
|
||||
}; };
|
||||
BITFIELD_END
|
||||
|
||||
wxDirName
|
||||
Plugins,
|
||||
Settings,
|
||||
Bios,
|
||||
Snapshots,
|
||||
Savestates,
|
||||
|
@ -156,14 +160,10 @@ public:
|
|||
wxString FullpathToBios() const;
|
||||
wxString FullpathToMcd( uint port, uint slot ) const;
|
||||
wxString FullpathTo( PluginsEnum_t pluginId ) const;
|
||||
wxString FullPathToConfig() const;
|
||||
|
||||
void LoadSaveUserMode( IniInterface& ini, const wxString& cwdhash );
|
||||
|
||||
wxString GetDefaultDocumentsFolder();
|
||||
|
||||
protected:
|
||||
void Apply();
|
||||
void LoadSave( IniInterface& ini );
|
||||
void LoadSaveMemcards( IniInterface& ini );
|
||||
|
||||
|
@ -181,4 +181,4 @@ extern ConfigOverrides OverrideOptions;
|
|||
extern wxFileConfig* OpenFileConfig( const wxString& filename );
|
||||
extern void AppConfig_ReloadGlobalSettings( bool overwrite = false );
|
||||
|
||||
extern AppConfig* g_Conf;
|
||||
extern wxScopedPtr<AppConfig> g_Conf;
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#include "Plugins.h"
|
||||
|
||||
#include "Dialogs/ModalPopups.h"
|
||||
#include "Dialogs/ConfigurationDialog.h"
|
||||
#include "Dialogs/LogOptionsDialog.h"
|
||||
|
||||
#include "Utilities/ScopedPtr.h"
|
||||
#include "Utilities/HashMap.h"
|
||||
|
||||
|
@ -28,15 +31,16 @@
|
|||
|
||||
IMPLEMENT_APP(Pcsx2App)
|
||||
|
||||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
DECLARE_EVENT_TYPE( pxEVT_SemaphorePing, -1 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
DEFINE_EVENT_TYPE( pxEVT_SemaphorePing );
|
||||
DEFINE_EVENT_TYPE( pxEVT_OpenModalDialog );
|
||||
DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins );
|
||||
|
||||
DEFINE_EVENT_TYPE( pxEVT_SemaphorePing )
|
||||
bool UseAdminMode = false;
|
||||
wxDirName SettingsFolder;
|
||||
bool UseDefaultSettingsFolder = true;
|
||||
|
||||
bool UseAdminMode = false;
|
||||
AppConfig* g_Conf = NULL;
|
||||
ConfigOverrides OverrideOptions;
|
||||
wxScopedPtr<AppConfig> g_Conf;
|
||||
ConfigOverrides OverrideOptions;
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
|
@ -57,8 +61,8 @@ namespace Exception
|
|||
};
|
||||
}
|
||||
|
||||
AppEmuThread::AppEmuThread() :
|
||||
CoreEmuThread()
|
||||
AppEmuThread::AppEmuThread( PluginManager& plugins ) :
|
||||
CoreEmuThread( plugins )
|
||||
, m_kevt()
|
||||
{
|
||||
}
|
||||
|
@ -127,19 +131,50 @@ void AppEmuThread::StateCheck()
|
|||
}
|
||||
}
|
||||
|
||||
static bool HandlePluginError( Exception::PluginError& ex )
|
||||
// Executes the emulator using a saved/existing virtual machine state and currently
|
||||
// configured CDVD source device.
|
||||
void Pcsx2App::SysExecute()
|
||||
{
|
||||
SysReset();
|
||||
LoadPluginsImmediate();
|
||||
m_CoreThread.reset( new AppEmuThread( *m_CorePlugins ) );
|
||||
m_CoreThread->Resume();
|
||||
}
|
||||
|
||||
// Executes the specified cdvd source and optional elf file. This command performs a
|
||||
// full closure of any existing VM state and starts a fresh VM with the requested
|
||||
// sources.
|
||||
void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc )
|
||||
{
|
||||
SysReset();
|
||||
LoadPluginsImmediate();
|
||||
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
||||
CDVDsys_ChangeSource( cdvdsrc );
|
||||
m_CoreThread.reset( new AppEmuThread( *m_CorePlugins ) );
|
||||
m_CoreThread->Resume();
|
||||
}
|
||||
|
||||
__forceinline bool EmulationInProgress()
|
||||
{
|
||||
return wxGetApp().EmuInProgress();
|
||||
}
|
||||
|
||||
|
||||
bool HandlePluginError( Exception::PluginError& ex )
|
||||
{
|
||||
if( pxDialogExists( DialogId_CoreSettings ) ) return true;
|
||||
|
||||
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
||||
_("\n\nPress Ok to go to the Plugin Configuration Panel.") );
|
||||
_("\n\nPress Ok to go to the Plugin Configuration Panel.")
|
||||
);
|
||||
|
||||
if( result )
|
||||
{
|
||||
g_Conf->SettingsTabName = L"Plugins";
|
||||
wxGetApp().PostMenuAction( MenuId_Config_Settings );
|
||||
wxGetApp().Ping();
|
||||
|
||||
// fixme: Send a message to the panel to select the failed plugin.
|
||||
// fixme: handle case where user cancels the settings dialog. (should return FALSE).
|
||||
if( Dialogs::ConfigurationDialog().ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -162,11 +197,14 @@ sptr AppEmuThread::ExecuteTask()
|
|||
|
||||
if( result )
|
||||
{
|
||||
wxGetApp().PostMenuAction( MenuId_Config_BIOS );
|
||||
wxGetApp().Ping();
|
||||
|
||||
// fixme: handle case where user cancels the settings dialog. (should return FALSE).
|
||||
// fixme: automatically re-try emu startup here...
|
||||
if( wxGetApp().ThreadedModalDialog( DialogId_BiosSelector ) == wxID_CANCEL )
|
||||
{
|
||||
// fixme: handle case where user cancels the settings dialog. (should return FALSE).
|
||||
}
|
||||
else
|
||||
{
|
||||
// fixme: automatically re-try emu startup here...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,10 +212,13 @@ sptr AppEmuThread::ExecuteTask()
|
|||
catch( Exception::PluginError& ex )
|
||||
{
|
||||
GetPluginManager().Close();
|
||||
if( HandlePluginError( ex ) )
|
||||
Console::Error( ex.FormatDiagnosticMessage() );
|
||||
Msgbox::Alert( ex.FormatDisplayMessage(), _("Plugin Open Error") );
|
||||
|
||||
/*if( HandlePluginError( ex ) )
|
||||
{
|
||||
// fixme: automatically re-try emu startup here...
|
||||
}
|
||||
}*/
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// [TODO] : Add exception handling here for debuggable PS2 exceptions that allows
|
||||
|
@ -194,8 +235,6 @@ sptr AppEmuThread::ExecuteTask()
|
|||
}
|
||||
|
||||
|
||||
wxFrame* Pcsx2App::GetMainWindow() const { return m_MainFrame; }
|
||||
|
||||
void Pcsx2App::OpenWizardConsole()
|
||||
{
|
||||
if( !IsDebugBuild ) return;
|
||||
|
@ -254,7 +293,7 @@ void Pcsx2App::ReadUserModeSettings()
|
|||
IniLoader loader( *conf_usermode );
|
||||
g_Conf->LoadSaveUserMode( loader, groupname );
|
||||
|
||||
if( !wxFile::Exists( g_Conf->FullPathToConfig() ) )
|
||||
if( !wxFile::Exists( GetSettingsFilename() ) )
|
||||
{
|
||||
// user wiped their pcsx2.ini -- needs a reconfiguration via wizard!
|
||||
// (we skip the first page since it's a usermode.ini thing)
|
||||
|
@ -361,7 +400,7 @@ bool Pcsx2App::OnInit()
|
|||
wxInitAllImageHandlers();
|
||||
if( !wxApp::OnInit() ) return false;
|
||||
|
||||
g_Conf = new AppConfig();
|
||||
g_Conf.reset( new AppConfig() );
|
||||
|
||||
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
||||
|
||||
|
@ -371,6 +410,8 @@ bool Pcsx2App::OnInit()
|
|||
Connect( pxEVT_MSGBOX, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) );
|
||||
Connect( pxEVT_CallStackBox, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) );
|
||||
Connect( pxEVT_SemaphorePing, wxCommandEventHandler( Pcsx2App::OnSemaphorePing ) );
|
||||
Connect( pxEVT_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
||||
Connect( pxEVT_ReloadPlugins, wxCommandEventHandler( Pcsx2App::OnReloadPlugins ) );
|
||||
|
||||
Connect( pxID_Window_GS, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
|
||||
|
||||
|
@ -406,9 +447,51 @@ bool Pcsx2App::OnInit()
|
|||
SetExitOnFrameDelete( true ); // but being explicit doesn't hurt...
|
||||
m_MainFrame->Show();
|
||||
|
||||
SysInit();
|
||||
ApplySettings( *g_Conf );
|
||||
InitPlugins();
|
||||
SysDetect();
|
||||
ApplySettings();
|
||||
|
||||
m_CoreAllocs.reset( new EmuCoreAllocations() );
|
||||
|
||||
if( m_CoreAllocs->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
|
||||
{
|
||||
wxString message( _("The following cpu recompilers failed to initialize and will not be available:\n\n") );
|
||||
|
||||
if( !m_CoreAllocs->RecSuccess_EE )
|
||||
{
|
||||
message += L"\t* R5900 (EE)\n";
|
||||
g_Session.ForceDisableEErec = true;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->RecSuccess_IOP )
|
||||
{
|
||||
message += L"\t* R3000A (IOP)\n";
|
||||
g_Session.ForceDisableIOPrec = true;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->RecSuccess_VU0 )
|
||||
{
|
||||
message += L"\t* VU0\n";
|
||||
g_Session.ForceDisableVU0rec = true;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->RecSuccess_VU1 )
|
||||
{
|
||||
message += L"\t* VU1\n";
|
||||
g_Session.ForceDisableVU1rec = true;
|
||||
}
|
||||
|
||||
message += pxE( ".Popup Error:EmuCore:MemoryForRecs",
|
||||
L"These errors are the result of memory allocation failures (see the program log for details). "
|
||||
L"Closing out some memory hogging background tasks may resolve this error.\n\n"
|
||||
L"These recompilers have been disabled and interpreters will be used in their place. "
|
||||
L"Interpreters can be very slow, so don't get too excited. Press OK to continue or CANCEL to close PCSX2."
|
||||
);
|
||||
|
||||
if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadPluginsPassive();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::StartupAborted& ex )
|
||||
|
@ -417,10 +500,16 @@ bool Pcsx2App::OnInit()
|
|||
return false;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::PluginError& ex )
|
||||
// Failures on the core initialization procedure (typically OutOfMemory errors) are bad,
|
||||
// since it means the emulator is completely non-functional. Let's pop up an error and
|
||||
// exit gracefully-ish.
|
||||
//
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
if( !HandlePluginError( ex ) )
|
||||
return false;
|
||||
Console::Error( ex.FormatDiagnosticMessage() );
|
||||
Msgbox::Alert( ex.FormatDisplayMessage() + L"\n\nPress OK to close PCSX2.",
|
||||
_("PCSX2 Critical Error"), wxICON_ERROR );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -433,11 +522,27 @@ void Pcsx2App::PostMenuAction( MenuIdentifiers menu_id ) const
|
|||
if( m_MainFrame == NULL ) return;
|
||||
|
||||
wxCommandEvent joe( wxEVT_COMMAND_MENU_SELECTED, menu_id );
|
||||
m_MainFrame->GetEventHandler()->AddPendingEvent( joe );
|
||||
if( wxThread::IsMain() )
|
||||
m_MainFrame->GetEventHandler()->ProcessEvent( joe );
|
||||
else
|
||||
m_MainFrame->GetEventHandler()->AddPendingEvent( joe );
|
||||
}
|
||||
|
||||
int Pcsx2App::ThreadedModalDialog( DialogIdentifiers dialogId )
|
||||
{
|
||||
wxASSERT( !wxThread::IsMain() ); // don't call me from MainThread!
|
||||
|
||||
MsgboxEventResult result;
|
||||
wxCommandEvent joe( pxEVT_OpenModalDialog, dialogId );
|
||||
joe.SetClientData( &result );
|
||||
AddPendingEvent( joe );
|
||||
result.WaitForMe.WaitNoCancel();
|
||||
return result.result;
|
||||
}
|
||||
|
||||
// Waits for the main GUI thread to respond. If run from the main GUI thread, returns
|
||||
// immediately without error.
|
||||
// immediately without error. Use this on non-GUI threads to have them sleep until
|
||||
// the GUI has processed all its pending messages.
|
||||
void Pcsx2App::Ping() const
|
||||
{
|
||||
if( wxThread::IsMain() ) return;
|
||||
|
@ -458,6 +563,53 @@ void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt )
|
|||
((Semaphore*)evt.GetClientData())->Post();
|
||||
}
|
||||
|
||||
void Pcsx2App::OnOpenModalDialog( wxCommandEvent& evt )
|
||||
{
|
||||
using namespace Dialogs;
|
||||
|
||||
MsgboxEventResult& evtres( *((MsgboxEventResult*)evt.GetClientData()) );
|
||||
switch( evt.GetId() )
|
||||
{
|
||||
case DialogId_CoreSettings:
|
||||
{
|
||||
static int _guard = 0;
|
||||
EntryGuard guard( _guard );
|
||||
if( guard.IsReentrant() ) return;
|
||||
evtres.result = ConfigurationDialog().ShowModal();
|
||||
}
|
||||
break;
|
||||
|
||||
case DialogId_BiosSelector:
|
||||
{
|
||||
static int _guard = 0;
|
||||
EntryGuard guard( _guard );
|
||||
if( guard.IsReentrant() ) return;
|
||||
evtres.result = BiosSelectorDialog().ShowModal();
|
||||
}
|
||||
break;
|
||||
|
||||
case DialogId_LogOptions:
|
||||
{
|
||||
static int _guard = 0;
|
||||
EntryGuard guard( _guard );
|
||||
if( guard.IsReentrant() ) return;
|
||||
evtres.result = LogOptionsDialog().ShowModal();
|
||||
}
|
||||
break;
|
||||
|
||||
case DialogId_About:
|
||||
{
|
||||
static int _guard = 0;
|
||||
EntryGuard guard( _guard );
|
||||
if( guard.IsReentrant() ) return;
|
||||
evtres.result = AboutBoxDialog().ShowModal();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
evtres.WaitForMe.Post();
|
||||
}
|
||||
|
||||
void Pcsx2App::OnMessageBox( pxMessageBoxEvent& evt )
|
||||
{
|
||||
Msgbox::OnEvent( evt );
|
||||
|
@ -467,16 +619,9 @@ void Pcsx2App::OnMessageBox( pxMessageBoxEvent& evt )
|
|||
|
||||
void Pcsx2App::CleanupMess()
|
||||
{
|
||||
safe_delete( m_Bitmap_Logo );
|
||||
safe_delete( g_Conf );
|
||||
}
|
||||
|
||||
// This cleanup procedure is issued by wxWidgets prior to destroying base windows and window
|
||||
// classes.
|
||||
void Pcsx2App::CleanUp()
|
||||
{
|
||||
SysShutdown();
|
||||
wxApp::CleanUp();
|
||||
m_CorePlugins.reset();
|
||||
m_ProgramLogBox = NULL;
|
||||
m_MainFrame = NULL;
|
||||
}
|
||||
|
||||
void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent& event) const
|
||||
|
@ -489,7 +634,11 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
|
|||
catch( Exception::PluginError& ex )
|
||||
{
|
||||
Console::Error( ex.FormatDiagnosticMessage() );
|
||||
Msgbox::Alert( ex.FormatDisplayMessage() );
|
||||
if( !HandlePluginError( ex ) )
|
||||
{
|
||||
Console::Error( L"User-canceled plugin configuration after load failure. Plugins not loaded!" );
|
||||
Msgbox::Alert( _("Warning! Plugins have not been loaded. PCSX2 will be inoperable.") );
|
||||
}
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::RuntimeError& ex )
|
||||
|
@ -505,15 +654,15 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
|
|||
|
||||
// Common exit handler which can be called from any event (though really it should
|
||||
// be called only from CloseWindow handlers since that's the more appropriate way
|
||||
// to handle window closures)
|
||||
// to handle cancelable window closures)
|
||||
//
|
||||
// returns true if the app can close, or false if the close event was canceled by
|
||||
// the glorious user, whomever (s)he-it might be.
|
||||
bool Pcsx2App::PrepForExit()
|
||||
{
|
||||
SysShutdown();
|
||||
m_CoreThread.reset();
|
||||
CleanupMess();
|
||||
|
||||
m_ProgramLogBox = NULL;
|
||||
m_MainFrame = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -521,9 +670,12 @@ int Pcsx2App::OnExit()
|
|||
{
|
||||
PrepForExit();
|
||||
|
||||
if( g_Conf != NULL )
|
||||
if( g_Conf )
|
||||
SaveSettings();
|
||||
|
||||
while( wxGetLocale() != NULL )
|
||||
delete wxGetLocale();
|
||||
|
||||
return wxApp::OnExit();
|
||||
}
|
||||
|
||||
|
@ -540,47 +692,48 @@ Pcsx2App::Pcsx2App() :
|
|||
|
||||
Pcsx2App::~Pcsx2App()
|
||||
{
|
||||
// Typically OnExit cleans everything up before we get here, *unless* we cancel
|
||||
// out of program startup in OnInit (return false) -- then remaning cleanup needs
|
||||
// to happen here in the destructor.
|
||||
|
||||
CleanupMess();
|
||||
while( wxGetLocale() != NULL )
|
||||
delete wxGetLocale();
|
||||
}
|
||||
|
||||
|
||||
void Pcsx2App::ApplySettings( const AppConfig& newconf )
|
||||
void Pcsx2App::ApplySettings( const AppConfig* oldconf )
|
||||
{
|
||||
DevAssert( wxThread::IsMain(), "ApplySettings valid from the GUI thread only." );
|
||||
|
||||
if( &newconf != g_Conf )
|
||||
// Ensure existence of necessary documents folders. Plugins and other parts
|
||||
// of PCSX2 rely on them.
|
||||
|
||||
g_Conf->Folders.MemoryCards.Mkdir();
|
||||
g_Conf->Folders.Savestates.Mkdir();
|
||||
g_Conf->Folders.Snapshots.Mkdir();
|
||||
|
||||
g_Conf->EmuOptions.BiosFilename = g_Conf->FullpathToBios();
|
||||
|
||||
// Update the compression attribute on the Memcards folder.
|
||||
// Memcards generally compress very well via NTFS compression.
|
||||
|
||||
NTFS_CompressFile( g_Conf->Folders.MemoryCards.ToString(), g_Conf->McdEnableNTFS );
|
||||
|
||||
if( (oldconf == NULL) || (oldconf->LanguageId != g_Conf->LanguageId) )
|
||||
{
|
||||
// Need to unload the current emulation state if the user changed plugins, because
|
||||
// the whole plugin system needs to be re-loaded.
|
||||
|
||||
const PluginInfo* pi = tbl_PluginInfo-1;
|
||||
while( ++pi, pi->shortname != NULL )
|
||||
wxDoNotLogInThisScope please;
|
||||
if( !i18n_SetLanguage( g_Conf->LanguageId ) )
|
||||
{
|
||||
if( newconf.FullpathTo( pi->id ) != g_Conf->FullpathTo( pi->id ) )
|
||||
break;
|
||||
}
|
||||
if( pi->shortname != NULL )
|
||||
{
|
||||
// [TODO] : Post notice that this shuts down existing emulation.
|
||||
SysEndExecution();
|
||||
safe_delete( g_plugins );
|
||||
// Think safe to do this earlier, but not positive.
|
||||
// Have to update the config *before* loading the new plugins.
|
||||
*g_Conf = newconf;
|
||||
LoadPlugins();
|
||||
}
|
||||
else {
|
||||
*g_Conf = newconf;
|
||||
if( !i18n_SetLanguage( wxLANGUAGE_DEFAULT ) )
|
||||
{
|
||||
i18n_SetLanguage( wxLANGUAGE_ENGLISH );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_Conf->Apply();
|
||||
if( m_MainFrame != NULL )
|
||||
m_MainFrame->ApplySettings();
|
||||
|
||||
if( g_EmuThread != NULL )
|
||||
g_EmuThread->ApplySettings( g_Conf->EmuOptions );
|
||||
if( m_CoreThread )
|
||||
m_CoreThread->ApplySettings( g_Conf->EmuOptions );
|
||||
}
|
||||
|
||||
void Pcsx2App::LoadSettings()
|
||||
|
|
|
@ -90,7 +90,7 @@ const wxBitmap& Pcsx2App::GetLogoBitmap()
|
|||
wxImage img;
|
||||
EmbeddedImage<res_BackgroundLogo> temp; // because gcc can't allow non-const temporaries.
|
||||
LoadImageAny( img, useTheme, mess, L"BackgroundLogo", temp );
|
||||
m_Bitmap_Logo = new wxBitmap( img );
|
||||
m_Bitmap_Logo.reset( new wxBitmap( img ) );
|
||||
|
||||
return *m_Bitmap_Logo;
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ wxImageList& Pcsx2App::GetImgList_Toolbars()
|
|||
if( m_ToolbarImages == NULL )
|
||||
{
|
||||
const int imgSize = g_Conf->Toolbar_ImageSize ? 64 : 32;
|
||||
m_ToolbarImages = new wxImageList( imgSize, imgSize );
|
||||
m_ToolbarImages.reset( new wxImageList( imgSize, imgSize ) );
|
||||
wxFileName mess;
|
||||
bool useTheme = (g_Conf->DeskTheme != L"default");
|
||||
|
||||
|
|
|
@ -686,17 +686,6 @@ static int pxCallstackDialog( const wxString& content, const wxString& caption,
|
|||
return wxMessageDialog( NULL, content, caption, flags ).ShowModal();
|
||||
}
|
||||
|
||||
struct MsgboxEventResult
|
||||
{
|
||||
Semaphore WaitForMe;
|
||||
int result;
|
||||
|
||||
MsgboxEventResult() :
|
||||
WaitForMe(), result( 0 )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class pxMessageBoxEvent : public wxEvent
|
||||
{
|
||||
protected:
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
~ConsoleTestThread()
|
||||
~ConsoleTestThread() throw()
|
||||
{
|
||||
m_done = true;
|
||||
}
|
||||
|
|
|
@ -26,23 +26,27 @@
|
|||
|
||||
using namespace wxHelpers;
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Helper class for creating wxStaticText labels which are aligned to center.
|
||||
// (automates the passing of wxDefaultSize and wxDefaultPosition)
|
||||
//
|
||||
class StaticTextCentered : public wxStaticText
|
||||
namespace Dialogs
|
||||
{
|
||||
public:
|
||||
StaticTextCentered( wxWindow* parent, const wxString& text, int id=wxID_ANY ) :
|
||||
wxStaticText( parent, id, text, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER )
|
||||
// Helper class for creating wxStaticText labels which are aligned to center.
|
||||
// (automates the passing of wxDefaultSize and wxDefaultPosition)
|
||||
//
|
||||
class StaticTextCentered : public wxStaticText
|
||||
{
|
||||
}
|
||||
};
|
||||
public:
|
||||
StaticTextCentered( wxWindow* parent, const wxString& text, int id=wxID_ANY ) :
|
||||
wxStaticText( parent, id, text, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AboutBoxDialog Implementation
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
||||
wxDialog( parent, id, _("About PCSX2"), parent->GetPosition()-wxSize( 32, 32 ) ),
|
||||
m_bitmap_logo( this, wxID_ANY, wxGetApp().GetLogoBitmap(),
|
||||
wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN ),
|
||||
|
@ -120,5 +124,3 @@ AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
|||
mainSizer.Add( new wxButton( this, wxID_OK, L"I've seen enough"), SizerFlags::StdCenter() );
|
||||
SetSizerAndFit( &mainSizer );
|
||||
}
|
||||
|
||||
} // end namespace Dialogs
|
||||
|
|
|
@ -144,8 +144,8 @@ void Dialogs::ConfigurationDialog::OnApply_Click( wxCommandEvent& evt )
|
|||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
Dialogs::BiosSelectorDialog::BiosSelectorDialog( wxWindow* parent ) :
|
||||
wxDialogWithHelpers( parent, wxID_ANY, _("BIOS Selector"), false )
|
||||
Dialogs::BiosSelectorDialog::BiosSelectorDialog( wxWindow* parent, int id ) :
|
||||
wxDialogWithHelpers( parent, id, _("BIOS Selector"), false )
|
||||
{
|
||||
wxBoxSizer& bleh( *new wxBoxSizer( wxVERTICAL ) );
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace Dialogs
|
|||
|
||||
public:
|
||||
virtual ~ConfigurationDialog();
|
||||
ConfigurationDialog(wxWindow* parent, int id=wxID_ANY);
|
||||
ConfigurationDialog(wxWindow* parent=NULL, int id=DialogId_CoreSettings);
|
||||
|
||||
protected:
|
||||
template< typename T >
|
||||
|
@ -60,7 +60,7 @@ namespace Dialogs
|
|||
|
||||
public:
|
||||
virtual ~BiosSelectorDialog() {}
|
||||
BiosSelectorDialog(wxWindow* parent );
|
||||
BiosSelectorDialog( wxWindow* parent=NULL, int id=DialogId_BiosSelector );
|
||||
|
||||
protected:
|
||||
void OnOk_Click( wxCommandEvent& evt );
|
||||
|
|
|
@ -76,10 +76,7 @@ FirstTimeWizard::UsermodePage::UsermodePage( wxWizard* parent ) :
|
|||
|
||||
void FirstTimeWizard::UsermodePage::OnUsermodeChanged( wxCommandEvent& evt )
|
||||
{
|
||||
m_panel_UserSel.Apply( *g_Conf ); // this assigns the current user mode to g_ApplyState.UseAdminMode
|
||||
if( g_ApplyState.UseAdminMode == UseAdminMode ) return;
|
||||
|
||||
UseAdminMode = g_ApplyState.UseAdminMode;
|
||||
m_panel_UserSel.Apply();
|
||||
g_Conf->Folders.ApplyDefaults();
|
||||
m_dirpick_settings.Reset();
|
||||
}
|
||||
|
@ -161,7 +158,7 @@ void FirstTimeWizard::OnPageChanging( wxWizardEvent& evt )
|
|||
|
||||
if( page == 0 )
|
||||
{
|
||||
if( wxFile::Exists( g_Conf->FullPathToConfig() ) )
|
||||
if( wxFile::Exists( GetSettingsFilename() ) )
|
||||
{
|
||||
// Asks the user if they want to import or overwrite the existing settings.
|
||||
|
||||
|
|
|
@ -112,8 +112,8 @@ LogOptionsDialog::iopLogOptionsPanel::iopLogOptionsPanel( wxWindow* parent ) :
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
LogOptionsDialog::LogOptionsDialog(wxWindow* parent, int id, const wxPoint& pos, const wxSize& size):
|
||||
wxDialogWithHelpers( parent, id, _("Logging"), true, pos, size )
|
||||
LogOptionsDialog::LogOptionsDialog(wxWindow* parent, int id):
|
||||
wxDialogWithHelpers( parent, id, _("Logging"), true )
|
||||
{
|
||||
eeLogOptionsPanel& eeBox = *new eeLogOptionsPanel( this );
|
||||
iopLogOptionsPanel& iopSizer = *new iopLogOptionsPanel( this );
|
||||
|
|
|
@ -14,9 +14,8 @@
|
|||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/image.h>
|
||||
|
||||
#include "App.h"
|
||||
|
||||
#include "wxHelpers.h"
|
||||
#include "CheckedStaticBox.h"
|
||||
|
@ -26,7 +25,7 @@ namespace Dialogs {
|
|||
class LogOptionsDialog: public wxDialogWithHelpers
|
||||
{
|
||||
public:
|
||||
LogOptionsDialog( wxWindow* parent, int id, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize );
|
||||
LogOptionsDialog( wxWindow* parent=NULL, int id=DialogId_LogOptions );
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "App.h"
|
||||
#include "Panels/ConfigurationPanels.h"
|
||||
|
||||
#include <wx/image.h>
|
||||
|
@ -68,7 +69,7 @@ namespace Dialogs
|
|||
class AboutBoxDialog: public wxDialog
|
||||
{
|
||||
public:
|
||||
AboutBoxDialog( wxWindow* parent, int id );
|
||||
AboutBoxDialog( wxWindow* parent=NULL, int id=DialogId_About );
|
||||
|
||||
protected:
|
||||
wxStaticBitmap m_bitmap_logo;
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace HostGui
|
|||
// Sets the status bar message without mirroring the output to the console.
|
||||
void SetStatusMsg( const wxString& text )
|
||||
{
|
||||
wxGetApp().GetMainWindow()->SetStatusText( text );
|
||||
wxGetApp().GetMainFrame().SetStatusText( text );
|
||||
}
|
||||
|
||||
void Notice( const wxString& text )
|
||||
|
@ -63,10 +63,7 @@ void Pcsx2App::OnEmuKeyDown( wxKeyEvent& evt )
|
|||
switch( evt.GetKeyCode() )
|
||||
{
|
||||
case WXK_ESCAPE:
|
||||
if( g_Conf->CloseGSonEsc )
|
||||
StateRecovery::MakeGsOnly();
|
||||
|
||||
SysEndExecution();
|
||||
m_CoreThread->Suspend();
|
||||
break;
|
||||
|
||||
case WXK_F1:
|
||||
|
@ -82,7 +79,7 @@ void Pcsx2App::OnEmuKeyDown( wxKeyEvent& evt )
|
|||
Console::Notice( " > Selected savestate slot %d", StatesC);
|
||||
|
||||
if( GSchangeSaveState != NULL )
|
||||
GSchangeSaveState(StatesC, SaveState::GetFilename(StatesC).mb_str());
|
||||
GSchangeSaveState(StatesC, SaveStateBase::GetFilename(StatesC).mb_str());
|
||||
break;
|
||||
|
||||
case WXK_F3:
|
||||
|
@ -100,15 +97,10 @@ void Pcsx2App::OnEmuKeyDown( wxKeyEvent& evt )
|
|||
break;
|
||||
|
||||
case WXK_F9: //gsdx "on the fly" renderer switching
|
||||
|
||||
SysSuspend();
|
||||
StateRecovery::MakeGsOnly();
|
||||
|
||||
GetPluginManager().Close( PluginId_GS );
|
||||
m_CoreThread->Suspend();
|
||||
m_CorePlugins->Close( PluginId_GS );
|
||||
renderswitch = !renderswitch;
|
||||
|
||||
StateRecovery::Recover();
|
||||
SysResume();
|
||||
m_CoreThread->Resume();
|
||||
break;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
|
|
|
@ -126,10 +126,12 @@ void MainEmuFrame::PopulatePadMenu()
|
|||
//
|
||||
void MainEmuFrame::OnCloseWindow(wxCloseEvent& evt)
|
||||
{
|
||||
// Note Closure Veting would be handled here (user prompt confirmation
|
||||
// Note Closure Vetoing would be handled here (user prompt confirmation
|
||||
// of closing the app)
|
||||
|
||||
wxGetApp().PrepForExit();
|
||||
if( !wxGetApp().PrepForExit() )
|
||||
evt.Veto( true );
|
||||
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
|
|
|
@ -82,13 +82,13 @@ bool MainEmuFrame::_DoSelectIsoBrowser()
|
|||
|
||||
void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
||||
{
|
||||
SysSuspend();
|
||||
wxGetApp().SysSuspend();
|
||||
|
||||
if( !wxFileExists( g_Conf->CurrentIso ) )
|
||||
{
|
||||
if( !_DoSelectIsoBrowser() )
|
||||
{
|
||||
SysResume();
|
||||
wxGetApp().SysResume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -100,66 +100,37 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
|||
|
||||
if( !result )
|
||||
{
|
||||
SysResume();
|
||||
wxGetApp().SysResume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SysEndExecution();
|
||||
|
||||
g_Conf->EmuOptions.SkipBiosSplash = GetMenuBar()->IsChecked( MenuId_SkipBiosToggle );
|
||||
wxGetApp().SaveSettings();
|
||||
|
||||
InitPlugins();
|
||||
|
||||
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
||||
SysExecute( new AppEmuThread(), g_Conf->CdvdSource );
|
||||
wxGetApp().SysExecute( g_Conf->CdvdSource );
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_IsoBrowse_Click( wxCommandEvent &event )
|
||||
{
|
||||
SysSuspend();
|
||||
wxGetApp().SysSuspend();
|
||||
_DoSelectIsoBrowser();
|
||||
SysResume();
|
||||
wxGetApp().SysResume();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_RunIso_Click( wxCommandEvent &event )
|
||||
{
|
||||
SysSuspend();
|
||||
wxGetApp().SysSuspend();
|
||||
|
||||
if( !_DoSelectIsoBrowser() )
|
||||
{
|
||||
SysResume();
|
||||
wxGetApp().SysResume();
|
||||
return;
|
||||
}
|
||||
|
||||
SysEndExecution();
|
||||
|
||||
InitPlugins();
|
||||
SysExecute( new AppEmuThread(), CDVDsrc_Iso );
|
||||
wxGetApp().SysExecute( CDVDsrc_Iso );
|
||||
}
|
||||
|
||||
/*void MainEmuFrame::Menu_RunWithoutDisc_Click(wxCommandEvent &event)
|
||||
{
|
||||
if( EmulationInProgress() )
|
||||
{
|
||||
SysSuspend();
|
||||
|
||||
// [TODO] : Add one of 'dems checkboxes that read like "[x] don't show this stupid shit again, kthx."
|
||||
bool result = Msgbox::OkCancel( pxE( ".Popup:ConfirmEmuReset", L"This will reset the emulator and your current emulation session will be lost. Are you sure?") );
|
||||
|
||||
if( !result )
|
||||
{
|
||||
SysResume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SysEndExecution();
|
||||
InitPlugins();
|
||||
SysExecute( new AppEmuThread(), CDVDsrc_NoDisc );
|
||||
}*/
|
||||
|
||||
void MainEmuFrame::Menu_IsoRecent_Click(wxCommandEvent &event)
|
||||
{
|
||||
//Console::Status( "%d", event.GetId() - g_RecentIsoList->GetBaseId() );
|
||||
|
@ -194,34 +165,32 @@ void MainEmuFrame::Menu_SaveStateOther_Click(wxCommandEvent &event)
|
|||
|
||||
void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
|
||||
{
|
||||
SysReset();
|
||||
Close();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_EmuClose_Click(wxCommandEvent &event)
|
||||
{
|
||||
SysEndExecution();
|
||||
//wxGetApp()->
|
||||
GetMenuBar()->Check( MenuId_Emu_Pause, false );
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_EmuPause_Click(wxCommandEvent &event)
|
||||
{
|
||||
if( event.IsChecked() )
|
||||
SysSuspend();
|
||||
wxGetApp().SysSuspend();
|
||||
else
|
||||
SysResume();
|
||||
wxGetApp().SysResume();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_EmuReset_Click(wxCommandEvent &event)
|
||||
{
|
||||
bool wasRunning = EmulationInProgress();
|
||||
SysReset();
|
||||
wxGetApp().SysReset();
|
||||
|
||||
GetMenuBar()->Check( MenuId_Emu_Pause, false );
|
||||
|
||||
if( !wasRunning ) return;
|
||||
InitPlugins();
|
||||
SysExecute( new AppEmuThread() );
|
||||
wxGetApp().SysExecute();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_ConfigPlugin_Click(wxCommandEvent &event)
|
||||
|
@ -229,8 +198,11 @@ void MainEmuFrame::Menu_ConfigPlugin_Click(wxCommandEvent &event)
|
|||
typedef void (CALLBACK* PluginConfigureFnptr)();
|
||||
const PluginsEnum_t pid = (PluginsEnum_t)( event.GetId() - MenuId_Config_GS );
|
||||
|
||||
LoadPlugins();
|
||||
ScopedWindowDisable disabler( this );
|
||||
LoadPluginsImmediate();
|
||||
if( g_plugins == NULL ) return;
|
||||
|
||||
wxWindowDisabler disabler;
|
||||
//ScopedWindowDisable disabler( this );
|
||||
g_plugins->Configure( pid );
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,6 @@ struct Component_FileMcd;
|
|||
|
||||
#include <wx/file.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
extern void NTFS_CompressFile( const wxString& file, bool compressMode );
|
||||
#endif
|
||||
|
||||
static const int MCD_SIZE = 1024 * 8 * 16;
|
||||
static const int MC2_SIZE = 1024 * 528 * 16;
|
||||
|
||||
|
@ -106,9 +102,7 @@ FileMemoryCard::FileMemoryCard()
|
|||
// [TODO] : Add memcard size detection and report it to the console log.
|
||||
// (8MB, 256Mb, whatever)
|
||||
|
||||
#ifdef _WIN32
|
||||
NTFS_CompressFile( str, g_Conf->McdEnableNTFS );
|
||||
#endif
|
||||
|
||||
if( !m_file[port][slot].Open( str.c_str(), wxFile::read_write ) )
|
||||
{
|
||||
|
|
|
@ -70,7 +70,6 @@ Panels::BiosSelectorPanel::BiosSelectorPanel( wxWindow& parent, int idealWidth )
|
|||
_("BIOS Search Path:"), // static box label
|
||||
_("Select folder with PS2 BIOS roms") // dir picker popup label
|
||||
) )
|
||||
, m_BiosList( NULL )
|
||||
{
|
||||
m_ComboBox.SetFont( wxFont( m_ComboBox.GetFont().GetPointSize()+1, wxFONTFAMILY_MODERN, wxNORMAL, wxNORMAL, false, L"Lucida Console" ) );
|
||||
m_ComboBox.SetMinSize( wxSize( wxDefaultCoord, std::max( m_ComboBox.GetMinSize().GetHeight(), 96 ) ) );
|
||||
|
@ -88,7 +87,6 @@ Panels::BiosSelectorPanel::BiosSelectorPanel( wxWindow& parent, int idealWidth )
|
|||
|
||||
Panels::BiosSelectorPanel::~BiosSelectorPanel()
|
||||
{
|
||||
safe_delete( m_BiosList );
|
||||
}
|
||||
|
||||
bool Panels::BiosSelectorPanel::ValidateEnumerationStatus()
|
||||
|
@ -102,11 +100,10 @@ bool Panels::BiosSelectorPanel::ValidateEnumerationStatus()
|
|||
if( m_FolderPicker.GetPath().Exists() )
|
||||
wxDir::GetAllFiles( m_FolderPicker.GetPath().ToString(), bioslist.get(), L"*.bin", wxDIR_FILES );
|
||||
|
||||
if( (m_BiosList == NULL) || (*bioslist != *m_BiosList) )
|
||||
if( !m_BiosList || (*bioslist != *m_BiosList) )
|
||||
validated = false;
|
||||
|
||||
delete m_BiosList;
|
||||
m_BiosList = bioslist.release();
|
||||
m_BiosList.swap( bioslist );
|
||||
|
||||
return validated;
|
||||
}
|
||||
|
@ -116,7 +113,7 @@ void Panels::BiosSelectorPanel::ReloadSettings()
|
|||
m_FolderPicker.Reset();
|
||||
}
|
||||
|
||||
void Panels::BiosSelectorPanel::Apply( AppConfig& conf )
|
||||
void Panels::BiosSelectorPanel::Apply()
|
||||
{
|
||||
int sel = m_ComboBox.GetSelection();
|
||||
if( sel == wxNOT_FOUND )
|
||||
|
@ -133,11 +130,13 @@ void Panels::BiosSelectorPanel::Apply( AppConfig& conf )
|
|||
);
|
||||
}
|
||||
|
||||
conf.BaseFilenames.Bios = (*m_BiosList)[(int)m_ComboBox.GetClientData(sel)];
|
||||
g_Conf->BaseFilenames.Bios = (*m_BiosList)[(int)m_ComboBox.GetClientData(sel)];
|
||||
}
|
||||
|
||||
void Panels::BiosSelectorPanel::DoRefresh()
|
||||
{
|
||||
if( !m_BiosList ) return;
|
||||
|
||||
wxFileName right( g_Conf->FullpathToBios() );
|
||||
right.MakeAbsolute();
|
||||
|
||||
|
|
|
@ -93,10 +93,6 @@ namespace Panels
|
|||
// TODO : Rename me to CurOwnerBook, or rename the one above to ParentPage.
|
||||
wxBookCtrlBase* ParentBook;
|
||||
|
||||
// Crappy hack to handle the UseAdminMode option, which can't be part of AppConfig
|
||||
// because AppConfig depends on this value to initialize itself.
|
||||
bool UseAdminMode;
|
||||
|
||||
StaticApplyState() :
|
||||
PanelList()
|
||||
, CurOwnerPage( wxID_NONE )
|
||||
|
@ -168,7 +164,7 @@ namespace Panels
|
|||
// configuration structure (which is typically a copy of g_Conf). If validation
|
||||
// of form contents fails, the function should throw Exception::CannotApplySettings.
|
||||
// If no exceptions are thrown, then the operation is assumed a success. :)
|
||||
virtual void Apply( AppConfig& conf )=0;
|
||||
virtual void Apply()=0;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -183,7 +179,7 @@ namespace Panels
|
|||
virtual ~UsermodeSelectionPanel() { }
|
||||
UsermodeSelectionPanel( wxWindow& parent, int idealWidth=wxDefaultCoord, bool isFirstTime = true );
|
||||
|
||||
void Apply( AppConfig& conf );
|
||||
void Apply();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -198,7 +194,7 @@ namespace Panels
|
|||
virtual ~LanguageSelectionPanel() { }
|
||||
LanguageSelectionPanel( wxWindow& parent, int idealWidth=wxDefaultCoord );
|
||||
|
||||
void Apply( AppConfig& conf );
|
||||
void Apply();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -216,7 +212,7 @@ namespace Panels
|
|||
|
||||
public:
|
||||
CpuPanel( wxWindow& parent, int idealWidth );
|
||||
void Apply( AppConfig& conf );
|
||||
void Apply();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -227,7 +223,7 @@ namespace Panels
|
|||
|
||||
public:
|
||||
VideoPanel( wxWindow& parent, int idealWidth );
|
||||
void Apply( AppConfig& conf );
|
||||
void Apply();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -248,7 +244,7 @@ namespace Panels
|
|||
|
||||
public:
|
||||
SpeedHacksPanel( wxWindow& parent, int idealWidth );
|
||||
void Apply( AppConfig& conf );
|
||||
void Apply();
|
||||
|
||||
protected:
|
||||
const wxChar* GetEEcycleSliderMsg( int val );
|
||||
|
@ -267,7 +263,7 @@ namespace Panels
|
|||
|
||||
public:
|
||||
GameFixesPanel( wxWindow& parent, int idealWidth );
|
||||
void Apply( AppConfig& conf );
|
||||
void Apply();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -286,7 +282,7 @@ namespace Panels
|
|||
DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid, const wxString& label, const wxString& dialogLabel );
|
||||
virtual ~DirPickerPanel() { }
|
||||
|
||||
void Apply( AppConfig& conf );
|
||||
void Apply();
|
||||
void Reset();
|
||||
wxDirName GetPath() const { return wxDirName( m_pickerCtrl->GetPath() ); }
|
||||
|
||||
|
@ -354,9 +350,9 @@ namespace Panels
|
|||
class BiosSelectorPanel : public BaseSelectorPanel
|
||||
{
|
||||
protected:
|
||||
wxScopedPtr<wxArrayString> m_BiosList;
|
||||
wxListBox& m_ComboBox;
|
||||
DirPickerPanel& m_FolderPicker;
|
||||
wxArrayString* m_BiosList;
|
||||
|
||||
public:
|
||||
BiosSelectorPanel( wxWindow& parent, int idealWidth );
|
||||
|
@ -364,7 +360,7 @@ namespace Panels
|
|||
void ReloadSettings();
|
||||
|
||||
protected:
|
||||
virtual void Apply( AppConfig& conf );
|
||||
virtual void Apply();
|
||||
virtual void DoRefresh();
|
||||
virtual bool ValidateEnumerationStatus();
|
||||
};
|
||||
|
@ -399,16 +395,18 @@ namespace Panels
|
|||
class EnumThread : public Threading::PersistentThread
|
||||
{
|
||||
public:
|
||||
EnumeratedPluginInfo* Results; // array of plugin results.
|
||||
SafeList<EnumeratedPluginInfo> Results; // array of plugin results.
|
||||
|
||||
protected:
|
||||
PluginSelectorPanel& m_master;
|
||||
volatile bool m_cancel;
|
||||
|
||||
public:
|
||||
virtual ~EnumThread();
|
||||
virtual ~EnumThread() throw()
|
||||
{
|
||||
PersistentThread::Cancel();
|
||||
}
|
||||
|
||||
EnumThread( PluginSelectorPanel& master );
|
||||
void Cancel();
|
||||
void DoNextPlugin( int evtidx );
|
||||
|
||||
protected:
|
||||
|
@ -447,25 +445,27 @@ namespace Panels
|
|||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// PluginSelectorPanel Members
|
||||
// PluginSelectorPanel Members
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
protected:
|
||||
wxArrayString* m_FileList; // list of potential plugin files
|
||||
StatusPanel& m_StatusPanel;
|
||||
ComboBoxPanel& m_ComponentBoxes;
|
||||
EnumThread* m_EnumeratorThread;
|
||||
|
||||
wxScopedPtr<wxArrayString> m_FileList; // list of potential plugin files
|
||||
wxScopedPtr<EnumThread> m_EnumeratorThread;
|
||||
|
||||
public:
|
||||
virtual ~PluginSelectorPanel();
|
||||
PluginSelectorPanel( wxWindow& parent, int idealWidth );
|
||||
|
||||
void CancelRefresh(); // used from destructor, stays non-virtual
|
||||
void Apply( AppConfig& conf );
|
||||
void Apply();
|
||||
void ReloadSettings();
|
||||
|
||||
protected:
|
||||
void OnConfigure_Clicked( wxCommandEvent& evt );
|
||||
void OnShowStatusBar( wxCommandEvent& evt );
|
||||
virtual void OnProgress( wxCommandEvent& evt );
|
||||
virtual void OnEnumComplete( wxCommandEvent& evt );
|
||||
|
||||
|
|
|
@ -78,9 +78,9 @@ Panels::CpuPanel::CpuPanel( wxWindow& parent, int idealWidth ) :
|
|||
m_Option_sVU1->SetValue( recOps.EnableVU1 );
|
||||
}
|
||||
|
||||
void Panels::CpuPanel::Apply( AppConfig& conf )
|
||||
void Panels::CpuPanel::Apply()
|
||||
{
|
||||
Pcsx2Config::RecompilerOptions& recOps( conf.EmuOptions.Cpu.Recompiler );
|
||||
Pcsx2Config::RecompilerOptions& recOps( g_Conf->EmuOptions.Cpu.Recompiler );
|
||||
recOps.EnableEE = m_Option_RecEE->GetValue();
|
||||
recOps.EnableIOP = m_Option_RecIOP->GetValue();
|
||||
recOps.EnableVU0 = m_Option_mVU0->GetValue() || m_Option_sVU0->GetValue();
|
||||
|
|
|
@ -93,8 +93,7 @@ Panels::DirPickerPanel::DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid
|
|||
|
||||
m_checkCtrl = &AddCheckBox( s_lower, _("Use default setting") );
|
||||
m_checkCtrl->SetToolTip( pxE( ".Tooltip:DirPicker:UseDefault",
|
||||
L"When checked this folder will automatically reflect the default associated with PCSX2's current usermode setting. "
|
||||
L"" )
|
||||
L"When checked this folder will automatically reflect the default associated with PCSX2's current usermode setting. " )
|
||||
);
|
||||
|
||||
#ifndef __WXGTK__
|
||||
|
@ -134,7 +133,7 @@ void Panels::DirPickerPanel::Reset()
|
|||
m_pickerCtrl->SetPath( GetNormalizedConfigFolder( m_FolderId ) );
|
||||
}
|
||||
|
||||
void Panels::DirPickerPanel::Apply( AppConfig& conf )
|
||||
void Panels::DirPickerPanel::Apply()
|
||||
{
|
||||
conf.Folders.Set( m_FolderId, m_pickerCtrl->GetPath(), m_checkCtrl->GetValue() );
|
||||
g_Conf->Folders.Set( m_FolderId, m_pickerCtrl->GetPath(), m_checkCtrl->GetValue() );
|
||||
}
|
||||
|
|
|
@ -85,9 +85,9 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow& parent, int idealWidth ) :
|
|||
}
|
||||
|
||||
// I could still probably get rid of the for loop, but I think this is clearer.
|
||||
void Panels::GameFixesPanel::Apply( AppConfig& conf )
|
||||
void Panels::GameFixesPanel::Apply()
|
||||
{
|
||||
Pcsx2Config::GamefixOptions& opts( conf.EmuOptions.Gamefixes );
|
||||
Pcsx2Config::GamefixOptions& opts( g_Conf->EmuOptions.Gamefixes );
|
||||
for (int i = 0; i < NUM_OF_GAME_FIXES; i++)
|
||||
{
|
||||
if (m_checkbox[i]->GetValue())
|
||||
|
|
|
@ -60,31 +60,40 @@ void Panels::StaticApplyState::StartWizard()
|
|||
bool Panels::StaticApplyState::ApplyPage( int pageid, bool saveOnSuccess )
|
||||
{
|
||||
bool retval = true;
|
||||
|
||||
// Save these settings so we can restore them if the Apply fails.
|
||||
|
||||
bool oldAdminMode = UseAdminMode;
|
||||
wxDirName oldSettingsFolder = SettingsFolder;
|
||||
bool oldUseDefSet = UseDefaultSettingsFolder;
|
||||
|
||||
AppConfig confcopy( *g_Conf );
|
||||
|
||||
try
|
||||
{
|
||||
AppConfig confcopy( *g_Conf );
|
||||
|
||||
g_ApplyState.UseAdminMode = UseAdminMode;
|
||||
|
||||
PanelApplyList_t::iterator yay = PanelList.begin();
|
||||
while( yay != PanelList.end() )
|
||||
{
|
||||
//DbgCon::Status( L"Writing settings for: " + (*yay)->GetLabel() );
|
||||
if( (pageid < 0) || (*yay)->IsOnPage( pageid ) )
|
||||
(*yay)->Apply( confcopy );
|
||||
(*yay)->Apply();
|
||||
yay++;
|
||||
}
|
||||
|
||||
// If an exception is thrown above, this code below won't get run.
|
||||
// (conveniently skipping any option application! :D)
|
||||
|
||||
UseAdminMode = g_ApplyState.UseAdminMode;
|
||||
wxGetApp().ApplySettings( confcopy );
|
||||
wxGetApp().ApplySettings( &confcopy );
|
||||
if( saveOnSuccess )
|
||||
wxGetApp().SaveSettings();
|
||||
}
|
||||
catch( Exception::CannotApplySettings& ex )
|
||||
{
|
||||
UseAdminMode = oldAdminMode;
|
||||
SettingsFolder = oldSettingsFolder;
|
||||
UseDefaultSettingsFolder = oldUseDefSet;
|
||||
*g_Conf = confcopy;
|
||||
|
||||
wxMessageBox( ex.FormatDisplayMessage(), _("Cannot apply settings...") );
|
||||
|
||||
if( ex.GetPanel() != NULL )
|
||||
|
@ -92,6 +101,15 @@ bool Panels::StaticApplyState::ApplyPage( int pageid, bool saveOnSuccess )
|
|||
|
||||
retval = false;
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
UseAdminMode = oldAdminMode;
|
||||
SettingsFolder = oldSettingsFolder;
|
||||
UseDefaultSettingsFolder = oldUseDefSet;
|
||||
*g_Conf = confcopy;
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -133,12 +151,12 @@ Panels::UsermodeSelectionPanel::UsermodeSelectionPanel( wxWindow& parent, int id
|
|||
SetSizer( &s_boxer );
|
||||
}
|
||||
|
||||
void Panels::UsermodeSelectionPanel::Apply( AppConfig& conf )
|
||||
void Panels::UsermodeSelectionPanel::Apply()
|
||||
{
|
||||
if( !m_radio_cwd->GetValue() && !m_radio_user->GetValue() )
|
||||
throw Exception::CannotApplySettings( this, wxLt( "You must select one of the available user modes before proceeding." ) );
|
||||
|
||||
g_ApplyState.UseAdminMode = m_radio_cwd->GetValue();
|
||||
UseAdminMode = m_radio_cwd->GetValue();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
@ -173,20 +191,20 @@ Panels::LanguageSelectionPanel::LanguageSelectionPanel( wxWindow& parent, int id
|
|||
SetSizer( &s_lang );
|
||||
}
|
||||
|
||||
void Panels::LanguageSelectionPanel::Apply( AppConfig& conf )
|
||||
void Panels::LanguageSelectionPanel::Apply()
|
||||
{
|
||||
// The combo box's order is sorted and may not match our m_langs order, so
|
||||
// we have to do a string comparison to find a match:
|
||||
|
||||
wxString sel( m_picker->GetString( m_picker->GetSelection() ) );
|
||||
|
||||
conf.LanguageId = wxLANGUAGE_DEFAULT; // use this if no matches found
|
||||
g_Conf->LanguageId = wxLANGUAGE_DEFAULT; // use this if no matches found
|
||||
int size = m_langs.size();
|
||||
for( int i=0; i<size; ++i )
|
||||
{
|
||||
if( m_langs[i].englishName == sel )
|
||||
{
|
||||
conf.LanguageId = m_langs[i].wxLangId;
|
||||
g_Conf->LanguageId = m_langs[i].wxLangId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,12 +34,14 @@ using namespace wxHelpers;
|
|||
using namespace Threading;
|
||||
|
||||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
DECLARE_EVENT_TYPE(wxEVT_EnumeratedNext, -1)
|
||||
DECLARE_EVENT_TYPE(wxEVT_EnumerationFinished, -1)
|
||||
DECLARE_EVENT_TYPE(pxEVT_EnumeratedNext, -1)
|
||||
DECLARE_EVENT_TYPE(pxEVT_EnumerationFinished, -1)
|
||||
DECLARE_EVENT_TYPE(pxEVT_ShowStatusBar, -1)
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
DEFINE_EVENT_TYPE(wxEVT_EnumeratedNext)
|
||||
DEFINE_EVENT_TYPE(wxEVT_EnumerationFinished);
|
||||
DEFINE_EVENT_TYPE(pxEVT_EnumeratedNext)
|
||||
DEFINE_EVENT_TYPE(pxEVT_EnumerationFinished);
|
||||
DEFINE_EVENT_TYPE(pxEVT_ShowStatusBar);
|
||||
|
||||
typedef s32 (CALLBACK* PluginTestFnptr)();
|
||||
typedef void (CALLBACK* PluginConfigureFnptr)();
|
||||
|
@ -55,8 +57,10 @@ namespace Exception
|
|||
};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PluginEnumerator class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
class PluginEnumerator
|
||||
{
|
||||
protected:
|
||||
|
@ -74,15 +78,15 @@ public:
|
|||
// Constructor!
|
||||
//
|
||||
// Possible Exceptions:
|
||||
// BadStream - thrown if the provided file is simply not a loadable DLL.
|
||||
// NotPcsxPlugin - thrown if the DLL is not a PCSX2 plugin, or if it's of an unsupported version.
|
||||
// BadStream - thrown if the provided file is simply not a loadable DLL.
|
||||
// NotEnumerablePlugin - thrown if the DLL is not a PCSX2 plugin, or if it's of an unsupported version.
|
||||
//
|
||||
PluginEnumerator( const wxString& plugpath ) :
|
||||
m_plugpath( plugpath )
|
||||
, m_plugin()
|
||||
{
|
||||
if( !m_plugin.Load( m_plugpath ) )
|
||||
throw Exception::BadStream( m_plugpath, "File is not a valid dynamic library" );
|
||||
throw Exception::BadStream( m_plugpath, "File is not a valid dynamic library." );
|
||||
|
||||
wxDoNotLogInThisScope please;
|
||||
m_GetLibType = (_PS2EgetLibType)m_plugin.GetSymbol( L"PS2EgetLibType" );
|
||||
|
@ -90,9 +94,8 @@ public:
|
|||
m_GetLibVersion2 = (_PS2EgetLibVersion2)m_plugin.GetSymbol( L"PS2EgetLibVersion2" );
|
||||
|
||||
if( m_GetLibType == NULL || m_GetLibName == NULL || m_GetLibVersion2 == NULL )
|
||||
{
|
||||
throw Exception::NotEnumerablePlugin( m_plugpath );
|
||||
}
|
||||
|
||||
m_type = m_GetLibType();
|
||||
}
|
||||
|
||||
|
@ -134,7 +137,10 @@ public:
|
|||
|
||||
static const wxString failed_separator( L"-------- Unsupported Plugins --------" );
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PluginSelectorPanel implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
Panels::PluginSelectorPanel::StatusPanel::StatusPanel( wxWindow* parent ) :
|
||||
wxPanelWithHelpers( parent )
|
||||
, m_gauge( *new wxGauge( this, wxID_ANY, 10 ) )
|
||||
|
@ -221,10 +227,8 @@ void Panels::PluginSelectorPanel::ComboBoxPanel::Reset()
|
|||
// ------------------------------------------------------------------------
|
||||
Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow& parent, int idealWidth ) :
|
||||
BaseSelectorPanel( parent, idealWidth )
|
||||
, m_FileList( NULL )
|
||||
, m_StatusPanel( *new StatusPanel( this ) )
|
||||
, m_ComponentBoxes( *new ComboBoxPanel( this ) )
|
||||
, m_EnumeratorThread( NULL )
|
||||
{
|
||||
// note: the status panel is a floating window, so that it can be positioned in the
|
||||
// center of the dialog after it's been fitted to the contents.
|
||||
|
@ -242,8 +246,9 @@ Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow& parent, int idealWid
|
|||
|
||||
SetSizer( &s_main );
|
||||
|
||||
Connect( wxEVT_EnumeratedNext, wxCommandEventHandler( PluginSelectorPanel::OnProgress ) );
|
||||
Connect( wxEVT_EnumerationFinished, wxCommandEventHandler( PluginSelectorPanel::OnEnumComplete ) );
|
||||
Connect( pxEVT_EnumeratedNext, wxCommandEventHandler( PluginSelectorPanel::OnProgress ) );
|
||||
Connect( pxEVT_EnumerationFinished, wxCommandEventHandler( PluginSelectorPanel::OnEnumComplete ) );
|
||||
Connect( pxEVT_ShowStatusBar, wxCommandEventHandler( PluginSelectorPanel::OnShowStatusBar ) );
|
||||
Connect( ButtonId_Configure, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PluginSelectorPanel::OnConfigure_Clicked ) );
|
||||
}
|
||||
|
||||
|
@ -257,10 +262,19 @@ void Panels::PluginSelectorPanel::ReloadSettings()
|
|||
m_ComponentBoxes.GetDirPicker().Reset();
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::Apply( AppConfig& conf )
|
||||
static wxString GetApplyFailedMsg()
|
||||
{
|
||||
return pxE( ".Popup Error:PluginSelector:ApplyFailed",
|
||||
L"All plugins must have valid selections for PCSX2 to run. If you are unable to make\n"
|
||||
L"a valid selection due to missing plugins or an incomplete install of PCSX2, then\n"
|
||||
L"press cancel to close the Configuration panel."
|
||||
);
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::Apply()
|
||||
{
|
||||
// user never entered plugins panel? Skip application since combo boxes are invalid/uninitialized.
|
||||
if( m_FileList == NULL ) return;
|
||||
if( !m_FileList ) return;
|
||||
|
||||
for( int i=0; i<NumPluginTypes; ++i )
|
||||
{
|
||||
|
@ -271,32 +285,72 @@ void Panels::PluginSelectorPanel::Apply( AppConfig& conf )
|
|||
|
||||
throw Exception::CannotApplySettings( this,
|
||||
// English Log
|
||||
wxsFormat( L"User did not specify a valid selection for the %s plugin.", plugname.c_str() ),
|
||||
wxsFormat( L"PluginSelectorPanel: Invalid or missing selection for the %s plugin.", plugname.c_str() ),
|
||||
|
||||
// Translated
|
||||
wxsFormat( L"Please select a valid plugin for the %s.", plugname.c_str() ) + L"\n\n" +
|
||||
pxE( ".Popup Error:Invalid Plugin Selection",
|
||||
L"All plugins must have valid selections for PCSX2 to run. If you are unable to make\n"
|
||||
L"a valid selection due to missing plugins or an incomplete install of PCSX2, then\n"
|
||||
L"press cancel to close the Configuration panel."
|
||||
)
|
||||
wxsFormat( L"Please select a valid plugin for the %s.", plugname.c_str() ) + L"\n\n" + GetApplyFailedMsg()
|
||||
);
|
||||
}
|
||||
|
||||
conf.BaseFilenames.Plugins[tbl_PluginInfo[i].id] = GetFilename((int)m_ComponentBoxes.Get(i).GetClientData(sel));
|
||||
g_Conf->BaseFilenames.Plugins[tbl_PluginInfo[i].id] = GetFilename((int)m_ComponentBoxes.Get(i).GetClientData(sel));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Make sure folders are up to date, and try to load/reload plugins if needed...
|
||||
|
||||
g_Conf->Folders.ApplyDefaults();
|
||||
|
||||
// Need to unload the current emulation state if the user changed plugins, because
|
||||
// the whole plugin system needs to be re-loaded.
|
||||
|
||||
const PluginInfo* pi = tbl_PluginInfo-1;
|
||||
while( ++pi, pi->shortname != NULL )
|
||||
{
|
||||
if( g_Conf->FullpathTo( pi->id ) != g_Conf->FullpathTo( pi->id ) )
|
||||
break;
|
||||
}
|
||||
|
||||
if( pi->shortname != NULL )
|
||||
{
|
||||
if( wxGetApp().m_CoreThread )
|
||||
{
|
||||
// [TODO] : Post notice that this shuts down existing emulation, and may not safely recover.
|
||||
}
|
||||
|
||||
wxGetApp().SysReset();
|
||||
}
|
||||
|
||||
if( !wxGetApp().m_CorePlugins )
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadPluginsImmediate();
|
||||
}
|
||||
catch( Exception::PluginError& ex )
|
||||
{
|
||||
// Rethrow PluginLoadErrors as a failure to Apply...
|
||||
|
||||
wxString plugname( tbl_PluginInfo[ex.PluginId].GetShortname() );
|
||||
|
||||
throw Exception::CannotApplySettings( this,
|
||||
// English Log
|
||||
ex.FormatDiagnosticMessage(),
|
||||
|
||||
// Translated
|
||||
wxsFormat( L"The selected %s plugin failed to load.", plugname.c_str() ) + L"\n\n" + GetApplyFailedMsg()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::CancelRefresh()
|
||||
{
|
||||
safe_delete( m_EnumeratorThread );
|
||||
safe_delete( m_FileList );
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::DoRefresh()
|
||||
{
|
||||
m_ComponentBoxes.Reset();
|
||||
if( m_FileList == NULL )
|
||||
if( !m_FileList )
|
||||
{
|
||||
wxCommandEvent evt;
|
||||
OnEnumComplete( evt );
|
||||
|
@ -304,21 +358,17 @@ void Panels::PluginSelectorPanel::DoRefresh()
|
|||
}
|
||||
|
||||
// Disable all controls until enumeration is complete.
|
||||
// Show status bar for plugin enumeration.
|
||||
|
||||
// fixme: the status bar doesn't always fit itself to the window correctly because
|
||||
// sometimes this gets called before the parent window has been fully created. I'm
|
||||
// not quite sure how to fix (a delayed event/message might work tho implementing it
|
||||
// may not be trivial) -- air
|
||||
// Show status bar for plugin enumeration. Use a pending event so that
|
||||
// the window's size can get initialized properly before trying to custom-
|
||||
// fit the status panel to it.
|
||||
|
||||
m_ComponentBoxes.Hide();
|
||||
m_StatusPanel.SetSize( m_ComponentBoxes.GetSize().GetWidth() - 8, wxDefaultCoord );
|
||||
m_StatusPanel.CentreOnParent();
|
||||
m_StatusPanel.Show();
|
||||
wxCommandEvent evt( pxEVT_ShowStatusBar );
|
||||
GetEventHandler()->AddPendingEvent( evt );
|
||||
|
||||
// Use a thread to load plugins.
|
||||
safe_delete( m_EnumeratorThread );
|
||||
m_EnumeratorThread = new EnumThread( *this );
|
||||
m_EnumeratorThread.reset( NULL );
|
||||
m_EnumeratorThread.reset( new EnumThread( *this ) );
|
||||
|
||||
if( DisableThreading )
|
||||
m_EnumeratorThread->DoNextPlugin( 0 );
|
||||
|
@ -328,6 +378,8 @@ void Panels::PluginSelectorPanel::DoRefresh()
|
|||
|
||||
bool Panels::PluginSelectorPanel::ValidateEnumerationStatus()
|
||||
{
|
||||
m_EnumeratorThread.reset(); // make sure the thread is STOPPED, just in case...
|
||||
|
||||
bool validated = true;
|
||||
|
||||
// re-enumerate plugins, and if anything changed then we need to wipe
|
||||
|
@ -339,17 +391,16 @@ bool Panels::PluginSelectorPanel::ValidateEnumerationStatus()
|
|||
|
||||
int pluggers = EnumeratePluginsInFolder( m_ComponentBoxes.GetPluginsPath(), pluginlist.get() );
|
||||
|
||||
if( (m_FileList == NULL) || (*pluginlist != *m_FileList) )
|
||||
if( !m_FileList || (*pluginlist != *m_FileList) )
|
||||
validated = false;
|
||||
|
||||
if( pluggers == 0 )
|
||||
{
|
||||
safe_delete( m_FileList );
|
||||
m_FileList.reset();
|
||||
return validated;
|
||||
}
|
||||
|
||||
delete m_FileList;
|
||||
m_FileList = pluginlist.release();
|
||||
m_FileList.swap( pluginlist );
|
||||
|
||||
m_StatusPanel.SetGaugeLength( pluggers );
|
||||
|
||||
|
@ -370,9 +421,16 @@ void Panels::PluginSelectorPanel::OnConfigure_Clicked( wxCommandEvent& evt )
|
|||
}
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::OnShowStatusBar( wxCommandEvent& evt )
|
||||
{
|
||||
m_StatusPanel.SetSize( m_ComponentBoxes.GetSize().GetWidth() - 8, wxDefaultCoord );
|
||||
m_StatusPanel.CentreOnParent();
|
||||
m_StatusPanel.Show();
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::OnEnumComplete( wxCommandEvent& evt )
|
||||
{
|
||||
safe_delete( m_EnumeratorThread );
|
||||
m_EnumeratorThread.reset();
|
||||
|
||||
// fixme: Default plugins should be picked based on the timestamp of the DLL or something?
|
||||
// (for now we just force it to selection zero if nothing's selected)
|
||||
|
@ -395,7 +453,7 @@ void Panels::PluginSelectorPanel::OnEnumComplete( wxCommandEvent& evt )
|
|||
|
||||
void Panels::PluginSelectorPanel::OnProgress( wxCommandEvent& evt )
|
||||
{
|
||||
if( m_FileList == NULL ) return;
|
||||
if( !m_FileList ) return;
|
||||
|
||||
const size_t evtidx = evt.GetExtraLong();
|
||||
|
||||
|
@ -404,7 +462,7 @@ void Panels::PluginSelectorPanel::OnProgress( wxCommandEvent& evt )
|
|||
const int nextidx = evtidx+1;
|
||||
if( nextidx == m_FileList->Count() )
|
||||
{
|
||||
wxCommandEvent done( wxEVT_EnumerationFinished );
|
||||
wxCommandEvent done( pxEVT_EnumerationFinished );
|
||||
GetEventHandler()->AddPendingEvent( done );
|
||||
}
|
||||
else
|
||||
|
@ -447,28 +505,16 @@ void Panels::PluginSelectorPanel::OnProgress( wxCommandEvent& evt )
|
|||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// EnumThread Method Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EnumThread method implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master ) :
|
||||
PersistentThread()
|
||||
, Results( new EnumeratedPluginInfo[master.FileCount()] )
|
||||
, Results( master.FileCount(), L"PluginSelectorResults" )
|
||||
, m_master( master )
|
||||
, m_cancel( false )
|
||||
{
|
||||
}
|
||||
|
||||
Panels::PluginSelectorPanel::EnumThread::~EnumThread()
|
||||
{
|
||||
EnumThread::Cancel();
|
||||
safe_delete_array( Results );
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::EnumThread::Cancel()
|
||||
{
|
||||
m_cancel = true;
|
||||
Sleep( 2 );
|
||||
PersistentThread::Cancel();
|
||||
Results.MatchLengthToAllocatedSize();
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::EnumThread::DoNextPlugin( int curidx )
|
||||
|
@ -499,7 +545,7 @@ void Panels::PluginSelectorPanel::EnumThread::DoNextPlugin( int curidx )
|
|||
Console::Status( ex.FormatDiagnosticMessage() );
|
||||
}
|
||||
|
||||
wxCommandEvent yay( wxEVT_EnumeratedNext );
|
||||
wxCommandEvent yay( pxEVT_EnumeratedNext );
|
||||
yay.SetExtraLong( curidx );
|
||||
m_master.GetEventHandler()->AddPendingEvent( yay );
|
||||
}
|
||||
|
@ -509,15 +555,15 @@ sptr Panels::PluginSelectorPanel::EnumThread::ExecuteTask()
|
|||
DevCon::Status( "Plugin Enumeration Thread started..." );
|
||||
|
||||
wxGetApp().Ping(); // gives the gui thread some time to refresh
|
||||
Sleep( 3 );
|
||||
|
||||
for( int curidx=0; curidx < m_master.FileCount(); ++curidx )
|
||||
{
|
||||
if( m_cancel ) return 0;
|
||||
DoNextPlugin( curidx );
|
||||
pthread_testcancel();
|
||||
}
|
||||
|
||||
wxCommandEvent done( wxEVT_EnumerationFinished );
|
||||
wxCommandEvent done( pxEVT_EnumerationFinished );
|
||||
m_master.GetEventHandler()->AddPendingEvent( done );
|
||||
|
||||
DevCon::Status( "Plugin Enumeration Thread complete!" );
|
||||
|
|
|
@ -219,9 +219,9 @@ Panels::SpeedHacksPanel::SpeedHacksPanel( wxWindow& parent, int idealWidth ) :
|
|||
Connect( m_slider_vustealer->GetId(), wxEVT_SCROLL_CHANGED, wxScrollEventHandler( SpeedHacksPanel::VUCycleRate_Scroll ) );
|
||||
}
|
||||
|
||||
void Panels::SpeedHacksPanel::Apply( AppConfig& conf )
|
||||
void Panels::SpeedHacksPanel::Apply()
|
||||
{
|
||||
Pcsx2Config::SpeedhackOptions& opts( conf.EmuOptions.Speedhacks );
|
||||
Pcsx2Config::SpeedhackOptions& opts( g_Conf->EmuOptions.Speedhacks );
|
||||
opts.EECycleRate = m_slider_eecycle->GetValue()-1;
|
||||
opts.VUCycleSteal = m_slider_vustealer->GetValue();
|
||||
|
||||
|
|
|
@ -25,6 +25,6 @@ Panels::VideoPanel::VideoPanel( wxWindow& parent, int idealWidth ) :
|
|||
// MTGS Forced Synchronization
|
||||
}
|
||||
|
||||
void Panels::VideoPanel::Apply( AppConfig& conf )
|
||||
void Panels::VideoPanel::Apply()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "Utilities/ScopedPtr.h"
|
||||
#include "App.h"
|
||||
|
||||
#include <wx/dir.h>
|
||||
#include <wx/file.h>
|
||||
|
@ -44,9 +44,73 @@ int EnumeratePluginsInFolder( const wxDirName& searchpath, wxArrayString* dest )
|
|||
wxDir::GetAllFiles( searchpath.ToString(), realdest, wxsFormat( pattern, wxDynamicLibrary::GetDllExt()), wxDIR_FILES ) : 0;
|
||||
}
|
||||
|
||||
void LoadPlugins()
|
||||
using namespace Threading;
|
||||
|
||||
void Pcsx2App::OnReloadPlugins( wxCommandEvent& evt )
|
||||
{
|
||||
if( g_plugins != NULL ) return;
|
||||
ReloadPlugins();
|
||||
}
|
||||
|
||||
void Pcsx2App::ReloadPlugins()
|
||||
{
|
||||
class LoadPluginsTask : public Threading::BaseTaskThread
|
||||
{
|
||||
public:
|
||||
PluginManager* Result;
|
||||
Exception::PluginError* Ex_PluginError;
|
||||
Exception::RuntimeError* Ex_RuntimeError;
|
||||
|
||||
protected:
|
||||
const wxString (&m_folders)[PluginId_Count];
|
||||
|
||||
public:
|
||||
LoadPluginsTask( const wxString (&folders)[PluginId_Count] ) :
|
||||
Result( NULL )
|
||||
, Ex_PluginError( NULL )
|
||||
, Ex_RuntimeError( NULL )
|
||||
, m_folders( folders )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~LoadPluginsTask() throw()
|
||||
{
|
||||
BaseTaskThread::Cancel();
|
||||
}
|
||||
|
||||
protected:
|
||||
void Task()
|
||||
{
|
||||
wxGetApp().Ping();
|
||||
Sleep(3);
|
||||
|
||||
try
|
||||
{
|
||||
//throw Exception::PluginError( PluginId_PAD, "This one is for testing the error handler!" );
|
||||
Result = PluginManager_Create( m_folders );
|
||||
}
|
||||
catch( Exception::PluginError& ex )
|
||||
{
|
||||
Result = NULL;
|
||||
Ex_PluginError = new Exception::PluginError( ex );
|
||||
}
|
||||
catch( Exception::RuntimeError& innerEx )
|
||||
{
|
||||
// Runtime errors are typically recoverable, so handle them here
|
||||
// and prep them for re-throw on the main thread.
|
||||
Result = NULL;
|
||||
Ex_RuntimeError = new Exception::RuntimeError(
|
||||
L"A runtime error occurred on the LoadPlugins thread.\n" + innerEx.FormatDiagnosticMessage(),
|
||||
innerEx.FormatDisplayMessage()
|
||||
);
|
||||
}
|
||||
|
||||
// anything else leave unhandled so that the debugger catches it!
|
||||
}
|
||||
};
|
||||
|
||||
m_CoreThread.reset();
|
||||
m_CorePlugins.reset();
|
||||
|
||||
wxString passins[PluginId_Count];
|
||||
|
||||
const PluginInfo* pi = tbl_PluginInfo-1;
|
||||
|
@ -57,29 +121,45 @@ void LoadPlugins()
|
|||
if( passins[pi->id].IsEmpty() || !wxFileExists( passins[pi->id] ) )
|
||||
passins[pi->id] = g_Conf->FullpathTo( pi->id );
|
||||
}
|
||||
|
||||
LoadPluginsTask task( passins );
|
||||
task.Start();
|
||||
task.PostTask();
|
||||
task.WaitForResult();
|
||||
|
||||
if( task.Result == NULL )
|
||||
{
|
||||
if( task.Ex_PluginError != NULL )
|
||||
throw *task.Ex_PluginError;
|
||||
if( task.Ex_RuntimeError != NULL )
|
||||
throw *task.Ex_RuntimeError; // Re-Throws generic threaded errors
|
||||
}
|
||||
|
||||
g_plugins = PluginManager_Create( passins );
|
||||
m_CorePlugins.reset( task.Result );
|
||||
}
|
||||
|
||||
void InitPlugins()
|
||||
// Posts a message to the App to reload plugins. Plugins are loaded via a background thread
|
||||
// which is started on a pending event, so don't expect them to be ready "right now."
|
||||
void LoadPluginsPassive()
|
||||
{
|
||||
if( g_plugins == NULL )
|
||||
LoadPlugins();
|
||||
|
||||
GetPluginManager().Init();
|
||||
wxCommandEvent evt( pxEVT_ReloadPlugins );
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
}
|
||||
|
||||
// All plugins except the CDVD are opened here. The CDVD must be opened manually by
|
||||
// the GUI, depending on the user's menu/config in use.
|
||||
//
|
||||
// Exceptions:
|
||||
// PluginFailure - if any plugin fails to initialize or open.
|
||||
// ThreadCreationError - If the MTGS thread fails to be created.
|
||||
//
|
||||
void OpenPlugins()
|
||||
// Blocks until plugins have been successfully loaded, or throws an exception if
|
||||
// the user cancels the loading procedure after error.
|
||||
void LoadPluginsImmediate()
|
||||
{
|
||||
if( g_plugins == NULL )
|
||||
InitPlugins();
|
||||
wxASSERT( wxThread::IsMain() );
|
||||
|
||||
GetPluginManager().Open();
|
||||
static int _reentrant = 0;
|
||||
EntryGuard guard( _reentrant );
|
||||
|
||||
wxASSERT( !guard.IsReentrant() );
|
||||
wxGetApp().ReloadPlugins();
|
||||
}
|
||||
|
||||
void UnloadPlugins()
|
||||
{
|
||||
wxGetApp().m_CorePlugins.reset();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ bool States_isSlotUsed(int num)
|
|||
if (ElfCRC == 0)
|
||||
return false;
|
||||
else
|
||||
return wxFileExists( SaveState::GetFilename( num ) );
|
||||
return wxFileExists( SaveStateBase::GetFilename( num ) );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -62,12 +62,12 @@ void States_Load( const wxString& file )
|
|||
StateRecovery::Recover();
|
||||
}
|
||||
|
||||
SysExecute( new AppEmuThread() );
|
||||
wxGetApp().SysExecute();
|
||||
}
|
||||
|
||||
void States_Load(int num)
|
||||
{
|
||||
wxString file( SaveState::GetFilename( num ) );
|
||||
wxString file( SaveStateBase::GetFilename( num ) );
|
||||
|
||||
if( !wxFileExists( file ) )
|
||||
{
|
||||
|
@ -120,79 +120,5 @@ void States_Save( const wxString& file )
|
|||
void States_Save(int num)
|
||||
{
|
||||
Console::Status( "Saving savestate to slot %d...", num );
|
||||
States_Save( SaveState::GetFilename( num ) );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
void vSyncDebugStuff( uint frame )
|
||||
{
|
||||
#ifdef OLD_TESTBUILD_STUFF
|
||||
if( g_TestRun.enabled && g_TestRun.frame > 0 ) {
|
||||
if( frame > g_TestRun.frame ) {
|
||||
// take a snapshot
|
||||
if( g_TestRun.pimagename != NULL && GSmakeSnapshot2 != NULL ) {
|
||||
if( g_TestRun.snapdone ) {
|
||||
g_TestRun.curimage++;
|
||||
g_TestRun.snapdone = 0;
|
||||
g_TestRun.frame += 20;
|
||||
if( g_TestRun.curimage >= g_TestRun.numimages ) {
|
||||
// exit
|
||||
g_EmuThread->Cancel();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// query for the image
|
||||
GSmakeSnapshot2(g_TestRun.pimagename, &g_TestRun.snapdone, g_TestRun.jpgcapture);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// exit
|
||||
g_EmuThread->Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GSVSYNC();
|
||||
|
||||
if( g_SaveGSStream == 1 ) {
|
||||
freezeData fP;
|
||||
|
||||
g_SaveGSStream = 2;
|
||||
g_fGSSave->gsFreeze();
|
||||
|
||||
if (GSfreeze(FREEZE_SIZE, &fP) == -1) {
|
||||
safe_delete( g_fGSSave );
|
||||
g_SaveGSStream = 0;
|
||||
}
|
||||
else {
|
||||
fP.data = (s8*)malloc(fP.size);
|
||||
if (fP.data == NULL) {
|
||||
safe_delete( g_fGSSave );
|
||||
g_SaveGSStream = 0;
|
||||
}
|
||||
else {
|
||||
if (GSfreeze(FREEZE_SAVE, &fP) == -1) {
|
||||
safe_delete( g_fGSSave );
|
||||
g_SaveGSStream = 0;
|
||||
}
|
||||
else {
|
||||
g_fGSSave->Freeze( fP.size );
|
||||
if (fP.size) {
|
||||
g_fGSSave->FreezeMem( fP.data, fP.size );
|
||||
free(fP.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( g_SaveGSStream == 2 ) {
|
||||
|
||||
if( --g_nLeftGSFrames <= 0 ) {
|
||||
safe_delete( g_fGSSave );
|
||||
g_SaveGSStream = 0;
|
||||
Console::WriteLn("Done saving GS stream");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
States_Save( SaveStateBase::GetFilename( num ) );
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "Utilities/HashMap.h"
|
||||
#include "wxHelpers.h"
|
||||
|
||||
#include <wx/cshelp.h>
|
||||
|
@ -276,12 +277,21 @@ void pxTextWrapperBase::Wrap( const wxWindow *win, const wxString& text, int wid
|
|||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
HashTools::HashMap< wxWindowID, int > m_DialogIdents( 0, wxID_ANY );
|
||||
|
||||
bool pxDialogExists( wxWindowID id )
|
||||
{
|
||||
int dest = 0;
|
||||
m_DialogIdents.TryGetValue( id, dest );
|
||||
return (dest > 0);
|
||||
}
|
||||
|
||||
wxDialogWithHelpers::wxDialogWithHelpers( wxWindow* parent, int id, const wxString& title, bool hasContextHelp, const wxPoint& pos, const wxSize& size ) :
|
||||
wxDialog( parent, id, title, pos, size , wxDEFAULT_DIALOG_STYLE), //, (wxCAPTION | wxMAXIMIZE | wxCLOSE_BOX | wxRESIZE_BORDER) ), // flags for resizable dialogs, currently unused.
|
||||
m_hasContextHelp( hasContextHelp )
|
||||
{
|
||||
++m_DialogIdents[GetId()];
|
||||
|
||||
if( hasContextHelp )
|
||||
wxHelpProvider::Set( new wxSimpleHelpProvider() );
|
||||
|
||||
|
@ -291,6 +301,12 @@ wxDialogWithHelpers::wxDialogWithHelpers( wxWindow* parent, int id, const wxStr
|
|||
// any good.
|
||||
}
|
||||
|
||||
wxDialogWithHelpers::~wxDialogWithHelpers()
|
||||
{
|
||||
--m_DialogIdents[GetId()];
|
||||
wxASSERT( m_DialogIdents[GetId()] >= 0 );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Creates a new checkbox and adds it to the specified sizer/parent combo, with optional tooltip.
|
||||
// Uses the default spacer setting for adding checkboxes, and the tooltip (if specified) is applied
|
||||
|
|
|
@ -55,6 +55,7 @@ protected:
|
|||
|
||||
public:
|
||||
wxDialogWithHelpers(wxWindow* parent, int id, const wxString& title, bool hasContextHelp, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize );
|
||||
virtual ~wxDialogWithHelpers() throw();
|
||||
|
||||
wxCheckBox& AddCheckBox( wxSizer& sizer, const wxString& label, const wxString& subtext=wxEmptyString, const wxString& tooltip=wxEmptyString );
|
||||
wxStaticText& AddStaticText(wxSizer& sizer, const wxString& label, int alignFlags=wxALIGN_CENTRE, int size=wxDefaultCoord );
|
||||
|
@ -88,3 +89,6 @@ protected:
|
|||
m_StartNewRadioGroup = true;
|
||||
}
|
||||
};
|
||||
|
||||
extern bool pxDialogExists( wxWindowID id );
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 245 KiB |
|
@ -235,7 +235,7 @@ bool IsBIOS(const wxString& filename, wxString& description)
|
|||
romver[12], romver[13], // day
|
||||
romver[10], romver[11], // month
|
||||
romver[6], romver[7], romver[8], romver[9], // year!
|
||||
(aROMVER[5]=='C') ? L"Console" : (aROMVER[5]=='D') ? L"Devel" : L""
|
||||
(aROMVER[5]=='C') ? L"Console" : (aROMVER[5]=='D') ? L"Devel" : wxEmptyString
|
||||
);
|
||||
found = true;
|
||||
}
|
||||
|
|
|
@ -35,10 +35,10 @@ CoreEmuThread& CoreEmuThread::Get()
|
|||
|
||||
void CoreEmuThread::CpuInitializeMess()
|
||||
{
|
||||
GetPluginManager().Open();
|
||||
m_plugins.Open();
|
||||
cpuReset();
|
||||
SysClearExecutionCache();
|
||||
GetPluginManager().Open();
|
||||
m_plugins.Open();
|
||||
|
||||
if( StateRecovery::HasState() )
|
||||
{
|
||||
|
@ -133,53 +133,61 @@ sptr CoreEmuThread::ExecuteTask()
|
|||
|
||||
void CoreEmuThread::StateCheck()
|
||||
{
|
||||
ScopedLock locker( m_lock_ExecMode );
|
||||
|
||||
switch( m_ExecMode )
|
||||
{
|
||||
case ExecMode_NoThreadYet:
|
||||
case ExecMode_Idle:
|
||||
// threads should never have an idle execution state set while the
|
||||
// thread is in any way active or alive.
|
||||
DevAssert( false, "Invalid execution state detected." );
|
||||
break;
|
||||
|
||||
// These are not the case statements you're looking for. Move along.
|
||||
case ExecMode_Running:
|
||||
pthread_testcancel();
|
||||
break;
|
||||
|
||||
case ExecMode_Suspending:
|
||||
{
|
||||
ScopedLock locker( m_lock_ExecMode );
|
||||
m_plugins.Close();
|
||||
m_ExecMode = ExecMode_Suspended;
|
||||
m_SuspendEvent.Post();
|
||||
}
|
||||
}
|
||||
// fall through...
|
||||
|
||||
case ExecMode_Suspended:
|
||||
m_lock_ExecMode.Unlock();
|
||||
while( m_ExecMode == ExecMode_Suspended )
|
||||
m_ResumeEvent.WaitGui();
|
||||
|
||||
m_plugins.Open();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CoreEmuThread::CoreEmuThread() :
|
||||
m_ExecMode( ExecMode_Idle )
|
||||
, m_ResumeEvent()
|
||||
, m_SuspendEvent()
|
||||
CoreEmuThread::CoreEmuThread( PluginManager& plugins ) :
|
||||
m_ExecMode( ExecMode_NoThreadYet )
|
||||
, m_lock_ExecMode()
|
||||
|
||||
, m_resetRecompilers( false )
|
||||
, m_resetProfilers( false )
|
||||
|
||||
, m_lock_ExecMode()
|
||||
, m_plugins( plugins )
|
||||
, m_ResumeEvent()
|
||||
, m_SuspendEvent()
|
||||
|
||||
{
|
||||
PersistentThread::Start();
|
||||
}
|
||||
|
||||
// Invoked by the pthread_exit or pthread_cancel
|
||||
void CoreEmuThread::DoThreadCleanup()
|
||||
{
|
||||
GetPluginManager().Close();
|
||||
m_plugins.Shutdown();
|
||||
PersistentThread::DoThreadCleanup();
|
||||
}
|
||||
|
||||
CoreEmuThread::~CoreEmuThread()
|
||||
CoreEmuThread::~CoreEmuThread() throw()
|
||||
{
|
||||
PersistentThread::Cancel();
|
||||
}
|
||||
|
@ -187,13 +195,26 @@ CoreEmuThread::~CoreEmuThread()
|
|||
// Resumes the core execution state, or does nothing is the core is already running. If
|
||||
// settings were changed, resets will be performed as needed and emulation state resumed from
|
||||
// memory savestates.
|
||||
//
|
||||
// Exceptions (can occur on first call only):
|
||||
// PluginInitError - thrown if a plugin fails init (init is performed on the current thread
|
||||
// on the first time the thread is resumed from it's initial idle state)
|
||||
// ThreadCreationError - Insufficient system resources to create thread.
|
||||
//
|
||||
void CoreEmuThread::Resume()
|
||||
{
|
||||
if( IsSelf() || !IsRunning() ) return;
|
||||
|
||||
if( IsSelf() ) return;
|
||||
|
||||
{
|
||||
ScopedLock locker( m_lock_ExecMode );
|
||||
|
||||
if( m_ExecMode == ExecMode_NoThreadYet )
|
||||
{
|
||||
m_plugins.Init();
|
||||
Start();
|
||||
m_ExecMode = ExecMode_Idle;
|
||||
}
|
||||
|
||||
if( m_ExecMode == ExecMode_Running )
|
||||
return;
|
||||
|
||||
|
|
|
@ -19,14 +19,15 @@
|
|||
|
||||
using namespace Threading;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CoreEmuThread
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CoreEmuThread class
|
||||
// --------------------------------------------------------------------------------------
|
||||
class CoreEmuThread : public PersistentThread
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
enum ExecutionMode
|
||||
{
|
||||
ExecMode_NoThreadYet,
|
||||
ExecMode_Idle,
|
||||
ExecMode_Running,
|
||||
ExecMode_Suspending,
|
||||
|
@ -34,22 +35,22 @@ public:
|
|||
};
|
||||
|
||||
protected:
|
||||
volatile ExecutionMode m_ExecMode;
|
||||
volatile ExecutionMode m_ExecMode;
|
||||
MutexLock m_lock_ExecMode;
|
||||
|
||||
Semaphore m_ResumeEvent;
|
||||
Semaphore m_SuspendEvent;
|
||||
|
||||
bool m_resetRecompilers;
|
||||
bool m_resetProfilers;
|
||||
bool m_resetRecompilers;
|
||||
bool m_resetProfilers;
|
||||
|
||||
MutexLock m_lock_ExecMode;
|
||||
PluginManager& m_plugins;
|
||||
Semaphore m_ResumeEvent;
|
||||
Semaphore m_SuspendEvent;
|
||||
|
||||
public:
|
||||
static CoreEmuThread& Get();
|
||||
|
||||
public:
|
||||
explicit CoreEmuThread();
|
||||
virtual ~CoreEmuThread();
|
||||
explicit CoreEmuThread( PluginManager& plugins );
|
||||
virtual ~CoreEmuThread() throw();
|
||||
|
||||
bool IsSuspended() const { return (m_ExecMode == ExecMode_Suspended); }
|
||||
virtual void Suspend( bool isBlocking = true );
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets=".\vsprops\common.vsprops;..\..\..\common\vsprops\BaseProperties.vsprops;..\..\..\common\vsprops\3rdpartyDeps.vsprops;..\..\..\common\vsprops\pthreads.vsprops;.\vsprops\devbuild.vsprops;..\..\..\common\vsprops\CodeGen_Debug.vsprops;..\..\..\common\vsprops\IncrementalLinking.vsprops"
|
||||
UseOfMFC="0"
|
||||
|
|
|
@ -212,8 +212,8 @@ Global
|
|||
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.Build.0 = Release|Win32
|
||||
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|x64.ActiveCfg = Release|Win32
|
||||
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.ActiveCfg = Debug SSE2|Win32
|
||||
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.Build.0 = Debug SSE2|Win32
|
||||
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.ActiveCfg = Debug SSE4|Win32
|
||||
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|Win32.Build.0 = Debug SSE4|Win32
|
||||
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Devel|Win32.ActiveCfg = Release SSE2|Win32
|
||||
{18E42F6F-3A62-41EE-B42F-79366C4F1E95}.Devel|Win32.Build.0 = Release SSE2|Win32
|
||||
|
|
|
@ -1109,12 +1109,9 @@ __declspec(align(16)) struct GIFPath
|
|||
{
|
||||
if((++reg & 0xf) == nreg)
|
||||
{
|
||||
reg = 0;
|
||||
|
||||
reg = 0;
|
||||
if(--nloop == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\$(ProjectName)-$(SSEtype)-dbg.dll"
|
||||
ModuleDefinitionFile=".\GSdx.def"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
|
@ -119,7 +120,6 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\$(ProjectName)-$(SSEtype).dll"
|
||||
ModuleDefinitionFile=".\GSdx.def"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
|
@ -245,7 +245,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\$(ProjectName)-$(SSEtype).dll"
|
||||
OutputFile="$(OutDir)\$(ProjectName)-$(SSEtype)-dbg.dll"
|
||||
ModuleDefinitionFile=".\GSdx.def"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
|
@ -308,6 +308,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\$(ProjectName)-$(SSEtype)-dbg.dll"
|
||||
ModuleDefinitionFile=".\GSdx.def"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
|
@ -371,7 +372,6 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\$(ProjectName)-$(SSEtype).dll"
|
||||
ModuleDefinitionFile=".\GSdx.def"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
|
|
Loading…
Reference in New Issue