diff --git a/pcsx2/Counters.c b/pcsx2/Counters.c index ecae946554..36335fdba8 100644 --- a/pcsx2/Counters.c +++ b/pcsx2/Counters.c @@ -37,9 +37,6 @@ Counter counters[6]; u32 nextsCounter; // records the cpuRegs.cycle value of the last call to rcntUpdate() s32 nextCounter; // delta from nextsCounter, in cycles, until the next rcntUpdate() -static void (*s_prevExecuteVU1Block)() = NULL; -LARGE_INTEGER lfreq; - void rcntReset(int index) { counters[index].count = 0; counters[index].sCycleT = cpuRegs.cycle; @@ -111,51 +108,21 @@ void rcntInit() { UpdateVSyncRate(); -#ifdef _WIN32 - QueryPerformanceFrequency(&lfreq); -#endif - for (i=0; i<4; i++) rcntReset(i); cpuRcntSet(); - - assert(Cpu != NULL && Cpu->ExecuteVU1Block != NULL ); - s_prevExecuteVU1Block = Cpu->ExecuteVU1Block; } // debug code, used for stats int g_nCounters[4]; static int iFrame = 0; +long iFrameLimitEnable = 1; #ifndef _WIN32 #include #endif static s64 m_iTicks=0; -static s64 m_iSlowTicks=0; static u64 m_iStart=0; -//static u64 m_iSlowStart=0; - -u64 GetTickFrequency() -{ -#ifdef _WIN32 - return lfreq.QuadPart; -#else - return 1000000; -#endif -} - -u64 GetCPUTicks() -{ -#ifdef _WIN32 - LARGE_INTEGER count; - QueryPerformanceCounter(&count); - return count.QuadPart; -#else - struct timeval t; - gettimeofday(&t, NULL); - return (u64)t.tv_sec*1000000+t.tv_usec; -#endif -} typedef struct { @@ -179,6 +146,9 @@ static __forceinline void vSyncInfoCalc( vSyncTimingInfo* info, u32 framesPerSec // depending on user-set speedhack options, and it can break float/double code // (as in returning infinities and junk) + // NOTE: mgs3 likes a /4 vsync, but many games prefer /2. This seems to indicate a + // problem in the counters vsync gates somewhere. + u64 Frame = ((u64)PS2CLK * 1000000ULL) / framesPerSecond; u64 HalfFrame = Frame / 2; u64 Blank = HalfFrame / 2; // two blanks and renders per frame @@ -220,9 +190,9 @@ static __forceinline void vSyncInfoCalc( vSyncTimingInfo* info, u32 framesPerSec } -void UpdateVSyncRate() +u32 UpdateVSyncRate() { - const char *limiterMsg = "Framelimiter rate updated (UpdateVSyncRate): %.2f fps\n"; + const char *limiterMsg = "Framelimiter rate updated (UpdateVSyncRate): %d.%d fps\n"; // fixme - According to some docs, progressive-scan modes actually refresh slower than // interlaced modes. But I can't fathom how, since the refresh rate is a function of @@ -235,18 +205,12 @@ void UpdateVSyncRate() if(Config.PsxType & 1) { if( vSyncInfo.Framerate != FRAMERATE_PAL ) - { - SysPrintf( "PCSX2: Switching to PAL display timings.\n" ); vSyncInfoCalc( &vSyncInfo, FRAMERATE_PAL, SCANLINES_TOTAL_PAL ); - } } else { if( vSyncInfo.Framerate != FRAMERATE_NTSC ) - { - SysPrintf( "PCSX2: Switching to NTSC display timings.\n" ); vSyncInfoCalc( &vSyncInfo, FRAMERATE_NTSC, SCANLINES_TOTAL_NTSC ); - } } counters[4].CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated @@ -258,7 +222,7 @@ void UpdateVSyncRate() if( m_iTicks != ticks ) { m_iTicks = ticks; - SysPrintf( limiterMsg, (float)Config.CustomFps ); + SysPrintf( limiterMsg, Config.CustomFps, 0 ); } } else @@ -267,35 +231,22 @@ void UpdateVSyncRate() if( m_iTicks != ticks ) { m_iTicks = ticks; - SysPrintf( limiterMsg, (Config.PsxType & 1) ? 50.00 : 59.94 ); + SysPrintf( limiterMsg, vSyncInfo.Framerate/100, vSyncInfo.Framerate%100 ); } } - { - u32 frameSkipThreshold = Config.CustomFrameSkip; - if( Config.CustomFrameSkip == 0) - { - // default: load the frameSkipThreshold with a value roughly 90% of our current framerate - frameSkipThreshold = ( vSyncInfo.Framerate * 228 ) / 256; - } - - m_iSlowTicks = GetTickFrequency() / frameSkipThreshold; - m_iStart = GetCPUTicks(); - - // sanity check against users who set a "minimum" frame that's higher - // than the maximum framerate: - if( m_iSlowTicks < m_iTicks ) m_iSlowTicks = m_iTicks; - } + m_iStart = GetCPUTicks(); + iFrameLimitEnable = 1; cpuRcntSet(); + + return (u32)m_iTicks; } extern u32 CSRw; extern u64 SuperVUGetRecTimes(int clear); extern u32 vu0time; -extern void DummyExecuteVU1Block(void); - void vSyncDebugStuff() { #ifdef EE_PROFILING @@ -378,121 +329,37 @@ void vSyncDebugStuff() { #endif } -static __forceinline void frameLimit() +// Framelimiter - Measures the delta time between calls and stalls until a +// 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. +static __forceinline void frameLimit() { - static u8 bOkayToSkip = 0; - static u8 bKeepSkipping = 0; - s64 sDeltaTime; u64 uExpectedEnd; u64 iEnd; if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_NORMAL ) return; + if( Config.CustomFps >= 999 ) return; // means the user would rather just have framelimiting turned off... + if( !iFrameLimitEnable ) // Frameskipper disabled the limiter + { + m_iStart = GetCPUTicks(); + return; + } uExpectedEnd = m_iStart + m_iTicks; iEnd = GetCPUTicks(); sDeltaTime = iEnd - uExpectedEnd; - if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_LIMIT ) + // If the framerate drops too low, reset the expected value. This avoids + // excessive amounts of "fast forward" syndrome which would occur if we + // tried to catch up too much. + + if( (sDeltaTime>>3) > m_iTicks ) { - // Non-skip Compensation: If the framerate drops too low, reset the - // expected value. This avoids excessive amounts of - // "fast forward" syndrome which would occur if we tried to - // catch up too much. - - if( (sDeltaTime>>3) > m_iTicks ) - { - m_iStart = iEnd; - return; - } + m_iStart = iEnd; + return; } - else - { - // FrameSkip and VU-Skip Magic! - // Skips a sequence of consecutive frames after a sequence of rendered frames - - // This is the least number of consecutive frames we will render w/o skipping - #define noSkipFrames (Config.CustomConsecutiveFrames>0) ? Config.CustomConsecutiveFrames : 2 - // This is the number of consecutive frames we will skip - #define yesSkipFrames (Config.CustomConsecutiveSkip>0) ? Config.CustomConsecutiveSkip : 2 - - const s64 uSlowExpectedEnd = m_iStart + m_iSlowTicks; - const s64 sSlowDeltaTime = iEnd - uSlowExpectedEnd; - - if (bOkayToSkip == 0) - { - // -- Standard operation section -- - // Means neither skipping frames nor force-rendering consecutive frames. - - if( sSlowDeltaTime > 0 ) - { - // The game is running below the minimum framerate, so use the SlowExpectedEnd. - // But don't start skipping yet! That would be too sensitive, and wouldn't - // allow compensation for occasional abnormal hiccups. - // So the skipping code is only engaged if the SlowDeltaTime falls behind by a full frame. - - m_iStart = uSlowExpectedEnd; - - if( sSlowDeltaTime > m_iSlowTicks*2 ) - { - //SysPrintf( "Frameskip Initiated!\n" ); - if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 1, 0, 0); - else GSsetFrameSkip(1); - if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) - Cpu->ExecuteVU1Block = DummyExecuteVU1Block; - - bOkayToSkip = noSkipFrames; - bKeepSkipping = yesSkipFrames; - } - return; // don't run the framelimiter. - } - } - else if (bOkayToSkip == noSkipFrames) - { - // -- Frames-a-Skippin' Section -- - - if (bKeepSkipping <= 1) - { - //first set VU1 to enabled THEN unfreeze GS regs - if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) - Cpu->ExecuteVU1Block = s_prevExecuteVU1Block; - if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); - else GSsetFrameSkip(0); - bOkayToSkip--; - - // Note: If we lag behind by 8 frames then it's time to give up on the idea - // of catching up. Force the game to drop some frames by resetting iStart to - // something closer iEnd. - - if( sSlowDeltaTime > m_iSlowTicks * 8 ) - { - //SysPrintf( "Frameskip couldn't skip enough -- had to lose some time!\n" ); - m_iStart = iEnd - m_iSlowTicks; - return; - } - } - - m_iStart = uSlowExpectedEnd; - bKeepSkipping--; - return; - } - else - { - // -- Consecutive frames section -- - // Force-render consecutive frames without skipping. - - bOkayToSkip--; - - if( sSlowDeltaTime > 0 ) - { - m_iStart = uSlowExpectedEnd; - return; - } - } - } - - // If we got this far it means the game is running near or above full framerate. // use the expected frame completion time as our starting point. // improves smoothness by making the framelimiter more adaptive to the @@ -501,13 +368,23 @@ static __forceinline void frameLimit() m_iStart = uExpectedEnd; - while( sDeltaTime < 0 ) { + while( sDeltaTime < 0 ) + { _TIMESLICE(); iEnd = GetCPUTicks(); + + if( !(*(volatile long*)&iFrameLimitEnable) ) + { + // Frameskipper turned us off + m_iStart = iEnd; + break; + } + sDeltaTime = iEnd - uExpectedEnd; } } + static __forceinline void VSyncStart(u32 sCycle) // VSync Start { vSyncDebugStuff(); // EE Profiling and Debug code @@ -547,7 +424,6 @@ __forceinline void rcntUpdate_hScanline() iopBranchAction = 1; if (counters[4].mode & MODE_HBLANK) { //HBLANK Start - //hScanlineNextCycle(difference, modeCycles); rcntStartGate(0, counters[4].sCycle); psxCheckStartGate16(0); @@ -557,7 +433,6 @@ __forceinline void rcntUpdate_hScanline() counters[4].mode = MODE_HRENDER; } else { //HBLANK END / HRENDER Begin - //hScanlineNextCycle(difference, modeCycles); if (CSRw & 0x4) GSCSRr |= 4; // signal if (!(GSIMR&0x400)) gsIrq(); if (gates) rcntEndGate(0, counters[4].sCycle); diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index aba6119ed5..f807a40756 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -94,6 +94,6 @@ u32 rcntRcount(int index); u32 rcntCycle(int index); int rcntFreeze(gzFile f, int Mode); -void UpdateVSyncRate(); +u32 UpdateVSyncRate(); #endif /* __COUNTERS_H__ */ diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index 47ec3f52b4..4f8d9a7be6 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -32,9 +32,11 @@ using namespace std; -//#define MTGS_LOG SysPrintf +#ifdef DEBUG +#define MTGS_LOG SysPrintf +#else #define MTGS_LOG 0&& - +#endif #if defined(_WIN32) && !defined(WIN32_PTHREADS) @@ -294,6 +296,59 @@ CRITICAL_SECTION stackLock; static int g_mtgsCopyLock = 0; #endif +// FrameSkipping Stuff + +static s64 m_iSlowTicks=0; +static u64 m_iSlowStart=0; +static void (*s_prevExecuteVU1Block)() = NULL; + +extern "C" void DummyExecuteVU1Block(void); + +static void OnModeChanged( u32 framerate, u32 iTicks ) +{ + m_iSlowStart = GetCPUTicks(); + + u32 frameSkipThreshold = Config.CustomFrameSkip*100; + if( Config.CustomFrameSkip == 0) + { + // default: load the frameSkipThreshold with a value roughly 90% of our current framerate + frameSkipThreshold = ( framerate * 228 ) / 256; + } + + m_iSlowTicks = ( GetTickFrequency() * 100 ) / frameSkipThreshold; + + // sanity check against users who set a "minimum" frame that's higher + // than the maximum framerate: + if( m_iSlowTicks < iTicks ) m_iSlowTicks = iTicks; +} + +extern "C" void gsSetVideoRegionType( u32 isPal ) +{ + u32 framerate; + + if( isPal ) + { + if( Config.PsxType & 1 ) return; + SysPrintf( "PAL Display Mode Initialized.\n" ); + Config.PsxType |= 1; + framerate = FRAMERATE_PAL; + } + else + { + if( !(Config.PsxType & 1 ) ) return; + SysPrintf( "NTSC Display Mode Initialized.\n" ); + Config.PsxType &= ~1; + framerate = FRAMERATE_NTSC; + } + + u32 newTickrate = UpdateVSyncRate(); + if( CHECK_MULTIGS ) + GSRingBufSimplePacket( GS_RINGTYPE_MODECHANGE, framerate, newTickrate, 0 ); + else + OnModeChanged( framerate, newTickrate ); +} + + // Initializes MultiGS ringbuffer and registers. // (does nothing for single threaded GS) void gsInit() @@ -318,11 +373,19 @@ void gsInit() if( GSsetBaseMem != NULL ) GSsetBaseMem(g_MTGSMem); } + + assert(Cpu != NULL && Cpu->ExecuteVU1Block != NULL ); + s_prevExecuteVU1Block = Cpu->ExecuteVU1Block; } // Opens the gsRingbuffer thread. s32 gsOpen() { + OnModeChanged( + (Config.PsxType & 1) ? FRAMERATE_PAL : FRAMERATE_NTSC, + UpdateVSyncRate() + ); + if( !CHECK_MULTIGS ) return GSopen((void *)&pDsp, "PCSX2", 0); @@ -750,17 +813,13 @@ void gsWrite8(u32 mem, u8 value) { GIF_LOG("GS write 8 at %8.8lx with data %8.8lx\n", mem, value); } -extern void UpdateVSyncRate(); - void gsWrite16(u32 mem, u16 value) { GIF_LOG("GS write 16 at %8.8lx with data %8.8lx\n", mem, value); switch (mem) { case 0x12000010: // GS_SMODE1 - if((value & 0x6000) == 0x6000) Config.PsxType |= 1; // PAL - else Config.PsxType &= ~1; // NTSC - UpdateVSyncRate(); + gsSetVideoRegionType( (value & 0x6000) == 0x6000 ); break; case 0x12000020: // GS_SMODE2 @@ -794,10 +853,8 @@ void gsWrite32(u32 mem, u32 value) switch (mem) { case 0x12000010: // GS_SMODE1 - if((value & 0x6000) == 0x6000) Config.PsxType |= 1; // PAL - else Config.PsxType &= ~1; // NTSC - UpdateVSyncRate(); - break; + gsSetVideoRegionType( (value & 0x6000) == 0x6000 ); + break; case 0x12000020: // GS_SMODE2 if(value & 0x1) Config.PsxType |= 2; // Interlaced @@ -826,9 +883,7 @@ void gsWrite64(u32 mem, u64 value) { switch (mem) { case 0x12000010: // GS_SMODE1 - if((value & 0x6000) == 0x6000) Config.PsxType |= 1; // PAL - else Config.PsxType &= ~1; // NTSC - UpdateVSyncRate(); + gsSetVideoRegionType( (value & 0x6000) == 0x6000 ); break; case 0x12000020: // GS_SMODE2 @@ -1591,6 +1646,128 @@ void gifMFIFOInterrupt() cpuRegs.interrupt &= ~(1 << 11); } +extern "C" long iFrameLimitEnable; // used to enable/disable the EE framelimiter. + +// FrameSkipper - Measures delta time between calls and issues frameskips +// it the time is too long. Also regulates the status of the EE's framelimiter. + +// This function does not regulate frame limiting, meaning it does no stalling. +// Stalling functions are performed by the EE: If the MTGS were throtted and not +// the EE, the EE would fill the ringbuffer while the MTGS regulated frames -- +// fine for most situations but could result in literally dozens of frames queued +// up in the ringbuffer durimg some game menu screens; which in turn would result +// in a half-second lag of keystroke actions becoming visible to the user (bad!). + +// Alternative: Instead of this, I could have everything regulated here, and then +// put a framecount limit on the MTGS ringbuffer. But that seems no less complicated +// and would also mean that aforementioned menus would still be laggy by whatever +// frame count threshold. This method is more responsive. + +static __forceinline void frameSkip() +{ + static u8 FramesToRender = 0; + static u8 FramesToSkip = 0; + static bool justSkipped = false; + + if( CHECK_FRAMELIMIT != PCSX2_FRAMELIMIT_SKIP && + CHECK_FRAMELIMIT != PCSX2_FRAMELIMIT_VUSKIP ) return; + + // FrameSkip and VU-Skip Magic! + // Skips a sequence of consecutive frames after a sequence of rendered frames + + // This is the least number of consecutive frames we will render w/o skipping + #define noSkipFrames ((Config.CustomConsecutiveFrames>0) ? Config.CustomConsecutiveFrames : 1) + // This is the number of consecutive frames we will skip + #define yesSkipFrames ((Config.CustomConsecutiveSkip>0) ? Config.CustomConsecutiveSkip : 1) + + const u64 iEnd = GetCPUTicks(); + const s64 uSlowExpectedEnd = m_iSlowStart + m_iSlowTicks; + const s64 sSlowDeltaTime = iEnd - uSlowExpectedEnd; + + m_iSlowStart = uSlowExpectedEnd; + + if( FramesToRender == 0 ) + { + // -- Standard operation section -- + // Means neither skipping frames nor force-rendering consecutive frames. + + if( sSlowDeltaTime > 0 ) + { + // The game is running below the minimum framerate, so use the SlowExpectedEnd. + // But don't start skipping yet! That would be too sensitive. + // So the skipping code is only engaged if the SlowDeltaTime falls behind by + // a full frame, or if we're already skipping (in which case we don't care + // to avoid errant skips). + + if( justSkipped || sSlowDeltaTime > m_iSlowTicks*2 ) + { + //SysPrintf( "Frameskip Initiated! Lateness: %d\n", (int)( sSlowDeltaTime / m_iSlowTicks ) ); + + InterlockedExchange( &iFrameLimitEnable, 0 ); + GSsetFrameSkip(1); + + if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) + InterlockedExchangePointer( &Cpu->ExecuteVU1Block, DummyExecuteVU1Block ); + + FramesToRender = noSkipFrames+1; + FramesToSkip = yesSkipFrames; + } + } + else + { + // Running at or above full speed, so reset the StartTime + + InterlockedExchange( &iFrameLimitEnable, 1 ); + m_iSlowStart = iEnd; + } + justSkipped = false; + return; + } + else if( FramesToSkip > 0 ) + { + // -- Frames-a-Skippin' Section -- + + FramesToSkip--; + + if( FramesToSkip == 0 ) + { + // Skipped our last frame, so restore non-skip behavior + + GSsetFrameSkip(0); + + // Note: If we lag behind by 250ms then it's time to give up on the idea + // of catching up. Force the game to slow down by resetting iStart to + // something closer to iEnd. + + if( sSlowDeltaTime > (m_iSlowTicks + ((s64)GetTickFrequency() / 4)) ) + { + //SysPrintf( "Frameskip couldn't skip enough -- had to lose some time!\n" ); + m_iSlowStart = iEnd - m_iSlowTicks; + } + + justSkipped = true; + if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) + InterlockedExchangePointer( &Cpu->ExecuteVU1Block, s_prevExecuteVU1Block ); + } + else + return; + } + + //SysPrintf( "Consecutive Frames -- Lateness: %d\n", (int)( sSlowDeltaTime / m_iSlowTicks ) ); + + // -- Consecutive frames section -- + // Force-render consecutive frames without skipping. + // re-enable the frame limiter of the EE if frames render fast. + + FramesToRender--; + + if( sSlowDeltaTime < 0 ) + { + InterlockedExchange( &iFrameLimitEnable, 1 ); + m_iSlowStart = iEnd; + } +} + extern "C" void GSPostVsyncEnd() { *(u32*)(PS2MEM_GS+0x1000) ^= 0x2000; // swap the vsync field @@ -1604,14 +1781,35 @@ extern "C" void GSPostVsyncEnd() GSRingBufSimplePacket(GS_RINGTYPE_VSYNC, (*(u32*)(PS2MEM_GS+0x1000)&0x2000), 0, 0); GS_SETEVENT(); } - else { + else + { GSvsync((*(u32*)(PS2MEM_GS+0x1000)&0x2000)); - // update here on single thread mode *OBSOLETE* - if( PAD1update != NULL ) PAD1update(0); - if( PAD2update != NULL ) PAD2update(1); + + // update here on single thread mode *OBSOLETE* + if( PAD1update != NULL ) PAD1update(0); + if( PAD2update != NULL ) PAD2update(1); + + frameSkip(); } } +static void _resetFrameskip() +{ + InterlockedExchangePointer( &Cpu->ExecuteVU1Block, s_prevExecuteVU1Block ); + InterlockedExchange( &iFrameLimitEnable, 1 ); + GSsetFrameSkip( 0 ); +} + +// Disables the GS Frameskip at runtime without any racy mess... +extern "C" void gsResetFrameSkip() +{ + if( CHECK_MULTIGS ) + GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); + else + _resetFrameskip(); +} + + GS_THREADPROC { g_GsExitCode = GSopen((void *)&pDsp, "PCSX2", 1); @@ -1624,8 +1822,6 @@ GS_THREADPROC u32 prevCmd=0; #endif - SysPrintf("Starting GS thread\n"); - while( !gsHasToExit ) { event_wait( g_hGsEvent ); @@ -1683,6 +1879,9 @@ GS_THREADPROC case GS_RINGTYPE_VSYNC: { GSvsync(*(u32*)(g_pGSRingPos+4)); + + frameSkip(); + if( PAD1update != NULL ) PAD1update(0); if( PAD2update != NULL ) PAD2update(1); @@ -1697,8 +1896,10 @@ GS_THREADPROC } case GS_RINGTYPE_FRAMESKIP: - if( GSsetFrameSkip != NULL ) - GSsetFrameSkip(*(u32*)(g_pGSRingPos+4)); + _resetFrameskip(); + + //if( GSsetFrameSkip != NULL ) + // GSsetFrameSkip(*(u32*)(g_pGSRingPos+4)); break; case GS_RINGTYPE_MEMWRITE8: @@ -1786,6 +1987,9 @@ GS_THREADPROC GSwriteCSR( *(u32*)(g_pGSRingPos+4) ); break; + case GS_RINGTYPE_MODECHANGE: + OnModeChanged( *(u32*)(g_pGSRingPos+4), *(u32*)(g_pGSRingPos+8) ); + break; default: diff --git a/pcsx2/GS.h b/pcsx2/GS.h index bfba5076ee..7ce1a5355e 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -65,6 +65,7 @@ enum GS_RINGTYPE , GS_RINGTYPE_RESET // issues a GSreset() command. , GS_RINGTYPE_SOFTRESET // issues a soft reset for the GIF , GS_RINGTYPE_WRITECSR +, GS_RINGTYPE_MODECHANGE // for issued mode changes. }; // if returns NULL, don't copy (memory is preserved) @@ -77,6 +78,8 @@ void gsInit(); s32 gsOpen(); void gsShutdown(); void gsReset(); +void gsSetVideoRegionType( u32 isPal ); +void gsResetFrameSkip(); // mem and size are the ones from GSRingBufCopy extern void GSRINGBUF_DONECOPY(const u8 *mem, u32 size); diff --git a/pcsx2/Misc.c b/pcsx2/Misc.c index b88760edb8..2e04a213c5 100644 --- a/pcsx2/Misc.c +++ b/pcsx2/Misc.c @@ -827,7 +827,6 @@ int StatesC = 0; extern void iDumpRegisters(u32 startpc, u32 temp); extern void recExecuteVU0Block(void); extern void recExecuteVU1Block(void); -extern void DummyExecuteVU1Block(void); extern char strgametitle[256]; char* mystrlwr( char* string ) @@ -895,22 +894,16 @@ void ProcessFKeys(int fkey, int shift) Config.Options = (Config.Options&~PCSX2_FRAMELIMIT_MASK)|(((Config.Options&PCSX2_FRAMELIMIT_MASK)+PCSX2_FRAMELIMIT_LIMIT)&PCSX2_FRAMELIMIT_MASK); } + gsResetFrameSkip(); + switch(CHECK_FRAMELIMIT) { case PCSX2_FRAMELIMIT_NORMAL: - if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); - else GSsetFrameSkip(0); - Cpu->ExecuteVU1Block = recExecuteVU1Block; limitMsg = "None/Normal"; break; case PCSX2_FRAMELIMIT_LIMIT: - if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); - else GSsetFrameSkip(0); - Cpu->ExecuteVU1Block = recExecuteVU1Block; - //Quality option, turn off timestretching on the SPU2 plugin limitMsg = "Limit"; break; case PCSX2_FRAMELIMIT_SKIP: - Cpu->ExecuteVU1Block = recExecuteVU1Block; case PCSX2_FRAMELIMIT_VUSKIP: if( GSsetFrameSkip == NULL ) { @@ -1078,6 +1071,41 @@ void injectIRX(char *filename){ rd[i].extInfoSize=0; } +// [TODO] I'd like to move the following functions to their own module eventually. +// It might even be a good idea to just go ahead and move them into Win32/Linux +// specific files since they're all #ifdef'd that way anyways. + +static LARGE_INTEGER lfreq; + +void InitCPUTicks() +{ +#ifdef _WIN32 + QueryPerformanceFrequency(&lfreq); +#endif +} + +u64 GetTickFrequency() +{ +#ifdef _WIN32 + return lfreq.QuadPart; +#else + return 1000000; // unix measures in microseconds +#endif +} + +u64 GetCPUTicks() +{ +#ifdef _WIN32 + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + return count.QuadPart; +#else + struct timeval t; + gettimeofday(&t, NULL); + return ((u64)t.tv_sec*GetTickFrequency())+t.tv_usec; +#endif +} + __forceinline void _TIMESLICE() { #ifdef _WIN32 diff --git a/pcsx2/Misc.h b/pcsx2/Misc.h index b662134a7d..d5e14f3214 100644 --- a/pcsx2/Misc.h +++ b/pcsx2/Misc.h @@ -391,6 +391,9 @@ static __forceinline long InterlockedCompareExchangePointer(PVOID volatile *dest #endif +extern void InitCPUTicks(); +extern u64 GetTickFrequency(); +extern u64 GetCPUTicks(); // Timeslice releaser for those many idle loop spots through out PCSX2. extern void _TIMESLICE(); diff --git a/pcsx2/R5900.c b/pcsx2/R5900.c index b9315cf7d0..571d5cc316 100644 --- a/pcsx2/R5900.c +++ b/pcsx2/R5900.c @@ -626,7 +626,9 @@ void cpuExecuteBios() break; } - UpdateVSyncRate(); + // Set the video mode to user's default request: + gsSetVideoRegionType( Config.PsxType & 1 ); + SysPrintf("* PCSX2 *: ExecuteBios\n"); bExecBIOS = TRUE; diff --git a/pcsx2/windows/WinMain.c b/pcsx2/windows/WinMain.c index 398f593961..acc29e16c8 100644 --- a/pcsx2/windows/WinMain.c +++ b/pcsx2/windows/WinMain.c @@ -652,7 +652,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // [TODO] : Add the other plugin overrides here... - + InitCPUTicks(); if (SysInit() == -1) return 1; #ifdef PCSX2_DEVBUILD diff --git a/pcsx2/x86/iGS.cpp b/pcsx2/x86/iGS.cpp index 5b1298bee9..a0e13bd6c3 100644 --- a/pcsx2/x86/iGS.cpp +++ b/pcsx2/x86/iGS.cpp @@ -89,93 +89,17 @@ void gsConstWrite8(u32 mem, int mmreg) } } -void recSetSMODE1() -{ - iFlushCall(0); - AND32ItoR(EAX, 0x6000); - CMP32ItoR(EAX, 0x6000); - j8Ptr[5] = JNE8(0); - - // PAL - OR32ItoM( (uptr)&Config.PsxType, 1); - j8Ptr[6] = JMP8(0); - - x86SetJ8( j8Ptr[5] ); - - // NTSC - AND32ItoM( (uptr)&Config.PsxType, ~1 ); - - x86SetJ8( j8Ptr[6] ); - CALLFunc((uptr)UpdateVSyncRate); -} - -void recSetSMODE2() -{ - TEST32ItoR(EAX, 1); - j8Ptr[5] = JZ8(0); - - // Interlaced - OR32ItoM( (uptr)&Config.PsxType, 2); - j8Ptr[6] = JMP8(0); - - x86SetJ8( j8Ptr[5] ); - - // Non-Interlaced - AND32ItoM( (uptr)&Config.PsxType, ~2 ); - - x86SetJ8( j8Ptr[6] ); -} - void gsConstWrite16(u32 mem, int mmreg) { switch (mem&~3) { + case 0x12000010: // GS_SMODE1 - assert( !(mem&3)); - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem16( (uptr)PS2GS_BASE(mem), mmreg ); - - if( CHECK_MULTIGS ) - _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); - - recSetSMODE1(); - - if( CHECK_MULTIGS ) { - iFlushCall(0); - - _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); - _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE16, X86ARG1); - CALLFunc((uptr)GSRingBufSimplePacket); -#ifndef __x86_64__ - ADD32ItoR(ESP, 12); -#endif - - } - - break; - case 0x12000020: // GS_SMODE2 - assert( !(mem&3)); - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem16( (uptr)PS2GS_BASE(mem), mmreg ); - - if( CHECK_MULTIGS ) - _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); - - recSetSMODE2(); - - if( CHECK_MULTIGS ) { - iFlushCall(0); - - _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); - _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE16, X86ARG1); - CALLFunc((uptr)GSRingBufSimplePacket); -#ifndef __x86_64__ - ADD32ItoR(ESP, 12); -#endif - } - + // SMODE1 and SMODE2 fall back on the gsWrite library. + iFlushCall(0); + _callFunctionArg2((uptr)gsWrite16, MEM_CONSTTAG, mmreg, mem, 0 ); break; - + case 0x12001000: // GS_CSR assert( !(mem&2) ); @@ -187,7 +111,7 @@ void gsConstWrite16(u32 mem, int mmreg) AND32ItoR(ECX, ~(0xffff<<(mem&2)*8)); OR32ItoR(EAX, ECX); _callFunctionArg1((uptr)CSRwrite, EAX|MEM_X86TAG, 0); - break; + return; // don't write to GSMEM default: _eeWriteConstMem16( (uptr)PS2GS_BASE(mem), mmreg ); @@ -236,49 +160,12 @@ void gsConstWrite32(u32 mem, int mmreg) { switch (mem) { case 0x12000010: // GS_SMODE1 - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem32( (uptr)PS2GS_BASE(mem), mmreg ); - - if( CHECK_MULTIGS ) - _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); - - recSetSMODE1(); - - if( CHECK_MULTIGS ) { - iFlushCall(0); - - _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); - _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); - CALLFunc((uptr)GSRingBufSimplePacket); -#ifndef __x86_64__ - ADD32ItoR(ESP, 12); -#endif - } - - break; - case 0x12000020: // GS_SMODE2 - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem32( (uptr)PS2GS_BASE(mem), mmreg ); - - if( CHECK_MULTIGS ) - _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); - - recSetSMODE2(); - - if( CHECK_MULTIGS ) { - iFlushCall(0); - - _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); - _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); - CALLFunc((uptr)GSRingBufSimplePacket); -#ifndef __x86_64__ - ADD32ItoR(ESP, 12); -#endif - } - + // SMODE1 and SMODE2 fall back on the gsWrite library. + iFlushCall(0); + _callFunctionArg2((uptr)gsWrite16, MEM_CONSTTAG, mmreg, mem, 0 ); break; - + case 0x12001000: // GS_CSR iFlushCall(0); _callFunctionArg1((uptr)CSRwrite, mmreg, 0); @@ -305,47 +192,10 @@ void gsConstWrite64(u32 mem, int mmreg) { switch (mem) { case 0x12000010: // GS_SMODE1 - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem64((uptr)PS2GS_BASE(mem), mmreg); - - if( CHECK_MULTIGS ) - _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); - - recSetSMODE1(); - - if( CHECK_MULTIGS ) { - iFlushCall(0); - - _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); - _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); - CALLFunc((uptr)GSRingBufSimplePacket); -#ifndef __x86_64__ - ADD32ItoR(ESP, 12); -#endif - } - - break; - case 0x12000020: // GS_SMODE2 - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem64((uptr)PS2GS_BASE(mem), mmreg); - - if( CHECK_MULTIGS ) - _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); - - recSetSMODE2(); - - if( CHECK_MULTIGS ) { - iFlushCall(0); - - _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); - _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); - CALLFunc((uptr)GSRingBufSimplePacket); -#ifndef __x86_64__ - ADD32ItoR(ESP, 12); -#endif - } - + // SMODE1 and SMODE2 fall back on the gsWrite library. + iFlushCall(0); + _callFunctionArg2((uptr)gsWrite16, MEM_CONSTTAG, mmreg, mem, 0 ); break; case 0x12001000: // GS_CSR @@ -381,47 +231,10 @@ void gsConstWrite128(u32 mem, int mmreg) { switch (mem) { case 0x12000010: // GS_SMODE1 - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem128( (uptr)PS2GS_BASE(mem), mmreg); - - if( CHECK_MULTIGS ) - _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); - - recSetSMODE1(); - - if( CHECK_MULTIGS ) { - iFlushCall(0); - - _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); - _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); - CALLFunc((uptr)GSRingBufSimplePacket); -#ifndef __x86_64__ - ADD32ItoR(ESP, 12); -#endif - } - - break; - case 0x12000020: // GS_SMODE2 - _eeMoveMMREGtoR(EAX, mmreg); - _eeWriteConstMem128( (uptr)PS2GS_BASE(mem), mmreg); - - if( CHECK_MULTIGS ) - _callPushArg(MEM_X86TAG|EAX, 0, X86ARG3); - - recSetSMODE2(); - - if( CHECK_MULTIGS ) { - iFlushCall(0); - - _callPushArg(MEM_CONSTTAG, mem&0x13ff, X86ARG2); - _callPushArg(MEM_CONSTTAG, GS_RINGTYPE_MEMWRITE32, X86ARG1); - CALLFunc((uptr)GSRingBufSimplePacket); -#ifndef __x86_64__ - ADD32ItoR(ESP, 12); -#endif - } - + // SMODE1 and SMODE2 fall back on the gsWrite library. + iFlushCall(0); + _callFunctionArg2((uptr)gsWrite16, MEM_CONSTTAG, mmreg, mem, 0 ); break; case 0x12001000: // GS_CSR