mirror of https://github.com/PCSX2/pcsx2.git
Working on a special end case scenario with the frameskipper, when minfps==maxfps (using 50/50/0/0 as frameskip settings, for example). Previous versions would skip constantly. This version is better, but maybe could be improved yet.
Also: Changed default frameskip options to be a little more aggressive. When using zeros (defaults) skipping starts around 95% instead of 90%. (57fps NTSC and 48 fps PAL). This seems to work a lot better with the new frameskipper. :) git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@388 a6443dda-0b58-4228-96e9-037be469359c
This commit is contained in:
parent
61508452e7
commit
209e073b44
|
@ -236,8 +236,6 @@ u32 UpdateVSyncRate()
|
|||
}
|
||||
|
||||
m_iStart = GetCPUTicks();
|
||||
//iFrameLimitEnable = 1;
|
||||
|
||||
cpuRcntSet();
|
||||
|
||||
return (u32)m_iTicks;
|
||||
|
@ -340,11 +338,6 @@ static __forceinline void frameLimit()
|
|||
|
||||
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();
|
||||
|
@ -355,9 +348,15 @@ static __forceinline void frameLimit()
|
|||
// excessive amounts of "fast forward" syndrome which would occur if we
|
||||
// tried to catch up too much.
|
||||
|
||||
if( (sDeltaTime>>3) > m_iTicks )
|
||||
if( sDeltaTime > m_iTicks*8 )
|
||||
{
|
||||
m_iStart = iEnd;
|
||||
m_iStart = iEnd - m_iTicks;
|
||||
|
||||
// Let the GS Skipper know we lost time.
|
||||
// Keeps the GS skipper from trying to catch up to a framerate
|
||||
// that the limiter already gave up on.
|
||||
|
||||
gsSyncLimiterStartTime( m_iStart );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -372,14 +371,6 @@ static __forceinline void frameLimit()
|
|||
{
|
||||
_TIMESLICE();
|
||||
iEnd = GetCPUTicks();
|
||||
|
||||
/*if( !(*(volatile long*)&iFrameLimitEnable) )
|
||||
{
|
||||
// Frameskipper turned us off
|
||||
m_iStart = iEnd;
|
||||
break;
|
||||
}*/
|
||||
|
||||
sDeltaTime = iEnd - uExpectedEnd;
|
||||
}
|
||||
}
|
||||
|
@ -398,13 +389,13 @@ static __forceinline void VSyncStart(u32 sCycle) // VSync Start
|
|||
if (Config.Patch) applypatch(1); // Apply patches (ToDo: clean up patch code)
|
||||
}
|
||||
|
||||
extern void GSPostVsyncEnd();
|
||||
extern void gsPostVsyncEnd();
|
||||
|
||||
static __forceinline void VSyncEnd(u32 sCycle) // VSync End
|
||||
{
|
||||
iFrame++;
|
||||
|
||||
GSPostVsyncEnd();
|
||||
gsPostVsyncEnd();
|
||||
|
||||
hwIntcIrq(3); // HW Irq
|
||||
psxVBlankEnd(); // psxCounters vBlank End
|
||||
|
|
86
pcsx2/GS.cpp
86
pcsx2/GS.cpp
|
@ -300,6 +300,9 @@ static int g_mtgsCopyLock = 0;
|
|||
|
||||
static s64 m_iSlowTicks=0;
|
||||
static u64 m_iSlowStart=0;
|
||||
static bool m_justSkipped = false;
|
||||
static bool m_StrictSkipping = false;
|
||||
|
||||
static void (*s_prevExecuteVU1Block)() = NULL;
|
||||
|
||||
extern "C" void DummyExecuteVU1Block(void);
|
||||
|
@ -312,14 +315,21 @@ static void OnModeChanged( u32 framerate, u32 iTicks )
|
|||
if( Config.CustomFrameSkip == 0)
|
||||
{
|
||||
// default: load the frameSkipThreshold with a value roughly 90% of our current framerate
|
||||
frameSkipThreshold = ( framerate * 228 ) / 256;
|
||||
frameSkipThreshold = ( framerate * 242 ) / 256;
|
||||
}
|
||||
|
||||
m_iSlowTicks = ( GetTickFrequency() * 50 ) / frameSkipThreshold;
|
||||
|
||||
// sanity check against users who set a "minimum" frame that's higher
|
||||
// than the maximum framerate:
|
||||
if( m_iSlowTicks < iTicks ) m_iSlowTicks = iTicks;
|
||||
// than the maximum framerate. Also, if framerates are within 1/3300th
|
||||
// of a second of each other, assume strict skipping (it's too close,
|
||||
// and could cause excessive skipping).
|
||||
|
||||
if( m_iSlowTicks <= (iTicks + ((s64)GetTickFrequency()/3300)) )
|
||||
{
|
||||
m_iSlowTicks = iTicks;
|
||||
m_StrictSkipping = true;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void gsSetVideoRegionType( u32 isPal )
|
||||
|
@ -691,12 +701,19 @@ void gsReset()
|
|||
|
||||
memset(g_path, 0, sizeof(g_path));
|
||||
memset(s_byRegs, 0, sizeof(s_byRegs));
|
||||
|
||||
gsWaitGS(); // so that the vSync reset below won't explode.
|
||||
}
|
||||
else
|
||||
{
|
||||
SysPrintf("GIF reset\n");
|
||||
}
|
||||
|
||||
|
||||
OnModeChanged(
|
||||
(Config.PsxType & 1) ? FRAMERATE_PAL : FRAMERATE_NTSC,
|
||||
UpdateVSyncRate()
|
||||
);
|
||||
|
||||
#ifndef PCSX2_VIRTUAL_MEM
|
||||
memset(g_RealGSMem, 0, 0x2000);
|
||||
#endif
|
||||
|
@ -1646,7 +1663,32 @@ void gifMFIFOInterrupt()
|
|||
cpuRegs.interrupt &= ~(1 << 11);
|
||||
}
|
||||
|
||||
//extern "C" long iFrameLimitEnable; // used to enable/disable the EE framelimiter.
|
||||
extern "C" void gsSyncLimiterStartTime( u64 startTime )
|
||||
{
|
||||
// This sync issue applies only to configs that are trying to maintain
|
||||
// a perfect "specific" framerate (where both min and max fps are the same)
|
||||
// any other config will eventually equalize out.
|
||||
|
||||
if( !m_StrictSkipping ) return;
|
||||
|
||||
//SysPrintf("LostTime on the EE!\n");
|
||||
|
||||
if( CHECK_MULTIGS )
|
||||
{
|
||||
const u32* stp = (u32*)&startTime;
|
||||
GSRingBufSimplePacket(
|
||||
GS_RINGTYPE_STARTTIME,
|
||||
stp[0],
|
||||
stp[1],
|
||||
0
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iSlowStart = startTime;
|
||||
//m_justSkipped = false;
|
||||
}
|
||||
}
|
||||
|
||||
// FrameSkipper - Measures delta time between calls and issues frameskips
|
||||
// it the time is too long. Also regulates the status of the EE's framelimiter.
|
||||
|
@ -1667,7 +1709,6 @@ 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;
|
||||
|
@ -1691,19 +1732,19 @@ static __forceinline void frameSkip()
|
|||
// -- Standard operation section --
|
||||
// Means neither skipping frames nor force-rendering consecutive frames.
|
||||
|
||||
if( sSlowDeltaTime > 0 )
|
||||
if( sSlowDeltaTime > 0 )
|
||||
{
|
||||
// The game is running below the minimum framerate, so use the SlowExpectedEnd.
|
||||
// The game is running below the minimum framerate.
|
||||
// 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 )
|
||||
if( (m_justSkipped && (sSlowDeltaTime > m_iSlowTicks/2)) ||
|
||||
sSlowDeltaTime > m_iSlowTicks*2 )
|
||||
{
|
||||
//SysPrintf( "Frameskip Initiated! Lateness: %d\n", (int)( sSlowDeltaTime / m_iSlowTicks ) );
|
||||
//SysPrintf( "Frameskip Initiated! Lateness: %d\n", (int)( (sSlowDeltaTime*100) / m_iSlowTicks ) );
|
||||
|
||||
//InterlockedExchange( &iFrameLimitEnable, 0 );
|
||||
GSsetFrameSkip(1);
|
||||
|
||||
if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP )
|
||||
|
@ -1715,12 +1756,15 @@ static __forceinline void frameSkip()
|
|||
}
|
||||
else
|
||||
{
|
||||
// Running at or above full speed, so reset the StartTime
|
||||
// Running at or above full speed, so reset the StartTime since the Limiter
|
||||
// will muck things up. (special case: if skip and limit fps are equal then
|
||||
// we don't reset times since it would cause desyncing. We let the EE regulate
|
||||
// it via calls to gsSyncLimiterStartTime).
|
||||
|
||||
//InterlockedExchange( &iFrameLimitEnable, 1 );
|
||||
m_iSlowStart = iEnd;
|
||||
if( !m_StrictSkipping )
|
||||
m_iSlowStart = iEnd;
|
||||
}
|
||||
justSkipped = false;
|
||||
m_justSkipped = false;
|
||||
return;
|
||||
}
|
||||
else if( FramesToSkip > 0 )
|
||||
|
@ -1745,7 +1789,7 @@ static __forceinline void frameSkip()
|
|||
m_iSlowStart = iEnd - m_iSlowTicks;
|
||||
}
|
||||
|
||||
justSkipped = true;
|
||||
m_justSkipped = true;
|
||||
if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP )
|
||||
InterlockedExchangePointer( &Cpu->ExecuteVU1Block, s_prevExecuteVU1Block );
|
||||
}
|
||||
|
@ -1757,18 +1801,16 @@ static __forceinline void frameSkip()
|
|||
|
||||
// -- 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()
|
||||
extern "C" void gsPostVsyncEnd()
|
||||
{
|
||||
*(u32*)(PS2MEM_GS+0x1000) ^= 0x2000; // swap the vsync field
|
||||
|
||||
|
@ -1796,7 +1838,6 @@ extern "C" void GSPostVsyncEnd()
|
|||
static void _resetFrameskip()
|
||||
{
|
||||
InterlockedExchangePointer( &Cpu->ExecuteVU1Block, s_prevExecuteVU1Block );
|
||||
//InterlockedExchange( &iFrameLimitEnable, 1 );
|
||||
GSsetFrameSkip( 0 );
|
||||
}
|
||||
|
||||
|
@ -1991,6 +2032,11 @@ GS_THREADPROC
|
|||
OnModeChanged( *(u32*)(g_pGSRingPos+4), *(u32*)(g_pGSRingPos+8) );
|
||||
break;
|
||||
|
||||
case GS_RINGTYPE_STARTTIME:
|
||||
m_iSlowStart = *(u64*)(g_pGSRingPos+4);
|
||||
//m_justSkipped = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
SysPrintf("GSThreadProc, bad packet (%x) at g_pGSRingPos: %x, g_pGSWritePos: %x\n", tag, g_pGSRingPos, g_pGSWritePos);
|
||||
|
|
|
@ -66,6 +66,7 @@ enum GS_RINGTYPE
|
|||
, GS_RINGTYPE_SOFTRESET // issues a soft reset for the GIF
|
||||
, GS_RINGTYPE_WRITECSR
|
||||
, GS_RINGTYPE_MODECHANGE // for issued mode changes.
|
||||
, GS_RINGTYPE_STARTTIME // special case for min==max fps frameskip settings
|
||||
};
|
||||
|
||||
// if returns NULL, don't copy (memory is preserved)
|
||||
|
@ -80,6 +81,7 @@ void gsShutdown();
|
|||
void gsReset();
|
||||
void gsSetVideoRegionType( u32 isPal );
|
||||
void gsResetFrameSkip();
|
||||
void gsSyncLimiterStartTime( u64 startTime );
|
||||
|
||||
// mem and size are the ones from GSRingBufCopy
|
||||
extern void GSRINGBUF_DONECOPY(const u8 *mem, u32 size);
|
||||
|
|
|
@ -167,6 +167,8 @@ BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
GetDlgItemText(hW, IDC_CUSTOM_CONSECUTIVE_SKIP, cConsecutiveSkip, 20);
|
||||
Config.CustomConsecutiveSkip = atoi(cConsecutiveSkip);
|
||||
|
||||
// [TODO]: This needs to inform the GS too, but it doesn't matter for now
|
||||
// since the CPU is reset regardless.
|
||||
UpdateVSyncRate();
|
||||
SaveConfig();
|
||||
|
||||
|
|
Loading…
Reference in New Issue