mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2024-11-15 09:11:48 +00:00
Handle the sleep at the end of D_SRB2Loop instead of the start
Simplifies logic in the other parts of the loop, and fixes problems with it frequently waiting too long.
This commit is contained in:
parent
685190fe40
commit
b18e53417a
4 changed files with 79 additions and 90 deletions
75
src/d_main.c
75
src/d_main.c
|
@ -687,29 +687,6 @@ static void D_Display(void)
|
|||
}
|
||||
}
|
||||
|
||||
static boolean D_CheckFrameCap(void)
|
||||
{
|
||||
static boolean init = false;
|
||||
static precise_t startCap = 0;
|
||||
precise_t endCap = 0;
|
||||
|
||||
endCap = I_GetPreciseTime();
|
||||
|
||||
if (init == false)
|
||||
{
|
||||
startCap = endCap;
|
||||
init = true;
|
||||
}
|
||||
else if (I_CheckFrameCap(startCap, endCap))
|
||||
{
|
||||
// Framerate should be capped.
|
||||
return true;
|
||||
}
|
||||
|
||||
startCap = endCap;
|
||||
return false;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// D_SRB2Loop
|
||||
// =========================================================================
|
||||
|
@ -720,10 +697,13 @@ void D_SRB2Loop(void)
|
|||
{
|
||||
tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS;
|
||||
static lumpnum_t gstartuplumpnum;
|
||||
boolean ticked;
|
||||
boolean interp;
|
||||
|
||||
boolean ticked = false;
|
||||
boolean interp = false;
|
||||
boolean doDisplay = false;
|
||||
boolean frameCap = false;
|
||||
|
||||
precise_t frameTime = 0;
|
||||
int frameElapsed = 0;
|
||||
|
||||
if (dedicated)
|
||||
server = true;
|
||||
|
@ -775,6 +755,9 @@ void D_SRB2Loop(void)
|
|||
|
||||
for (;;)
|
||||
{
|
||||
frameTime = I_GetPreciseTime();
|
||||
frameElapsed = 0;
|
||||
|
||||
if (lastwipetic)
|
||||
{
|
||||
oldentertics = lastwipetic;
|
||||
|
@ -804,19 +787,6 @@ void D_SRB2Loop(void)
|
|||
doDisplay = false;
|
||||
ticked = false;
|
||||
|
||||
frameCap = D_CheckFrameCap();
|
||||
|
||||
// Moved to here from I_FinishUpdate.
|
||||
// It doesn't track fades properly anymore by being here (might be easy fix),
|
||||
// but it's a little more accurate for actual rendering when its here.
|
||||
SCR_CalculateFPS();
|
||||
|
||||
if (!realtics && !singletics)
|
||||
{
|
||||
if (frameCap)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef HW3SOUND
|
||||
HW3S_BeginFrameUpdate();
|
||||
#endif
|
||||
|
@ -872,15 +842,6 @@ void D_SRB2Loop(void)
|
|||
tictime = entertime;
|
||||
}
|
||||
|
||||
// Handle interp sleep / framerate cap here.
|
||||
// TryRunTics needs ran if possible to prevent lagged map changes,
|
||||
// (and if that runs, the code above needs to also run)
|
||||
// so this is done here after TryRunTics.
|
||||
if (frameCap)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(paused || P_AutoPause()))
|
||||
{
|
||||
#if 0
|
||||
|
@ -912,11 +873,6 @@ void D_SRB2Loop(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (frameCap)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
renderdeltatics = realtics * FRACUNIT;
|
||||
rendertimefrac = FRACUNIT;
|
||||
}
|
||||
|
@ -940,6 +896,19 @@ void D_SRB2Loop(void)
|
|||
#endif
|
||||
|
||||
LUA_Step();
|
||||
|
||||
// Moved to here from I_FinishUpdate.
|
||||
// It doesn't track fades properly anymore by being here (might be easy fix),
|
||||
// but it's a little more accurate for actual rendering when its here.
|
||||
SCR_CalculateFPS();
|
||||
|
||||
// Fully completed frame made, handle frame cap delay.
|
||||
frameElapsed = I_PreciseToMicros(I_GetPreciseTime() - frameTime);
|
||||
|
||||
if (!singletics)
|
||||
{
|
||||
I_FrameCapSleep(frameElapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,13 +58,17 @@ precise_t I_GetPreciseTime(void);
|
|||
*/
|
||||
int I_PreciseToMicros(precise_t d);
|
||||
|
||||
/** \brief The I_Sleep function
|
||||
/** \brief Sleeps by the value of cv_sleep
|
||||
|
||||
\return void
|
||||
*/
|
||||
void I_Sleep(void);
|
||||
|
||||
boolean I_CheckFrameCap(precise_t start, precise_t end);
|
||||
/** \brief Sleeps for a variable amount of time, depending on how much time the last frame took.
|
||||
|
||||
\return void
|
||||
*/
|
||||
boolean I_FrameCapSleep(const int elapsed);
|
||||
|
||||
/** \brief Get events
|
||||
|
||||
|
|
|
@ -509,7 +509,7 @@ void SCR_DisplayTicRate(void)
|
|||
INT32 ticcntcolor = 0;
|
||||
const INT32 h = vid.height-(8*vid.dupy);
|
||||
UINT32 cap = R_GetFramerateCap();
|
||||
double fps = ceil(averageFPS);
|
||||
double fps = round(averageFPS);
|
||||
|
||||
if (gamestate == GS_NULL)
|
||||
return;
|
||||
|
@ -525,10 +525,11 @@ void SCR_DisplayTicRate(void)
|
|||
ticcntcolor = V_GREENMAP;
|
||||
}
|
||||
|
||||
|
||||
if (cv_ticrate.value == 2) // compact counter
|
||||
V_DrawString(vid.width-(32*vid.dupx), h,
|
||||
ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%04.0f", fps));
|
||||
{
|
||||
V_DrawRightAlignedString(vid.width, h,
|
||||
ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%04.2f", averageFPS)); // use averageFPS directly
|
||||
}
|
||||
else if (cv_ticrate.value == 1) // full counter
|
||||
{
|
||||
if (cap > 0)
|
||||
|
|
|
@ -2167,6 +2167,10 @@ float I_GetTimeFrac(void)
|
|||
return elapsed_tics;
|
||||
}
|
||||
|
||||
//
|
||||
// I_GetPreciseTime
|
||||
// returns time in precise_t
|
||||
//
|
||||
precise_t I_GetPreciseTime(void)
|
||||
{
|
||||
return SDL_GetPerformanceCounter();
|
||||
|
@ -2184,7 +2188,7 @@ int I_PreciseToMicros(precise_t d)
|
|||
}
|
||||
|
||||
//
|
||||
//I_StartupTimer
|
||||
// I_StartupTimer
|
||||
//
|
||||
void I_StartupTimer(void)
|
||||
{
|
||||
|
@ -2195,71 +2199,82 @@ void I_StartupTimer(void)
|
|||
elapsed_tics = 0.0;
|
||||
}
|
||||
|
||||
//
|
||||
// I_Sleep
|
||||
// Sleeps by the value of cv_sleep
|
||||
//
|
||||
void I_Sleep(void)
|
||||
{
|
||||
if (cv_sleep.value != -1)
|
||||
SDL_Delay(cv_sleep.value);
|
||||
}
|
||||
|
||||
boolean I_CheckFrameCap(precise_t start, precise_t end)
|
||||
//
|
||||
// I_FrameCapSleep
|
||||
// Sleeps for a variable amount of time, depending on how much time the last frame took.
|
||||
//
|
||||
boolean I_FrameCapSleep(const int elapsed)
|
||||
{
|
||||
const INT64 delayGranularity = 2000;
|
||||
// I picked 2ms as it's what GZDoom uses before it stops trying to sleep,
|
||||
// but maybe other values might work better.
|
||||
|
||||
const UINT32 capFrames = R_GetFramerateCap();
|
||||
int capMicros = 0;
|
||||
|
||||
int elapsed;
|
||||
|
||||
if (capFrames == 0)
|
||||
{
|
||||
// We don't want to cap.
|
||||
return false;
|
||||
}
|
||||
|
||||
elapsed = I_PreciseToMicros(end - start);
|
||||
capMicros = 1000000 / capFrames;
|
||||
|
||||
if (elapsed < capMicros)
|
||||
{
|
||||
// Experimental variable delay code.
|
||||
if (cv_sleep.value > 0)
|
||||
const INT64 error = capMicros / 40;
|
||||
// 2.5% ... How much we might expect the framerate to flucuate.
|
||||
// No exact logic behind this number, simply tried stuff until the framerate
|
||||
// reached the cap 300 more often and only overshot it occasionally.
|
||||
|
||||
INT64 wait = (capMicros - elapsed) - error;
|
||||
|
||||
while (wait > 0)
|
||||
{
|
||||
const INT64 delayGranularity = 2000; // 2ms, I picked this as it's what GZDoom uses before it stops trying to sleep.
|
||||
INT64 wait = (capMicros - elapsed);
|
||||
precise_t sleepStart = I_GetPreciseTime();
|
||||
precise_t sleepEnd = sleepStart;
|
||||
int sleepElasped = 0;
|
||||
|
||||
while (wait > 0)
|
||||
if (wait > delayGranularity && cv_sleep.value != -1)
|
||||
{
|
||||
precise_t sleepStart = I_GetPreciseTime();
|
||||
precise_t sleepEnd = sleepStart;
|
||||
int sleepElasped = 0;
|
||||
// Wait 1ms at a time (on default settings)
|
||||
// until we're close enough.
|
||||
SDL_Delay(cv_sleep.value);
|
||||
|
||||
if (wait > delayGranularity)
|
||||
sleepEnd = I_GetPreciseTime();
|
||||
sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
// When we have an extremely fine wait,
|
||||
// we do this to spin-lock the remaining time.
|
||||
while (sleepElasped < wait)
|
||||
{
|
||||
// Wait 1ms at a time (on default settings)
|
||||
// until we're close enough.
|
||||
SDL_Delay(cv_sleep.value);
|
||||
|
||||
sleepEnd = I_GetPreciseTime();
|
||||
sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
// When we have an extremely fine wait,
|
||||
// we do this to spin-lock the remaining time.
|
||||
|
||||
while (sleepElasped < wait)
|
||||
{
|
||||
sleepEnd = I_GetPreciseTime();
|
||||
sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart);
|
||||
}
|
||||
}
|
||||
|
||||
wait -= sleepElasped;
|
||||
break;
|
||||
}
|
||||
|
||||
wait -= sleepElasped;
|
||||
}
|
||||
|
||||
// We took our nap.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Waited enough to draw again.
|
||||
// We're lagging behind.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue