diff --git a/include/text_strings.h.in b/include/text_strings.h.in index b77a51ca..06173692 100644 --- a/include/text_strings.h.in +++ b/include/text_strings.h.in @@ -27,8 +27,6 @@ #define TEXT_OPT_NEAREST _("Nearest") #define TEXT_OPT_LINEAR _("Linear") #define TEXT_OPT_MVOLUME _("Master Volume") -#define TEXT_OPT_VSYNC _("Vertical Sync") -#define TEXT_OPT_DOUBLE _("Double") #define TEXT_RESET_WINDOW _("Reset Window") #define TEXT_OPT_UNBOUND _("NONE") diff --git a/src/game/options_menu.c b/src/game/options_menu.c index 7b8d9f74..b9033bee 100644 --- a/src/game/options_menu.c +++ b/src/game/options_menu.c @@ -72,9 +72,7 @@ static const u8 optsVideoStr[][32] = { { TEXT_OPT_TEXFILTER }, { TEXT_OPT_NEAREST }, { TEXT_OPT_LINEAR }, - { TEXT_RESET_WINDOW }, - { TEXT_OPT_VSYNC }, - { TEXT_OPT_DOUBLE }, + { TEXT_RESET_WINDOW } }; static const u8 optsAudioStr[][32] = { @@ -114,12 +112,6 @@ static const u8 *filterChoices[] = { optsVideoStr[3], }; -static const u8 *vsyncChoices[] = { - toggleStr[0], - toggleStr[1], - optsVideoStr[6], -}; - enum OptType { OPT_INVALID = 0, OPT_TOGGLE, @@ -186,12 +178,8 @@ static void optmenu_act_exit(UNUSED struct Option *self, s32 arg) { if (!arg) game_exit(); // only exit on A press and not directions } -static void optvideo_reset_window(UNUSED struct Option *self, s32 arg) { - if (!arg) { - // Restrict reset to A press and not directions - configWindow.reset = true; - configWindow.settings_changed = true; - } +static void optvide_reset_window(UNUSED struct Option *self, s32 arg) { + if (!arg) configWindow.reset = true;; // Restrict reset to A press and not directions } /* submenu option lists */ @@ -229,9 +217,8 @@ static struct Option optsControls[] = { static struct Option optsVideo[] = { DEF_OPT_TOGGLE( optsVideoStr[0], &configWindow.fullscreen ), - DEF_OPT_CHOICE( optsVideoStr[5], &configWindow.vsync, vsyncChoices ), DEF_OPT_CHOICE( optsVideoStr[1], &configFiltering, filterChoices ), - DEF_OPT_BUTTON( optsVideoStr[4], optvideo_reset_window ), + DEF_OPT_BUTTON( optsVideoStr[4], optvide_reset_window ), }; static struct Option optsAudio[] = { @@ -243,8 +230,8 @@ static struct Option optsCheats[] = { DEF_OPT_TOGGLE( optsCheatsStr[1], &Cheats.MoonJump ), DEF_OPT_TOGGLE( optsCheatsStr[2], &Cheats.GodMode ), DEF_OPT_TOGGLE( optsCheatsStr[3], &Cheats.InfiniteLives ), - DEF_OPT_TOGGLE( optsCheatsStr[4], &Cheats.SuperSpeed ), - DEF_OPT_TOGGLE( optsCheatsStr[5], &Cheats.Responsive ), + DEF_OPT_TOGGLE( optsCheatsStr[4], &Cheats.SuperSpeed), + DEF_OPT_TOGGLE( optsCheatsStr[5], &Cheats.Responsive), }; @@ -256,7 +243,7 @@ static struct SubMenu menuCamera = DEF_SUBMENU( menuStr[4], optsCamera ); static struct SubMenu menuControls = DEF_SUBMENU( menuStr[5], optsControls ); static struct SubMenu menuVideo = DEF_SUBMENU( menuStr[6], optsVideo ); static struct SubMenu menuAudio = DEF_SUBMENU( menuStr[7], optsAudio ); -static struct SubMenu menuCheats = DEF_SUBMENU( menuStr[9], optsCheats ); +static struct SubMenu menuCheats = DEF_SUBMENU( menuStr[9], optsCheats ); /* main options menu definition */ diff --git a/src/pc/configfile.c b/src/pc/configfile.c index ce9a08ad..0b6fe370 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -40,11 +40,10 @@ ConfigWindow configWindow = { .y = SDL_WINDOWPOS_CENTERED, .w = DESIRED_SCREEN_WIDTH, .h = DESIRED_SCREEN_HEIGHT, - .vsync = 1, .reset = false, + .vsync = false, .fullscreen = false, .exiting_fullscreen = false, - .settings_changed = false, }; unsigned int configFiltering = 1; // 0=force nearest, 1=linear, (TODO) 2=three-point unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME @@ -85,7 +84,6 @@ static const struct ConfigOption options[] = { {.name = "window_y", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.y}, {.name = "window_w", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.w}, {.name = "window_h", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.h}, - {.name = "vsync", .type = CONFIG_TYPE_UINT, .uintValue = &configWindow.vsync}, {.name = "texture_filtering", .type = CONFIG_TYPE_UINT, .uintValue = &configFiltering}, {.name = "master_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configMasterVolume}, {.name = "key_a", .type = CONFIG_TYPE_BIND, .uintValue = configKeyA}, diff --git a/src/pc/configfile.h b/src/pc/configfile.h index cafd272f..01d657c2 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -11,11 +11,10 @@ typedef struct { unsigned int x, y, w, h; - unsigned int vsync; bool reset; + bool vsync; bool fullscreen; bool exiting_fullscreen; - bool settings_changed; } ConfigWindow; extern ConfigWindow configWindow; diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c index cc660d79..363d9209 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c @@ -39,12 +39,9 @@ # define FRAMERATE 30 #endif -static const Uint32 FRAME_TIME = 1000 / FRAMERATE; - static SDL_Window *wnd; static SDL_GLContext ctx = NULL; static int inverted_scancode_table[512]; -static Uint32 frame_start = 0; const SDL_Scancode windows_scancode_table[] = { @@ -113,9 +110,9 @@ static void gfx_sdl_set_fullscreen() { } static void gfx_sdl_reset_dimension_and_pos() { - if (configWindow.exiting_fullscreen) { + if (configWindow.exiting_fullscreen) configWindow.exiting_fullscreen = false; - } else if (configWindow.reset) { + else if (configWindow.reset) { configWindow.x = SDL_WINDOWPOS_CENTERED; configWindow.y = SDL_WINDOWPOS_CENTERED; configWindow.w = DESIRED_SCREEN_WIDTH; @@ -126,14 +123,29 @@ static void gfx_sdl_reset_dimension_and_pos() { configWindow.fullscreen = false; return; } - } else if (!configWindow.settings_changed) { + } else return; - } - configWindow.settings_changed = false; SDL_SetWindowSize(wnd, configWindow.w, configWindow.h); SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y); - SDL_GL_SetSwapInterval(configWindow.vsync); // in case vsync changed +} + +static bool test_vsync(void) { + // Even if SDL_GL_SetSwapInterval succeeds, it doesn't mean that VSync actually works. + // A 60 Hz monitor should have a swap interval of 16.67 milliseconds. + // If it takes less than 12 milliseconds, assume that VSync is not working. + // SDL_GetTicks() probably does not offer enough precision for this kind of shit. + Uint32 start, end; + + // do an extra swap, sometimes the first one takes longer (maybe creates buffers?) + SDL_GL_SwapWindow(wnd); + + SDL_GL_SwapWindow(wnd); + start = SDL_GetTicks(); + SDL_GL_SwapWindow(wnd); + end = SDL_GetTicks(); + + return (end - start >= 12); } static void gfx_sdl_init(void) { @@ -153,9 +165,11 @@ static void gfx_sdl_init(void) { if (gCLIOpts.FullScreen == 1) configWindow.fullscreen = true; - else if (gCLIOpts.FullScreen == 2) + + if (gCLIOpts.FullScreen == 2) configWindow.fullscreen = false; + const char* window_title = #ifndef USE_GLES "Super Mario 64 PC port (OpenGL)"; @@ -169,11 +183,14 @@ static void gfx_sdl_init(void) { SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE ); ctx = SDL_GL_CreateContext(wnd); - - SDL_GL_SetSwapInterval(configWindow.vsync); + SDL_GL_SetSwapInterval(2); gfx_sdl_set_fullscreen(); + configWindow.vsync = test_vsync(); + if (!configWindow.vsync) + printf("Warning: VSync is not enabled or not working. Falling back to timer for synchronization\n"); + for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) { inverted_scancode_table[windows_scancode_table[i]] = i; } @@ -258,19 +275,23 @@ static void gfx_sdl_handle_events(void) { } static bool gfx_sdl_start_frame(void) { - frame_start = SDL_GetTicks(); return true; } static void sync_framerate_with_timer(void) { - Uint32 elapsed = SDL_GetTicks() - frame_start; + // Number of milliseconds a frame should take (30 fps) + const Uint32 FRAME_TIME = 1000 / FRAMERATE; + static Uint32 last_time; + + Uint32 elapsed = SDL_GetTicks() - last_time; if (elapsed < FRAME_TIME) SDL_Delay(FRAME_TIME - elapsed); + + last_time = SDL_GetTicks(); } static void gfx_sdl_swap_buffers_begin(void) { - // if vsync is set to 2, depend only on SwapInterval to sync - if (configWindow.vsync <= 1) + if (!configWindow.vsync) sync_framerate_with_timer(); SDL_GL_SwapWindow(wnd); }