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.
|
// 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
|
#ifdef __cplusplus
|
||||||
struct u128
|
struct u128
|
||||||
{
|
{
|
||||||
u64 lo;
|
u64 lo;
|
||||||
u64 hi;
|
u64 hi;
|
||||||
|
|
||||||
// Implicit conversion from u64
|
// Explicit conversion from u64
|
||||||
u128( u64 src ) :
|
static u128 From64( u64 src )
|
||||||
lo( src )
|
{
|
||||||
, hi( 0 ) {}
|
u128 retval = { src, 0 };
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
// Implicit conversion from u32
|
// Explicit conversion from u32
|
||||||
u128( u32 src ) :
|
static u128 From32( u32 src )
|
||||||
lo( src )
|
{
|
||||||
, hi( 0 ) {}
|
u128 retval = { src, 0 };
|
||||||
|
return retval;
|
||||||
u128() {}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct s128
|
struct s128
|
||||||
|
@ -129,17 +136,19 @@ struct s128
|
||||||
s64 lo;
|
s64 lo;
|
||||||
s64 hi;
|
s64 hi;
|
||||||
|
|
||||||
// Implicit conversion from u64
|
// explicit conversion from s64, with sign extension.
|
||||||
s128( s64 src ) :
|
static s128 From64( s64 src )
|
||||||
lo( src )
|
{
|
||||||
, hi( 0 ) {}
|
s128 retval = { src, (src < 0) ? -1 : 0 };
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
// Implicit conversion from u32
|
// explicit conversion from s32, with sign extension.
|
||||||
s128( s32 src ) :
|
static s128 From64( s32 src )
|
||||||
lo( src )
|
{
|
||||||
, hi( 0 ) {}
|
s128 retval = { src, (src < 0) ? -1 : 0 };
|
||||||
|
return retval;
|
||||||
s128() {}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -47,6 +47,8 @@ extern bool DevAssert( bool condition, const char* msg );
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
|
int MakeNewType();
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// BaseException
|
// BaseException
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -87,6 +89,9 @@ namespace Exception
|
||||||
// Returns a message suitable for end-user display.
|
// Returns a message suitable for end-user display.
|
||||||
// This message is usually meant for display in a user popup or such.
|
// This message is usually meant for display in a user popup or such.
|
||||||
virtual wxString FormatDisplayMessage() const { return m_message_user; }
|
virtual wxString FormatDisplayMessage() const { return m_message_user; }
|
||||||
|
|
||||||
|
virtual void Rethrow() const=0;
|
||||||
|
virtual BaseException* Clone() const=0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Construction using two pre-formatted pre-translated messages
|
// Construction using two pre-formatted pre-translated messages
|
||||||
|
@ -129,7 +134,9 @@ namespace Exception
|
||||||
// it will be optionally translated.
|
// it will be optionally translated.
|
||||||
//
|
//
|
||||||
#define DEFINE_EXCEPTION_COPYTORS( classname ) \
|
#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 DEFINE_RUNTIME_EXCEPTION( classname, defmsg ) \
|
||||||
DEFINE_EXCEPTION_COPYTORS( classname ) \
|
DEFINE_EXCEPTION_COPYTORS( classname ) \
|
||||||
|
@ -161,7 +168,7 @@ namespace Exception
|
||||||
DEFINE_LOGIC_EXCEPTION( LogicError, wxLt("An unhandled logic error has occurred.") )
|
DEFINE_LOGIC_EXCEPTION( LogicError, wxLt("An unhandled logic error has occurred.") )
|
||||||
};
|
};
|
||||||
|
|
||||||
class ObjectIsNull : public RuntimeError
|
class ObjectIsNull : public virtual RuntimeError
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxString ObjectName;
|
wxString ObjectName;
|
||||||
|
|
|
@ -33,27 +33,33 @@ extern void pcsx2_aligned_free(void* pmem);
|
||||||
// pointer to null after deallocation.
|
// pointer to null after deallocation.
|
||||||
|
|
||||||
#define safe_delete( ptr ) \
|
#define safe_delete( ptr ) \
|
||||||
((void) (delete ptr), ptr = NULL)
|
((void) (delete (ptr)), (ptr) = NULL)
|
||||||
|
|
||||||
#define safe_delete_array( ptr ) \
|
#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
|
// 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
|
// 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
|
// didn't always check, so best to be cautious unless absolutely certain it's being covered on
|
||||||
// all ported platforms.
|
// all ported platforms.
|
||||||
#define safe_free( ptr ) \
|
#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
|
// 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
|
// NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to
|
||||||
// do it here.
|
// do it here.
|
||||||
#define safe_aligned_free( ptr ) \
|
#define safe_aligned_free( ptr ) \
|
||||||
((void) ( _aligned_free( ptr ), ptr = NULL ))
|
((void) ( _aligned_free( ptr ), (ptr) = NULL ))
|
||||||
|
|
||||||
#define SafeSysMunmap( ptr, size ) \
|
#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
|
// Handy little class for allocating a resizable memory block, complete with
|
||||||
|
|
|
@ -1,4 +1,210 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <wx/scopedptr.h>
|
|
||||||
#include <wx/scopedarray.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 <semaphore.h>
|
||||||
|
|
||||||
#include "Pcsx2Defs.h"
|
#include "Pcsx2Defs.h"
|
||||||
|
#include "ScopedPtr.h"
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
|
@ -87,6 +88,7 @@ namespace Threading
|
||||||
|
|
||||||
void Lock();
|
void Lock();
|
||||||
void Unlock();
|
void Unlock();
|
||||||
|
bool TryLock();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns the number of available logical CPUs (cores plus hyperthreaded cpus)
|
// 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.
|
// sleeps the current thread for the given number of milliseconds.
|
||||||
extern void Sleep( int ms );
|
extern void Sleep( int ms );
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
// --------------------------------------------------------------------------------------
|
||||||
// PersistentThread - Helper class for the basics of starting/managing persistent threads.
|
// IThread - Interface for the public access to PersistentThread.
|
||||||
//
|
// --------------------------------------------------------------------------------------
|
||||||
// Use this as a base class for your threaded procedure, and implement the 'int ExecuteTask()'
|
// Class usage: Can be used for allowing safe nullification of a thread handle. Rather
|
||||||
// method. Use Start() and Cancel() to start and shutdown the thread, and use m_sem_event
|
// than being NULL'd, the handle can be mapped to an IThread implementation which acts
|
||||||
// internally to post/receive events for the thread (make a public accessor for it in your
|
// as a do-nothing placebo or an assertion generator.
|
||||||
// derived class if your thread utilizes the post).
|
//
|
||||||
//
|
class IThread
|
||||||
// Notes:
|
{
|
||||||
// * Constructing threads as static global vars isn't recommended since it can potentially
|
DeclareNoncopyableObject(IThread);
|
||||||
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
|
||||||
// no dependency options for ensuring correct static var initializations). Use heap
|
public:
|
||||||
// allocation to create thread objects instead.
|
IThread() {}
|
||||||
//
|
virtual ~IThread() throw() {}
|
||||||
class PersistentThread
|
|
||||||
|
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);
|
DeclareNoncopyableObject(PersistentThread);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef int (*PlainJoeFP)();
|
typedef int (*PlainJoeFP)();
|
||||||
|
|
||||||
|
wxString m_name; // diagnostic name for our thread.
|
||||||
|
|
||||||
pthread_t m_thread;
|
pthread_t m_thread;
|
||||||
Semaphore m_sem_event; // general wait event that's needed by most threads.
|
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
|
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.
|
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_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.
|
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:
|
public:
|
||||||
virtual ~PersistentThread() throw();
|
virtual ~PersistentThread() throw();
|
||||||
PersistentThread();
|
PersistentThread();
|
||||||
|
PersistentThread( const char* name );
|
||||||
|
|
||||||
virtual void Start();
|
virtual void Start();
|
||||||
virtual void Cancel( bool isBlocking = true );
|
virtual void Cancel( bool isBlocking = true );
|
||||||
virtual void Detach();
|
virtual bool 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 sptr Block();
|
virtual sptr Block();
|
||||||
|
|
||||||
|
virtual int GetReturnCode() const;
|
||||||
|
virtual void RethrowException() const;
|
||||||
|
|
||||||
|
bool IsRunning() const;
|
||||||
bool IsSelf() const;
|
bool IsSelf() const;
|
||||||
|
wxString GetName() const;
|
||||||
|
|
||||||
virtual void DoThreadCleanup();
|
virtual void DoThreadCleanup();
|
||||||
|
|
||||||
protected:
|
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.
|
// Used to dispatch the thread callback function.
|
||||||
// (handles some thread cleanup on Win32, and is basically a typecast
|
// (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!
|
// Implemented by derived class to handle threading actions!
|
||||||
virtual sptr ExecuteTask()=0;
|
virtual sptr ExecuteTask()=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// ScopedLock: Helper class for using Mutexes.
|
// ScopedLock: Helper class for using Mutexes.
|
||||||
// Using this class provides an exception-safe (and generally clean) method of locking
|
// Using this class provides an exception-safe (and generally clean) method of locking
|
||||||
|
|
|
@ -17,17 +17,19 @@
|
||||||
|
|
||||||
#include "Dependencies.h"
|
#include "Dependencies.h"
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// wxBaseTools.h
|
// wxBaseTools.h
|
||||||
//
|
//
|
||||||
// This file is meant to contain utility classes for users of the wxWidgets library.
|
// 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
|
// 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
|
// you don't need to include or link against wxCore (GUI) to build them. For tools
|
||||||
// which require wxCore, see wxGuiTools.h
|
// which require wxCore, see wxGuiTools.h
|
||||||
// ----------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// wxDoNotLogInThisScope
|
// --------------------------------------------------------------------------------------
|
||||||
|
// wxDoNotLogInThisScope
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
// This class is used to disable wx's sometimes inappropriate amount of forced error logging
|
// 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
|
// during specific activities. For example, when using wxDynamicLibrary to detect the
|
||||||
// validity of DLLs, wx will log errors for missing symbols. (sigh)
|
// 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 "PrecompiledHeader.h"
|
||||||
#include "Threading.h"
|
#include "Threading.h"
|
||||||
|
#include "wxBaseTools.h"
|
||||||
|
|
||||||
#include <wx/datetime.h>
|
#include <wx/datetime.h>
|
||||||
#include <wx/thread.h>
|
#include <wx/thread.h>
|
||||||
|
@ -37,11 +38,13 @@ namespace Threading
|
||||||
}
|
}
|
||||||
|
|
||||||
PersistentThread::PersistentThread() :
|
PersistentThread::PersistentThread() :
|
||||||
m_thread()
|
m_name( L"PersistentThread" )
|
||||||
|
, m_thread()
|
||||||
, m_sem_event()
|
, m_sem_event()
|
||||||
, m_sem_finished()
|
, m_sem_finished()
|
||||||
|
, m_lock_start( true ) // recursive mutexing!
|
||||||
, m_returncode( 0 )
|
, m_returncode( 0 )
|
||||||
, m_detached( false )
|
, m_detached( true ) // start out with m_thread in detached/invalid state
|
||||||
, m_running( false )
|
, m_running( false )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -53,40 +56,42 @@ namespace Threading
|
||||||
// your sister, and then cheating on her with your daughter.
|
// your sister, and then cheating on her with your daughter.
|
||||||
PersistentThread::~PersistentThread() throw()
|
PersistentThread::~PersistentThread() throw()
|
||||||
{
|
{
|
||||||
if( !m_running ) return;
|
if( m_running )
|
||||||
|
|
||||||
wxASSERT( !IsSelf() ); // not allowed from our own thread.
|
|
||||||
|
|
||||||
if( !_InterlockedExchange( &m_detached, true ) )
|
|
||||||
{
|
{
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
m_sem_finished.WaitGui();
|
m_sem_finished.WaitGui();
|
||||||
#else
|
#else
|
||||||
m_sem_finished.Wait();
|
m_sem_finished.Wait();
|
||||||
#endif
|
#endif
|
||||||
m_running = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function should not be called from the owner thread.
|
// This function should not be called from the owner thread.
|
||||||
void PersistentThread::Start()
|
void PersistentThread::Start()
|
||||||
{
|
{
|
||||||
|
ScopedLock startlock( m_lock_start ); // Prevents sudden parallel startup
|
||||||
if( m_running ) return;
|
if( m_running ) return;
|
||||||
|
|
||||||
|
Detach(); // clean up previous thread, if one exists.
|
||||||
m_sem_finished.Reset();
|
m_sem_finished.Reset();
|
||||||
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
|
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
|
||||||
throw Exception::ThreadCreationError();
|
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.
|
// 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.
|
wxASSERT( !IsSelf() ); // not allowed from our own thread.
|
||||||
|
|
||||||
|
if( _InterlockedExchange( &m_detached, true ) ) return false;
|
||||||
pthread_detach( m_thread );
|
pthread_detach( m_thread );
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remarks:
|
// Remarks:
|
||||||
|
@ -102,15 +107,15 @@ namespace Threading
|
||||||
//
|
//
|
||||||
void PersistentThread::Cancel( bool isBlocking )
|
void PersistentThread::Cancel( bool isBlocking )
|
||||||
{
|
{
|
||||||
|
wxASSERT( !IsSelf() );
|
||||||
if( !m_running ) return;
|
if( !m_running ) return;
|
||||||
|
|
||||||
if( _InterlockedExchange( &m_detached, true ) )
|
if( m_detached )
|
||||||
{
|
{
|
||||||
Console::Notice( "Threading Warning: Attempted to cancel detached thread; Ignoring..." );
|
Console::Notice( "Threading Warning: Attempted to cancel detached thread; Ignoring..." );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxASSERT( !IsSelf() );
|
|
||||||
pthread_cancel( m_thread );
|
pthread_cancel( m_thread );
|
||||||
|
|
||||||
if( isBlocking )
|
if( isBlocking )
|
||||||
|
@ -121,8 +126,6 @@ namespace Threading
|
||||||
m_sem_finished.Wait();
|
m_sem_finished.Wait();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
|
||||||
pthread_detach( m_thread );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocks execution of the calling thread until this thread completes its task. The
|
// Blocks execution of the calling thread until this thread completes its task. The
|
||||||
|
@ -153,14 +156,10 @@ namespace Threading
|
||||||
|
|
||||||
bool PersistentThread::IsRunning() const
|
bool PersistentThread::IsRunning() const
|
||||||
{
|
{
|
||||||
if (!m_running) return false;
|
return !!m_running;
|
||||||
|
|
||||||
if( !!m_detached )
|
|
||||||
return !!m_running;
|
|
||||||
else
|
|
||||||
return ( ESRCH != pthread_kill( m_thread, 0 ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets the return code of the thread.
|
||||||
// Exceptions:
|
// Exceptions:
|
||||||
// InvalidOperation - thrown if the thread is still running or has never been started.
|
// InvalidOperation - thrown if the thread is still running or has never been started.
|
||||||
//
|
//
|
||||||
|
@ -171,32 +170,95 @@ namespace Threading
|
||||||
|
|
||||||
return m_returncode;
|
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.
|
// invoked when canceling or exiting the thread.
|
||||||
void PersistentThread::DoThreadCleanup()
|
void PersistentThread::DoThreadCleanup()
|
||||||
{
|
{
|
||||||
wxASSERT( IsSelf() ); // only allowed from our own thread, thanks.
|
wxASSERT( IsSelf() ); // only allowed from our own thread, thanks.
|
||||||
_InterlockedExchange( &m_running, false );
|
m_running = false;
|
||||||
m_sem_finished.Post();
|
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 )
|
void* PersistentThread::_internal_callback( void* itsme )
|
||||||
{
|
{
|
||||||
jASSUME( itsme != NULL );
|
jASSUME( itsme != NULL );
|
||||||
PersistentThread& owner = *((PersistentThread*)itsme);
|
PersistentThread& owner = *((PersistentThread*)itsme);
|
||||||
|
|
||||||
pthread_cleanup_push( _pt_callback_cleanup, itsme );
|
pthread_cleanup_push( _pt_callback_cleanup, itsme );
|
||||||
owner.m_returncode = owner.ExecuteTask();
|
owner._internal_execute();
|
||||||
pthread_cleanup_pop( true );
|
pthread_cleanup_pop( true );
|
||||||
|
|
||||||
return (void*)owner.m_returncode;
|
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.
|
wxASSERT( IsSelf() ); // only allowed from our own thread, thanks.
|
||||||
|
|
||||||
#ifdef _WINDOWS_
|
#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;
|
static const int MS_VC_EXCEPTION = 0x406D1388;
|
||||||
|
|
||||||
#pragma pack(push,8)
|
#pragma pack(push,8)
|
||||||
|
@ -210,10 +272,10 @@ namespace Threading
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
THREADNAME_INFO info;
|
THREADNAME_INFO info;
|
||||||
info.dwType = 0x1000;
|
info.dwType = 0x1000;
|
||||||
info.szName = name;
|
info.szName = name;
|
||||||
info.dwThreadID = GetCurrentThreadId();
|
info.dwThreadID = GetCurrentThreadId();
|
||||||
info.dwFlags = 0;
|
info.dwFlags = 0;
|
||||||
|
|
||||||
__try
|
__try
|
||||||
{
|
{
|
||||||
|
@ -480,6 +542,11 @@ namespace Threading
|
||||||
pthread_mutex_unlock( &mutex );
|
pthread_mutex_unlock( &mutex );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MutexLock::TryLock()
|
||||||
|
{
|
||||||
|
return EBUSY != pthread_mutex_trylock( &mutex );
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// InterlockedExchanges / AtomicExchanges (PCSX2's Helper versions)
|
// InterlockedExchanges / AtomicExchanges (PCSX2's Helper versions)
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -85,12 +85,12 @@ __forceinline void xWrite64( u64 val )
|
||||||
xWrite( val );
|
xWrite( val );
|
||||||
}
|
}
|
||||||
|
|
||||||
const xAddressIndexerBase ptr;
|
const xAddressIndexerBase ptr;
|
||||||
const xAddressIndexer<u128> ptr128;
|
const xAddressIndexer<u128> ptr128;
|
||||||
const xAddressIndexer<u64> ptr64;
|
const xAddressIndexer<u64> ptr64;
|
||||||
const xAddressIndexer<u32> ptr32;
|
const xAddressIndexer<u32> ptr32;
|
||||||
const xAddressIndexer<u16> ptr16;
|
const xAddressIndexer<u16> ptr16;
|
||||||
const xAddressIndexer<u8> ptr8;
|
const xAddressIndexer<u8> ptr8;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
// GS Playback
|
// GS Playback
|
||||||
int g_SaveGSStream = 0; // save GS stream; 1 - prepare, 2 - save
|
int g_SaveGSStream = 0; // save GS stream; 1 - prepare, 2 - save
|
||||||
int g_nLeftGSFrames = 0; // when saving, number of frames left
|
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.
|
// fixme - need to take this concept and make it MTGS friendly.
|
||||||
#ifdef _STGS_GSSTATE_CODE
|
#ifdef _STGS_GSSTATE_CODE
|
||||||
|
@ -76,7 +76,7 @@ void SaveGSState(const wxString& file)
|
||||||
Console::WriteLn( wxsFormat( L"\t%s", file.c_str() ) );
|
Console::WriteLn( wxsFormat( L"\t%s", file.c_str() ) );
|
||||||
|
|
||||||
SafeArray<u8> buf;
|
SafeArray<u8> buf;
|
||||||
g_fGSSave.reset( new memSavingState( buf ) );
|
g_fGSSave = new memSavingState( buf );
|
||||||
|
|
||||||
g_SaveGSStream = 1;
|
g_SaveGSStream = 1;
|
||||||
g_nLeftGSFrames = 2;
|
g_nLeftGSFrames = 2;
|
||||||
|
|
|
@ -107,6 +107,7 @@ mtgsThreadObject::mtgsThreadObject() :
|
||||||
, m_lock_Stack()
|
, m_lock_Stack()
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
m_name = L"MTGS";
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtgsThreadObject::Start()
|
void mtgsThreadObject::Start()
|
||||||
|
@ -139,6 +140,7 @@ void mtgsThreadObject::PollStatus()
|
||||||
|
|
||||||
mtgsThreadObject::~mtgsThreadObject() throw()
|
mtgsThreadObject::~mtgsThreadObject() throw()
|
||||||
{
|
{
|
||||||
|
_parent::Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtgsThreadObject::OnResumeReady()
|
void mtgsThreadObject::OnResumeReady()
|
||||||
|
@ -244,8 +246,6 @@ void mtgsThreadObject::OpenPlugin()
|
||||||
|
|
||||||
sptr mtgsThreadObject::ExecuteTask()
|
sptr mtgsThreadObject::ExecuteTask()
|
||||||
{
|
{
|
||||||
SetName( "MTGS" );
|
|
||||||
|
|
||||||
#ifdef RINGBUF_DEBUG_STACK
|
#ifdef RINGBUF_DEBUG_STACK
|
||||||
PacketTagType prevCmd;
|
PacketTagType prevCmd;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,29 +28,29 @@
|
||||||
# include "svnrev.h"
|
# include "svnrev.h"
|
||||||
#endif
|
#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 );
|
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 );
|
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 );
|
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 );
|
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 );
|
return Mcd->McdGetCRC( (PS2E_THISPTR) Mcd, port, slot );
|
||||||
}
|
}
|
||||||
|
@ -988,10 +988,10 @@ void PluginManager::Init()
|
||||||
throw Exception::PluginInitError( pid );
|
throw Exception::PluginInitError( pid );
|
||||||
} while( ++pi, pi->shortname != NULL );
|
} while( ++pi, pi->shortname != NULL );
|
||||||
|
|
||||||
if( EmuPlugins.Mcd == NULL )
|
if( SysPlugins.Mcd == NULL )
|
||||||
{
|
{
|
||||||
EmuPlugins.Mcd = (PS2E_ComponentAPI_Mcd*)m_mcdPlugin->NewComponentInstance( PS2E_TYPE_Mcd );
|
SysPlugins.Mcd = (PS2E_ComponentAPI_Mcd*)m_mcdPlugin->NewComponentInstance( PS2E_TYPE_Mcd );
|
||||||
if( EmuPlugins.Mcd == NULL )
|
if( SysPlugins.Mcd == NULL )
|
||||||
{
|
{
|
||||||
// fixme: use plugin's GetLastError (not implemented yet!)
|
// fixme: use plugin's GetLastError (not implemented yet!)
|
||||||
throw Exception::PluginInitError( PluginId_Mcd, "Internal Memorycard Plugin failed to initialize." );
|
throw Exception::PluginInitError( PluginId_Mcd, "Internal Memorycard Plugin failed to initialize." );
|
||||||
|
@ -1029,10 +1029,10 @@ void PluginManager::Shutdown()
|
||||||
|
|
||||||
// More memorycard hacks!!
|
// More memorycard hacks!!
|
||||||
|
|
||||||
if( (EmuPlugins.Mcd != NULL) && (m_mcdPlugin != NULL) )
|
if( (SysPlugins.Mcd != NULL) && (m_mcdPlugin != NULL) )
|
||||||
{
|
{
|
||||||
m_mcdPlugin->DeleteComponentInstance( (PS2E_THISPTR)EmuPlugins.Mcd );
|
m_mcdPlugin->DeleteComponentInstance( (PS2E_THISPTR)SysPlugins.Mcd );
|
||||||
EmuPlugins.Mcd = NULL;
|
SysPlugins.Mcd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DbgCon::Status( "Plugins shutdown successfully." );
|
DbgCon::Status( "Plugins shutdown successfully." );
|
||||||
|
|
|
@ -48,6 +48,7 @@ namespace Exception
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DEFINE_EXCEPTION_COPYTORS( PluginError )
|
DEFINE_EXCEPTION_COPYTORS( PluginError )
|
||||||
|
|
||||||
PluginError() {}
|
PluginError() {}
|
||||||
PluginError( PluginsEnum_t pid, const char* msg="Generic plugin error" )
|
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
|
// make the current PluginManager largely obsolete (with the exception of the general Load/Unload
|
||||||
// management facilities)
|
// management facilities)
|
||||||
//
|
//
|
||||||
class EmuPluginBindings
|
class SysPluginBindings
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
PS2E_ComponentAPI_Mcd* Mcd;
|
PS2E_ComponentAPI_Mcd* Mcd;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EmuPluginBindings() :
|
SysPluginBindings() :
|
||||||
Mcd( NULL )
|
Mcd( NULL )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -204,7 +205,7 @@ public:
|
||||||
friend class PluginManager;
|
friend class PluginManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern EmuPluginBindings EmuPlugins;
|
extern SysPluginBindings SysPlugins;
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -20,129 +20,268 @@
|
||||||
#include "HostGui.h"
|
#include "HostGui.h"
|
||||||
#include "zlib/zlib.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()
|
DevAssert( wxThread::IsMain(), "StateThread creation is allowed from the Main thread only." );
|
||||||
{
|
if( state_buffer_lock )
|
||||||
if( !g_RecoveryState ) return;
|
throw Exception::RuntimeError( "Cannot save state; a previous save or load action is already in progress." );
|
||||||
|
|
||||||
Console::Status( "Resuming execution from full memory state..." );
|
Start();
|
||||||
memLoadingState( *g_RecoveryState ).FreezeAll();
|
sys_resume_lock = true;
|
||||||
|
|
||||||
StateRecovery::Clear();
|
|
||||||
SysClearExecutionCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SafeArray<u8> gzSavingBuffer;
|
protected:
|
||||||
|
sptr ExecuteTask()
|
||||||
class gzThreadClass : public PersistentThread
|
|
||||||
{
|
{
|
||||||
typedef PersistentThread _parent;
|
memSavingState( state_buffer ).FreezeAll();
|
||||||
|
return 0;
|
||||||
protected:
|
}
|
||||||
gzFile m_file;
|
|
||||||
|
void DoThreadCleanup()
|
||||||
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 )
|
|
||||||
{
|
{
|
||||||
SysSuspend( false );
|
wxCommandEvent evt( pxEVT_FreezeFinished );
|
||||||
gzThread.reset( NULL ); // blocks on any existing gzipping business.
|
evt.SetClientData( this );
|
||||||
|
wxGetApp().AddPendingEvent( evt );
|
||||||
|
|
||||||
memSavingState( gzSavingBuffer ).FreezeAll();
|
_parent::DoThreadCleanup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// start that encoding thread:
|
class StateThread_ZipToDisk : public PersistentThread
|
||||||
gzThread.reset( new gzThreadClass( file ) );
|
{
|
||||||
|
typedef PersistentThread _parent;
|
||||||
SysResume();
|
|
||||||
|
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
|
~StateThread_ZipToDisk() throw()
|
||||||
// (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 )
|
|
||||||
{
|
{
|
||||||
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).
|
protected:
|
||||||
// If a current recovery state is already present, then nothing is done (the
|
sptr ExecuteTask()
|
||||||
// existing recovery state takes precedence since if it were out-of-date it'd be
|
|
||||||
// deleted!).
|
|
||||||
void MakeFull()
|
|
||||||
{
|
{
|
||||||
if( g_RecoveryState ) return;
|
Sleep( 2 );
|
||||||
if( !EmulationInProgress() ) return;
|
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" ) );
|
gzclose( m_gzfp ); m_gzfp = NULL;
|
||||||
memSavingState( *g_RecoveryState ).FreezeAll();
|
throw;
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
sys_resume_lock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears and deallocates any recovery states.
|
~StateThread_UnzipFromDisk() throw()
|
||||||
void Clear()
|
|
||||||
{
|
{
|
||||||
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(); }
|
bool IsFinished() const { return m_idx >= m_memory.GetSizeInBytes(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace StateRecovery
|
extern bool StateCopy_IsValid();
|
||||||
{
|
extern bool StateCopy_HasFullState();
|
||||||
extern bool HasState();
|
extern bool StateCopy_HasPartialState();
|
||||||
extern void Recover();
|
|
||||||
extern void SaveToFile( const wxString& file );
|
extern void StateCopy_FreezeToMem();
|
||||||
extern void SaveToSlot( uint num );
|
extern void StateCopy_ThawFromMem();
|
||||||
extern void MakeFull();
|
extern void StateCopy_SaveToFile( const wxString& file );
|
||||||
extern void Clear();
|
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)
|
static void _ReadMcd(u8 *data, u32 adr, int size)
|
||||||
{
|
{
|
||||||
EmuPlugins.McdRead(
|
SysPlugins.McdRead(
|
||||||
sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
|
sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
|
||||||
data, adr, size
|
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)
|
static void _SaveMcd(const u8 *data, u32 adr, int size)
|
||||||
{
|
{
|
||||||
EmuPlugins.McdSave(
|
SysPlugins.McdSave(
|
||||||
sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
|
sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
|
||||||
data, adr, size
|
data, adr, size
|
||||||
);
|
);
|
||||||
|
@ -69,7 +69,7 @@ static void _SaveMcd(const u8 *data, u32 adr, int size)
|
||||||
|
|
||||||
static void _EraseMCDBlock(u32 adr)
|
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 )
|
static u8 sio_xor( const u8 *buf, uint length )
|
||||||
|
@ -601,7 +601,7 @@ void InitializeSIO(u8 value)
|
||||||
const uint port = sio.GetMemcardIndex();
|
const uint port = sio.GetMemcardIndex();
|
||||||
const uint slot = sio.activeMemcardSlot[port];
|
const uint slot = sio.activeMemcardSlot[port];
|
||||||
|
|
||||||
if( EmuPlugins.McdIsPresent( port, slot ) )
|
if( SysPlugins.McdIsPresent( port, slot ) )
|
||||||
{
|
{
|
||||||
sio2.packet.recvVal1 = 0x1100;
|
sio2.packet.recvVal1 = 0x1100;
|
||||||
PAD_LOG("START MEMCARD [port:%d, slot:%d] - Present", port, slot );
|
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 port=0; port<2; ++port )
|
||||||
{
|
{
|
||||||
for( int slot=0; slot<8; ++slot )
|
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 );
|
Freeze( m_mcdCRCs );
|
||||||
|
@ -689,7 +689,7 @@ void SaveStateBase::sioFreeze()
|
||||||
{
|
{
|
||||||
for( int slot=0; slot<8; ++slot )
|
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] )
|
if( newCRC != m_mcdCRCs[port][slot] )
|
||||||
{
|
{
|
||||||
m_mcdCRCs[port][slot] = newCRC;
|
m_mcdCRCs[port][slot] = newCRC;
|
||||||
|
|
|
@ -252,40 +252,11 @@ void SysClearExecutionCache()
|
||||||
vuMicroCpuReset();
|
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 )
|
void SysLoadState( const wxString& srcfile )
|
||||||
{
|
{
|
||||||
SafeArray<u8> buf;
|
//SysClearExecutionCache();
|
||||||
gzFile gzfp = gzopen( srcfile.ToUTF8().data(), "rb" );
|
//cpuReset();
|
||||||
if( gzfp == NULL )
|
//joe.FreezeAll();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maps a block of memory for use as a recompiled code buffer, and ensures that the
|
// 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_shortSuspend( false )
|
||||||
, m_plugins( plugins )
|
, m_plugins( plugins )
|
||||||
{
|
{
|
||||||
|
m_name = L"EE Core";
|
||||||
}
|
}
|
||||||
|
|
||||||
SysCoreThread::~SysCoreThread() throw()
|
SysCoreThread::~SysCoreThread() throw()
|
||||||
|
@ -280,13 +281,13 @@ void SysCoreThread::CpuInitializeMess()
|
||||||
cpuReset();
|
cpuReset();
|
||||||
SysClearExecutionCache();
|
SysClearExecutionCache();
|
||||||
|
|
||||||
if( StateRecovery::HasState() )
|
if( StateCopy_IsValid() )
|
||||||
{
|
{
|
||||||
// no need to boot bios or detect CDs when loading savestates.
|
// 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
|
// [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
|
// 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.
|
// don't really want to run a game with the wrong ISO loaded into the emu.
|
||||||
StateRecovery::Recover();
|
StateCopy_ThawFromMem();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -354,7 +355,6 @@ static void _cet_callback_cleanup( void* handle )
|
||||||
|
|
||||||
sptr SysCoreThread::ExecuteTask()
|
sptr SysCoreThread::ExecuteTask()
|
||||||
{
|
{
|
||||||
SetName( "EE Core" );
|
|
||||||
tls_coreThread = this;
|
tls_coreThread = this;
|
||||||
|
|
||||||
StateCheck();
|
StateCheck();
|
||||||
|
|
|
@ -19,7 +19,19 @@
|
||||||
|
|
||||||
using namespace Threading;
|
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;
|
typedef PersistentThread _parent;
|
||||||
|
|
||||||
|
|
126
pcsx2/gui/App.h
126
pcsx2/gui/App.h
|
@ -26,6 +26,7 @@ class MainEmuFrame;
|
||||||
class GSFrame;
|
class GSFrame;
|
||||||
class ConsoleLogFrame;
|
class ConsoleLogFrame;
|
||||||
class PipeRedirectionBase;
|
class PipeRedirectionBase;
|
||||||
|
class AppCoreThread;
|
||||||
|
|
||||||
#include "Utilities/HashMap.h"
|
#include "Utilities/HashMap.h"
|
||||||
#include "Utilities/wxGuiTools.h"
|
#include "Utilities/wxGuiTools.h"
|
||||||
|
@ -39,6 +40,9 @@ BEGIN_DECLARE_EVENT_TYPES()
|
||||||
DECLARE_EVENT_TYPE( pxEVT_OpenModalDialog, -1 )
|
DECLARE_EVENT_TYPE( pxEVT_OpenModalDialog, -1 )
|
||||||
DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 )
|
DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 )
|
||||||
DECLARE_EVENT_TYPE( pxEVT_LoadPluginsComplete, -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()
|
END_DECLARE_EVENT_TYPES()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -73,11 +77,11 @@ enum MenuIdentifiers
|
||||||
MenuId_SkipBiosToggle, // enables the Bios Skip speedhack
|
MenuId_SkipBiosToggle, // enables the Bios Skip speedhack
|
||||||
|
|
||||||
|
|
||||||
MenuId_Emu_SuspendResume, // suspends/resumes active emulation, retains plugin states
|
MenuId_Sys_SuspendResume, // suspends/resumes active emulation, retains plugin states
|
||||||
MenuId_Emu_Close, // Closes the emulator (states are preserved)
|
MenuId_Sys_Close, // Closes the emulator (states are preserved)
|
||||||
MenuId_Emu_Reset, // Issues a complete reset (wipes preserved states)
|
MenuId_Sys_Reset, // Issues a complete reset (wipes preserved states)
|
||||||
MenuId_Emu_LoadStates, // Opens load states submenu
|
MenuId_Sys_LoadStates, // Opens load states submenu
|
||||||
MenuId_Emu_SaveStates, // Opens save states submenu
|
MenuId_Sys_SaveStates, // Opens save states submenu
|
||||||
MenuId_EnablePatches,
|
MenuId_EnablePatches,
|
||||||
|
|
||||||
MenuId_State_Load,
|
MenuId_State_Load,
|
||||||
|
@ -298,15 +302,15 @@ public:
|
||||||
protected:
|
protected:
|
||||||
wxImageList m_ConfigImages;
|
wxImageList m_ConfigImages;
|
||||||
|
|
||||||
wxScopedPtr<wxImageList> m_ToolbarImages;
|
ScopedPtr<wxImageList> m_ToolbarImages;
|
||||||
wxScopedPtr<wxBitmap> m_Bitmap_Logo;
|
ScopedPtr<wxBitmap> m_Bitmap_Logo;
|
||||||
wxScopedPtr<PipeRedirectionBase>m_StdoutRedirHandle;
|
ScopedPtr<PipeRedirectionBase> m_StdoutRedirHandle;
|
||||||
wxScopedPtr<PipeRedirectionBase>m_StderrRedirHandle;
|
ScopedPtr<PipeRedirectionBase> m_StderrRedirHandle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxScopedPtr<SysCoreAllocations> m_CoreAllocs;
|
ScopedPtr<SysCoreAllocations> m_CoreAllocs;
|
||||||
wxScopedPtr<PluginManager> m_CorePlugins;
|
ScopedPtr<PluginManager> m_CorePlugins;
|
||||||
wxScopedPtr<SysCoreThread> m_CoreThread;
|
ScopedPtr<SysCoreThread> m_CoreThread;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
|
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
|
||||||
|
@ -333,16 +337,8 @@ public:
|
||||||
|
|
||||||
void SysExecute();
|
void SysExecute();
|
||||||
void SysExecute( CDVD_SourceType cdvdsrc );
|
void SysExecute( CDVD_SourceType cdvdsrc );
|
||||||
void SysReset()
|
void SysReset();
|
||||||
{
|
bool SysIsActive() const;
|
||||||
m_CoreThread.reset();
|
|
||||||
m_CorePlugins.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EmuInProgress() const
|
|
||||||
{
|
|
||||||
return m_CoreThread && m_CoreThread->IsRunning();
|
|
||||||
}
|
|
||||||
|
|
||||||
const wxBitmap& GetLogoBitmap();
|
const wxBitmap& GetLogoBitmap();
|
||||||
wxImageList& GetImgList_Config();
|
wxImageList& GetImgList_Config();
|
||||||
|
@ -350,28 +346,13 @@ public:
|
||||||
|
|
||||||
const AppImageIds& GetImgId() const { return m_ImageId; }
|
const AppImageIds& GetImgId() const { return m_ImageId; }
|
||||||
|
|
||||||
MainEmuFrame& GetMainFrame() const
|
bool HasMainFrame() const { return m_MainFrame != NULL; }
|
||||||
{
|
bool HasCoreThread() const { return m_CoreThread != NULL; }
|
||||||
wxASSERT( ((uptr)GetTopWindow()) == ((uptr)m_MainFrame) );
|
|
||||||
wxASSERT( m_MainFrame != NULL );
|
|
||||||
return *m_MainFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
MainEmuFrame& GetMainFrameOrExcept() const
|
MainEmuFrame& GetMainFrame() const;
|
||||||
{
|
SysCoreThread& GetCoreThread() const;
|
||||||
if( m_MainFrame == NULL )
|
MainEmuFrame& GetMainFrameOrExcept() const;
|
||||||
throw Exception::ObjectIsNull( "main application frame" );
|
SysCoreThread& GetCoreThreadOrExcept() const;
|
||||||
|
|
||||||
return *m_MainFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
SysCoreThread& GetCoreThreadOrExcept() const
|
|
||||||
{
|
|
||||||
if( !m_CoreThread )
|
|
||||||
throw Exception::ObjectIsNull( "core emulation thread" );
|
|
||||||
|
|
||||||
return *m_CoreThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGsFrame();
|
void OpenGsFrame();
|
||||||
void OnGsFrameClosed();
|
void OnGsFrameClosed();
|
||||||
|
@ -412,9 +393,14 @@ protected:
|
||||||
void OnLoadPluginsComplete( wxCommandEvent& evt );
|
void OnLoadPluginsComplete( wxCommandEvent& evt );
|
||||||
void OnSemaphorePing( wxCommandEvent& evt );
|
void OnSemaphorePing( wxCommandEvent& evt );
|
||||||
void OnOpenModalDialog( wxCommandEvent& evt );
|
void OnOpenModalDialog( wxCommandEvent& evt );
|
||||||
|
void OnCoreThreadTerminated( wxCommandEvent& evt );
|
||||||
|
|
||||||
|
void OnFreezeFinished( wxCommandEvent& evt );
|
||||||
|
void OnThawFinished( wxCommandEvent& evt );
|
||||||
|
|
||||||
void OnMessageBox( pxMessageBoxEvent& evt );
|
void OnMessageBox( pxMessageBoxEvent& evt );
|
||||||
void OnEmuKeyDown( wxKeyEvent& evt );
|
void OnEmuKeyDown( wxKeyEvent& evt );
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Override wx default exception handling behavior
|
// 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;
|
typedef SysCoreThread _parent;
|
||||||
|
|
||||||
|
@ -443,15 +429,16 @@ protected:
|
||||||
wxKeyEvent m_kevt;
|
wxKeyEvent m_kevt;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AppEmuThread( PluginManager& plugins );
|
AppCoreThread( PluginManager& plugins );
|
||||||
virtual ~AppEmuThread() throw();
|
virtual ~AppCoreThread() throw();
|
||||||
|
|
||||||
virtual void Suspend( bool isBlocking=true );
|
virtual void Suspend( bool isBlocking=true );
|
||||||
virtual void StateCheck( bool isCancelable=true );
|
virtual void StateCheck( bool isCancelable=true );
|
||||||
virtual void ApplySettings( const Pcsx2Config& src );
|
virtual void ApplySettings( const Pcsx2Config& src );
|
||||||
virtual void OnResumeReady();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void OnResumeReady();
|
||||||
|
virtual void DoThreadCleanup();
|
||||||
sptr ExecuteTask();
|
sptr ExecuteTask();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -470,6 +457,7 @@ public:
|
||||||
bool IsReentrant() const { return Counter > 1; }
|
bool IsReentrant() const { return Counter > 1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern bool sys_resume_lock;
|
||||||
|
|
||||||
extern int EnumeratePluginsInFolder( const wxDirName& searchPath, wxArrayString* dest );
|
extern int EnumeratePluginsInFolder( const wxDirName& searchPath, wxArrayString* dest );
|
||||||
extern void LoadPluginsPassive();
|
extern void LoadPluginsPassive();
|
||||||
|
@ -477,13 +465,13 @@ extern void LoadPluginsImmediate();
|
||||||
extern void UnloadPlugins();
|
extern void UnloadPlugins();
|
||||||
|
|
||||||
extern bool HandlePluginError( Exception::PluginError& ex );
|
extern bool HandlePluginError( Exception::PluginError& ex );
|
||||||
extern bool EmulationInProgress();
|
|
||||||
extern bool SysHasValidState();
|
|
||||||
|
|
||||||
extern void AppLoadSettings();
|
extern void AppLoadSettings();
|
||||||
extern void AppSaveSettings();
|
extern void AppSaveSettings();
|
||||||
extern void AppApplySettings( const AppConfig* oldconf=NULL );
|
extern void AppApplySettings( const AppConfig* oldconf=NULL );
|
||||||
|
|
||||||
|
extern bool SysHasValidState();
|
||||||
|
|
||||||
extern void SysStatus( const wxString& text );
|
extern void SysStatus( const wxString& text );
|
||||||
extern void SysSuspend( bool closePlugins = true );
|
extern void SysSuspend( bool closePlugins = true );
|
||||||
extern void SysResume();
|
extern void SysResume();
|
||||||
|
@ -491,36 +479,8 @@ extern void SysReset();
|
||||||
extern void SysExecute();
|
extern void SysExecute();
|
||||||
extern void SysExecute( CDVD_SourceType cdvdsrc );
|
extern void SysExecute( CDVD_SourceType cdvdsrc );
|
||||||
|
|
||||||
|
extern bool HasMainFrame();
|
||||||
|
extern bool HasCoreThread();
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
extern MainEmuFrame& GetMainFrame();
|
||||||
// AppInvoke macro
|
extern SysCoreThread& GetCoreThread();
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// 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 )
|
|
||||||
|
|
|
@ -525,7 +525,8 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite )
|
||||||
AppLoadSettings();
|
AppLoadSettings();
|
||||||
|
|
||||||
AppApplySettings();
|
AppApplySettings();
|
||||||
AppInvoke( MainFrame, ReloadRecentLists() );
|
if( HasMainFrame() )
|
||||||
|
GetMainFrame().ReloadRecentLists();
|
||||||
|
|
||||||
g_Conf->Folders.Logs.Mkdir();
|
g_Conf->Folders.Logs.Mkdir();
|
||||||
|
|
||||||
|
|
|
@ -178,4 +178,4 @@ extern ConfigOverrides OverrideOptions;
|
||||||
extern wxFileConfig* OpenFileConfig( const wxString& filename );
|
extern wxFileConfig* OpenFileConfig( const wxString& filename );
|
||||||
extern void AppConfig_OnChangedSettingsFolder( bool overwrite = false );
|
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_OpenModalDialog );
|
||||||
DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins );
|
DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins );
|
||||||
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
|
DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete );
|
||||||
|
DEFINE_EVENT_TYPE( pxEVT_AppCoreThread_Terminated );
|
||||||
|
DEFINE_EVENT_TYPE( pxEVT_FreezeFinished );
|
||||||
|
DEFINE_EVENT_TYPE( pxEVT_ThawFinished );
|
||||||
|
|
||||||
bool UseAdminMode = false;
|
bool UseAdminMode = false;
|
||||||
wxDirName SettingsFolder;
|
wxDirName SettingsFolder;
|
||||||
bool UseDefaultSettingsFolder = true;
|
bool UseDefaultSettingsFolder = true;
|
||||||
|
|
||||||
wxScopedPtr<AppConfig> g_Conf;
|
ScopedPtr<AppConfig> g_Conf;
|
||||||
ConfigOverrides OverrideOptions;
|
ConfigOverrides OverrideOptions;
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
|
@ -54,7 +57,7 @@ namespace Exception
|
||||||
class StartupAborted : public BaseException
|
class StartupAborted : public BaseException
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~StartupAborted() throw() {}
|
DEFINE_EXCEPTION_COPYTORS( StartupAborted )
|
||||||
|
|
||||||
StartupAborted( const wxString& msg_eng=L"Startup initialization was aborted by the user." )
|
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 )
|
SysCoreThread( plugins )
|
||||||
, m_kevt()
|
, m_kevt()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AppEmuThread::~AppEmuThread() throw()
|
AppCoreThread::~AppCoreThread() throw()
|
||||||
{
|
{
|
||||||
AppInvoke( MainFrame, ApplySettings() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppEmuThread::Suspend( bool isBlocking )
|
void AppCoreThread::Suspend( bool isBlocking )
|
||||||
{
|
{
|
||||||
_parent::Suspend( 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
|
// Clear the sticky key statuses, because hell knows what'll change while the PAD
|
||||||
// plugin is suspended.
|
// plugin is suspended.
|
||||||
|
@ -88,7 +91,7 @@ void AppEmuThread::Suspend( bool isBlocking )
|
||||||
m_kevt.m_altDown = false;
|
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;
|
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 )
|
if( GSopen2 != NULL )
|
||||||
wxGetApp().OpenGsFrame();
|
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
|
// 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 );
|
extern int TranslateGDKtoWXK( u32 keysym );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void AppEmuThread::StateCheck( bool isCancelable )
|
void AppCoreThread::StateCheck( bool isCancelable )
|
||||||
{
|
{
|
||||||
_parent::StateCheck( isCancelable );
|
_parent::StateCheck( isCancelable );
|
||||||
|
|
||||||
const keyEvent* ev = PADkeyEvent();
|
const keyEvent* ev = PADkeyEvent();
|
||||||
if( ev == NULL || (ev->key == 0) ) return;
|
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 );
|
m_kevt.SetEventType( ( ev->evt == KEYPRESS ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP );
|
||||||
const bool isDown = (ev->evt == KEYPRESS);
|
const bool isDown = (ev->evt == KEYPRESS);
|
||||||
|
|
||||||
|
@ -141,8 +156,13 @@ void AppEmuThread::StateCheck( bool isCancelable )
|
||||||
wxGetApp().PostPadKey( m_kevt );
|
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
|
// 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
|
// which are not part of g_Conf. The subsequent call to apply g_Conf settings (which is
|
||||||
// usually the desired behavior) will be ignored.
|
// usually the desired behavior) will be ignored.
|
||||||
|
@ -153,17 +173,14 @@ void AppEmuThread::ApplySettings( const Pcsx2Config& src )
|
||||||
SysCoreThread::ApplySettings( src );
|
SysCoreThread::ApplySettings( src );
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline bool EmulationInProgress()
|
// 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.
|
||||||
return wxGetApp().EmuInProgress();
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline bool SysHasValidState()
|
__forceinline bool SysHasValidState()
|
||||||
{
|
{
|
||||||
return wxGetApp().EmuInProgress() || StateRecovery::HasState();
|
bool isRunning = HasCoreThread() ? GetCoreThread().IsRunning() : false;
|
||||||
|
return isRunning || StateCopy_HasFullState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HandlePluginError( Exception::PluginError& ex )
|
bool HandlePluginError( Exception::PluginError& ex )
|
||||||
{
|
{
|
||||||
if( pxDialogExists( DialogId_CoreSettings ) ) return true;
|
if( pxDialogExists( DialogId_CoreSettings ) ) return true;
|
||||||
|
@ -183,7 +200,7 @@ bool HandlePluginError( Exception::PluginError& ex )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
sptr AppEmuThread::ExecuteTask()
|
sptr AppCoreThread::ExecuteTask()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -195,7 +212,7 @@ sptr AppEmuThread::ExecuteTask()
|
||||||
m_plugins.Close();
|
m_plugins.Close();
|
||||||
if( ex.StreamName == g_Conf->FullpathToBios() )
|
if( ex.StreamName == g_Conf->FullpathToBios() )
|
||||||
{
|
{
|
||||||
GetPluginManager().Close();
|
m_plugins.Close();
|
||||||
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
||||||
_("\n\nPress Ok to go to the BIOS Configuration Panel.") );
|
_("\n\nPress Ok to go to the BIOS Configuration Panel.") );
|
||||||
|
|
||||||
|
@ -270,7 +287,7 @@ void Pcsx2App::ReadUserModeSettings()
|
||||||
|
|
||||||
wxFileName usermodefile( FilenameDefs::GetUsermodeConfig() );
|
wxFileName usermodefile( FilenameDefs::GetUsermodeConfig() );
|
||||||
usermodefile.SetPath( usrlocaldir.ToString() );
|
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 ) );
|
wxString groupname( wxsFormat( L"CWD.%08x", hashres ) );
|
||||||
|
|
||||||
|
@ -401,10 +418,10 @@ bool Pcsx2App::OnInit()
|
||||||
wxInitAllImageHandlers();
|
wxInitAllImageHandlers();
|
||||||
if( !wxApp::OnInit() ) return false;
|
if( !wxApp::OnInit() ) return false;
|
||||||
|
|
||||||
g_Conf.reset( new AppConfig() );
|
g_Conf = new AppConfig();
|
||||||
|
|
||||||
m_StdoutRedirHandle.reset( NewPipeRedir(stdout) );
|
m_StdoutRedirHandle = NewPipeRedir(stdout);
|
||||||
m_StderrRedirHandle.reset( NewPipeRedir(stderr) );
|
m_StderrRedirHandle = NewPipeRedir(stderr);
|
||||||
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
||||||
|
|
||||||
#define pxMessageBoxEventThing(func) \
|
#define pxMessageBoxEventThing(func) \
|
||||||
|
@ -416,11 +433,14 @@ bool Pcsx2App::OnInit()
|
||||||
Connect( pxEVT_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
Connect( pxEVT_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
||||||
Connect( pxEVT_ReloadPlugins, wxCommandEventHandler( Pcsx2App::OnReloadPlugins ) );
|
Connect( pxEVT_ReloadPlugins, wxCommandEventHandler( Pcsx2App::OnReloadPlugins ) );
|
||||||
Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler( Pcsx2App::OnLoadPluginsComplete ) );
|
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 ) );
|
Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) );
|
||||||
|
|
||||||
// User/Admin Mode Dual Setup:
|
// 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
|
// 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-
|
// 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
|
// compatible \documents folder usage. The mode is determined by the presence and
|
||||||
|
@ -456,7 +476,7 @@ bool Pcsx2App::OnInit()
|
||||||
SysDetect();
|
SysDetect();
|
||||||
AppApplySettings();
|
AppApplySettings();
|
||||||
|
|
||||||
m_CoreAllocs.reset( new SysCoreAllocations() );
|
m_CoreAllocs = new SysCoreAllocations();
|
||||||
|
|
||||||
if( m_CoreAllocs->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
|
if( m_CoreAllocs->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
|
||||||
{
|
{
|
||||||
|
@ -578,6 +598,14 @@ void Pcsx2App::Ping() const
|
||||||
// Pcsx2App Event Handlers
|
// 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 )
|
void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
((Semaphore*)evt.GetClientData())->Post();
|
((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.
|
// the glorious user, whomever (s)he-it might be.
|
||||||
bool Pcsx2App::PrepForExit()
|
bool Pcsx2App::PrepForExit()
|
||||||
{
|
{
|
||||||
m_CoreThread.reset();
|
m_CoreThread = NULL;
|
||||||
CleanupMess();
|
CleanupMess();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -750,6 +778,36 @@ Pcsx2App::~Pcsx2App()
|
||||||
CleanupMess();
|
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 )
|
void AppApplySettings( const AppConfig* oldconf )
|
||||||
{
|
{
|
||||||
DevAssert( wxThread::IsMain(), "ApplySettings valid from the GUI thread only." );
|
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.
|
if( HasMainFrame() )
|
||||||
AppInvoke( MainFrame, ApplySettings() );
|
GetMainFrame().ApplySettings();
|
||||||
AppInvoke( CoreThread, ApplySettings( g_Conf->EmuOptions ) );
|
if( HasCoreThread() )
|
||||||
|
GetCoreThread().ApplySettings( g_Conf->EmuOptions );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppLoadSettings()
|
void AppLoadSettings()
|
||||||
|
@ -793,7 +852,8 @@ void AppLoadSettings()
|
||||||
IniLoader loader( *conf );
|
IniLoader loader( *conf );
|
||||||
g_Conf->LoadSave( loader );
|
g_Conf->LoadSave( loader );
|
||||||
|
|
||||||
AppInvoke( MainFrame, LoadRecentIsoList( *conf ) );
|
if( HasMainFrame() )
|
||||||
|
GetMainFrame().LoadRecentIsoList( *conf );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppSaveSettings()
|
void AppSaveSettings()
|
||||||
|
@ -804,7 +864,8 @@ void AppSaveSettings()
|
||||||
IniSaver saver( *conf );
|
IniSaver saver( *conf );
|
||||||
g_Conf->LoadSave( saver );
|
g_Conf->LoadSave( saver );
|
||||||
|
|
||||||
AppInvoke( MainFrame, SaveRecentIsoList( *conf ) );
|
if( HasMainFrame() )
|
||||||
|
GetMainFrame().SaveRecentIsoList( *conf );
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -815,9 +876,15 @@ void AppSaveSettings()
|
||||||
// configured CDVD source device.
|
// configured CDVD source device.
|
||||||
void Pcsx2App::SysExecute()
|
void Pcsx2App::SysExecute()
|
||||||
{
|
{
|
||||||
|
if( sys_resume_lock )
|
||||||
|
{
|
||||||
|
Console::WriteLn( "SysExecute: State is locked, ignoring Execute request!" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SysReset();
|
SysReset();
|
||||||
LoadPluginsImmediate();
|
LoadPluginsImmediate();
|
||||||
m_CoreThread.reset( new AppEmuThread( *m_CorePlugins ) );
|
m_CoreThread = new AppCoreThread( *m_CorePlugins );
|
||||||
m_CoreThread->Resume();
|
m_CoreThread->Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,15 +893,35 @@ void Pcsx2App::SysExecute()
|
||||||
// sources.
|
// sources.
|
||||||
void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc )
|
void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc )
|
||||||
{
|
{
|
||||||
|
if( sys_resume_lock )
|
||||||
|
{
|
||||||
|
Console::WriteLn( "SysExecute: State is locked, ignoring Execute request!" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SysReset();
|
SysReset();
|
||||||
LoadPluginsImmediate();
|
LoadPluginsImmediate();
|
||||||
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
|
||||||
CDVDsys_ChangeSource( cdvdsrc );
|
CDVDsys_ChangeSource( cdvdsrc );
|
||||||
|
|
||||||
m_CoreThread.reset( new AppEmuThread( *m_CorePlugins ) );
|
m_CoreThread = new AppCoreThread( *m_CorePlugins );
|
||||||
m_CoreThread->Resume();
|
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()
|
void Pcsx2App::OpenGsFrame()
|
||||||
{
|
{
|
||||||
if( m_gsFrame != NULL ) return;
|
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.
|
// 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 )
|
void SysStatus( const wxString& text )
|
||||||
{
|
{
|
||||||
// mirror output to the console!
|
// mirror output to the console!
|
||||||
Console::Status( text.c_str() );
|
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
|
// Executes the emulator using a saved/existing virtual machine state and currently
|
||||||
|
@ -878,18 +967,48 @@ void SysExecute( CDVD_SourceType cdvdsrc )
|
||||||
|
|
||||||
void SysResume()
|
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 )
|
void SysSuspend( bool closePlugins )
|
||||||
{
|
{
|
||||||
|
if( !HasCoreThread() ) return;
|
||||||
|
|
||||||
if( closePlugins )
|
if( closePlugins )
|
||||||
AppInvoke( CoreThread, Suspend(closePlugins) );
|
GetCoreThread().Suspend();
|
||||||
else
|
else
|
||||||
AppInvoke( CoreThread, ShortSuspend() );
|
GetCoreThread().ShortSuspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysReset()
|
void SysReset()
|
||||||
{
|
{
|
||||||
wxGetApp().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()
|
const wxBitmap& Pcsx2App::GetLogoBitmap()
|
||||||
{
|
{
|
||||||
if( m_Bitmap_Logo != NULL )
|
if( m_Bitmap_Logo )
|
||||||
return *m_Bitmap_Logo;
|
return *m_Bitmap_Logo;
|
||||||
|
|
||||||
wxFileName mess;
|
wxFileName mess;
|
||||||
|
@ -90,7 +90,7 @@ const wxBitmap& Pcsx2App::GetLogoBitmap()
|
||||||
wxImage img;
|
wxImage img;
|
||||||
EmbeddedImage<res_BackgroundLogo> temp; // because gcc can't allow non-const temporaries.
|
EmbeddedImage<res_BackgroundLogo> temp; // because gcc can't allow non-const temporaries.
|
||||||
LoadImageAny( img, useTheme, mess, L"BackgroundLogo", temp );
|
LoadImageAny( img, useTheme, mess, L"BackgroundLogo", temp );
|
||||||
m_Bitmap_Logo.reset( new wxBitmap( img ) );
|
m_Bitmap_Logo = new wxBitmap( img );
|
||||||
|
|
||||||
return *m_Bitmap_Logo;
|
return *m_Bitmap_Logo;
|
||||||
}
|
}
|
||||||
|
@ -137,10 +137,10 @@ wxImageList& Pcsx2App::GetImgList_Config()
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
wxImageList& Pcsx2App::GetImgList_Toolbars()
|
wxImageList& Pcsx2App::GetImgList_Toolbars()
|
||||||
{
|
{
|
||||||
if( m_ToolbarImages == NULL )
|
if( !m_ToolbarImages )
|
||||||
{
|
{
|
||||||
const int imgSize = g_Conf->Toolbar_ImageSize ? 64 : 32;
|
const int imgSize = g_Conf->Toolbar_ImageSize ? 64 : 32;
|
||||||
m_ToolbarImages.reset( new wxImageList( imgSize, imgSize ) );
|
m_ToolbarImages = new wxImageList( imgSize, imgSize );
|
||||||
wxFileName mess;
|
wxFileName mess;
|
||||||
bool useTheme = (g_Conf->DeskTheme != L"default");
|
bool useTheme = (g_Conf->DeskTheme != L"default");
|
||||||
|
|
||||||
|
|
|
@ -72,14 +72,13 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
||||||
static const wxString LabelGreets = wxString::FromUTF8(
|
static const wxString LabelGreets = wxString::FromUTF8(
|
||||||
"Contributors"
|
"Contributors"
|
||||||
"\n\n"
|
"\n\n"
|
||||||
"Hiryu and Sjeep for libcvd (the iso parsing and"
|
"Hiryu and Sjeep (libcdvd / iso filesystem), nneeve (fpu and vu)"
|
||||||
"filesystem driver code), nneeve (fpu and vu help)"
|
|
||||||
"\n\n"
|
"\n\n"
|
||||||
"Plugin Specialists: ChickenLiver (Lilypad), Efp (efp),"
|
"Plugin Specialists: ChickenLiver (Lilypad), Efp (efp),"
|
||||||
"Gabest (Gsdx, Cdvdolio, Xpad), Zeydlitz (ZZogl)"
|
"Gabest (Gsdx, Cdvdolio, Xpad), Zeydlitz (ZZogl)"
|
||||||
"\n\n"
|
"\n\n"
|
||||||
"Special thanks to: black_wd, Belmont, BGome, _Demo_, Dreamtime,"
|
"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 );
|
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 ), "Framelimiter_TurboToggle" );
|
||||||
m_Accels.Map( AAC( WXK_TAB ).Shift(), "Framelimiter_MasterToggle" );
|
m_Accels.Map( AAC( WXK_TAB ).Shift(), "Framelimiter_MasterToggle" );
|
||||||
|
|
||||||
m_Accels.Map( AAC( WXK_ESCAPE ), "Emu_Suspend" );
|
m_Accels.Map( AAC( WXK_ESCAPE ), "Sys_Suspend" );
|
||||||
m_Accels.Map( AAC( WXK_F8 ), "Emu_TakeSnapshot" );
|
m_Accels.Map( AAC( WXK_F8 ), "Sys_TakeSnapshot" );
|
||||||
m_Accels.Map( AAC( WXK_F9 ), "Emu_RenderswitchToggle" );
|
m_Accels.Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle" );
|
||||||
|
|
||||||
m_Accels.Map( AAC( WXK_F10 ), "Emu_LoggingToggle" );
|
m_Accels.Map( AAC( WXK_F10 ), "Sys_LoggingToggle" );
|
||||||
m_Accels.Map( AAC( WXK_F11 ), "Emu_FreezeGS" );
|
m_Accels.Map( AAC( WXK_F11 ), "Sys_FreezeGS" );
|
||||||
m_Accels.Map( AAC( WXK_F12 ), "Emu_RecordingToggle" );
|
m_Accels.Map( AAC( WXK_F12 ), "Sys_RecordingToggle" );
|
||||||
}
|
}
|
||||||
|
|
||||||
GSFrame::GSFrame(wxWindow* parent, const wxString& title):
|
GSFrame::GSFrame(wxWindow* parent, const wxString& title):
|
||||||
|
@ -54,7 +54,8 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title):
|
||||||
|
|
||||||
GSFrame::~GSFrame() throw()
|
GSFrame::~GSFrame() throw()
|
||||||
{
|
{
|
||||||
AppInvoke( CoreThread, Suspend() ); // Just in case...!
|
if( HasCoreThread() )
|
||||||
|
GetCoreThread().Suspend(); // Just in case...!
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSFrame::OnCloseWindow(wxCloseEvent& evt)
|
void GSFrame::OnCloseWindow(wxCloseEvent& evt)
|
||||||
|
|
|
@ -69,31 +69,32 @@ namespace Implementations
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emu_Suspend()
|
void Sys_Suspend()
|
||||||
{
|
{
|
||||||
AppInvoke( CoreThread, Suspend() );
|
if( HasCoreThread() )
|
||||||
AppInvoke( MainFrame, ApplySettings() );
|
GetCoreThread().Suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emu_Resume()
|
void Sys_Resume()
|
||||||
{
|
{
|
||||||
AppInvoke( CoreThread, Resume() );
|
if( HasCoreThread() )
|
||||||
AppInvoke( MainFrame, ApplySettings() );
|
GetCoreThread().Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emu_TakeSnapshot()
|
void Sys_TakeSnapshot()
|
||||||
{
|
{
|
||||||
GSmakeSnapshot( g_Conf->Folders.Snapshots.ToAscii().data() );
|
GSmakeSnapshot( g_Conf->Folders.Snapshots.ToAscii().data() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emu_RenderToggle()
|
void Sys_RenderToggle()
|
||||||
{
|
{
|
||||||
AppInvoke( CoreThread, Suspend() );
|
if( !HasCoreThread() ) return;
|
||||||
|
SysSuspend();
|
||||||
renderswitch = !renderswitch;
|
renderswitch = !renderswitch;
|
||||||
AppInvoke( CoreThread, Resume() );
|
SysResume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emu_LoggingToggle()
|
void Sys_LoggingToggle()
|
||||||
{
|
{
|
||||||
#ifdef PCSX2_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
// There's likely a better way to implement this, but this seemed useful.
|
// There's likely a better way to implement this, but this seemed useful.
|
||||||
|
@ -108,7 +109,7 @@ namespace Implementations
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emu_FreezeGS()
|
void Sys_FreezeGS()
|
||||||
{
|
{
|
||||||
// fixme : fix up gsstate mess and make it mtgs compatible -- air
|
// fixme : fix up gsstate mess and make it mtgs compatible -- air
|
||||||
#ifdef _STGS_GSSTATE_CODE
|
#ifdef _STGS_GSSTATE_CODE
|
||||||
|
@ -137,7 +138,7 @@ namespace Implementations
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emu_RecordingToggle()
|
void Sys_RecordingToggle()
|
||||||
{
|
{
|
||||||
g_Pcsx2Recording ^= 1;
|
g_Pcsx2Recording ^= 1;
|
||||||
|
|
||||||
|
@ -206,37 +207,37 @@ static const GlobalCommandDescriptor CommandDeclarations[] =
|
||||||
NULL,
|
NULL,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "Emu_Suspend",
|
{ "Sys_Suspend",
|
||||||
Implementations::Emu_Suspend,
|
Implementations::Sys_Suspend,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "Emu_TakeSnapshot",
|
{ "Sys_TakeSnapshot",
|
||||||
Implementations::Emu_TakeSnapshot,
|
Implementations::Sys_TakeSnapshot,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "Emu_RenderswitchToggle",
|
{ "Sys_RenderswitchToggle",
|
||||||
Implementations::Emu_RenderToggle,
|
Implementations::Sys_RenderToggle,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "Emu_LoggingToggle",
|
{ "Sys_LoggingToggle",
|
||||||
Implementations::Emu_LoggingToggle,
|
Implementations::Sys_LoggingToggle,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "Emu_FreezeGS",
|
{ "Sys_FreezeGS",
|
||||||
Implementations::Emu_FreezeGS,
|
Implementations::Sys_FreezeGS,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
},
|
},
|
||||||
{ "Emu_RecordingToggle",
|
{ "Sys_RecordingToggle",
|
||||||
Implementations::Emu_RecordingToggle,
|
Implementations::Sys_RecordingToggle,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
},
|
},
|
||||||
|
@ -304,11 +305,11 @@ void Pcsx2App::InitDefaultGlobalAccelerators()
|
||||||
GlobalAccels.Map( AAC( WXK_TAB ), "Framelimiter_TurboToggle" );
|
GlobalAccels.Map( AAC( WXK_TAB ), "Framelimiter_TurboToggle" );
|
||||||
GlobalAccels.Map( AAC( WXK_TAB ).Shift(), "Framelimiter_MasterToggle" );
|
GlobalAccels.Map( AAC( WXK_TAB ).Shift(), "Framelimiter_MasterToggle" );
|
||||||
|
|
||||||
GlobalAccels.Map( AAC( WXK_ESCAPE ), "Emu_Suspend");
|
GlobalAccels.Map( AAC( WXK_ESCAPE ), "Sys_Suspend");
|
||||||
GlobalAccels.Map( AAC( WXK_F8 ), "Emu_TakeSnapshot");
|
GlobalAccels.Map( AAC( WXK_F8 ), "Sys_TakeSnapshot");
|
||||||
GlobalAccels.Map( AAC( WXK_F9 ), "Emu_RenderswitchToggle");
|
GlobalAccels.Map( AAC( WXK_F9 ), "Sys_RenderswitchToggle");
|
||||||
|
|
||||||
GlobalAccels.Map( AAC( WXK_F10 ), "Emu_LoggingToggle");
|
GlobalAccels.Map( AAC( WXK_F10 ), "Sys_LoggingToggle");
|
||||||
GlobalAccels.Map( AAC( WXK_F11 ), "Emu_FreezeGS");
|
GlobalAccels.Map( AAC( WXK_F11 ), "Sys_FreezeGS");
|
||||||
GlobalAccels.Map( AAC( WXK_F12 ), "Emu_RecordingToggle");
|
GlobalAccels.Map( AAC( WXK_F12 ), "Sys_RecordingToggle");
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,8 +211,8 @@ void MainEmuFrame::ConnectMenus()
|
||||||
ConnectMenu( MenuId_SkipBiosToggle, Menu_SkipBiosToggle_Click );
|
ConnectMenu( MenuId_SkipBiosToggle, Menu_SkipBiosToggle_Click );
|
||||||
ConnectMenu( MenuId_Exit, Menu_Exit_Click );
|
ConnectMenu( MenuId_Exit, Menu_Exit_Click );
|
||||||
|
|
||||||
ConnectMenu( MenuId_Emu_SuspendResume, Menu_SuspendResume_Click );
|
ConnectMenu( MenuId_Sys_SuspendResume, Menu_SuspendResume_Click );
|
||||||
ConnectMenu( MenuId_Emu_Reset, Menu_EmuReset_Click );
|
ConnectMenu( MenuId_Sys_Reset, Menu_EmuReset_Click );
|
||||||
|
|
||||||
ConnectMenu( MenuId_State_LoadOther, Menu_LoadStateOther_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"));
|
_("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() );
|
_("Stops emulation dead in its tracks") )->Enable( SysHasValidState() );
|
||||||
|
|
||||||
m_menuEmu.AppendSeparator();
|
m_menuEmu.AppendSeparator();
|
||||||
|
|
||||||
//m_menuEmu.Append(MenuId_Emu_Close, _("Close"),
|
//m_menuEmu.Append(MenuId_Sys_Close, _("Close"),
|
||||||
// _("Stops emulation and closes the GS window."));
|
// _("Stops emulation and closes the GS window."));
|
||||||
|
|
||||||
m_menuEmu.Append(MenuId_Emu_LoadStates, _("Load state"), &m_LoadStatesSubmenu);
|
m_menuEmu.Append(MenuId_Sys_LoadStates, _("Load state"), &m_LoadStatesSubmenu);
|
||||||
m_menuEmu.Append(MenuId_Emu_SaveStates, _("Save state"), &m_SaveStatesSubmenu);
|
m_menuEmu.Append(MenuId_Sys_SaveStates, _("Save state"), &m_SaveStatesSubmenu);
|
||||||
|
|
||||||
m_menuEmu.AppendSeparator();
|
m_menuEmu.AppendSeparator();
|
||||||
m_menuEmu.Append(MenuId_EnablePatches, _("Enable Patches"),
|
m_menuEmu.Append(MenuId_EnablePatches, _("Enable Patches"),
|
||||||
wxEmptyString, wxITEM_CHECK);
|
wxEmptyString, wxITEM_CHECK);
|
||||||
|
|
||||||
m_menuEmu.AppendSeparator();
|
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"));
|
_("Resets emulation state and re-runs current image"));
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -470,9 +470,7 @@ void MainEmuFrame::ReloadRecentLists()
|
||||||
|
|
||||||
if( m_RecentIsoList )
|
if( m_RecentIsoList )
|
||||||
m_RecentIsoList->Save( *cfg );
|
m_RecentIsoList->Save( *cfg );
|
||||||
m_RecentIsoList.reset();
|
m_RecentIsoList.Reassign( new wxFileHistory(g_Conf->RecentFileCount) )->Load( *cfg );
|
||||||
m_RecentIsoList.reset( new wxFileHistory( g_Conf->RecentFileCount ) );
|
|
||||||
m_RecentIsoList->Load( *cfg );
|
|
||||||
UpdateIsoSrcFile();
|
UpdateIsoSrcFile();
|
||||||
cfg->Flush();
|
cfg->Flush();
|
||||||
}
|
}
|
||||||
|
@ -484,12 +482,11 @@ void MainEmuFrame::ApplySettings()
|
||||||
GetMenuBar()->Check( MenuId_Config_Multitap0Toggle, g_Conf->EmuOptions.MultitapPort0_Enabled );
|
GetMenuBar()->Check( MenuId_Config_Multitap0Toggle, g_Conf->EmuOptions.MultitapPort0_Enabled );
|
||||||
GetMenuBar()->Check( MenuId_Config_Multitap1Toggle, g_Conf->EmuOptions.MultitapPort1_Enabled );
|
GetMenuBar()->Check( MenuId_Config_Multitap1Toggle, g_Conf->EmuOptions.MultitapPort1_Enabled );
|
||||||
|
|
||||||
GetMenuBar()->Enable( MenuId_Emu_SuspendResume, SysHasValidState() );
|
GetMenuBar()->Enable( MenuId_Sys_SuspendResume, SysHasValidState() );
|
||||||
|
|
||||||
bool result = false;
|
|
||||||
AppInvokeBool( CoreThread, IsSuspended(), result );
|
|
||||||
GetMenuBar()->SetLabel( MenuId_Emu_SuspendResume, result ? _("Resume") :_("Suspend") );
|
|
||||||
|
|
||||||
|
if( HasCoreThread() )
|
||||||
|
GetMenuBar()->SetLabel( MenuId_Sys_SuspendResume, GetCoreThread().IsSuspended() ? _("Resume") :_("Suspend") );
|
||||||
|
|
||||||
if( m_RecentIsoList )
|
if( m_RecentIsoList )
|
||||||
{
|
{
|
||||||
if( m_RecentIsoList->GetMaxFiles() != g_Conf->RecentFileCount )
|
if( m_RecentIsoList->GetMaxFiles() != g_Conf->RecentFileCount )
|
||||||
|
|
|
@ -43,7 +43,7 @@ class MainEmuFrame : public wxFrame
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxScopedPtr<wxFileHistory> m_RecentIsoList;
|
ScopedPtr<wxFileHistory> m_RecentIsoList;
|
||||||
wxStatusBar& m_statusbar;
|
wxStatusBar& m_statusbar;
|
||||||
wxStaticBitmap m_background;
|
wxStaticBitmap m_background;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ public:
|
||||||
|
|
||||||
void OnLogBoxHidden();
|
void OnLogBoxHidden();
|
||||||
|
|
||||||
bool IsPaused() const { return GetMenuBar()->IsChecked( MenuId_Emu_SuspendResume ); }
|
bool IsPaused() const { return GetMenuBar()->IsChecked( MenuId_Sys_SuspendResume ); }
|
||||||
void UpdateIsoSrcFile();
|
void UpdateIsoSrcFile();
|
||||||
void UpdateIsoSrcSelection();
|
void UpdateIsoSrcSelection();
|
||||||
void ApplySettings();
|
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."
|
// [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 )
|
if( !result )
|
||||||
{
|
{
|
||||||
|
@ -190,11 +190,9 @@ void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
|
||||||
void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
if( !SysHasValidState() ) return;
|
if( !SysHasValidState() ) return;
|
||||||
|
if( !HasCoreThread() ) return;
|
||||||
|
|
||||||
bool result = false;
|
if( GetCoreThread().IsSuspended() )
|
||||||
AppInvokeBool( CoreThread, IsSuspended(), result );
|
|
||||||
|
|
||||||
if( result )
|
|
||||||
SysResume();
|
SysResume();
|
||||||
else
|
else
|
||||||
SysSuspend();
|
SysSuspend();
|
||||||
|
@ -202,15 +200,13 @@ void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event)
|
||||||
|
|
||||||
void MainEmuFrame::Menu_EmuReset_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_EmuReset_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
bool wasInProgress = EmulationInProgress();
|
if( !SysHasValidState() ) return;
|
||||||
bool wasSuspended;
|
bool wasSuspended = HasCoreThread() ? GetCoreThread().IsSuspended() : true;
|
||||||
|
|
||||||
AppInvokeBool( CoreThread, IsSuspended(), wasSuspended );
|
|
||||||
|
|
||||||
SysReset();
|
SysReset();
|
||||||
|
|
||||||
if( !wasInProgress || wasSuspended ) return;
|
if( !wasSuspended )
|
||||||
SysExecute();
|
SysExecute();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_ConfigPlugin_Click(wxCommandEvent &event)
|
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
|
// Impl Note: ScopedPtr used so that resources get cleaned up if an exception
|
||||||
// occurs during file enumeration.
|
// occurs during file enumeration.
|
||||||
wxScopedPtr<wxArrayString> bioslist( new wxArrayString() );
|
ScopedPtr<wxArrayString> bioslist( new wxArrayString() );
|
||||||
|
|
||||||
if( m_FolderPicker.GetPath().Exists() )
|
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) )
|
if( !m_BiosList || (*bioslist != *m_BiosList) )
|
||||||
validated = false;
|
validated = false;
|
||||||
|
|
||||||
m_BiosList.swap( bioslist );
|
m_BiosList.SwapPtr( bioslist );
|
||||||
|
|
||||||
return validated;
|
return validated;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace Exception
|
||||||
Panels::BaseApplicableConfigPanel* m_Panel;
|
Panels::BaseApplicableConfigPanel* m_Panel;
|
||||||
|
|
||||||
public:
|
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.") )
|
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
|
class BiosSelectorPanel : public BaseSelectorPanel
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
wxScopedPtr<wxArrayString> m_BiosList;
|
ScopedPtr<wxArrayString> m_BiosList;
|
||||||
wxListBox& m_ComboBox;
|
wxListBox& m_ComboBox;
|
||||||
DirPickerPanel& m_FolderPicker;
|
DirPickerPanel& m_FolderPicker;
|
||||||
|
|
||||||
|
@ -454,8 +454,8 @@ namespace Panels
|
||||||
ComboBoxPanel& m_ComponentBoxes;
|
ComboBoxPanel& m_ComponentBoxes;
|
||||||
bool m_Canceled;
|
bool m_Canceled;
|
||||||
|
|
||||||
wxScopedPtr<wxArrayString> m_FileList; // list of potential plugin files
|
ScopedPtr<wxArrayString> m_FileList; // list of potential plugin files
|
||||||
wxScopedPtr<EnumThread> m_EnumeratorThread;
|
ScopedPtr<EnumThread> m_EnumeratorThread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~PluginSelectorPanel();
|
virtual ~PluginSelectorPanel();
|
||||||
|
|
|
@ -364,9 +364,7 @@ void Panels::PluginSelectorPanel::DoRefresh()
|
||||||
wxCommandEvent evt( pxEVT_ShowStatusBar );
|
wxCommandEvent evt( pxEVT_ShowStatusBar );
|
||||||
GetEventHandler()->AddPendingEvent( evt );
|
GetEventHandler()->AddPendingEvent( evt );
|
||||||
|
|
||||||
// Use a thread to load plugins.
|
m_EnumeratorThread.Delete() = new EnumThread( *this );
|
||||||
m_EnumeratorThread.reset( NULL );
|
|
||||||
m_EnumeratorThread.reset( new EnumThread( *this ) );
|
|
||||||
|
|
||||||
if( DisableThreading )
|
if( DisableThreading )
|
||||||
m_EnumeratorThread->DoNextPlugin( 0 );
|
m_EnumeratorThread->DoNextPlugin( 0 );
|
||||||
|
@ -376,7 +374,7 @@ void Panels::PluginSelectorPanel::DoRefresh()
|
||||||
|
|
||||||
bool Panels::PluginSelectorPanel::ValidateEnumerationStatus()
|
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;
|
bool validated = true;
|
||||||
|
|
||||||
|
@ -385,20 +383,20 @@ bool Panels::PluginSelectorPanel::ValidateEnumerationStatus()
|
||||||
|
|
||||||
// Impl Note: ScopedPtr used so that resources get cleaned up if an exception
|
// Impl Note: ScopedPtr used so that resources get cleaned up if an exception
|
||||||
// occurs during file enumeration.
|
// 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) )
|
if( !m_FileList || (*pluginlist != *m_FileList) )
|
||||||
validated = false;
|
validated = false;
|
||||||
|
|
||||||
if( pluggers == 0 )
|
if( pluggers == 0 )
|
||||||
{
|
{
|
||||||
m_FileList.reset();
|
m_FileList = NULL;
|
||||||
return validated;
|
return validated;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_FileList.swap( pluginlist );
|
m_FileList.SwapPtr( pluginlist );
|
||||||
|
|
||||||
m_StatusPanel.SetGaugeLength( pluggers );
|
m_StatusPanel.SetGaugeLength( pluggers );
|
||||||
|
|
||||||
|
@ -428,7 +426,7 @@ void Panels::PluginSelectorPanel::OnShowStatusBar( wxCommandEvent& evt )
|
||||||
|
|
||||||
void Panels::PluginSelectorPanel::OnEnumComplete( 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?
|
// 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)
|
// (for now we just force it to selection zero if nothing's selected)
|
||||||
|
|
|
@ -63,13 +63,15 @@ protected:
|
||||||
int ExecuteTask();
|
int ExecuteTask();
|
||||||
};
|
};
|
||||||
|
|
||||||
static wxScopedPtr<LoadPluginsTask> _loadTask;
|
static ScopedPtr<LoadPluginsTask> _loadTask;
|
||||||
|
|
||||||
LoadPluginsTask::~LoadPluginsTask() throw()
|
LoadPluginsTask::~LoadPluginsTask() throw()
|
||||||
{
|
{
|
||||||
_loadTask.release();
|
if( _loadTask )
|
||||||
|
_loadTask.DetachPtr(); // avoids recursive deletion
|
||||||
|
|
||||||
PersistentThread::Cancel();
|
PersistentThread::Cancel();
|
||||||
_loadTask.reset();
|
_loadTask = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LoadPluginsTask::ExecuteTask()
|
int LoadPluginsTask::ExecuteTask()
|
||||||
|
@ -111,10 +113,10 @@ int LoadPluginsTask::ExecuteTask()
|
||||||
|
|
||||||
int EnumeratePluginsInFolder( const wxDirName& searchpath, wxArrayString* dest )
|
int EnumeratePluginsInFolder( const wxDirName& searchpath, wxArrayString* dest )
|
||||||
{
|
{
|
||||||
wxScopedPtr<wxArrayString> placebo;
|
ScopedPtr<wxArrayString> placebo;
|
||||||
wxArrayString* realdest = dest;
|
wxArrayString* realdest = dest;
|
||||||
if( realdest == NULL )
|
if( realdest == NULL )
|
||||||
placebo.reset( realdest = new wxArrayString() );
|
placebo = realdest = new wxArrayString(); // placebo is our /dev/null -- gets deleted when done
|
||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
// Windows pretty well has a strict "must end in .dll" rule.
|
// 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 )
|
void Pcsx2App::OnLoadPluginsComplete( wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
// scoped ptr ensures the thread object is cleaned up even on exception:
|
// scoped ptr ensures the thread object is cleaned up even on exception:
|
||||||
wxScopedPtr<LoadPluginsTask> killTask( (LoadPluginsTask*)evt.GetClientData() );
|
ScopedPtr<LoadPluginsTask> killTask( (LoadPluginsTask*)evt.GetClientData() );
|
||||||
m_CorePlugins.reset( killTask->Result );
|
m_CorePlugins = killTask->Result;
|
||||||
|
|
||||||
if( !m_CorePlugins )
|
if( !m_CorePlugins )
|
||||||
{
|
{
|
||||||
|
@ -153,8 +155,8 @@ void Pcsx2App::ReloadPlugins()
|
||||||
{
|
{
|
||||||
if( _loadTask ) return;
|
if( _loadTask ) return;
|
||||||
|
|
||||||
m_CoreThread.reset();
|
m_CoreThread = NULL;
|
||||||
m_CorePlugins.reset();
|
m_CorePlugins = NULL;
|
||||||
|
|
||||||
wxString passins[PluginId_Count];
|
wxString passins[PluginId_Count];
|
||||||
|
|
||||||
|
@ -166,7 +168,7 @@ void Pcsx2App::ReloadPlugins()
|
||||||
passins[pi->id] = g_Conf->FullpathTo( pi->id );
|
passins[pi->id] = g_Conf->FullpathTo( pi->id );
|
||||||
} while( ++pi, pi->shortname != NULL );
|
} 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. :)
|
// ... and when it finishes it posts up a OnLoadPluginsComplete(). Bye. :)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,5 +205,5 @@ void LoadPluginsImmediate()
|
||||||
|
|
||||||
void UnloadPlugins()
|
void UnloadPlugins()
|
||||||
{
|
{
|
||||||
wxGetApp().m_CorePlugins.reset();
|
wxGetApp().m_CorePlugins = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,16 +23,6 @@
|
||||||
|
|
||||||
StartupParams g_Startup;
|
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.
|
// returns true if the new state was loaded, or false if nothing happened.
|
||||||
void States_Load( const wxString& file )
|
void States_Load( const wxString& file )
|
||||||
|
@ -55,7 +45,7 @@ void States_Load( const wxString& file )
|
||||||
catch( Exception::BaseException& )
|
catch( Exception::BaseException& )
|
||||||
{
|
{
|
||||||
// VM state is probably ruined. We'll need to recover from the in-memory backup.
|
// VM state is probably ruined. We'll need to recover from the in-memory backup.
|
||||||
StateRecovery::Recover();
|
//StateRecovery::Recover();
|
||||||
}
|
}
|
||||||
|
|
||||||
SysExecute();
|
SysExecute();
|
||||||
|
@ -64,7 +54,7 @@ void States_Load( const wxString& file )
|
||||||
// Save state save-to-file (or slot) helpers.
|
// Save state save-to-file (or slot) helpers.
|
||||||
void States_Save( const wxString& file )
|
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.") );
|
Msgbox::Alert( _("You need to start emulation first before you can save it's state.") );
|
||||||
return;
|
return;
|
||||||
|
@ -73,7 +63,7 @@ void States_Save( const wxString& file )
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Console::Status( wxsFormat( L"Saving savestate to file: %s", file.c_str() ) );
|
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() ) );
|
SysStatus( wxsFormat( _("State saved to file: %s"), wxFileName( file ).GetFullName().c_str() ) );
|
||||||
}
|
}
|
||||||
catch( Exception::BaseException& ex )
|
catch( Exception::BaseException& ex )
|
||||||
|
@ -103,6 +93,14 @@ void States_Save( const wxString& file )
|
||||||
static int StatesC = 0;
|
static int StatesC = 0;
|
||||||
static const int StateSlotsCount = 10;
|
static const int StateSlotsCount = 10;
|
||||||
|
|
||||||
|
bool States_isSlotUsed(int num)
|
||||||
|
{
|
||||||
|
if (ElfCRC == 0)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return wxFileExists( SaveStateBase::GetFilename( num ) );
|
||||||
|
}
|
||||||
|
|
||||||
void States_FreezeCurrentSlot()
|
void States_FreezeCurrentSlot()
|
||||||
{
|
{
|
||||||
Console::Status( "Saving savestate to slot %d...", StatesC );
|
Console::Status( "Saving savestate to slot %d...", StatesC );
|
||||||
|
|
|
@ -1938,10 +1938,6 @@
|
||||||
RelativePath="..\..\gui\GlobalCommands.cpp"
|
RelativePath="..\..\gui\GlobalCommands.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\HostGui.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\gui\i18n.cpp"
|
RelativePath="..\..\gui\i18n.cpp"
|
||||||
>
|
>
|
||||||
|
@ -2519,6 +2515,10 @@
|
||||||
RelativePath="..\..\gui\Resources\EmbeddedImage.h"
|
RelativePath="..\..\gui\Resources\EmbeddedImage.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\HostGui.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\gui\IniInterface.h"
|
RelativePath="..\..\gui\IniInterface.h"
|
||||||
>
|
>
|
||||||
|
|
|
@ -153,6 +153,7 @@ public:
|
||||||
m_outpipe( outpipe )
|
m_outpipe( outpipe )
|
||||||
, m_color( color )
|
, m_color( color )
|
||||||
{
|
{
|
||||||
|
m_name = (m_color == Color_Red) ? L"Redirect_Stderr" : L"Redirect_Stdout";
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~WinPipeThread() throw()
|
virtual ~WinPipeThread() throw()
|
||||||
|
@ -166,8 +167,6 @@ protected:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
|
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
|
||||||
SetName( (m_color == Color_Red) ? "Redirect_Stderr" :" Redirect_Stdout" );
|
|
||||||
|
|
||||||
while( true )
|
while( true )
|
||||||
{
|
{
|
||||||
Sleep( 100 );
|
Sleep( 100 );
|
||||||
|
|
Loading…
Reference in New Issue