Cleanup for VsyncInThread, lots of source code comments. (it's fun reading! ...maybe)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2318 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-12-06 15:31:11 +00:00
parent 6b5e302f82
commit acbe1ed547
9 changed files with 156 additions and 39 deletions

View File

@ -30,7 +30,6 @@
using namespace Threading; using namespace Threading;
extern u8 psxhblankgate; extern u8 psxhblankgate;
extern void ApplyPatch( int place = 1);
static const uint EECNT_FUTURE_TARGET = 0x10000000; static const uint EECNT_FUTURE_TARGET = 0x10000000;
@ -293,7 +292,6 @@ void frameLimitReset()
// Framelimiter - Measures the delta time between calls and stalls until a // Framelimiter - Measures the delta time between calls and stalls until a
// certain amount of time passes if such time hasn't passed yet. // certain amount of time passes if such time hasn't passed yet.
// See the GS FrameSkip function for details on why this is here and not in the GS. // See the GS FrameSkip function for details on why this is here and not in the GS.
extern int limitOn;
static __forceinline void frameLimit() static __forceinline void frameLimit()
{ {
// 999 means the user would rather just have framelimiting turned off... // 999 means the user would rather just have framelimiting turned off...
@ -325,8 +323,10 @@ static __forceinline void frameLimit()
if( sDeltaTime >= 0 ) return; if( sDeltaTime >= 0 ) return;
// If we're way ahead then we can afford to sleep the thread a bit. // If we're way ahead then we can afford to sleep the thread a bit.
// (note, sleep(1) thru sleep(2) tend to be the least accurate sleeps, and longer // (note, on Windows sleep(1) thru sleep(2) tend to be the least accurate sleeps,
// sleeps tend to be pretty reliable, so that's why the convoluted if/else below) // and longer sleeps tend to be pretty reliable, so that's why the convoluted if/
// else below. The same generally isn't true for Linux, but no harm either way
// really.)
s32 msec = (int)((sDeltaTime*-1000) / (s64)GetTickFrequency()); s32 msec = (int)((sDeltaTime*-1000) / (s64)GetTickFrequency());
if( msec > 4 ) Threading::Sleep( msec ); if( msec > 4 ) Threading::Sleep( msec );
@ -339,8 +339,18 @@ static __forceinline void frameLimit()
static __forceinline void VSyncStart(u32 sCycle) static __forceinline void VSyncStart(u32 sCycle)
{ {
EECNT_LOG( "///////// EE COUNTER VSYNC START \\\\\\\\\\\\\\\\\\\\ (frame: %d)", iFrame ); Cpu->CheckExecutionState();
vSyncDebugStuff( iFrame ); // EE Profiling and Debug code SysCoreThread::Get().VsyncInThread();
EECNT_LOG( "///////// EE COUNTER VSYNC START (frame: %6d) \\\\\\\\\\\\\\\\\\\\ ", iFrame );
// EE Profiling and Debug code.
// FIXME: should probably be moved to VsyncInThread, and handled
// by UI implementations. (ie, AppCoreThread in PCSX2-wx interface).
vSyncDebugStuff( iFrame );
if (CHECK_MICROVU0) vsyncVUrec(0);
if (CHECK_MICROVU1) vsyncVUrec(1);
if ((CSRw & 0x8)) if ((CSRw & 0x8))
{ {
@ -355,7 +365,6 @@ static __forceinline void VSyncStart(u32 sCycle)
psxVBlankStart(); psxVBlankStart();
if (gates) rcntStartGate(true, sCycle); // Counters Start Gate code if (gates) rcntStartGate(true, sCycle); // Counters Start Gate code
if (EmuConfig.EnablePatches) ApplyPatch(); // fixme - Apply patches
// INTC - VB Blank Start Hack -- // INTC - VB Blank Start Hack --
// Hack fix! This corrects a freezeup in Granda 2 where it decides to spin // Hack fix! This corrects a freezeup in Granda 2 where it decides to spin
@ -445,8 +454,6 @@ __forceinline void rcntUpdate_vSync()
if (vsyncCounter.Mode == MODE_VSYNC) if (vsyncCounter.Mode == MODE_VSYNC)
{ {
Cpu->CheckExecutionState();
VSyncEnd(vsyncCounter.sCycle); VSyncEnd(vsyncCounter.sCycle);
vsyncCounter.sCycle += vSyncInfo.Blank; vsyncCounter.sCycle += vSyncInfo.Blank;
@ -464,9 +471,6 @@ __forceinline void rcntUpdate_vSync()
// Accumulate hsync rounding errors: // Accumulate hsync rounding errors:
hsyncCounter.sCycle += vSyncInfo.hSyncError; hsyncCounter.sCycle += vSyncInfo.hSyncError;
if (CHECK_MICROVU0) vsyncVUrec(0);
if (CHECK_MICROVU1) vsyncVUrec(1);
# ifdef VSYNC_DEBUG # ifdef VSYNC_DEBUG
vblankinc++; vblankinc++;
if( vblankinc > 1 ) if( vblankinc > 1 )

View File

@ -390,7 +390,6 @@ static void intExecute()
static void intCheckExecutionState() static void intCheckExecutionState()
{ {
SysCoreThread::Get().OnVsyncInThread();
SysCoreThread::Get().StateCheckInThread(); SysCoreThread::Get().StateCheckInThread();
} }
@ -407,12 +406,15 @@ static void intClear(u32 Addr, u32 Size)
static void intShutdown() { static void intShutdown() {
} }
R5900cpu intCpu = { R5900cpu intCpu =
{
intAlloc, intAlloc,
intShutdown,
intReset, intReset,
intStep, intStep,
intExecute, intExecute,
intCheckExecutionState, intCheckExecutionState,
intClear, intClear,
intShutdown
}; };

View File

@ -1147,6 +1147,11 @@ void PluginManager::Freeze( PluginsEnum_t pid, SaveStateBase& state )
bool PluginManager::KeyEvent( const keyEvent& evt ) bool PluginManager::KeyEvent( const keyEvent& evt )
{ {
// [TODO] : The plan here is to give plugins "first chance" handling of keys.
// Handling order will be fixed (GS, SPU2, PAD, etc), and the first plugin to
// pick up the key and return "true" (for handled) will cause the loop to break.
// The current version of PS2E doesn't support it yet, though.
const PluginInfo* pi = tbl_PluginInfo; do { const PluginInfo* pi = tbl_PluginInfo; do {
if( pi->id != PluginId_PAD ) if( pi->id != PluginId_PAD )
m_info[pi->id].CommonBindings.KeyEvent( const_cast<keyEvent*>(&evt) ); m_info[pi->id].CommonBindings.KeyEvent( const_cast<keyEvent*>(&evt) );

View File

@ -263,16 +263,102 @@ void __fastcall intDoBranch(u32 target);
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// R5900 Public Interface / API // R5900 Public Interface / API
//
// [TODO] : This is on the list to get converted to a proper C++ class. I'm putting it
// off until I get my new IOPint and IOPrec re-merged. --air
//
struct R5900cpu struct R5900cpu
{ {
void (*Allocate)(); // throws exceptions on failure. // Memory allocation function, for allocating virtual memory spaces needed by
// the emulator. (ints/recs are free to allocate additional memory while running
// code, however any virtual mapped memory should always be allocated as soon
// as possible, to claim the memory before some plugin does..)
//
// Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped
// to prevent multi-thread race conditions.
//
// Notable Exception Throws:
// OutOfMemory - Not enough memory, or the memory areas required were already
// reserved.
//
void (*Allocate)();
// Deallocates ram allocated by Allocate and/or by runtime code execution.
//
// Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped
// to prevent multi-thread race conditions.
//
// Exception Throws: None. This function is a destructor, and should not throw.
//
void (*Shutdown)();
// Initializes / Resets code execution states. Typically implementation is only
// needed for recompilers, as interpreters have no internal execution states and
// rely on the CPU/VM states almost entirely.
//
// Thread Affinity:
// Can be called from any thread. Execute status must be suspended or stopped
// to prevent multi-thread race conditions.
//
// Exception Throws: Emulator-defined. Common exception types to look for:
// OutOfMemory, Stream Exceptions
//
void (*Reset)(); void (*Reset)();
// Steps a single instruction. Meant to be used by debuggers. Is currently unused
// and unimplemented. Future note: recompiler "step" should *always* fall back
// on interpreters.
//
// Exception Throws: [TODO] (possible execution-related throws to be added)
//
void (*Step)(); void (*Step)();
// Executes code until a break is signaled. Execution can be paused or suspended
// via thread-style signals that are handled by CheckExecutionState callbacks.
// Execution Breakages are handled the same way, where-by a signal causes the Execute
// call to return at the nearest state check (typically handled internally using
// either C++ exceptions or setjmp/longjmp).
//
// Exception Throws: [TODO] (possible execution-related throws to be added)
//
void (*Execute)(); void (*Execute)();
// Checks for execution suspension or cancellation. In pthreads terms this provides
// a "cancellation point." Execution state checks are typically performed at Vsyncs
// by the generic VM event handlers in R5900.cpp/Counters.cpp (applies to both recs
// and ints).
//
// Implementation note: Because of the nuances of recompiled code execution, setjmp
// may be used in place of thread cancellation or C++ exceptions (non-SEH exceptions
// cannot unwind through the recompiled code stackframes).
//
// Thread Affinity:
// Must be called on the same thread as Execute only.
//
// Exception Throws:
// May throw threading/Pthreads cancellations if the compiler supports SEH.
// ThreadTimedOut - For canceling VM execution in response to MTGS deadlock. (if the
// core emulator does not support multithreaded GS then this will not be a throw
// exception).
//
void (*CheckExecutionState)(); void (*CheckExecutionState)();
// Manual recompiled code cache clear; typically useful to recompilers only. Size is
// in MIPS words (32 bits). Dev note: this callback is nearly obsolete, and might be
// better off replaced with some generic API callbacks from VTLB block protection.
// Also: the calls from COP0's TLB remap code should be replaced with full recompiler
// resets, since TLB remaps affect more than just the code they contain (code that
// may reference the remaped blocks via memory loads/stores, for example).
//
// Thread Affinity Rule:
// Can be called from any thread (namely for being called from debugging threads)
//
// Exception Throws: [TODO] Emulator defined? (probably shouldn't throw, probably
// doesn't matter if we're stripping it out soon. ;)
//
void (*Clear)(u32 Addr, u32 Size); void (*Clear)(u32 Addr, u32 Size);
void (*Shutdown)(); // deallocates memory reserved by Allocate
}; };
extern R5900cpu *Cpu; extern R5900cpu *Cpu;

View File

@ -19,6 +19,7 @@
#include "Counters.h" #include "Counters.h"
#include "GS.h" #include "GS.h"
#include "Elfheader.h" #include "Elfheader.h"
#include "Patch.h"
#include "PageFaultSource.h" #include "PageFaultSource.h"
#include "SysThreads.h" #include "SysThreads.h"
@ -279,10 +280,37 @@ void SysCoreThread::_reset_stuff_as_needed()
} }
} }
void SysCoreThread::OnVsyncInThread() // Called by the VsyncInThread() if a valid keyEvent is pending and is unhandled by other
// PS2 core plugins.
void SysCoreThread::DispatchKeyEventToUI( const keyEvent& evt )
{ {
} }
// This is called from the PS2 VM at the start of every vsync (either 59.94 or 50 hz by PS2
// clock scale, which does not correlate to the actual host machine vsync).
//
// Default tasks: Updates PADs and applies vsync patches. Derived classes can override this
// to change either PAD and/or Patching behaviors.
//
// [TODO]: Should probably also handle profiling and debugging updates, once those are
// re-implemented.
//
void SysCoreThread::VsyncInThread()
{
if( !pxAssert(g_plugins!=NULL) ) return;
const keyEvent* ev = PADkeyEvent();
if( ev != NULL && (ev->key != 0) )
{
// Give plugins first try to handle keys. If none of them handles the key, it will
// be passed to the main user interface.
if( !g_plugins->KeyEvent( *ev ) )
DispatchKeyEventToUI( *ev );
}
if (EmuConfig.EnablePatches) ApplyPatch();
}
void SysCoreThread::StateCheckInThread() void SysCoreThread::StateCheckInThread()
{ {
GetMTGS().RethrowException(); GetMTGS().RethrowException();
@ -290,8 +318,6 @@ void SysCoreThread::StateCheckInThread()
if( !m_hasValidState ) if( !m_hasValidState )
throw Exception::RuntimeError( "Invalid emulation state detected; Virtual machine threads have been cancelled." ); throw Exception::RuntimeError( "Invalid emulation state detected; Virtual machine threads have been cancelled." );
//OnVsyncInThread();
_reset_stuff_as_needed(); _reset_stuff_as_needed();
} }

View File

@ -217,7 +217,8 @@ public:
bool HasPendingStateChangeRequest() const; bool HasPendingStateChangeRequest() const;
virtual void StateCheckInThread(); virtual void StateCheckInThread();
virtual void OnVsyncInThread(); virtual void VsyncInThread();
virtual void DispatchKeyEventToUI( const keyEvent& evt );
virtual const wxString& GetElfOverride() const { return m_elf_override; } virtual const wxString& GetElfOverride() const { return m_elf_override; }
virtual void SetElfOverride( const wxString& elf ); virtual void SetElfOverride( const wxString& elf );

View File

@ -542,7 +542,8 @@ protected:
virtual void OnResumeInThread( bool IsSuspended ); virtual void OnResumeInThread( bool IsSuspended );
virtual void OnSuspendInThread(); virtual void OnSuspendInThread();
virtual void OnCleanupInThread(); virtual void OnCleanupInThread();
virtual void OnVsyncInThread(); //virtual void VsyncInThread();
virtual void DispatchKeyEventToUI( const keyEvent& ev );
virtual void ExecuteTaskInThread(); virtual void ExecuteTaskInThread();
}; };

View File

@ -163,23 +163,15 @@ void AppCoreThread::OnCleanupInThread()
extern int TranslateGDKtoWXK( u32 keysym ); extern int TranslateGDKtoWXK( u32 keysym );
#endif #endif
void AppCoreThread::OnVsyncInThread() void AppCoreThread::DispatchKeyEventToUI( const keyEvent& ev )
{ {
_parent::OnVsyncInThread(); m_kevt.SetEventType( ( ev.evt == KEYPRESS ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP );
const bool isDown = (ev.evt == KEYPRESS);
if( !pxAssert(g_plugins!=NULL) ) return;
const keyEvent* ev = PADkeyEvent();
if( ev == NULL || (ev->key == 0) ) return;
g_plugins->KeyEvent( *ev );
m_kevt.SetEventType( ( ev->evt == KEYPRESS ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP );
const bool isDown = (ev->evt == KEYPRESS);
#ifdef __WXMSW__ #ifdef __WXMSW__
const int vkey = wxCharCodeMSWToWX( ev->key ); const int vkey = wxCharCodeMSWToWX( ev.key );
#elif defined( __WXGTK__ ) #elif defined( __WXGTK__ )
const int vkey = TranslateGDKtoWXK( ev->key ); const int vkey = TranslateGDKtoWXK( ev.key );
#else #else
# error Unsupported Target Platform. # error Unsupported Target Platform.
#endif #endif

View File

@ -656,8 +656,6 @@ static jmp_buf m_SetJmp_StateCheck;
static void recCheckExecutionState() static void recCheckExecutionState()
{ {
SysCoreThread::Get().OnVsyncInThread();
#if PCSX2_SEH #if PCSX2_SEH
SysCoreThread::Get().StateCheckInThread(); SysCoreThread::Get().StateCheckInThread();
@ -1733,10 +1731,12 @@ StartRecomp:
R5900cpu recCpu = R5900cpu recCpu =
{ {
recAlloc, recAlloc,
recShutdown,
recResetEE, recResetEE,
recStep, recStep,
recExecute, recExecute,
recCheckExecutionState, recCheckExecutionState,
recClear, recClear,
recShutdown
}; };