diff --git a/common/include/Utilities/Dependencies.h b/common/include/Utilities/Dependencies.h index f36cac9d1d..ec977b25ef 100644 --- a/common/include/Utilities/Dependencies.h +++ b/common/include/Utilities/Dependencies.h @@ -26,6 +26,7 @@ class wxOutputStream; class wxFileOutputStream; class wxFFileOutputStream; +class wxStreamBase; class wxInputStream; class wxFileInputStream; class wxFFileInputStream; diff --git a/common/include/Utilities/SafeArray.h b/common/include/Utilities/SafeArray.h index 6e6d940b97..96c373cb26 100644 --- a/common/include/Utilities/SafeArray.h +++ b/common/include/Utilities/SafeArray.h @@ -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. diff --git a/common/include/Utilities/pxStreams.h b/common/include/Utilities/pxStreams.h index 1eb07714d1..326965231e 100644 --- a/common/include/Utilities/pxStreams.h +++ b/common/include/Utilities/pxStreams.h @@ -13,31 +13,58 @@ * If not, see . */ +#pragma once + // -------------------------------------------------------------------------------------- -// pxStreamWriter +// pxStreamBase // -------------------------------------------------------------------------------------- -class pxStreamWriter +class pxStreamBase { - DeclareNoncopyableObject(pxStreamWriter); + DeclareNoncopyableObject(pxStreamBase); protected: - wxString m_filename; - ScopedPtr 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& 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 m_stream_out; + +public: + pxOutputStream(const wxString& filename, ScopedPtr& 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& 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 m_stream; + ScopedPtr m_stream_in; public: - pxStreamReader(const wxString& filename, ScopedPtr& input); - pxStreamReader(const wxString& filename, wxInputStream* input); + pxInputStream(const wxString& filename, ScopedPtr& 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& 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 ) diff --git a/common/src/Utilities/Exceptions.cpp b/common/src/Utilities/Exceptions.cpp index 64037aa4d1..65670f0e19 100644 --- a/common/src/Utilities/Exceptions.cpp +++ b/common/src/Utilities/Exceptions.cpp @@ -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()) diff --git a/common/src/Utilities/pxStreams.cpp b/common/src/Utilities/pxStreams.cpp index 3d960a430c..00eed7a253 100644 --- a/common/src/Utilities/pxStreams.cpp +++ b/common/src/Utilities/pxStreams.cpp @@ -22,39 +22,55 @@ #include // -------------------------------------------------------------------------------------- -// 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& input) - : m_filename( filename ) - , m_stream( input.DetachPtr() ) +pxInputStream::pxInputStream(const wxString& filename, ScopedPtr& 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& stream ) +wxStreamBase* pxInputStream::GetWxStreamBase() const { return m_stream_in.GetPtr(); } + +void pxInputStream::SetStream( const wxString& filename, ScopedPtr& 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& output) - : m_filename( filename ) - , m_outstream( output.DetachPtr() ) +pxOutputStream::pxOutputStream(const wxString& filename, ScopedPtr& 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& stream ) +wxStreamBase* pxOutputStream::GetWxStreamBase() const { return m_stream_out.GetPtr(); } + + +void pxOutputStream::SetStream( const wxString& filename, ScopedPtr& 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) diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index c6333e951a..70ace94b46 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -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& load_from ) : SaveStateBase( const_cast&>(load_from) ) { @@ -400,7 +415,7 @@ memLoadingState::memLoadingState( const SafeArray* 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); diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index 4022a646b3..e4bba1ddbd 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -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 ); diff --git a/pcsx2/ZipTools/ThreadedZipTools.h b/pcsx2/ZipTools/ThreadedZipTools.h index d12adfb159..f56242705b 100644 --- a/pcsx2/ZipTools/ThreadedZipTools.h +++ b/pcsx2/ZipTools/ThreadedZipTools.h @@ -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 m_list; + ScopedPtr m_data; + +public: + ArchiveEntryList() {} + + ArchiveEntryList( ArchiveDataBuffer* data ) + { + m_data = data; + } + + ArchiveEntryList( ScopedPtr& 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* 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* srcdata, ScopedPtr& 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(); }; diff --git a/pcsx2/ZipTools/thread_gzip.cpp b/pcsx2/ZipTools/thread_gzip.cpp index aea95b766d..8832922982 100644 --- a/pcsx2/ZipTools/thread_gzip.cpp +++ b/pcsx2/ZipTools/thread_gzip.cpp @@ -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; iGetWxStreamBase(); + 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 ) ) diff --git a/pcsx2/gui/SysState.cpp b/pcsx2/gui/SysState.cpp index 527ff9e67a..018f793105 100644 --- a/pcsx2/gui/SysState.cpp +++ b/pcsx2/gui/SysState.cpp @@ -19,10 +19,11 @@ #include "System/SysThreads.h" #include "SaveState.h" +#include "VUmicro.h" #include "ZipTools/ThreadedZipTools.h" -#include "wx/wfstream.h" +#include // 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; iAdd( 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& srcdata, ScopedPtr& 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& src, const wxString& filename ) + SysExecEvent_ZipToDisk( ScopedPtr& 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 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 out( new pxStreamWriter(tempfile, new wxZipOutputStream(woot)) ); - wxZipOutputStream* gzfp = (wxZipOutputStream*)out->GetBaseStream(); + ScopedPtr 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 reader( new pxStreamReader(m_filename, new wxZipInputStream(woot)) ); + ScopedPtr 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; iGetSize(), 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 zipbuf(new VmStateBuffer( L"Zippable Savestate" )); - GetSysExecutorThread().PostEvent(new SysExecEvent_DownloadState( zipbuf )); - GetSysExecutorThread().PostEvent(new SysExecEvent_ZipToDisk( zipbuf, file )); + ScopedPtr 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 )