From 18bfa35f9b78613fa625a13c3ec15119cdc1d10e Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sat, 4 Mar 2017 16:31:34 +0100 Subject: [PATCH] Allow switching VSync on/off without vid_restart (for SDL2) --- src/backends/generic/vid.c | 10 +++++++ src/backends/sdl/input.c | 8 ++++++ src/backends/sdl/refresh.c | 40 +++++++++++++-------------- src/client/cl_main.c | 6 ++-- src/client/header/ref.h | 3 ++ src/client/refresh/gl/r_main.c | 9 ++++++ src/client/refresh/gl/r_sdl.c | 22 +++++++++++++-- src/client/refresh/gl3/gl3_main.c | 7 +++++ src/client/refresh/gl3/gl3_misc.c | 23 --------------- src/client/refresh/gl3/gl3_sdl.c | 24 ++++++++++++++-- src/client/refresh/gl3/header/local.h | 2 ++ 11 files changed, 103 insertions(+), 51 deletions(-) diff --git a/src/backends/generic/vid.c b/src/backends/generic/vid.c index c83889c3..7f572bce 100644 --- a/src/backends/generic/vid.c +++ b/src/backends/generic/vid.c @@ -447,3 +447,13 @@ R_EndFrame(void) re.EndFrame(); } } + +qboolean +R_IsVSyncActive(void) +{ + if(ref_active) + { + return re.IsVSyncActive(); + } + return false; +} diff --git a/src/backends/sdl/input.c b/src/backends/sdl/input.c index 12cffb1f..8e837f85 100644 --- a/src/backends/sdl/input.c +++ b/src/backends/sdl/input.c @@ -296,6 +296,8 @@ IN_TranslateSDLtoQ2Key(unsigned int keysym) /* ------------------------------------------------------------------ */ +extern int glimp_refreshRate; + /* * Updates the input queue state. Called every * frame by the client and does nearly all the @@ -430,6 +432,12 @@ IN_Update(void) { Key_MarkAllUp(); } + else if(event.window.event == SDL_WINDOWEVENT_MOVED) + { + // make sure GLimp_GetRefreshRate() will query from SDL again - the window might + // be on another display now! + glimp_refreshRate = -1; + } #else /* SDL1.2 */ case SDL_ACTIVEEVENT: diff --git a/src/backends/sdl/refresh.c b/src/backends/sdl/refresh.c index 5fe37703..76255e7b 100644 --- a/src/backends/sdl/refresh.c +++ b/src/backends/sdl/refresh.c @@ -52,8 +52,6 @@ static SDL_Surface* window = NULL; #endif -qboolean vsync_active; - #if SDL_VERSION_ATLEAST(2, 0, 0) // some compatibility defines #define SDL_SRCCOLORKEY SDL_TRUE @@ -340,11 +338,6 @@ GLimp_InitGraphics(qboolean fullscreen, int *pwidth, int *pheight) return false; } - // VSync is really set in the renderer dll, but we want vsync_active here - // so just get it from the Cvar here, even though it's a bit ugly - cvar_t* gl_swapinterval = Cvar_Get("gl_swapinterval", "1", CVAR_ARCHIVE); - vsync_active = gl_swapinterval->value ? true : false; - /* Note: window title is now set in re.InitContext() to include renderer name */ #if SDL_VERSION_ATLEAST(2, 0, 0) /* Set the window icon - For SDL2, this must be done after creating the window */ @@ -377,13 +370,7 @@ void GLimp_GrabInput(qboolean grab) #endif } -/* - * Returns the VSync state. - */ -qboolean GLimp_VsyncEnabled(void) -{ - return vsync_active; -} +int glimp_refreshRate = -1; /* * Returns the current display refresh rate. @@ -391,17 +378,26 @@ qboolean GLimp_VsyncEnabled(void) int GLimp_GetRefreshRate(void) { #if SDL_VERSION_ATLEAST(2, 0, 0) - int i; - int refresh = 0; - SDL_DisplayMode mode; - for (i = 0; i < SDL_GetNumVideoDisplays(); ++i) + // do this only once, assuming people don't change their display settings + // or plug in new displays while the game is running + if (glimp_refreshRate == -1) { - SDL_GetCurrentDisplayMode(i, &mode); - refresh = refresh < mode.refresh_rate ? mode.refresh_rate : refresh; + SDL_DisplayMode mode; + // TODO: probably refreshRate should be reset to -1 if window is moved + int i = SDL_GetWindowDisplayIndex(window); + if(i >= 0 && SDL_GetCurrentDisplayMode(i, &mode) == 0) + { + glimp_refreshRate = mode.refresh_rate; + } + + if (glimp_refreshRate <= 0) + { + glimp_refreshRate = 60; // apparently the stuff above failed, use default + } } - return refresh; + return glimp_refreshRate; #else // Asume 60hz. return 60 @@ -427,6 +423,8 @@ VID_ShutdownWindow(void) } window = NULL; + // make sure that after vid_restart the refreshrate will be queried from SDL2 again. + glimp_refreshRate = -1; if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_VIDEO) { diff --git a/src/client/cl_main.c b/src/client/cl_main.c index 5de6199d..e3caee37 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -711,8 +711,8 @@ CL_UpdateWindowedMouse(void) } } -qboolean GLimp_VsyncEnabled(void); int GLimp_GetRefreshRate(void); +qboolean R_IsVSyncActive(void); void CL_Frame(int msec) @@ -736,7 +736,7 @@ CL_Frame(int msec) } // Target render frame rate - if (GLimp_VsyncEnabled()) + if (R_IsVSyncActive()) { rfps = GLimp_GetRefreshRate(); @@ -830,7 +830,7 @@ CL_Frame(int msec) double frametime = (1000.0 / cl_maxfps->value - packetdelta) <= (1000.0 / gl_maxfps->value - renderdelta) ? (1000.0 / cl_maxfps->value - packetdelta) : (1000.0 / gl_maxfps->value - renderdelta); - if (frametime > 1) + if (frametime > 1) // FIXME: why > ?? { Sys_Sleep(1); } diff --git a/src/client/header/ref.h b/src/client/header/ref.h index 8b3cabbc..5dd8fe7a 100644 --- a/src/client/header/ref.h +++ b/src/client/header/ref.h @@ -148,6 +148,9 @@ typedef struct // VID_ShutdownWindow() to shut down window as well, if !contextOnly void (EXPORT *ShutdownWindow)(qboolean contextOnly); + // returns true if vsync is active, else false + qboolean (EXPORT *IsVSyncActive)(void); + // All data that will be used in a level should be // registered before rendering any frames to prevent disk hits, // but they can still be registered at a later time diff --git a/src/client/refresh/gl/r_main.c b/src/client/refresh/gl/r_main.c index 815be649..0ba45c80 100644 --- a/src/client/refresh/gl/r_main.c +++ b/src/client/refresh/gl/r_main.c @@ -1574,6 +1574,7 @@ RI_Shutdown(void) } extern void UpdateHardwareGamma(); +extern void RI_SetSwapInterval(void); void RI_BeginFrame(float camera_separation) @@ -1700,6 +1701,12 @@ RI_BeginFrame(float camera_separation) gl_texturesolidmode->modified = false; } + if (gl_swapinterval->modified) + { + gl_swapinterval->modified = false; + RI_SetSwapInterval(); + } + /* clear screen if desired */ R_Clear(); } @@ -1852,6 +1859,7 @@ extern void RDraw_FadeScreen(void); extern void RDraw_StretchRaw(int x, int y, int w, int h, int cols, int rows, byte *data); extern void RI_SetPalette(const unsigned char *palette); +extern qboolean RI_IsVSyncActive(void); extern void RI_EndFrame(void); Q2_DLL_EXPORTED refexport_t @@ -1868,6 +1876,7 @@ GetRefAPI(refimport_t imp) re.PrepareForWindow = RI_PrepareForWindow; re.InitContext = RI_InitContext; re.ShutdownWindow = RI_ShutdownWindow; + re.IsVSyncActive = RI_IsVSyncActive; re.BeginRegistration = RI_BeginRegistration; re.RegisterModel = RI_RegisterModel; re.RegisterSkin = RI_RegisterSkin; diff --git a/src/client/refresh/gl/r_sdl.c b/src/client/refresh/gl/r_sdl.c index 89dbff15..02ee8b2a 100644 --- a/src/client/refresh/gl/r_sdl.c +++ b/src/client/refresh/gl/r_sdl.c @@ -63,6 +63,7 @@ static SDL_Surface* window = NULL; #endif qboolean have_stencil = false; +static qboolean vsyncActive = false; /* * Returns the adress of a GL function @@ -370,6 +371,17 @@ int RI_PrepareForWindow(void) return flags; } +void RI_SetSwapInterval(void) +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + /* Set vsync - TODO: -1 could be set for "late swap tearing" */ + SDL_GL_SetSwapInterval(gl_swapinterval->value ? 1 : 0); + vsyncActive = SDL_GL_GetSwapInterval() != 0; +#else + R_Printf(PRINT_ALL, "SDL1.2 requires a vid_restart to apply changes to gl_swapinterval (vsync)!\n"); +#endif +} + int RI_InitContext(void* win) { int msaa_samples = 0, stencil_bits = 0; @@ -400,8 +412,9 @@ int RI_InitContext(void* win) #if SDL_VERSION_ATLEAST(2, 0, 0) /* For SDL2, this must be done after creating the window */ - /* Set vsync - TODO: -1 could be set for "late swap tearing" */ - SDL_GL_SetSwapInterval(gl_swapinterval->value ? 1 : 0); + RI_SetSwapInterval(); +#else // SDL1.2 - set vsyncActive to whatever is configured, hoping it was actually set + vsyncActive = gl_swapinterval->value ? 1 : 0; #endif /* Initialize the stencil buffer */ @@ -429,6 +442,11 @@ int RI_InitContext(void* win) return true; } +qboolean RI_IsVSyncActive(void) +{ + return vsyncActive; +} + /* * Swaps the buffers to show the new frame */ diff --git a/src/client/refresh/gl3/gl3_main.c b/src/client/refresh/gl3/gl3_main.c index 159f13b1..c2513325 100644 --- a/src/client/refresh/gl3/gl3_main.c +++ b/src/client/refresh/gl3/gl3_main.c @@ -1638,6 +1638,12 @@ GL3_BeginFrame(float camera_separation) gl_anisotropic->modified = false; } + if(gl_swapinterval->modified) + { + gl_swapinterval->modified = false; + GL3_SetSwapInterval(); + } + STUB_ONCE("TODO: texture-alpha/solid-mode stuff??") #if 0 if (gl_texturealphamode->modified) @@ -1703,6 +1709,7 @@ GetRefAPI(refimport_t imp) re.PrepareForWindow = GL3_PrepareForWindow; re.InitContext = GL3_InitContext; re.ShutdownWindow = GL3_ShutdownWindow; + re.IsVSyncActive = GL3_IsVsyncActive; re.BeginRegistration = GL3_BeginRegistration; re.RegisterModel = GL3_RegisterModel; diff --git a/src/client/refresh/gl3/gl3_misc.c b/src/client/refresh/gl3/gl3_misc.c index 7fa4fce4..f2db6041 100644 --- a/src/client/refresh/gl3/gl3_misc.c +++ b/src/client/refresh/gl3/gl3_misc.c @@ -68,29 +68,6 @@ GL3_SetDefaultState(void) STUB("need replacement for R_TexEnv(GL_REPLACE);"); - STUB("Apparently the GL_POINT stuff works differently in OpenGL3 core"); -#if 0 - { - // TODO: are we gonna use glPointParameter? - float attenuations[3] = {0.01f, 0.0f, 0.01f}; - /* - attenuations[0] = gl_particle_att_a->value; - attenuations[1] = gl_particle_att_b->value; - attenuations[2] = gl_particle_att_c->value; - */ - STUB("gl_particle_att_[abc], gl_particle_min/max_size ??"); - - /* GL_POINT_SMOOTH is not implemented by some OpenGL - drivers, especially the crappy Mesa3D backends like - i915.so. That the points are squares and not circles - is not a problem by Quake II! */ - glEnable(GL_POINT_SMOOTH); - glPointParameterf(GL_POINT_SIZE_MIN_EXT, 2.0f); // TODO was gl_particle_min_size->value); - glPointParameterf(GL_POINT_SIZE_MAX_EXT, 40.0f); // TODO was gl_particle_max_size->value); - glPointParameterf(GL_DISTANCE_ATTENUATION_EXT, attenuations); - } -#endif // 0 - if (gl_msaa_samples->value) { glEnable(GL_MULTISAMPLE); diff --git a/src/client/refresh/gl3/gl3_sdl.c b/src/client/refresh/gl3/gl3_sdl.c index 82ed300c..132a5efa 100644 --- a/src/client/refresh/gl3/gl3_sdl.c +++ b/src/client/refresh/gl3/gl3_sdl.c @@ -47,6 +47,7 @@ #endif qboolean have_stencil = false; +static qboolean vsyncActive = false; // called by GLimp_InitGraphics() before creating window, // returns flags for SDL window creation, -1 on error @@ -199,8 +200,9 @@ int GL3_InitContext(void* win) #if SDL_VERSION_ATLEAST(2, 0, 0) /* For SDL2, this must be done after creating the window */ - /* Set vsync - TODO: -1 could be set for "late swap tearing" */ - SDL_GL_SetSwapInterval(gl_swapinterval->value ? 1 : 0); + GL3_SetSwapInterval(); +#else // SDL1.2 - set vsyncActive to whatever is configured, hoping it was actually set + vsyncActive = gl_swapinterval->value ? 1 : 0; #endif /* Initialize the stencil buffer */ @@ -251,6 +253,24 @@ int GL3_InitContext(void* win) return true; } + + +void GL3_SetSwapInterval(void) +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + /* Set vsync - TODO: -1 could be set for "late swap tearing" */ + SDL_GL_SetSwapInterval(gl_swapinterval->value ? 1 : 0); + vsyncActive = SDL_GL_GetSwapInterval() != 0; +#else + R_Printf(PRINT_ALL, "SDL1.2 requires a vid_restart to apply changes to gl_swapinterval (vsync)!\n"); +#endif +} + +qboolean GL3_IsVsyncActive(void) +{ + return vsyncActive; +} + /* * Swaps the buffers to show the new frame */ diff --git a/src/client/refresh/gl3/header/local.h b/src/client/refresh/gl3/header/local.h index 9baaf670..20321386 100644 --- a/src/client/refresh/gl3/header/local.h +++ b/src/client/refresh/gl3/header/local.h @@ -329,6 +329,8 @@ extern qboolean have_stencil; extern int GL3_PrepareForWindow(void); extern int GL3_InitContext(void* win); +extern void GL3_SetSwapInterval(void); +extern qboolean GL3_IsVsyncActive(void); extern void GL3_EndFrame(void); extern void GL3_ShutdownWindow(qboolean contextOnly);