]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
vid_vsync: fully support adaptive, remove polling, print better errors
authorbones_was_here <bones_was_here@xonotic.au>
Tue, 3 Oct 2023 17:24:44 +0000 (03:24 +1000)
committerbones_was_here <bones_was_here@xonotic.au>
Wed, 8 Nov 2023 17:25:58 +0000 (03:25 +1000)
Adaptive vsync was partially supported: it worked if set before window
creation but not if toggled on afterwards, and wasn't mentioned in the
cvar description.

The immediate application of `vid_vsync` cvar changes was implented by
polling, which was ok for one cvar but I'll be making more vid_ cvars
apply immediately (no vid_restart needed), and don't want to poll for
things that rarely change every frame.

SDL is now queried for the current state of vsync instead of storing
what we believe to be the current state.

If the setting can't be applied the reason (as reported by SDL) is now
printed.

Signed-off-by: bones_was_here <bones_was_here@xonotic.au>
cl_demo.c
cl_main.c
vid_sdl.c
vid_shared.c

index 927e85b5f95d586eb11b5d0170124387f8bf39d1..b1f2e685716f0c1ff4b2a1bf4659c8194342899d 100644 (file)
--- a/cl_demo.c
+++ b/cl_demo.c
@@ -585,6 +585,9 @@ static void CL_FinishTimeDemo (void)
                else
                        host.state = host_shutdown;
        }
+
+       // Might need to re-enable vsync
+       Cvar_Callback(&vid_vsync);
 }
 
 /*
@@ -617,6 +620,9 @@ void CL_TimeDemo_f(cmd_state_t *cmd)
        cls.timedemo = host.restless = true;
        cls.td_frames = -2;             // skip the first frame
        cls.demonum = -1;               // stop demo loop
+
+       // Might need to disable vsync
+       Cvar_Callback(&vid_vsync);
 }
 
 /*
index 01ce5e6d583a06fe4fd2de9e6d48dfd53bcbf920..b7d4f148d50101eb38da70369c95044f2d358032 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -454,9 +454,9 @@ void CL_DisconnectEx(qbool kicked, const char *fmt, ... )
        }
        cls.state = ca_disconnected;
        cl.islocalgame = false;
-
-       cls.demoplayback = cls.timedemo = host.restless = false;
        cls.signon = 0;
+       cls.demoplayback = cls.timedemo = host.restless = false;
+       Cvar_Callback(&vid_vsync); // might need to re-enable vsync
 
        Cvar_Callback(&cl_netport);
 
index 12e45f8aea0dc76c4cf00856764be2e32da4df5e..1a6756aa44b5bad70c1984b288a6d50d6047327c 100644 (file)
--- a/vid_sdl.c
+++ b/vid_sdl.c
@@ -72,7 +72,6 @@ static qbool vid_usingmouse = false;
 static qbool vid_usingmouse_relativeworks = false; // SDL2 workaround for unimplemented RelativeMouse mode
 static qbool vid_usinghidecursor = false;
 static qbool vid_hasfocus = false;
-static qbool vid_usingvsync = false;
 static SDL_Joystick *vid_sdljoystick = NULL;
 static SDL_GameController *vid_sdlgamecontroller = NULL;
 static cvar_t joy_sdl2_trigger_deadzone = {CF_ARCHIVE | CF_CLIENT, "joy_sdl2_trigger_deadzone", "0.5", "deadzone for triggers to be registered as key presses"};
@@ -1320,6 +1319,21 @@ qbool GL_ExtensionSupported(const char *name)
        return SDL_GL_ExtensionSupported(name);
 }
 
+static void VID_SetVsync_c(cvar_t *var)
+{
+       signed char vsyncwanted = cls.timedemo ? 0 : bound(-1, vid_vsync.integer, 1);
+
+       if (!context)
+               return;
+       if (SDL_GL_GetSwapInterval() == vsyncwanted)
+               return;
+
+       if (SDL_GL_SetSwapInterval(vsyncwanted) >= 0)
+               Con_DPrintf("Vsync %s\n", vsyncwanted ? "activated" : "deactivated");
+       else
+               Con_Printf(CON_ERROR "ERROR: can't %s vsync because %s\n", vsyncwanted ? "activate" : "deactivate", SDL_GetError());
+}
+
 void VID_Init (void)
 {
 #ifndef __IPHONEOS__
@@ -1336,6 +1350,8 @@ void VID_Init (void)
        R_RegisterModule("SDL", sdl_start, sdl_shutdown, sdl_newmap, NULL, NULL);
 #endif
 
+       Cvar_RegisterCallback(&vid_vsync,                  VID_SetVsync_c);
+
        if (SDL_Init(SDL_INIT_VIDEO) < 0)
                Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
        if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
@@ -1606,8 +1622,8 @@ static qbool VID_InitModeGL(viddef_mode_t *mode)
        }
 #endif
 
-       SDL_GL_SetSwapInterval(bound(-1, vid_vsync.integer, 1));
-       vid_usingvsync = (vid_vsync.integer != 0);
+       // apply vid_vsync
+       Cvar_Callback(&vid_vsync);
 
        vid_hidden = false;
        vid_activewindow = true;
@@ -1658,7 +1674,6 @@ void VID_Shutdown (void)
 
 void VID_Finish (void)
 {
-       qbool vid_usevsync;
        vid_activewindow = !vid_hidden && vid_hasfocus;
 
        VID_UpdateGamma();
@@ -1672,16 +1687,6 @@ void VID_Finish (void)
                        CHECKGLERROR
                        if (r_speeds.integer == 2 || gl_finish.integer)
                                GL_Finish();
-
-                       vid_usevsync = (vid_vsync.integer && !cls.timedemo);
-                       if (vid_usingvsync != vid_usevsync)
-                       {
-                               vid_usingvsync = vid_usevsync;
-                               if (SDL_GL_SetSwapInterval(vid_usevsync != 0) >= 0)
-                                       Con_DPrintf("Vsync %s\n", vid_usevsync ? "activated" : "deactivated");
-                               else
-                                       Con_DPrintf("ERROR: can't %s vsync\n", vid_usevsync ? "activate" : "deactivate");
-                       }
                        SDL_GL_SwapWindow(window);
                        break;
                }
index 2532d8e4c2e8a278fa73187ad5fe9083219fdc55..aa3bdb1f4621b7588eed854b2b9eee487244c0da 100644 (file)
@@ -147,7 +147,7 @@ cvar_t vid_touchscreen_density = {CF_CLIENT, "vid_touchscreen_density", "2.0", "
 cvar_t vid_touchscreen_xdpi = {CF_CLIENT, "vid_touchscreen_xdpi", "300", "Horizontal DPI of the screen (only valid on Android currently)"};
 cvar_t vid_touchscreen_ydpi = {CF_CLIENT, "vid_touchscreen_ydpi", "300", "Vertical DPI of the screen (only valid on Android currently)"};
 
-cvar_t vid_vsync = {CF_CLIENT | CF_ARCHIVE, "vid_vsync", "0", "sync to vertical blank, prevents 'tearing' (seeing part of one frame and part of another on the screen at the same time), automatically disabled when doing timedemo benchmarks"};
+cvar_t vid_vsync = {CF_CLIENT | CF_ARCHIVE, "vid_vsync", "0", "sync to vertical blank, prevents 'tearing' (seeing part of one frame and part of another on the screen at the same time) at the cost of latency, 1 always syncs and -1 is adaptive (stops syncing if the framerate drops, unsupported by some platforms), automatically disabled when doing timedemo benchmarks"};
 cvar_t vid_mouse = {CF_CLIENT | CF_ARCHIVE, "vid_mouse", "1", "whether to use the mouse in windowed mode (fullscreen always does)"};
 cvar_t vid_mouse_clickthrough = {CF_CLIENT | CF_ARCHIVE, "vid_mouse_clickthrough", "0", "mouse behavior in windowed mode: 0 = click to focus, 1 = allow interaction even if the window is not focused (click-through behaviour, can be useful when using third-party game overlays)"};
 cvar_t vid_grabkeyboard = {CF_CLIENT | CF_ARCHIVE, "vid_grabkeyboard", "0", "whether to grab the keyboard when mouse is active (prevents use of volume control keys, music player keys, etc on some keyboards)"};