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
|
// D_SRB2Loop
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
@ -720,10 +697,13 @@ void D_SRB2Loop(void)
|
||||||
{
|
{
|
||||||
tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS;
|
tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS;
|
||||||
static lumpnum_t gstartuplumpnum;
|
static lumpnum_t gstartuplumpnum;
|
||||||
boolean ticked;
|
|
||||||
boolean interp;
|
boolean ticked = false;
|
||||||
|
boolean interp = false;
|
||||||
boolean doDisplay = false;
|
boolean doDisplay = false;
|
||||||
boolean frameCap = false;
|
|
||||||
|
precise_t frameTime = 0;
|
||||||
|
int frameElapsed = 0;
|
||||||
|
|
||||||
if (dedicated)
|
if (dedicated)
|
||||||
server = true;
|
server = true;
|
||||||
|
@ -775,6 +755,9 @@ void D_SRB2Loop(void)
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
frameTime = I_GetPreciseTime();
|
||||||
|
frameElapsed = 0;
|
||||||
|
|
||||||
if (lastwipetic)
|
if (lastwipetic)
|
||||||
{
|
{
|
||||||
oldentertics = lastwipetic;
|
oldentertics = lastwipetic;
|
||||||
|
@ -804,19 +787,6 @@ void D_SRB2Loop(void)
|
||||||
doDisplay = false;
|
doDisplay = false;
|
||||||
ticked = 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
|
#ifdef HW3SOUND
|
||||||
HW3S_BeginFrameUpdate();
|
HW3S_BeginFrameUpdate();
|
||||||
#endif
|
#endif
|
||||||
|
@ -872,15 +842,6 @@ void D_SRB2Loop(void)
|
||||||
tictime = entertime;
|
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 (!(paused || P_AutoPause()))
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -912,11 +873,6 @@ void D_SRB2Loop(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (frameCap)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderdeltatics = realtics * FRACUNIT;
|
renderdeltatics = realtics * FRACUNIT;
|
||||||
rendertimefrac = FRACUNIT;
|
rendertimefrac = FRACUNIT;
|
||||||
}
|
}
|
||||||
|
@ -940,6 +896,19 @@ void D_SRB2Loop(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LUA_Step();
|
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);
|
int I_PreciseToMicros(precise_t d);
|
||||||
|
|
||||||
/** \brief The I_Sleep function
|
/** \brief Sleeps by the value of cv_sleep
|
||||||
|
|
||||||
\return void
|
\return void
|
||||||
*/
|
*/
|
||||||
void I_Sleep(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
|
/** \brief Get events
|
||||||
|
|
||||||
|
|
|
@ -509,7 +509,7 @@ void SCR_DisplayTicRate(void)
|
||||||
INT32 ticcntcolor = 0;
|
INT32 ticcntcolor = 0;
|
||||||
const INT32 h = vid.height-(8*vid.dupy);
|
const INT32 h = vid.height-(8*vid.dupy);
|
||||||
UINT32 cap = R_GetFramerateCap();
|
UINT32 cap = R_GetFramerateCap();
|
||||||
double fps = ceil(averageFPS);
|
double fps = round(averageFPS);
|
||||||
|
|
||||||
if (gamestate == GS_NULL)
|
if (gamestate == GS_NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -525,10 +525,11 @@ void SCR_DisplayTicRate(void)
|
||||||
ticcntcolor = V_GREENMAP;
|
ticcntcolor = V_GREENMAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (cv_ticrate.value == 2) // compact counter
|
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
|
else if (cv_ticrate.value == 1) // full counter
|
||||||
{
|
{
|
||||||
if (cap > 0)
|
if (cap > 0)
|
||||||
|
|
|
@ -2167,6 +2167,10 @@ float I_GetTimeFrac(void)
|
||||||
return elapsed_tics;
|
return elapsed_tics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// I_GetPreciseTime
|
||||||
|
// returns time in precise_t
|
||||||
|
//
|
||||||
precise_t I_GetPreciseTime(void)
|
precise_t I_GetPreciseTime(void)
|
||||||
{
|
{
|
||||||
return SDL_GetPerformanceCounter();
|
return SDL_GetPerformanceCounter();
|
||||||
|
@ -2184,7 +2188,7 @@ int I_PreciseToMicros(precise_t d)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
//I_StartupTimer
|
// I_StartupTimer
|
||||||
//
|
//
|
||||||
void I_StartupTimer(void)
|
void I_StartupTimer(void)
|
||||||
{
|
{
|
||||||
|
@ -2195,71 +2199,82 @@ void I_StartupTimer(void)
|
||||||
elapsed_tics = 0.0;
|
elapsed_tics = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// I_Sleep
|
||||||
|
// Sleeps by the value of cv_sleep
|
||||||
|
//
|
||||||
void I_Sleep(void)
|
void I_Sleep(void)
|
||||||
{
|
{
|
||||||
if (cv_sleep.value != -1)
|
if (cv_sleep.value != -1)
|
||||||
SDL_Delay(cv_sleep.value);
|
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();
|
const UINT32 capFrames = R_GetFramerateCap();
|
||||||
int capMicros = 0;
|
int capMicros = 0;
|
||||||
|
|
||||||
int elapsed;
|
|
||||||
|
|
||||||
if (capFrames == 0)
|
if (capFrames == 0)
|
||||||
{
|
{
|
||||||
// We don't want to cap.
|
// We don't want to cap.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
elapsed = I_PreciseToMicros(end - start);
|
|
||||||
capMicros = 1000000 / capFrames;
|
capMicros = 1000000 / capFrames;
|
||||||
|
|
||||||
if (elapsed < capMicros)
|
if (elapsed < capMicros)
|
||||||
{
|
{
|
||||||
// Experimental variable delay code.
|
const INT64 error = capMicros / 40;
|
||||||
if (cv_sleep.value > 0)
|
// 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.
|
precise_t sleepStart = I_GetPreciseTime();
|
||||||
INT64 wait = (capMicros - elapsed);
|
precise_t sleepEnd = sleepStart;
|
||||||
|
int sleepElasped = 0;
|
||||||
|
|
||||||
while (wait > 0)
|
if (wait > delayGranularity && cv_sleep.value != -1)
|
||||||
{
|
{
|
||||||
precise_t sleepStart = I_GetPreciseTime();
|
// Wait 1ms at a time (on default settings)
|
||||||
precise_t sleepEnd = sleepStart;
|
// until we're close enough.
|
||||||
int sleepElasped = 0;
|
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();
|
sleepEnd = I_GetPreciseTime();
|
||||||
sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart);
|
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)
|
break;
|
||||||
{
|
|
||||||
sleepEnd = I_GetPreciseTime();
|
|
||||||
sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wait -= sleepElasped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wait -= sleepElasped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We took our nap.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Waited enough to draw again.
|
// We're lagging behind.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue