From b5f952fc5e88de6eed726cd6489be611f898e64e Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Thu, 29 Jan 2009 22:54:06 +0000 Subject: [PATCH] Fixed a bug that caused old pre1.8 versions of Gsdx to crash at startup, and fixed some instability problems when loading savestates. Cleaned up some MTGS code, and improved performance a bit, especially for games that tend to stress the GPU (when Gsdx registers 70%+ cpu). Programmer notes: Several code cleanups to header files. Added MemcpyFast.h and SafeArray.h, and removed a couple more ugly #include inter-dependencies. :) git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@656 a6443dda-0b58-4228-96e9-037be469359c --- pcsx2/Common.h | 5 +- pcsx2/Elfheader.cpp | 8 + pcsx2/GS.cpp | 4 +- pcsx2/GS.h | 10 +- pcsx2/MTGS.cpp | 62 ++- pcsx2/MemcpyFast.h | 57 +++ pcsx2/Misc.cpp | 4 +- pcsx2/Misc.h | 61 +-- pcsx2/Paths.h | 16 +- pcsx2/R5900.cpp | 12 +- pcsx2/SafeArray.h | 244 +++++++++++ pcsx2/SaveState.cpp | 8 +- pcsx2/System.h | 216 +--------- pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 456 +++++++++++---------- pcsx2/windows/WinMain.cpp | 1 + pcsx2/windows/WinSysExec.cpp | 5 +- pcsx2/windows/memzero.h | 25 +- 17 files changed, 653 insertions(+), 541 deletions(-) create mode 100644 pcsx2/MemcpyFast.h create mode 100644 pcsx2/SafeArray.h diff --git a/pcsx2/Common.h b/pcsx2/Common.h index 0119ec2230..308bb6ac8f 100644 --- a/pcsx2/Common.h +++ b/pcsx2/Common.h @@ -63,14 +63,15 @@ extern TESTRUNARGS g_TestRun; #define PSXSOUNDCLK ((int)(48000)) #include "Plugins.h" -#include "System.h" +#include "Misc.h" +#include "SaveState.h" #include "DebugTools/Debug.h" #include "R5900.h" #include "Memory.h" #include "Elfheader.h" #include "Hw.h" // Moving this before one of the other includes causes compilation issues. -#include "Misc.h" +//#include "Misc.h" #include "Patch.h" #define PCSX2_VERSION "Playground (beta)" diff --git a/pcsx2/Elfheader.cpp b/pcsx2/Elfheader.cpp index b14ff706cc..c26d3b9143 100644 --- a/pcsx2/Elfheader.cpp +++ b/pcsx2/Elfheader.cpp @@ -537,12 +537,20 @@ u32 loadElfCRC( const char* filename ) int loadElfFile(const char *filename) { + // Reset all recompilers prior to initiating a BIOS or new ELF. The cleaner the + // slate, the happier the recompiler! + + SysResetExecutionState(); + if( filename == NULL || filename[0] == 0 ) { Console::Notice( "Running the PS2 BIOS..." ); return -1; } + // We still need to run the BIOS stub, so that all the EE hardware gets initialized correctly. + cpuExecuteBios(); + int elfsize; Console::Status("loadElfFile: %s", params filename); diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index c4673385e0..237a10f9b4 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -290,7 +290,7 @@ static bool _gsGIFSoftReset( int mask ) if( !warned ) { Console::Notice( "GIF Warning > Soft reset requested, but the GS plugin doesn't support it!" ); - warned = true; + //warned = true; } return false; } @@ -307,7 +307,7 @@ void gsGIFReset() { #ifndef PCSX2_VIRTUAL_MEM // fixme - should this be here? (air) - memzero_obj(g_RealGSMem); + //memzero_obj(g_RealGSMem); #endif // perform a soft reset (but do not do a full reset if the soft reset API is unavailable) diff --git a/pcsx2/GS.h b/pcsx2/GS.h index d1c2e29149..68641b0aae 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -230,10 +230,14 @@ public: #endif //return (uptr)&SendSimplePacket; } + protected: - // Sets the gsEvent flag and releases a timeslice. - // For use in loops that wait on the GS thread to do certain things. - void SetEventWait(); + // Saves MMX/XMM regs, posts an event to the mtgsThread flag and releases a timeslice. + // For use in surrounding loops that wait on the mtgs. + void PrepEventWait(); + + // Restores MMX/XMM regs. For use in surrounding loops that wait on the mtgs. + void PostEventWait() const; // Processes a GIFtag & packet, and throws out some gsIRQs as needed. // Used to keep interrupts in sync with the EE, while the GS itself diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 690bdd3308..0ed487386b 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -206,6 +206,8 @@ mtgsThreadObject::mtgsThreadObject() : , m_RingBuffer( m_RingBufferSize + (Ps2MemSize::GSregs/sizeof(u128)) ) , m_gsMem( (u8*)m_RingBuffer.GetPtr( m_RingBufferSize ) ) { + memzero_obj( m_path ); + // Wait for the thread to finish initialization (it runs GSinit, which can take // some time since it's creating a new window and all), and then check for errors. @@ -641,7 +643,7 @@ void mtgsThreadObject::SetEvent() m_CopyDataTally = 0; } -void mtgsThreadObject::SetEventWait() +void mtgsThreadObject::PrepEventWait() { // Freeze registers because some kernel code likes to destroy them FreezeXMMRegs(1); @@ -649,6 +651,10 @@ void mtgsThreadObject::SetEventWait() //Console::Notice( "MTGS Stall! EE waits for nothing! ... except your GPU sometimes." ); SetEvent(); Timeslice(); +} + +void mtgsThreadObject::PostEventWait() const +{ FreezeXMMRegs(0); FreezeMMXRegs(0); } @@ -825,20 +831,21 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s { // generic gs wait/stall. // Waits until the readpos is outside the scope of the write area. - while( true ) + + // if the writepos is past the readpos then we're safe. + // But if not then we need to make sure the readpos is outside the scope of + // the block about to be written (writepos + size) + if( writepos < volatize(m_RingPos) ) { - // two conditionals in the following while() loop, so precache - // the readpos for more efficient behavior: - uint readpos = volatize(m_RingPos); - - // if the writepos is past the readpos then we're safe: - if( writepos >= readpos ) break; - - // writepos is behind the readpos, so do a second check to see if the + // writepos is behind the readpos, so we need to wait until // readpos is out past the end of the future write pos: - if( writepos+size < readpos ) break; - SetEventWait(); + PrepEventWait(); + while( writepos+size < volatize(m_RingPos) ) + { + SpinWait(); + } + PostEventWait(); } } else if( writepos + size > m_RingBufferSize ) @@ -851,6 +858,7 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s // greater than the current write position then we need to stall // until it loops around to the beginning of the buffer + PrepEventWait(); while( true ) { uint readpos = volatize(m_RingPos); @@ -863,7 +871,7 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s // position below (bad!) if( readpos < writepos && readpos != 0 ) break; - SetEventWait(); + SpinWait(); } m_lock_RingRestart.Lock(); @@ -871,6 +879,7 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s writepos = 0; AtomicExchange( m_WritePos, writepos ); m_lock_RingRestart.Unlock(); + SetEvent(); // stall until the read position is past the end of our incoming block, // or until it reaches the current write position (signals an empty buffer). @@ -881,27 +890,31 @@ int mtgsThreadObject::PrepDataPacket( GIF_PATH pathidx, const u8* srcdata, u32 s if( readpos == m_WritePos ) break; if( writepos+size < readpos ) break; - SetEventWait(); + SpinWait(); } + PostEventWait(); } else // always true - if( writepos + size == MTGS_RINGBUFFEREND ) { // Yay. Perfect fit. What are the odds? - //SysPrintf( "MTGS > Perfect Fit!\n"); + + PrepEventWait(); while( true ) { uint readpos = volatize(m_RingPos); - // is the buffer empty? Don't wait... - if( readpos == writepos ) break; + // stop waiting if the buffer is empty! + if( writepos == readpos ) break; // Copy is ready so long as readpos is less than writepos and *not* - // equal to the base of the ringbuffer (otherwise the buffer will stop) + // equal to the base of the ringbuffer (otherwise the buffer will stop + // when the writepos is wrapped around to zero later-on in SendDataPacket) if( readpos < writepos && readpos != 0 ) break; - SetEventWait(); + SpinWait(); } + PostEventWait(); } #ifdef RINGBUF_DEBUG_STACK @@ -934,8 +947,15 @@ __forceinline uint mtgsThreadObject::_PrepForSimplePacket() future_writepos &= m_RingBufferMask; - while( future_writepos == volatize(m_RingPos) ) - SetEventWait(); + if( future_writepos == volatize(m_RingPos) ) + { + PrepEventWait(); + do + { + SpinWait(); + } while( future_writepos == volatize(m_RingPos) ); + PostEventWait(); + } return future_writepos; } diff --git a/pcsx2/MemcpyFast.h b/pcsx2/MemcpyFast.h new file mode 100644 index 0000000000..a80192a3da --- /dev/null +++ b/pcsx2/MemcpyFast.h @@ -0,0 +1,57 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __MEMCPY_FAST_H__ +#define __MEMCPY_FAST_H__ + +void _memset16_unaligned( void* dest, u16 data, size_t size ); + +#if defined(_WIN32) && !defined(__x86_64__) + + // The new simplified memcpy_amd_ is now faster than memcpy_raz_. + // memcpy_amd_ also does mmx register saving, negating the need for freezeregs (code cleanup!) + // Additionally, using one single memcpy implementation keeps the code cache cleaner. + + //extern void __fastcall memcpy_raz_udst(void *dest, const void *src, size_t bytes); + //extern void __fastcall memcpy_raz_usrc(void *dest, const void *src, size_t bytes); + //extern void __fastcall memcpy_raz_(void *dest, const void *src, size_t bytes); + extern void __fastcall memcpy_amd_(void *dest, const void *src, size_t bytes); + +# include "windows/memzero.h" +# define memcpy_fast memcpy_amd_ +# define memcpy_aligned memcpy_amd_ + +#else + + // for now linux uses the GCC memcpy/memset implementations. + #define memcpy_fast memcpy + #define memcpy_raz_ memcpy + #define memcpy_raz_u memcpy + + #define memcpy_aligned memcpy + #define memcpy_raz_u memcpy + + #include "Linux/memzero.h" + +#endif + + +extern u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize); +extern void memxor_mmx(void* dst, const void* src1, int cmpsize); + +#endif diff --git a/pcsx2/Misc.cpp b/pcsx2/Misc.cpp index 414e7864f4..7170e451bf 100644 --- a/pcsx2/Misc.cpp +++ b/pcsx2/Misc.cpp @@ -28,9 +28,10 @@ #include "Common.h" #include "PsxCommon.h" +#include "SaveState.h" + #include "CDVDisodrv.h" #include "VUmicro.h" - #include "VU.h" #include "iCore.h" #include "iVUzerorec.h" @@ -556,6 +557,7 @@ void ProcessFKeys(int fkey, int shift) SaveState::GetFilename( Text, StatesC ); gzLoadingState joe( Text ); // throws exception on version mismatch cpuReset(); + SysResetExecutionState(); joe.FreezeAll(); } catch( Exception::StateLoadError_Recoverable& ) diff --git a/pcsx2/Misc.h b/pcsx2/Misc.h index e04cdaadf4..05333354e7 100644 --- a/pcsx2/Misc.h +++ b/pcsx2/Misc.h @@ -19,11 +19,10 @@ #ifndef __MISC_H__ #define __MISC_H__ -#include "PS2Etypes.h" #include "System.h" -#include "SaveState.h" -// --->> GNU GetText / NLS +///////////////////////////////////////////////////////////////////////// +// GNU GetText / NLS #ifdef ENABLE_NLS @@ -49,27 +48,6 @@ #endif // ENABLE_NLS -// <<--- End GNU GetText / NLS - - -// --->> Path Utilities [PathUtil.c] - -#define g_MaxPath 255 // 255 is safer with antiquitated Win32 ASCII APIs. - -namespace Path -{ - void Combine( string& dest, const string& srcPath, const string& srcFile ); - bool isRooted( const string& path ); - bool isDirectory( const string& path ); - bool isFile( const string& path ); - bool Exists( const string& path ); - int getFileSize( const string& path ); - - void ReplaceExtension( string& dest, const string& src, const string& ext ); -} - -// <<--- END Path Utilities [PathUtil.c] - // [TODO] : Move the config options mess from Misc.h into "config.h" or someting more sensible. ///////////////////////////////////////////////////////////////////////// @@ -227,41 +205,6 @@ extern u8 g_globalXMMSaved; #define FreezeXMMRegs(save) if( g_EEFreezeRegs ) { FreezeXMMRegs_(save); } #define FreezeMMXRegs(save) if( g_EEFreezeRegs ) { FreezeMMXRegs_(save); } -void _memset16_unaligned( void* dest, u16 data, size_t size ); - -#if defined(_WIN32) && !defined(__x86_64__) - - // The new simplified memcpy_amd_ is now faster than memcpy_raz_. - // memcpy_amd_ also does mmx register saving, negating the need for freezeregs (code cleanup!) - // Additionally, using one single memcpy implementation keeps the code cache cleaner. - - //extern void __fastcall memcpy_raz_udst(void *dest, const void *src, size_t bytes); - //extern void __fastcall memcpy_raz_usrc(void *dest, const void *src, size_t bytes); - //extern void __fastcall memcpy_raz_(void *dest, const void *src, size_t bytes); - extern void __fastcall memcpy_amd_(void *dest, const void *src, size_t bytes); - -# include "windows/memzero.h" -# define memcpy_fast memcpy_amd_ -# define memcpy_aligned memcpy_amd_ - -#else - - // for now linux uses the GCC memcpy/memset implementations. - #define memcpy_fast memcpy - #define memcpy_raz_ memcpy - #define memcpy_raz_u memcpy - - #define memcpy_aligned memcpy - #define memcpy_raz_u memcpy - - #include "Linux/memzero.h" - -#endif - - -u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize); -void memxor_mmx(void* dst, const void* src1, int cmpsize); - #ifdef _MSC_VER #pragma pack() #endif diff --git a/pcsx2/Paths.h b/pcsx2/Paths.h index b98cde45de..99580cf417 100644 --- a/pcsx2/Paths.h +++ b/pcsx2/Paths.h @@ -13,7 +13,21 @@ #define LANGS_DIR "Langs" #define LOGS_DIR "logs" - #define DEFAULT_MEMCARD1 "Mcd001.ps2" #define DEFAULT_MEMCARD2 "Mcd002.ps2" + +#define g_MaxPath 255 // 255 is safer with antiquated Win32 ASCII APIs. + +namespace Path +{ + void Combine( string& dest, const string& srcPath, const string& srcFile ); + bool isRooted( const string& path ); + bool isDirectory( const string& path ); + bool isFile( const string& path ); + bool Exists( const string& path ); + int getFileSize( const string& path ); + + void ReplaceExtension( string& dest, const string& src, const string& ext ); +} + #endif diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index f36f7472d3..2d8549139b 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -125,8 +125,6 @@ void cpuShutdown() // biosShutdown(); psxShutdown(); disR5900FreeSyms(); - - //Cpu->Shutdown(); } void cpuException(u32 code, u32 bd) @@ -630,6 +628,10 @@ void cpuTestHwInts() { cpuTestTIMRInts(); } +// This function performs a "hackish" execution of the BIOS stub, which initializes EE +// memory and hardware. It forcefully breaks execution when the stub is finished, prior +// to the PS2 logos being displayed. This allows us to "shortcut" right into a game +// without having to wait through the logos or endure game/bios localization checks. void cpuExecuteBios() { // Set the video mode to user's default request: @@ -660,7 +662,11 @@ void cpuExecuteBios() // REC_CLEARM(0x00200008); // REC_CLEARM(0x00100008); // REC_CLEARM(cpuRegs.pc); - //if( CHECK_EEREC ) Cpu->Reset(); + + // Reset the EErecs here, because the bios generates "slow" blocks that have hacky + // bBiosEnd checks in them and stuff. This deletes them so that the recs replace them + // with new faster versions: + Cpu->Reset(); Console::Notice("* PCSX2 *: ExecuteBios Complete"); //GSprintf(5, "PCSX2 " PCSX2_VERSION "\nExecuteBios Complete\n"); diff --git a/pcsx2/SafeArray.h b/pcsx2/SafeArray.h new file mode 100644 index 0000000000..1346350bf2 --- /dev/null +++ b/pcsx2/SafeArray.h @@ -0,0 +1,244 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2008 Pcsx2 Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __SAFEARRAY_H__ +#define __SAFEARRAY_H__ + +#include "MemcpyFast.h" + +////////////////////////////////////////////////////////////// +// Safe deallocation macros -- always check pointer validity (non-null) +// and set pointer to null on deallocation. + +#define safe_delete( ptr ) \ + if( ptr != NULL ) { \ + delete ptr; \ + ptr = NULL; \ + } + +#define safe_delete_array( ptr ) \ + if( ptr != NULL ) { \ + delete[] ptr; \ + ptr = NULL; \ + } + +#define safe_free( ptr ) \ + if( ptr != NULL ) { \ + free( ptr ); \ + ptr = NULL; \ + } + +#define safe_aligned_free( ptr ) \ + if( ptr != NULL ) { \ + _aligned_free( ptr ); \ + ptr = NULL; \ + } + +#define SafeSysMunmap( ptr, size ) \ + if( ptr != NULL ) { \ + SysMunmap( (uptr)ptr, size ); \ + ptr = NULL; \ + } + + +////////////////////////////////////////////////////////////////// +// Handy little class for allocating a resizable memory block, complete with +// exception-based error handling and automatic cleanup. + +template< typename T > +class MemoryAlloc : public NoncopyableObject +{ +public: + static const int DefaultChunkSize = 0x1000 * sizeof(T); + +public: + const std::string Name; // user-assigned block name + int ChunkSize; + +protected: + T* m_ptr; + int m_size; // size of the allocation of memory + + const static std::string m_str_Unnamed; +protected: + // Internal contructor for use by derrived classes. This allws a derrived class to + // use its own memory allocation (with an aligned memory, for example). + // Throws: + // Exception::OutOfMemory if the allocated_mem pointr is NULL. + explicit MemoryAlloc( const std::string& name, T* allocated_mem, int initSize ) : + Name( name ) + , ChunkSize( DefaultChunkSize ) + , m_ptr( allocated_mem ) + , m_size( initSize ) + { + if( m_ptr == NULL ) + throw Exception::OutOfMemory(); + } + + virtual T* _virtual_realloc( int newsize ) + { + return (T*)realloc( m_ptr, newsize * sizeof(T) ); + } + +public: + virtual ~MemoryAlloc() + { + safe_free( m_ptr ); + } + + explicit MemoryAlloc( const std::string& name="Unnamed" ) : + Name( name ) + , ChunkSize( DefaultChunkSize ) + , m_ptr( NULL ) + , m_size( 0 ) + { + } + + explicit MemoryAlloc( int initialSize, const std::string& name="Unnamed" ) : + Name( name ) + , ChunkSize( DefaultChunkSize ) + , m_ptr( (T*)malloc( initialSize * sizeof(T) ) ) + , m_size( initialSize ) + { + if( m_ptr == NULL ) + throw Exception::OutOfMemory(); + } + + // Returns the size of the memory allocation, as according to the array type. + int GetLength() const { return m_size; } + // Returns the size of the memory allocation in bytes. + int GetSizeInBytes() const { return m_size * sizeof(T); } + + // Ensures that the allocation is large enough to fit data of the + // amount requested. The memory allocation is not resized smaller. + void MakeRoomFor( int blockSize ) + { + std::string temp; + + if( blockSize > m_size ) + { + const uint newalloc = blockSize + ChunkSize; + m_ptr = _virtual_realloc( newalloc ); + if( m_ptr == NULL ) + { + throw Exception::OutOfMemory( + "Out-of-memory on block re-allocation. " + "Old size: " + to_string( m_size ) + " bytes, " + "New size: " + to_string( newalloc ) + " bytes" + ); + } + m_size = newalloc; + } + } + + // Gets a pointer to the requested allocation index. + // DevBuilds : Throws std::out_of_range() if the index is invalid. + T *GetPtr( uint idx=0 ) { return _getPtr( idx ); } + const T *GetPtr( uint idx=0 ) const { return _getPtr( idx ); } + + // Gets an element of this memory allocation much as if it were an array. + // DevBuilds : Throws std::out_of_range() if the index is invalid. + T& operator[]( int idx ) { return *_getPtr( (uint)idx ); } + const T& operator[]( int idx ) const { return *_getPtr( (uint)idx ); } + + virtual MemoryAlloc* Clone() const + { + MemoryAlloc* retval = new MemoryAlloc( m_size ); + memcpy_fast( retval->GetPtr(), m_ptr, sizeof(T) * m_size ); + return retval; + } + +protected: + // A safe array index fetcher. Throws an exception if the array index + // is outside the bounds of the array. + // Performance Considerations: This function adds quite a bit of overhead + // to array indexing and thus should be done infrequently if used in + // time-critical situations. Indead of using it from inside loops, cache + // the pointer into a local variable and use stad (unsafe) C indexes. + T* _getPtr( uint i ) const + { +#ifdef PCSX2_DEVBUILD + if( i >= (uint)m_size ) + { + throw Exception::IndexBoundsFault( + "Index out of bounds on MemoryAlloc: " + Name + + " (index=" + to_string(i) + + ", size=" + to_string(m_size) + ")" + ); + } +#endif + return &m_ptr[i]; + } + +}; + +////////////////////////////////////////////////////////////////// +// Handy little class for allocating a resizable memory block, complete with +// exception-based error handling and automatic cleanup. +// This one supports aligned data allocations too! + +template< typename T, uint Alignment > +class SafeAlignedArray : public MemoryAlloc +{ +protected: + T* _virtual_realloc( int newsize ) + { + // TODO : aligned_realloc will need a linux implementation now. -_- + return (T*)_aligned_realloc( m_ptr, newsize * sizeof(T), Alignment ); + } + + // Appends "(align: xx)" to the name of the allocation in devel builds. + // Maybe useful,maybe not... no harm in atatching it. :D + string _getName( const string& src ) + { +#ifdef PCSX2_DEVBUILD + return src + "(align:" + to_string(Alignment) + ")"; +#endif + return src; + } + +public: + virtual ~SafeAlignedArray() + { + safe_aligned_free( m_ptr ); + // mptr is set to null, so the parent class's destructor won't re-free it. + } + + explicit SafeAlignedArray( const std::string& name="Unnamed" ) : + MemoryAlloc( name ) + { + } + + explicit SafeAlignedArray( int initialSize, const std::string& name="Unnamed" ) : + MemoryAlloc( + _getName(name), + (T*)_aligned_malloc( initialSize * sizeof(T), Alignment ), + initialSize + ) + { + } + + virtual SafeAlignedArray* Clone() const + { + SafeAlignedArray* retval = new SafeAlignedArray( m_size ); + memcpy_fast( retval->GetPtr(), m_ptr, sizeof(T) * m_size ); + return retval; + } +}; + +#endif diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 83c7f644ae..3e0431aba8 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -20,9 +20,10 @@ #include "Common.h" #include "PsxCommon.h" +#include "SaveState.h" + #include "CDVDisodrv.h" #include "VUmicro.h" - #include "VU.h" #include "iCore.h" #include "iVUzerorec.h" @@ -31,7 +32,6 @@ #include "COP0.h" #include "Cache.h" -#include "Paths.h" using namespace R5900; @@ -43,8 +43,8 @@ extern void recResetIOP(); static void PreLoadPrep() { - recResetEE(); - recResetIOP(); + SysResetExecutionState(); + #ifdef PCSX2_VIRTUAL_MEM DWORD OldProtect; // make sure can write diff --git a/pcsx2/System.h b/pcsx2/System.h index 538b34dd92..c98ac20922 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -22,6 +22,8 @@ #include "PS2Etypes.h" #include "Exceptions.h" #include "Paths.h" +#include "MemcpyFast.h" +#include "SafeArray.h" void SysDetect(); // Detects cpu type and fills cpuInfo structs. bool SysInit(); // Init logfiles, directories, critical memory resources, and other OS-specific one-time @@ -37,11 +39,11 @@ void SysResetExecutionState(); void *SysLoadLibrary(const char *lib); // Loads Library void *SysLoadSym(void *lib, const char *sym); // Loads Symbol from Library -const char *SysLibError(); // Gets previous error loading sysbols +const char *SysLibError(); // Gets previous error loading symbols void SysCloseLibrary(void *lib); // Closes Library // Maps a block of memory for use as a recompiled code buffer. -// The allocated block has code execution privliges. +// The allocated block has code execution privileges. // Returns NULL on allocation failure. void *SysMmap(uptr base, u32 size); @@ -99,7 +101,7 @@ namespace Console extern void ClearColor(); // The following Write functions return bool so that we can use macros to exclude - // them from different buildypes. The return values are always zero. + // them from different build types. The return values are always zero. // Writes a newline to the console. extern bool __fastcall Newline(); @@ -171,44 +173,10 @@ using Console::Color_Cyan; using Console::Color_Yellow; using Console::Color_White; -////////////////////////////////////////////////////////////// -// Safe deallocation macros -- always check pointer validity (non-null) -// and set pointer to null on deallocation. - -#define safe_delete( ptr ) \ - if( ptr != NULL ) { \ - delete ptr; \ - ptr = NULL; \ - } - -#define safe_delete_array( ptr ) \ - if( ptr != NULL ) { \ - delete[] ptr; \ - ptr = NULL; \ - } - -#define safe_free( ptr ) \ - if( ptr != NULL ) { \ - free( ptr ); \ - ptr = NULL; \ - } - -#define safe_aligned_free( ptr ) \ - if( ptr != NULL ) { \ - _aligned_free( ptr ); \ - ptr = NULL; \ - } - -#define SafeSysMunmap( ptr, size ) \ - if( ptr != NULL ) { \ - SysMunmap( (uptr)ptr, size ); \ - ptr = NULL; \ - } - ////////////////////////////////////////////////////////////// // Dev / Debug conditionals -- // Consts for using if() statements instead of uglier #ifdef macros. -// Abbrivated macros for dev/debug only consoles and mesgboxes. +// Abbreviated macros for dev/debug only consoles and msgboxes. #ifdef PCSX2_DEVBUILD @@ -264,177 +232,5 @@ int SysMapUserPhysicalPages(void* Addr, uptr NumPages, uptr* pblock, int pageoff #endif -////////////////////////////////////////////////////////////////// -// Handy little class for allocating a resizable memory block, complete with -// exception-based error handling and automatic cleanup. - -template< typename T > -class MemoryAlloc : public NoncopyableObject -{ -public: - static const int DefaultChunkSize = 0x1000 * sizeof(T); - -public: - const std::string Name; // user-assigned block name - int ChunkSize; - -protected: - T* m_ptr; - int m_size; // size of the allocation of memory - - const static std::string m_str_Unnamed; -protected: - // Internal contructor for use by derrived classes. This allws a derrived class to - // use its own memory allocation (with an aligned memory, for example). - // Throws: - // Exception::OutOfMemory if the allocated_mem pointr is NULL. - explicit MemoryAlloc( const std::string& name, T* allocated_mem, int initSize ) : - Name( name ) - , ChunkSize( DefaultChunkSize ) - , m_ptr( allocated_mem ) - , m_size( initSize ) - { - if( m_ptr == NULL ) - throw Exception::OutOfMemory(); - } - - virtual T* _virtual_realloc( int newsize ) - { - return (T*)realloc( m_ptr, newsize * sizeof(T) ); - } - -public: - virtual ~MemoryAlloc() - { - safe_free( m_ptr ); - } - - explicit MemoryAlloc( const std::string& name="Unnamed" ) : - Name( name ) - , ChunkSize( DefaultChunkSize ) - , m_ptr( NULL ) - , m_size( 0 ) - { - } - - explicit MemoryAlloc( int initialSize, const std::string& name="Unnamed" ) : - Name( name ) - , ChunkSize( DefaultChunkSize ) - , m_ptr( (T*)malloc( initialSize * sizeof(T) ) ) - , m_size( initialSize ) - { - if( m_ptr == NULL ) - throw Exception::OutOfMemory(); - } - - // Returns the size of the memory allocation, as according to the array type. - int GetLength() const { return m_size; } - // Returns the size of the memory allocation in bytes. - int GetSizeInBytes() const { return m_size * sizeof(T); } - - // Ensures that the allocation is large enough to fit data of the - // amount requested. The memory allocation is not resized smaller. - void MakeRoomFor( int blockSize ) - { - std::string temp; - - if( blockSize > m_size ) - { - const uint newalloc = blockSize + ChunkSize; - m_ptr = _virtual_realloc( newalloc ); - if( m_ptr == NULL ) - { - throw Exception::OutOfMemory( - "Out-of-memory on block re-allocation. " - "Old size: " + to_string( m_size ) + " bytes, " - "New size: " + to_string( newalloc ) + " bytes" - ); - } - m_size = newalloc; - } - } - - // Gets a pointer to the requested allocation index. - // DevBuilds : Throws std::out_of_range() if the index is invalid. - T *GetPtr( uint idx=0 ) { return _getPtr( idx ); } - const T *GetPtr( uint idx=0 ) const { return _getPtr( idx ); } - - // Gets an element of this memory allocation much as if it were an array. - // DevBuilds : Throws std::out_of_range() if the index is invalid. - T& operator[]( int idx ) { return *_getPtr( (uint)idx ); } - const T& operator[]( int idx ) const { return *_getPtr( (uint)idx ); } - - virtual MemoryAlloc& Clone() const - { - MemoryAlloc* retval = new MemoryAlloc( m_size ); - memcpy( retval->GetPtr(), m_ptr, sizeof(T) * m_size ); - return *retval; - } - -protected: - // A safe array index fetcher. Throws an exception if the array index - // is outside the bounds of the array. - // Performance Considerations: This function adds quite a bit of overhead - // to array indexing and thus should be done infrequently if used in - // time-critical situations. Indead of using it from inside loops, cache - // the pointer into a local variable and use stad (unsafe) C indexes. - T* _getPtr( uint i ) const - { -#ifdef PCSX2_DEVBUILD - if( i >= (uint)m_size ) - { - throw Exception::IndexBoundsFault( - "Index out of bounds on MemoryAlloc: " + Name + - " (index=" + to_string(i) + - ", size=" + to_string(m_size) + ")" - ); - } -#endif - return &m_ptr[i]; - } - -}; - -template< typename T, uint Alignment > -class SafeAlignedArray : public MemoryAlloc -{ -protected: - T* _virtual_realloc( int newsize ) - { - // TODO : aligned_realloc will need a linux implementation now. -_- - return (T*)_aligned_realloc( m_ptr, newsize * sizeof(T), Alignment ); - } - - // Appends "(align: xx)" to the name of the allocation in devel builds. - // Maybe useful,maybe not... no harm in atatching it. :D - string _getName( const string& src ) - { -#ifdef PCSX2_DEVBUILD - return src + "(align:" + to_string(Alignment) + ")"; -#endif - return src; - } - -public: - virtual ~SafeAlignedArray() - { - safe_aligned_free( m_ptr ); - // mptr is set to null, so the parent class's destructor won't re-free it. - } - - explicit SafeAlignedArray( const std::string& name="Unnamed" ) : - MemoryAlloc( name ) - { - } - - explicit SafeAlignedArray( int initialSize, const std::string& name="Unnamed" ) : - MemoryAlloc( - _getName(name), - (T*)_aligned_malloc( initialSize * sizeof(T), Alignment ), - initialSize - ) - { - } -}; #endif /* __SYSTEM_H__ */ diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 7dc26ce769..44e3e939b0 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -719,22 +719,6 @@ - - - - - - - @@ -751,10 +735,6 @@ RelativePath="..\..\Patch.h" > - - @@ -812,14 +792,6 @@ RelativePath="..\..\PrecompiledHeader.h" > - - - - @@ -1120,202 +1092,6 @@ > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2969,6 +2745,30 @@ RelativePath="..\..\Exceptions.h" > + + + + + + + + + + + @@ -2977,6 +2777,10 @@ RelativePath="..\..\Plugins.h" > + + @@ -2985,6 +2789,14 @@ RelativePath="..\..\SamplProf.h" > + + + + @@ -3005,6 +2817,202 @@ RelativePath="..\WinThreads.cpp" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +