From 03ed0656e1e8177c5a65b58c969dbc4fc6e0284b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 20 Jul 2017 14:20:50 +0200 Subject: [PATCH] - fixed: The frame timer for interpolating the renderer should always take its time from the actual beginning of the frame instead of checking the system timer in real time when rendering starts. This fixes two issues: * timer related texture animations are not being recreated multiple times if a scene renders multiple viewpoints (e.g. camera textures or portals.) * interpolation is smoother when maps have a high think time of multiple milliseconds. A good map to see the difference would be ZDCMP2 which has a think time of 4-5 milliseconds. With the timer taken in real time after the thinkers have run and VSync on this resulted in alternating time slices of 11 and 21 ms between frame interpolations instead of an even 16 as should be done for smooth 60 fps because roughly every second frame was offset by those 5 ms. --- src/d_main.cpp | 3 ++- src/d_net.cpp | 1 + src/posix/cocoa/i_timer.cpp | 10 +++++++++- src/posix/i_system.h | 1 + src/posix/sdl/i_timer.cpp | 10 +++++++++- src/win32/i_system.cpp | 14 +++++++++++++- src/win32/i_system.h | 1 + 7 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index a918ddbb5..6bffbce1b 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1017,7 +1017,8 @@ void D_DoomLoop () lasttic = gametic; I_StartFrame (); } - + I_SetFrameTime(); + // process one or more tics if (singletics) { diff --git a/src/d_net.cpp b/src/d_net.cpp index 0e5e82c07..77a560e60 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1948,6 +1948,7 @@ void TryRunTics (void) C_Ticker (); M_Ticker (); I_GetTime (true); + I_SetFrameTime(); G_Ticker(); gametic++; diff --git a/src/posix/cocoa/i_timer.cpp b/src/posix/cocoa/i_timer.cpp index ac5c49d3e..dbeca1270 100644 --- a/src/posix/cocoa/i_timer.cpp +++ b/src/posix/cocoa/i_timer.cpp @@ -178,9 +178,17 @@ unsigned int I_FPSTime() } +static uint32_t FrameTime; + +void I_SetFrameTime() +{ + FrameTime = I_MSTime(); +} + + double I_GetTimeFrac(uint32_t* ms) { - const uint32_t now = I_MSTime(); + const uint32_t now = FrameTime; if (NULL != ms) { diff --git a/src/posix/i_system.h b/src/posix/i_system.h index c9b90fcb5..4d0577467 100644 --- a/src/posix/i_system.h +++ b/src/posix/i_system.h @@ -67,6 +67,7 @@ extern int (*I_WaitForTic) (int); extern void (*I_FreezeTime) (bool frozen); double I_GetTimeFrac (uint32_t *ms); +void I_SetFrameTime(); // Return a seed value for the RNG. unsigned int I_MakeRNGSeed(); diff --git a/src/posix/sdl/i_timer.cpp b/src/posix/sdl/i_timer.cpp index 04f0ed3dc..a779852c7 100644 --- a/src/posix/sdl/i_timer.cpp +++ b/src/posix/sdl/i_timer.cpp @@ -208,10 +208,18 @@ void I_SelectTimer() } } + +static uint32_t FrameTime; + +void I_SetFrameTime() +{ + FrameTime = SDL_GetTicks(); +} + // Returns the fractional amount of a tic passed since the most recent tic double I_GetTimeFrac (uint32_t *ms) { - uint32_t now = SDL_GetTicks (); + uint32_t now = FrameTime; if (ms) *ms = TicStart + (1000 / TICRATE); if (TicStart == 0) { diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index a43492abf..08c4646c1 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -484,10 +484,22 @@ static void CALLBACK TimerTicked(UINT id, UINT msg, DWORD_PTR user, DWORD_PTR dw // saved tic. // //========================================================================== +static uint32_t FrameTime; + +void I_SetFrameTime() +{ + FrameTime = timeGetTime(); +} double I_GetTimeFrac(uint32_t *ms) { - DWORD now = timeGetTime(); + //DWORD now = MAX(FrameTime, TicStart); + DWORD now = FrameTime; + if (FrameTime < TicStart) + { + // Preliminary kept in to see if this can happen. Should be removed once confirmed ok. + Printf("Timer underflow!\n"); + } if (ms != NULL) { *ms = TicNext; diff --git a/src/win32/i_system.h b/src/win32/i_system.h index c83d3a2cc..2ddb7dff4 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -63,6 +63,7 @@ extern int (*I_WaitForTic) (int); extern void (*I_FreezeTime) (bool frozen); double I_GetTimeFrac (uint32_t *ms); +void I_SetFrameTime(); // Return a seed value for the RNG. unsigned int I_MakeRNGSeed();