mirror of https://github.com/PCSX2/pcsx2.git
(work in progress -- some of this stuff still doesn't quite work as it should)
* Rewrote Savestate code, fixed lots of stuff in PersistentThread, and renamed most "Emu"s to "Sys". * Removed wxScopedPtr and whipped up our own ScopedPtr that doesn't use boost's fail-style function names (and made it more thread-safe). * Handling exceptions across threads: Added Clone() and Rethrow() methods to BaseException, and added a Rethrow() to PersistentThread. * Go rid of AppInvoke macros (those were nasty!) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1929 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
893fcebf52
commit
15d2824d1b
|
@ -105,23 +105,30 @@ typedef s32 sptr;
|
|||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// A rough-and-ready cross platform 128-bit datatype, Non-SSE style.
|
||||
//
|
||||
// Note: These structs do not provide any additional constructors because C++ can't allow
|
||||
// the use of dataypes with constructors in unions (and since unions are ont of the primary
|
||||
// uses of these types, that measn we can't have constructors). Embedded functions for
|
||||
// performing explicity conversion from 64 and 32 bit values is provided instead.
|
||||
//
|
||||
#ifdef __cplusplus
|
||||
struct u128
|
||||
{
|
||||
u64 lo;
|
||||
u64 hi;
|
||||
|
||||
// Implicit conversion from u64
|
||||
u128( u64 src ) :
|
||||
lo( src )
|
||||
, hi( 0 ) {}
|
||||
// Explicit conversion from u64
|
||||
static u128 From64( u64 src )
|
||||
{
|
||||
u128 retval = { src, 0 };
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Implicit conversion from u32
|
||||
u128( u32 src ) :
|
||||
lo( src )
|
||||
, hi( 0 ) {}
|
||||
|
||||
u128() {}
|
||||
// Explicit conversion from u32
|
||||
static u128 From32( u32 src )
|
||||
{
|
||||
u128 retval = { src, 0 };
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
|
||||
struct s128
|
||||
|
@ -129,17 +136,19 @@ struct s128
|
|||
s64 lo;
|
||||
s64 hi;
|
||||
|
||||
// Implicit conversion from u64
|
||||
s128( s64 src ) :
|
||||
lo( src )
|
||||
, hi( 0 ) {}
|
||||
// explicit conversion from s64, with sign extension.
|
||||
static s128 From64( s64 src )
|
||||
{
|
||||
s128 retval = { src, (src < 0) ? -1 : 0 };
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Implicit conversion from u32
|
||||
s128( s32 src ) :
|
||||
lo( src )
|
||||
, hi( 0 ) {}
|
||||
|
||||
s128() {}
|
||||
// explicit conversion from s32, with sign extension.
|
||||
static s128 From64( s32 src )
|
||||
{
|
||||
s128 retval = { src, (src < 0) ? -1 : 0 };
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
|
|
@ -47,6 +47,8 @@ extern bool DevAssert( bool condition, const char* msg );
|
|||
|
||||
namespace Exception
|
||||
{
|
||||
int MakeNewType();
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseException
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -87,6 +89,9 @@ namespace Exception
|
|||
// Returns a message suitable for end-user display.
|
||||
// This message is usually meant for display in a user popup or such.
|
||||
virtual wxString FormatDisplayMessage() const { return m_message_user; }
|
||||
|
||||
virtual void Rethrow() const=0;
|
||||
virtual BaseException* Clone() const=0;
|
||||
|
||||
protected:
|
||||
// Construction using two pre-formatted pre-translated messages
|
||||
|
@ -129,7 +134,9 @@ namespace Exception
|
|||
// it will be optionally translated.
|
||||
//
|
||||
#define DEFINE_EXCEPTION_COPYTORS( classname ) \
|
||||
virtual ~classname() throw() {}
|
||||
virtual ~classname() throw() {} \
|
||||
virtual void Rethrow() const { throw classname( *this ); } \
|
||||
virtual BaseException* Clone() const { return new classname( *this ); }
|
||||
|
||||
#define DEFINE_RUNTIME_EXCEPTION( classname, defmsg ) \
|
||||
DEFINE_EXCEPTION_COPYTORS( classname ) \
|
||||
|
@ -161,7 +168,7 @@ namespace Exception
|
|||
DEFINE_LOGIC_EXCEPTION( LogicError, wxLt("An unhandled logic error has occurred.") )
|
||||
};
|
||||
|
||||
class ObjectIsNull : public RuntimeError
|
||||
class ObjectIsNull : public virtual RuntimeError
|
||||
{
|
||||
public:
|
||||
wxString ObjectName;
|
||||
|
|
|
@ -33,27 +33,33 @@ extern void pcsx2_aligned_free(void* pmem);
|
|||
// pointer to null after deallocation.
|
||||
|
||||
#define safe_delete( ptr ) \
|
||||
((void) (delete ptr), ptr = NULL)
|
||||
((void) (delete (ptr)), (ptr) = NULL)
|
||||
|
||||
#define safe_delete_array( ptr ) \
|
||||
((void) (delete[] ptr), ptr = NULL)
|
||||
((void) (delete[] (ptr)), (ptr) = NULL)
|
||||
|
||||
// fixme: I'm pretty sure modern libc implementations under gcc and msvc check null status
|
||||
// inside free(), meaning we shouldn't have to do it ourselves. But legacy implementations
|
||||
// didn't always check, so best to be cautious unless absolutely certain it's being covered on
|
||||
// all ported platforms.
|
||||
#define safe_free( ptr ) \
|
||||
((void) (( ( ptr != NULL ) && (free( ptr ), !!0) ), ptr = NULL))
|
||||
((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL))
|
||||
|
||||
#define safe_fclose( ptr ) \
|
||||
((void) (( ( (ptr) != NULL ) && (fclose( ptr ), !!0) ), (ptr) = NULL))
|
||||
|
||||
// Implementation note: all known implementations of _aligned_free check the pointer for
|
||||
// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to
|
||||
// do it here.
|
||||
#define safe_aligned_free( ptr ) \
|
||||
((void) ( _aligned_free( ptr ), ptr = NULL ))
|
||||
((void) ( _aligned_free( ptr ), (ptr) = NULL ))
|
||||
|
||||
#define SafeSysMunmap( ptr, size ) \
|
||||
((void) ( HostSys::Munmap( (uptr)ptr, size ), ptr = NULL ))
|
||||
((void) ( HostSys::Munmap( (uptr)(ptr), size ), (ptr) = NULL ))
|
||||
|
||||
// Microsoft Windows only macro, useful for freeing out COM objects:
|
||||
#define safe_release( ptr ) \
|
||||
((void) (( ( (ptr) != NULL ) && ((ptr)->Release(), !!0) ), (ptr) = NULL))
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Handy little class for allocating a resizable memory block, complete with
|
||||
|
|
|
@ -1,4 +1,210 @@
|
|||
#pragma once
|
||||
|
||||
#include <wx/scopedptr.h>
|
||||
#include <wx/scopedarray.h>
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedPtr
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template< typename T >
|
||||
class ScopedPtr
|
||||
{
|
||||
DeclareNoncopyableObject(ScopedPtr);
|
||||
|
||||
protected:
|
||||
T* m_ptr;
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
wxEXPLICIT ScopedPtr(T * ptr = NULL) : m_ptr(ptr) { }
|
||||
|
||||
~ScopedPtr()
|
||||
{ Delete(); }
|
||||
|
||||
ScopedPtr& Reassign(T * ptr = NULL)
|
||||
{
|
||||
if ( ptr != m_ptr )
|
||||
{
|
||||
Delete();
|
||||
m_ptr = ptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ScopedPtr& Delete()
|
||||
{
|
||||
// Thread-safe deletion: Set the pointer to NULL first, and then issue
|
||||
// the deletion. This allows pending Application messages that might be
|
||||
// dependent on the current object to nullify their actions.
|
||||
|
||||
T* deleteme = m_ptr;
|
||||
m_ptr = NULL;
|
||||
delete deleteme;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Removes the pointer from scoped management, but does not delete!
|
||||
T *DetachPtr()
|
||||
{
|
||||
T *ptr = m_ptr;
|
||||
m_ptr = NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Returns the managed pointer. Can return NULL as a valid result if the ScopedPtr
|
||||
// has no object in management.
|
||||
T* GetPtr() const
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
void SwapPtr(ScopedPtr& other)
|
||||
{
|
||||
T * const tmp = other.m_ptr;
|
||||
other.m_ptr = m_ptr;
|
||||
m_ptr = tmp;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ScopedPtr Operators
|
||||
// ----------------------------------------------------------------------------
|
||||
// I've decided to use the ATL's approach to pointer validity tests, opposed to
|
||||
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't
|
||||
// allow the T* implicit casting.
|
||||
|
||||
bool operator!() const throw()
|
||||
{
|
||||
return m_ptr == NULL;
|
||||
}
|
||||
|
||||
operator T*() const
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
// Equality
|
||||
bool operator==(T* pT) const throw()
|
||||
{
|
||||
return m_ptr == pT;
|
||||
}
|
||||
|
||||
// Inequality
|
||||
bool operator!=(T* pT) const throw()
|
||||
{
|
||||
return !operator==(pT);
|
||||
}
|
||||
|
||||
// Convenient assignment operator. ScopedPtr = NULL will issue an automatic deletion
|
||||
// of the managed pointer.
|
||||
ScopedPtr& operator=( T* src )
|
||||
{
|
||||
return Reassign( src );
|
||||
}
|
||||
|
||||
// Dereference operator, returns a handle to the managed pointer.
|
||||
// Generates a debug assertion if the object is NULL!
|
||||
T& operator*() const
|
||||
{
|
||||
wxASSERT(m_ptr != NULL);
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
wxASSERT(m_ptr != NULL);
|
||||
return m_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxObjPtr -- fancified version of wxScopedPtr
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is a non-null scoped pointer container. What that means is that the object
|
||||
// always resets itself to a valid "placebo" function rather than NULL, such that methods
|
||||
// can be invoked safely without fear of NULL pointer exceptions. This system is useful
|
||||
// for objects where most or all public methods can fail silently, and still allow program
|
||||
// execution flow to continue.
|
||||
//
|
||||
// It also implements basic scoped pointer behavior: when the pxObjPtr class is deleted,
|
||||
// it will automatically delete the pointer in its posession, if the pointer is valid.
|
||||
//
|
||||
// Notes:
|
||||
// * This class intentionally does not implement the "release" API, because it doesn't
|
||||
// really make sense within the context of a non-nullable pointer specification.
|
||||
//
|
||||
template< typename T, T& DefaultStaticInst >
|
||||
class pxObjPtr
|
||||
{
|
||||
DeclareNoncopyableObject(pxObjPtr);
|
||||
|
||||
protected:
|
||||
T * m_ptr;
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
explicit pxObjPtr(T * ptr = &DefaultStaticInst) : m_ptr(ptr) { }
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return m_ptr != &DefaultStaticInst;
|
||||
}
|
||||
|
||||
~pxObjPtr()
|
||||
{
|
||||
if( !IsEmpty() ) delete m_ptr;
|
||||
m_ptr = NULL;
|
||||
}
|
||||
|
||||
// test for pointer validity: defining conversion to unspecified_bool_type
|
||||
// and not more obvious bool to avoid implicit conversions to integer types
|
||||
typedef T *(pxObjPtr<T,DefaultStaticInst>::*unspecified_bool_type)() const;
|
||||
|
||||
operator unspecified_bool_type() const
|
||||
{
|
||||
return ( !IsEmpty() ) ? &pxScopedPtr<T>::get : NULL;
|
||||
}
|
||||
|
||||
void reset(T * ptr = &DefaultStaticInst)
|
||||
{
|
||||
if ( ptr != m_ptr )
|
||||
{
|
||||
if( !IsEmpty() )
|
||||
delete m_ptr;
|
||||
m_ptr = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
T& operator*() const
|
||||
{
|
||||
wxASSERT(m_ptr != NULL);
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
wxASSERT(m_ptr != NULL);
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
wxASSERT(m_ptr != NULL);
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
void swap(pxObjPtr& other)
|
||||
{
|
||||
// Neither pointer in either container should ever be NULL...
|
||||
wxASSERT(m_ptr != NULL);
|
||||
wxASSERT(other.m_ptr != NULL);
|
||||
|
||||
T * const tmp = other.m_ptr;
|
||||
other.m_ptr = m_ptr;
|
||||
m_ptr = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <semaphore.h>
|
||||
|
||||
#include "Pcsx2Defs.h"
|
||||
#include "ScopedPtr.h"
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
|
@ -87,6 +88,7 @@ namespace Threading
|
|||
|
||||
void Lock();
|
||||
void Unlock();
|
||||
bool TryLock();
|
||||
};
|
||||
|
||||
// Returns the number of available logical CPUs (cores plus hyperthreaded cpus)
|
||||
|
@ -101,55 +103,94 @@ namespace Threading
|
|||
// sleeps the current thread for the given number of milliseconds.
|
||||
extern void Sleep( int ms );
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PersistentThread - Helper class for the basics of starting/managing persistent threads.
|
||||
//
|
||||
// Use this as a base class for your threaded procedure, and implement the 'int ExecuteTask()'
|
||||
// method. Use Start() and Cancel() to start and shutdown the thread, and use m_sem_event
|
||||
// internally to post/receive events for the thread (make a public accessor for it in your
|
||||
// derived class if your thread utilizes the post).
|
||||
//
|
||||
// Notes:
|
||||
// * Constructing threads as static global vars isn't recommended since it can potentially
|
||||
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
||||
// no dependency options for ensuring correct static var initializations). Use heap
|
||||
// allocation to create thread objects instead.
|
||||
//
|
||||
class PersistentThread
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IThread - Interface for the public access to PersistentThread.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Class usage: Can be used for allowing safe nullification of a thread handle. Rather
|
||||
// than being NULL'd, the handle can be mapped to an IThread implementation which acts
|
||||
// as a do-nothing placebo or an assertion generator.
|
||||
//
|
||||
class IThread
|
||||
{
|
||||
DeclareNoncopyableObject(IThread);
|
||||
|
||||
public:
|
||||
IThread() {}
|
||||
virtual ~IThread() throw() {}
|
||||
|
||||
virtual bool IsSelf() const { return false; }
|
||||
virtual bool IsRunning() { return false; }
|
||||
virtual int GetReturnCode() const
|
||||
{
|
||||
DevAssert( false, "Cannot obtain a return code from a placebo thread." );
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void Start() {}
|
||||
virtual void Cancel( bool isBlocking = true ) {}
|
||||
virtual sptr Block() { return NULL; }
|
||||
virtual bool Detach() { return false; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PersistentThread - Helper class for the basics of starting/managing persistent threads.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Use this as a base class for your threaded procedure, and implement the 'int ExecuteTask()'
|
||||
// method. Use Start() and Cancel() to start and shutdown the thread, and use m_sem_event
|
||||
// internally to post/receive events for the thread (make a public accessor for it in your
|
||||
// derived class if your thread utilizes the post).
|
||||
//
|
||||
// Notes:
|
||||
// * Constructing threads as static global vars isn't recommended since it can potentially
|
||||
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
||||
// no dependency options for ensuring correct static var initializations). Use heap
|
||||
// allocation to create thread objects instead.
|
||||
//
|
||||
class PersistentThread : public virtual IThread
|
||||
{
|
||||
DeclareNoncopyableObject(PersistentThread);
|
||||
|
||||
protected:
|
||||
typedef int (*PlainJoeFP)();
|
||||
|
||||
wxString m_name; // diagnostic name for our thread.
|
||||
|
||||
pthread_t m_thread;
|
||||
Semaphore m_sem_event; // general wait event that's needed by most threads.
|
||||
Semaphore m_sem_finished; // used for canceling and closing threads in a deadlock-safe manner
|
||||
MutexLock m_lock_start; // used to lock the Start() code from starting simutaneous threads accidentally.
|
||||
sptr m_returncode; // value returned from the thread on close.
|
||||
|
||||
|
||||
volatile long m_detached; // a boolean value which indicates if the m_thread handle is valid
|
||||
volatile long m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
|
||||
|
||||
// exception handle, set non-NULL if the thread terminated with an exception
|
||||
// Use RethrowException() to re-throw the exception using its original exception type.
|
||||
ScopedPtr<Exception::BaseException> m_except;
|
||||
|
||||
public:
|
||||
virtual ~PersistentThread() throw();
|
||||
PersistentThread();
|
||||
PersistentThread( const char* name );
|
||||
|
||||
virtual void Start();
|
||||
virtual void Cancel( bool isBlocking = true );
|
||||
virtual void Detach();
|
||||
|
||||
// Gets the return code of the thread.
|
||||
// Throws std::logic_error if the thread has not terminated.
|
||||
virtual int GetReturnCode() const;
|
||||
|
||||
virtual bool IsRunning() const;
|
||||
virtual bool Detach();
|
||||
virtual sptr Block();
|
||||
|
||||
|
||||
virtual int GetReturnCode() const;
|
||||
virtual void RethrowException() const;
|
||||
|
||||
bool IsRunning() const;
|
||||
bool IsSelf() const;
|
||||
wxString GetName() const;
|
||||
|
||||
virtual void DoThreadCleanup();
|
||||
|
||||
protected:
|
||||
void SetName( __unused const char* name );
|
||||
void DoSetThreadName( const wxString& name );
|
||||
void DoSetThreadName( __unused const char* name );
|
||||
void _internal_execute();
|
||||
|
||||
// Used to dispatch the thread callback function.
|
||||
// (handles some thread cleanup on Win32, and is basically a typecast
|
||||
|
@ -159,7 +200,7 @@ namespace Threading
|
|||
// Implemented by derived class to handle threading actions!
|
||||
virtual sptr ExecuteTask()=0;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ScopedLock: Helper class for using Mutexes.
|
||||
// Using this class provides an exception-safe (and generally clean) method of locking
|
||||
|
|
|
@ -17,17 +17,19 @@
|
|||
|
||||
#include "Dependencies.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------
|
||||
// wxBaseTools.h
|
||||
//
|
||||
// This file is meant to contain utility classes for users of the wxWidgets library.
|
||||
// All classes in this file are strictly dependent on wxBase libraries only, meaning
|
||||
// you don't need to include or link against wxCore (GUI) to build them. For tools
|
||||
// which require wxCore, see wxGuiTools.h
|
||||
// ----------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// wxDoNotLogInThisScope
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// wxDoNotLogInThisScope
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is used to disable wx's sometimes inappropriate amount of forced error logging
|
||||
// during specific activities. For example, when using wxDynamicLibrary to detect the
|
||||
// validity of DLLs, wx will log errors for missing symbols. (sigh)
|
||||
|
@ -54,3 +56,35 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// wxToUTF8 - shortcut for str.ToUTF8().data()
|
||||
// --------------------------------------------------------------------------------------
|
||||
class wxToUTF8
|
||||
{
|
||||
DeclareNoncopyableObject( wxToUTF8 );
|
||||
|
||||
protected:
|
||||
wxCharBuffer m_charbuffer;
|
||||
|
||||
public:
|
||||
wxToUTF8( const wxString& str ) : m_charbuffer( str.ToUTF8().data() ) { }
|
||||
virtual ~wxToUTF8() throw() {}
|
||||
|
||||
operator const char*() { return m_charbuffer.data(); }
|
||||
};
|
||||
|
||||
// This class provided for completeness sake. You probably should use ToUTF8 instead.
|
||||
class wxToAscii
|
||||
{
|
||||
DeclareNoncopyableObject( wxToAscii );
|
||||
|
||||
protected:
|
||||
wxCharBuffer m_charbuffer;
|
||||
|
||||
public:
|
||||
wxToAscii( const wxString& str ) : m_charbuffer( str.ToAscii().data() ) { }
|
||||
virtual ~wxToAscii() throw() {}
|
||||
|
||||
operator const char*() { return m_charbuffer.data(); }
|
||||
};
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "Threading.h"
|
||||
#include "wxBaseTools.h"
|
||||
|
||||
#include <wx/datetime.h>
|
||||
#include <wx/thread.h>
|
||||
|
@ -37,11 +38,13 @@ namespace Threading
|
|||
}
|
||||
|
||||
PersistentThread::PersistentThread() :
|
||||
m_thread()
|
||||
m_name( L"PersistentThread" )
|
||||
, m_thread()
|
||||
, m_sem_event()
|
||||
, m_sem_finished()
|
||||
, m_lock_start( true ) // recursive mutexing!
|
||||
, m_returncode( 0 )
|
||||
, m_detached( false )
|
||||
, m_detached( true ) // start out with m_thread in detached/invalid state
|
||||
, m_running( false )
|
||||
{
|
||||
}
|
||||
|
@ -53,40 +56,42 @@ namespace Threading
|
|||
// your sister, and then cheating on her with your daughter.
|
||||
PersistentThread::~PersistentThread() throw()
|
||||
{
|
||||
if( !m_running ) return;
|
||||
|
||||
wxASSERT( !IsSelf() ); // not allowed from our own thread.
|
||||
|
||||
if( !_InterlockedExchange( &m_detached, true ) )
|
||||
if( m_running )
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
m_sem_finished.WaitGui();
|
||||
#else
|
||||
m_sem_finished.Wait();
|
||||
#endif
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
Detach();
|
||||
}
|
||||
|
||||
// This function should not be called from the owner thread.
|
||||
void PersistentThread::Start()
|
||||
{
|
||||
ScopedLock startlock( m_lock_start ); // Prevents sudden parallel startup
|
||||
if( m_running ) return;
|
||||
|
||||
Detach(); // clean up previous thread, if one exists.
|
||||
m_sem_finished.Reset();
|
||||
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
|
||||
throw Exception::ThreadCreationError();
|
||||
|
||||
m_running = true;
|
||||
m_detached = false;
|
||||
}
|
||||
|
||||
// Returns: TRUE if the detachment was performed, or FALSE if the thread was
|
||||
// already detached or isn't running at all.
|
||||
// This function should not be called from the owner thread.
|
||||
void PersistentThread::Detach()
|
||||
bool PersistentThread::Detach()
|
||||
{
|
||||
if( !m_running ) return;
|
||||
if( _InterlockedExchange( &m_detached, true ) ) return;
|
||||
|
||||
wxASSERT( !IsSelf() ); // not allowed from our own thread.
|
||||
|
||||
if( _InterlockedExchange( &m_detached, true ) ) return false;
|
||||
pthread_detach( m_thread );
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remarks:
|
||||
|
@ -102,15 +107,15 @@ namespace Threading
|
|||
//
|
||||
void PersistentThread::Cancel( bool isBlocking )
|
||||
{
|
||||
wxASSERT( !IsSelf() );
|
||||
if( !m_running ) return;
|
||||
|
||||
if( _InterlockedExchange( &m_detached, true ) )
|
||||
if( m_detached )
|
||||
{
|
||||
Console::Notice( "Threading Warning: Attempted to cancel detached thread; Ignoring..." );
|
||||
return;
|
||||
}
|
||||
|
||||
wxASSERT( !IsSelf() );
|
||||
pthread_cancel( m_thread );
|
||||
|
||||
if( isBlocking )
|
||||
|
@ -121,8 +126,6 @@ namespace Threading
|
|||
m_sem_finished.Wait();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
pthread_detach( m_thread );
|
||||
}
|
||||
|
||||
// Blocks execution of the calling thread until this thread completes its task. The
|
||||
|
@ -153,14 +156,10 @@ namespace Threading
|
|||
|
||||
bool PersistentThread::IsRunning() const
|
||||
{
|
||||
if (!m_running) return false;
|
||||
|
||||
if( !!m_detached )
|
||||
return !!m_running;
|
||||
else
|
||||
return ( ESRCH != pthread_kill( m_thread, 0 ) );
|
||||
return !!m_running;
|
||||
}
|
||||
|
||||
// Gets the return code of the thread.
|
||||
// Exceptions:
|
||||
// InvalidOperation - thrown if the thread is still running or has never been started.
|
||||
//
|
||||
|
@ -171,32 +170,95 @@ namespace Threading
|
|||
|
||||
return m_returncode;
|
||||
}
|
||||
|
||||
// Throws an exception if the thread encountered one. Uses the BaseException's Rethrow() method,
|
||||
// which ensures the exception type remains consistent. Debuggable stacktraces will be lost, since
|
||||
// the thread will have allowed itself to terminate properly.
|
||||
void PersistentThread::RethrowException() const
|
||||
{
|
||||
if( !m_except ) return;
|
||||
m_except->Rethrow();
|
||||
}
|
||||
|
||||
// invoked when canceling or exiting the thread.
|
||||
void PersistentThread::DoThreadCleanup()
|
||||
{
|
||||
wxASSERT( IsSelf() ); // only allowed from our own thread, thanks.
|
||||
_InterlockedExchange( &m_running, false );
|
||||
m_running = false;
|
||||
m_sem_finished.Post();
|
||||
}
|
||||
|
||||
wxString PersistentThread::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void PersistentThread::_internal_execute()
|
||||
{
|
||||
m_running = true;
|
||||
DoSetThreadName( m_name );
|
||||
|
||||
try {
|
||||
m_returncode = ExecuteTask();
|
||||
}
|
||||
catch( std::logic_error& ex )
|
||||
{
|
||||
throw Exception::LogicError( wxsFormat( L"(thread: %s) STL Logic Error: %s\n\t%s",
|
||||
GetName().c_str(), wxString::FromUTF8( ex.what() ) )
|
||||
);
|
||||
}
|
||||
catch( Exception::LogicError& ex )
|
||||
{
|
||||
m_except->DiagMsg() = wxsFormat( L"(thread:%s) ", GetName() ) + m_except->DiagMsg();
|
||||
ex.Rethrow();
|
||||
}
|
||||
catch( std::runtime_error& ex )
|
||||
{
|
||||
m_except = new Exception::RuntimeError(
|
||||
// Diagnostic message:
|
||||
wxsFormat( L"(thread: %s) STL Runtime Error: %s\n\t%s",
|
||||
GetName().c_str(), wxString::FromUTF8( ex.what() )
|
||||
),
|
||||
|
||||
// User Message (not translated, std::exception doesn't have that kind of fancy!
|
||||
wxsFormat( L"A runtime error occurred in %s:\n\n%s (STL)",
|
||||
GetName().c_str(), wxString::FromUTF8( ex.what() )
|
||||
)
|
||||
);
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
m_except = ex.Clone();
|
||||
m_except->DiagMsg() = wxsFormat( L"(thread:%s) ", GetName() ) + m_except->DiagMsg();
|
||||
}
|
||||
}
|
||||
|
||||
void* PersistentThread::_internal_callback( void* itsme )
|
||||
{
|
||||
jASSUME( itsme != NULL );
|
||||
PersistentThread& owner = *((PersistentThread*)itsme);
|
||||
|
||||
pthread_cleanup_push( _pt_callback_cleanup, itsme );
|
||||
owner.m_returncode = owner.ExecuteTask();
|
||||
owner._internal_execute();
|
||||
pthread_cleanup_pop( true );
|
||||
|
||||
return (void*)owner.m_returncode;
|
||||
}
|
||||
|
||||
void PersistentThread::DoSetThreadName( const wxString& name )
|
||||
{
|
||||
DoSetThreadName( wxToUTF8(name) );
|
||||
}
|
||||
|
||||
void PersistentThread::SetName( __unused const char* name )
|
||||
void PersistentThread::DoSetThreadName( __unused const char* name )
|
||||
{
|
||||
wxASSERT( IsSelf() ); // only allowed from our own thread, thanks.
|
||||
|
||||
#ifdef _WINDOWS_
|
||||
|
||||
// This code sample was borrowed form some obscure MSDN article.
|
||||
// In a rare bout of sanity, it's an actual Micrsoft-published hack
|
||||
// that actually works!
|
||||
|
||||
static const int MS_VC_EXCEPTION = 0x406D1388;
|
||||
|
||||
#pragma pack(push,8)
|
||||
|
@ -210,10 +272,10 @@ namespace Threading
|
|||
#pragma pack(pop)
|
||||
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = GetCurrentThreadId();
|
||||
info.dwFlags = 0;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = GetCurrentThreadId();
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
|
@ -480,6 +542,11 @@ namespace Threading
|
|||
pthread_mutex_unlock( &mutex );
|
||||
}
|
||||
|
||||
bool MutexLock::TryLock()
|
||||
{
|
||||
return EBUSY != pthread_mutex_trylock( &mutex );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// InterlockedExchanges / AtomicExchanges (PCSX2's Helper versions)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -85,12 +85,12 @@ __forceinline void xWrite64( u64 val )
|
|||
xWrite( val );
|
||||
}
|
||||
|
||||
const xAddressIndexerBase ptr;
|
||||
const xAddressIndexer<u128> ptr128;
|
||||
const xAddressIndexer<u64> ptr64;
|
||||
const xAddressIndexer<u32> ptr32;
|
||||
const xAddressIndexer<u16> ptr16;
|
||||
const xAddressIndexer<u8> ptr8;
|
||||
const xAddressIndexerBase ptr;
|
||||
const xAddressIndexer<u128> ptr128;
|
||||
const xAddressIndexer<u64> ptr64;
|
||||
const xAddressIndexer<u32> ptr32;
|
||||
const xAddressIndexer<u16> ptr16;
|
||||
const xAddressIndexer<u8> ptr8;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
// 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;
|
||||
static ScopedPtr<memSavingState> g_fGSSave;
|
||||
|
||||
// fixme - need to take this concept and make it MTGS friendly.
|
||||
#ifdef _STGS_GSSTATE_CODE
|
||||
|
@ -76,7 +76,7 @@ void SaveGSState(const wxString& file)
|
|||
Console::WriteLn( wxsFormat( L"\t%s", file.c_str() ) );
|
||||
|
||||
SafeArray<u8> buf;
|
||||
g_fGSSave.reset( new memSavingState( buf ) );
|
||||
g_fGSSave = new memSavingState( buf );
|
||||
|
||||
g_SaveGSStream = 1;
|
||||
g_nLeftGSFrames = 2;
|
||||
|
|
|
@ -107,6 +107,7 @@ mtgsThreadObject::mtgsThreadObject() :
|
|||
, m_lock_Stack()
|
||||
#endif
|
||||
{
|
||||
m_name = L"MTGS";
|
||||
}
|
||||
|
||||
void mtgsThreadObject::Start()
|
||||
|
@ -139,6 +140,7 @@ void mtgsThreadObject::PollStatus()
|
|||
|
||||
mtgsThreadObject::~mtgsThreadObject() throw()
|
||||
{
|
||||
_parent::Cancel();
|
||||
}
|
||||
|
||||
void mtgsThreadObject::OnResumeReady()
|
||||
|
@ -244,8 +246,6 @@ void mtgsThreadObject::OpenPlugin()
|
|||
|
||||
sptr mtgsThreadObject::ExecuteTask()
|
||||
{
|
||||
SetName( "MTGS" );
|
||||
|
||||
#ifdef RINGBUF_DEBUG_STACK
|
||||
PacketTagType prevCmd;
|
||||
#endif
|
||||
|
|
|
@ -28,29 +28,29 @@
|
|||
# include "svnrev.h"
|
||||
#endif
|
||||
|
||||
EmuPluginBindings EmuPlugins;
|
||||
SysPluginBindings SysPlugins;
|
||||
|
||||
bool EmuPluginBindings::McdIsPresent( uint port, uint slot )
|
||||
bool SysPluginBindings::McdIsPresent( uint port, uint slot )
|
||||
{
|
||||
return !!Mcd->McdIsPresent( (PS2E_THISPTR) Mcd, port, slot );
|
||||
}
|
||||
|
||||
void EmuPluginBindings::McdRead( uint port, uint slot, u8 *dest, u32 adr, int size )
|
||||
void SysPluginBindings::McdRead( uint port, uint slot, u8 *dest, u32 adr, int size )
|
||||
{
|
||||
Mcd->McdRead( (PS2E_THISPTR) Mcd, port, slot, dest, adr, size );
|
||||
}
|
||||
|
||||
void EmuPluginBindings::McdSave( uint port, uint slot, const u8 *src, u32 adr, int size )
|
||||
void SysPluginBindings::McdSave( uint port, uint slot, const u8 *src, u32 adr, int size )
|
||||
{
|
||||
Mcd->McdSave( (PS2E_THISPTR) Mcd, port, slot, src, adr, size );
|
||||
}
|
||||
|
||||
void EmuPluginBindings::McdEraseBlock( uint port, uint slot, u32 adr )
|
||||
void SysPluginBindings::McdEraseBlock( uint port, uint slot, u32 adr )
|
||||
{
|
||||
Mcd->McdEraseBlock( (PS2E_THISPTR) Mcd, port, slot, adr );
|
||||
}
|
||||
|
||||
u64 EmuPluginBindings::McdGetCRC( uint port, uint slot )
|
||||
u64 SysPluginBindings::McdGetCRC( uint port, uint slot )
|
||||
{
|
||||
return Mcd->McdGetCRC( (PS2E_THISPTR) Mcd, port, slot );
|
||||
}
|
||||
|
@ -988,10 +988,10 @@ void PluginManager::Init()
|
|||
throw Exception::PluginInitError( pid );
|
||||
} while( ++pi, pi->shortname != NULL );
|
||||
|
||||
if( EmuPlugins.Mcd == NULL )
|
||||
if( SysPlugins.Mcd == NULL )
|
||||
{
|
||||
EmuPlugins.Mcd = (PS2E_ComponentAPI_Mcd*)m_mcdPlugin->NewComponentInstance( PS2E_TYPE_Mcd );
|
||||
if( EmuPlugins.Mcd == NULL )
|
||||
SysPlugins.Mcd = (PS2E_ComponentAPI_Mcd*)m_mcdPlugin->NewComponentInstance( PS2E_TYPE_Mcd );
|
||||
if( SysPlugins.Mcd == NULL )
|
||||
{
|
||||
// fixme: use plugin's GetLastError (not implemented yet!)
|
||||
throw Exception::PluginInitError( PluginId_Mcd, "Internal Memorycard Plugin failed to initialize." );
|
||||
|
@ -1029,10 +1029,10 @@ void PluginManager::Shutdown()
|
|||
|
||||
// More memorycard hacks!!
|
||||
|
||||
if( (EmuPlugins.Mcd != NULL) && (m_mcdPlugin != NULL) )
|
||||
if( (SysPlugins.Mcd != NULL) && (m_mcdPlugin != NULL) )
|
||||
{
|
||||
m_mcdPlugin->DeleteComponentInstance( (PS2E_THISPTR)EmuPlugins.Mcd );
|
||||
EmuPlugins.Mcd = NULL;
|
||||
m_mcdPlugin->DeleteComponentInstance( (PS2E_THISPTR)SysPlugins.Mcd );
|
||||
SysPlugins.Mcd = NULL;
|
||||
}
|
||||
|
||||
DbgCon::Status( "Plugins shutdown successfully." );
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace Exception
|
|||
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( PluginError )
|
||||
|
||||
PluginError() {}
|
||||
PluginError( PluginsEnum_t pid, const char* msg="Generic plugin error" )
|
||||
{
|
||||
|
@ -183,13 +184,13 @@ class mtgsThreadObject;
|
|||
// make the current PluginManager largely obsolete (with the exception of the general Load/Unload
|
||||
// management facilities)
|
||||
//
|
||||
class EmuPluginBindings
|
||||
class SysPluginBindings
|
||||
{
|
||||
protected:
|
||||
PS2E_ComponentAPI_Mcd* Mcd;
|
||||
|
||||
public:
|
||||
EmuPluginBindings() :
|
||||
SysPluginBindings() :
|
||||
Mcd( NULL )
|
||||
{
|
||||
|
||||
|
@ -204,7 +205,7 @@ public:
|
|||
friend class PluginManager;
|
||||
};
|
||||
|
||||
extern EmuPluginBindings EmuPlugins;
|
||||
extern SysPluginBindings SysPlugins;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -20,129 +20,268 @@
|
|||
#include "HostGui.h"
|
||||
#include "zlib/zlib.h"
|
||||
|
||||
using namespace Threading;
|
||||
static SafeArray<u8> state_buffer;
|
||||
|
||||
static wxScopedPtr< SafeArray<u8> > g_RecoveryState;
|
||||
// Simple lock boolean for the state buffer in use by a thread. This simple solution works because
|
||||
// we are assured that state save/load actions will only be initiated from the main thread.
|
||||
static bool state_buffer_lock = false;
|
||||
|
||||
namespace StateRecovery {
|
||||
// This boolean is to keep the system from resuming emulation until the current state has completely
|
||||
// uploaded or downloaded itself. It is only modified from the main thread, and should only be read
|
||||
// form the main thread.
|
||||
bool sys_resume_lock = false;
|
||||
|
||||
bool HasState()
|
||||
class StateThread_Freeze : public PersistentThread
|
||||
{
|
||||
typedef PersistentThread _parent;
|
||||
|
||||
public:
|
||||
StateThread_Freeze( const wxString& file )
|
||||
{
|
||||
return g_RecoveryState;
|
||||
}
|
||||
m_name = L"SaveState::CopyAndZip";
|
||||
|
||||
void Recover()
|
||||
{
|
||||
if( !g_RecoveryState ) return;
|
||||
DevAssert( wxThread::IsMain(), "StateThread creation is allowed from the Main thread only." );
|
||||
if( state_buffer_lock )
|
||||
throw Exception::RuntimeError( "Cannot save state; a previous save or load action is already in progress." );
|
||||
|
||||
Console::Status( "Resuming execution from full memory state..." );
|
||||
memLoadingState( *g_RecoveryState ).FreezeAll();
|
||||
|
||||
StateRecovery::Clear();
|
||||
SysClearExecutionCache();
|
||||
Start();
|
||||
sys_resume_lock = true;
|
||||
}
|
||||
|
||||
SafeArray<u8> gzSavingBuffer;
|
||||
|
||||
class gzThreadClass : public PersistentThread
|
||||
protected:
|
||||
sptr ExecuteTask()
|
||||
{
|
||||
typedef PersistentThread _parent;
|
||||
|
||||
protected:
|
||||
gzFile m_file;
|
||||
|
||||
public:
|
||||
gzThreadClass( const wxString& file ) :
|
||||
m_file( gzopen( file.ToUTF8().data(), "wb" ) )
|
||||
{
|
||||
if( m_file == NULL )
|
||||
throw Exception::CreateStream( file, "Cannot create savestate file for writing." );
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
virtual void DoThreadCleanup()
|
||||
{
|
||||
gzSavingBuffer.Dispose();
|
||||
if( m_file != NULL )
|
||||
{
|
||||
gzclose( m_file );
|
||||
m_file = NULL;
|
||||
}
|
||||
|
||||
_parent::DoThreadCleanup();
|
||||
}
|
||||
|
||||
virtual ~gzThreadClass() throw()
|
||||
{
|
||||
// fixme: something a little more graceful than Block, perhaps?
|
||||
Block();
|
||||
}
|
||||
|
||||
protected:
|
||||
int ExecuteTask()
|
||||
{
|
||||
if( (m_file == NULL) || (gzSavingBuffer.GetSizeInBytes() == 0) ) return 0 ;
|
||||
SetName( "Savestate::gzipper" );
|
||||
gzwrite( m_file, gzSavingBuffer.GetPtr(), gzSavingBuffer.GetSizeInBytes() );
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
wxScopedPtr<gzThreadClass> gzThread;
|
||||
|
||||
void SaveToFile( const wxString& file )
|
||||
memSavingState( state_buffer ).FreezeAll();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DoThreadCleanup()
|
||||
{
|
||||
SysSuspend( false );
|
||||
gzThread.reset( NULL ); // blocks on any existing gzipping business.
|
||||
wxCommandEvent evt( pxEVT_FreezeFinished );
|
||||
evt.SetClientData( this );
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
|
||||
memSavingState( gzSavingBuffer ).FreezeAll();
|
||||
_parent::DoThreadCleanup();
|
||||
}
|
||||
};
|
||||
|
||||
// start that encoding thread:
|
||||
gzThread.reset( new gzThreadClass( file ) );
|
||||
|
||||
SysResume();
|
||||
class StateThread_ZipToDisk : public PersistentThread
|
||||
{
|
||||
typedef PersistentThread _parent;
|
||||
|
||||
protected:
|
||||
gzFile m_gzfp;
|
||||
|
||||
public:
|
||||
StateThread_ZipToDisk( const wxString& file ) : m_gzfp( NULL )
|
||||
{
|
||||
m_name = L"SaveState::ZipToDisk";
|
||||
|
||||
DevAssert( wxThread::IsMain(), "StateThread creation is allowed from the Main thread only." );
|
||||
if( state_buffer_lock )
|
||||
throw Exception::RuntimeError( "Cannot save state; a previous save or load action is already in progress." );
|
||||
|
||||
m_gzfp = gzopen( file.ToUTF8().data(), "wb" );
|
||||
if( m_gzfp == NULL )
|
||||
throw Exception::CreateStream( file, "Cannot create savestate file for writing." );
|
||||
|
||||
try{ Start(); }
|
||||
catch(...)
|
||||
{
|
||||
gzclose( m_gzfp ); m_gzfp = NULL;
|
||||
throw;
|
||||
}
|
||||
sys_resume_lock = true;
|
||||
}
|
||||
|
||||
// Saves recovery state info to the given saveslot, 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. :)
|
||||
void SaveToSlot( uint num )
|
||||
~StateThread_ZipToDisk() throw()
|
||||
{
|
||||
SaveToFile( SaveStateBase::GetFilename( num ) );
|
||||
sys_resume_lock = false; // just in case;
|
||||
if( m_gzfp != NULL ) gzclose( m_gzfp );
|
||||
}
|
||||
|
||||
// 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()
|
||||
protected:
|
||||
sptr ExecuteTask()
|
||||
{
|
||||
if( g_RecoveryState ) return;
|
||||
if( !EmulationInProgress() ) return;
|
||||
Sleep( 2 );
|
||||
if( gzwrite( (gzFile)m_gzfp, state_buffer.GetPtr(), state_buffer.GetSizeInBytes() ) < state_buffer.GetSizeInBytes() )
|
||||
throw Exception::BadStream();
|
||||
|
||||
try
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DoThreadCleanup()
|
||||
{
|
||||
wxCommandEvent evt( pxEVT_FreezeFinished );
|
||||
evt.SetClientData( this ); // tells message to clean us up.
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
|
||||
_parent::DoThreadCleanup();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class StateThread_UnzipFromDisk : public PersistentThread
|
||||
{
|
||||
typedef PersistentThread _parent;
|
||||
|
||||
protected:
|
||||
gzFile m_gzfp;
|
||||
|
||||
public:
|
||||
StateThread_UnzipFromDisk( const wxString& file ) : m_gzfp( NULL )
|
||||
{
|
||||
m_name = L"SaveState::UnzipFromDisk";
|
||||
|
||||
DevAssert( wxThread::IsMain(), "StateThread creation is allowed from the Main thread only." );
|
||||
if( state_buffer_lock )
|
||||
throw Exception::RuntimeError( "Cannot save state; a previous save or load action is already in progress." );
|
||||
|
||||
m_gzfp = gzopen( file.ToUTF8().data(), "wb" );
|
||||
if( m_gzfp == NULL )
|
||||
throw Exception::CreateStream( file, "Cannot create savestate file for writing." );
|
||||
|
||||
try{ Start(); }
|
||||
catch(...)
|
||||
{
|
||||
g_RecoveryState.reset( new SafeArray<u8>( L"Memory Savestate Recovery" ) );
|
||||
memSavingState( *g_RecoveryState ).FreezeAll();
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
Msgbox::Alert( wxsFormat( // fixme: needs proper translation
|
||||
L"PCSX2 encountered an error while trying to backup/suspend the PS2 VirtualMachine state. "
|
||||
L"You may resume emulation without losing any data, however the machine state will not be "
|
||||
L"able to recover if you make changes to your PCSX2 configuration.\n\n"
|
||||
L"Details: %s", ex.FormatDisplayMessage().c_str() )
|
||||
);
|
||||
g_RecoveryState.reset();
|
||||
gzclose( m_gzfp ); m_gzfp = NULL;
|
||||
throw;
|
||||
}
|
||||
sys_resume_lock = true;
|
||||
}
|
||||
|
||||
// Clears and deallocates any recovery states.
|
||||
void Clear()
|
||||
~StateThread_UnzipFromDisk() throw()
|
||||
{
|
||||
g_RecoveryState.reset();
|
||||
sys_resume_lock = false; // just in case;
|
||||
if( m_gzfp != NULL ) gzclose( m_gzfp );
|
||||
}
|
||||
|
||||
protected:
|
||||
sptr ExecuteTask()
|
||||
{
|
||||
// fixme: should start initially with the file size, and then grow from there.
|
||||
|
||||
static const int BlockSize = 327680;
|
||||
int curidx = 0;
|
||||
do
|
||||
{
|
||||
state_buffer.ExactAlloc( curidx+BlockSize );
|
||||
gzread( m_gzfp, state_buffer.GetPtr(curidx), BlockSize );
|
||||
curidx += BlockSize;
|
||||
} while( !gzeof(m_gzfp) );
|
||||
}
|
||||
|
||||
void DoThreadCleanup()
|
||||
{
|
||||
wxCommandEvent evt( pxEVT_ThawFinished );
|
||||
evt.SetClientData( this ); // tells message to clean us up.
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
|
||||
_parent::DoThreadCleanup();
|
||||
}
|
||||
};
|
||||
|
||||
void Pcsx2App::OnFreezeFinished( wxCommandEvent& evt )
|
||||
{
|
||||
state_buffer.Dispose();
|
||||
state_buffer_lock = false;
|
||||
|
||||
SysClearExecutionCache();
|
||||
SysResume();
|
||||
|
||||
if( PersistentThread* thread = (PersistentThread*)evt.GetClientData() )
|
||||
{
|
||||
delete thread;
|
||||
}
|
||||
}
|
||||
|
||||
void Pcsx2App::OnThawFinished( wxCommandEvent& evt )
|
||||
{
|
||||
state_buffer.Dispose();
|
||||
state_buffer_lock = false;
|
||||
|
||||
SysClearExecutionCache();
|
||||
SysResume();
|
||||
|
||||
if( PersistentThread* thread = (PersistentThread*)evt.GetClientData() )
|
||||
{
|
||||
delete thread;
|
||||
}
|
||||
}
|
||||
|
||||
void StateCopy_SaveToFile( const wxString& file )
|
||||
{
|
||||
if( state_buffer_lock ) return;
|
||||
// [TODO] Implement optional 7zip compression here?
|
||||
}
|
||||
|
||||
// Saves recovery state info to the given saveslot, 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. :)
|
||||
void StateCopy_SaveToSlot( uint num )
|
||||
{
|
||||
if( state_buffer_lock ) return;
|
||||
StateCopy_SaveToFile( SaveStateBase::GetFilename( num ) );
|
||||
}
|
||||
|
||||
bool StateCopy_IsValid()
|
||||
{
|
||||
return !state_buffer.IsDisposed();
|
||||
}
|
||||
|
||||
bool StateCopy_HasFullState()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StateCopy_HasPartialState()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void StateCopy_FreezeToMem()
|
||||
{
|
||||
if( state_buffer_lock ) return;
|
||||
}
|
||||
|
||||
void StateCopy_ThawFromMem()
|
||||
{
|
||||
if( state_buffer_lock ) return;
|
||||
}
|
||||
|
||||
void StateCopy_Clear()
|
||||
{
|
||||
if( state_buffer_lock ) return;
|
||||
state_buffer.Dispose();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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 ) return;
|
||||
//if( !SysHasValidState() ) return;
|
||||
|
||||
/*
|
||||
try
|
||||
{
|
||||
g_RecoveryState = new SafeArray<u8>( L"Memory Savestate Recovery" );
|
||||
memSavingState( *g_RecoveryState ).FreezeAll();
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
Msgbox::Alert( wxsFormat( // fixme: needs proper translation
|
||||
L"PCSX2 encountered an error while trying to backup/suspend the PS2 VirtualMachine state. "
|
||||
L"You may resume emulation without losing any data, however the machine state will not be "
|
||||
L"able to recover if you make changes to your PCSX2 configuration.\n\n"
|
||||
L"Details: %s", ex.FormatDisplayMessage().c_str() )
|
||||
);
|
||||
g_RecoveryState = NULL;
|
||||
}*/
|
||||
}
|
||||
|
||||
|
|
|
@ -193,13 +193,13 @@ public:
|
|||
bool IsFinished() const { return m_idx >= m_memory.GetSizeInBytes(); }
|
||||
};
|
||||
|
||||
namespace StateRecovery
|
||||
{
|
||||
extern bool HasState();
|
||||
extern void Recover();
|
||||
extern void SaveToFile( const wxString& file );
|
||||
extern void SaveToSlot( uint num );
|
||||
extern void MakeFull();
|
||||
extern void Clear();
|
||||
}
|
||||
extern bool StateCopy_IsValid();
|
||||
extern bool StateCopy_HasFullState();
|
||||
extern bool StateCopy_HasPartialState();
|
||||
|
||||
extern void StateCopy_FreezeToMem();
|
||||
extern void StateCopy_ThawFromMem();
|
||||
extern void StateCopy_SaveToFile( const wxString& file );
|
||||
extern void StateCopy_SaveToSlot( uint num );
|
||||
extern void StateCopy_Clear();
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ static bool IsMtapPresent( uint port )
|
|||
|
||||
static void _ReadMcd(u8 *data, u32 adr, int size)
|
||||
{
|
||||
EmuPlugins.McdRead(
|
||||
SysPlugins.McdRead(
|
||||
sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
|
||||
data, adr, size
|
||||
);
|
||||
|
@ -61,7 +61,7 @@ static void _ReadMcd(u8 *data, u32 adr, int size)
|
|||
|
||||
static void _SaveMcd(const u8 *data, u32 adr, int size)
|
||||
{
|
||||
EmuPlugins.McdSave(
|
||||
SysPlugins.McdSave(
|
||||
sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
|
||||
data, adr, size
|
||||
);
|
||||
|
@ -69,7 +69,7 @@ static void _SaveMcd(const u8 *data, u32 adr, int size)
|
|||
|
||||
static void _EraseMCDBlock(u32 adr)
|
||||
{
|
||||
EmuPlugins.McdEraseBlock( sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()], adr );
|
||||
SysPlugins.McdEraseBlock( sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()], adr );
|
||||
}
|
||||
|
||||
static u8 sio_xor( const u8 *buf, uint length )
|
||||
|
@ -601,7 +601,7 @@ void InitializeSIO(u8 value)
|
|||
const uint port = sio.GetMemcardIndex();
|
||||
const uint slot = sio.activeMemcardSlot[port];
|
||||
|
||||
if( EmuPlugins.McdIsPresent( port, slot ) )
|
||||
if( SysPlugins.McdIsPresent( port, slot ) )
|
||||
{
|
||||
sio2.packet.recvVal1 = 0x1100;
|
||||
PAD_LOG("START MEMCARD [port:%d, slot:%d] - Present", port, slot );
|
||||
|
@ -665,7 +665,7 @@ void SaveStateBase::sioFreeze()
|
|||
for( int port=0; port<2; ++port )
|
||||
{
|
||||
for( int slot=0; slot<8; ++slot )
|
||||
m_mcdCRCs[port][slot] = EmuPlugins.McdGetCRC( port, slot );
|
||||
m_mcdCRCs[port][slot] = SysPlugins.McdGetCRC( port, slot );
|
||||
}
|
||||
}
|
||||
Freeze( m_mcdCRCs );
|
||||
|
@ -689,7 +689,7 @@ void SaveStateBase::sioFreeze()
|
|||
{
|
||||
for( int slot=0; slot<8; ++slot )
|
||||
{
|
||||
u64 newCRC = EmuPlugins.McdGetCRC( port, slot );
|
||||
u64 newCRC = SysPlugins.McdGetCRC( port, slot );
|
||||
if( newCRC != m_mcdCRCs[port][slot] )
|
||||
{
|
||||
m_mcdCRCs[port][slot] = newCRC;
|
||||
|
|
|
@ -252,40 +252,11 @@ void SysClearExecutionCache()
|
|||
vuMicroCpuReset();
|
||||
}
|
||||
|
||||
// The calling function should trap and handle exceptions as needed.
|
||||
// Exceptions:
|
||||
// Exception::StateLoadError - thrown when a fully recoverable exception ocurred. The
|
||||
// virtual machine memory state is fully intact.
|
||||
//
|
||||
// Any other exception means the Virtual Memory state is indeterminate and probably
|
||||
// invalid.
|
||||
void SysLoadState( const wxString& srcfile )
|
||||
{
|
||||
SafeArray<u8> buf;
|
||||
gzFile gzfp = gzopen( srcfile.ToUTF8().data(), "rb" );
|
||||
if( gzfp == NULL )
|
||||
throw Exception::BadSavedState( srcfile, "File not found, or permission denied!" );
|
||||
|
||||
int curidx = 0;
|
||||
do
|
||||
{
|
||||
buf.MakeRoomFor( curidx+327680 );
|
||||
gzread( gzfp, buf.GetPtr(curidx), 327680 );
|
||||
curidx += 327680;
|
||||
} while( !gzeof(gzfp) );
|
||||
|
||||
gzclose( gzfp );
|
||||
|
||||
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();
|
||||
|
||||
SysClearExecutionCache();
|
||||
cpuReset();
|
||||
joe.FreezeAll();
|
||||
//SysClearExecutionCache();
|
||||
//cpuReset();
|
||||
//joe.FreezeAll();
|
||||
}
|
||||
|
||||
// Maps a block of memory for use as a recompiled code buffer, and ensures that the
|
||||
|
|
|
@ -204,6 +204,7 @@ SysCoreThread::SysCoreThread( PluginManager& plugins ) :
|
|||
, m_shortSuspend( false )
|
||||
, m_plugins( plugins )
|
||||
{
|
||||
m_name = L"EE Core";
|
||||
}
|
||||
|
||||
SysCoreThread::~SysCoreThread() throw()
|
||||
|
@ -280,13 +281,13 @@ void SysCoreThread::CpuInitializeMess()
|
|||
cpuReset();
|
||||
SysClearExecutionCache();
|
||||
|
||||
if( StateRecovery::HasState() )
|
||||
if( StateCopy_IsValid() )
|
||||
{
|
||||
// no need to boot bios or detect CDs when loading savestates.
|
||||
// [TODO] : It might be useful to detect game SLUS/CRC and compare it against
|
||||
// the savestate info, and issue a warning to the user since, chances are, they
|
||||
// don't really want to run a game with the wrong ISO loaded into the emu.
|
||||
StateRecovery::Recover();
|
||||
StateCopy_ThawFromMem();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -354,7 +355,6 @@ static void _cet_callback_cleanup( void* handle )
|
|||
|
||||
sptr SysCoreThread::ExecuteTask()
|
||||
{
|
||||
SetName( "EE Core" );
|
||||
tls_coreThread = this;
|
||||
|
||||
StateCheck();
|
||||
|
|
|
@ -19,7 +19,19 @@
|
|||
|
||||
using namespace Threading;
|
||||
|
||||
class SysSuspendableThread : public PersistentThread
|
||||
class ISysThread : public virtual IThread
|
||||
{
|
||||
public:
|
||||
ISysThread() {}
|
||||
virtual ~ISysThread() throw() {};
|
||||
|
||||
virtual bool IsSuspended() const { return false; }
|
||||
virtual void Suspend( bool isBlocking = true ) { }
|
||||
virtual void Resume() {}
|
||||
};
|
||||
|
||||
|
||||
class SysSuspendableThread : public PersistentThread, public virtual ISysThread
|
||||
{
|
||||
typedef PersistentThread _parent;
|
||||
|
||||
|
|
126
pcsx2/gui/App.h
126
pcsx2/gui/App.h
|
@ -26,6 +26,7 @@ class MainEmuFrame;
|
|||
class GSFrame;
|
||||
class ConsoleLogFrame;
|
||||
class PipeRedirectionBase;
|
||||
class AppCoreThread;
|
||||
|
||||
#include "Utilities/HashMap.h"
|
||||
#include "Utilities/wxGuiTools.h"
|
||||
|
@ -39,6 +40,9 @@ BEGIN_DECLARE_EVENT_TYPES()
|
|||
DECLARE_EVENT_TYPE( pxEVT_OpenModalDialog, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_LoadPluginsComplete, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_AppCoreThread_Terminated, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_FreezeFinished, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_ThawFinished, -1 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -73,11 +77,11 @@ enum MenuIdentifiers
|
|||
MenuId_SkipBiosToggle, // enables the Bios Skip speedhack
|
||||
|
||||
|
||||
MenuId_Emu_SuspendResume, // suspends/resumes active emulation, retains plugin states
|
||||
MenuId_Emu_Close, // Closes the emulator (states are preserved)
|
||||
MenuId_Emu_Reset, // Issues a complete reset (wipes preserved states)
|
||||
MenuId_Emu_LoadStates, // Opens load states submenu
|
||||
MenuId_Emu_SaveStates, // Opens save states submenu
|
||||
MenuId_Sys_SuspendResume, // suspends/resumes active emulation, retains plugin states
|
||||
MenuId_Sys_Close, // Closes the emulator (states are preserved)
|
||||
MenuId_Sys_Reset, // Issues a complete reset (wipes preserved states)
|
||||
MenuId_Sys_LoadStates, // Opens load states submenu
|
||||
MenuId_Sys_SaveStates, // Opens save states submenu
|
||||
MenuId_EnablePatches,
|
||||
|
||||
MenuId_State_Load,
|
||||
|
@ -298,15 +302,15 @@ public:
|
|||
protected:
|
||||
wxImageList m_ConfigImages;
|
||||
|
||||
wxScopedPtr<wxImageList> m_ToolbarImages;
|
||||
wxScopedPtr<wxBitmap> m_Bitmap_Logo;
|
||||
wxScopedPtr<PipeRedirectionBase>m_StdoutRedirHandle;
|
||||
wxScopedPtr<PipeRedirectionBase>m_StderrRedirHandle;
|
||||
ScopedPtr<wxImageList> m_ToolbarImages;
|
||||
ScopedPtr<wxBitmap> m_Bitmap_Logo;
|
||||
ScopedPtr<PipeRedirectionBase> m_StdoutRedirHandle;
|
||||
ScopedPtr<PipeRedirectionBase> m_StderrRedirHandle;
|
||||
|
||||
public:
|
||||
wxScopedPtr<SysCoreAllocations> m_CoreAllocs;
|
||||
wxScopedPtr<PluginManager> m_CorePlugins;
|
||||
wxScopedPtr<SysCoreThread> m_CoreThread;
|
||||
ScopedPtr<SysCoreAllocations> m_CoreAllocs;
|
||||
ScopedPtr<PluginManager> m_CorePlugins;
|
||||
ScopedPtr<SysCoreThread> m_CoreThread;
|
||||
|
||||
protected:
|
||||
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
|
||||
|
@ -333,16 +337,8 @@ public:
|
|||
|
||||
void SysExecute();
|
||||
void SysExecute( CDVD_SourceType cdvdsrc );
|
||||
void SysReset()
|
||||
{
|
||||
m_CoreThread.reset();
|
||||
m_CorePlugins.reset();
|
||||
}
|
||||
|
||||
bool EmuInProgress() const
|
||||
{
|
||||
return m_CoreThread && m_CoreThread->IsRunning();
|
||||
}
|
||||
void SysReset();
|
||||
bool SysIsActive() const;
|
||||
|
||||
const wxBitmap& GetLogoBitmap();
|
||||
wxImageList& GetImgList_Config();
|
||||
|
@ -350,28 +346,13 @@ public:
|
|||
|
||||
const AppImageIds& GetImgId() const { return m_ImageId; }
|
||||
|
||||
MainEmuFrame& GetMainFrame() const
|
||||
{
|
||||
wxASSERT( ((uptr)GetTopWindow()) == ((uptr)m_MainFrame) );
|
||||
wxASSERT( m_MainFrame != NULL );
|
||||
return *m_MainFrame;
|
||||
}
|
||||
bool HasMainFrame() const { return m_MainFrame != NULL; }
|
||||
bool HasCoreThread() const { return m_CoreThread != NULL; }
|
||||
|
||||
MainEmuFrame& GetMainFrameOrExcept() const
|
||||
{
|
||||
if( m_MainFrame == NULL )
|
||||
throw Exception::ObjectIsNull( "main application frame" );
|
||||
|
||||
return *m_MainFrame;
|
||||
}
|
||||
|
||||
SysCoreThread& GetCoreThreadOrExcept() const
|
||||
{
|
||||
if( !m_CoreThread )
|
||||
throw Exception::ObjectIsNull( "core emulation thread" );
|
||||
|
||||
return *m_CoreThread;
|
||||
}
|
||||
MainEmuFrame& GetMainFrame() const;
|
||||
SysCoreThread& GetCoreThread() const;
|
||||
MainEmuFrame& GetMainFrameOrExcept() const;
|
||||
SysCoreThread& GetCoreThreadOrExcept() const;
|
||||
|
||||
void OpenGsFrame();
|
||||
void OnGsFrameClosed();
|
||||
|
@ -412,9 +393,14 @@ protected:
|
|||
void OnLoadPluginsComplete( wxCommandEvent& evt );
|
||||
void OnSemaphorePing( wxCommandEvent& evt );
|
||||
void OnOpenModalDialog( wxCommandEvent& evt );
|
||||
void OnCoreThreadTerminated( wxCommandEvent& evt );
|
||||
|
||||
void OnFreezeFinished( wxCommandEvent& evt );
|
||||
void OnThawFinished( wxCommandEvent& evt );
|
||||
|
||||
void OnMessageBox( pxMessageBoxEvent& evt );
|
||||
void OnEmuKeyDown( wxKeyEvent& evt );
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Override wx default exception handling behavior
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -432,10 +418,10 @@ protected:
|
|||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppEmuThread class
|
||||
// AppCoreThread class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
class AppEmuThread : public SysCoreThread
|
||||
class AppCoreThread : public SysCoreThread
|
||||
{
|
||||
typedef SysCoreThread _parent;
|
||||
|
||||
|
@ -443,15 +429,16 @@ protected:
|
|||
wxKeyEvent m_kevt;
|
||||
|
||||
public:
|
||||
AppEmuThread( PluginManager& plugins );
|
||||
virtual ~AppEmuThread() throw();
|
||||
AppCoreThread( PluginManager& plugins );
|
||||
virtual ~AppCoreThread() throw();
|
||||
|
||||
virtual void Suspend( bool isBlocking=true );
|
||||
virtual void StateCheck( bool isCancelable=true );
|
||||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
virtual void OnResumeReady();
|
||||
|
||||
protected:
|
||||
virtual void OnResumeReady();
|
||||
virtual void DoThreadCleanup();
|
||||
sptr ExecuteTask();
|
||||
};
|
||||
|
||||
|
@ -470,6 +457,7 @@ public:
|
|||
bool IsReentrant() const { return Counter > 1; }
|
||||
};
|
||||
|
||||
extern bool sys_resume_lock;
|
||||
|
||||
extern int EnumeratePluginsInFolder( const wxDirName& searchPath, wxArrayString* dest );
|
||||
extern void LoadPluginsPassive();
|
||||
|
@ -477,13 +465,13 @@ extern void LoadPluginsImmediate();
|
|||
extern void UnloadPlugins();
|
||||
|
||||
extern bool HandlePluginError( Exception::PluginError& ex );
|
||||
extern bool EmulationInProgress();
|
||||
extern bool SysHasValidState();
|
||||
|
||||
extern void AppLoadSettings();
|
||||
extern void AppSaveSettings();
|
||||
extern void AppApplySettings( const AppConfig* oldconf=NULL );
|
||||
|
||||
extern bool SysHasValidState();
|
||||
|
||||
extern void SysStatus( const wxString& text );
|
||||
extern void SysSuspend( bool closePlugins = true );
|
||||
extern void SysResume();
|
||||
|
@ -491,36 +479,8 @@ extern void SysReset();
|
|||
extern void SysExecute();
|
||||
extern void SysExecute( CDVD_SourceType cdvdsrc );
|
||||
|
||||
extern bool HasMainFrame();
|
||||
extern bool HasCoreThread();
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppInvoke macro
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This handy macro provides a safe way to invoke functions on objects that may or may not
|
||||
// exist. If the object is null, the function is not called. Useful for calling things that
|
||||
// are cosmetic optional, such as logging or status bars.
|
||||
//
|
||||
// Performance Note: This macro uses exception handling, and should not be used in the
|
||||
// context of tight loops or performant code.
|
||||
//
|
||||
// Parameters:
|
||||
// obj - name of the object. The name must have a matching accessor in Pcsx2App in the
|
||||
// format of GetSomethingOrExcept(), where 'Something' would be the object name.
|
||||
// runme - The function to call, complete with parameters. Note that parameters that
|
||||
// perform actions (such as creating new objects or something) won't be run unless
|
||||
// the 'obj' itself exists.
|
||||
//
|
||||
#define AppInvoke( obj, runme ) \
|
||||
do { \
|
||||
try { \
|
||||
wxGetApp().Get##obj##OrExcept().runme; \
|
||||
} \
|
||||
catch( Exception::ObjectIsNull& ) { } \
|
||||
} while( false )
|
||||
|
||||
#define AppInvokeBool( obj, runme, dest ) \
|
||||
{ \
|
||||
try { \
|
||||
(dest) = wxGetApp().Get##obj##OrExcept().runme; \
|
||||
} \
|
||||
catch( Exception::ObjectIsNull& ) { } \
|
||||
} while( false )
|
||||
extern MainEmuFrame& GetMainFrame();
|
||||
extern SysCoreThread& GetCoreThread();
|
||||
|
|
|
@ -525,7 +525,8 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite )
|
|||
AppLoadSettings();
|
||||
|
||||
AppApplySettings();
|
||||
AppInvoke( MainFrame, ReloadRecentLists() );
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ReloadRecentLists();
|
||||
|
||||
g_Conf->Folders.Logs.Mkdir();
|
||||
|
||||
|
|
|
@ -178,4 +178,4 @@ extern ConfigOverrides OverrideOptions;
|
|||
extern wxFileConfig* OpenFileConfig( const wxString& filename );
|
||||
extern void AppConfig_OnChangedSettingsFolder( bool overwrite = false );
|
||||
|
||||
extern wxScopedPtr<AppConfig> g_Conf;
|
||||
extern ScopedPtr<AppConfig> g_Conf;
|
||||
|
|
|
@ -37,12 +37,15 @@ DEFINE_EVENT_TYPE( pxEVT_SemaphorePing );
|
|||
DEFINE_EVENT_TYPE( pxEVT_OpenModalDialog );
|
||||
DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins );
|
||||
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
|
||||
DEFINE_EVENT_TYPE( pxEVT_AppCoreThread_Terminated );
|
||||
DEFINE_EVENT_TYPE( pxEVT_FreezeFinished );
|
||||
DEFINE_EVENT_TYPE( pxEVT_ThawFinished );
|
||||
|
||||
bool UseAdminMode = false;
|
||||
wxDirName SettingsFolder;
|
||||
bool UseDefaultSettingsFolder = true;
|
||||
|
||||
wxScopedPtr<AppConfig> g_Conf;
|
||||
ScopedPtr<AppConfig> g_Conf;
|
||||
ConfigOverrides OverrideOptions;
|
||||
|
||||
namespace Exception
|
||||
|
@ -54,7 +57,7 @@ namespace Exception
|
|||
class StartupAborted : public BaseException
|
||||
{
|
||||
public:
|
||||
virtual ~StartupAborted() throw() {}
|
||||
DEFINE_EXCEPTION_COPYTORS( StartupAborted )
|
||||
|
||||
StartupAborted( const wxString& msg_eng=L"Startup initialization was aborted by the user." )
|
||||
{
|
||||
|
@ -64,21 +67,21 @@ namespace Exception
|
|||
};
|
||||
}
|
||||
|
||||
AppEmuThread::AppEmuThread( PluginManager& plugins ) :
|
||||
AppCoreThread::AppCoreThread( PluginManager& plugins ) :
|
||||
SysCoreThread( plugins )
|
||||
, m_kevt()
|
||||
{
|
||||
}
|
||||
|
||||
AppEmuThread::~AppEmuThread() throw()
|
||||
AppCoreThread::~AppCoreThread() throw()
|
||||
{
|
||||
AppInvoke( MainFrame, ApplySettings() );
|
||||
}
|
||||
|
||||
void AppEmuThread::Suspend( bool isBlocking )
|
||||
void AppCoreThread::Suspend( bool isBlocking )
|
||||
{
|
||||
_parent::Suspend( isBlocking );
|
||||
AppInvoke( MainFrame, ApplySettings() );
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ApplySettings();
|
||||
|
||||
// Clear the sticky key statuses, because hell knows what'll change while the PAD
|
||||
// plugin is suspended.
|
||||
|
@ -88,7 +91,7 @@ void AppEmuThread::Suspend( bool isBlocking )
|
|||
m_kevt.m_altDown = false;
|
||||
}
|
||||
|
||||
void AppEmuThread::OnResumeReady()
|
||||
void AppCoreThread::OnResumeReady()
|
||||
{
|
||||
if( !DevAssert( wxThread::IsMain(), "SysCoreThread can only be resumed from the main/gui thread." ) ) return;
|
||||
|
||||
|
@ -99,7 +102,19 @@ void AppEmuThread::OnResumeReady()
|
|||
if( GSopen2 != NULL )
|
||||
wxGetApp().OpenGsFrame();
|
||||
|
||||
AppInvoke( MainFrame, ApplySettings() );
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ApplySettings();
|
||||
}
|
||||
|
||||
// Called whenever the thread has terminated, for either regular or irregular reasons.
|
||||
// Typically the thread handles all its own errors, so there's no need to have error
|
||||
// handling here. However it's a good idea to update the status of the GUI to reflect
|
||||
// the new (lack of) thread status, so this posts a message to the App to do so.
|
||||
void AppCoreThread::DoThreadCleanup()
|
||||
{
|
||||
wxCommandEvent evt( pxEVT_AppCoreThread_Terminated );
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
_parent::DoThreadCleanup();
|
||||
}
|
||||
|
||||
// This is used when the GS plugin is handling its own window. Messages from the PAD
|
||||
|
@ -111,14 +126,14 @@ static const int pxID_PadHandler_Keydown = 8030;
|
|||
extern int TranslateGDKtoWXK( u32 keysym );
|
||||
#endif
|
||||
|
||||
void AppEmuThread::StateCheck( bool isCancelable )
|
||||
void AppCoreThread::StateCheck( bool isCancelable )
|
||||
{
|
||||
_parent::StateCheck( isCancelable );
|
||||
|
||||
const keyEvent* ev = PADkeyEvent();
|
||||
if( ev == NULL || (ev->key == 0) ) return;
|
||||
|
||||
GetPluginManager().KeyEvent( *ev );
|
||||
m_plugins.KeyEvent( *ev );
|
||||
m_kevt.SetEventType( ( ev->evt == KEYPRESS ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP );
|
||||
const bool isDown = (ev->evt == KEYPRESS);
|
||||
|
||||
|
@ -141,8 +156,13 @@ void AppEmuThread::StateCheck( bool isCancelable )
|
|||
wxGetApp().PostPadKey( m_kevt );
|
||||
}
|
||||
|
||||
void AppEmuThread::ApplySettings( const Pcsx2Config& src )
|
||||
// To simplify settings application rules and re-entry conditions, the main App's implementation
|
||||
// of ApplySettings requires that the caller manually ensure that the thread has been properly
|
||||
// suspended. If the thread has mot been suspended, this call will fail *silently*.
|
||||
void AppCoreThread::ApplySettings( const Pcsx2Config& src )
|
||||
{
|
||||
if( !IsSuspended() ) return;
|
||||
|
||||
// Re-entry guard protects against cases where code wants to manually set core settings
|
||||
// which are not part of g_Conf. The subsequent call to apply g_Conf settings (which is
|
||||
// usually the desired behavior) will be ignored.
|
||||
|
@ -153,17 +173,14 @@ void AppEmuThread::ApplySettings( const Pcsx2Config& src )
|
|||
SysCoreThread::ApplySettings( src );
|
||||
}
|
||||
|
||||
__forceinline bool EmulationInProgress()
|
||||
{
|
||||
return wxGetApp().EmuInProgress();
|
||||
}
|
||||
|
||||
// Returns true if there is a "valid" virtual machine state from the user's perspective. This
|
||||
// means the user has started the emulator and not issued a full reset.
|
||||
__forceinline bool SysHasValidState()
|
||||
{
|
||||
return wxGetApp().EmuInProgress() || StateRecovery::HasState();
|
||||
bool isRunning = HasCoreThread() ? GetCoreThread().IsRunning() : false;
|
||||
return isRunning || StateCopy_HasFullState();
|
||||
}
|
||||
|
||||
|
||||
bool HandlePluginError( Exception::PluginError& ex )
|
||||
{
|
||||
if( pxDialogExists( DialogId_CoreSettings ) ) return true;
|
||||
|
@ -183,7 +200,7 @@ bool HandlePluginError( Exception::PluginError& ex )
|
|||
return result;
|
||||
}
|
||||
|
||||
sptr AppEmuThread::ExecuteTask()
|
||||
sptr AppCoreThread::ExecuteTask()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -195,7 +212,7 @@ sptr AppEmuThread::ExecuteTask()
|
|||
m_plugins.Close();
|
||||
if( ex.StreamName == g_Conf->FullpathToBios() )
|
||||
{
|
||||
GetPluginManager().Close();
|
||||
m_plugins.Close();
|
||||
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
||||
_("\n\nPress Ok to go to the BIOS Configuration Panel.") );
|
||||
|
||||
|
@ -270,7 +287,7 @@ void Pcsx2App::ReadUserModeSettings()
|
|||
|
||||
wxFileName usermodefile( FilenameDefs::GetUsermodeConfig() );
|
||||
usermodefile.SetPath( usrlocaldir.ToString() );
|
||||
wxScopedPtr<wxFileConfig> conf_usermode( OpenFileConfig( usermodefile.GetFullPath() ) );
|
||||
ScopedPtr<wxFileConfig> conf_usermode( OpenFileConfig( usermodefile.GetFullPath() ) );
|
||||
|
||||
wxString groupname( wxsFormat( L"CWD.%08x", hashres ) );
|
||||
|
||||
|
@ -401,10 +418,10 @@ bool Pcsx2App::OnInit()
|
|||
wxInitAllImageHandlers();
|
||||
if( !wxApp::OnInit() ) return false;
|
||||
|
||||
g_Conf.reset( new AppConfig() );
|
||||
g_Conf = new AppConfig();
|
||||
|
||||
m_StdoutRedirHandle.reset( NewPipeRedir(stdout) );
|
||||
m_StderrRedirHandle.reset( NewPipeRedir(stderr) );
|
||||
m_StdoutRedirHandle = NewPipeRedir(stdout);
|
||||
m_StderrRedirHandle = NewPipeRedir(stderr);
|
||||
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
||||
|
||||
#define pxMessageBoxEventThing(func) \
|
||||
|
@ -416,11 +433,14 @@ bool Pcsx2App::OnInit()
|
|||
Connect( pxEVT_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
||||
Connect( pxEVT_ReloadPlugins, wxCommandEventHandler( Pcsx2App::OnReloadPlugins ) );
|
||||
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
|
||||
|
||||
Connect( pxEVT_FreezeFinished, wxCommandEventHandler( Pcsx2App::OnFreezeFinished ) );
|
||||
Connect( pxEVT_ThawFinished, wxCommandEventHandler( Pcsx2App::OnThawFinished ) );
|
||||
|
||||
Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
|
||||
|
||||
// User/Admin Mode Dual Setup:
|
||||
// Pcsx2 now supports two fundamental modes of operation. The default is Classic mode,
|
||||
// PCSX2 now supports two fundamental modes of operation. The default is Classic mode,
|
||||
// which uses the Current Working Directory (CWD) for all user data files, and requires
|
||||
// Admin access on Vista (and some Linux as well). The second mode is the Vista-
|
||||
// compatible \documents folder usage. The mode is determined by the presence and
|
||||
|
@ -456,7 +476,7 @@ bool Pcsx2App::OnInit()
|
|||
SysDetect();
|
||||
AppApplySettings();
|
||||
|
||||
m_CoreAllocs.reset( new SysCoreAllocations() );
|
||||
m_CoreAllocs = new SysCoreAllocations();
|
||||
|
||||
if( m_CoreAllocs->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
|
||||
{
|
||||
|
@ -578,6 +598,14 @@ void Pcsx2App::Ping() const
|
|||
// Pcsx2App Event Handlers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Invoked by the AppCoreThread when the thread has terminated itself.
|
||||
void Pcsx2App::OnCoreThreadTerminated( wxCommandEvent& evt )
|
||||
{
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ApplySettings();
|
||||
m_CoreThread = NULL;
|
||||
}
|
||||
|
||||
void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt )
|
||||
{
|
||||
((Semaphore*)evt.GetClientData())->Post();
|
||||
|
@ -709,7 +737,7 @@ void Pcsx2App::HandleEvent(wxEvtHandler *handler, wxEventFunction func, wxEvent&
|
|||
// the glorious user, whomever (s)he-it might be.
|
||||
bool Pcsx2App::PrepForExit()
|
||||
{
|
||||
m_CoreThread.reset();
|
||||
m_CoreThread = NULL;
|
||||
CleanupMess();
|
||||
|
||||
return true;
|
||||
|
@ -750,6 +778,36 @@ Pcsx2App::~Pcsx2App()
|
|||
CleanupMess();
|
||||
}
|
||||
|
||||
MainEmuFrame& Pcsx2App::GetMainFrame() const
|
||||
{
|
||||
wxASSERT( ((uptr)GetTopWindow()) == ((uptr)m_MainFrame) );
|
||||
wxASSERT( m_MainFrame != NULL );
|
||||
return *m_MainFrame;
|
||||
}
|
||||
|
||||
SysCoreThread& Pcsx2App::GetCoreThread() const
|
||||
{
|
||||
wxASSERT( m_CoreThread != NULL );
|
||||
return *m_CoreThread;
|
||||
}
|
||||
|
||||
|
||||
MainEmuFrame& Pcsx2App::GetMainFrameOrExcept() const
|
||||
{
|
||||
if( m_MainFrame == NULL )
|
||||
throw Exception::ObjectIsNull( "main application frame" );
|
||||
|
||||
return *m_MainFrame;
|
||||
}
|
||||
|
||||
SysCoreThread& Pcsx2App::GetCoreThreadOrExcept() const
|
||||
{
|
||||
if( !m_CoreThread )
|
||||
throw Exception::ObjectIsNull( "core emulation thread" );
|
||||
|
||||
return *m_CoreThread;
|
||||
}
|
||||
|
||||
void AppApplySettings( const AppConfig* oldconf )
|
||||
{
|
||||
DevAssert( wxThread::IsMain(), "ApplySettings valid from the GUI thread only." );
|
||||
|
@ -780,9 +838,10 @@ void AppApplySettings( const AppConfig* oldconf )
|
|||
}
|
||||
}
|
||||
|
||||
// Both AppInvokes cause unhandled runtime errors in Linux.
|
||||
AppInvoke( MainFrame, ApplySettings() );
|
||||
AppInvoke( CoreThread, ApplySettings( g_Conf->EmuOptions ) );
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().ApplySettings();
|
||||
if( HasCoreThread() )
|
||||
GetCoreThread().ApplySettings( g_Conf->EmuOptions );
|
||||
}
|
||||
|
||||
void AppLoadSettings()
|
||||
|
@ -793,7 +852,8 @@ void AppLoadSettings()
|
|||
IniLoader loader( *conf );
|
||||
g_Conf->LoadSave( loader );
|
||||
|
||||
AppInvoke( MainFrame, LoadRecentIsoList( *conf ) );
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().LoadRecentIsoList( *conf );
|
||||
}
|
||||
|
||||
void AppSaveSettings()
|
||||
|
@ -804,7 +864,8 @@ void AppSaveSettings()
|
|||
IniSaver saver( *conf );
|
||||
g_Conf->LoadSave( saver );
|
||||
|
||||
AppInvoke( MainFrame, SaveRecentIsoList( *conf ) );
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().SaveRecentIsoList( *conf );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -815,9 +876,15 @@ void AppSaveSettings()
|
|||
// configured CDVD source device.
|
||||
void Pcsx2App::SysExecute()
|
||||
{
|
||||
if( sys_resume_lock )
|
||||
{
|
||||
Console::WriteLn( "SysExecute: State is locked, ignoring Execute request!" );
|
||||
return;
|
||||
}
|
||||
|
||||
SysReset();
|
||||
LoadPluginsImmediate();
|
||||
m_CoreThread.reset( new AppEmuThread( *m_CorePlugins ) );
|
||||
m_CoreThread = new AppCoreThread( *m_CorePlugins );
|
||||
m_CoreThread->Resume();
|
||||
}
|
||||
|
||||
|
@ -826,15 +893,35 @@ void Pcsx2App::SysExecute()
|
|||
// sources.
|
||||
void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc )
|
||||
{
|
||||
if( sys_resume_lock )
|
||||
{
|
||||
Console::WriteLn( "SysExecute: State is locked, ignoring Execute request!" );
|
||||
return;
|
||||
}
|
||||
|
||||
SysReset();
|
||||
LoadPluginsImmediate();
|
||||
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
||||
CDVDsys_ChangeSource( cdvdsrc );
|
||||
|
||||
m_CoreThread.reset( new AppEmuThread( *m_CorePlugins ) );
|
||||
m_CoreThread = new AppCoreThread( *m_CorePlugins );
|
||||
m_CoreThread->Resume();
|
||||
}
|
||||
|
||||
void Pcsx2App::SysReset()
|
||||
{
|
||||
m_CoreThread = NULL;
|
||||
}
|
||||
|
||||
// Returns the state of the emulated system (Virtual Machine). Returns true if the
|
||||
// system is active, or is in the process of reporting or handling an error. Returns
|
||||
// false if there is no active system (thread is shutdown or hasn't been started).
|
||||
bool Pcsx2App::SysIsActive() const
|
||||
{
|
||||
return m_CoreThread && m_CoreThread->IsRunning();
|
||||
}
|
||||
|
||||
|
||||
void Pcsx2App::OpenGsFrame()
|
||||
{
|
||||
if( m_gsFrame != NULL ) return;
|
||||
|
@ -857,11 +944,13 @@ void Pcsx2App::OnGsFrameClosed()
|
|||
|
||||
|
||||
// Writes text to console and updates the window status bar and/or HUD or whateverness.
|
||||
// FIXME: This probably isn't thread safe. >_<
|
||||
void SysStatus( const wxString& text )
|
||||
{
|
||||
// mirror output to the console!
|
||||
Console::Status( text.c_str() );
|
||||
AppInvoke( MainFrame, SetStatusText( text ) );
|
||||
if( HasMainFrame() )
|
||||
GetMainFrame().SetStatusText( text );
|
||||
}
|
||||
|
||||
// Executes the emulator using a saved/existing virtual machine state and currently
|
||||
|
@ -878,18 +967,48 @@ void SysExecute( CDVD_SourceType cdvdsrc )
|
|||
|
||||
void SysResume()
|
||||
{
|
||||
AppInvoke( CoreThread, Resume() );
|
||||
if( !HasCoreThread() ) return;
|
||||
|
||||
if( sys_resume_lock )
|
||||
{
|
||||
Console::WriteLn( "SysResume: State is locked, ignoring Resume request!" );
|
||||
return;
|
||||
}
|
||||
|
||||
GetCoreThread().Resume();
|
||||
}
|
||||
|
||||
void SysSuspend( bool closePlugins )
|
||||
{
|
||||
if( !HasCoreThread() ) return;
|
||||
|
||||
if( closePlugins )
|
||||
AppInvoke( CoreThread, Suspend(closePlugins) );
|
||||
GetCoreThread().Suspend();
|
||||
else
|
||||
AppInvoke( CoreThread, ShortSuspend() );
|
||||
GetCoreThread().ShortSuspend();
|
||||
}
|
||||
|
||||
void SysReset()
|
||||
{
|
||||
wxGetApp().SysReset();
|
||||
}
|
||||
|
||||
bool HasMainFrame()
|
||||
{
|
||||
return wxGetApp().HasMainFrame();
|
||||
}
|
||||
|
||||
bool HasCoreThread()
|
||||
{
|
||||
return wxGetApp().HasCoreThread();
|
||||
}
|
||||
|
||||
MainEmuFrame& GetMainFrame()
|
||||
{
|
||||
return wxGetApp().GetMainFrame();
|
||||
}
|
||||
|
||||
SysCoreThread& GetCoreThread()
|
||||
{
|
||||
return wxGetApp().GetCoreThread();
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ const wxImage& LoadImageAny(
|
|||
// ------------------------------------------------------------------------
|
||||
const wxBitmap& Pcsx2App::GetLogoBitmap()
|
||||
{
|
||||
if( m_Bitmap_Logo != NULL )
|
||||
if( m_Bitmap_Logo )
|
||||
return *m_Bitmap_Logo;
|
||||
|
||||
wxFileName mess;
|
||||
|
@ -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.reset( new wxBitmap( img ) );
|
||||
m_Bitmap_Logo = new wxBitmap( img );
|
||||
|
||||
return *m_Bitmap_Logo;
|
||||
}
|
||||
|
@ -137,10 +137,10 @@ wxImageList& Pcsx2App::GetImgList_Config()
|
|||
// ------------------------------------------------------------------------
|
||||
wxImageList& Pcsx2App::GetImgList_Toolbars()
|
||||
{
|
||||
if( m_ToolbarImages == NULL )
|
||||
if( !m_ToolbarImages )
|
||||
{
|
||||
const int imgSize = g_Conf->Toolbar_ImageSize ? 64 : 32;
|
||||
m_ToolbarImages.reset( new wxImageList( imgSize, imgSize ) );
|
||||
m_ToolbarImages = new wxImageList( imgSize, imgSize );
|
||||
wxFileName mess;
|
||||
bool useTheme = (g_Conf->DeskTheme != L"default");
|
||||
|
||||
|
|
|
@ -72,14 +72,13 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
|||
static const wxString LabelGreets = wxString::FromUTF8(
|
||||
"Contributors"
|
||||
"\n\n"
|
||||
"Hiryu and Sjeep for libcvd (the iso parsing and"
|
||||
"filesystem driver code), nneeve (fpu and vu help)"
|
||||
"Hiryu and Sjeep (libcdvd / iso filesystem), nneeve (fpu and vu)"
|
||||
"\n\n"
|
||||
"Plugin Specialists: ChickenLiver (Lilypad), Efp (efp),"
|
||||
"Gabest (Gsdx, Cdvdolio, Xpad), Zeydlitz (ZZogl)"
|
||||
"\n\n"
|
||||
"Special thanks to: black_wd, Belmont, BGome, _Demo_, Dreamtime,"
|
||||
"F|RES, MrBrown, razorblade, Seta-san, Skarmeth"
|
||||
"F|RES, MrBrown, razorblade, Seta-san, Skarmeth, feal87"
|
||||
);
|
||||
|
||||
wxBoxSizer& mainSizer = *new wxBoxSizer( wxVERTICAL );
|
||||
|
|
|
@ -33,13 +33,13 @@ void GSFrame::InitDefaultAccelerators()
|
|||
m_Accels.Map( AAC( WXK_TAB ), "Framelimiter_TurboToggle" );
|
||||
m_Accels.Map( AAC( WXK_TAB ).Shift(), "Framelimiter_MasterToggle" );
|
||||
|
||||
m_Accels.Map( AAC( WXK_ESCAPE ), "Emu_Suspend" );
|
||||
m_Accels.Map( AAC( WXK_F8 ), "Emu_TakeSnapshot" );
|
||||
m_Accels.Map( AAC( WXK_F9 ), "Emu_RenderswitchToggle" );
|
||||
m_Accels.Map( AAC( WXK_ESCAPE ), "Sys_Suspend" );
|
||||
m_Accels.Map( AAC( WXK_F8 ), "Sys_TakeSnapshot" );
|
||||
m_Accels.Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle" );
|
||||
|
||||
m_Accels.Map( AAC( WXK_F10 ), "Emu_LoggingToggle" );
|
||||
m_Accels.Map( AAC( WXK_F11 ), "Emu_FreezeGS" );
|
||||
m_Accels.Map( AAC( WXK_F12 ), "Emu_RecordingToggle" );
|
||||
m_Accels.Map( AAC( WXK_F10 ), "Sys_LoggingToggle" );
|
||||
m_Accels.Map( AAC( WXK_F11 ), "Sys_FreezeGS" );
|
||||
m_Accels.Map( AAC( WXK_F12 ), "Sys_RecordingToggle" );
|
||||
}
|
||||
|
||||
GSFrame::GSFrame(wxWindow* parent, const wxString& title):
|
||||
|
@ -54,7 +54,8 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title):
|
|||
|
||||
GSFrame::~GSFrame() throw()
|
||||
{
|
||||
AppInvoke( CoreThread, Suspend() ); // Just in case...!
|
||||
if( HasCoreThread() )
|
||||
GetCoreThread().Suspend(); // Just in case...!
|
||||
}
|
||||
|
||||
void GSFrame::OnCloseWindow(wxCloseEvent& evt)
|
||||
|
|
|
@ -69,31 +69,32 @@ namespace Implementations
|
|||
{
|
||||
}
|
||||
|
||||
void Emu_Suspend()
|
||||
void Sys_Suspend()
|
||||
{
|
||||
AppInvoke( CoreThread, Suspend() );
|
||||
AppInvoke( MainFrame, ApplySettings() );
|
||||
if( HasCoreThread() )
|
||||
GetCoreThread().Suspend();
|
||||
}
|
||||
|
||||
void Emu_Resume()
|
||||
void Sys_Resume()
|
||||
{
|
||||
AppInvoke( CoreThread, Resume() );
|
||||
AppInvoke( MainFrame, ApplySettings() );
|
||||
if( HasCoreThread() )
|
||||
GetCoreThread().Resume();
|
||||
}
|
||||
|
||||
void Emu_TakeSnapshot()
|
||||
void Sys_TakeSnapshot()
|
||||
{
|
||||
GSmakeSnapshot( g_Conf->Folders.Snapshots.ToAscii().data() );
|
||||
}
|
||||
|
||||
void Emu_RenderToggle()
|
||||
void Sys_RenderToggle()
|
||||
{
|
||||
AppInvoke( CoreThread, Suspend() );
|
||||
if( !HasCoreThread() ) return;
|
||||
SysSuspend();
|
||||
renderswitch = !renderswitch;
|
||||
AppInvoke( CoreThread, Resume() );
|
||||
SysResume();
|
||||
}
|
||||
|
||||
void Emu_LoggingToggle()
|
||||
void Sys_LoggingToggle()
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
// There's likely a better way to implement this, but this seemed useful.
|
||||
|
@ -108,7 +109,7 @@ namespace Implementations
|
|||
#endif
|
||||
}
|
||||
|
||||
void Emu_FreezeGS()
|
||||
void Sys_FreezeGS()
|
||||
{
|
||||
// fixme : fix up gsstate mess and make it mtgs compatible -- air
|
||||
#ifdef _STGS_GSSTATE_CODE
|
||||
|
@ -137,7 +138,7 @@ namespace Implementations
|
|||
|
||||
}
|
||||
|
||||
void Emu_RecordingToggle()
|
||||
void Sys_RecordingToggle()
|
||||
{
|
||||
g_Pcsx2Recording ^= 1;
|
||||
|
||||
|
@ -206,37 +207,37 @@ static const GlobalCommandDescriptor CommandDeclarations[] =
|
|||
NULL,
|
||||
},
|
||||
|
||||
{ "Emu_Suspend",
|
||||
Implementations::Emu_Suspend,
|
||||
{ "Sys_Suspend",
|
||||
Implementations::Sys_Suspend,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
|
||||
{ "Emu_TakeSnapshot",
|
||||
Implementations::Emu_TakeSnapshot,
|
||||
{ "Sys_TakeSnapshot",
|
||||
Implementations::Sys_TakeSnapshot,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
|
||||
{ "Emu_RenderswitchToggle",
|
||||
Implementations::Emu_RenderToggle,
|
||||
{ "Sys_RenderswitchToggle",
|
||||
Implementations::Sys_RenderToggle,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
|
||||
{ "Emu_LoggingToggle",
|
||||
Implementations::Emu_LoggingToggle,
|
||||
{ "Sys_LoggingToggle",
|
||||
Implementations::Sys_LoggingToggle,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
|
||||
{ "Emu_FreezeGS",
|
||||
Implementations::Emu_FreezeGS,
|
||||
{ "Sys_FreezeGS",
|
||||
Implementations::Sys_FreezeGS,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
{ "Emu_RecordingToggle",
|
||||
Implementations::Emu_RecordingToggle,
|
||||
{ "Sys_RecordingToggle",
|
||||
Implementations::Sys_RecordingToggle,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
|
@ -304,11 +305,11 @@ void Pcsx2App::InitDefaultGlobalAccelerators()
|
|||
GlobalAccels.Map( AAC( WXK_TAB ), "Framelimiter_TurboToggle" );
|
||||
GlobalAccels.Map( AAC( WXK_TAB ).Shift(), "Framelimiter_MasterToggle" );
|
||||
|
||||
GlobalAccels.Map( AAC( WXK_ESCAPE ), "Emu_Suspend");
|
||||
GlobalAccels.Map( AAC( WXK_F8 ), "Emu_TakeSnapshot");
|
||||
GlobalAccels.Map( AAC( WXK_F9 ), "Emu_RenderswitchToggle");
|
||||
GlobalAccels.Map( AAC( WXK_ESCAPE ), "Sys_Suspend");
|
||||
GlobalAccels.Map( AAC( WXK_F8 ), "Sys_TakeSnapshot");
|
||||
GlobalAccels.Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle");
|
||||
|
||||
GlobalAccels.Map( AAC( WXK_F10 ), "Emu_LoggingToggle");
|
||||
GlobalAccels.Map( AAC( WXK_F11 ), "Emu_FreezeGS");
|
||||
GlobalAccels.Map( AAC( WXK_F12 ), "Emu_RecordingToggle");
|
||||
GlobalAccels.Map( AAC( WXK_F10 ), "Sys_LoggingToggle");
|
||||
GlobalAccels.Map( AAC( WXK_F11 ), "Sys_FreezeGS");
|
||||
GlobalAccels.Map( AAC( WXK_F12 ), "Sys_RecordingToggle");
|
||||
}
|
||||
|
|
|
@ -211,8 +211,8 @@ void MainEmuFrame::ConnectMenus()
|
|||
ConnectMenu( MenuId_SkipBiosToggle, Menu_SkipBiosToggle_Click );
|
||||
ConnectMenu( MenuId_Exit, Menu_Exit_Click );
|
||||
|
||||
ConnectMenu( MenuId_Emu_SuspendResume, Menu_SuspendResume_Click );
|
||||
ConnectMenu( MenuId_Emu_Reset, Menu_EmuReset_Click );
|
||||
ConnectMenu( MenuId_Sys_SuspendResume, Menu_SuspendResume_Click );
|
||||
ConnectMenu( MenuId_Sys_Reset, Menu_EmuReset_Click );
|
||||
|
||||
ConnectMenu( MenuId_State_LoadOther, Menu_LoadStateOther_Click );
|
||||
|
||||
|
@ -367,23 +367,23 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title):
|
|||
_("Closing PCSX2 may be hazardous to your health"));
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
m_menuEmu.Append(MenuId_Emu_SuspendResume, _("Suspend"),
|
||||
m_menuEmu.Append(MenuId_Sys_SuspendResume, _("Suspend"),
|
||||
_("Stops emulation dead in its tracks") )->Enable( SysHasValidState() );
|
||||
|
||||
m_menuEmu.AppendSeparator();
|
||||
|
||||
//m_menuEmu.Append(MenuId_Emu_Close, _("Close"),
|
||||
//m_menuEmu.Append(MenuId_Sys_Close, _("Close"),
|
||||
// _("Stops emulation and closes the GS window."));
|
||||
|
||||
m_menuEmu.Append(MenuId_Emu_LoadStates, _("Load state"), &m_LoadStatesSubmenu);
|
||||
m_menuEmu.Append(MenuId_Emu_SaveStates, _("Save state"), &m_SaveStatesSubmenu);
|
||||
m_menuEmu.Append(MenuId_Sys_LoadStates, _("Load state"), &m_LoadStatesSubmenu);
|
||||
m_menuEmu.Append(MenuId_Sys_SaveStates, _("Save state"), &m_SaveStatesSubmenu);
|
||||
|
||||
m_menuEmu.AppendSeparator();
|
||||
m_menuEmu.Append(MenuId_EnablePatches, _("Enable Patches"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
|
||||
m_menuEmu.AppendSeparator();
|
||||
m_menuEmu.Append(MenuId_Emu_Reset, _("Reset"),
|
||||
m_menuEmu.Append(MenuId_Sys_Reset, _("Reset"),
|
||||
_("Resets emulation state and re-runs current image"));
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -470,9 +470,7 @@ void MainEmuFrame::ReloadRecentLists()
|
|||
|
||||
if( m_RecentIsoList )
|
||||
m_RecentIsoList->Save( *cfg );
|
||||
m_RecentIsoList.reset();
|
||||
m_RecentIsoList.reset( new wxFileHistory( g_Conf->RecentFileCount ) );
|
||||
m_RecentIsoList->Load( *cfg );
|
||||
m_RecentIsoList.Reassign( new wxFileHistory(g_Conf->RecentFileCount) )->Load( *cfg );
|
||||
UpdateIsoSrcFile();
|
||||
cfg->Flush();
|
||||
}
|
||||
|
@ -484,12 +482,11 @@ void MainEmuFrame::ApplySettings()
|
|||
GetMenuBar()->Check( MenuId_Config_Multitap0Toggle, g_Conf->EmuOptions.MultitapPort0_Enabled );
|
||||
GetMenuBar()->Check( MenuId_Config_Multitap1Toggle, g_Conf->EmuOptions.MultitapPort1_Enabled );
|
||||
|
||||
GetMenuBar()->Enable( MenuId_Emu_SuspendResume, SysHasValidState() );
|
||||
|
||||
bool result = false;
|
||||
AppInvokeBool( CoreThread, IsSuspended(), result );
|
||||
GetMenuBar()->SetLabel( MenuId_Emu_SuspendResume, result ? _("Resume") :_("Suspend") );
|
||||
GetMenuBar()->Enable( MenuId_Sys_SuspendResume, SysHasValidState() );
|
||||
|
||||
if( HasCoreThread() )
|
||||
GetMenuBar()->SetLabel( MenuId_Sys_SuspendResume, GetCoreThread().IsSuspended() ? _("Resume") :_("Suspend") );
|
||||
|
||||
if( m_RecentIsoList )
|
||||
{
|
||||
if( m_RecentIsoList->GetMaxFiles() != g_Conf->RecentFileCount )
|
||||
|
|
|
@ -43,7 +43,7 @@ class MainEmuFrame : public wxFrame
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
protected:
|
||||
wxScopedPtr<wxFileHistory> m_RecentIsoList;
|
||||
ScopedPtr<wxFileHistory> m_RecentIsoList;
|
||||
wxStatusBar& m_statusbar;
|
||||
wxStaticBitmap m_background;
|
||||
|
||||
|
@ -74,7 +74,7 @@ public:
|
|||
|
||||
void OnLogBoxHidden();
|
||||
|
||||
bool IsPaused() const { return GetMenuBar()->IsChecked( MenuId_Emu_SuspendResume ); }
|
||||
bool IsPaused() const { return GetMenuBar()->IsChecked( MenuId_Sys_SuspendResume ); }
|
||||
void UpdateIsoSrcFile();
|
||||
void UpdateIsoSrcSelection();
|
||||
void ApplySettings();
|
||||
|
|
|
@ -93,10 +93,10 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
|||
}
|
||||
}
|
||||
|
||||
if( EmulationInProgress() )
|
||||
if( SysHasValidState() )
|
||||
{
|
||||
// [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?") );
|
||||
bool result = Msgbox::OkCancel( pxE( ".Popup:ConfirmSysReset", L"This will reset the emulator and your current emulation session will be lost. Are you sure?") );
|
||||
|
||||
if( !result )
|
||||
{
|
||||
|
@ -190,11 +190,9 @@ void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
|
|||
void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event)
|
||||
{
|
||||
if( !SysHasValidState() ) return;
|
||||
if( !HasCoreThread() ) return;
|
||||
|
||||
bool result = false;
|
||||
AppInvokeBool( CoreThread, IsSuspended(), result );
|
||||
|
||||
if( result )
|
||||
if( GetCoreThread().IsSuspended() )
|
||||
SysResume();
|
||||
else
|
||||
SysSuspend();
|
||||
|
@ -202,15 +200,13 @@ void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event)
|
|||
|
||||
void MainEmuFrame::Menu_EmuReset_Click(wxCommandEvent &event)
|
||||
{
|
||||
bool wasInProgress = EmulationInProgress();
|
||||
bool wasSuspended;
|
||||
|
||||
AppInvokeBool( CoreThread, IsSuspended(), wasSuspended );
|
||||
if( !SysHasValidState() ) return;
|
||||
bool wasSuspended = HasCoreThread() ? GetCoreThread().IsSuspended() : true;
|
||||
|
||||
SysReset();
|
||||
|
||||
if( !wasInProgress || wasSuspended ) return;
|
||||
SysExecute();
|
||||
if( !wasSuspended )
|
||||
SysExecute();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_ConfigPlugin_Click(wxCommandEvent &event)
|
||||
|
|
|
@ -95,15 +95,15 @@ bool Panels::BiosSelectorPanel::ValidateEnumerationStatus()
|
|||
|
||||
// Impl Note: ScopedPtr used so that resources get cleaned up if an exception
|
||||
// occurs during file enumeration.
|
||||
wxScopedPtr<wxArrayString> bioslist( new wxArrayString() );
|
||||
ScopedPtr<wxArrayString> bioslist( new wxArrayString() );
|
||||
|
||||
if( m_FolderPicker.GetPath().Exists() )
|
||||
wxDir::GetAllFiles( m_FolderPicker.GetPath().ToString(), bioslist.get(), L"*.bin", wxDIR_FILES );
|
||||
wxDir::GetAllFiles( m_FolderPicker.GetPath().ToString(), bioslist, L"*.bin", wxDIR_FILES );
|
||||
|
||||
if( !m_BiosList || (*bioslist != *m_BiosList) )
|
||||
validated = false;
|
||||
|
||||
m_BiosList.swap( bioslist );
|
||||
m_BiosList.SwapPtr( bioslist );
|
||||
|
||||
return validated;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace Exception
|
|||
Panels::BaseApplicableConfigPanel* m_Panel;
|
||||
|
||||
public:
|
||||
virtual ~CannotApplySettings() throw() {}
|
||||
DEFINE_EXCEPTION_COPYTORS( CannotApplySettings )
|
||||
|
||||
explicit CannotApplySettings( Panels::BaseApplicableConfigPanel* thispanel, const char* msg=wxLt("Cannot apply new settings, one of the settings is invalid.") )
|
||||
{
|
||||
|
@ -351,7 +351,7 @@ namespace Panels
|
|||
class BiosSelectorPanel : public BaseSelectorPanel
|
||||
{
|
||||
protected:
|
||||
wxScopedPtr<wxArrayString> m_BiosList;
|
||||
ScopedPtr<wxArrayString> m_BiosList;
|
||||
wxListBox& m_ComboBox;
|
||||
DirPickerPanel& m_FolderPicker;
|
||||
|
||||
|
@ -454,8 +454,8 @@ namespace Panels
|
|||
ComboBoxPanel& m_ComponentBoxes;
|
||||
bool m_Canceled;
|
||||
|
||||
wxScopedPtr<wxArrayString> m_FileList; // list of potential plugin files
|
||||
wxScopedPtr<EnumThread> m_EnumeratorThread;
|
||||
ScopedPtr<wxArrayString> m_FileList; // list of potential plugin files
|
||||
ScopedPtr<EnumThread> m_EnumeratorThread;
|
||||
|
||||
public:
|
||||
virtual ~PluginSelectorPanel();
|
||||
|
|
|
@ -364,9 +364,7 @@ void Panels::PluginSelectorPanel::DoRefresh()
|
|||
wxCommandEvent evt( pxEVT_ShowStatusBar );
|
||||
GetEventHandler()->AddPendingEvent( evt );
|
||||
|
||||
// Use a thread to load plugins.
|
||||
m_EnumeratorThread.reset( NULL );
|
||||
m_EnumeratorThread.reset( new EnumThread( *this ) );
|
||||
m_EnumeratorThread.Delete() = new EnumThread( *this );
|
||||
|
||||
if( DisableThreading )
|
||||
m_EnumeratorThread->DoNextPlugin( 0 );
|
||||
|
@ -376,7 +374,7 @@ void Panels::PluginSelectorPanel::DoRefresh()
|
|||
|
||||
bool Panels::PluginSelectorPanel::ValidateEnumerationStatus()
|
||||
{
|
||||
m_EnumeratorThread.reset(); // make sure the thread is STOPPED, just in case...
|
||||
m_EnumeratorThread = NULL; // make sure the thread is STOPPED, just in case...
|
||||
|
||||
bool validated = true;
|
||||
|
||||
|
@ -385,20 +383,20 @@ bool Panels::PluginSelectorPanel::ValidateEnumerationStatus()
|
|||
|
||||
// Impl Note: ScopedPtr used so that resources get cleaned up if an exception
|
||||
// occurs during file enumeration.
|
||||
wxScopedPtr<wxArrayString> pluginlist( new wxArrayString() );
|
||||
ScopedPtr<wxArrayString> pluginlist( new wxArrayString() );
|
||||
|
||||
int pluggers = EnumeratePluginsInFolder( m_ComponentBoxes.GetPluginsPath(), pluginlist.get() );
|
||||
int pluggers = EnumeratePluginsInFolder( m_ComponentBoxes.GetPluginsPath(), pluginlist );
|
||||
|
||||
if( !m_FileList || (*pluginlist != *m_FileList) )
|
||||
validated = false;
|
||||
|
||||
if( pluggers == 0 )
|
||||
{
|
||||
m_FileList.reset();
|
||||
m_FileList = NULL;
|
||||
return validated;
|
||||
}
|
||||
|
||||
m_FileList.swap( pluginlist );
|
||||
m_FileList.SwapPtr( pluginlist );
|
||||
|
||||
m_StatusPanel.SetGaugeLength( pluggers );
|
||||
|
||||
|
@ -428,7 +426,7 @@ void Panels::PluginSelectorPanel::OnShowStatusBar( wxCommandEvent& evt )
|
|||
|
||||
void Panels::PluginSelectorPanel::OnEnumComplete( wxCommandEvent& evt )
|
||||
{
|
||||
m_EnumeratorThread.reset();
|
||||
m_EnumeratorThread = NULL;
|
||||
|
||||
// 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)
|
||||
|
|
|
@ -63,13 +63,15 @@ protected:
|
|||
int ExecuteTask();
|
||||
};
|
||||
|
||||
static wxScopedPtr<LoadPluginsTask> _loadTask;
|
||||
static ScopedPtr<LoadPluginsTask> _loadTask;
|
||||
|
||||
LoadPluginsTask::~LoadPluginsTask() throw()
|
||||
{
|
||||
_loadTask.release();
|
||||
if( _loadTask )
|
||||
_loadTask.DetachPtr(); // avoids recursive deletion
|
||||
|
||||
PersistentThread::Cancel();
|
||||
_loadTask.reset();
|
||||
_loadTask = NULL;
|
||||
}
|
||||
|
||||
int LoadPluginsTask::ExecuteTask()
|
||||
|
@ -111,10 +113,10 @@ int LoadPluginsTask::ExecuteTask()
|
|||
|
||||
int EnumeratePluginsInFolder( const wxDirName& searchpath, wxArrayString* dest )
|
||||
{
|
||||
wxScopedPtr<wxArrayString> placebo;
|
||||
ScopedPtr<wxArrayString> placebo;
|
||||
wxArrayString* realdest = dest;
|
||||
if( realdest == NULL )
|
||||
placebo.reset( realdest = new wxArrayString() );
|
||||
placebo = realdest = new wxArrayString(); // placebo is our /dev/null -- gets deleted when done
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// Windows pretty well has a strict "must end in .dll" rule.
|
||||
|
@ -137,8 +139,8 @@ void Pcsx2App::OnReloadPlugins( wxCommandEvent& evt )
|
|||
void Pcsx2App::OnLoadPluginsComplete( wxCommandEvent& evt )
|
||||
{
|
||||
// scoped ptr ensures the thread object is cleaned up even on exception:
|
||||
wxScopedPtr<LoadPluginsTask> killTask( (LoadPluginsTask*)evt.GetClientData() );
|
||||
m_CorePlugins.reset( killTask->Result );
|
||||
ScopedPtr<LoadPluginsTask> killTask( (LoadPluginsTask*)evt.GetClientData() );
|
||||
m_CorePlugins = killTask->Result;
|
||||
|
||||
if( !m_CorePlugins )
|
||||
{
|
||||
|
@ -153,8 +155,8 @@ void Pcsx2App::ReloadPlugins()
|
|||
{
|
||||
if( _loadTask ) return;
|
||||
|
||||
m_CoreThread.reset();
|
||||
m_CorePlugins.reset();
|
||||
m_CoreThread = NULL;
|
||||
m_CorePlugins = NULL;
|
||||
|
||||
wxString passins[PluginId_Count];
|
||||
|
||||
|
@ -166,7 +168,7 @@ void Pcsx2App::ReloadPlugins()
|
|||
passins[pi->id] = g_Conf->FullpathTo( pi->id );
|
||||
} while( ++pi, pi->shortname != NULL );
|
||||
|
||||
_loadTask.reset( new LoadPluginsTask( passins ) );
|
||||
_loadTask.Delete() = new LoadPluginsTask( passins );
|
||||
// ... and when it finishes it posts up a OnLoadPluginsComplete(). Bye. :)
|
||||
}
|
||||
|
||||
|
@ -203,5 +205,5 @@ void LoadPluginsImmediate()
|
|||
|
||||
void UnloadPlugins()
|
||||
{
|
||||
wxGetApp().m_CorePlugins.reset();
|
||||
wxGetApp().m_CorePlugins = NULL;
|
||||
}
|
||||
|
|
|
@ -23,16 +23,6 @@
|
|||
|
||||
StartupParams g_Startup;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Save Slot Detection System
|
||||
|
||||
bool States_isSlotUsed(int num)
|
||||
{
|
||||
if (ElfCRC == 0)
|
||||
return false;
|
||||
else
|
||||
return wxFileExists( SaveStateBase::GetFilename( num ) );
|
||||
}
|
||||
|
||||
// returns true if the new state was loaded, or false if nothing happened.
|
||||
void States_Load( const wxString& file )
|
||||
|
@ -55,7 +45,7 @@ void States_Load( const wxString& file )
|
|||
catch( Exception::BaseException& )
|
||||
{
|
||||
// VM state is probably ruined. We'll need to recover from the in-memory backup.
|
||||
StateRecovery::Recover();
|
||||
//StateRecovery::Recover();
|
||||
}
|
||||
|
||||
SysExecute();
|
||||
|
@ -64,7 +54,7 @@ void States_Load( const wxString& file )
|
|||
// Save state save-to-file (or slot) helpers.
|
||||
void States_Save( const wxString& file )
|
||||
{
|
||||
if( !EmulationInProgress() )
|
||||
if( !SysHasValidState() )
|
||||
{
|
||||
Msgbox::Alert( _("You need to start emulation first before you can save it's state.") );
|
||||
return;
|
||||
|
@ -73,7 +63,7 @@ void States_Save( const wxString& file )
|
|||
try
|
||||
{
|
||||
Console::Status( wxsFormat( L"Saving savestate to file: %s", file.c_str() ) );
|
||||
StateRecovery::SaveToFile( file );
|
||||
StateCopy_SaveToFile( file );
|
||||
SysStatus( wxsFormat( _("State saved to file: %s"), wxFileName( file ).GetFullName().c_str() ) );
|
||||
}
|
||||
catch( Exception::BaseException& ex )
|
||||
|
@ -103,6 +93,14 @@ void States_Save( const wxString& file )
|
|||
static int StatesC = 0;
|
||||
static const int StateSlotsCount = 10;
|
||||
|
||||
bool States_isSlotUsed(int num)
|
||||
{
|
||||
if (ElfCRC == 0)
|
||||
return false;
|
||||
else
|
||||
return wxFileExists( SaveStateBase::GetFilename( num ) );
|
||||
}
|
||||
|
||||
void States_FreezeCurrentSlot()
|
||||
{
|
||||
Console::Status( "Saving savestate to slot %d...", StatesC );
|
||||
|
|
|
@ -1938,10 +1938,6 @@
|
|||
RelativePath="..\..\gui\GlobalCommands.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\HostGui.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\i18n.cpp"
|
||||
>
|
||||
|
@ -2519,6 +2515,10 @@
|
|||
RelativePath="..\..\gui\Resources\EmbeddedImage.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\HostGui.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\IniInterface.h"
|
||||
>
|
||||
|
|
|
@ -153,6 +153,7 @@ public:
|
|||
m_outpipe( outpipe )
|
||||
, m_color( color )
|
||||
{
|
||||
m_name = (m_color == Color_Red) ? L"Redirect_Stderr" : L"Redirect_Stdout";
|
||||
}
|
||||
|
||||
virtual ~WinPipeThread() throw()
|
||||
|
@ -166,8 +167,6 @@ protected:
|
|||
try
|
||||
{
|
||||
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
|
||||
SetName( (m_color == Color_Red) ? "Redirect_Stderr" :" Redirect_Stdout" );
|
||||
|
||||
while( true )
|
||||
{
|
||||
Sleep( 100 );
|
||||
|
|
Loading…
Reference in New Issue