diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h index c1ab822280..dda2546297 100644 --- a/include/SDL3/SDL_render.h +++ b/include/SDL3/SDL_render.h @@ -2142,6 +2142,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_AddVulkanRenderSemaphores(SDL_Renderer *rend /** * Toggle VSync of the given renderer. * + * When a renderer is created, vsync defaults to SDL_RENDERER_VSYNC_DISABLED. + * * \param renderer The renderer to toggle * \param vsync the vertical refresh sync interval, 1 to synchronize present * with every vertical refresh, 2 to synchronize present with @@ -2168,7 +2170,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_SetRenderVSync(SDL_Renderer *renderer, int v * * \param renderer The renderer to toggle * \param vsync an int filled with the current vertical refresh sync interval. - * See SDL_SetRenderVSync for the meaning of the value. + * See SDL_SetRenderVSync() for the meaning of the value. * \returns 0 on success or a negative error code on failure; call * SDL_GetError() for more information. * diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h index 9efc10c855..84d0173327 100644 --- a/include/SDL3/SDL_video.h +++ b/include/SDL3/SDL_video.h @@ -1801,6 +1801,40 @@ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_WindowHasSurface(SDL_Window *window); */ extern SDL_DECLSPEC SDL_Surface *SDLCALL SDL_GetWindowSurface(SDL_Window *window); +/** + * Toggle VSync for the window surface. + * + * When a window surface is created, vsync defaults to SDL_WINDOW_SURFACE_VSYNC_DISABLED. + * + * \param window the window + * \param vsync the vertical refresh sync interval, 1 to synchronize present with every vertical refresh, 2 to synchronize present with every second vertical refresh, etc., SDL_WINDOW_SURFACE_VSYNC_ADAPTIVE for late swap tearing (adaptive vsync), or SDL_WINDOW_SURFACE_VSYNC_DISABLED to disable. Not every value is supported by every driver, so you should check the return value to see whether the requested setting is supported. + * \returns 0 on success or a negative error code on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetWindowSurfaceVSync + */ +extern SDL_DECLSPEC int SDLCALL SDL_SetWindowSurfaceVSync(SDL_Window *window, int vsync); + +#define SDL_WINDOW_SURFACE_VSYNC_DISABLED 0 +#define SDL_WINDOW_SURFACE_VSYNC_ADAPTIVE (-1) + +/** + * Get VSync for the window surface. + * + * \param window the window to query + * \param vsync an int filled with the current vertical refresh sync interval. + * See SDL_SetWindowSurfaceVSync() for the meaning of the value. + * \returns 0 on success or a negative error code on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_SetWindowSurfaceVSync + */ +extern SDL_DECLSPEC int SDLCALL SDL_GetWindowSurfaceVSync(SDL_Window *window, int *vsync); + /** * Copy the window surface to the screen. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index f670900605..d91b6f14b6 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -474,6 +474,7 @@ SDL3_0.0.0 { SDL_GetWindowSize; SDL_GetWindowSizeInPixels; SDL_GetWindowSurface; + SDL_GetWindowSurfaceVSync; SDL_GetWindowTitle; SDL_GlobDirectory; SDL_GlobStorageDirectory; @@ -765,6 +766,7 @@ SDL3_0.0.0 { SDL_SetWindowResizable; SDL_SetWindowShape; SDL_SetWindowSize; + SDL_SetWindowSurfaceVSync; SDL_SetWindowTitle; SDL_SetWindowsMessageHook; SDL_SetX11EventHook; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 629a12d8d3..967b6bfb26 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -499,6 +499,7 @@ #define SDL_GetWindowSize SDL_GetWindowSize_REAL #define SDL_GetWindowSizeInPixels SDL_GetWindowSizeInPixels_REAL #define SDL_GetWindowSurface SDL_GetWindowSurface_REAL +#define SDL_GetWindowSurfaceVSync SDL_GetWindowSurfaceVSync_REAL #define SDL_GetWindowTitle SDL_GetWindowTitle_REAL #define SDL_GlobDirectory SDL_GlobDirectory_REAL #define SDL_GlobStorageDirectory SDL_GlobStorageDirectory_REAL @@ -790,6 +791,7 @@ #define SDL_SetWindowResizable SDL_SetWindowResizable_REAL #define SDL_SetWindowShape SDL_SetWindowShape_REAL #define SDL_SetWindowSize SDL_SetWindowSize_REAL +#define SDL_SetWindowSurfaceVSync SDL_SetWindowSurfaceVSync_REAL #define SDL_SetWindowTitle SDL_SetWindowTitle_REAL #define SDL_SetWindowsMessageHook SDL_SetWindowsMessageHook_REAL #define SDL_SetX11EventHook SDL_SetX11EventHook_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 1147fe02ff..251660ff98 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -519,6 +519,7 @@ SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetWindowProperties,(SDL_Window *a),(a),ret SDL_DYNAPI_PROC(int,SDL_GetWindowSize,(SDL_Window *a, int *b, int *c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_GetWindowSizeInPixels,(SDL_Window *a, int *b, int *c),(a,b,c),return) SDL_DYNAPI_PROC(SDL_Surface*,SDL_GetWindowSurface,(SDL_Window *a),(a),return) +SDL_DYNAPI_PROC(int,SDL_GetWindowSurfaceVSync,(SDL_Window *a, int *b),(a,b),return) SDL_DYNAPI_PROC(const char*,SDL_GetWindowTitle,(SDL_Window *a),(a),return) SDL_DYNAPI_PROC(char**,SDL_GlobDirectory,(const char *a, const char *b, SDL_GlobFlags c, int *d),(a,b,c,d),return) SDL_DYNAPI_PROC(char**,SDL_GlobStorageDirectory,(SDL_Storage *a, const char *b, const char *c, SDL_GlobFlags d, int *e),(a,b,c,d,e),return) @@ -800,6 +801,7 @@ SDL_DYNAPI_PROC(int,SDL_SetWindowPosition,(SDL_Window *a, int b, int c),(a,b,c), SDL_DYNAPI_PROC(int,SDL_SetWindowResizable,(SDL_Window *a, SDL_bool b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_SetWindowShape,(SDL_Window *a, SDL_Surface *b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_SetWindowSize,(SDL_Window *a, int b, int c),(a,b,c),return) +SDL_DYNAPI_PROC(int,SDL_SetWindowSurfaceVSync,(SDL_Window *a, int b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_SetWindowTitle,(SDL_Window *a, const char *b),(a,b),return) SDL_DYNAPI_PROC(void,SDL_SetWindowsMessageHook,(SDL_WindowsMessageHook a, void *b),(a,b),) SDL_DYNAPI_PROC(void,SDL_SetX11EventHook,(SDL_X11EventHook a, void *b),(a,b),) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index d5701d8b3d..24daf9a0b1 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -4727,10 +4727,13 @@ int SDL_SetRenderVSync(SDL_Renderer *renderer, int vsync) renderer->wanted_vsync = vsync ? SDL_TRUE : SDL_FALSE; - /* for the software renderer, forward eventually the call to the WindowTexture renderer */ + /* for the software renderer, forward the call to the WindowTexture renderer */ #if SDL_VIDEO_RENDER_SW if (renderer->software) { - if (SDL_SetWindowTextureVSync(renderer->window, vsync) == 0) { + if (!renderer->window) { + return SDL_Unsupported(); + } + if (SDL_SetWindowTextureVSync(NULL, renderer->window, vsync) == 0) { renderer->simulate_vsync = SDL_FALSE; return 0; } diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 9353bc1975..1de2c3d74a 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -262,6 +262,8 @@ struct SDL_VideoDevice int (*SetWindowKeyboardGrab)(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed); void (*DestroyWindow)(SDL_VideoDevice *_this, SDL_Window *window); int (*CreateWindowFramebuffer)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormatEnum *format, void **pixels, int *pitch); + int (*SetWindowFramebufferVSync)(SDL_VideoDevice *_this, SDL_Window *window, int vsync); + int (*GetWindowFramebufferVSync)(SDL_VideoDevice *_this, SDL_Window *window, int *vsync); int (*UpdateWindowFramebuffer)(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects); void (*DestroyWindowFramebuffer)(SDL_VideoDevice *_this, SDL_Window *window); void (*OnWindowEnter)(SDL_VideoDevice *_this, SDL_Window *window); diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 29658b6a8c..7f30b46ffa 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -395,10 +395,35 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, S return 0; } -static SDL_VideoDevice *_this = NULL; -static SDL_AtomicInt SDL_messagebox_count; +int SDL_SetWindowTextureVSync(SDL_VideoDevice *_this, SDL_Window *window, int vsync) +{ + SDL_WindowTextureData *data; -static int SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window *window, const SDL_Rect *rects, int numrects) + data = (SDL_WindowTextureData *)SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_TEXTUREDATA_POINTER, NULL); + if (!data) { + return -1; + } + if (!data->renderer) { + return -1; + } + return SDL_SetRenderVSync(data->renderer, vsync); +} + +static int SDL_GetWindowTextureVSync(SDL_VideoDevice *_this, SDL_Window *window, int *vsync) +{ + SDL_WindowTextureData *data; + + data = (SDL_WindowTextureData *)SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_TEXTUREDATA_POINTER, NULL); + if (!data) { + return -1; + } + if (!data->renderer) { + return -1; + } + return SDL_GetRenderVSync(data->renderer, vsync); +} + +static int SDL_UpdateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects) { SDL_WindowTextureData *data; SDL_Rect rect; @@ -430,24 +455,13 @@ static int SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window *window, return 0; } -static void SDL_DestroyWindowTexture(SDL_VideoDevice *unused, SDL_Window *window) +static void SDL_DestroyWindowTexture(SDL_VideoDevice *_this, SDL_Window *window) { SDL_ClearProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_TEXTUREDATA_POINTER); } -int SDL_SetWindowTextureVSync(SDL_Window *window, int vsync) -{ - SDL_WindowTextureData *data; - - data = (SDL_WindowTextureData *)SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_TEXTUREDATA_POINTER, NULL); - if (!data) { - return -1; - } - if (!data->renderer) { - return -1; - } - return SDL_SetRenderVSync(data->renderer, vsync); -} +static SDL_VideoDevice *_this = NULL; +static SDL_AtomicInt SDL_messagebox_count; static int SDLCALL cmpmodes(const void *A, const void *B) { @@ -3202,6 +3216,8 @@ static SDL_Surface *SDL_CreateWindowFramebuffer(SDL_Window *window) !!! FIXME: framebuffer at the right places; is it feasible we could have an !!! FIXME: accelerated OpenGL window and a second ends up in software? */ _this->CreateWindowFramebuffer = SDL_CreateWindowTexture; + _this->SetWindowFramebufferVSync = SDL_SetWindowTextureVSync; + _this->GetWindowFramebufferVSync = SDL_GetWindowTextureVSync; _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture; _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture; created_framebuffer = SDL_TRUE; @@ -3250,6 +3266,26 @@ SDL_Surface *SDL_GetWindowSurface(SDL_Window *window) return window->surface; } +int SDL_SetWindowSurfaceVSync(SDL_Window *window, int vsync) +{ + CHECK_WINDOW_MAGIC(window, -1); + + if (!_this->SetWindowFramebufferVSync) { + return SDL_Unsupported(); + } + return _this->SetWindowFramebufferVSync(_this, window, vsync); +} + +int SDL_GetWindowSurfaceVSync(SDL_Window *window, int *vsync) +{ + CHECK_WINDOW_MAGIC(window, -1); + + if (!_this->GetWindowFramebufferVSync) { + return SDL_Unsupported(); + } + return _this->GetWindowFramebufferVSync(_this, window, vsync); +} + int SDL_UpdateWindowSurface(SDL_Window *window) { SDL_Rect full_rect; diff --git a/src/video/SDL_video_c.h b/src/video/SDL_video_c.h index 7e06bde8d7..3e8a694443 100644 --- a/src/video/SDL_video_c.h +++ b/src/video/SDL_video_c.h @@ -24,6 +24,8 @@ #include "SDL_internal.h" +typedef struct SDL_VideoDevice SDL_VideoDevice; + /** * Initialize the video subsystem, optionally specifying a video driver. * @@ -55,7 +57,7 @@ extern int SDL_VideoInit(const char *driver_name); */ extern void SDL_VideoQuit(void); -extern int SDL_SetWindowTextureVSync(SDL_Window *window, int vsync); +extern int SDL_SetWindowTextureVSync(SDL_VideoDevice *_this, SDL_Window *window, int vsync); extern int SDL_ReadSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a);