Lots of FPS stuff

- Disabled VSync, due to the numerous problems it has.
- Instead, added an FPS cap.
- Frame interpolation is now tied to fpscap != 35.
- By default, the FPS cap is set to the monitor's refresh rate.
- Rewrote the FPS counter.
This commit is contained in:
Sally Coolatta 2022-03-26 23:48:08 -04:00
parent 417bbd1bf2
commit 369d5398c5
13 changed files with 231 additions and 120 deletions

View file

@ -5197,7 +5197,6 @@ boolean TryRunTics(tic_t realtics)
while (neededtic > gametic) while (neededtic > gametic)
{ {
DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic));
prev_tics = I_GetTime();
ps_tictime = I_GetPreciseTime(); ps_tictime = I_GetPreciseTime();

View file

@ -688,6 +688,7 @@ void D_SRB2Loop(void)
{ {
tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS; tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS;
boolean ticked; boolean ticked;
boolean interp;
if (dedicated) if (dedicated)
server = true; server = true;
@ -759,10 +760,19 @@ void D_SRB2Loop(void)
debugload--; debugload--;
#endif #endif
if (!realtics && !singletics && cv_frameinterpolation.value != 1) interp = R_UsingFrameInterpolation();
if (interp)
{ {
I_Sleep(); if (I_CheckFrameCap())
continue; continue;
}
else
{
if (!realtics && !singletics)
{
I_Sleep();
continue;
}
} }
#ifdef HW3SOUND #ifdef HW3SOUND
@ -777,20 +787,22 @@ void D_SRB2Loop(void)
// process tics (but maybe not if realtic == 0) // process tics (but maybe not if realtic == 0)
ticked = TryRunTics(realtics); ticked = TryRunTics(realtics);
if (cv_frameinterpolation.value == 1 && !(paused || P_AutoPause())) if (interp && !(paused || P_AutoPause()))
{ {
static float tictime; static float tictime = 0.0f;
float entertime = I_GetTimeFrac(); float entertime = I_GetTimeFrac();
float ticdiff = 0.0f;
fixed_t entertimefrac; fixed_t entertimefrac;
if (ticked) if (ticked)
tictime = entertime; tictime = entertime;
if (aproxfps < 35.0) ticdiff = entertime - tictime;
if (ticdiff >= 1.0f)
entertimefrac = FRACUNIT; entertimefrac = FRACUNIT;
else else
entertimefrac = FLOAT_TO_FIXED(entertime - tictime); entertimefrac = FLOAT_TO_FIXED(ticdiff);
// renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based // renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based
renderdeltatics = realtics * FRACUNIT; renderdeltatics = realtics * FRACUNIT;
@ -807,7 +819,7 @@ void D_SRB2Loop(void)
renderdeltatics = realtics * FRACUNIT; renderdeltatics = realtics * FRACUNIT;
} }
if (cv_frameinterpolation.value == 1) if (interp)
{ {
D_Display(); D_Display();
} }
@ -817,9 +829,10 @@ void D_SRB2Loop(void)
rendergametic = gametic; rendergametic = gametic;
rendertimeout = entertic+TICRATE/17; rendertimeout = entertic+TICRATE/17;
// Update display, next frame, with current state. if (!interp)
// (Only display if not already done for frame interp) {
cv_frameinterpolation.value == 0 ? D_Display() : (void)0; D_Display();
}
if (moviemode) if (moviemode)
M_SaveFrame(); M_SaveFrame();
@ -828,8 +841,10 @@ void D_SRB2Loop(void)
} }
else if (rendertimeout < entertic) // in case the server hang or netsplit else if (rendertimeout < entertic) // in case the server hang or netsplit
{ {
// (Only display if not already done for frame interp) if (!interp)
cv_frameinterpolation.value == 0 ? D_Display() : (void)0; {
D_Display();
}
if (moviemode) if (moviemode)
M_SaveFrame(); M_SaveFrame();
@ -853,6 +868,11 @@ void D_SRB2Loop(void)
Discord_RunCallbacks(); Discord_RunCallbacks();
} }
#endif #endif
// 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 game logic when its here.
SCR_CalculateFPS();
} }
} }

View file

@ -56,7 +56,7 @@ precise_t I_GetPreciseTime(void);
/** \brief Returns the difference between precise times as microseconds. /** \brief Returns the difference between precise times as microseconds.
*/ */
int I_PreciseToMicros(precise_t d); INT64 I_PreciseToMicros(precise_t d);
/** \brief The I_Sleep function /** \brief The I_Sleep function
@ -64,6 +64,8 @@ int I_PreciseToMicros(precise_t d);
*/ */
void I_Sleep(void); void I_Sleep(void);
boolean I_CheckFrameCap(void);
/** \brief Get events /** \brief Get events
Called by D_SRB2Loop, Called by D_SRB2Loop,

View file

@ -151,4 +151,6 @@ void I_BeginRead(void);
*/ */
void I_EndRead(void); void I_EndRead(void);
UINT32 I_GetRefreshRate(void);
#endif #endif

View file

@ -63,6 +63,7 @@
#include "d_player.h" // KITEM_ constants #include "d_player.h" // KITEM_ constants
#include "k_color.h" #include "k_color.h"
#include "k_grandprix.h" #include "k_grandprix.h"
#include "r_fps.h"
#include "i_joy.h" // for joystick menu controls #include "i_joy.h" // for joystick menu controls
@ -1259,18 +1260,18 @@ static menuitem_t OP_VideoOptionsMenu[] =
{IT_STRING|IT_CVAR, NULL, "Fullscreen", {.cvar = &cv_fullscreen}, 20}, {IT_STRING|IT_CVAR, NULL, "Fullscreen", {.cvar = &cv_fullscreen}, 20},
#endif #endif
#ifdef HWRENDER #ifdef HWRENDER
{IT_STRING | IT_CVAR, NULL, "Renderer", {.cvar = &cv_renderer}, 30}, {IT_STRING | IT_CVAR, NULL, "Renderer", {.cvar = &cv_renderer}, 30},
#else #else
{IT_TRANSTEXT | IT_PAIR, "Renderer", "Software", {.cvar = &cv_renderer}, 30}, {IT_TRANSTEXT | IT_PAIR, "Renderer", "Software", {.cvar = &cv_renderer}, 30},
#endif #endif
{IT_STRING | IT_CVAR | IT_CV_SLIDER, {IT_STRING | IT_CVAR | IT_CV_SLIDER,
NULL, "Gamma", {.cvar = &cv_globalgamma}, 50}, NULL, "Gamma", {.cvar = &cv_globalgamma}, 50},
{IT_STRING | IT_CVAR, NULL, "Show FPS", {.cvar = &cv_ticrate}, 60}, {IT_STRING | IT_CVAR, NULL, "Show FPS", {.cvar = &cv_ticrate}, 60},
{IT_STRING | IT_CVAR, NULL, "Vertical Sync", {.cvar = &cv_vidwait}, 70}, {IT_STRING | IT_CVAR, NULL, "FPS Cap", {.cvar = &cv_fpscap}, 70},
{IT_STRING | IT_CVAR, NULL, "Draw Distance", {.cvar = &cv_drawdist}, 90}, {IT_STRING | IT_CVAR, NULL, "Draw Distance", {.cvar = &cv_drawdist}, 90},
{IT_STRING | IT_CVAR, NULL, "Weather Draw Distance", {.cvar = &cv_drawdist_precip}, 100}, {IT_STRING | IT_CVAR, NULL, "Weather Draw Distance", {.cvar = &cv_drawdist_precip}, 100},
{IT_STRING | IT_CVAR, NULL, "Skyboxes", {.cvar = &cv_skybox}, 110}, {IT_STRING | IT_CVAR, NULL, "Skyboxes", {.cvar = &cv_skybox}, 110},
#ifdef HWRENDER #ifdef HWRENDER

View file

@ -24,6 +24,32 @@
#include "hardware/hw_main.h" // for cv_glshearing #include "hardware/hw_main.h" // for cv_glshearing
#endif #endif
static CV_PossibleValue_t fpscap_cons_t[] = {
{-1, "MIN"},
{1000, "MAX"},
//{0, "Uncapped"},
//{-1, "Refresh"},
{0, NULL}
};
consvar_t cv_fpscap = CVAR_INIT ("fpscap", "-1", CV_SAVE, fpscap_cons_t, NULL);
UINT32 R_GetFramerateCap(void)
{
if (cv_fpscap.value < 0)
{
return I_GetRefreshRate();
}
else
{
return cv_fpscap.value;
}
}
boolean R_UsingFrameInterpolation(void)
{
return (R_GetFramerateCap() != TICRATE); // maybe use ">" instead?
}
static viewvars_t pview_old[MAXSPLITSCREENPLAYERS]; static viewvars_t pview_old[MAXSPLITSCREENPLAYERS];
static viewvars_t pview_new[MAXSPLITSCREENPLAYERS]; static viewvars_t pview_new[MAXSPLITSCREENPLAYERS];
static viewvars_t skyview_old[MAXSPLITSCREENPLAYERS]; static viewvars_t skyview_old[MAXSPLITSCREENPLAYERS];
@ -156,7 +182,7 @@ void R_SetViewContext(enum viewcontext_e _viewcontext)
fixed_t R_InterpolateFixed(fixed_t from, fixed_t to) fixed_t R_InterpolateFixed(fixed_t from, fixed_t to)
{ {
if (cv_frameinterpolation.value == 0) if (!R_UsingFrameInterpolation())
{ {
return to; return to;
} }
@ -166,7 +192,7 @@ fixed_t R_InterpolateFixed(fixed_t from, fixed_t to)
angle_t R_InterpolateAngle(angle_t from, angle_t to) angle_t R_InterpolateAngle(angle_t from, angle_t to)
{ {
if (cv_frameinterpolation.value == 0) if (!R_UsingFrameInterpolation())
{ {
return to; return to;
} }

View file

@ -19,6 +19,11 @@
#include "p_local.h" #include "p_local.h"
#include "r_state.h" #include "r_state.h"
extern consvar_t cv_fpscap;
UINT32 R_GetFramerateCap(void);
boolean R_UsingFrameInterpolation(void);
enum viewcontext_e enum viewcontext_e
{ {
VIEWCONTEXT_PLAYER1 = 0, VIEWCONTEXT_PLAYER1 = 0,

View file

@ -104,9 +104,6 @@ lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
lighttable_t *scalelightfixed[MAXLIGHTSCALE]; lighttable_t *scalelightfixed[MAXLIGHTSCALE];
lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
// Frame interpolation/uncapped
tic_t prev_tics;
// Hack to support extra boom colormaps. // Hack to support extra boom colormaps.
extracolormap_t *extra_colormaps = NULL; extracolormap_t *extra_colormaps = NULL;
@ -175,9 +172,6 @@ consvar_t cv_fov[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("fov4", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange) CVAR_INIT ("fov4", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange)
}; };
// Frame interpolation/uncapped
consvar_t cv_frameinterpolation = CVAR_INIT ("frameinterpolation", "On", CV_SAVE, CV_OnOff, NULL);
// Okay, whoever said homremoval causes a performance hit should be shot. // Okay, whoever said homremoval causes a performance hit should be shot.
consvar_t cv_homremoval = CVAR_INIT ("homremoval", "Yes", CV_SAVE, homremoval_cons_t, NULL); consvar_t cv_homremoval = CVAR_INIT ("homremoval", "Yes", CV_SAVE, homremoval_cons_t, NULL);
@ -1679,5 +1673,5 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_movebob); CV_RegisterVar(&cv_movebob);
// Frame interpolation/uncapped // Frame interpolation/uncapped
CV_RegisterVar(&cv_frameinterpolation); CV_RegisterVar(&cv_fpscap);
} }

View file

@ -116,10 +116,6 @@ extern consvar_t cv_fov[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_skybox; extern consvar_t cv_skybox;
extern consvar_t cv_tailspickup; extern consvar_t cv_tailspickup;
// Frame interpolation (uncapped framerate)
extern tic_t prev_tics;
extern consvar_t cv_frameinterpolation;
// Called by startup code. // Called by startup code.
void R_Init(void); void R_Init(void);

View file

@ -33,12 +33,15 @@
#include "s_sound.h" // ditto #include "s_sound.h" // ditto
#include "g_game.h" // ditto #include "g_game.h" // ditto
#include "p_local.h" // P_AutoPause() #include "p_local.h" // P_AutoPause()
#ifdef HWRENDER #ifdef HWRENDER
#include "hardware/hw_main.h" #include "hardware/hw_main.h"
#include "hardware/hw_light.h" #include "hardware/hw_light.h"
#include "hardware/hw_model.h" #include "hardware/hw_model.h"
#endif #endif
// SRB2Kart
#include "r_fps.h" // R_GetFramerateCap
#if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200)) #if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
#define RUSEASM //MSC.NET can't patch itself #define RUSEASM //MSC.NET can't patch itself
@ -68,16 +71,17 @@ viddef_t vid;
INT32 setmodeneeded; //video mode change needed if > 0 (the mode number to set + 1) INT32 setmodeneeded; //video mode change needed if > 0 (the mode number to set + 1)
UINT8 setrenderneeded = 0; UINT8 setrenderneeded = 0;
static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"}, {24, "24 bits"}, {32, "32 bits"}, {0, NULL}};
static CV_PossibleValue_t shittyscreen_cons_t[] = {{0, "Okay"}, {1, "Shitty"}, {2, "Extra Shitty"}, {0, NULL}};
//added : 03-02-98: default screen mode, as loaded/saved in config //added : 03-02-98: default screen mode, as loaded/saved in config
consvar_t cv_scr_width = CVAR_INIT ("scr_width", "640", CV_SAVE, CV_Unsigned, NULL); consvar_t cv_scr_width = CVAR_INIT ("scr_width", "640", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_scr_height = CVAR_INIT ("scr_height", "400", CV_SAVE, CV_Unsigned, NULL); consvar_t cv_scr_height = CVAR_INIT ("scr_height", "400", CV_SAVE, CV_Unsigned, NULL);
static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"}, {24, "24 bits"}, {32, "32 bits"}, {0, NULL}};
consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL); consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL);
consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL); consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL);
consvar_t cv_vhseffect = CVAR_INIT ("vhspause", "On", CV_SAVE, CV_OnOff, NULL); consvar_t cv_vhseffect = CVAR_INIT ("vhspause", "On", CV_SAVE, CV_OnOff, NULL);
static CV_PossibleValue_t shittyscreen_cons_t[] = {{0, "Okay"}, {1, "Shitty"}, {2, "Extra Shitty"}, {0, NULL}};
consvar_t cv_shittyscreen = CVAR_INIT ("televisionsignal", "Okay", CV_NOSHOWHELP, shittyscreen_cons_t, NULL); consvar_t cv_shittyscreen = CVAR_INIT ("televisionsignal", "Okay", CV_NOSHOWHELP, shittyscreen_cons_t, NULL);
CV_PossibleValue_t cv_renderer_t[] = { CV_PossibleValue_t cv_renderer_t[] = {
@ -518,107 +522,87 @@ boolean SCR_IsAspectCorrect(INT32 width, INT32 height)
); );
} }
// XMOD FPS display double averageFPS = 0.0f;
// moved out of os-specific code for consistency
static boolean ticsgraph[TICRATE];
static tic_t lasttic;
static tic_t totaltics;
static UINT32 fpstime = 0; #define FPS_SAMPLE_RATE (50000) // How often to update FPS samples, in microseconds
static UINT32 lastupdatetime = 0; #define NUM_FPS_SAMPLES 16 // Number of samples to store
#define FPSUPDATERATE 1/20 // What fraction of a second to update at. The fraction will not simplify to 0, trust me. static double fps_samples[NUM_FPS_SAMPLES];
#define FPSMAXSAMPLES 16
static UINT32 fpssamples[FPSMAXSAMPLES]; void SCR_CalculateFPS(void)
static UINT32 fpssampleslen = 0;
static UINT32 fpssum = 0;
double aproxfps = 0.0f;
void SCR_CalcAproxFps(void)
{ {
tic_t i = 0; static precise_t startTime = 0;
tic_t ontic = I_GetTime(); precise_t endTime = 0;
totaltics = 0; static precise_t updateTime = 0;
INT64 updateElapsed = 0;
int i;
// Update FPS time endTime = I_GetPreciseTime();
if (I_PreciseToMicros(fpstime - lastupdatetime) > 1000000 * FPSUPDATERATE)
updateElapsed = I_PreciseToMicros(endTime - updateTime);
if (updateElapsed >= FPS_SAMPLE_RATE)
{ {
if (fpssampleslen == FPSMAXSAMPLES) static int sampleIndex = 0;
INT64 frameElapsed = I_PreciseToMicros(endTime - startTime);
fps_samples[sampleIndex] = frameElapsed / 1000.0f;
sampleIndex++;
if (sampleIndex >= NUM_FPS_SAMPLES)
sampleIndex = 0;
averageFPS = 0.0f;
for (i = 0; i < NUM_FPS_SAMPLES; i++)
{ {
fpssum -= fpssamples[0]; averageFPS += fps_samples[i];
for (i = 1; i < fpssampleslen; i++)
fpssamples[i-1] = fpssamples[i];
} }
else averageFPS = 1000.0f / (averageFPS / NUM_FPS_SAMPLES);
fpssampleslen++;
fpssamples[fpssampleslen-1] = I_GetPreciseTime() - fpstime; updateTime = endTime;
fpssum += fpssamples[fpssampleslen-1];
aproxfps = 1000000 / (I_PreciseToMicros(fpssum) / (double)fpssampleslen);
lastupdatetime = I_GetPreciseTime();
} }
fpstime = I_GetPreciseTime(); startTime = endTime;
// Update ticrate time
for (i = lasttic + 1; i < TICRATE+lasttic && i < ontic; ++i)
ticsgraph[i % TICRATE] = false;
ticsgraph[ontic % TICRATE] = true;
for (i = 0;i < TICRATE;++i)
if (ticsgraph[i])
++totaltics;
lasttic = ontic;
} }
void SCR_DisplayTicRate(void) void SCR_DisplayTicRate(void)
{ {
const UINT8 *ticcntcolor = NULL; const UINT8 *ticcntcolor = NULL;
UINT32 cap = R_GetFramerateCap();
UINT32 benchmark = (cap == 0) ? I_GetRefreshRate() : cap;
INT32 x = 318;
double fps = ceil(averageFPS);
// draw "FPS" // draw "FPS"
V_DrawFixedPatch(306<<FRACBITS, 183<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, framecounter, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE)); V_DrawFixedPatch(306<<FRACBITS, 183<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, framecounter, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE));
if (cv_frameinterpolation.value == 1) if (fps > (benchmark - 5))
{ ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE);
if (aproxfps <= 15.0f) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE); else if (fps < 20)
else if (aproxfps >= 60.0f) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE); ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE);
/* if (cap != 0)
if (cv_fpscap.value != 0)
{
// draw total frame:
//V_DrawPingNum(318, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, cv_fpscap.value, ticcntcolor);
// draw "/"
//V_DrawFixedPatch(306<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, frameslash, ticcntcolor);
// draw our actual framerate
V_DrawPingNum(306, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, aproxfps, ticcntcolor);
}
else
*/
{
// draw our actual framerate
V_DrawPingNum(318, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, aproxfps, ticcntcolor);
}
}
else
{ {
if (totaltics <= 15) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE); UINT32 digits = 1;
else if (totaltics >= TICRATE) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE); UINT32 c2 = cap;
while (c2 > 0)
{
c2 = c2 / 10;
digits++;
}
// draw total frame: // draw total frame:
V_DrawPingNum(318, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, TICRATE, ticcntcolor); V_DrawPingNum(x, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, cap, ticcntcolor);
x -= digits * 4;
// draw "/" // draw "/"
V_DrawFixedPatch(306<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, frameslash, ticcntcolor); V_DrawFixedPatch(x<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, frameslash, ticcntcolor);
// draw our actual framerate
V_DrawPingNum(306, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, totaltics, ticcntcolor);
} }
// draw our actual framerate
V_DrawPingNum(x, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, fps, ticcntcolor);
} }
// SCR_DisplayLocalPing // SCR_DisplayLocalPing

View file

@ -191,7 +191,8 @@ extern boolean R_SSE2;
extern viddef_t vid; extern viddef_t vid;
extern INT32 setmodeneeded; // mode number to set if needed, or 0 extern INT32 setmodeneeded; // mode number to set if needed, or 0
extern UINT8 setrenderneeded; extern UINT8 setrenderneeded;
extern double aproxfps;
extern double averageFPS;
void SCR_ChangeRenderer(void); void SCR_ChangeRenderer(void);
@ -231,7 +232,7 @@ void SCR_CheckDefaultMode(void);
// Set the mode number which is saved in the config // Set the mode number which is saved in the config
void SCR_SetDefaultMode(void); void SCR_SetDefaultMode(void);
void SCR_CalcAproxFps(void); void SCR_CalculateFPS(void);
FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height); FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height);

View file

@ -173,7 +173,6 @@ static char returnWadPath[256];
#include "../d_net.h" #include "../d_net.h"
#include "../g_game.h" #include "../g_game.h"
#include "../filesrch.h" #include "../filesrch.h"
#include "../k_pwrlv.h"
#include "endtxt.h" #include "endtxt.h"
#include "sdlmain.h" #include "sdlmain.h"
@ -181,7 +180,10 @@ static char returnWadPath[256];
#include "../m_argv.h" #include "../m_argv.h"
// SRB2Kart
#include "../k_pwrlv.h"
#include "../r_main.h" // Frame interpolation/uncapped #include "../r_main.h" // Frame interpolation/uncapped
#include "../r_fps.h"
#ifdef MAC_ALERT #ifdef MAC_ALERT
#include "macosx/mac_alert.h" #include "macosx/mac_alert.h"
@ -1669,9 +1671,9 @@ precise_t I_GetPreciseTime(void)
return SDL_GetPerformanceCounter(); return SDL_GetPerformanceCounter();
} }
int I_PreciseToMicros(precise_t d) INT64 I_PreciseToMicros(precise_t d)
{ {
return (int)(d / (timer_frequency / 1000000.0)); return (INT64)(d / (timer_frequency / 1000000.0));
} }
// //
@ -1692,6 +1694,58 @@ void I_Sleep(void)
SDL_Delay(cv_sleep.value); SDL_Delay(cv_sleep.value);
} }
boolean I_CheckFrameCap(void)
{
static precise_t start = 0;
precise_t end;
INT64 elapsed;
UINT32 capFrames = R_GetFramerateCap();
int capMicros = 0;
end = I_GetPreciseTime();
if (capFrames == 0)
{
// We don't want to cap.
start = end;
return false;
}
elapsed = I_PreciseToMicros(end - start);
capMicros = 1000000 / capFrames;
if (elapsed < capMicros)
{
// Wait to draw the next frame.
UINT32 wait = ((capMicros - elapsed) / 1000);
if (cv_sleep.value > 1)
{
// 1 is the default, and in non-interpolated mode is just the bare minimum wait.
// Since we're already adding some wait with an FPS cap, only apply when it's above 1.
wait += cv_sleep.value - 1;
}
// If the wait's greater than our granularity value,
// we'll just burn the couple extra cycles in the main loop
// in order to get to the next frame. This makes us reach just
// that much closer to exactly the FPS cap!
#define DELAY_GRANULARITY 10 // 10ms is the average clock tick of most OS scheduling. (https://www.libsdl.org/release/SDL-1.2.15/docs/html/sdldelay.html)
if (wait >= DELAY_GRANULARITY)
{
SDL_Delay(wait);
}
#undef DELAY_GRANULARITY
return true;
}
// Waited enough to draw again.
start = end;
return false;
}
#ifdef NEWSIGNALHANDLER #ifdef NEWSIGNALHANDLER
static void newsignalhandler_Warn(const char *pr) static void newsignalhandler_Warn(const char *pr)
{ {

View file

@ -1293,7 +1293,7 @@ void I_FinishUpdate(void)
if (rendermode == render_none) if (rendermode == render_none)
return; //Alam: No software or OpenGl surface return; //Alam: No software or OpenGl surface
SCR_CalcAproxFps(); //SCR_CalculateFPS(); // Moved to main loop
if (I_SkipFrame()) if (I_SkipFrame())
return; return;
@ -1583,8 +1583,15 @@ static SDL_bool Impl_CreateContext(void)
int flags = 0; // Use this to set SDL_RENDERER_* flags now int flags = 0; // Use this to set SDL_RENDERER_* flags now
if (usesdl2soft) if (usesdl2soft)
flags |= SDL_RENDERER_SOFTWARE; flags |= SDL_RENDERER_SOFTWARE;
#if 0
// This shit is BROKEN.
// - The version of SDL we're using cannot toggle VSync at runtime. We'll need a new SDL version implemented to have this work properly.
// - cv_vidwait is initialized before config is loaded, so it's forced to default value at runtime, and forced off when switching. The config loading code would need restructured.
// - With both this & frame interpolation on, I_FinishUpdate takes x10 longer. At this point, it is simpler to use a standard FPS cap.
// So you can probably guess why I'm kinda over this, I'm just disabling it.
else if (cv_vidwait.value) else if (cv_vidwait.value)
flags |= SDL_RENDERER_PRESENTVSYNC; flags |= SDL_RENDERER_PRESENTVSYNC;
#endif
if (!renderer) if (!renderer)
renderer = SDL_CreateRenderer(window, -1, flags); renderer = SDL_CreateRenderer(window, -1, flags);
@ -2064,3 +2071,23 @@ void I_ShutdownGraphics(void)
framebuffer = SDL_FALSE; framebuffer = SDL_FALSE;
} }
#endif #endif
UINT32 I_GetRefreshRate(void)
{
int index = SDL_GetWindowDisplayIndex(window);
SDL_DisplayMode m;
if (SDL_WasInit(SDL_INIT_VIDEO) == 0)
{
// Video not init yet.
return 0;
}
if (SDL_GetDesktopDisplayMode(index, &m) != 0)
{
// Error has occurred.
return 0;
}
return m.refresh_rate;
}