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:
Jake.Stine 2008-12-04 18:02:12 +00:00 committed by Gregory Hainaut
parent 61508452e7
commit 209e073b44
4 changed files with 80 additions and 39 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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();