Skip to content

Commit

Permalink
Allow changing vsync and framerate limit at runtime
Browse files Browse the repository at this point in the history
Also implements a new menu item flag: MENUITEMFLAG_SLIDER_DEFERRED,
which only calls the MENUOP_GETSLIDER callback on entering dimmed mode,
storing its value for later ticks, and only calls the MENUOP_SET
callback on leaving dimmed mode. This was necessary to prevent the
framerate limit slider from immediately affecting the framerate, leading
to an annoying slow down as the value was decremented to 0.
  • Loading branch information
ZenithMDC committed Nov 27, 2024
1 parent 7af85e5 commit 299f7ec
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 19 deletions.
10 changes: 10 additions & 0 deletions port/fast3d/gfx_sdl2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,10 @@ static double gfx_sdl_get_time(void) {
return SDL_GetPerformanceCounter() / (double)qpc_freq;
}

static int32_t gfx_sdl_get_target_fps(void) {
return target_fps;
}

static void gfx_sdl_set_target_fps(int fps) {
target_fps = fps;
}
Expand All @@ -379,6 +383,10 @@ static void gfx_sdl_set_window_title(const char *title) {
SDL_SetWindowTitle(wnd, title);
}

static int gfx_sdl_get_swap_interval(void) {
return SDL_GL_GetSwapInterval();
}

static bool gfx_sdl_set_swap_interval(int interval) {
const bool success = SDL_GL_SetSwapInterval(interval) >= 0;
vsync_enabled = success && (interval != 0);
Expand Down Expand Up @@ -440,9 +448,11 @@ struct GfxWindowManagerAPI gfx_sdl = {
gfx_sdl_swap_buffers_begin,
gfx_sdl_swap_buffers_end,
gfx_sdl_get_time,
gfx_sdl_get_target_fps,
gfx_sdl_set_target_fps,
gfx_sdl_can_disable_vsync,
gfx_sdl_get_window_handle,
gfx_sdl_set_window_title,
gfx_sdl_get_swap_interval,
gfx_sdl_set_swap_interval,
};
2 changes: 2 additions & 0 deletions port/fast3d/gfx_window_manager_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ struct GfxWindowManagerAPI {
void (*swap_buffers_begin)(void);
void (*swap_buffers_end)(void);
double (*get_time)(void); // For debug
int32_t (*get_target_fps)(void);
void (*set_target_fps)(int fps);
bool (*can_disable_vsync)(void);
void *(*get_window_handle)(void);
void (*set_window_title)(const char *);
int (*get_swap_interval)(void);
bool (*set_swap_interval)(int);
};

Expand Down
4 changes: 4 additions & 0 deletions port/include/video.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ s32 videoGetDetailTextures(void);
s32 videoGetDisplayModeIndex(void);
s32 videoGetDisplayMode(displaymode *out, const s32 index);
s32 videoGetNumDisplayModes(void);
s32 videoGetVsync(void);
s32 videoGetFramerateLimit(void);

void videoSetWindowOffset(s32 x, s32 y);
void videoSetFullscreen(s32 fs);
Expand All @@ -51,6 +53,8 @@ void videoSetTextureFilter(u32 filter);
void videoSetTextureFilter2D(s32 filter);
void videoSetDetailTextures(s32 detail);
void videoSetDisplayMode(const s32 index);
void videoSetVsync(const s32 vsync);
void videoSetFramerateLimit(const s32 limit);

s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize);
void videoSetFramebuffer(s32 target);
Expand Down
70 changes: 70 additions & 0 deletions port/src/optionsmenu.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,60 @@ static MenuItemHandlerResult menuhandlerCenterWindow(s32 operation, struct menui
return 0;
}

static MenuItemHandlerResult menuhandlerVsync(s32 operation, struct menuitem *item, union handlerdata *data)
{
static const char *opts[] = {
"Adaptive",
"Off",
"On (Sync Every Frame)",
"On (Sync Every 2 Frames)",
"On (Sync Every 3 Frames)",
"On (Sync Every 4 Frames)",
"On (Sync Every 5 Frames)",
"On (Sync Every 6 Frames)",
"On (Sync Every 7 Frames)",
"On (Sync Every 8 Frames)",
"On (Sync Every 9 Frames)",
"On (Sync Every 10 Frames)"
};

switch (operation) {
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = ARRAYCOUNT(opts);
break;
case MENUOP_GETOPTIONTEXT:
return (intptr_t)opts[data->dropdown.value];
case MENUOP_SET:
videoSetVsync(data->dropdown.value - 1);
case MENUOP_GETSELECTEDINDEX:
data->dropdown.value = videoGetVsync() + 1;
}

return 0;
}

static MenuItemHandlerResult menuhandlerFramerateLimit(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GETSLIDER:
data->slider.value = videoGetFramerateLimit();
break;
case MENUOP_SET:
if (g_TickRateDiv < 2) {
g_TickRateDiv = (data->slider.value == 0 || data->slider.value > 60) ? 0 : 1;
}
videoSetFramerateLimit(data->slider.value);
break;
case MENUOP_GETSLIDERLABEL:
if (data->slider.value == 0) {
sprintf(data->slider.label, "Off");
}
break;
}

return 0;
}

static MenuItemHandlerResult menuhandlerResolution(s32 operation, struct menuitem *item, union handlerdata *data)
{
static char resstring[32];
Expand Down Expand Up @@ -929,6 +983,22 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
0,
menuhandlerCenterWindow,
},
{
MENUITEMTYPE_DROPDOWN,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Vsync",
0,
menuhandlerVsync,
},
{
MENUITEMTYPE_SLIDER,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE | MENUITEMFLAG_SLIDER_DEFERRED,
(uintptr_t)"Framerate Limit",
VIDEO_MAX_FPS,
menuhandlerFramerateLimit,
},
{
MENUITEMTYPE_CHECKBOX,
0,
Expand Down
41 changes: 31 additions & 10 deletions port/src/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,18 +86,11 @@ s32 videoInit(void)
};

gfx_init(&set);
videoInitDisplayModes();

if (!wmAPI->set_swap_interval(vidVsync)) {
vidVsync = 0;
}

if (vidVsync == 0 && vidFramerateLimit == 0) {
// cap FPS if there's no vsync to prevent the game from exploding
vidFramerateLimit = VIDEO_MAX_FPS;
}
videoInitDisplayModes();
videoSetVsync(vidVsync);
videoSetFramerateLimit(vidFramerateLimit);

wmAPI->set_target_fps(vidFramerateLimit); // disabled because vsync is on
gfx_set_texture_filter((enum FilteringMode)texFilter);

initDone = true;
Expand Down Expand Up @@ -224,6 +217,18 @@ s32 videoGetDisplayModeIndex(void)
return 0;
}

s32 videoGetVsync(void)
{
vidVsync = wmAPI->get_swap_interval();
return vidVsync;
}

s32 videoGetFramerateLimit(void)
{
vidFramerateLimit = wmAPI->get_target_fps();
return vidFramerateLimit;
}

static s32 videoInitDisplayModes(void)
{
if (!wmAPI->get_current_display_mode(&vidModeDefault.width, &vidModeDefault.height)) {
Expand Down Expand Up @@ -409,6 +414,22 @@ s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize)
return gfx_create_framebuffer(w, h, upscale, autoresize);
}

void videoSetVsync(const s32 vsync)
{
vidVsync = wmAPI->set_swap_interval(vsync) ? vsync : 0;

if (vidVsync == 0 && vidFramerateLimit == 0) {
// cap FPS if there's no vsync to prevent the game from exploding
videoSetFramerateLimit(VIDEO_MAX_FPS);
}
}

void videoSetFramerateLimit(const s32 limit)
{
vidFramerateLimit = (vidVsync == 0 && limit == 0) ? VIDEO_MAX_FPS : limit;
wmAPI->set_target_fps(vidFramerateLimit);
}

void videoSetFramebuffer(s32 target)
{
return gfx_set_framebuffer(target, 1.f);
Expand Down
44 changes: 36 additions & 8 deletions src/game/menuitem.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ u8 g_KeyboardKeys[5][10] = {
{ '1','2','1','2','1','2','3','1','2','3' },
};

static s32 deferredindex = -1;

s32 func0f0e5ce0(s32 value)
{
if (value < var800711a4) {
Expand Down Expand Up @@ -2171,7 +2173,7 @@ Gfx* menuitemColorBoxRender(Gfx *gdl, struct menurendercontext *context)
return gdl;
}

#endif
#endif

Gfx *menuitemSelectableRender(Gfx *gdl, struct menurendercontext *context)
{
Expand Down Expand Up @@ -2332,8 +2334,15 @@ Gfx *menuitemSliderRender(Gfx *gdl, struct menurendercontext *context)
extray = 0;

if (context->item->handler != NULL) {
context->item->handler(MENUOP_GETSLIDER, context->item, &data);
slidervalue = (s16) data.slider.value;
if ((context->item->flags & MENUITEMFLAG_SLIDER_DEFERRED) &&
deferredindex != -1 &&
context->dialog->dimmed &&
context->focused) {
slidervalue = (s16) deferredindex;
} else {
context->item->handler(MENUOP_GETSLIDER, context->item, &data);
slidervalue = (s16) data.slider.value;
}
} else {
slidervalue = 0;
}
Expand Down Expand Up @@ -2484,8 +2493,17 @@ bool menuitemSliderTick(struct menuitem *item, struct menudialog *dialog, struct

if (tickflags & MENUTICKFLAG_DIALOGISDIMMED) {
if (item->handler) {
item->handler(MENUOP_GETSLIDER, item, &handlerdata);
index = (s16) handlerdata.slider.value;
if (item->flags & MENUITEMFLAG_SLIDER_DEFERRED) {
if (deferredindex == -1) {
item->handler(MENUOP_GETSLIDER, item, &handlerdata);
deferredindex = (s16) handlerdata.slider.value;
}
index = deferredindex;
} else {
item->handler(MENUOP_GETSLIDER, item, &handlerdata);
index = (s16) handlerdata.slider.value;
}

} else {
index = 0;
}
Expand Down Expand Up @@ -2565,11 +2583,21 @@ bool menuitemSliderTick(struct menuitem *item, struct menudialog *dialog, struct
inputs->leftright = 0;
handlerdata.slider.value = index;

if (item->handler) {
item->handler(MENUOP_SET, item, &handlerdata);
if (item->flags & MENUITEMFLAG_SLIDER_DEFERRED) {
deferredindex = index;
} else {
if (item->handler) {
item->handler(MENUOP_SET, item, &handlerdata);
}
}

if (inputs->select) {
if (item->flags & MENUITEMFLAG_SLIDER_DEFERRED) {
deferredindex = -1;
if (item->handler) {
item->handler(MENUOP_SET, item, &handlerdata);
}
}
dialog->dimmed = false;
}
} else {
Expand Down Expand Up @@ -2609,7 +2637,7 @@ Gfx *menuitemCarouselRender(Gfx *gdl, struct menurendercontext *context)

#ifdef PLATFORM_N64
s16 chevronOffset = 0;
#else
#else
s16 chevronOffset = 3;
#endif

Expand Down
3 changes: 2 additions & 1 deletion src/include/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -1666,6 +1666,7 @@
#define MENUITEMFLAG_CAROUSEL_04000000 0x04000000
#define MENUITEMFLAG_LITERAL_TEXT 0x08000000
#define MENUITEMFLAG_SLIDER_WIDE 0x10000000
#define MENUITEMFLAG_SLIDER_DEFERRED 0x20000000

#define MENUITEMTYPE_LABEL 0x01
#define MENUITEMTYPE_LIST 0x02
Expand Down Expand Up @@ -1696,7 +1697,7 @@

#ifndef PLATFORM_N64
#define MENUITEMTYPE_COLORBOX 0x1b
#endif
#endif

#define MENUMODELFLAG_HASSCALE 0x01
#define MENUMODELFLAG_HASPOSITION 0x02
Expand Down

0 comments on commit 299f7ec

Please sign in to comment.