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;