diff --git a/common/include/PS2Edefs.h b/common/include/PS2Edefs.h index 3fdd3b0944..917f722315 100644 --- a/common/include/PS2Edefs.h +++ b/common/include/PS2Edefs.h @@ -540,6 +540,7 @@ typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); //typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); // PAD +typedef s32 (CALLBACK* _PADinit)(u32 flags); typedef s32 (CALLBACK* _PADopen)(void *pDsp); typedef u8 (CALLBACK* _PADstartPoll)(int pad); typedef u8 (CALLBACK* _PADpoll)(u8 value); diff --git a/common/include/Utilities/Threading.h b/common/include/Utilities/Threading.h index 1c5d1afa3a..fda1c78468 100644 --- a/common/include/Utilities/Threading.h +++ b/common/include/Utilities/Threading.h @@ -43,6 +43,8 @@ namespace Exception }; } +class wxTimeSpan; + namespace Threading { ////////////////////////////////////////////////////////////////////////////////////////// @@ -74,7 +76,9 @@ namespace Threading void Reset(); void Post(); void Post( int multiple ); + void Wait(); + void Wait( const wxTimeSpan& timeout ); void WaitNoCancel(); int Count(); }; @@ -107,7 +111,7 @@ namespace Threading // PersistentThread - Helper class for the basics of starting/managing persistent threads. // // Use this as a base class for your threaded procedure, and implement the 'int ExecuteTask()' - // method. Use Start() and Cancel() to start and shutdown the thread, and use m_post_event + // method. Use Start() and Cancel() to start and shutdown the thread, and use m_sem_event // internally to post/receive events for the thread (make a public accessor for it in your // derived class if your thread utilizes the post). // @@ -127,7 +131,7 @@ namespace Threading sptr m_returncode; // value returned from the thread on close. bool m_running; - Semaphore m_post_event; // general wait event that's needed by most threads. + Semaphore m_sem_event; // general wait event that's needed by most threads. public: virtual ~PersistentThread(); @@ -259,7 +263,7 @@ namespace Threading { if( !m_running ) return m_returncode; m_Done = true; - m_post_event.Post(); + m_sem_event.Post(); return PersistentThread::Block(); } @@ -270,7 +274,7 @@ namespace Threading jASSUME( m_running ); m_TaskComplete = false; m_post_TaskComplete.Reset(); - m_post_event.Post(); + m_sem_event.Post(); } // Blocks current thread execution pending the completion of the parallel task. @@ -293,7 +297,7 @@ namespace Threading do { // Wait for a job! - m_post_event.Wait(); + m_sem_event.Wait(); if( m_Done ) break; Task(); diff --git a/common/src/Utilities/ThreadTools.cpp b/common/src/Utilities/ThreadTools.cpp index d84c8cadc8..23a2fb8065 100644 --- a/common/src/Utilities/ThreadTools.cpp +++ b/common/src/Utilities/ThreadTools.cpp @@ -19,6 +19,8 @@ #include "PrecompiledHeader.h" #include "Threading.h" +#include + #ifdef __LINUX__ # include // for pthread_kill, which is in pthread.h on w32-pthreads #endif @@ -31,7 +33,7 @@ namespace Threading m_thread() , m_returncode( 0 ) , m_running( false ) - , m_post_event() + , m_sem_event() { } @@ -175,22 +177,30 @@ namespace Threading sem_post( &sema ); } + // Valid on Win32 builds only!! Attempts to use it on Linux will result in unresolved + // external linker errors. +#if defined(_MSC_VER) void Semaphore::Post( int multiple ) { -#if defined(_MSC_VER) sem_post_multiple( &sema, multiple ); -#endif } +#endif void Semaphore::Wait() { sem_wait( &sema ); } + void Semaphore::Wait( const wxTimeSpan& timeout ) + { + const timespec fail = { timeout.GetSeconds().GetLo(), 0 }; + sem_timedwait( &sema, &fail ); + } + // Performs an uncancellable wait on a semaphore; restoring the thread's previous cancel state // after the wait has completed. Useful for situations where the semaphore itself is stored on // the stack and passed to another thread via GUI message or such, avoiding complications where - // the thread might be cancelled and the stack value becomes invalid. + // the thread might be canceled and the stack value becomes invalid. // // Performance note: this function has quite a bit more overhead compared to Semaphore::Wait(), so // consider manually specifying the thread as uncancellable and using Wait() instead if you need diff --git a/common/src/Utilities/Windows/WinMisc.cpp b/common/src/Utilities/Windows/WinMisc.cpp index b89d8c360d..cc33ebaeea 100644 --- a/common/src/Utilities/Windows/WinMisc.cpp +++ b/common/src/Utilities/Windows/WinMisc.cpp @@ -107,12 +107,11 @@ void Win32::RealVersionInfo::InitVersionString() int majorVersion = (DWORD)(LOBYTE(LOWORD(version))); int minorVersion = (DWORD)(HIBYTE(LOWORD(version))); - RealVersionInfo really; wxString verName( wxString::FromAscii( GetVersionName( minorVersion, majorVersion ) ) ); bool IsCompatMode = false; - if( really.IsVista() ) + if( IsVista() ) { m_VersionString = L"Windows Vista"; @@ -131,7 +130,7 @@ void Win32::RealVersionInfo::InitVersionString() else m_VersionString += L" (32-bit)"; } - else if( really.IsXP() ) + else if( IsXP() ) { m_VersionString = wxsFormat( L"Windows XP v%d.%d", majorVersion, minorVersion ); diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 23fe962d36..e04b7ae9f2 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -22,10 +22,10 @@ class IniInterface; enum PluginsEnum_t { - PluginId_CDVD = 0, - PluginId_GS, + PluginId_GS = 0, PluginId_PAD, PluginId_SPU2, + PluginId_CDVD, PluginId_USB, PluginId_FW, PluginId_DEV9, diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index 4d75360a04..c1d416f291 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -28,6 +28,7 @@ #include "GS.h" #include "VUmicro.h" +#include "ps2/CoreEmuThread.h" using namespace Threading; @@ -436,10 +437,10 @@ __forceinline void rcntUpdate_hScanline() } } -__forceinline bool rcntUpdate_vSync() +__forceinline void rcntUpdate_vSync() { s32 diff = (cpuRegs.cycle - vsyncCounter.sCycle); - if( diff < vsyncCounter.CycleT ) return false; + if( diff < vsyncCounter.CycleT ) return; //iopBranchAction = 1; if (vsyncCounter.Mode == MODE_VSYNC) @@ -449,8 +450,8 @@ __forceinline bool rcntUpdate_vSync() vsyncCounter.sCycle += vSyncInfo.Blank; vsyncCounter.CycleT = vSyncInfo.Render; vsyncCounter.Mode = MODE_VRENDER; - - return true; + + CoreEmuThread::Get().StateCheck(); } else // VSYNC end / VRENDER begin { @@ -477,7 +478,6 @@ __forceinline bool rcntUpdate_vSync() } # endif } - return false; } static __forceinline void _cpuTestTarget( int i ) @@ -518,14 +518,14 @@ static __forceinline void _cpuTestOverflow( int i ) // forceinline note: this method is called from two locations, but one // of them is the interpreter, which doesn't count. ;) So might as // well forceinline it! -__forceinline bool rcntUpdate() +__forceinline void rcntUpdate() { - bool retval = rcntUpdate_vSync(); + rcntUpdate_vSync(); // Update counters so that we can perform overflow and target tests. - for (int i=0; i<=3; i++) { - + for (int i=0; i<=3; i++) + { // We want to count gated counters (except the hblank which exclude below, and are // counted by the hblank timer instead) @@ -550,7 +550,6 @@ __forceinline bool rcntUpdate() } cpuRcntSet(); - return retval; } static __forceinline void _rcntSetGate( int index ) @@ -582,8 +581,8 @@ __forceinline void rcntStartGate(bool isVblank, u32 sCycle) { int i; - for (i=0; i <=3; i++) { - + for (i=0; i <=3; i++) + { //if ((mode == 0) && ((counters[i].mode & 0x83) == 0x83)) if (!isVblank && counters[i].mode.IsCounting && (counters[i].mode.ClockSource == 3) ) { diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index 5333bcb111..d1aae3fd00 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -135,8 +135,8 @@ extern s32 nextCounter; // delta until the next counter event (must be signed) extern u32 nextsCounter; extern void rcntUpdate_hScanline(); -extern bool rcntUpdate_vSync(); -extern bool rcntUpdate(); +extern void rcntUpdate_vSync(); +extern void rcntUpdate(); extern void rcntInit(); extern void rcntStartGate(bool mode, u32 sCycle); diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index 7fe8740041..e08388b5bd 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -30,8 +30,6 @@ using namespace Threading; using namespace std; using namespace R5900; -static bool m_gsOpened = false; - u32 CSRw; PCSX2_ALIGNED16( u8 g_RealGSMem[0x2000] ); @@ -150,61 +148,10 @@ void gsInit() } } -// Opens the gsRingbuffer thread. -s32 gsOpen() -{ - if( m_gsOpened ) return 0; - - //video - // Only bind the gsIrq if we're not running the MTGS. - // The MTGS simulates its own gsIrq in order to maintain proper sync. - - m_gsOpened = mtgsOpen(); - if( !m_gsOpened ) - { - // MTGS failed to init or is disabled. Try the GS instead! - // ... and set the memptr again just in case (for switching between GS/MTGS on the fly) - - GSsetBaseMem( PS2MEM_GS ); - GSirqCallback( gsIrq ); - - m_gsOpened = !GSopen( &pDsp, "PCSX2", 0 ); - } - - /*if( m_gsOpened ) - { - gsOnModeChanged( - (Config.PsxType & 1) ? FRAMERATE_PAL : FRAMERATE_NTSC, - UpdateVSyncRate() - ); - }*/ - - // FIXME : This is the gs/vsync tie-in for framelimiting, but it really - // needs to be called from the hotkey framelimiter enable/disable too. - - if(GSsetFrameLimit == NULL) - { - DevCon::Notice("Notice: GS Plugin does not implement GSsetFrameLimit."); - } - else - { - GSsetFrameLimit( EmuConfig.Video.EnableFrameLimiting ); - } - - return !m_gsOpened; -} - -void gsClose() -{ - if( !m_gsOpened ) return; - m_gsOpened = false; - safe_delete( mtgsThread ); -} - void gsReset() { // Sanity check in case the plugin hasn't been initialized... - if( !m_gsOpened ) return; + if( mtgsThread == NULL ) return; mtgsThread->Reset(); gsOnModeChanged( diff --git a/pcsx2/GS.h b/pcsx2/GS.h index a02a9a7263..02b539758e 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -178,7 +178,11 @@ protected: uint m_WritePos; // cur pos ee thread is writing to // used to regulate thread startup and gsInit - Threading::Semaphore m_post_InitDone; + Threading::Semaphore m_sem_InitDone; + + // used for quitting the ringbuffer thread only -- is posted by the ringbuffer when + // a QUIT message is processed (signals that the GS has been closed). + Threading::Semaphore m_sem_Quitter; Threading::MutexLock m_lock_RingRestart; @@ -282,8 +286,7 @@ protected: extern mtgsThreadObject* mtgsThread; void mtgsWaitGS(); -bool mtgsOpen(); -//void mtgsRingBufSimplePacket( s32 command, u32 data0, u32 data1, u32 data2 ); +void mtgsOpen(); ///////////////////////////////////////////////////////////////////////////// // Generalized GS Functions and Stuff diff --git a/pcsx2/Interpreter.cpp b/pcsx2/Interpreter.cpp index 8becc344ae..3e2a35bb44 100644 --- a/pcsx2/Interpreter.cpp +++ b/pcsx2/Interpreter.cpp @@ -74,8 +74,6 @@ static void execI() opcode.interpret(); } -static bool EventRaised = false; - static __forceinline void _doBranch_shared(u32 tar) { branch2 = cpuRegs.branch = 1; @@ -96,7 +94,7 @@ static void __fastcall doBranch( u32 target ) _doBranch_shared( target ); cpuRegs.cycle += cpuBlockCycles >> 3; cpuBlockCycles &= (1<<3)-1; - EventRaised |= intEventTest(); + intEventTest(); } void __fastcall intDoBranch(u32 target) @@ -108,7 +106,7 @@ void __fastcall intDoBranch(u32 target) { cpuRegs.cycle += cpuBlockCycles >> 3; cpuBlockCycles &= (1<<3)-1; - EventRaised |= intEventTest(); + intEventTest(); } } @@ -371,10 +369,10 @@ void intReset() branch2 = 0; } - bool intEventTest() +void intEventTest() { // Perform counters, ints, and IOP updates: - return _cpuBranchTest_Shared(); + _cpuBranchTest_Shared(); } void intExecute() @@ -384,22 +382,12 @@ void intExecute() // Mem protection should be handled by the caller here so that it can be // done in a more optimized fashion. - EventRaised = false; - - while( !EventRaised ) + while( true ) { execI(); } } -static void intExecuteBlock() -{ - g_EEFreezeRegs = false; - - branch2 = 0; - while (!branch2) execI(); -} - static void intStep() { g_EEFreezeRegs = false; @@ -418,7 +406,6 @@ R5900cpu intCpu = { intReset, intStep, intExecute, - intExecuteBlock, intClear, intShutdown }; diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index ea689271b4..773fd86164 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -18,9 +18,10 @@ #include "PrecompiledHeader.h" -#include #include +#include + #include "Common.h" #include "VU.h" #include "GS.h" @@ -181,7 +182,7 @@ mtgsThreadObject::mtgsThreadObject() : , m_RingPos( 0 ) , m_WritePos( 0 ) -, m_post_InitDone() +, m_sem_InitDone() , m_lock_RingRestart() , m_PacketLocker( true ) // true - makes it a recursive lock @@ -204,16 +205,16 @@ mtgsThreadObject::mtgsThreadObject() : void mtgsThreadObject::Start() { - m_post_InitDone.Reset(); + m_sem_InitDone.Reset(); 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. - m_post_InitDone.Wait(); + m_sem_InitDone.Wait(); if( m_returncode != 0 ) // means the thread failed to init the GS plugin - throw Exception::PluginFailure( "GS", wxLt("%s plugin initialization failed.") ); // plugin returned an error after having been asked very nicely to initialize itself." ); + throw Exception::PluginFailure( "GS", wxLt("%s plugin failed to open.") ); } mtgsThreadObject::~mtgsThreadObject() @@ -226,7 +227,9 @@ void mtgsThreadObject::Cancel() Console::WriteLn( "MTGS > Closing GS thread..." ); SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 ); SetEvent(); - pthread_join( m_thread, NULL ); + m_sem_Quitter.Wait( wxTimeSpan( 0, 0, 5, 0 ) ); + Sleep( 2 ); + PersistentThread::Cancel( true ); } void mtgsThreadObject::Reset() @@ -495,11 +498,7 @@ struct PacketTagType u32 command; u32 data[3]; }; -// Until such time as there is a Gsdx port for Linux, or a Linux plugin needs the functionality, -// lets only declare this for Windows. -#ifndef __LINUX__ -extern bool renderswitch; -#endif + sptr mtgsThreadObject::ExecuteTask() { Console::WriteLn("MTGS > Thread Started, Opening GS Plugin..."); @@ -507,19 +506,13 @@ sptr mtgsThreadObject::ExecuteTask() memcpy_aligned( m_gsMem, PS2MEM_GS, sizeof(PS2MEM_GS) ); GSsetBaseMem( m_gsMem ); GSirqCallback( NULL ); - - #ifdef __LINUX__ - m_returncode = GSopen((void *)&pDsp, "PCSX2", 1); - #else - //tells GSdx to go into dx9 sw if "renderswitch" is set. Abusing the isMultiThread int - //for that so we don't need a new callback - m_returncode = GSopen((void *)&pDsp, "PCSX2", renderswitch ? 2 : 1); - #endif + + g_plugins->Open( PluginId_GS ); Console::WriteLn( "MTGS > GSopen Finished, return code: 0x%x", params m_returncode ); GSCSRr = 0x551B4000; // 0x55190000 - m_post_InitDone.Post(); + m_sem_InitDone.Post(); if (m_returncode != 0) { return m_returncode; } // error msg will be issued to the user by Plugins.c #ifdef RINGBUF_DEBUG_STACK @@ -528,7 +521,7 @@ sptr mtgsThreadObject::ExecuteTask() while( true ) { - m_post_event.Wait(); + m_sem_event.Wait(); AtomicExchange( m_RingBufferIsBusy, 1 ); @@ -675,6 +668,7 @@ sptr mtgsThreadObject::ExecuteTask() case GS_RINGTYPE_QUIT: g_plugins->Close( PluginId_GS ); + m_sem_Quitter.Post(); return 0; #ifdef PCSX2_DEVBUILD @@ -715,7 +709,7 @@ void mtgsThreadObject::WaitGS() // For use in loops that wait on the GS thread to do certain things. void mtgsThreadObject::SetEvent() { - m_post_event.Post(); + m_sem_event.Post(); m_CopyCommandTally = 0; m_CopyDataTally = 0; } @@ -1087,23 +1081,30 @@ void mtgsWaitGS() mtgsThread->WaitGS(); } -bool mtgsOpen() +// Exceptions: +// ThreadCreationError - Thready could not be created (indicates OS resource limitations) +// PluginFailure - GS plugin's "GSopen" call failed. +// +void mtgsOpen() { // better not be a thread already running, yo! assert( mtgsThread == NULL ); + if( mtgsThread != NULL ) return; + + mtgsThread = new mtgsThreadObject(); try { - mtgsThread = new mtgsThreadObject(); mtgsThread->Start(); } - catch( Exception::ThreadCreationError& ) + catch( ... ) { - Console::Error( "MTGS > Thread creation failed!" ); - mtgsThread = NULL; - return false; + // if the thread start fails for any reason then set the handle to null. + // The handle is used as a NULL test of thread running status, which is why + // we really need to do this. :) + safe_delete( mtgsThread ); + throw; } - return true; } diff --git a/pcsx2/MemoryCard.cpp b/pcsx2/MemoryCard.cpp index fdbf21227d..d8d4100d74 100644 --- a/pcsx2/MemoryCard.cpp +++ b/pcsx2/MemoryCard.cpp @@ -83,7 +83,14 @@ void MemoryCard::Load( uint mcd ) { // Translation note: detailed description should mention that the memory card will be disabled // for the duration of this session. - Msgbox::Alert( wxsFormat( _("Could not load MemoryCard from file: %s"), str.c_str() ) ); + Msgbox::Alert( pxE( ".Popup:MemoryCard:FailedtoOpen", + wxsFormat( + L"Could not load or create a MemoryCard from the file:\n\n%s\n\n" + L"The MemoryCard in slot %d has been automatically disabled. You can correct the problem\n" + L"and re-enable the MemoryCard at any time using Config:MemoryCards from the main menu.", + str.c_str(), mcd + ) ) + ); } } @@ -106,7 +113,7 @@ void MemoryCard::Read( uint mcd, u8 *data, u32 adr, int size ) if( !mcfp.IsOpened() ) { - DevCon::Error( "MemoryCard > Ignoring attempted read from disabled card." ); + DevCon::Error( "MemoryCard: Ignoring attempted read from disabled card." ); memset(data, 0, size); return; } @@ -121,7 +128,7 @@ void MemoryCard::Save( uint mcd, const u8 *data, u32 adr, int size ) if( !mcfp.IsOpened() ) { - DevCon::Error( "MemoryCard > Ignoring attempted save/write to disabled card." ); + DevCon::Error( "MemoryCard: Ignoring attempted save/write to disabled card." ); return; } @@ -152,12 +159,12 @@ void MemoryCard::Erase( uint mcd, u32 adr ) if( !mcfp.IsOpened() ) { - DevCon::Error( "MemoryCard > Ignoring seek for disabled card." ); + DevCon::Error( "MemoryCard: Ignoring seek for disabled card." ); return; } Seek(mcfp, adr); - mcfp.Write( data, 528*16 ); + mcfp.Write( data, sizeof(data) ); } @@ -172,12 +179,7 @@ void MemoryCard::Create( const wxString& mcdFile ) memset8_obj<0xff>( effeffs ); for( uint i=0; i<16384; i++ ) - { - for( uint j=0; j<528; j++ ) - fp.Write( effeffs, sizeof(effeffs) ); - - //for(j=0; j<16; j++) fputc(enc[j],fp); - } + fp.Write( effeffs, sizeof(effeffs) ); } u64 MemoryCard::GetCRC( uint mcd ) diff --git a/pcsx2/Misc.cpp b/pcsx2/Misc.cpp index c5095df805..ce0b735f9c 100644 --- a/pcsx2/Misc.cpp +++ b/pcsx2/Misc.cpp @@ -48,7 +48,9 @@ using namespace std; using namespace R5900; static int g_Pcsx2Recording = 0; // true 1 if recording video and sound -bool renderswitch = 0; + +// renderswitch - tells GSdx to go into dx9 sw if "renderswitch" is set. +bool renderswitch = false; struct KeyModifiers keymodifiers = {false, false, false, false}; @@ -330,7 +332,11 @@ void ProcessFKeys(int fkey, struct KeyModifiers *keymod) case 9: //gsdx "on the fly" renderer switching StateRecovery::MakeGsOnly(); g_EmulationInProgress = false; - CloseGS(); + + // close GS and PAD together, because the PAD depends on the GS window. + g_plugins->Close( PluginId_PAD ); + safe_delete( mtgsThread ); + renderswitch = !renderswitch; StateRecovery::Recover(); HostGui::BeginExecution(); // also sets g_EmulationInProgress to true later diff --git a/pcsx2/Plugins.cpp b/pcsx2/Plugins.cpp index 6032786ee0..13b9edbad8 100644 --- a/pcsx2/Plugins.cpp +++ b/pcsx2/Plugins.cpp @@ -34,13 +34,15 @@ // const PluginInfo tbl_PluginInfo[] = { - { "GS", PluginId_GS, PS2E_LT_GS, PS2E_GS_VERSION }, - { "PAD", PluginId_PAD, PS2E_LT_PAD, PS2E_PAD_VERSION }, - { "SPU2", PluginId_SPU2, PS2E_LT_SPU2, PS2E_SPU2_VERSION }, - { "CDVD", PluginId_CDVD, PS2E_LT_CDVD, PS2E_CDVD_VERSION }, - { "DEV9", PluginId_DEV9, PS2E_LT_DEV9, PS2E_DEV9_VERSION }, - { "USB", PluginId_USB, PS2E_LT_USB, PS2E_USB_VERSION }, - { "FW", PluginId_FW, PS2E_LT_FW, PS2E_FW_VERSION }, + { "GS", PluginId_GS, PS2E_LT_GS, PS2E_GS_VERSION }, + { "PAD", PluginId_PAD, PS2E_LT_PAD, PS2E_PAD_VERSION }, + { "SPU2", PluginId_SPU2, PS2E_LT_SPU2, PS2E_SPU2_VERSION }, + { "CDVD", PluginId_CDVD, PS2E_LT_CDVD, PS2E_CDVD_VERSION }, + { "USB", PluginId_USB, PS2E_LT_USB, PS2E_USB_VERSION }, + { "FW", PluginId_FW, PS2E_LT_FW, PS2E_FW_VERSION }, + { "DEV9", PluginId_DEV9, PS2E_LT_DEV9, PS2E_DEV9_VERSION }, + + { NULL } // SIO is currently unused (legacy?) //{ "SIO", PluginId_SIO, PS2E_LT_SIO, PS2E_SIO_VERSION } @@ -74,7 +76,7 @@ struct LegacyApi_CommonMethod // returns the method name as a wxString, converted from UTF8. wxString GetMethodName( PluginsEnum_t pid ) const { - return wxString::FromUTF8( tbl_PluginInfo[pid].shortname) + wxString::FromUTF8( MethodName ); + return tbl_PluginInfo[pid].GetShortname() + wxString::FromUTF8( MethodName ); } }; @@ -148,6 +150,7 @@ static void CALLBACK GS_printf(int timeout, char *fmt, ...) } // PAD +_PADinit PADinit; _PADopen PADopen; _PADstartPoll PADstartPoll; _PADpoll PADpoll; @@ -230,6 +233,11 @@ DEV9handler dev9Handler; USBhandler usbHandler; uptr pDsp; +static s32 CALLBACK _hack_PADinit() +{ + return PADinit( 3 ); +} + // ---------------------------------------------------------------------------- // Important: Contents of this array must match the order of the contents of the // LegacyPluginAPI_Common structure defined in Plugins.h. @@ -434,28 +442,28 @@ static const LegacyApi_OptMethod s_MethMessOpt_CDVD[] = // ---------------------------------------------------------------------------- static const LegacyApi_ReqMethod s_MethMessReq_SPU2[] = { - { "SPU2open", (vMeth**)SPU2open, NULL }, - { "SPU2write", (vMeth**)SPU2write, NULL }, - { "SPU2read", (vMeth**)SPU2read, NULL }, - { "SPU2readDMA4Mem", (vMeth**)SPU2readDMA4Mem, NULL }, - { "SPU2readDMA7Mem", (vMeth**)SPU2readDMA7Mem, NULL }, - { "SPU2writeDMA4Mem", (vMeth**)SPU2writeDMA4Mem, NULL }, - { "SPU2writeDMA7Mem", (vMeth**)SPU2writeDMA7Mem, NULL }, - { "SPU2interruptDMA4", (vMeth**)SPU2interruptDMA4, NULL }, - { "SPU2interruptDMA7", (vMeth**)SPU2interruptDMA7, NULL }, - { "SPU2setDMABaseAddr", (vMeth**)SPU2setDMABaseAddr,NULL }, - { "SPU2ReadMemAddr", (vMeth**)SPU2ReadMemAddr, NULL }, - { "SPU2irqCallback", (vMeth**)SPU2irqCallback, NULL }, + { "SPU2open", (vMeth**)&SPU2open, NULL }, + { "SPU2write", (vMeth**)&SPU2write, NULL }, + { "SPU2read", (vMeth**)&SPU2read, NULL }, + { "SPU2readDMA4Mem", (vMeth**)&SPU2readDMA4Mem, NULL }, + { "SPU2readDMA7Mem", (vMeth**)&SPU2readDMA7Mem, NULL }, + { "SPU2writeDMA4Mem", (vMeth**)&SPU2writeDMA4Mem, NULL }, + { "SPU2writeDMA7Mem", (vMeth**)&SPU2writeDMA7Mem, NULL }, + { "SPU2interruptDMA4", (vMeth**)&SPU2interruptDMA4,NULL }, + { "SPU2interruptDMA7", (vMeth**)&SPU2interruptDMA7,NULL }, + { "SPU2setDMABaseAddr", (vMeth**)&SPU2setDMABaseAddr,NULL }, + { "SPU2ReadMemAddr", (vMeth**)&SPU2ReadMemAddr, NULL }, + { "SPU2irqCallback", (vMeth**)&SPU2irqCallback, NULL }, { NULL } }; static const LegacyApi_OptMethod s_MethMessOpt_SPU2[] = { - { "SPU2setClockPtr", (vMeth**)SPU2setClockPtr }, - { "SPU2async", (vMeth**)SPU2async }, - { "SPU2WriteMemAddr", (vMeth**)SPU2WriteMemAddr }, - { "SPU2setupRecording", (vMeth**)SPU2setupRecording }, + { "SPU2setClockPtr", (vMeth**)&SPU2setClockPtr }, + { "SPU2async", (vMeth**)&SPU2async }, + { "SPU2WriteMemAddr", (vMeth**)&SPU2WriteMemAddr }, + { "SPU2setupRecording", (vMeth**)&SPU2setupRecording}, { NULL } }; @@ -499,6 +507,7 @@ static const LegacyApi_ReqMethod s_MethMessReq_USB[] = { "USBwrite32", (vMeth**)&USBwrite32, NULL }, { "USBirqCallback", (vMeth**)&USBirqCallback, NULL }, { "USBirqHandler", (vMeth**)&USBirqHandler, NULL }, + { NULL } }; static const LegacyApi_OptMethod s_MethMessOpt_USB[] = @@ -516,6 +525,7 @@ static const LegacyApi_ReqMethod s_MethMessReq_FW[] = { "FWread32", (vMeth**)&FWread32, NULL }, { "FWwrite32", (vMeth**)&FWwrite32, NULL }, { "FWirqCallback", (vMeth**)&FWirqCallback, NULL }, + { NULL } }; static const LegacyApi_OptMethod s_MethMessOpt_FW[] = @@ -525,10 +535,10 @@ static const LegacyApi_OptMethod s_MethMessOpt_FW[] = static const LegacyApi_ReqMethod* const s_MethMessReq[] = { - s_MethMessReq_CDVD, s_MethMessReq_GS, s_MethMessReq_PAD, s_MethMessReq_SPU2, + s_MethMessReq_CDVD, s_MethMessReq_USB, s_MethMessReq_FW, s_MethMessReq_DEV9 @@ -536,10 +546,10 @@ static const LegacyApi_ReqMethod* const s_MethMessReq[] = static const LegacyApi_OptMethod* const s_MethMessOpt[] = { - s_MethMessOpt_CDVD, s_MethMessOpt_GS, s_MethMessOpt_PAD, s_MethMessOpt_SPU2, + s_MethMessOpt_CDVD, s_MethMessOpt_USB, s_MethMessOpt_FW, s_MethMessOpt_DEV9 @@ -554,69 +564,23 @@ Exception::NotPcsxPlugin::NotPcsxPlugin( const PluginsEnum_t& pid ) : Stream( wxString::FromUTF8( tbl_PluginInfo[pid].shortname ), wxLt("File is not a PCSX2 plugin") ) {} -void PluginManager::BindCommon( PluginsEnum_t pid ) +PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] ) { - const LegacyApi_CommonMethod* current = s_MethMessCommon; - VoidMethod** target = (VoidMethod**)&m_CommonBindings[pid]; - - while( current->MethodName != NULL ) + const PluginInfo* pi = tbl_PluginInfo-1; + while( ++pi, pi->shortname != NULL ) { - *target = (VoidMethod*)m_libs[pid].GetSymbol( current->GetMethodName( pid ) ); - target++; - current++; - } -} + const PluginsEnum_t pid = pi->id; -void PluginManager::BindRequired( PluginsEnum_t pid ) -{ - const LegacyApi_ReqMethod* current = s_MethMessReq[pid]; - const wxDynamicLibrary& lib = m_libs[pid]; + if( folders[pid].IsEmpty() ) + throw Exception::InvalidArgument( "Invalid argument in PluginManager::ctor: Empty plugin filename." ); - while( current->MethodName != NULL ) - { - *(current->Dest) = (VoidMethod*)lib.GetSymbol( current->GetMethodName() ); + m_info[pid].Filename = folders[pid]; - if( *(current->Dest) == NULL ) - *(current->Dest) = current->Fallback; + if( !wxFile::Exists( folders[pid] ) ) + throw Exception::FileNotFound( folders[pid] ); - if( *(current->Dest) == NULL ) - { - throw Exception::NotPcsxPlugin( pid ); - } - current++; - } -} - -void PluginManager::BindOptional( PluginsEnum_t pid ) -{ - const LegacyApi_OptMethod* current = s_MethMessOpt[pid]; - const wxDynamicLibrary& lib = m_libs[pid]; - - while( current->MethodName != NULL ) - { - *(current->Dest) = (VoidMethod*)lib.GetSymbol( current->GetMethodName() ); - current++; - } -} - -// Exceptions: -// FileNotFound - Thrown if one of th configured plugins doesn't exist. -// NotPcsxPlugin - Thrown if one of the configured plugins is an invalid or unsupported DLL -void PluginManager::LoadPlugins() -{ - if( m_loaded ) return; - m_loaded = true; - - for( int i=0; iFullpathTo( pid ) ); - - if( !wxFile::Exists( plugpath ) ) - throw Exception::FileNotFound( plugpath ); - - if( !m_libs[i].Load( plugpath ) ) - throw Exception::NotPcsxPlugin( plugpath ); + if( !m_info[pid].Lib.Load( folders[pid] ) ) + throw Exception::NotPcsxPlugin( folders[pid] ); // Try to enumerate the new v2.0 plugin interface first. // If that fails, fall back on the old style interface. @@ -632,45 +596,227 @@ void PluginManager::LoadPlugins() // Bind Optional Functions // (leave pointer null and do not generate error) - } + + // Hack for PAD's stupid parameter passed on Init + PADinit = (_PADinit)m_info[PluginId_PAD].CommonBindings.Init; + m_info[PluginId_PAD].CommonBindings.Init = _hack_PADinit; +} + +PluginManager::~PluginManager() +{ + Close(); + Shutdown(); + + // All library unloading done automatically. +} + +void PluginManager::BindCommon( PluginsEnum_t pid ) +{ + const LegacyApi_CommonMethod* current = s_MethMessCommon; + VoidMethod** target = (VoidMethod**)&m_info[pid].CommonBindings; + + wxDoNotLogInThisScope please; + + while( current->MethodName != NULL ) + { + *target = (VoidMethod*)m_info[pid].Lib.GetSymbol( current->GetMethodName( pid ) ); + + if( *target == NULL ) + *target = current->Fallback; + + if( *target == NULL ) + throw Exception::NotPcsxPlugin( pid ); + + target++; + current++; + } +} + +void PluginManager::BindRequired( PluginsEnum_t pid ) +{ + const LegacyApi_ReqMethod* current = s_MethMessReq[pid]; + const wxDynamicLibrary& lib = m_info[pid].Lib; + + wxDoNotLogInThisScope please; + + while( current->MethodName != NULL ) + { + *(current->Dest) = (VoidMethod*)lib.GetSymbol( current->GetMethodName() ); + + if( *(current->Dest) == NULL ) + *(current->Dest) = current->Fallback; + + if( *(current->Dest) == NULL ) + throw Exception::NotPcsxPlugin( pid ); + + current++; + } +} + +void PluginManager::BindOptional( PluginsEnum_t pid ) +{ + const LegacyApi_OptMethod* current = s_MethMessOpt[pid]; + const wxDynamicLibrary& lib = m_info[pid].Lib; + + wxDoNotLogInThisScope please; + + while( current->MethodName != NULL ) + { + *(current->Dest) = (VoidMethod*)lib.GetSymbol( current->GetMethodName() ); + current++; + } +} + +// Exceptions: +// FileNotFound - Thrown if one of the configured plugins doesn't exist. +// NotPcsxPlugin - Thrown if one of the configured plugins is an invalid or unsupported DLL + +extern bool renderswitch; +extern void spu2DMA4Irq(); +extern void spu2DMA7Irq(); +extern void spu2Irq(); + +static bool OpenPlugin_CDVD() +{ + if( CDVDapi_Plugin.open( NULL ) ) return false; + CDVDapi_Plugin.newDiskCB( cdvdNewDiskCB ); + return true; +} + +static bool OpenPlugin_GS() +{ + // Abusing the isMultiThread parameter for that so we don't need a new callback + return !GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 ); +} + +static bool OpenPlugin_PAD() +{ + return !PADopen( (void*)&pDsp ); +} + +static bool OpenPlugin_SPU2() +{ + if( SPU2open( (void*)&pDsp ) ) return false; + + SPU2irqCallback( spu2Irq, spu2DMA4Irq, spu2DMA7Irq ); + if( SPU2setDMABaseAddr != NULL ) SPU2setDMABaseAddr((uptr)psxM); + if( SPU2setClockPtr != NULL ) SPU2setClockPtr(&psxRegs.cycle); + return true; +} + +static bool OpenPlugin_DEV9() +{ + dev9Handler = NULL; + + if( DEV9open( (void*)&pDsp ) ) return false; + DEV9irqCallback( dev9Irq ); + dev9Handler = DEV9irqHandler(); + return true; +} + +static bool OpenPlugin_USB() +{ + usbHandler = NULL; + + if( USBopen( (void*)&pDsp ) ) return false; + USBirqCallback( usbIrq ); + usbHandler = USBirqHandler(); + if( USBsetRAM != NULL ) + USBsetRAM(psxM); + return true; +} + +static bool OpenPlugin_FW() +{ + if( FWopen( (void*)&pDsp ) ) return false; + FWirqCallback( fwIrq ); + return true; } void PluginManager::Open( PluginsEnum_t pid ) { + if( m_info[pid].IsOpened ) return; + // Each Open needs to be called explicitly. >_< + + bool result = true; + switch( pid ) + { + case PluginId_CDVD: result = OpenPlugin_CDVD(); break; + case PluginId_GS: result = OpenPlugin_GS(); break; + case PluginId_PAD: result = OpenPlugin_PAD(); break; + case PluginId_SPU2: result = OpenPlugin_SPU2(); break; + case PluginId_USB: result = OpenPlugin_USB(); break; + case PluginId_FW: result = OpenPlugin_FW(); break; + case PluginId_DEV9: result = OpenPlugin_DEV9(); break; + } + if( !result ) + throw Exception::PluginFailure( tbl_PluginInfo[pid].shortname, wxLt("%s plugin failed to open.") ); + + m_info[pid].IsOpened = true; } void PluginManager::Close( PluginsEnum_t pid ) { - if( m_IsOpened[pid] ) + if( !m_info[pid].IsOpened ) return; + + m_info[pid].IsOpened = false; + m_info[pid].CommonBindings.Close(); +} + +void PluginManager::Close() +{ + const PluginInfo* pi = tbl_PluginInfo-1; + while( ++pi, pi->shortname != NULL ) + Close( pi->id ); +} + +// Initializes all plugins. Plugin initialization should be done once for every new emulation +// session. During a session emulation can be paused/resumed using Open/Close, and should be +// terminated using Shutdown(). +// +// In a purist emulation sense, Init() and Shutdown() should only ever need be called for when +// the PS2's hardware has received a *full* hard reset. Soft resets typically should rely on +// the PS2's bios/kernel to re-initialize hardware on the fly. +// +void PluginManager::Init() +{ + const PluginInfo* pi = tbl_PluginInfo-1; + while( ++pi, pi->shortname != NULL ) { - m_IsOpened[pid] = false; - m_CommonBindings[pid].Close(); + const PluginsEnum_t pid = pi->id; + + if( m_info[pid].IsInitialized ) continue; + m_info[pid].IsInitialized = true; + if( 0 != m_info[pid].CommonBindings.Init() ) + throw Exception::PluginFailure( tbl_PluginInfo[pid].shortname, wxLt( "%s plugin: Initialization Failure" ) ); } } -void PluginManager::Init( PluginsEnum_t pid ) +// Shuts down all plugins. Plugins are closed first, if necessary. +// +// In a purist emulation sense, Init() and Shutdown() should only ever need be called for when +// the PS2's hardware has received a *full* hard reset. Soft resets typically should rely on +// the PS2's bios/kernel to re-initialize hardware on the fly. +// +void PluginManager::Shutdown() { - if( !m_IsInitialized[pid] ) - { - m_IsInitialized[pid] = true; - m_CommonBindings[pid].Init(); - } -} + Close(); -void PluginManager::Shutdown( PluginsEnum_t pid ) -{ - if( m_IsInitialized[pid] ) + const PluginInfo* pi = tbl_PluginInfo-1; + while( ++pi, pi->shortname != NULL ) { - m_IsInitialized[pid] = false; - m_CommonBindings[pid].Shutdown(); + const PluginsEnum_t pid = pi->id; + if( !m_info[pid].IsInitialized ) continue; + m_info[pid].IsInitialized = false; + m_info[pid].CommonBindings.Shutdown(); } } void PluginManager::Freeze( PluginsEnum_t pid, int mode, freezeData* data ) { - m_CommonBindings[pid].Freeze( mode, data ); + m_info[pid].CommonBindings.Freeze( mode, data ); } // ---------------------------------------------------------------------------- @@ -687,7 +833,7 @@ void PluginManager::Freeze( PluginsEnum_t pid, SaveState& state ) } else { - state.FreezePlugin( tbl_PluginInfo[pid].shortname, m_CommonBindings[pid].Freeze ); + state.FreezePlugin( tbl_PluginInfo[pid].shortname, m_info[pid].CommonBindings.Freeze ); } } @@ -702,585 +848,96 @@ void PluginManager::Freeze( PluginsEnum_t pid, SaveState& state ) // void PluginManager::Freeze( SaveState& state ) { - for( int i=0; ishortname != NULL ) + Freeze( pi->id, state ); +} + +// Creates an instance of a plugin manager, using the specified plugin filenames for sources. +// Impl Note: Have to use this stupid effing 'friend' declaration because static members of +// classes can't access their own protected members. W-T-F? +// +PluginManager* PluginManager_Create( const wxString (&folders)[PluginId_Count] ) +{ + PluginManager* retval = new PluginManager( folders ); + retval->Init(); + return retval; +} + +PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] ) +{ + wxString passins[PluginId_Count]; + + const PluginInfo* pi = tbl_PluginInfo-1; + while( ++pi, pi->shortname != NULL ) + passins[pi->id] = folders[pi->id]; + + return PluginManager_Create( passins ); +} + +void LoadPlugins() +{ + wxString passins[PluginId_Count]; + + const PluginInfo* pi = tbl_PluginInfo-1; + while( ++pi, pi->shortname != NULL ) + passins[pi->id] = g_Conf->FullpathTo( pi->id ); + + g_plugins = PluginManager_Create( passins ); } void InitPlugins() { - /*if (plugins_initialized) return; + if( g_plugins == NULL ) + LoadPlugins(); - // Ensure plugins have been loaded.... - LoadPlugins();*/ - - //if( !plugins_loaded ) throw Exception::InvalidOperation( "Bad coder mojo - InitPlugins called prior to plugins having been loaded." ); - - /*if (ReportError(GSinit(), "GSinit")) return -1; - if (ReportError(PAD1init(1), "PAD1init")) return -1; - if (ReportError(PAD2init(2), "PAD2init")) return -1; - if (ReportError(SPU2init(), "SPU2init")) return -1; - - if (ReportError(DoCDVDinit(), "CDVDinit")) return -1; - - if (ReportError(DEV9init(), "DEV9init")) return -1; - if (ReportError(USBinit(), "USBinit")) return -1; - if (ReportError(FWinit(), "FWinit")) return -1; - - only_loading_elf = false; - plugins_initialized = true; - return 0;*/ + g_plugins->Init(); } +// All plugins except the CDVD are opened here. The CDVD must be opened manually by +// the GUI, depending on the user's menu/config in use. +// +// Exceptions: +// PluginFailure - if any plugin fails to initialize or open. +// ThreadCreationError - If the MTGS thread fails to be created. +// void OpenPlugins() { - /*if (!plugins_initialized) - { - if( InitPlugins() == -1 ) return -1; - }*/ + if( g_plugins == NULL ) + InitPlugins(); - /*if ((!OpenCDVD(pTitleFilename)) || (!OpenGS()) || (!OpenPAD1()) || (!OpenPAD2()) || - (!OpenSPU2()) || (!OpenDEV9()) || (!OpenUSB()) || (!OpenFW())) - return -1; + mtgsOpen(); - if (!only_loading_elf) cdvdDetectDisk(); - - return 0;*/ + const PluginInfo* pi = tbl_PluginInfo-1; + while( ++pi, pi->shortname != NULL ) + g_plugins->Open( pi->id ); } void ClosePlugins( bool closegs ) { + if( g_plugins == NULL ) return; + safe_delete( mtgsThread ); + + const PluginInfo* pi = tbl_PluginInfo-1; + while( ++pi, pi->shortname != NULL ) + g_plugins->Close( pi->id ); } void ShutdownPlugins() { + if( g_plugins == NULL ) return; + ClosePlugins( true ); + g_plugins->Shutdown(); } -void CloseGS() +void ReleasePlugins() { + safe_delete( g_plugins ); } - #ifdef _not_wxWidgets_Land_ -namespace PluginTypes -{ - enum PluginTypes - { - GS = 0, - PAD, - PAD1, - PAD2, - SPU2, - CDVD, - DEV9, - USB, - FW - }; -} - -int PS2E_LT[9] = { -PS2E_LT_GS, -PS2E_LT_PAD,PS2E_LT_PAD, PS2E_LT_PAD, -PS2E_LT_SPU2, -PS2E_LT_CDVD, -PS2E_LT_DEV9, -PS2E_LT_USB, -PS2E_LT_FW}; - -int PS2E_VERSION[9] = { -PS2E_GS_VERSION, -PS2E_PAD_VERSION,PS2E_PAD_VERSION, PS2E_PAD_VERSION, -PS2E_SPU2_VERSION, -PS2E_CDVD_VERSION, -PS2E_DEV9_VERSION, -PS2E_USB_VERSION, -PS2E_FW_VERSION}; - -#define Sfy(x) #x -#define Strfy(x) Sfy(x) -#define MapSymbolVarType(var,type,name) var = (type)SysLoadSym(drv,Strfy(name)) -#define MapSymbolVar(var,name) MapSymbolVarType(var,_##name,name) -#define MapSymbolVar_Fallback(var,name,fallback) if((MapSymbolVar(var,name))==NULL) var = fallback -#define MapSymbolVar_Error(var,name) if((MapSymbolVar(var,name))==NULL) \ -{ \ - const char* errString = SysLibError(); \ - Msgbox::Alert("%s: Error loading %hs: %s", params &filename, #name, errString); \ - return -1; \ -} - -#define MapSymbol(name) MapSymbolVar(name,name) -#define MapSymbol_Fallback(name,fallback) MapSymbolVar_Fallback(name,name,fallback) -#define MapSymbol_Error(name) MapSymbolVar_Error(name,name) - -#define MapSymbol2(base,name) MapSymbolVar(base##_plugin.name,base##name) -#define MapSymbol2_Fallback(base,name,fallback) MapSymbolVar_Fallback(base##_plugin.name,base##name,fallback) -#define MapSymbol2_Error(base,name) MapSymbolVar_Error(base##_plugin.name,base##name) - -// for pad1/2 -#define MapSymbolPAD(var,name) MapSymbolVar(var##name,PAD##name) -#define MapSymbolPAD_Fallback(var,name) if((MapSymbolVarType(var##name,_PAD##name,PAD##name))==NULL) var##name = var##_##name -#define MapSymbolPAD_Error(var,name) MapSymbolVar_Error(var##name,PAD##name) - -void *GSplugin; - -static int _TestPS2Esyms(void* drv, int type, int expected_version, const wxString& filename) -{ - _PS2EgetLibType PS2EgetLibType; - _PS2EgetLibVersion2 PS2EgetLibVersion2; - _PS2EgetLibName PS2EgetLibName; - - MapSymbol_Error(PS2EgetLibType); - MapSymbol_Error(PS2EgetLibVersion2); - MapSymbol_Error(PS2EgetLibName); - - int actual_version = ((PS2EgetLibVersion2(type) >> 16)&0xff); - - if( actual_version != expected_version) { - Msgbox::Alert("Can't load '%s', wrong PS2E version (%x != %x)", params filename.c_str(), actual_version, expected_version); - return -1; - } - - return 0; -} - -static __forceinline bool TestPS2Esyms(void* &drv, PluginTypes::PluginTypes type, const string& filename) -{ - if (_TestPS2Esyms(drv, PS2E_LT[type],PS2E_VERSION[type],filename) < 0) return false; - return true; -} - -s32 CALLBACK GS_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK GS_keyEvent(keyEvent *ev) {} -void CALLBACK GS_makeSnapshot(const char *path) {} -void CALLBACK GS_irqCallback(void (*callback)()) {} -void CALLBACK GS_configure() {} -void CALLBACK GS_about() {} -s32 CALLBACK GS_test() { return 0; } - -int LoadGSplugin(const wxString& filename) -{ - void *drv; - - GSplugin = SysLoadLibrary(filename.c_str()); - if (GSplugin == NULL) { Msgbox::Alert ("Could Not Load GS Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = GSplugin; - if (!TestPS2Esyms(drv, PluginTypes::GS, filename)) return -1; - MapSymbol_Error(GSinit); - MapSymbol_Error(GSshutdown); - MapSymbol_Error(GSopen); - MapSymbol_Error(GSclose); - MapSymbol_Error(GSgifTransfer1); - MapSymbol_Error(GSgifTransfer2); - MapSymbol_Error(GSgifTransfer3); - MapSymbol_Error(GSreadFIFO); - MapSymbol(GSgetLastTag); - MapSymbol(GSreadFIFO2); // optional - MapSymbol_Error(GSvsync); - - MapSymbol_Fallback(GSkeyEvent,GS_keyEvent); - MapSymbol(GSchangeSaveState); - MapSymbol(GSgifSoftReset); - MapSymbol_Fallback(GSmakeSnapshot,GS_makeSnapshot); - MapSymbol_Fallback(GSirqCallback,GS_irqCallback); - MapSymbol_Fallback(GSprintf,GS_printf); - MapSymbol_Error(GSsetBaseMem); - MapSymbol(GSsetGameCRC); - MapSymbol_Error(GSreset); - MapSymbol_Error(GSwriteCSR); - MapSymbol(GSmakeSnapshot2); - MapSymbol(GSgetDriverInfo); - - MapSymbol(GSsetFrameSkip); - MapSymbol(GSsetFrameLimit); - MapSymbol(GSsetupRecording); - -#ifdef _WIN32 - MapSymbol(GSsetWindowInfo); -#endif - MapSymbol_Fallback(GSfreeze,GS_freeze); - MapSymbol_Fallback(GSconfigure,GS_configure); - MapSymbol_Fallback(GSabout,GS_about); - MapSymbol_Fallback(GStest,GS_test); - - return 0; -} - -void *PAD1plugin; - -void CALLBACK PAD1_configure() {} -void CALLBACK PAD1_about() {} -s32 CALLBACK PAD1_test() { return 0; } -s32 CALLBACK PAD1_freeze(int mode, freezeData *data) { if (mode == FREEZE_SIZE) data->size = 0; return 0; } -s32 CALLBACK PAD1_setSlot(u8 port, u8 slot) { return slot == 1; } -s32 CALLBACK PAD1_queryMtap(u8 port) { return 0; } - -int LoadPAD1plugin(const wxString& filename) { - void *drv; - - PAD1plugin = SysLoadLibrary(filename.c_str()); - if (PAD1plugin == NULL) { Msgbox::Alert("Could Not Load PAD1 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = PAD1plugin; - if (!TestPS2Esyms(drv, PluginTypes::PAD, filename)) return -1; - MapSymbolPAD_Error(PAD1,init); - MapSymbolPAD_Error(PAD1,shutdown); - MapSymbolPAD_Error(PAD1,open); - MapSymbolPAD_Error(PAD1,close); - MapSymbolPAD_Error(PAD1,keyEvent); - MapSymbolPAD_Error(PAD1,startPoll); - MapSymbolPAD_Error(PAD1,poll); - MapSymbolPAD_Error(PAD1,query); - MapSymbolPAD(PAD1,update); - - MapSymbolPAD(PAD1,gsDriverInfo); - MapSymbolPAD_Fallback(PAD1,configure); - MapSymbolPAD_Fallback(PAD1,about); - MapSymbolPAD_Fallback(PAD1,test); - MapSymbolPAD_Fallback(PAD1,freeze); - MapSymbolPAD_Fallback(PAD1,setSlot); - MapSymbolPAD_Fallback(PAD1,queryMtap); - - return 0; -} - -void *PAD2plugin; - -void CALLBACK PAD2_configure() {} -void CALLBACK PAD2_about() {} -s32 CALLBACK PAD2_test() { return 0; } -s32 CALLBACK PAD2_freeze(int mode, freezeData *data) { if (mode == FREEZE_SIZE) data->size = 0; return 0; } -s32 CALLBACK PAD2_setSlot(u8 port, u8 slot) { return slot == 1; } -s32 CALLBACK PAD2_queryMtap(u8 port) { return 0; } - -int LoadPAD2plugin(const wxString& filename) { - void *drv; - - PAD2plugin = SysLoadLibrary(filename.c_str()); - if (PAD2plugin == NULL) { Msgbox::Alert("Could Not Load PAD2 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = PAD2plugin; - if (!TestPS2Esyms(drv, PluginTypes::PAD, filename)) return -1; - MapSymbolPAD_Error(PAD2,init); - MapSymbolPAD_Error(PAD2,shutdown); - MapSymbolPAD_Error(PAD2,open); - MapSymbolPAD_Error(PAD2,close); - MapSymbolPAD_Error(PAD2,keyEvent); - MapSymbolPAD_Error(PAD2,startPoll); - MapSymbolPAD_Error(PAD2,poll); - MapSymbolPAD_Error(PAD2,query); - MapSymbolPAD(PAD2,update); - - MapSymbolPAD(PAD2,gsDriverInfo); - MapSymbolPAD_Fallback(PAD2,configure); - MapSymbolPAD_Fallback(PAD2,about); - MapSymbolPAD_Fallback(PAD2,test); - MapSymbolPAD_Fallback(PAD2,freeze); - MapSymbolPAD_Fallback(PAD2,setSlot); - MapSymbolPAD_Fallback(PAD2,queryMtap); - - return 0; -} - -void *SPU2plugin; - -s32 CALLBACK SPU2_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK SPU2_configure() {} -void CALLBACK SPU2_about() {} -s32 CALLBACK SPU2_test() { return 0; } - -int LoadSPU2plugin(const wxString& filename) { - void *drv; - - SPU2plugin = SysLoadLibrary(filename.c_str()); - if (SPU2plugin == NULL) { Msgbox::Alert("Could Not Load SPU2 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = SPU2plugin; - if (!TestPS2Esyms(drv, PluginTypes::SPU2, filename)) return -1; - MapSymbol_Error(SPU2init); - MapSymbol_Error(SPU2shutdown); - MapSymbol_Error(SPU2open); - MapSymbol_Error(SPU2close); - MapSymbol_Error(SPU2write); - MapSymbol_Error(SPU2read); - MapSymbol_Error(SPU2readDMA4Mem); - MapSymbol_Error(SPU2writeDMA4Mem); - MapSymbol_Error(SPU2interruptDMA4); - MapSymbol_Error(SPU2readDMA7Mem); - MapSymbol_Error(SPU2writeDMA7Mem); - MapSymbol_Error(SPU2interruptDMA7); - MapSymbol(SPU2setDMABaseAddr); - MapSymbol_Error(SPU2ReadMemAddr); - MapSymbol_Error(SPU2WriteMemAddr); - MapSymbol_Error(SPU2irqCallback); - - MapSymbol(SPU2setClockPtr); - - MapSymbol(SPU2setupRecording); - - MapSymbol_Fallback(SPU2freeze,SPU2_freeze); - MapSymbol_Fallback(SPU2configure,SPU2_configure); - MapSymbol_Fallback(SPU2about,SPU2_about); - MapSymbol_Fallback(SPU2test,SPU2_test); - MapSymbol(SPU2async); - - return 0; -} - -void *CDVDplugin; - - -int LoadCDVDplugin(const wxString& filename) { - void *drv; - - CDVDplugin = SysLoadLibrary(filename.c_str()); - if (CDVDplugin == NULL) { Msgbox::Alert("Could Not Load CDVD Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = CDVDplugin; - if (!TestPS2Esyms(drv, PluginTypes::CDVD, filename)) return -1; - MapSymbol2_Error(CDVD,init); - MapSymbol2_Error(CDVD,shutdown); - MapSymbol2_Error(CDVD,open); - MapSymbol2_Error(CDVD,close); - MapSymbol2_Error(CDVD,readTrack); - MapSymbol2_Error(CDVD,getBuffer); - MapSymbol2_Error(CDVD,readSubQ); - MapSymbol2_Error(CDVD,getTN); - MapSymbol2_Error(CDVD,getTD); - MapSymbol2_Error(CDVD,getTOC); - MapSymbol2_Error(CDVD,getDiskType); - MapSymbol2_Error(CDVD,getTrayStatus); - MapSymbol2_Error(CDVD,ctrlTrayOpen); - MapSymbol2_Error(CDVD,ctrlTrayClose); - - MapSymbol2_Fallback(CDVD,configure,CDVD_configure); - MapSymbol2_Fallback(CDVD,about,CDVD_about); - MapSymbol2_Fallback(CDVD,test,CDVD_test); - MapSymbol2_Fallback(CDVD,newDiskCB,CDVD_newDiskCB); - - MapSymbol2_Fallback(CDVD,readSector,CDVD_readSector); - MapSymbol2_Fallback(CDVD,getBuffer2,CDVD_getBuffer2); - MapSymbol2_Fallback(CDVD,getDualInfo,CDVD_getDualInfo); - - CDVD->initCount = &cdvdInitCount; - cdvdInitCount=0; - - return 0; -} - -void *DEV9plugin; - -s32 CALLBACK DEV9_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK DEV9_configure() {} -void CALLBACK DEV9_about() {} -s32 CALLBACK DEV9_test() { return 0; } - -int LoadDEV9plugin(const wxString& filename) { - void *drv; - - DEV9plugin = SysLoadLibrary(filename.c_str()); - if (DEV9plugin == NULL) { Msgbox::Alert("Could Not Load DEV9 Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = DEV9plugin; - if (!TestPS2Esyms(drv, PluginTypes::DEV9, filename)) return -1; - MapSymbol_Error(DEV9init); - MapSymbol_Error(DEV9shutdown); - MapSymbol_Error(DEV9open); - MapSymbol_Error(DEV9close); - MapSymbol_Error(DEV9read8); - MapSymbol_Error(DEV9read16); - MapSymbol_Error(DEV9read32); - MapSymbol_Error(DEV9write8); - MapSymbol_Error(DEV9write16); - MapSymbol_Error(DEV9write32); - MapSymbol_Error(DEV9readDMA8Mem); - MapSymbol_Error(DEV9writeDMA8Mem); - MapSymbol_Error(DEV9irqCallback); - MapSymbol_Error(DEV9irqHandler); - - MapSymbol_Fallback(DEV9freeze,DEV9_freeze); - MapSymbol_Fallback(DEV9configure,DEV9_configure); - MapSymbol_Fallback(DEV9about,DEV9_about); - MapSymbol_Fallback(DEV9test,DEV9_test); - - return 0; -} - -void *USBplugin; - -s32 CALLBACK USB_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK USB_configure() {} -void CALLBACK USB_about() {} -s32 CALLBACK USB_test() { return 0; } - -int LoadUSBplugin(const wxString& filename) { - void *drv; - - USBplugin = SysLoadLibrary(filename.c_str()); - if (USBplugin == NULL) { Msgbox::Alert("Could Not Load USB Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = USBplugin; - if (!TestPS2Esyms(drv, PluginTypes::USB, filename)) return -1; - MapSymbol_Error(USBinit); - MapSymbol_Error(USBshutdown); - MapSymbol_Error(USBopen); - MapSymbol_Error(USBclose); - MapSymbol_Error(USBread8); - MapSymbol_Error(USBread16); - MapSymbol_Error(USBread32); - MapSymbol_Error(USBwrite8); - MapSymbol_Error(USBwrite16); - MapSymbol_Error(USBwrite32); - MapSymbol_Error(USBirqCallback); - MapSymbol_Error(USBirqHandler); - MapSymbol_Error(USBsetRAM); - - MapSymbol(USBasync); - - MapSymbol_Fallback(USBfreeze,USB_freeze); - MapSymbol_Fallback(USBconfigure,USB_configure); - MapSymbol_Fallback(USBabout,USB_about); - MapSymbol_Fallback(USBtest,USB_test); - - return 0; -} -void *FWplugin; - -s32 CALLBACK FW_freeze(int mode, freezeData *data) { data->size = 0; return 0; } -void CALLBACK FW_configure() {} -void CALLBACK FW_about() {} -s32 CALLBACK FW_test() { return 0; } - -int LoadFWplugin(const wxString& filename) { - void *drv; - - FWplugin = SysLoadLibrary(filename.c_str()); - if (FWplugin == NULL) { Msgbox::Alert("Could Not Load FW Plugin '%hs': %s", params &filename, SysLibError()); return -1; } - drv = FWplugin; - if (!TestPS2Esyms(drv, PluginTypes::FW, filename)) return -1; - MapSymbol_Error(FWinit); - MapSymbol_Error(FWshutdown); - MapSymbol_Error(FWopen); - MapSymbol_Error(FWclose); - MapSymbol_Error(FWread32); - MapSymbol_Error(FWwrite32); - MapSymbol_Error(FWirqCallback); - - MapSymbol_Fallback(FWfreeze,FW_freeze); - MapSymbol_Fallback(FWconfigure,FW_configure); - MapSymbol_Fallback(FWabout,FW_about); - MapSymbol_Fallback(FWtest,FW_test); - - return 0; -} - -struct PluginOpenStatusFlags -{ - u8 GS : 1 - , CDVD : 1 - , DEV9 : 1 - , USB : 1 - , SPU2 : 1 - , PAD1 : 1 - , PAD2 : 1 - , FW : 1; - -}; - -static PluginOpenStatusFlags OpenStatus = {0}; - -static bool plugins_loaded = false; -static bool plugins_initialized = false; -static bool only_loading_elf = false; - -int LoadPlugins() -{ - if (plugins_loaded) return 0; - - if (LoadGSplugin( Path::Combine( Config.Paths.Plugins, Config.Plugins.GS )) == -1) return -1; - if (LoadPAD1plugin( Path::Combine( Config.Paths.Plugins, Config.Plugins.PAD1 )) == -1) return -1; - if (LoadPAD2plugin( Path::Combine( Config.Paths.Plugins, Config.Plugins.PAD2 )) == -1) return -1; - if (LoadSPU2plugin( Path::Combine( Config.Paths.Plugins, Config.Plugins.SPU2 )) == -1) return -1; - if (LoadCDVDplugin( Path::Combine( Config.Paths.Plugins, Config.Plugins.CDVD )) == -1) return -1; - if (LoadDEV9plugin( Path::Combine( Config.Paths.Plugins, Config.Plugins.DEV9 )) == -1) return -1; - if (LoadUSBplugin( Path::Combine( Config.Paths.Plugins, Config.Plugins.USB )) == -1) return -1; - if (LoadFWplugin( Path::Combine( Config.Paths.Plugins, Config.Plugins.FW )) == -1) return -1; - - plugins_loaded = true; - - return 0; -} - -bool ReportError(int err, const char *str) -{ - if (err != 0) - { - Msgbox::Alert("%s error: %d", params str, err); - return true; - } - return false; -} - -bool ReportError2(int err, const char *str) -{ - if (err != 0) - { - Msgbox::Alert("Error Opening %s Plugin", params str, err); - return true; - } - return false; -} - -int InitPlugins() -{ - if (plugins_initialized) return 0; - - // Ensure plugins have been loaded.... - if (LoadPlugins() == -1) return -1; - - //if( !plugins_loaded ) throw Exception::InvalidOperation( "Bad coder mojo - InitPlugins called prior to plugins having been loaded." ); - - if (ReportError(GSinit(), "GSinit")) return -1; - if (ReportError(PAD1init(1), "PAD1init")) return -1; - if (ReportError(PAD2init(2), "PAD2init")) return -1; - if (ReportError(SPU2init(), "SPU2init")) return -1; - - if (ReportError(DoCDVDinit(), "CDVDinit")) return -1; - - if (ReportError(DEV9init(), "DEV9init")) return -1; - if (ReportError(USBinit(), "USBinit")) return -1; - if (ReportError(FWinit(), "FWinit")) return -1; - - only_loading_elf = false; - plugins_initialized = true; - return 0; -} - -void ShutdownPlugins() -{ - if (!plugins_initialized) return; - - mtgsWaitGS(); - ClosePlugins( true ); - - if (GSshutdown != NULL) GSshutdown(); - - if (PAD1shutdown != NULL) PAD1shutdown(); - if (PAD2shutdown != NULL) PAD2shutdown(); - - if (SPU2shutdown != NULL) SPU2shutdown(); - - //if (CDVDshutdown != NULL) CDVDshutdown(); - DoCDVDshutdown(); - - // safety measures, in case ISO is currently loaded. - if(cdvdInitCount>0) - CDVD_plugin.shutdown(); - - if (DEV9shutdown != NULL) DEV9shutdown(); - if (USBshutdown != NULL) USBshutdown(); - if (FWshutdown != NULL) FWshutdown(); - - plugins_initialized = false; -} - -extern void spu2DMA4Irq(); -extern void spu2DMA7Irq(); -extern void spu2Irq(); bool OpenGS() { @@ -1499,43 +1156,6 @@ void ClosePlugins( bool closegs ) CLOSE_PLUGIN( SPU2 ); } -//used to close the GS plugin window and pads, to switch gsdx renderer -void CloseGS() -{ - if( CHECK_MULTIGS ) mtgsWaitGS(); - - CLOSE_PLUGIN( PAD1 ); - CLOSE_PLUGIN( PAD2 ); - - if( OpenStatus.GS ) - { - gsClose(); - OpenStatus.GS = false; - } -} - -void ReleasePlugins() -{ - if (!plugins_loaded) return; - - if ((GSplugin == NULL) || (PAD1plugin == NULL) || (PAD2plugin == NULL) || - (SPU2plugin == NULL) || (CDVDplugin == NULL) || (DEV9plugin == NULL) || - (USBplugin == NULL) || (FWplugin == NULL)) return; - - ShutdownPlugins(); - - SysCloseLibrary(GSplugin); GSplugin = NULL; - SysCloseLibrary(PAD1plugin); PAD1plugin = NULL; - SysCloseLibrary(PAD2plugin); PAD2plugin = NULL; - SysCloseLibrary(SPU2plugin); SPU2plugin = NULL; - SysCloseLibrary(CDVDplugin); CDVDplugin = NULL; - SysCloseLibrary(DEV9plugin); DEV9plugin = NULL; - SysCloseLibrary(USBplugin); USBplugin = NULL; - SysCloseLibrary(FWplugin); FWplugin = NULL; - - plugins_loaded = false; -} - void PluginsResetGS() { // PADs are tied to the GS window, so shut them down together with the GS. diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index 9738d7870f..e0b08106ea 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -16,8 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#ifndef __PLUGINS_H__ -#define __PLUGINS_H__ +#pragma once #define PLUGINtypedefs #define PLUGINfuncs @@ -31,6 +30,11 @@ struct PluginInfo PluginsEnum_t id; int typemask; int version; // minimum version required / supported + + wxString GetShortname() const + { + return wxString::FromUTF8( shortname ); + } }; namespace Exception @@ -60,6 +64,17 @@ struct LegacyPluginAPI_Common s32 (CALLBACK* Test)(); void (CALLBACK* Configure)(); void (CALLBACK* About)(); + + LegacyPluginAPI_Common() : + Init ( NULL ) + , Close ( NULL ) + , Shutdown( NULL ) + , Freeze ( NULL ) + , Test ( NULL ) + , Configure( NULL ) + , About ( NULL ) + { + } }; class SaveState; @@ -68,39 +83,52 @@ class SaveState; // class PluginManager { + DeclareNoncopyableObject( PluginManager ) + protected: + struct PluginStatus_t + { + bool IsInitialized; + bool IsOpened; + wxString Filename; + + LegacyPluginAPI_Common CommonBindings; + wxDynamicLibrary Lib; + + PluginStatus_t() : + IsInitialized( false ) + , IsOpened( false ) + , Filename() + , CommonBindings() + , Lib() + { + } + }; + bool m_initialized; - bool m_loaded; - bool m_IsInitialized[PluginId_Count]; - bool m_IsOpened[PluginId_Count]; - - LegacyPluginAPI_Common m_CommonBindings[PluginId_Count]; - wxDynamicLibrary m_libs[PluginId_Count]; + PluginStatus_t m_info[PluginId_Count]; public: ~PluginManager(); - PluginManager() : - m_initialized( false ) - , m_loaded( false ) - { - memzero_obj( m_IsInitialized ); - memzero_obj( m_IsOpened ); - } - void LoadPlugins(); - void UnloadPlugins(); - - void Init( PluginsEnum_t pid ); - void Shutdown( PluginsEnum_t pid ); + void Init(); + void Shutdown(); void Open( PluginsEnum_t pid ); void Close( PluginsEnum_t pid ); + void Close(); void Freeze( PluginsEnum_t pid, int mode, freezeData* data ); void Freeze( PluginsEnum_t pid, SaveState& state ); void Freeze( SaveState& state ); + friend PluginManager* PluginManager_Create( const wxString (&folders)[PluginId_Count] ); + friend PluginManager* PluginManager_Create( const wxChar* (&folders)[PluginId_Count] ); + protected: + // Internal constructor, should be called by Create only. + PluginManager( const wxString (&folders)[PluginId_Count] ); + void BindCommon( PluginsEnum_t pid ); void BindRequired( PluginsEnum_t pid ); void BindOptional( PluginsEnum_t pid ); @@ -112,16 +140,12 @@ extern PluginManager* g_plugins; extern int EnumeratePluginsInFolder( const wxDirName& searchPath, wxArrayString* dest ); -void LoadPlugins(); -void ReleasePlugins(); +extern void LoadPlugins(); +extern void ReleasePlugins(); -void OpenPlugins(); -void ClosePlugins( bool closegs ); -void CloseGS(); +extern void InitPlugins(); +extern void ShutdownPlugins(); -void InitPlugins(); -void ShutdownPlugins(); +extern void OpenPlugins(); +extern void ClosePlugins( bool closegs ); -void PluginsResetGS(); - -#endif /* __PLUGINS_H__ */ diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index d1cb5f5093..1c3afe1b6d 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -361,7 +361,7 @@ u32 g_nextBranchCycle = 0; // Shared portion of the branch test, called from both the Interpreter // and the recompiler. (moved here to help alleviate redundant code) -__forceinline bool _cpuBranchTest_Shared() +__forceinline void _cpuBranchTest_Shared() { eeEventTestIsActive = true; g_nextBranchCycle = cpuRegs.cycle + eeWaitCycles; @@ -373,12 +373,11 @@ __forceinline bool _cpuBranchTest_Shared() iopBranchAction = true; // ---- Counters ------------- - bool vsyncEvent = false; rcntUpdate_hScanline(); if( cpuTestCycle( nextsCounter, nextCounter ) ) { - vsyncEvent = rcntUpdate(); + rcntUpdate(); _cpuTestPERF(); } @@ -490,8 +489,6 @@ __forceinline bool _cpuBranchTest_Shared() TESTINT(30, intcInterrupt); TESTINT(31, dmacInterrupt); } - - return vsyncEvent; } __releaseinline void cpuTestINTCInts() @@ -572,8 +569,7 @@ void cpuExecuteBios() while( cpuRegs.pc != 0x00200008 && cpuRegs.pc != 0x00100008 ) { - g_nextBranchCycle = cpuRegs.cycle; - Cpu->ExecuteBlock(); + Cpu->Execute(); } g_ExecBiosHack = false; diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index a6f06bbd96..d849fe8a26 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -228,7 +228,7 @@ extern bool eeEventTestIsActive; extern u32 s_iLastCOP0Cycle; extern u32 s_iLastPERFCycle[2]; -bool intEventTest(); +void intEventTest(); void intSetBranch(); // This is a special form of the interpreter's doBranch that is run from various @@ -243,8 +243,7 @@ struct R5900cpu void (*Allocate)(); // throws exceptions on failure. void (*Reset)(); void (*Step)(); - void (*Execute)(); /* executes up to a break */ - void (*ExecuteBlock)(); + void (*Execute)(); void (*Clear)(u32 Addr, u32 Size); void (*Shutdown)(); // deallocates memory reserved by Allocate }; @@ -267,7 +266,7 @@ extern void cpuSetNextBranchDelta( s32 delta ); extern int cpuTestCycle( u32 startCycle, s32 delta ); extern void cpuSetBranch(); -extern bool _cpuBranchTest_Shared(); // for internal use by the Dynarecs and Ints inside R5900: +extern void _cpuBranchTest_Shared(); // for internal use by the Dynarecs and Ints inside R5900: extern void cpuTestINTCInts(); extern void cpuTestDMACInts(); diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index be12768db9..ea9f72efb2 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -19,6 +19,7 @@ #include "PrecompiledHeader.h" #include "App.h" #include "IniInterface.h" +#include "Plugins.h" #include @@ -266,7 +267,7 @@ namespace FilenameDefs wxFileName( L"Mcd002.ps2" ) }; - if( IsDevBuild && ((uint)slot) < 2 ) + if( IsDevBuild && ((uint)slot) >= 2 ) throw Exception::IndexBoundsFault( L"FilenameDefs::Memcard", slot, 2 ); return retval[slot]; @@ -373,6 +374,10 @@ AppConfig::AppConfig() : , EmuOptions() , m_IsLoaded( false ) { + Mcd[0].Enabled = true; + Mcd[1].Enabled = true; + Mcd[0].Filename = FilenameDefs::Memcard(0); + Mcd[1].Filename = FilenameDefs::Memcard(1); } // ------------------------------------------------------------------------ @@ -395,6 +400,17 @@ void AppConfig::LoadSaveUserMode( IniInterface& ini, const wxString& cwdhash ) ini.Flush(); } +// ------------------------------------------------------------------------ +void AppConfig::LoadSaveMemcards( IniInterface& ini ) +{ + IniScopedGroup path( ini, L"MemoryCards" ); + + ini.Entry( L"Slot1Enable", Mcd[0].Enabled, true ); + ini.Entry( L"Slot2Enable", Mcd[1].Enabled, true ); + ini.Entry( L"Slot1Filename", Mcd[0].Filename, FilenameDefs::Memcard(0) ); + ini.Entry( L"Slot2Filename", Mcd[1].Filename, FilenameDefs::Memcard(1) ); +} + // ------------------------------------------------------------------------ void AppConfig::LoadSave( IniInterface& ini ) { @@ -584,22 +600,9 @@ void AppConfig::FilenameOptions::LoadSave( IniInterface& ini ) IniScopedGroup path( ini, L"Filenames" ); static const wxFileName pc( L"Please Configure" ); - static const wxString g_PluginNames[] = - { - L"CDVD", - L"GS", - L"PAD1", - L"PAD2", - L"SPU2", - L"USB", - L"FW", - L"DEV9" - }; for( int i=0; iSetClientData( (void*)(int)tbl_PluginInfo[i].id ); + s_plugin.Add( bleh ); } m_FolderPicker.SetStaticDesc( _("Click the Browse button to select a different folder for PCSX2 plugins.") ); @@ -225,6 +231,7 @@ Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow& parent, int idealWid Connect( wxEVT_EnumeratedNext, wxCommandEventHandler( PluginSelectorPanel::OnProgress ) ); Connect( wxEVT_EnumerationFinished, wxCommandEventHandler( PluginSelectorPanel::OnEnumComplete ) ); + Connect( ButtonId_Configure, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PluginSelectorPanel::OnConfigure_Clicked ) ); } Panels::PluginSelectorPanel::~PluginSelectorPanel() @@ -239,7 +246,7 @@ void Panels::PluginSelectorPanel::Apply( AppConfig& conf ) int sel = m_ComponentBoxes.Get(i).GetSelection(); if( sel == wxNOT_FOUND ) { - wxString plugname( wxString::FromAscii( tbl_PluginInfo[i].shortname ) ); + wxString plugname( tbl_PluginInfo[i].GetShortname() ); throw Exception::CannotApplySettings( this, // English Log @@ -307,6 +314,17 @@ bool Panels::PluginSelectorPanel::ValidateEnumerationStatus() } // ------------------------------------------------------------------------ +void Panels::PluginSelectorPanel::OnConfigure_Clicked( wxCommandEvent& evt ) +{ + PluginsEnum_t pid = (PluginsEnum_t)(int)evt.GetClientData(); + + int sel = m_ComponentBoxes.Get(pid).GetSelection(); + if( sel == wxNOT_FOUND ) return; + wxDynamicLibrary dynlib( (*m_FileList)[(int)m_ComponentBoxes.Get(pid).GetClientData(sel)] ); + if( PluginConfigureFnptr configfunc = (PluginConfigureFnptr)dynlib.GetSymbol( tbl_PluginInfo[pid].GetShortname() + L"configure" ) ) + configfunc(); +} + void Panels::PluginSelectorPanel::OnEnumComplete( wxCommandEvent& evt ) { safe_delete( m_EnumeratorThread ); diff --git a/pcsx2/gui/main.cpp b/pcsx2/gui/main.cpp index c783293135..7240c351d1 100644 --- a/pcsx2/gui/main.cpp +++ b/pcsx2/gui/main.cpp @@ -150,6 +150,8 @@ bool Pcsx2App::OnInit() g_Conf = new AppConfig(); g_EmuThread = new CoreEmuThread(); + delete wxMessageOutput::Set( new wxMessageOutputDebug() ); + wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() ); // User/Admin Mode Dual Setup: diff --git a/pcsx2/ps2/CoreEmuThread.cpp b/pcsx2/ps2/CoreEmuThread.cpp index 8d4c316112..3de10bbea2 100644 --- a/pcsx2/ps2/CoreEmuThread.cpp +++ b/pcsx2/ps2/CoreEmuThread.cpp @@ -27,18 +27,23 @@ #include "R3000A.h" #include "VUmicro.h" -sptr CoreEmuThread::ExecuteTask() -{ - while( !m_Done && (m_ExecMode != ExecMode_Running) ) - { - m_ResumeEvent.Wait(); - } +static __threadlocal CoreEmuThread* tls_coreThread = NULL; +CoreEmuThread& CoreEmuThread::Get() +{ + wxASSERT_MSG( tls_coreThread != NULL, L"This function must be called from the context of a running CoreEmuThread." ); + return *tls_coreThread; +} + +void CoreEmuThread::CpuInitializeMess() +{ try { + OpenPlugins(); cpuReset(); SysClearExecutionCache(); - OpenPlugins(); + + GSsetGameCRC( ElfCRC, 0 ); if( StateRecovery::HasState() ) { @@ -69,9 +74,25 @@ sptr CoreEmuThread::ExecuteTask() { Msgbox::Alert( ex.DisplayMessage() ); } +} + +sptr CoreEmuThread::ExecuteTask() +{ + tls_coreThread = this; + + while( !m_Done && (m_ExecMode != ExecMode_Running) ) + { + m_ResumeEvent.Wait(); + } + + CpuInitializeMess(); StateCheck(); + PCSX2_MEM_PROTECT_BEGIN(); + Cpu->Execute(); + PCSX2_MEM_PROTECT_END(); + return 0; } diff --git a/pcsx2/ps2/CoreEmuThread.h b/pcsx2/ps2/CoreEmuThread.h index e1e931c40c..896ea48bf4 100644 --- a/pcsx2/ps2/CoreEmuThread.h +++ b/pcsx2/ps2/CoreEmuThread.h @@ -50,7 +50,10 @@ protected: MutexLock m_lock_elf_file; MutexLock m_lock_ExecMode; - + +public: + static CoreEmuThread& Get(); + public: CoreEmuThread() : m_ExecMode( ExecMode_Idle ) @@ -80,7 +83,9 @@ public: void Resume(); void ApplySettings( const Pcsx2Config& src ); -protected: - sptr ExecuteTask(); void StateCheck(); + +protected: + void CpuInitializeMess(); + sptr ExecuteTask(); }; diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index d67392ef38..74983d8d84 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -108,7 +108,7 @@ static u32 dumplog = 0; #define dumplog 0 #endif -static void iBranchTest(u32 newpc = 0xffffffff, bool noDispatch=false); +static void iBranchTest(u32 newpc = 0xffffffff); static void ClearRecLUT(BASEBLOCK* base, int count); static u32 eeScaleBlockCycles(); @@ -538,7 +538,9 @@ static void recShutdown( void ) void recStep( void ) { } -static __forceinline bool recEventTest() + + +static void recEventTest() { #ifdef PCSX2_DEVBUILD // dont' remove this check unless doing an official release @@ -550,13 +552,12 @@ static __forceinline bool recEventTest() assert( !g_globalXMMSaved && !g_globalMMXSaved); #endif - // Perform counters, ints, and IOP updates: - bool retval = _cpuBranchTest_Shared(); + // Perform counters, interrupts, and IOP updates: + _cpuBranchTest_Shared(); #ifdef PCSX2_DEVBUILD assert( !g_globalXMMSaved && !g_globalMMXSaved); #endif - return retval; } //////////////////////////////////////////////////// @@ -568,7 +569,7 @@ u32 g_EEDispatchTemp; // The address for all cleared blocks. It recompiles the current pc and then // dispatches to the recompiled block address. -static __declspec(naked) void JITCompile() +static __naked void JITCompile() { __asm { mov esi, dword ptr [cpuRegs.pc] @@ -582,7 +583,7 @@ static __declspec(naked) void JITCompile() } } -static __declspec(naked) void JITCompileInBlock() +static __naked void JITCompileInBlock() { __asm { jmp JITCompile @@ -601,34 +602,23 @@ static void __naked DispatcherReg() } } +// [TODO] : Replace these functions with x86Emitter-generated code and we can compound this +// function and DispatcherReg() into a fast fall-through case (removes the DispatcerReg jump +// in this function, since execution will just fall right into the DispatcherReg implementation). +// +static void __naked DispatcherEvent() +{ + __asm + { + call recEventTest; + jmp DispatcherReg; + } +} + void recExecute() { // Optimization note : Compared pushad against manually pushing the regs one-by-one. // Manually pushing is faster, especially on Core2's and such. :) - do - { - g_EEFreezeRegs = true; - __asm - { - push ebx - push esi - push edi - push ebp - - call DispatcherReg - - pop ebp - pop edi - pop esi - pop ebx - } - g_EEFreezeRegs = false; - } - while( !recEventTest() ); -} - -static void recExecuteBlock() -{ g_EEFreezeRegs = true; __asm { @@ -638,14 +628,13 @@ static void recExecuteBlock() push ebp call DispatcherReg - + pop ebp pop edi pop esi pop ebx } g_EEFreezeRegs = false; - recEventTest(); } #else // _MSC_VER @@ -654,31 +643,6 @@ __forceinline void recExecute() { // Optimization note : Compared pushad against manually pushing the regs one-by-one. // Manually pushing is faster, especially on Core2's and such. :) - do { - g_EEFreezeRegs = true; - __asm__ - ( - ".intel_syntax noprefix\n" - "push ebx\n" - "push esi\n" - "push edi\n" - "push ebp\n" - - "call DispatcherReg\n" - - "pop ebp\n" - "pop edi\n" - "pop esi\n" - "pop ebx\n" - ".att_syntax\n" - ); - g_EEFreezeRegs = false; - } - while( !recEventTest() ); -} - -static void recExecuteBlock() -{ g_EEFreezeRegs = true; __asm__ ( @@ -689,7 +653,7 @@ static void recExecuteBlock() "push ebp\n" "call DispatcherReg\n" - + "pop ebp\n" "pop edi\n" "pop esi\n" @@ -697,8 +661,8 @@ static void recExecuteBlock() ".att_syntax\n" ); g_EEFreezeRegs = false; - recEventTest(); } + #endif namespace R5900 { @@ -1038,10 +1002,10 @@ static u32 eeScaleBlockCycles() // jump is assumed to be static, in which case the block will be "hardlinked" after // the first time it's dispatched. // -// noDispatch - When set true, the jump to Dispatcher. Used by the recs +// noDispatch - When set true, then jump to Dispatcher. Used by the recs // for blocks which perform exception checks without branching (it's enabled by // setting "branch = 2"; -static void iBranchTest(u32 newpc, bool noDispatch) +static void iBranchTest(u32 newpc) { if( g_ExecBiosHack ) CheckForBIOSEnd(); @@ -1050,13 +1014,46 @@ static void iBranchTest(u32 newpc, bool noDispatch) // cpuRegs.cycle += blockcycles; // if( cpuRegs.cycle > g_nextBranchCycle ) { DoEvents(); } - if (EmuConfig.Speedhacks.BIFC0 && s_nBlockFF) { + if (EmuConfig.Speedhacks.BIFC0 && s_nBlockFF) + { xMOV(eax, ptr32[&g_nextBranchCycle]); xADD(ptr32[&cpuRegs.cycle], eeScaleBlockCycles()); xCMP(eax, ptr32[&cpuRegs.cycle]); xCMOVL(eax, ptr32[&cpuRegs.cycle]); xMOV(ptr32[&cpuRegs.cycle], eax); - } else { + + xJMP( DispatcherEvent ); + } + else + { + // Optimization -- we need to load cpuRegs.pc on static block links, but doing it inside + // the if() block below (it would be paired with recBlocks.Link) breaks the sub/jcc + // pairing that modern CPUs optimize (applies to all P4+ and AMD X2+ CPUs). So let's do + // it up here instead. :D + + if( newpc != 0xffffffff ) + xMOV( ptr32[&cpuRegs.pc], newpc ); + + xMOV(eax, &cpuRegs.cycle); + xADD(eax, eeScaleBlockCycles()); + xMOV(&cpuRegs.cycle, eax); // update cycles + xSUB(eax, &g_nextBranchCycle); + + if (newpc == 0xffffffff) + { + xJNS( DispatcherEvent ); + xJMP( DispatcherReg ); + } + else + { + recBlocks.Link( HWADDR(newpc), xJcc32( Jcc_Signed ) ); + xJMP( DispatcherEvent ); + } + } + + /* + else + { xMOV(eax, &cpuRegs.cycle); xADD(eax, eeScaleBlockCycles()); xMOV(&cpuRegs.cycle, eax); // update cycles @@ -1072,7 +1069,10 @@ static void iBranchTest(u32 newpc, bool noDispatch) } } } - xRET(); + xCALL( recEventTest ); + xJMP( DispatcherReg ); + + */ } static void checkcodefn() @@ -1622,7 +1622,7 @@ StartRecomp: // for actual branching instructions. iFlushCall(FLUSH_EVERYTHING); - iBranchTest(0xffffffff, true); + iBranchTest(); } else { @@ -1671,7 +1671,6 @@ R5900cpu recCpu = { recResetEE, recStep, recExecute, - recExecuteBlock, recClear, recShutdown };