From c415d8d694d8d1ccd3b8456656f2ff4a35fa41e0 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Sat, 15 Aug 2009 06:17:43 +0000 Subject: [PATCH] wxgui: * Major cleanups and improvements to the Threading namespace. * Created CoreEmuThread class framework, which currently runs the EEcore, IOP, and VUs with threadsafe suspension, reset, and resume features. git-svn-id: http://pcsx2.googlecode.com/svn/branches/wxgui@1624 96395faa-99c1-11dd-bbfe-3dabce05a288 --- 3rdparty/w32pthreads/include/pthread.h | 13 +- 3rdparty/w32pthreads/pthreads_2008.vcproj | 2947 ++++++++++++++++++- common/include/Utilities/Exceptions.h | 13 +- common/include/Utilities/Threading.h | 143 +- common/src/Utilities/Exceptions.cpp | 2 +- common/src/Utilities/Linux/LnxThreads.cpp | 11 - common/src/Utilities/ThreadTools.cpp | 96 +- common/src/Utilities/Windows/WinThreads.cpp | 15 - pcsx2/CDVD/CDVD.cpp | 2 +- pcsx2/Config.h | 220 +- pcsx2/Elfheader.cpp | 45 +- pcsx2/Elfheader.h | 6 +- pcsx2/GS.h | 6 +- pcsx2/MTGS.cpp | 10 +- pcsx2/Memory.cpp | 11 +- pcsx2/Misc.cpp | 8 +- pcsx2/Pcsx2Config.cpp | 2 +- pcsx2/Plugins.cpp | 9 +- pcsx2/Plugins.h | 2 +- pcsx2/R5900.cpp | 24 +- pcsx2/R5900.h | 2 +- pcsx2/RecoverySystem.cpp | 2 +- pcsx2/Saveslots.cpp | 2 +- pcsx2/System.cpp | 50 +- pcsx2/System.h | 6 +- pcsx2/gui/App.h | 5 +- pcsx2/gui/ConsoleLogger.cpp | 63 +- pcsx2/gui/HostGui.cpp | 4 +- pcsx2/gui/MainFrame.cpp | 17 +- pcsx2/gui/MainFrame.h | 13 +- pcsx2/gui/MainMenuClicks.cpp | 54 +- pcsx2/gui/Panels/ConfigurationPanels.h | 6 +- pcsx2/gui/Panels/PluginSelectorPanel.cpp | 10 +- pcsx2/gui/main.cpp | 11 +- pcsx2/ps2/CoreEmuThread.cpp | 212 ++ pcsx2/ps2/CoreEmuThread.h | 86 + pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 68 +- pcsx2/x86/ix86-32/iR5900-32.cpp | 2 +- 38 files changed, 3827 insertions(+), 371 deletions(-) create mode 100644 pcsx2/ps2/CoreEmuThread.cpp create mode 100644 pcsx2/ps2/CoreEmuThread.h diff --git a/3rdparty/w32pthreads/include/pthread.h b/3rdparty/w32pthreads/include/pthread.h index 12b4a169b5..dfa5c44bda 100644 --- a/3rdparty/w32pthreads/include/pthread.h +++ b/3rdparty/w32pthreads/include/pthread.h @@ -570,19 +570,14 @@ typedef struct _ptw32_handle_t { #ifdef __cplusplus // Added support for various operators so that the struct is // more pthreads-compliant in behavior. (air) - const bool operator ==( const void* rightside ) + const bool operator ==( const struct _ptw32_handle_t rightside ) const { - return p == rightside; + return p == rightside.p; } - const bool operator !=( const void* rightside ) + const bool operator !=( const struct _ptw32_handle_t rightside ) const { - return p != rightside; - } - - bool operator =( void* rightside ) - { - p = rightside; + return p != rightside.p; } #endif diff --git a/3rdparty/w32pthreads/pthreads_2008.vcproj b/3rdparty/w32pthreads/pthreads_2008.vcproj index b18a1e9b32..2183445150 100644 --- a/3rdparty/w32pthreads/pthreads_2008.vcproj +++ b/3rdparty/w32pthreads/pthreads_2008.vcproj @@ -44,7 +44,6 @@ ExceptionHandling="2" UsePrecompiledHeader="0" WarningLevel="3" - CompileAs="1" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DaZ, FtZ, "chop" +#define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop" + ///////////////////////////////////////////////////////////////////////////////////////// // Pcsx2Config // @@ -50,28 +58,56 @@ class Pcsx2Config public: struct ProfilerOptions { - bool - Enabled:1, // universal toggle for the profiler. - RecBlocks_EE:1, // Enables per-block profiling for the EE recompiler [unimplemented] - RecBlocks_IOP:1, // Enables per-block profiling for the IOP recompiler [unimplemented] - RecBlocks_VU0:1, // Enables per-block profiling for the VU0 recompiler [unimplemented] - RecBlocks_VU1:1; // Enables per-block profiling for the VU1 recompiler [unimplemented] + union + { + struct + { + bool + Enabled:1, // universal toggle for the profiler. + RecBlocks_EE:1, // Enables per-block profiling for the EE recompiler [unimplemented] + RecBlocks_IOP:1, // Enables per-block profiling for the IOP recompiler [unimplemented] + RecBlocks_VU0:1, // Enables per-block profiling for the VU0 recompiler [unimplemented] + RecBlocks_VU1:1; // Enables per-block profiling for the VU1 recompiler [unimplemented] + }; + u8 bits; + }; + + ProfilerOptions() : bits( 0 ) {} void LoadSave( IniInterface& conf ); + + bool operator ==( const ProfilerOptions& right ) const + { + return OpEqu( bits ); + } + + bool operator !=( const ProfilerOptions& right ) const + { + return !this->operator ==( right ); + } }; // ------------------------------------------------------------------------ struct RecompilerOptions { - bool - EnableEE:1, - EnableIOP:1, - EnableVU0:1, - EnableVU1:1; - - bool - UseMicroVU0:1, - UseMicroVU1:1; + union + { + struct + { + bool + EnableEE:1, + EnableIOP:1, + EnableVU0:1, + EnableVU1:1; + + bool + UseMicroVU0:1, + UseMicroVU1:1; + }; + u8 bits; + }; + + RecompilerOptions() : bits( 0 ) { } void Load( const wxString& srcfile ); void Load( const wxInputStream& srcstream ); @@ -80,29 +116,64 @@ public: void LoadSave( IniInterface& conf ); + bool operator ==( const RecompilerOptions& right ) const + { + return OpEqu( bits ); + } + + bool operator !=( const RecompilerOptions& right ) const + { + return !this->operator ==( right ); + } + } Recompiler; // ------------------------------------------------------------------------ struct CpuOptions { + RecompilerOptions Recompiler; + u32 sseMXCSR; u32 sseVUMXCSR; - bool - vuOverflow:1, - vuExtraOverflow:1, - vuSignOverflow:1, - vuUnderflow:1; - - bool - fpuOverflow:1, - fpuExtraOverflow:1, - fpuFullMode:1; + struct + { + union + { + bool + vuOverflow:1, + vuExtraOverflow:1, + vuSignOverflow:1, + vuUnderflow:1; + + bool + fpuOverflow:1, + fpuExtraOverflow:1, + fpuFullMode:1; + }; + u8 bits; + }; - ProfilerOptions Profiler; - RecompilerOptions Recompiler; + CpuOptions() : + sseMXCSR( DEFAULT_sseMXCSR ) + , sseVUMXCSR( DEFAULT_sseVUMXCSR ) + , bits( 0 ) + { + } void LoadSave( IniInterface& conf ); + + bool operator ==( const CpuOptions& right ) const + { + return + OpEqu( sseMXCSR ) && OpEqu( sseVUMXCSR ) && + OpEqu( bits ) && OpEqu( Recompiler ); + } + + bool operator !=( const CpuOptions& right ) const + { + return !this->operator ==( right ); + } }; // ------------------------------------------------------------------------ @@ -128,36 +199,77 @@ public: // ------------------------------------------------------------------------ struct GamefixOptions { - bool - VuAddSubHack:1, // Fix for Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate. - VuClipFlagHack:1, // Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu. - FpuCompareHack:1, // Fix for Persona games, maybe others. It's to do with the VU clip flag (again). - FpuMulHack:1, // Fix for Tales of Destiny hangs. - XgKickHack:1; // Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others. + union + { + struct + { + bool + VuAddSubHack:1, // Fix for Tri-ace games, they use an encryption algorithm that requires VU ADDI opcode to be bit-accurate. + VuClipFlagHack:1, // Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu. + FpuCompareHack:1, // Fix for Persona games, maybe others. It's to do with the VU clip flag (again). + FpuMulHack:1, // Fix for Tales of Destiny hangs. + XgKickHack:1; // Fix for Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others. + }; + u8 bits; + }; + + GamefixOptions() : bits( 0 ) {} void LoadSave( IniInterface& conf ); + + bool operator ==( const GamefixOptions& right ) const + { + return OpEqu( bits ); + } + + bool operator !=( const GamefixOptions& right ) const + { + return !this->operator ==( right ); + } }; // ------------------------------------------------------------------------ struct SpeedhackOptions { - int - EECycleRate:2, // EE cyclerate selector (1.0, 1.5, 2.0) - VUCycleSteal:3, // VU Cycle Stealer factor (0, 1, 2, or 3) - IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate - IntcStat:1, // tells Pcsx2 to fast-forward through intc_stat waits. - BIFC0:1, // enables BIFC0 detection and fast-forwarding - - vuMinMax:1, // microVU specific MinMax hack; Can cause SPS, Black Screens, etc... - vuFlagHack:1; // MicroVU specific flag hack; Can cause Infinite loops, SPS, etc... + union + { + struct + { + int + EECycleRate:2, // EE cyclerate selector (1.0, 1.5, 2.0) + VUCycleSteal:3, // VU Cycle Stealer factor (0, 1, 2, or 3) + IopCycleRate_X2:1, // enables the x2 multiplier of the IOP cyclerate + IntcStat:1, // tells Pcsx2 to fast-forward through intc_stat waits. + BIFC0:1, // enables BIFC0 detection and fast-forwarding + + vuMinMax:1, // microVU specific MinMax hack; Can cause SPS, Black Screens, etc... + vuFlagHack:1; // MicroVU specific flag hack; Can cause Infinite loops, SPS, etc... + }; + u16 bits; + }; + + SpeedhackOptions() : bits( 0 ) {} void LoadSave( IniInterface& conf ); + + bool operator ==( const SpeedhackOptions& right ) const + { + return OpEqu( bits ); + } + + bool operator !=( const SpeedhackOptions& right ) const + { + return !this->operator ==( right ); + } }; public: bool CdvdVerboseReads:1; // enables cdvd read activity verbosely dumped to the console - bool CdvdDumpBlocks:1; - bool EnablePatches:1; + bool CdvdDumpBlocks:1; // enables cdvd block dumping + bool EnablePatches:1; // enables patch detection and application + + // when enabled performs bios stub execution, skipping full sony bios + splash screens + bool SkipBiosSplash:1; // Closes the GS/Video port on escape (good for fullscreen activity) bool closeGSonEsc:1; @@ -169,6 +281,7 @@ public: VideoOptions Video; SpeedhackOptions Speedhacks; GamefixOptions Gamefixes; + ProfilerOptions Profiler; void Load( const wxString& srcfile ); void Load( const wxInputStream& srcstream ); @@ -178,21 +291,6 @@ public: void LoadSave( IniInterface& ini ); }; -// Pauses the emulation state at the next PS2 vsync, and returns control to the calling -// thread; or does nothing if the core is already suspended. Calling this thread from the -// Core thread will result in deadlock. -extern void Core_Suspend(); - -// Applies a full suite of new settings, which will automatically facilitate the necessary -// resets of the core and components (including plugins, if needed). The scope of resetting -// is determined by comparing the current settings against the new settings. -extern void Core_ApplySettings( const Pcsx2Config& src ); - -// Resumes the core execution state, or does nothing is the core is already running. If -// settings were changed, resets will be performed as needed and emulation state resumed from -// memory savestates. -extern void Core_Resume(); - ////////////////////////////////////////////////////////////////////////// // Session Configuration Override Flags // @@ -244,10 +342,6 @@ extern SessionOverrideFlags g_Session; #define CHECK_FPU_EXTRA_FLAGS 1 // Always enabled now // Sets D/I flags on FPU instructions #define CHECK_FPU_FULL (EmuConfig.Cpu.fpuFullMode) -//------------ DEFAULT sseMXCSR VALUES!!! --------------- -#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop" -#define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop" - //------------ EE Recompiler defines - Comment to disable a recompiler --------------- #define SHIFT_RECOMPILE // Speed majorly reduced if disabled diff --git a/pcsx2/Elfheader.cpp b/pcsx2/Elfheader.cpp index 6da1d2d825..be490eb953 100644 --- a/pcsx2/Elfheader.cpp +++ b/pcsx2/Elfheader.cpp @@ -505,28 +505,27 @@ u32 loadElfCRC( const char* filename ) return crcval; } -int loadElfFile(const wxString& filename) +// Loads the elf binary data from the specified file into PS2 memory, and injects the ELF's +// starting execution point into cpuRegs.pc. If the filename is a cdrom URI in the form +// of "cdrom0:" or "cdrom1:" then the CDVD is used as the source; otherwise the ELF is loaded +// from the host filesystem. +// +// If the specified filename is empty then no action is taken (PS2 will continue booting +// normally as if it has no CD +// +// Throws exception on error: +// +void loadElfFile(const wxString& filename) { - // Reset all recompilers prior to initiating a BIOS or new ELF. The cleaner the - // slate, the happier the recompiler! - - SysClearExecutionCache(); - - if( filename.IsEmpty() ) - { - 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(); - + if( filename.IsEmpty() ) return; + int elfsize; Console::Status( wxsFormat( L"loadElfFile: %s", filename.c_str() ) ); const wxCharBuffer buffer( filename.ToAscii() ); const char* fnptr = buffer.data(); - + bool useCdvdSource=false; + if( !filename.StartsWith( L"cdrom0:" ) && !filename.StartsWith( L"cdrom1:" ) ) { // Loading from a file (or non-cd image) @@ -536,23 +535,25 @@ int loadElfFile(const wxString& filename) else { // Loading from a CD rom or CD image. + useCdvdSource = true; TocEntry toc; IsoFS_init( ); if ( IsoFS_findFile( fnptr + strlen( "cdromN:" ), &toc ) == -1 ) - return -1; + throw Exception::FileNotFound( filename, wxLt("ELF file was not found on the CDVD source media.") ); elfsize = toc.fileSize; } Console::Status( wxsFormat(L"loadElfFile: %d", elfsize) ); - if( elfsize == 0 ) return -1; + if( elfsize == 0 ) + throw Exception::BadStream( filename, wxLt("Unexpected end of ELF file: ") ); ElfObject elfobj( filename, elfsize ); if( elfobj.proghead == NULL ) { - throw Exception::CpuStateShutdown( - wxsFormat( L"Invalid ELF header encountered in file:\n\t%s", elfobj.filename.c_str() ), - wxsFormat( L"Invalid ELF header, file: %s", elfobj.filename.c_str() ) + throw Exception::BadStream( filename, useCdvdSource ? + wxLt("Invalid ELF file header. The CD-Rom may be damaged, or the ISO image corrupted.") : + wxLt("Invalid ELF file.") ); } @@ -583,6 +584,6 @@ int loadElfFile(const wxString& filename) ElfApplyPatches(); - return 0; + return; } diff --git a/pcsx2/Elfheader.h b/pcsx2/Elfheader.h index 6a7a3b94b0..8900a0d8ae 100644 --- a/pcsx2/Elfheader.h +++ b/pcsx2/Elfheader.h @@ -24,9 +24,9 @@ extern char args[256]; //to be filled by GUI extern unsigned int args_ptr; //------------------- -int loadElfFile(const wxString& filename); -u32 loadElfCRC(const char *filename); -void ElfApplyPatches(); +extern void loadElfFile(const wxString& filename); +extern u32 loadElfCRC(const char *filename); +extern void ElfApplyPatches(); extern u32 ElfCRC; diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 4914ce00ca..a02a9a7263 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -154,7 +154,7 @@ enum GS_RINGTYPE , GS_RINGTYPE_QUIT }; -class mtgsThreadObject : public Threading::Thread +class mtgsThreadObject : public Threading::PersistentThread { friend class SaveState; @@ -225,7 +225,7 @@ public: virtual ~mtgsThreadObject(); void Start(); - void Close(); + void Cancel(); void Reset(); void GIFSoftReset( int mask ); @@ -276,7 +276,7 @@ protected: uint _PrepForSimplePacket(); void _FinishSimplePacket( uint future_writepos ); - int Callback(); + sptr ExecuteTask(); }; extern mtgsThreadObject* mtgsThread; diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 56f6dc293f..5ed9716121 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -177,7 +177,7 @@ typedef void (*GIFRegHandler)(const u32* data); static GIFRegHandler s_GSHandlers[3] = { RegHandlerSIGNAL, RegHandlerFINISH, RegHandlerLABEL }; mtgsThreadObject::mtgsThreadObject() : - Thread() + PersistentThread() , m_RingPos( 0 ) , m_WritePos( 0 ) @@ -204,7 +204,7 @@ mtgsThreadObject::mtgsThreadObject() : void mtgsThreadObject::Start() { - Thread::Start(); + PersistentThread::Start(); // Wait for the thread to finish initialization (it runs GSopen, which can take // some time since it's creating a new window and all), and then check for errors. @@ -217,10 +217,10 @@ void mtgsThreadObject::Start() mtgsThreadObject::~mtgsThreadObject() { - Close(); + Cancel(); } -void mtgsThreadObject::Close() +void mtgsThreadObject::Cancel() { Console::WriteLn( "MTGS > Closing GS thread..." ); SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 ); @@ -499,7 +499,7 @@ struct PacketTagType #ifndef __LINUX__ extern bool renderswitch; #endif -int mtgsThreadObject::Callback() +sptr mtgsThreadObject::ExecuteTask() { Console::WriteLn("MTGS > Thread Started, Opening GS Plugin..."); diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index 99d7bc76d5..081c93261f 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -805,7 +805,7 @@ void memReset() wxString Bios( g_Conf->FullpathToBios() ); long filesize = Path::GetFileSize( Bios ); - if( filesize <= 0 ) + if( filesize > 0 ) { wxFile fp( Bios.c_str() ); fp.Read( PS2MEM_ROM, min( (long)Ps2MemSize::Rom, filesize ) ); @@ -813,7 +813,14 @@ void memReset() else { // Translated: Bios file not found or not specified ... A bios is required for Pcsx2 to run! - throw Exception::FileNotFound( Bios, wxLt("Bios not found") ); + throw Exception::FileNotFound( Bios, + L"Configured Bios file does not exist", + pxE( ".Error:BiosNotFound", + L"The configured BIOS file does not exist, or no BIOS has been configured.\n\n" + L"PCSX2 requires a PS2 BIOS to run; and the BIOS *must* be obtained from an actual PS2 unit\n" + L"that you own (borrowing doesn't count). Please consult the FAQs and Guides for further instructions." + ) + ); } BiosVersion = GetBiosVersion(); diff --git a/pcsx2/Misc.cpp b/pcsx2/Misc.cpp index 8e33b5d5f2..c6c0dc1e20 100644 --- a/pcsx2/Misc.cpp +++ b/pcsx2/Misc.cpp @@ -237,6 +237,10 @@ bool IsBIOS(const wxString& filename, wxString& description) return false; //fail quietly } +// return value: +// 0 - Invalid or unknown disc. +// 1 - PS1 CD +// 2 - PS2 CD int GetPS2ElfName( wxString& name ) { int f; @@ -262,7 +266,7 @@ int GetPS2ElfName( wxString& name ) if (pos==NULL){ pos=strstr(buffer, "BOOT"); if (pos==NULL) { - Console::Error("Boot Error > This is not a PS2 game!"); + Console::Error("Boot failed: This is not a Playstation or PS2 game!"); return 0; } return 1; @@ -453,7 +457,7 @@ void ProcessFKeys(int fkey, struct KeyModifiers *keymod) wxsFormat( L"Error! Could not load from saveslot %d\n", StatesC ) + ex.LogMessage(), // translated message: - wxsFormat( L"Error loading saveslot %d. Emulator reset.", StatesC ) + wxsFormat( _("Error loading saveslot %d. Emulator reset."), StatesC ) ); } break; diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index e0ad336429..d0768a0345 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -76,7 +76,6 @@ void Pcsx2Config::CpuOptions::LoadSave( IniInterface& ini ) IniBitBool( fpuFullMode, false ); Recompiler.LoadSave( ini ); - Profiler.LoadSave( ini ); ini.SetPath( L".." ); } @@ -112,6 +111,7 @@ void Pcsx2Config::LoadSave( IniInterface& ini ) Cpu.LoadSave( ini ); Video.LoadSave( ini ); Gamefixes.LoadSave( ini ); + Profiler.LoadSave( ini ); ini.SetPath( L".." ); ini.Flush(); diff --git a/pcsx2/Plugins.cpp b/pcsx2/Plugins.cpp index 2fd07ec9a8..be81deb3ce 100644 --- a/pcsx2/Plugins.cpp +++ b/pcsx2/Plugins.cpp @@ -720,14 +720,7 @@ void InitPlugins() return 0;*/ } -// ---------------------------------------------------------------------------- -// Opens all plugins and initializes the CDVD plugin to use the given filename. If the filename is null -// then the cdvd plugin uses whatever file it has been configured to use. If plugin have not been -// initialized by an explicit call to InitializePlugins, this method will do so for you. -// -// fixme: the cdvd filename really should be passed to the cdvd plugin as a separate API call. >_< -// -void OpenPlugins(const char* cdvdFilename) +void OpenPlugins() { /*if (!plugins_initialized) { diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index 54efe73b1d..54924566b7 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -113,7 +113,7 @@ extern PluginManager* g_plugins; void LoadPlugins(); void ReleasePlugins(); -void OpenPlugins(const char* pTitleFilename); +void OpenPlugins(); void ClosePlugins( bool closegs ); void CloseGS(); diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 0a3183aab2..d1cb5f5093 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -47,7 +47,7 @@ PCSX2_ALIGNED16(fpuRegisters fpuRegs); PCSX2_ALIGNED16(tlbs tlb[48]); R5900cpu *Cpu = NULL; -u32 bExecBIOS = 0; // set if the BIOS has already been executed +bool g_ExecBiosHack = false; // set if the BIOS has already been executed static bool cpuIsInitialized = false; static const uint eeWaitCycles = 3072; @@ -556,21 +556,27 @@ __forceinline void cpuTestHwInts() { // 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. +// +// Use of this function must be followed by the proper injection of the elf header's code +// execution entry point into cpuRegs.pc. Failure to modify cpuRegs.pc will result in the +// bios continuing its normal unimpeeded splashscreen execution. +// void cpuExecuteBios() { // Set the video mode to user's default request: gsSetRegionMode( (GS_RegionMode)EmuConfig.Video.DefaultRegionMode ); - Console::Notice( "* PCSX2 *: ExecuteBios" ); + Console::Status( "Executing Bios Stub..." ); - bExecBIOS = TRUE; - while (cpuRegs.pc != 0x00200008 && - cpuRegs.pc != 0x00100008) { + g_ExecBiosHack = true; + while( cpuRegs.pc != 0x00200008 && + cpuRegs.pc != 0x00100008 ) + { g_nextBranchCycle = cpuRegs.cycle; Cpu->ExecuteBlock(); } + g_ExecBiosHack = false; - bExecBIOS = FALSE; // { // FILE* f = fopen("eebios.bin", "wb"); // fwrite(PSM(0x80000000), 0x100000, 1, f); @@ -586,12 +592,12 @@ void cpuExecuteBios() // REC_CLEARM(0x00100008); // REC_CLEARM(cpuRegs.pc); - // 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 + // Reset the EErecs here, because the bios generates "slow" blocks that have + // g_ExecBiosHack checks in them. This deletes them so that the recs replace them // with new faster versions: Cpu->Reset(); - Console::Notice("* PCSX2 *: ExecuteBios Complete"); + Console::Notice("Execute Bios Stub Complete"); //GSprintf(5, "PCSX2 " PCSX2_VERSION "\nExecuteBios Complete\n"); } diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index 7dedb6c329..a6f06bbd96 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -28,7 +28,7 @@ extern const char* const bios[256]; extern s32 EEsCycle; extern u32 EEoCycle; -extern u32 bExecBIOS; +extern bool g_ExecBiosHack; union GPR_reg { // Declare union type GPR register u64 UD[2]; //128 bits diff --git a/pcsx2/RecoverySystem.cpp b/pcsx2/RecoverySystem.cpp index 0a87479df4..0c8664e575 100644 --- a/pcsx2/RecoverySystem.cpp +++ b/pcsx2/RecoverySystem.cpp @@ -80,7 +80,7 @@ namespace StateRecovery { void Recover() { // Just in case they weren't initialized earlier (no harm in calling this multiple times) - OpenPlugins(NULL); + OpenPlugins(); if( g_RecoveryState != NULL ) { diff --git a/pcsx2/Saveslots.cpp b/pcsx2/Saveslots.cpp index 83bef20545..9284352209 100644 --- a/pcsx2/Saveslots.cpp +++ b/pcsx2/Saveslots.cpp @@ -48,7 +48,7 @@ static void _loadStateOrExcept( const wxString& file ) // Make sure the cpu and plugins are ready to be state-ified! cpuReset(); - OpenPlugins( NULL ); + OpenPlugins(); joe.FreezeAll(); diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 9db1d9862c..202296a223 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -33,7 +33,7 @@ using namespace std; -Pcsx2Config EmuConfig = {0}; +Pcsx2Config EmuConfig; // disable all session overrides by default... SessionOverrideFlags g_Session = {false}; @@ -334,54 +334,6 @@ void SysEndExecution() g_ReturnToGui = true; } -// Runs an ELF image directly (ISO or ELF program or BIN) -// Used by Run::FromCD, and Run->Execute when no active emulation state is present. -// elf_file - if NULL, the CDVD plugin is queried for the ELF file. -// use_bios - forces the game to boot through the PS2 bios, instead of bypassing it. -void SysPrepareExecution( const wxString& elf_file, bool use_bios ) -{ - if( !g_EmulationInProgress ) - { - try - { - cpuReset(); - } - catch( Exception::BaseException& ex ) - { - Msgbox::Alert( ex.DisplayMessage() ); - return; - } - - //g_Startup.BootMode = (elf_file) ? BootMode_Elf : BootMode_Normal; - - OpenPlugins(NULL); - - if( elf_file.IsEmpty() ) - { - if( !StateRecovery::HasState() ) - { - // Not recovering a state, so need to execute the bios and load the ELF information. - // (note: gsRecoveries are done from ExecuteCpu) - - wxString ename; - if( !use_bios ) - GetPS2ElfName( ename ); - - loadElfFile( ename ); - } - } - else - { - // Custom ELF specified (not using CDVD). - // Run the BIOS and load the ELF. - loadElfFile( elf_file ); - } - } - - StateRecovery::Recover(); - HostGui::BeginExecution(); -} - void SysRestorableReset() { if( !g_EmulationInProgress ) return; diff --git a/pcsx2/System.h b/pcsx2/System.h index e52e7aa5f0..6bff8ca2d2 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -35,8 +35,7 @@ extern void SysShutdownMem(); extern void SysRestorableReset(); // Saves the current emulation state prior to spu reset. extern void SysClearExecutionCache(); // clears recompiled execution caches! -extern void SysEndExecution(); // terminates plugins, saves GS state (if enabled), and signals emulation loop to end. -extern void SysPrepareExecution( const wxString& elf_file, bool use_bios=false ); +extern void SysEndExecution(); // terminates plugins, saves GS state (if enabled), and signals emulation loop to end. // initiates high-speed execution of the emulation state. This function is currently // designed to be run from an event loop, but will eventually be re-tooled with threading @@ -82,6 +81,8 @@ extern void vSyncDebugStuff( uint frame ); // namespace Msgbox { + extern void OnEvent( wxCommandEvent& evt ); + // Pops up an alert Dialog Box with a singular "OK" button. // Always returns false. Replacement for SysMessage. extern bool Alert( const wxString& text ); @@ -91,3 +92,4 @@ namespace Msgbox extern bool OkCancel( const wxString& text ); } +DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 ); diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index f8c13d88eb..04ded9a56b 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -45,11 +45,11 @@ static const bool EnableThreadedLoggingTest = false; //true; // ConsoleThreadTest -- useful class for unit testing the thread safety and general performance // of the console logger. // -class ConsoleTestThread : public Thread +class ConsoleTestThread : public PersistentThread { protected: volatile bool m_done; - int Callback(); + sptr ExecuteTask(); public: ConsoleTestThread() : @@ -275,6 +275,7 @@ public: protected: void ReadUserModeSettings(); bool TryOpenConfigCwd(); + void OnMessageBox( wxCommandEvent& evt ); }; DECLARE_APP(Pcsx2App) diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index be181c6a7b..530d22097a 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -45,7 +45,7 @@ DEFINE_EVENT_TYPE(wxEVT_SemaphoreWait); using Console::Colors; // ---------------------------------------------------------------------------- -int ConsoleTestThread::Callback() +sptr ConsoleTestThread::ExecuteTask() { static int numtrack = 0; @@ -602,17 +602,72 @@ namespace Console } } +#define wxEVT_BOX_ALERT 78 + +using namespace Threading; + +DEFINE_EVENT_TYPE( pxEVT_MSGBOX ); + namespace Msgbox { + struct InstanceData + { + Semaphore WaitForMe; + int result; + + InstanceData() : + WaitForMe(), result( 0 ) + { + } + }; + + // parameters: + // flags - messagebox type flags, such as wxOK, wxCANCEL, etc. + // + static int ThreadedMessageBox( int flags, const wxString& text ) + { + // must pass the message to the main gui thread, and then stall this thread, to avoid + // threaded chaos where our thread keeps running while the popup is awaiting input. + + InstanceData instdat; + wxCommandEvent tevt( pxEVT_MSGBOX ); + tevt.SetString( text ); + tevt.SetClientData( &instdat ); + tevt.SetExtraLong( flags ); + wxGetApp().AddPendingEvent( tevt ); + instdat.WaitForMe.WaitNoCancel(); // Important! disable cancellation since we're using local stack vars. + return instdat.result; + } + + void OnEvent( wxCommandEvent& evt ) + { + // Must be called from the GUI thread ONLY. + wxASSERT( wxThread::IsMain() ); + + int result = Alert( evt.GetString() ); + InstanceData* instdat = (InstanceData*)evt.GetClientData(); + instdat->result = result; + instdat->WaitForMe.Post(); + } + bool Alert( const wxString& text ) { - wxMessageBox( text, L"Pcsx2 Message", wxOK, wxGetApp().GetTopWindow() ); + if( wxThread::IsMain() ) + wxMessageBox( text, L"Pcsx2 Message", wxOK, wxGetApp().GetTopWindow() ); + else + ThreadedMessageBox( wxOK, text ); return false; } bool OkCancel( const wxString& text ) { - int result = wxMessageBox( text, L"Pcsx2 Message", wxOK | wxCANCEL, wxGetApp().GetTopWindow() ); - return result == wxOK; + if( wxThread::IsMain() ) + { + return wxOK == wxMessageBox( text, L"Pcsx2 Message", wxOK | wxCANCEL, wxGetApp().GetTopWindow() ); + } + else + { + return wxOK == ThreadedMessageBox( wxOK | wxCANCEL, text ); + } } } diff --git a/pcsx2/gui/HostGui.cpp b/pcsx2/gui/HostGui.cpp index 112fd9d272..5aeb98a5af 100644 --- a/pcsx2/gui/HostGui.cpp +++ b/pcsx2/gui/HostGui.cpp @@ -17,7 +17,7 @@ */ #include "PrecompiledHeader.h" -#include "App.h" +#include "Mainframe.h" // This API is likely obsolete for the most part, so I've just included a few dummies // to keep things compiling until I can get to the point of tying up loose ends. @@ -44,6 +44,8 @@ namespace HostGui void BeginExecution() { + wxASSERT( g_EmuThread != NULL ); + g_EmuThread->Resume(); } void __fastcall KeyEvent( keyEvent* ev ) diff --git a/pcsx2/gui/MainFrame.cpp b/pcsx2/gui/MainFrame.cpp index f0f9f438f3..44cf164c18 100644 --- a/pcsx2/gui/MainFrame.cpp +++ b/pcsx2/gui/MainFrame.cpp @@ -167,8 +167,7 @@ void MainEmuFrame::ConnectMenus() ConnectMenu( Menu_RunELF, Menu_OpenELF_Click ); ConnectMenu( Menu_Run_Exit, Menu_Exit_Click ); - ConnectMenu( Menu_SuspendExec, Menu_Suspend_Click ); - ConnectMenu( Menu_ResumeExec, Menu_Resume_Click ); + ConnectMenu( Menu_PauseExec, Menu_Pause_Click ); ConnectMenu( Menu_Reset, Menu_Reset_Click ); ConnectMenu( Menu_State_LoadOther, Menu_LoadStateOther_Click ); @@ -224,7 +223,9 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title): m_LoadStatesSubmenu( *MakeStatesSubMenu( Menu_State_Load01 ) ), m_SaveStatesSubmenu( *MakeStatesSubMenu( Menu_State_Save01 ) ), - m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, Menu_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) ) + m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, Menu_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) ), + + m_IsPaused( false ) { // ------------------------------------------------------------------------ // Initial menubar setup. This needs to be done first so that the menu bar's visible size @@ -275,15 +276,14 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title): m_menuRun.Append(Menu_RunIso, _("Run ISO"), MakeIsoMenu() ); m_menuRun.Append(Menu_BootCDVD, _("Run CDVD"), MakeCdvdMenu() ); - m_menuRun.Append(Menu_RunWithoutDisc,_("Run without Disc"), _("Use this to access the PS2 system configuration menu")); - m_menuRun.Append(Menu_RunELF, _("Run ELF File..."), _("For running raw PS2 binaries.")); + m_menuRun.Append(Menu_SkipBiosToggle,_("ELF Injection Hack"), _("Skips PS2 splash screens when booting from Iso or CDVD media")); m_menuRun.AppendSeparator(); - m_menuRun.Append(Menu_SkipBiosToggle,_("Skip Bios on Boot"), _("Enable this to skip PS2 bootup screens (may hurt compat)")); + m_menuRun.Append(Menu_RunWithoutDisc,_("Boot without Disc"), _("Use this to access the PS2 system configuration menu")); + m_menuRun.Append(Menu_RunELF, _("Run ELF File..."), _("For running raw binaries")); m_menuRun.AppendSeparator(); - m_menuRun.Append(Menu_SuspendExec, _("Suspend"), _("Stops emulation dead in its tracks")); - m_menuRun.Append(Menu_ResumeExec, _("Resume"), _("Resumes suspended emulation")); + m_menuRun.Append(Menu_PauseExec, _("Pause"), _("Stops emulation dead in its tracks")); m_menuRun.Append(Menu_States, _("States"), MakeStatesMenu(), wxEmptyString); m_menuRun.Append(Menu_Reset, _("Reset"), _("Resets emulation state and reloads plugins")); @@ -337,4 +337,3 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title): Connect( wxEVT_MOVE, wxMoveEventHandler (MainEmuFrame::OnMoveAround) ); Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler(MainEmuFrame::OnCloseWindow) ); } - diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index 4085c469ff..a9f5679b44 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -23,6 +23,9 @@ #include #include "App.h" +#include "PS2/CoreEmuThread.h" + +extern CoreEmuThread* g_EmuThread; ////////////////////////////////////////////////////////////////////////////////////////// // @@ -50,8 +53,7 @@ protected: Menu_RunELF, Menu_SkipBiosToggle, // enables the Bios Skip speedhack Menu_EnableSkipBios, // check marked menu that toggles Skip Bios boot feature. - Menu_SuspendExec, // suspends active emulation - Menu_ResumeExec, // restores active emulation + Menu_PauseExec, // suspends/resumes active emulation Menu_Reset, // Issues a complete reset. Menu_States, // Opens states submenu Menu_Run_Exit = wxID_EXIT, @@ -134,6 +136,8 @@ protected: wxMenuItem& m_MenuItem_Console; + bool m_IsPaused; + // ------------------------------------------------------------------------ // MainEmuFrame Constructors and Member Methods // ------------------------------------------------------------------------ @@ -142,6 +146,8 @@ public: MainEmuFrame(wxWindow* parent, const wxString& title); void OnLogBoxHidden(); + bool IsPaused() const { return m_IsPaused; } + protected: void InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf ); @@ -160,8 +166,7 @@ protected: void Menu_SaveStateOther_Click(wxCommandEvent &event); void Menu_Exit_Click(wxCommandEvent &event); - void Menu_Suspend_Click(wxCommandEvent &event); - void Menu_Resume_Click(wxCommandEvent &event); + void Menu_Pause_Click(wxCommandEvent &event); void Menu_Reset_Click(wxCommandEvent &event); void Menu_Debug_Open_Click(wxCommandEvent &event); diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 4a6a729c8b..8dd01d440d 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -17,6 +17,7 @@ */ #include "PrecompiledHeader.h" +#include "HostGui.h" #include "CDVD/CDVD.h" #include "MainFrame.h" @@ -37,20 +38,63 @@ static const wxChar* isoFilterTypes = void MainEmuFrame::Menu_RunIso_Click(wxCommandEvent &event) { + g_EmuThread->Suspend(); + Console::Status( L"Default Folder: " + g_Conf->Folders.RunIso.ToString() ); wxFileDialog ctrl( this, _("Run PS2 Iso..."), g_Conf->Folders.RunIso.ToString(), wxEmptyString, isoFilterTypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST ); if( ctrl.ShowModal() == wxID_CANCEL ) return; g_Conf->Folders.RunIso = ctrl.GetPath(); - + //g_Conf->Save(); + + if( EmuConfig.SkipBiosSplash ) + { + // Fetch the ELF filename and CD type from the CDVD provider. + wxString ename( ctrl.GetFilename() ); + int result = GetPS2ElfName( ename ); + g_EmuThread->SetElfFile( wxEmptyString ); + switch( result ) + { + case 0: + Msgbox::Alert( _("Boot failed: CDVD image is not a PS1 or PS2 game.") ); + return; + + case 1: + Msgbox::Alert( _("Boot failed: PCSX2 does not support emulation of PS1 games.") ); + return; + + case 2: + // PS2 game. Valid! + g_EmuThread->SetElfFile( ename ); + break; + } + } } void MainEmuFrame::Menu_RunWithoutDisc_Click(wxCommandEvent &event) { + if( g_EmuThread->IsRunning() ) + { + g_EmuThread->Suspend(); + + // [TODO] : Add one of 'dems checkboxes that read like "[x] don't show this stupid shit again, kthx." + bool result = Msgbox::OkCancel( pxE( ".Popup:ConfirmEmuReset", L"This will reset the emulator and your current emulation session will be lost. Are you sure?") ); + + if( !result ) + { + if( !IsPaused() ) + g_EmuThread->Resume(); + return; + } + } + + g_EmuThread->Reset(); CDVDsys_ChangeSource( CDVDsrc_NoDisc ); - SysPrepareExecution( wxEmptyString, true ); + g_EmuThread->Resume(); + + //HostGui::BeginExecution(); } void MainEmuFrame::Menu_IsoRecent_Click(wxCommandEvent &event) @@ -76,11 +120,7 @@ void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event) Close(); } -void MainEmuFrame::Menu_Suspend_Click(wxCommandEvent &event) -{ -} - -void MainEmuFrame::Menu_Resume_Click(wxCommandEvent &event) +void MainEmuFrame::Menu_Pause_Click(wxCommandEvent &event) { } diff --git a/pcsx2/gui/Panels/ConfigurationPanels.h b/pcsx2/gui/Panels/ConfigurationPanels.h index 7f2bf8008a..debb6cdc9a 100644 --- a/pcsx2/gui/Panels/ConfigurationPanels.h +++ b/pcsx2/gui/Panels/ConfigurationPanels.h @@ -306,7 +306,7 @@ namespace Panels } }; - class EnumThread : public Threading::Thread + class EnumThread : public Threading::PersistentThread { public: EnumeratedPluginInfo* Results; // array of plugin results. @@ -317,10 +317,10 @@ namespace Panels public: virtual ~EnumThread(); EnumThread( PluginSelectorPanel& master ); - void Close(); + void Cancel(); protected: - int Callback(); + sptr ExecuteTask(); }; // This panel contains all of the plugin combo boxes. We stick them diff --git a/pcsx2/gui/Panels/PluginSelectorPanel.cpp b/pcsx2/gui/Panels/PluginSelectorPanel.cpp index 7d5b1167ef..8580e45d3d 100644 --- a/pcsx2/gui/Panels/PluginSelectorPanel.cpp +++ b/pcsx2/gui/Panels/PluginSelectorPanel.cpp @@ -337,7 +337,7 @@ void Panels::PluginSelectorPanel::OnProgress( wxCommandEvent& evt ) // EnumThread Method Implementations Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master ) : - Thread() + PersistentThread() , Results( new EnumeratedPluginInfo[master.FileCount()] ) , m_master( master ) , m_cancel( false ) @@ -347,17 +347,17 @@ Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master Panels::PluginSelectorPanel::EnumThread::~EnumThread() { safe_delete_array( Results ); - Close(); + Cancel(); } -void Panels::PluginSelectorPanel::EnumThread::Close() +void Panels::PluginSelectorPanel::EnumThread::Cancel() { m_cancel = true; Threading::Sleep( 1 ); - Thread::Close(); + PersistentThread::Cancel(); } -int Panels::PluginSelectorPanel::EnumThread::Callback() +sptr Panels::PluginSelectorPanel::EnumThread::ExecuteTask() { for( int curidx=0; curidx < m_master.FileCount() && !m_cancel; ++curidx ) { diff --git a/pcsx2/gui/main.cpp b/pcsx2/gui/main.cpp index b658c407fb..598cc27aad 100644 --- a/pcsx2/gui/main.cpp +++ b/pcsx2/gui/main.cpp @@ -30,11 +30,12 @@ IMPLEMENT_APP(Pcsx2App) AppConfig* g_Conf = NULL; wxFileHistory* g_RecentIsoList = NULL; +CoreEmuThread* g_EmuThread = NULL; namespace Exception { // -------------------------------------------------------------------------- - // Exception used to perfom an "errorless" termination of the app during OnInit + // Exception used to perform an "errorless" termination of the app during OnInit // procedures. This happens when a user cancels out of startup prompts/wizards. // class StartupAborted : public BaseException @@ -166,6 +167,7 @@ bool Pcsx2App::OnInit() wxApp::OnInit(); g_Conf = new AppConfig(); + g_EmuThread = new CoreEmuThread(); wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() ); @@ -231,10 +233,17 @@ bool Pcsx2App::OnInit() { Dialogs::ConfigurationDialog( m_MainFrame ).ShowModal(); }*/ + + Connect( pxEVT_MSGBOX, wxCommandEventHandler( Pcsx2App::OnMessageBox ) ); return true; } +void Pcsx2App::OnMessageBox( wxCommandEvent& evt ) +{ + Msgbox::OnEvent( evt ); +} + // Common exit handler which can be called from any event (though really it should // be called only from CloseWindow handlers since that's the more appropriate way // to handle window closures) diff --git a/pcsx2/ps2/CoreEmuThread.cpp b/pcsx2/ps2/CoreEmuThread.cpp new file mode 100644 index 0000000000..487783a2b0 --- /dev/null +++ b/pcsx2/ps2/CoreEmuThread.cpp @@ -0,0 +1,212 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2009 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 + */ + +#include "PrecompiledHeader.h" +#include "System.h" +#include "SaveState.h" +#include "ElfHeader.h" +#include "Plugins.h" +#include "CoreEmuThread.h" + +#include "R5900.h" +#include "R3000A.h" +#include "VUmicro.h" + +sptr CoreEmuThread::ExecuteTask() +{ + while( !m_Done && (m_ExecMode != ExecMode_Running) ) + { + m_ResumeEvent.Wait(); + } + + try + { + cpuReset(); + SysClearExecutionCache(); + OpenPlugins(); + + if( StateRecovery::HasState() ) + { + // no need to boot bios or detect CDs when loading savestates. + // [TODO] : It might be useful to detect game SLUS/CRC and compare it against + // the savestate info, and issue a warning to the user since, chances are, they + // don't really want to run a game with the wrong ISO loaded into the emu. + StateRecovery::Recover(); + } + else + { + ScopedLock lock( m_lock_elf_file ); + if( !m_elf_file.IsEmpty() ) + { + // Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF + // executable data, and injects the cpuRegs.pc with the address of the + // execution start point. + // + // This hack is necessary for non-CD ELF files, and is optional for game CDs + // (though not recommended for games because of rare ill side effects). + + cpuExecuteBios(); + loadElfFile( m_elf_file ); + } + } + } + catch( Exception::BaseException& ex ) + { + Msgbox::Alert( ex.DisplayMessage() ); + } + + StateCheck(); + + return 0; +} + +void CoreEmuThread::StateCheck() +{ + { + ScopedLock locker( m_lock_ExecMode ); + + switch( m_ExecMode ) + { + case ExecMode_Idle: + // threads should never have an idle execution state set while the + // thread is in any way active or alive. + DevAssert( false, "Invalid execution state detected." ); + break; + + // These are not the case statements you're looking for. Move along. + case ExecMode_Running: break; + case ExecMode_Suspended: break; + + case ExecMode_Suspending: + m_ExecMode = ExecMode_Suspended; + m_SuspendEvent.Post(); + break; + } + } + + while( (m_ExecMode == ExecMode_Suspended) && !m_Done ) + { + m_ResumeEvent.Wait(); + } +} + +void CoreEmuThread::Start() +{ + if( IsRunning() ) return; + + m_running = false; + m_ExecMode = ExecMode_Idle; + m_Done = false; + m_resetProfilers = false; + m_resetRecompilers = false; + m_elf_file = wxEmptyString; + + m_ResumeEvent.Reset(); + m_SuspendEvent.Reset(); + PersistentThread::Start(); + + pthread_detach( m_thread ); +} + +void CoreEmuThread::Reset() +{ + Cancel(); + StateRecovery::Clear(); +} + +// Resumes the core execution state, or does nothing is the core is already running. If +// settings were changed, resets will be performed as needed and emulation state resumed from +// memory savestates. +void CoreEmuThread::Resume() +{ + Start(); + + { + ScopedLock locker( m_lock_ExecMode ); + + if( m_ExecMode == ExecMode_Running ) + return; + + if( m_ExecMode == ExecMode_Suspending ) + { + // if there are resets to be done, then we need to make sure and wait for the + // emuThread to enter a fully suspended state before continuing... + + if( m_resetRecompilers || m_resetProfilers ) + { + locker.Unlock(); // no deadlocks please, thanks. :) + m_SuspendEvent.Wait(); + } + else + { + m_ExecMode = ExecMode_Running; + return; + } + } + + DevAssert( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Idle), + "EmuCoreThread is not in a suspended or idle state? wtf!" ); + } + + if( m_resetRecompilers || m_resetProfilers ) + { + SysClearExecutionCache(); + m_resetRecompilers = false; + m_resetProfilers = false; + } + + m_ExecMode = ExecMode_Running; + m_ResumeEvent.Post(); +} + +// Pauses the emulation state at the next PS2 vsync, and returns control to the calling +// thread; or does nothing if the core is already suspended. Calling this thread from the +// Core thread will result in deadlock. +// +// Parameters: +// isNonblocking - if set to true then the function will not block for emulation suspension. +// Defaults to false if parameter is not specified. Performing non-blocking suspension +// is mostly useful for starting certain non-Emu related gui activities (improves gui +// responsiveness). +// +void CoreEmuThread::Suspend( bool isBlocking ) +{ + { + ScopedLock locker( m_lock_ExecMode ); + + if( (m_ExecMode == ExecMode_Suspended) || (m_ExecMode == ExecMode_Idle) ) + return; + + if( m_ExecMode == ExecMode_Running ) + m_ExecMode = ExecMode_Suspending; + + DevAssert( m_ExecMode == ExecMode_Suspending, "ExecMode should be nothing other than Suspended..." ); + } + + m_SuspendEvent.Wait(); +} + +// Applies a full suite of new settings, which will automatically facilitate the necessary +// resets of the core and components (including plugins, if needed). The scope of resetting +// is determined by comparing the current settings against the new settings. +void CoreEmuThread::ApplySettings( const Pcsx2Config& src ) +{ + m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks ); + m_resetProfilers = (src.Profiler != EmuConfig.Profiler ); + EmuConfig = src; +} diff --git a/pcsx2/ps2/CoreEmuThread.h b/pcsx2/ps2/CoreEmuThread.h new file mode 100644 index 0000000000..e1e931c40c --- /dev/null +++ b/pcsx2/ps2/CoreEmuThread.h @@ -0,0 +1,86 @@ +/* Pcsx2 - Pc Ps2 Emulator + * Copyright (C) 2002-2009 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 + */ + +#pragma once + +#include "Utilities/Threading.h" + +using namespace Threading; + +///////////////////////////////////////////////////////////////////////////////////////// +// CoreEmuThread +// +class CoreEmuThread : public PersistentThread +{ +public: + enum ExecutionMode + { + ExecMode_Idle, + ExecMode_Running, + ExecMode_Suspending, + ExecMode_Suspended + }; + +protected: + volatile ExecutionMode m_ExecMode; + volatile bool m_Done; + + Semaphore m_ResumeEvent; + Semaphore m_SuspendEvent; + + bool m_resetRecompilers; + bool m_resetProfilers; + + wxString m_elf_file; + + MutexLock m_lock_elf_file; + MutexLock m_lock_ExecMode; + +public: + CoreEmuThread() : + m_ExecMode( ExecMode_Idle ) + , m_Done( false ) + , m_ResumeEvent() + , m_SuspendEvent() + , m_resetRecompilers( false ) + , m_resetProfilers( false ) + + , m_elf_file() + , m_lock_elf_file() + , m_lock_ExecMode() + { + } + + void SetElfFile( const wxString& text ) + { + ScopedLock lock( m_lock_elf_file ); + m_elf_file = text; + } + + void Start(); + void Reset(); + + bool IsSuspended() const { return (m_ExecMode == ExecMode_Suspended); } + void Suspend( bool isBlocking = true ); + void Resume(); + void ApplySettings( const Pcsx2Config& src ); + +protected: + sptr ExecuteTask(); + void StateCheck(); +}; diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index ae9c6e60f4..9c9a033cd8 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -262,62 +262,6 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -1098,6 +1042,14 @@ RelativePath="..\..\x86\BaseblockEx.h" > + + + + @@ -1974,10 +1926,6 @@ RelativePath="..\..\gui\i18n.cpp" > - - diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index 58dbc2e729..d67392ef38 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -1043,7 +1043,7 @@ static u32 eeScaleBlockCycles() // setting "branch = 2"; static void iBranchTest(u32 newpc, bool noDispatch) { - if( bExecBIOS ) CheckForBIOSEnd(); + if( g_ExecBiosHack ) CheckForBIOSEnd(); // Check the Event scheduler if our "cycle target" has been reached. // Equiv code to: