wxSavestates:

* Basic savestate loading/saving working now (needs testing).
 * No support for screenshots embedded into the savestate (yet).

git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxSavestates@4043 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2010-11-22 16:24:54 +00:00
parent 1dfc69670d
commit 6dcdf9cfa9
10 changed files with 448 additions and 146 deletions

View File

@ -26,6 +26,7 @@ class wxOutputStream;
class wxFileOutputStream;
class wxFFileOutputStream;
class wxStreamBase;
class wxInputStream;
class wxFileInputStream;
class wxFFileInputStream;

View File

@ -86,8 +86,14 @@ public:
// Gets a pointer to the requested allocation index.
// DevBuilds : Generates assertion if the index is invalid.
T *GetPtr( uint idx=0 ) { return _getPtr( idx ); }
const T *GetPtr( uint idx=0 ) const { return _getPtr( idx ); }
T* GetPtr( uint idx=0 ) { return _getPtr( idx ); }
const T* GetPtr( uint idx=0 ) const { return _getPtr( idx ); }
// Gets a pointer to the element directly after the last element in the array.
// This is equivalent to doing GetPtr(GetLength()), except that this call *avoids*
// the out-of-bounds assertion check that typically occurs when you do that. :)
T* GetPtrEnd( uint idx=0 ) { return &m_ptr[m_size]; }
const T* GetPtrEnd( uint idx=0 ) const { return &m_ptr[m_size]; }
// Gets an element of this memory allocation much as if it were an array.
// DevBuilds : Generates assertion if the index is invalid.

View File

@ -13,31 +13,58 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
// --------------------------------------------------------------------------------------
// pxStreamWriter
// pxStreamBase
// --------------------------------------------------------------------------------------
class pxStreamWriter
class pxStreamBase
{
DeclareNoncopyableObject(pxStreamWriter);
DeclareNoncopyableObject(pxStreamBase);
protected:
wxString m_filename;
ScopedPtr<wxOutputStream> m_outstream;
// Filename of the stream, provided by the creator/caller. This is typically used *only*
// for generating comprehensive error messages when an error occurs (the stream name is
// passed to the exception handlers).
wxString m_filename;
public:
pxStreamWriter(const wxString& filename, ScopedPtr<wxOutputStream>& output);
pxStreamWriter(const wxString& filename, wxOutputStream* output);
pxStreamBase(const wxString& filename);
virtual ~pxStreamBase() throw() {}
virtual ~pxStreamWriter() throw() {}
// Implementing classes should return the base wxStream object (usually either a wxInputStream
// or wxOputStream derivative).
virtual wxStreamBase* GetWxStreamBase() const=0;
virtual void Close()=0;
bool IsOk() const;
wxString GetStreamName() const { return m_filename; }
};
// --------------------------------------------------------------------------------------
// pxOutputStream
// --------------------------------------------------------------------------------------
class pxOutputStream : public pxStreamBase
{
DeclareNoncopyableObject(pxOutputStream);
protected:
ScopedPtr<wxOutputStream> m_stream_out;
public:
pxOutputStream(const wxString& filename, ScopedPtr<wxOutputStream>& output);
pxOutputStream(const wxString& filename, wxOutputStream* output);
virtual ~pxOutputStream() throw() {}
virtual void Write( const void* data, size_t size );
void Close() { m_outstream.Delete(); }
wxOutputStream* GetBaseStream() const { return m_outstream; }
void SetStream( const wxString& filename, ScopedPtr<wxOutputStream>& stream );
void SetStream( const wxString& filename, wxOutputStream* stream );
wxString GetStreamName() const { return m_filename; }
void Close() { m_stream_out.Delete(); }
virtual wxStreamBase* GetWxStreamBase() const;
template< typename T >
void Write( const T& data )
@ -47,30 +74,28 @@ public:
};
// --------------------------------------------------------------------------------------
// pxStreamReader
// pxInputStream
// --------------------------------------------------------------------------------------
class pxStreamReader
class pxInputStream : public pxStreamBase
{
DeclareNoncopyableObject(pxStreamReader);
DeclareNoncopyableObject(pxInputStream);
protected:
wxString m_filename;
ScopedPtr<wxInputStream> m_stream;
ScopedPtr<wxInputStream> m_stream_in;
public:
pxStreamReader(const wxString& filename, ScopedPtr<wxInputStream>& input);
pxStreamReader(const wxString& filename, wxInputStream* input);
pxInputStream(const wxString& filename, ScopedPtr<wxInputStream>& input);
pxInputStream(const wxString& filename, wxInputStream* input);
virtual ~pxStreamReader() throw() {}
virtual ~pxInputStream() throw() {}
virtual void Read( void* dest, size_t size );
void SetStream( const wxString& filename, ScopedPtr<wxInputStream>& stream );
void SetStream( const wxString& filename, wxInputStream* stream );
wxInputStream* GetBaseStream() const { return m_stream; }
void Close() { m_stream.Delete(); }
void Close() { m_stream_in.Delete(); }
wxString GetStreamName() const { return m_filename; }
virtual wxStreamBase* GetWxStreamBase() const;
template< typename T >
void Read( T& dest )

View File

@ -292,7 +292,7 @@ wxString Exception::BadStream::FormatDisplayMessage() const
return retval;
}
void Exception::BadStream::_formatDiagMsg( FastFormatUnicode& dest ) const
void Exception::BadStream::_formatDiagMsg( FastFormatUnicode& dest ) const
{
dest.Write( L"Path: " );
if (!StreamName.IsEmpty())

View File

@ -22,39 +22,55 @@
#include <errno.h>
// --------------------------------------------------------------------------------------
// pxStreamReader (implementations)
// pxStreamBase (implementations)
// --------------------------------------------------------------------------------------
pxStreamBase::pxStreamBase(const wxString& filename)
: m_filename( filename )
{
}
bool pxStreamBase::IsOk() const
{
wxStreamBase* woot = GetWxStreamBase();
return woot && woot->IsOk();
}
// --------------------------------------------------------------------------------------
// pxInputStream (implementations)
// --------------------------------------------------------------------------------------
// Interface for reading data from a gzip stream.
//
pxStreamReader::pxStreamReader(const wxString& filename, ScopedPtr<wxInputStream>& input)
: m_filename( filename )
, m_stream( input.DetachPtr() )
pxInputStream::pxInputStream(const wxString& filename, ScopedPtr<wxInputStream>& input)
: pxStreamBase( filename )
, m_stream_in( input.DetachPtr() )
{
}
pxStreamReader::pxStreamReader(const wxString& filename, wxInputStream* input)
: m_filename( filename )
, m_stream( input )
pxInputStream::pxInputStream(const wxString& filename, wxInputStream* input)
: pxStreamBase( filename )
, m_stream_in( input )
{
}
void pxStreamReader::SetStream( const wxString& filename, ScopedPtr<wxInputStream>& stream )
wxStreamBase* pxInputStream::GetWxStreamBase() const { return m_stream_in.GetPtr(); }
void pxInputStream::SetStream( const wxString& filename, ScopedPtr<wxInputStream>& stream )
{
m_filename = filename;
m_stream = stream.DetachPtr();
m_stream_in = stream.DetachPtr();
}
void pxStreamReader::SetStream( const wxString& filename, wxInputStream* stream )
void pxInputStream::SetStream( const wxString& filename, wxInputStream* stream )
{
m_filename = filename;
m_stream = stream;
m_stream_in = stream;
}
void pxStreamReader::Read( void* dest, size_t size )
void pxInputStream::Read( void* dest, size_t size )
{
m_stream->Read(dest, size);
if (m_stream->GetLastError() == wxSTREAM_READ_ERROR)
m_stream_in->Read(dest, size);
if (m_stream_in->GetLastError() == wxSTREAM_READ_ERROR)
{
int err = errno;
if (!err)
@ -69,43 +85,46 @@ void pxStreamReader::Read( void* dest, size_t size )
// must always use the explicit check against the number of bytes read to determine
// end-of-stream conditions.
if ((size_t)m_stream->LastRead() < size)
if ((size_t)m_stream_in->LastRead() < size)
throw Exception::EndOfStream( m_filename );
}
// --------------------------------------------------------------------------------------
// pxStreamWriter
// pxOutputStream
// --------------------------------------------------------------------------------------
pxStreamWriter::pxStreamWriter(const wxString& filename, ScopedPtr<wxOutputStream>& output)
: m_filename( filename )
, m_outstream( output.DetachPtr() )
pxOutputStream::pxOutputStream(const wxString& filename, ScopedPtr<wxOutputStream>& output)
: pxStreamBase( filename )
, m_stream_out( output.DetachPtr() )
{
}
pxStreamWriter::pxStreamWriter(const wxString& filename, wxOutputStream* output)
: m_filename( filename )
, m_outstream( output )
pxOutputStream::pxOutputStream(const wxString& filename, wxOutputStream* output)
: pxStreamBase( filename )
, m_stream_out( output )
{
}
void pxStreamWriter::SetStream( const wxString& filename, ScopedPtr<wxOutputStream>& stream )
wxStreamBase* pxOutputStream::GetWxStreamBase() const { return m_stream_out.GetPtr(); }
void pxOutputStream::SetStream( const wxString& filename, ScopedPtr<wxOutputStream>& stream )
{
m_filename = filename;
m_outstream = stream.DetachPtr();
m_stream_out = stream.DetachPtr();
}
void pxStreamWriter::SetStream( const wxString& filename, wxOutputStream* stream )
void pxOutputStream::SetStream( const wxString& filename, wxOutputStream* stream )
{
m_filename = filename;
m_outstream = stream;
m_stream_out = stream;
}
void pxStreamWriter::Write( const void* src, size_t size )
void pxOutputStream::Write( const void* src, size_t size )
{
m_outstream->Write(src, size);
if(m_outstream->GetLastError() == wxSTREAM_WRITE_ERROR)
m_stream_out->Write(src, size);
if(m_stream_out->GetLastError() == wxSTREAM_WRITE_ERROR)
{
int err = errno;
if (!err)

View File

@ -20,6 +20,7 @@
#include "ps2/BiosTools.h"
#include "COP0.h"
#include "VUmicro.h"
#include "Cache.h"
#include "AppConfig.h"
@ -163,6 +164,12 @@ void SaveStateBase::FreezeMainMemory()
FreezeMem(iopMem->Main, Ps2MemSize::IopRam); // 2 MB main memory
FreezeMem(iopHw, Ps2MemSize::IopHardware); // hardware memory
FreezeMem(vuRegs[0].Micro, VU0_PROGSIZE);
FreezeMem(vuRegs[0].Mem, VU0_MEMSIZE);
FreezeMem(vuRegs[1].Micro, VU1_PROGSIZE);
FreezeMem(vuRegs[1].Mem, VU1_MEMSIZE);
}
void SaveStateBase::FreezeRegisters()
@ -378,16 +385,24 @@ void memSavingState::FreezeMem( void* data, int size )
m_idx += size;
}
void memSavingState::FreezeAll()
void memSavingState::MakeRoomForData()
{
pxAssumeDev( m_memory, "Savestate memory/buffer pointer is null!" );
m_memory->ChunkSize = ReallocThreshold;
m_memory->MakeRoomFor( m_idx + MemoryBaseAllocSize );
}
// Saving of state data to a memory buffer
void memSavingState::FreezeAll()
{
MakeRoomForData();
_parent::FreezeAll();
}
// --------------------------------------------------------------------------------------
// memLoadingState (implementations)
// --------------------------------------------------------------------------------------
memLoadingState::memLoadingState( const SafeArray<u8>& load_from )
: SaveStateBase( const_cast<SafeArray<u8>&>(load_from) )
{
@ -400,7 +415,7 @@ memLoadingState::memLoadingState( const SafeArray<u8>* load_from )
memLoadingState::~memLoadingState() throw() { }
// Loading of state data
// Loading of state data from a memory buffer...
void memLoadingState::FreezeMem( void* data, int size )
{
const u8* const src = m_memory->GetPtr(m_idx);

View File

@ -118,7 +118,7 @@ protected:
u32 m_version; // version of the savestate being loaded.
int m_idx; // current read/write index of the allocation
int m_idx; // current read/write index of the allocation
int m_sectid;
int m_pid;
@ -163,10 +163,20 @@ public:
void PrepBlock( int size );
uint GetCurrentPos() const
{
return m_idx;
}
u8* GetBlockPtr()
{
return m_memory->GetPtr(m_idx);
}
u8* GetPtrEnd() const
{
return m_memory->GetPtrEnd();
}
void CommitBlock( int size )
{
@ -244,7 +254,8 @@ public:
memSavingState( VmStateBuffer& save_to );
memSavingState( VmStateBuffer* save_to );
// Saving of state data to a memory buffer
void MakeRoomForData();
void FreezeMem( void* data, int size );
void FreezeAll();
@ -259,7 +270,6 @@ public:
memLoadingState( const VmStateBuffer& load_from );
memLoadingState( const VmStateBuffer* load_from );
// Loading of state data from a memory buffer...
void FreezeMem( void* data, int size );
bool SeekToSection( PluginsEnum_t pid );

View File

@ -21,6 +21,140 @@
using namespace Threading;
// --------------------------------------------------------------------------------------
// BaseArchiveEntry
// --------------------------------------------------------------------------------------
class BaseArchiveEntry
{
protected:
BaseArchiveEntry() {}
virtual ~BaseArchiveEntry() throw() {}
public:
virtual wxString GetFilename() const=0;
virtual u8* GetDataPtr() const=0;
virtual uint GetDataSize() const=0;
};
// --------------------------------------------------------------------------------------
// ArchiveEntry
// --------------------------------------------------------------------------------------
class ArchiveEntry
{
protected:
wxString m_filename;
uptr m_dataidx;
size_t m_datasize;
public:
ArchiveEntry( const wxString& filename=wxEmptyString )
: m_filename( filename )
{
m_dataidx = 0;
m_datasize = 0;
}
virtual ~ArchiveEntry() throw() {}
ArchiveEntry& SetDataIndex( uptr idx )
{
m_dataidx = idx;
return *this;
}
ArchiveEntry& SetDataSize( size_t size )
{
m_datasize = size;
return *this;
}
wxString GetFilename() const
{
return m_filename;
}
uptr GetDataIndex() const
{
return m_dataidx;
}
uint GetDataSize() const
{
return m_datasize;
}
};
typedef SafeArray< u8 > ArchiveDataBuffer;
// --------------------------------------------------------------------------------------
// ArchiveEntryList
// --------------------------------------------------------------------------------------
class ArchiveEntryList
{
DeclareNoncopyableObject( ArchiveEntryList );
protected:
std::vector<ArchiveEntry> m_list;
ScopedPtr<ArchiveDataBuffer> m_data;
public:
ArchiveEntryList() {}
ArchiveEntryList( ArchiveDataBuffer* data )
{
m_data = data;
}
ArchiveEntryList( ScopedPtr<ArchiveDataBuffer>& data )
{
m_data = data.DetachPtr();
}
virtual ~ArchiveEntryList() throw() {}
const VmStateBuffer* GetBuffer() const
{
return m_data;
}
VmStateBuffer* GetBuffer()
{
return m_data;
}
u8* GetPtr( uint idx )
{
return &(*m_data)[idx];
}
const u8* GetPtr( uint idx ) const
{
return &(*m_data)[idx];
}
ArchiveEntryList& Add( const ArchiveEntry& src )
{
m_list.push_back( src );
return *this;
}
size_t GetLength() const
{
return m_list.size();
}
ArchiveEntry& operator[](uint idx)
{
return m_list[idx];
}
const ArchiveEntry& operator[](uint idx) const
{
return m_list[idx];
}
};
// --------------------------------------------------------------------------------------
// BaseCompressThread
// --------------------------------------------------------------------------------------
@ -30,33 +164,45 @@ class BaseCompressThread
typedef pxThread _parent;
protected:
ScopedPtr< SafeArray< u8 > > m_src_buffer;
ScopedPtr< pxStreamWriter > m_gzfp;
ScopedPtr< ArchiveEntryList > m_src_list;
ScopedPtr< pxOutputStream > m_gzfp;
bool m_PendingSaveFlag;
wxString m_final_filename;
BaseCompressThread( SafeArray<u8>* srcdata, pxStreamWriter* outarchive)
: m_src_buffer( srcdata )
public:
virtual ~BaseCompressThread() throw();
BaseCompressThread& SetSource( ArchiveEntryList* srcdata )
{
m_gzfp = outarchive;
m_PendingSaveFlag = false;
m_src_list = srcdata;
return *this;
}
BaseCompressThread( SafeArray<u8>* srcdata, ScopedPtr<pxStreamWriter>& outarchive)
: m_src_buffer( srcdata )
BaseCompressThread& SetSource( ScopedPtr< ArchiveEntryList >& srcdata )
{
m_gzfp = outarchive.DetachPtr();
m_PendingSaveFlag = false;
m_src_list = srcdata.DetachPtr();
return *this;
}
virtual ~BaseCompressThread() throw();
void SetPendingSave();
void ExecuteTaskInThread();
void OnCleanupInThread();
public:
BaseCompressThread& SetOutStream( pxOutputStream* out )
{
m_gzfp = out;
return *this;
}
BaseCompressThread& SetOutStream( ScopedPtr< pxOutputStream >& out )
{
m_gzfp = out.DetachPtr();
return *this;
}
BaseCompressThread& SetFinishedPath( const wxString& path )
{
m_final_filename = path;
return *this;
}
wxString GetStreamName() const { return m_gzfp->GetStreamName(); }
BaseCompressThread& SetTargetFilename(const wxString& filename)
@ -64,4 +210,14 @@ public:
m_final_filename = filename;
return *this;
}
protected:
BaseCompressThread()
{
m_PendingSaveFlag = false;
}
void SetPendingSave();
void ExecuteTaskInThread();
void OnCleanupInThread();
};

View File

@ -43,26 +43,38 @@ void BaseCompressThread::ExecuteTaskInThread()
// TODO : Add an API to PersistentThread for this! :) --air
//SetThreadPriority( THREAD_PRIORITY_BELOW_NORMAL );
if( !m_src_buffer ) return;
// Notes:
// * Safeguard against corruption by writing to a temp file, and then copying the final
// result over the original.
if( !m_src_list ) return;
SetPendingSave();
Yield( 3 );
static const int BlockSize = 0x64000;
int curidx = 0;
uint listlen = m_src_list->GetLength();
for( uint i=0; i<listlen; ++i )
{
const ArchiveEntry& entry = (*m_src_list)[i];
// Safeguard against corruption by writing to a temp file, and then
// copying the final result over the original:
wxArchiveOutputStream& woot = *(wxArchiveOutputStream*)m_gzfp->GetWxStreamBase();
woot.PutNextEntry( entry.GetFilename() );
static const uint BlockSize = 0x64000;
uint curidx = 0;
do {
uint thisBlockSize = std::min( BlockSize, entry.GetDataSize() - curidx );
m_gzfp->Write(m_src_list->GetPtr( entry.GetDataIndex() + curidx ), thisBlockSize);
curidx += thisBlockSize;
Yield( 2 );
} while( curidx < entry.GetDataSize() );
woot.CloseEntry();
}
do {
int thisBlockSize = std::min( BlockSize, m_src_buffer->GetSizeInBytes() - curidx );
m_gzfp->Write(m_src_buffer->GetPtr(curidx), thisBlockSize);
curidx += thisBlockSize;
Yield( 2 );
} while( curidx < m_src_buffer->GetSizeInBytes() );
//m_gzfp->CloseEntry();
m_gzfp->Close();
if( !wxRenameFile( m_gzfp->GetStreamName(), m_final_filename, true ) )

View File

@ -19,10 +19,11 @@
#include "System/SysThreads.h"
#include "SaveState.h"
#include "VUmicro.h"
#include "ZipTools/ThreadedZipTools.h"
#include "wx/wfstream.h"
#include <wx/wfstream.h>
// Used to hold the current state backup (fullcopy of PS2 memory and plugin states).
//static VmStateBuffer state_buffer( L"Public Savestate Buffer" );
@ -31,54 +32,88 @@ static const wxChar* EntryFilename_StateVersion = L"PCSX2 Savestate Version.id
static const wxChar* EntryFilename_Screenshot = L"Screenshot.jpg";
static const wxChar* EntryFilename_InternalStructures = L"PCSX2 Internal Structures.bin";
class BaseSavestateEntry
{
public:
virtual const wxChar* GetFilename() const=0;
virtual void* GetDataPtr() const=0;
virtual uint GetDataSize() const=0;
};
class SavestateEntry_EmotionMemory : public BaseSavestateEntry
// --------------------------------------------------------------------------------------
// SavestateEntry_* (EmotionMemory, IopMemory, etc)
// --------------------------------------------------------------------------------------
// Implementation Rationale:
// The address locations of PS2 virtual memory components is fully dynamic, so we need to
// resolve the pointers at the time they are requested (eeMem, iopMem, etc). Thusly, we
// cannot use static struct member initializers -- we need virtual functions that compute
// and resolve the addresses on-demand instead... --air
class SavestateEntry_EmotionMemory : public BaseArchiveEntry
{
public:
const wxChar* GetFilename() const { return L"eeMemory.bin"; }
void* GetDataPtr() const { return eeMem->Main; }
wxString GetFilename() const { return L"eeMemory.bin"; }
u8* GetDataPtr() const { return eeMem->Main; }
uint GetDataSize() const { return sizeof(eeMem->Main); }
};
class SavestateEntry_IopMemory : public BaseSavestateEntry
class SavestateEntry_IopMemory : public BaseArchiveEntry
{
public:
const wxChar* GetFilename() const { return L"iopMemory.bin"; }
void* GetDataPtr() const { return iopMem->Main; }
wxString GetFilename() const { return L"iopMemory.bin"; }
u8* GetDataPtr() const { return iopMem->Main; }
uint GetDataSize() const { return sizeof(iopMem->Main); }
};
class SavestateEntry_HwRegs : public BaseSavestateEntry
class SavestateEntry_HwRegs : public BaseArchiveEntry
{
public:
const wxChar* GetFilename() const { return L"eeHwRegs.bin"; }
void* GetDataPtr() const { return eeHw; }
wxString GetFilename() const { return L"eeHwRegs.bin"; }
u8* GetDataPtr() const { return eeHw; }
uint GetDataSize() const { return sizeof(eeHw); }
};
class SavestateEntry_IopHwRegs : public BaseSavestateEntry
class SavestateEntry_IopHwRegs : public BaseArchiveEntry
{
public:
const wxChar* GetFilename() const { return L"iopHwRegs.bin"; }
void* GetDataPtr() const { return iopHw; }
wxString GetFilename() const { return L"iopHwRegs.bin"; }
u8* GetDataPtr() const { return iopHw; }
uint GetDataSize() const { return sizeof(iopHw); }
};
class SavestateEntry_Scratchpad : public BaseSavestateEntry
class SavestateEntry_Scratchpad : public BaseArchiveEntry
{
public:
const wxChar* GetFilename() const { return L"Scratchpad.bin"; }
void* GetDataPtr() const { return eeMem->Scratch; }
wxString GetFilename() const { return L"Scratchpad.bin"; }
u8* GetDataPtr() const { return eeMem->Scratch; }
uint GetDataSize() const { return sizeof(eeMem->Scratch); }
};
class SavestateEntry_VU0mem : public BaseArchiveEntry
{
public:
wxString GetFilename() const { return L"vu0Memory.bin"; }
u8* GetDataPtr() const { return vuRegs[0].Mem; }
uint GetDataSize() const { return VU0_MEMSIZE; }
};
class SavestateEntry_VU1mem : public BaseArchiveEntry
{
public:
wxString GetFilename() const { return L"vu1Memory.bin"; }
u8* GetDataPtr() const { return vuRegs[1].Mem; }
uint GetDataSize() const { return VU1_MEMSIZE; }
};
class SavestateEntry_VU0prog : public BaseArchiveEntry
{
public:
wxString GetFilename() const { return L"vu0Programs.bin"; }
u8* GetDataPtr() const { return vuRegs[0].Micro; }
uint GetDataSize() const { return VU0_PROGSIZE; }
};
class SavestateEntry_VU1prog : public BaseArchiveEntry
{
public:
wxString GetFilename() const { return L"vu1Programs.bin"; }
u8* GetDataPtr() const { return vuRegs[1].Micro; }
uint GetDataSize() const { return VU1_PROGSIZE; }
};
// [TODO] : Add other components as files to the savestate gzip?
// * VU0/VU1 memory banks? VU0prog, VU1prog, VU0data, VU1data.
// * GS register data?
@ -88,13 +123,17 @@ public:
// would not be useful).
//
static const BaseSavestateEntry* const SavestateEntries[] =
static const BaseArchiveEntry* const SavestateEntries[] =
{
new SavestateEntry_EmotionMemory,
new SavestateEntry_IopMemory,
new SavestateEntry_HwRegs,
new SavestateEntry_IopHwRegs,
new SavestateEntry_Scratchpad,
new SavestateEntry_VU0mem,
new SavestateEntry_VU1mem,
new SavestateEntry_VU0prog,
new SavestateEntry_VU1prog,
};
static const uint NumSavestateEntries = ArraySize(SavestateEntries);
@ -107,7 +146,7 @@ static const uint NumSavestateEntries = ArraySize(SavestateEntries);
//
static Mutex mtx_CompressToDisk;
static void CheckVersion( pxStreamReader& thr )
static void CheckVersion( pxInputStream& thr )
{
u32 savever;
thr.Read( savever );
@ -135,16 +174,16 @@ static void CheckVersion( pxStreamReader& thr )
class SysExecEvent_DownloadState : public SysExecEvent
{
protected:
VmStateBuffer* m_dest_buffer;
ArchiveEntryList* m_dest_list;
public:
wxString GetEventName() const { return L"VM_Download"; }
virtual ~SysExecEvent_DownloadState() throw() {}
SysExecEvent_DownloadState* Clone() const { return new SysExecEvent_DownloadState( *this ); }
SysExecEvent_DownloadState( VmStateBuffer* dest=NULL )
SysExecEvent_DownloadState( ArchiveEntryList* dest_list=NULL )
{
m_dest_buffer = dest;
m_dest_list = dest_list;
}
bool IsCriticalEvent() const { return true; }
@ -160,9 +199,25 @@ protected:
.SetDiagMsg(L"SysExecEvent_DownloadState: Cannot freeze/download an invalid VM state!")
.SetUserMsg(L"There is no active virtual machine state to download or save." );
memSavingState saveme( m_dest_buffer );
memSavingState saveme( m_dest_list->GetBuffer() );
ArchiveEntry internals( EntryFilename_InternalStructures );
internals.SetDataIndex( saveme.GetCurrentPos() );
saveme.FreezeAll();
internals.SetDataSize( saveme.GetCurrentPos() - internals.GetDataIndex() );
m_dest_list->Add( internals );
for (uint i=0; i<NumSavestateEntries; ++i)
{
m_dest_list->Add( ArchiveEntry( SavestateEntries[i]->GetFilename() )
.SetDataIndex( saveme.GetCurrentPos() )
.SetDataSize( SavestateEntries[i]->GetDataSize() )
);
saveme.FreezeMem( SavestateEntries[i]->GetDataPtr(), SavestateEntries[i]->GetDataSize() );
}
UI_EnableStateActions();
paused_core.AllowResume();
}
@ -180,14 +235,7 @@ protected:
ScopedLock m_lock_Compress;
public:
VmStateCompressThread( VmStateBuffer* srcdata, pxStreamWriter* outarchive )
: _parent( srcdata, outarchive )
{
m_lock_Compress.Assign(mtx_CompressToDisk);
}
VmStateCompressThread( ScopedPtr<VmStateBuffer>& srcdata, ScopedPtr<pxStreamWriter>& outarchive )
: _parent( srcdata, outarchive )
VmStateCompressThread()
{
m_lock_Compress.Assign(mtx_CompressToDisk);
}
@ -216,7 +264,7 @@ protected:
class SysExecEvent_ZipToDisk : public SysExecEvent
{
protected:
VmStateBuffer* m_src_buffer;
ArchiveEntryList* m_src_list;
wxString m_filename;
public:
@ -228,16 +276,16 @@ public:
SysExecEvent_ZipToDisk* Clone() const { return new SysExecEvent_ZipToDisk( *this ); }
SysExecEvent_ZipToDisk( ScopedPtr<VmStateBuffer>& src, const wxString& filename )
SysExecEvent_ZipToDisk( ScopedPtr<ArchiveEntryList>& srclist, const wxString& filename )
: m_filename( filename )
{
m_src_buffer = src.DetachPtr();
m_src_list = srclist.DetachPtr();
}
SysExecEvent_ZipToDisk( VmStateBuffer* src, const wxString& filename )
SysExecEvent_ZipToDisk( ArchiveEntryList* srclist, const wxString& filename )
: m_filename( filename )
{
m_src_buffer = src;
m_src_list = srclist;
}
bool IsCriticalEvent() const { return true; }
@ -246,6 +294,9 @@ public:
protected:
void InvokeEvent()
{
// Provisionals for scoped cleanup, in case of exception:
ScopedPtr<ArchiveEntryList> elist( m_src_list );
wxString tempfile( m_filename + L".tmp" );
wxFFileOutputStream* woot = new wxFFileOutputStream(tempfile);
@ -253,8 +304,8 @@ protected:
throw Exception::CannotCreateStream(tempfile);
// Write the version and screenshot:
ScopedPtr<pxStreamWriter> out( new pxStreamWriter(tempfile, new wxZipOutputStream(woot)) );
wxZipOutputStream* gzfp = (wxZipOutputStream*)out->GetBaseStream();
ScopedPtr<pxOutputStream> out( new pxOutputStream(tempfile, new wxZipOutputStream(woot)) );
wxZipOutputStream* gzfp = (wxZipOutputStream*)out->GetWxStreamBase();
{
wxZipEntry* vent = new wxZipEntry(EntryFilename_StateVersion);
@ -277,16 +328,21 @@ protected:
//m_gzfp->PutNextEntry(EntryFilename_Screenshot);
//m_gzfp->Write();
//m_gzfp->Write();
//m_gzfp->CloseEntry();
(new VmStateCompressThread( m_src_buffer, out ))->
SetTargetFilename(m_filename).Start();
(*new VmStateCompressThread())
.SetSource(m_src_list)
.SetOutStream(out)
.SetFinishedPath(m_filename)
.Start();
// No errors? Release cleanup handlers:
elist.DetachPtr();
}
void CleanupEvent()
{
m_src_buffer = NULL;
}
};
@ -325,8 +381,7 @@ protected:
if (!woot->IsOk())
throw Exception::CannotCreateStream( m_filename ).SetDiagMsg(L"Cannot open file for reading.");
ScopedPtr<pxStreamReader> reader( new pxStreamReader(m_filename, new wxZipInputStream(woot)) );
ScopedPtr<pxInputStream> reader( new pxInputStream(m_filename, new wxZipInputStream(woot)) );
woot.DetachPtr();
if (!reader->IsOk())
@ -336,7 +391,7 @@ protected:
.SetUserMsg(_("This savestate cannot be loaded because it is not a valid gzip archive. It may have been created by an older unsupported version of PCSX2, or it may be corrupted."));
}
wxZipInputStream* gzreader = (wxZipInputStream*)reader->GetBaseStream();
wxZipInputStream* gzreader = (wxZipInputStream*)reader->GetWxStreamBase();
// look for version and screenshot information in the zip stream:
@ -359,12 +414,14 @@ protected:
DevCon.WriteLn(L" ... found '%s'", EntryFilename_StateVersion);
foundVersion = true;
CheckVersion(*reader);
continue;
}
if (entry->GetName().CmpNoCase(EntryFilename_InternalStructures) == 0)
{
DevCon.WriteLn(L" ... found '%s'", EntryFilename_InternalStructures);
foundInternal = entry.DetachPtr();
continue;
}
// No point in finding screenshots when loading states -- the screenshots are
@ -411,6 +468,7 @@ protected:
// *ALWAYS* start execution after the new savestate is loaded.
GetCoreThread().Pause();
SysClearExecutionCache();
for (uint i=0; i<NumSavestateEntries; ++i)
{
@ -437,7 +495,6 @@ protected:
VmStateBuffer buffer( foundInternal->GetSize(), L"StateBuffer_UnzipFromDisk" ); // start with an 8 meg buffer to avoid frequent reallocation.
reader->Read( buffer.GetPtr(), foundInternal->GetSize() );
//GetCoreThread().UploadStateCopy( buffer );
memLoadingState( buffer ).FreezeAll();
GetCoreThread().Resume(); // force resume regardless of emulation state earlier.
}
@ -451,9 +508,10 @@ void StateCopy_SaveToFile( const wxString& file )
{
UI_DisableStateActions();
ScopedPtr<VmStateBuffer> zipbuf(new VmStateBuffer( L"Zippable Savestate" ));
GetSysExecutorThread().PostEvent(new SysExecEvent_DownloadState( zipbuf ));
GetSysExecutorThread().PostEvent(new SysExecEvent_ZipToDisk( zipbuf, file ));
ScopedPtr<ArchiveEntryList> ziplist (new ArchiveEntryList( new VmStateBuffer( L"Zippable Savestate" ) ));
GetSysExecutorThread().PostEvent(new SysExecEvent_DownloadState ( ziplist ));
GetSysExecutorThread().PostEvent(new SysExecEvent_ZipToDisk ( ziplist, file ));
}
void StateCopy_LoadFromFile( const wxString& file )