From 4549769d7de1780686cc6cef0c613af9a072015f Mon Sep 17 00:00:00 2001 From: Misa Date: Sun, 7 Mar 2021 15:20:45 -0800 Subject: [PATCH] Add `SDL_RenderSetVSync()` Currently, if an application wants to toggle VSync, they'd have to tear down the renderer and recreate it. This patch fixes that by letting applications call SDL_RenderSetVSync(). This is the same as the patch in #3673, except it applies to all renderers (including PSP, even thought it seems that the VSync flag is disabled for that renderer). Furthermore, the renderer flags also change as well, which #3673 didn't do. It is also an API instead of using hint callbacks (which could be potentially dangerous). Closes #3673. --- include/SDL_render.h | 9 +++++++++ src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + src/render/SDL_render.c | 11 +++++++++++ src/render/SDL_sysrender.h | 2 ++ src/render/direct3d/SDL_render_d3d.c | 19 +++++++++++++++++++ src/render/direct3d11/SDL_render_d3d11.c | 16 ++++++++++++++++ src/render/metal/SDL_render_metal.m | 21 +++++++++++++++++++++ src/render/opengl/SDL_render_gl.c | 21 +++++++++++++++++++++ src/render/opengles/SDL_render_gles.c | 22 ++++++++++++++++++++++ src/render/opengles2/SDL_render_gles2.c | 21 +++++++++++++++++++++ src/render/psp/SDL_render_psp.c | 9 +++++++++ src/render/vitagxm/SDL_render_vita_gxm.c | 15 +++++++++++++++ 13 files changed, 168 insertions(+) diff --git a/include/SDL_render.h b/include/SDL_render.h index 8898c7839..f8e5e6ca9 100644 --- a/include/SDL_render.h +++ b/include/SDL_render.h @@ -1694,6 +1694,15 @@ extern DECLSPEC void *SDLCALL SDL_RenderGetMetalLayer(SDL_Renderer * renderer); */ extern DECLSPEC void *SDLCALL SDL_RenderGetMetalCommandEncoder(SDL_Renderer * renderer); +/** + * Toggle VSync of the given renderer. + * + * \param renderer The renderer to toggle + * \param vsync Non-zero for on, zero for off + * \returns a 0 int on success, or non-zero on failure + */ +extern DECLSPEC int SDLCALL SDL_RenderSetVSync(SDL_Renderer* renderer, int vsync); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 6a849c4fd..b28b5b8d1 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -819,3 +819,4 @@ #define SDL_GetTextureUserData SDL_GetTextureUserData_REAL #define SDL_RenderGeometry SDL_RenderGeometry_REAL #define SDL_RenderGeometryRaw SDL_RenderGeometryRaw_REAL +#define SDL_RenderSetVSync SDL_RenderSetVSync_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 5a913c360..9887e623c 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -884,3 +884,4 @@ SDL_DYNAPI_PROC(int,SDL_SetTextureUserData,(SDL_Texture *a, void *b),(a,b),retur SDL_DYNAPI_PROC(void*,SDL_GetTextureUserData,(SDL_Texture *a),(a),return) SDL_DYNAPI_PROC(int,SDL_RenderGeometry,(SDL_Renderer *a, SDL_Texture *b, const SDL_Vertex *c, int d, const int *e, int f),(a,b,c,d,e,f),return) SDL_DYNAPI_PROC(int,SDL_RenderGeometryRaw,(SDL_Renderer *a, SDL_Texture *b, const float *c, int d, const int *e, int f, const float *g, int h, int i, const void *j, int k, int l),(a,b,c,d,e,f,g,h,i,j,k,l),return) +SDL_DYNAPI_PROC(int,SDL_RenderSetVSync,(SDL_Renderer *a, int b),(a,b),return) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index ec545701d..eec6dc9bb 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -4124,4 +4124,15 @@ SDL_GetBlendModeAlphaOperation(SDL_BlendMode blendMode) return (SDL_BlendOperation)(((Uint32)blendMode >> 16) & 0xF); } +int +SDL_RenderSetVSync(SDL_Renderer * renderer, int vsync) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + if (renderer->SetVSync) { + return renderer->SetVSync(renderer, vsync); + } + return SDL_Unsupported(); +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index f569b51ed..8a640055b 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -163,6 +163,8 @@ struct SDL_Renderer void (*DestroyRenderer) (SDL_Renderer * renderer); + int (*SetVSync) (SDL_Renderer * renderer, int vsync); + int (*GL_BindTexture) (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh); int (*GL_UnbindTexture) (SDL_Renderer * renderer, SDL_Texture *texture); diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c index a847631df..a567b78b7 100644 --- a/src/render/direct3d/SDL_render_d3d.c +++ b/src/render/direct3d/SDL_render_d3d.c @@ -1743,6 +1743,24 @@ D3D_Reset(SDL_Renderer * renderer) return 0; } +static int +D3D_SetVSync(SDL_Renderer * renderer, const int vsync) +{ + D3D_RenderData *data = renderer->driverdata; + if (vsync) { + data->pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } else { + data->pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC; + } + if (D3D_Reset(renderer) < 0) { + /* D3D_Reset will call SDL_SetError() */ + return -1; + } + return 0; +} + SDL_Renderer * D3D_CreateRenderer(SDL_Window * window, Uint32 flags) { @@ -1805,6 +1823,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->RenderPresent = D3D_RenderPresent; renderer->DestroyTexture = D3D_DestroyTexture; renderer->DestroyRenderer = D3D_DestroyRenderer; + renderer->SetVSync = D3D_SetVSync; renderer->info = D3D_RenderDriver.info; renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); renderer->driverdata = data; diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index 979296b6a..d07a23e2b 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -2598,6 +2598,21 @@ D3D11_RenderPresent(SDL_Renderer * renderer) } } +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + /* no-op. */ +#else +static int +D3D11_SetVSync(SDL_Renderer * renderer, const int vsync) +{ + if (vsync) { + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } else { + renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC; + } + return 0; +} +#endif + SDL_Renderer * D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) { @@ -2666,6 +2681,7 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) if ((flags & SDL_RENDERER_PRESENTVSYNC)) { renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; } + renderer->SetVSync = D3D11_SetVSync; #endif /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m index 217ffdce4..ca6ff2a19 100644 --- a/src/render/metal/SDL_render_metal.m +++ b/src/render/metal/SDL_render_metal.m @@ -1760,6 +1760,26 @@ METAL_GetMetalCommandEncoder(SDL_Renderer * renderer) return (__bridge void*)data.mtlcmdencoder; }} +static int +METAL_SetVSync(SDL_Renderer * renderer, const int vsync) +{ +#if (defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13)) || TARGET_OS_MACCATALYST + if (@available(macOS 10.13, *)) { + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; + if (vsync) { + data.mtllayer.displaySyncEnabled = YES; + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } else { + data.mtllayer.displaySyncEnabled = NO; + renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC; + } + return 0; + } +#endif + return SDL_SetError("This Apple OS does not support displaySyncEnabled!"); +} + + static SDL_Renderer * METAL_CreateRenderer(SDL_Window * window, Uint32 flags) { @autoreleasepool { @@ -2010,6 +2030,7 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->RenderPresent = METAL_RenderPresent; renderer->DestroyTexture = METAL_DestroyTexture; renderer->DestroyRenderer = METAL_DestroyRenderer; + renderer->SetVSync = METAL_SetVSync; renderer->GetMetalLayer = METAL_GetMetalLayer; renderer->GetMetalCommandEncoder = METAL_GetMetalCommandEncoder; diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 591f68fb4..d7f7a4406 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -1716,6 +1716,26 @@ GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture) return 0; } +static int +GL_SetVSync(SDL_Renderer * renderer, const int vsync) +{ + int retval; + if (vsync) { + retval = SDL_GL_SetSwapInterval(1); + } else { + retval = SDL_GL_SetSwapInterval(0); + } + if (retval != 0) { + return retval; + } + if (SDL_GL_GetSwapInterval() > 0) { + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } else { + renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC; + } + return retval; +} + static SDL_Renderer * GL_CreateRenderer(SDL_Window * window, Uint32 flags) @@ -1785,6 +1805,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->RenderPresent = GL_RenderPresent; renderer->DestroyTexture = GL_DestroyTexture; renderer->DestroyRenderer = GL_DestroyRenderer; + renderer->SetVSync = GL_SetVSync; renderer->GL_BindTexture = GL_BindTexture; renderer->GL_UnbindTexture = GL_UnbindTexture; renderer->info = GL_RenderDriver.info; diff --git a/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c index 93480140c..017229e9c 100644 --- a/src/render/opengles/SDL_render_gles.c +++ b/src/render/opengles/SDL_render_gles.c @@ -1229,6 +1229,27 @@ static int GLES_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture) return 0; } +static int +GLES_SetVSync(SDL_Renderer * renderer, const int vsync) +{ + int retval; + if (vsync) { + retval = SDL_GL_SetSwapInterval(1); + } else { + retval = SDL_GL_SetSwapInterval(0); + } + if (retval != 0) { + return retval; + } + if (SDL_GL_GetSwapInterval() > 0) { + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } else { + renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC; + } + return retval; +} + + static SDL_Renderer * GLES_CreateRenderer(SDL_Window * window, Uint32 flags) { @@ -1294,6 +1315,7 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->RenderPresent = GLES_RenderPresent; renderer->DestroyTexture = GLES_DestroyTexture; renderer->DestroyRenderer = GLES_DestroyRenderer; + renderer->SetVSync = GLES_SetVSync; renderer->GL_BindTexture = GLES_BindTexture; renderer->GL_UnbindTexture = GLES_UnbindTexture; renderer->info = GLES_RenderDriver.info; diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index f342dc309..73cca1bcb 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -2012,6 +2012,26 @@ GLES2_RenderPresent(SDL_Renderer *renderer) SDL_GL_SwapWindow(renderer->window); } +static int +GLES2_SetVSync(SDL_Renderer * renderer, const int vsync) +{ + int retval; + if (vsync) { + retval = SDL_GL_SetSwapInterval(1); + } else { + retval = SDL_GL_SetSwapInterval(0); + } + if (retval != 0) { + return retval; + } + if (SDL_GL_GetSwapInterval() > 0) { + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } else { + renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC; + } + return retval; +} + /************************************************************************************************* * Bind/unbinding of textures @@ -2197,6 +2217,7 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) renderer->RenderPresent = GLES2_RenderPresent; renderer->DestroyTexture = GLES2_DestroyTexture; renderer->DestroyRenderer = GLES2_DestroyRenderer; + renderer->SetVSync = GLES2_SetVSync; renderer->GL_BindTexture = GLES2_BindTexture; renderer->GL_UnbindTexture = GLES2_UnbindTexture; diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 6b9b3aff6..e6627048f 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -921,6 +921,14 @@ PSP_DestroyRenderer(SDL_Renderer * renderer) SDL_free(renderer); } +static int +PSP_SetVSync(SDL_Renderer * renderer, const int vsync) +{ + PSP_RenderData *data = renderer->driverdata; + data->vsync = vsync; + return 0; +} + SDL_Renderer * PSP_CreateRenderer(SDL_Window * window, Uint32 flags) { @@ -962,6 +970,7 @@ PSP_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->RenderPresent = PSP_RenderPresent; renderer->DestroyTexture = PSP_DestroyTexture; renderer->DestroyRenderer = PSP_DestroyRenderer; + renderer->SetVSync = PSP_SetVSync; renderer->info = PSP_RenderDriver.info; renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); renderer->driverdata = data; diff --git a/src/render/vitagxm/SDL_render_vita_gxm.c b/src/render/vitagxm/SDL_render_vita_gxm.c index ee62c814f..bf3af3962 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm.c +++ b/src/render/vitagxm/SDL_render_vita_gxm.c @@ -201,6 +201,20 @@ StartDrawing(SDL_Renderer *renderer) data->drawing = SDL_TRUE; } +static int +VITA_GXM_SetVSync(SDL_Renderer * renderer, const int vsync) +{ + VITA_GXM_RenderData *data = renderer->driverdata; + if (vsync) { + data->displayData.wait_vblank = SDL_TRUE; + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } else { + data->displayData.wait_vblank = SDL_FALSE; + renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC; + } + return 0; +} + SDL_Renderer * VITA_GXM_CreateRenderer(SDL_Window *window, Uint32 flags) { @@ -241,6 +255,7 @@ VITA_GXM_CreateRenderer(SDL_Window *window, Uint32 flags) renderer->RenderPresent = VITA_GXM_RenderPresent; renderer->DestroyTexture = VITA_GXM_DestroyTexture; renderer->DestroyRenderer = VITA_GXM_DestroyRenderer; + renderer->SetVSync = VITA_GXM_SetVSync; renderer->info = VITA_GXM_RenderDriver.info; renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);