From ac4f317879a7f983b946aaae8682a5ccbda57b2b Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 22 Feb 2025 13:22:00 +0100 Subject: [PATCH] port: changes to the video settings PR: - change FPS calculation to use average FPS, use real time instead of render time for interval timing - remove Maximize Window (you already have a maximize button and it's saved to the INI) - remove Display FPS Interval from settings (the average user won't care and whoever cares can change it in the INI) - remove the tickrate override flag and implicit tickrate adjustment in the framerate limit option, instead add one checkbox to uncap tickrate (mostly because I'd like the game to default to the og 60 FPS cap since high FPS is still unstable) - rearrange some options a bit --- port/include/video.h | 6 +- port/src/main.c | 2 - port/src/optionsmenu.c | 147 +++++++---------------------------------- port/src/video.c | 54 ++++++++------- src/game/lv.c | 24 +++++-- src/include/data.h | 1 - 6 files changed, 73 insertions(+), 161 deletions(-) diff --git a/port/include/video.h b/port/include/video.h index 0c468dcbb..288c9b284 100644 --- a/port/include/video.h +++ b/port/include/video.h @@ -21,7 +21,6 @@ void videoStartFrame(void); void videoSubmitCommands(Gfx *cmds); void videoClearScreen(void); void videoEndFrame(void); -f64 videoGetDiffTime(void); void *videoGetWindowHandle(void); @@ -47,9 +46,11 @@ s32 videoGetNumDisplayModes(void); s32 videoGetVsync(void); s32 videoGetFramerateLimit(void); s32 videoGetDisplayFPS(void); -s32 videoGetDisplayFPSDivisor(void); s32 videoGetMSAA(void); +f32 videoGetAverageFPS(void); +f64 videoGetLastRenderTime(void); + void videoSetWindowOffset(s32 x, s32 y); void videoSetFullscreen(s32 fs); void videoSetFullscreenMode(s32 mode); @@ -60,7 +61,6 @@ void videoSetDisplayMode(const s32 index); void videoSetVsync(const s32 vsync); void videoSetFramerateLimit(const s32 limit); void videoSetDisplayFPS(const s32 displayfps); -void videoSetDisplayFPSDivisor(const s32 divisor); void videoSetMSAA(const s32 msaa); s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize); diff --git a/port/src/main.c b/port/src/main.c index 0b7e7e6c2..a622bc078 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -36,7 +36,6 @@ u32 g_VmNumPageReplaces = 0; u8 g_VmShowStats = 0; s32 g_TickRateDiv = 1; -s32 g_TickRateDivOverride = 0; s32 g_TickExtraSleep = true; s32 g_SkipIntro = false; @@ -166,7 +165,6 @@ PD_CONSTRUCTOR static void gameConfigInit(void) configRegisterInt("Game.MenuMouseControl", &g_MenuMouseControl, 0, 1); configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f); configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10); - configRegisterInt("Game.TickRateDivisorOverride", &g_TickRateDivOverride, 0, 1); configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1); configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1); configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1); diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index 8f0eaa2c1..7629d9f8d 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -721,19 +721,6 @@ static MenuItemHandlerResult menuhandlerFullScreenMode(s32 operation, struct men return 0; } -static MenuItemHandlerResult menuhandlerMaximizeWindow(s32 operation, struct menuitem *item, union handlerdata *data) -{ - switch (operation) { - case MENUOP_GET: - return videoGetMaximizeWindow(); - case MENUOP_SET: - videoSetMaximizeWindow(data->checkbox.value); - break; - } - - return 0; -} - static MenuItemHandlerResult menuhandlerCenterWindow(s32 operation, struct menuitem *item, union handlerdata *data) { switch (operation) { @@ -786,9 +773,6 @@ static MenuItemHandlerResult menuhandlerFramerateLimit(s32 operation, struct men data->slider.value = videoGetFramerateLimit(); break; case MENUOP_SET: - if (!g_TickRateDivOverride) { - g_TickRateDiv = (data->slider.value == 0 || data->slider.value > 60) ? 0 : 1; - } videoSetFramerateLimit(data->slider.value); break; case MENUOP_GETSLIDERLABEL: @@ -937,27 +921,6 @@ static MenuItemHandlerResult menuhandlerDisplayFPS(s32 operation, struct menuite return 0; } -static MenuItemHandlerResult menuhandlerDisplayFPSInterval(s32 operation, struct menuitem *item, union handlerdata *data) -{ - switch (operation) { - case MENUOP_GETSLIDER: - data->slider.value = videoGetDisplayFPSDivisor() - 1; - break; - case MENUOP_SET: - videoSetDisplayFPSDivisor(data->dropdown.value + 1); - break; - case MENUOP_GETSLIDERLABEL: - // NOTE: data->slider.label length must not exceed 15. - if (data->slider.value == 0) { - strcpy(data->slider.label, "1 Sec"); - } else { - sprintf(data->slider.label, "1/%d Secs", data->slider.value + 1); - } - } - - return 0; -} - static MenuItemHandlerResult menuhandlerGeMuzzleFlashes(s32 operation, struct menuitem *item, union handlerdata *data) { switch (operation) { @@ -971,44 +934,14 @@ static MenuItemHandlerResult menuhandlerGeMuzzleFlashes(s32 operation, struct me return 0; } -static MenuItemHandlerResult menuhandlerTickrateDivisorOverride(s32 operation, struct menuitem *item, union handlerdata *data) +static MenuItemHandlerResult menuhandlerUncapTickrate(s32 operation, struct menuitem *item, union handlerdata *data) { - s32 framerateLimit; - switch (operation) { case MENUOP_GET: - return g_TickRateDivOverride; + return (g_TickRateDiv == 0); case MENUOP_SET: - g_TickRateDivOverride = data->checkbox.value; - if (!g_TickRateDivOverride) { - framerateLimit = videoGetFramerateLimit(); - g_TickRateDiv = (framerateLimit == 0 || framerateLimit > 60) ? 0 : 1; - } - } - - return 0; -} - -static MenuItemHandlerResult menuhandlerTickrateDivisor(s32 operation, struct menuitem *item, union handlerdata *data) -{ - s32 framerateLimit; - - switch (operation) { - case MENUOP_CHECKHIDDEN: - if (!g_TickRateDivOverride) { - return true; - } + g_TickRateDiv = !data->checkbox.value; break; - case MENUOP_GETSLIDER: - data->slider.value = g_TickRateDiv; - break; - case MENUOP_SET: - if (g_TickRateDivOverride) { - g_TickRateDiv = data->slider.value; - } else { - framerateLimit = videoGetFramerateLimit(); - g_TickRateDiv = (framerateLimit == 0 || framerateLimit > 60) ? 0 : 1; - } } return 0; @@ -1087,14 +1020,6 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, menuhandlerResolution, }, - { - MENUITEMTYPE_CHECKBOX, - 0, - MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Maximize Window", - 0, - menuhandlerMaximizeWindow, - }, { MENUITEMTYPE_CHECKBOX, 0, @@ -1107,9 +1032,9 @@ struct menuitem g_ExtendedVideoMenuItems[] = { MENUITEMTYPE_DROPDOWN, 0, MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"HUD Centering", + (uintptr_t)"Anti-aliasing", 0, - menuhandlerCenterHUD, + menuhandlerMSAA, }, { MENUITEMTYPE_SEPARATOR, @@ -1135,6 +1060,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = { VIDEO_MAX_FPS, menuhandlerFramerateLimit, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Uncap Tickrate", + 0, + menuhandlerUncapTickrate, + }, { MENUITEMTYPE_CHECKBOX, 0, @@ -1143,14 +1076,6 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, menuhandlerDisplayFPS, }, - { - MENUITEMTYPE_SLIDER, - 0, - MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, - (uintptr_t)"Display FPS Interval", - 31, - menuhandlerDisplayFPSInterval, - }, { MENUITEMTYPE_SEPARATOR, 0, @@ -1159,14 +1084,6 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, NULL, }, - { - MENUITEMTYPE_DROPDOWN, - 0, - MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Anti-aliasing", - 0, - menuhandlerMSAA, - }, { MENUITEMTYPE_DROPDOWN, 0, @@ -1183,6 +1100,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, menuhandlerTexFilter2D, }, + { + MENUITEMTYPE_CHECKBOX, + 0, + MENUITEMFLAG_LITERAL_TEXT, + (uintptr_t)"Detail Textures", + 0, + menuhandlerTexDetail, + }, { MENUITEMTYPE_SEPARATOR, 0, @@ -1192,12 +1117,12 @@ struct menuitem g_ExtendedVideoMenuItems[] = { NULL, }, { - MENUITEMTYPE_CHECKBOX, + MENUITEMTYPE_DROPDOWN, 0, MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Detail Textures", + (uintptr_t)"HUD Centering", 0, - menuhandlerTexDetail, + menuhandlerCenterHUD, }, { MENUITEMTYPE_CHECKBOX, @@ -1223,30 +1148,6 @@ struct menuitem g_ExtendedVideoMenuItems[] = { 0, NULL, }, - { - MENUITEMTYPE_CHECKBOX, - 0, - MENUITEMFLAG_LITERAL_TEXT, - (uintptr_t)"Override Tickrate Divisor", - 0, - menuhandlerTickrateDivisorOverride, - }, - { - MENUITEMTYPE_SLIDER, - 0, - MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, - (uintptr_t)"Tickrate Divisor", - 10, - menuhandlerTickrateDivisor, - }, - { - MENUITEMTYPE_SEPARATOR, - 0, - 0, - 0, - 0, - NULL, - }, { MENUITEMTYPE_SELECTABLE, 0, diff --git a/port/src/video.c b/port/src/video.c index 7430204e8..296a71063 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -41,20 +41,26 @@ static s32 vidAllowHiDpi = false; static s32 vidVsync = 1; static s32 vidMSAA = 1; static s32 vidFramerateLimit = 0; + static s32 vidDisplayFPS = 0; -static s32 vidDisplayFPSDivisor = 16; -static displaymode vidModeDefault; +static f32 vidDisplayFPSInterval = 1.f; +static f32 vidAvgFPS = 0; +static f64 vidLastRenderTime; + static s32 vidNumModes = 1; +static displaymode vidModeDefault; static displaymode *vidModes = &vidModeDefault; -static f64 vidDiffTime; static s32 texFilter = FILTER_LINEAR; static s32 texFilter2D = true; -static s32 texDetail = true; +static s32 texDetail = false; static u32 dlcount = 0; static u32 frames = 0; static f64 startTime, endTime; +static f64 accumDelta = 0.0; +static f64 fpsTime = 0.0; +static s32 fpsNumFrames = 0; static s32 videoInitDisplayModes(void); @@ -121,8 +127,6 @@ void videoSubmitCommands(Gfx *cmds) void videoEndFrame(void) { - static f64 accumTime = 0.0; - if (!initDone) { return; } @@ -130,22 +134,32 @@ void videoEndFrame(void) gfx_end_frame(); ++frames; + ++fpsNumFrames; - endTime = wmAPI->get_time(); - accumTime += endTime - startTime; + const f64 flipTime = wmAPI->get_time(); + accumDelta += flipTime - endTime; + endTime = flipTime; + vidLastRenderTime = endTime - startTime; - if (accumTime >= 1.0 / (f64)vidDisplayFPSDivisor) { + if (endTime >= fpsTime) { char tmp[128]; - vidDiffTime = endTime - startTime; - accumTime = 0.0; - snprintf(tmp, sizeof(tmp), "fps %3u frt %lf frm %u", (u32)(1.0 / vidDiffTime), vidDiffTime, frames); + vidAvgFPS = fpsNumFrames ? ((f64)fpsNumFrames / accumDelta) : 0.f; + fpsNumFrames = 0; + accumDelta = 0.0; + snprintf(tmp, sizeof(tmp), "fps %4.1f frt %lf frm %u", vidAvgFPS, vidLastRenderTime, frames); wmAPI->set_window_title(tmp); + fpsTime = endTime + vidDisplayFPSInterval; } } -f64 videoGetDiffTime(void) +f64 videoGetLastRenderTime(void) { - return vidDiffTime; + return vidLastRenderTime; +} + +f32 videoGetAverageFPS(void) +{ + return vidAvgFPS; } void videoClearScreen(void) @@ -253,11 +267,6 @@ s32 videoGetDisplayFPS(void) return vidDisplayFPS; } -s32 videoGetDisplayFPSDivisor(void) -{ - return vidDisplayFPSDivisor; -} - static s32 videoInitDisplayModes(void) { if (!wmAPI->get_current_display_mode(&vidModeDefault.width, &vidModeDefault.height)) { @@ -470,11 +479,6 @@ void videoSetDisplayFPS(const s32 displayfps) vidDisplayFPS = displayfps; } -void videoSetDisplayFPSDivisor(const s32 divisor) -{ - vidDisplayFPSDivisor = divisor; -} - void videoSetFramebuffer(s32 target) { return gfx_set_framebuffer(target, 1.f); @@ -529,7 +533,7 @@ PD_CONSTRUCTOR static void videoConfigInit(void) configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1); configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS); configRegisterInt("Video.DisplayFPS", &vidDisplayFPS, 0, 1); - configRegisterInt("Video.DisplayFPSDivisor", &vidDisplayFPSDivisor, 1, 32); + configRegisterFloat("Video.DisplayFPSInterval", &vidDisplayFPSInterval, 0.01f, 32.f); configRegisterInt("Video.MSAA", &vidMSAA, 1, 16); configRegisterInt("Video.TextureFilter", &texFilter, 0, 2); configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1); diff --git a/src/game/lv.c b/src/game/lv.c index 3ce268583..56d9e9ab3 100644 --- a/src/game/lv.c +++ b/src/game/lv.c @@ -957,16 +957,26 @@ void lvFindThreats(void) #ifndef PLATFORM_N64 Gfx *lvRenderFPS(Gfx *gdl) { + const f32 fps = videoGetAverageFPS(); + const u8 a = 160; s32 x = 27, y = 13; - f32 fps = 1.0f / videoGetDiffTime(); - s32 ifps = (s32)fps; - u8 r = (ifps <= 30) ? 255 : (ifps <= 60) ? roundf(255 * (1.0f - (ifps - 30.0f) / 30.0f)) : 0; - u8 g = (ifps <= 30) ? roundf(255 * (ifps - 1.0f) / 29.0f) : 255; - u8 b = (ifps > 60 && ifps <= 90) ? roundf(255 * (ifps - 60.0f) / 30.0f) : (ifps > 90) ? 255 : 0; - u8 a = 160; - u32 color = r << 24 | g << 16 | b << 8 | a; + u32 color; char buffer[16]; + if (fps <= 30.f) { + // red -> yellow + color = 0xff000000 | a | ((u32)((fps / 30.f) * 255.f) << 16); + } else if (fps <= 60.f) { + // yellow -> green + color = 0x00ff0000 | a | ((u32)((1.f - (fps - 30.f) / 30.f) * 255.f) << 24); + } else if (fps <= 90.f) { + // green -> cyan + color = 0x00ff0000 | a | ((u32)(((fps - 60.f) / 30.f) * 255.f) << 8); + } else { + // cyan + color = 0x00ffff00 | a; + } + if (g_CharsNumeric && g_FontNumeric) { snprintf(buffer, sizeof buffer, "%.2f", fps); diff --git a/src/include/data.h b/src/include/data.h index 787cdfb27..d1bf537ca 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -551,7 +551,6 @@ extern s32 g_BlurFb; extern s32 g_BlurFbCapTimer; extern bool g_BlurFbDirty; extern s32 g_TickRateDiv; -extern s32 g_TickRateDivOverride; extern s32 g_TickExtraSleep; extern s32 g_MusicDisableMpDeath; extern s32 g_BgunGeMuzzleFlashes;