SDL: Handle error return value for SDL_GetSwapInterval

From 8a135339490675891f192657b5479c0dc7ad9f66 Mon Sep 17 00:00:00 2001
From: Sylvain Becker <[EMAIL REDACTED]>
Date: Sun, 1 Jan 2023 17:20:41 +0100
Subject: [PATCH] Handle error return value for SDL_GetSwapInterval

---
 docs/README-migration.md                |  1 +
 include/SDL3/SDL_video.h                | 10 ++++++----
 src/dynapi/SDL_dynapi_procs.h           |  2 +-
 src/render/opengl/SDL_render_gl.c       | 21 ++++++++++++++++++---
 src/render/opengles2/SDL_render_gles2.c | 21 ++++++++++++++++++---
 src/video/SDL_video.c                   | 19 ++++++++++++++-----
 test/testgl2.c                          | 11 ++++++++++-
 7 files changed, 68 insertions(+), 17 deletions(-)

diff --git a/docs/README-migration.md b/docs/README-migration.md
index 24e06265c6d4..52c3adfd23d2 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -838,6 +838,7 @@ SDL_SetWindowBrightness and SDL_SetWindowGammaRamp have been removed from the AP
 
 Programs which have access to shaders can implement more robust versions of those functions using custom shader code rendered as a post-process effect.
 
+'SDL_GL_GetSwapInterval()' takes 'interval' as an output parameter and returns -1 on error.
 
 Removed 'SDL_GL_CONTEXT_EGL' from OpenGL configuration attributes
 You can instead use 'SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);'
diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h
index d041cc56269b..aef9928563d9 100644
--- a/include/SDL3/SDL_video.h
+++ b/include/SDL3/SDL_video.h
@@ -1989,18 +1989,20 @@ extern DECLSPEC int SDLCALL SDL_GL_SetSwapInterval(int interval);
  * Get the swap interval for the current OpenGL context.
  *
  * If the system can't determine the swap interval, or there isn't a valid
- * current context, this function will return 0 as a safe default.
+ * current context, this function will set *interval to 0 as a safe default.
  *
- * \returns 0 if there is no vertical retrace synchronization, 1 if the buffer
+ * \param interval Output interval value. 0 if there is no vertical retrace synchronization, 1 if the buffer
  *          swap is synchronized with the vertical retrace, and -1 if late
- *          swaps happen immediately instead of waiting for the next retrace;
+ *          swaps happen immediately instead of waiting for the next retrace
+ *
+ * \returns 0 on success or -1 error.
  *          call SDL_GetError() for more information.
  *
  * \since This function is available since SDL 3.0.0.
  *
  * \sa SDL_GL_SetSwapInterval
  */
-extern DECLSPEC int SDLCALL SDL_GL_GetSwapInterval(void);
+extern DECLSPEC int SDLCALL SDL_GL_GetSwapInterval(int *interval);
 
 /**
  * Update a window with OpenGL rendering.
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index c7682df04140..069178d22a0c 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -224,7 +224,7 @@ SDL_DYNAPI_PROC(SDL_GLContext,SDL_GL_GetCurrentContext,(void),(),return)
 SDL_DYNAPI_PROC(SDL_Window*,SDL_GL_GetCurrentWindow,(void),(),return)
 SDL_DYNAPI_PROC(void,SDL_GL_GetDrawableSize,(SDL_Window *a, int *b, int *c),(a,b,c),)
 SDL_DYNAPI_PROC(void*,SDL_GL_GetProcAddress,(const char *a),(a),return)
-SDL_DYNAPI_PROC(int,SDL_GL_GetSwapInterval,(void),(),return)
+SDL_DYNAPI_PROC(int,SDL_GL_GetSwapInterval,(int *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GL_LoadLibrary,(const char *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GL_MakeCurrent,(SDL_Window *a, SDL_GLContext b),(a,b),return)
 SDL_DYNAPI_PROC(void,SDL_GL_ResetAttributes,(void),(),)
diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c
index 5fcad4a55553..cfa3c8d80352 100644
--- a/src/render/opengl/SDL_render_gl.c
+++ b/src/render/opengl/SDL_render_gl.c
@@ -1651,6 +1651,7 @@ static int GL_UnbindTexture(SDL_Renderer *renderer, SDL_Texture *texture)
 static int GL_SetVSync(SDL_Renderer *renderer, const int vsync)
 {
     int retval;
+    int interval = 0;
     if (vsync) {
         retval = SDL_GL_SetSwapInterval(1);
     } else {
@@ -1659,7 +1660,13 @@ static int GL_SetVSync(SDL_Renderer *renderer, const int vsync)
     if (retval != 0) {
         return retval;
     }
-    if (SDL_GL_GetSwapInterval() > 0) {
+
+    retval = SDL_GL_GetSwapInterval(&interval);
+    if (retval < 0) {
+        return retval;
+    }
+
+    if (interval > 0) {
         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
     } else {
         renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC;
@@ -1804,8 +1811,16 @@ static SDL_Renderer *GL_CreateRenderer(SDL_Window *window, Uint32 flags)
     } else {
         SDL_GL_SetSwapInterval(0);
     }
-    if (SDL_GL_GetSwapInterval() > 0) {
-        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+
+    {
+        int interval = 0;
+        if (SDL_GL_GetSwapInterval(&interval) < 0) {
+            /* Error */
+        } else {
+            if (interval > 0) {
+                renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+            }
+        }
     }
 
     /* Check for debug output support */
diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c
index 312d97487050..e41ca0a4d66a 100644
--- a/src/render/opengles2/SDL_render_gles2.c
+++ b/src/render/opengles2/SDL_render_gles2.c
@@ -1962,6 +1962,7 @@ static int GLES2_RenderPresent(SDL_Renderer *renderer)
 static int GLES2_SetVSync(SDL_Renderer *renderer, const int vsync)
 {
     int retval;
+    int interval = 0;
     if (vsync) {
         retval = SDL_GL_SetSwapInterval(1);
     } else {
@@ -1970,7 +1971,13 @@ static int GLES2_SetVSync(SDL_Renderer *renderer, const int vsync)
     if (retval != 0) {
         return retval;
     }
-    if (SDL_GL_GetSwapInterval() > 0) {
+
+    retval = SDL_GL_GetSwapInterval(&interval);
+    if (retval < 0) {
+        return retval;
+    }
+
+    if (interval > 0) {
         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
     } else {
         renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC;
@@ -2131,8 +2138,16 @@ static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
     } else {
         SDL_GL_SetSwapInterval(0);
     }
-    if (SDL_GL_GetSwapInterval() > 0) {
-        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+
+    {
+        int interval = 0;
+        if (SDL_GL_GetSwapInterval(&interval) < 0) {
+            /* Error */
+        } else {
+            if (interval > 0) {
+                renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+            }
+        }
     }
 
     /* Check for debug output support */
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 55c8da223ea9..b77aff093715 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -4053,16 +4053,25 @@ int SDL_GL_SetSwapInterval(int interval)
     }
 }
 
-int SDL_GL_GetSwapInterval(void)
+int SDL_GL_GetSwapInterval(int *interval)
 {
+    if (interval == NULL) {
+       return SDL_InvalidParamError("interval");
+    }
+
+    *interval = 0;
+
     if (_this == NULL) {
-        return 0;
+        return SDL_SetError("no video driver");;
     } else if (SDL_GL_GetCurrentContext() == NULL) {
-        return 0;
+        return SDL_SetError("no current context");;
     } else if (_this->GL_GetSwapInterval) {
-        return _this->GL_GetSwapInterval(_this);
-    } else {
+        int val = _this->GL_GetSwapInterval(_this);
+         
+        *interval = val;
         return 0;
+    } else {
+        return SDL_SetError("not implemented");;
     }
 }
 
diff --git a/test/testgl2.c b/test/testgl2.c
index c8c7ddee7301..8b2bf758770d 100644
--- a/test/testgl2.c
+++ b/test/testgl2.c
@@ -209,6 +209,8 @@ int main(int argc, char *argv[])
     int status;
     int dw, dh;
     int swap_interval = 0;
+    int interval = 0;
+    int ret_interval = 0;
 
     /* Enable standard application logging */
     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
@@ -293,7 +295,14 @@ int main(int argc, char *argv[])
 
     SDL_GetCurrentDisplayMode(0, &mode);
     SDL_Log("Screen BPP    : %" SDL_PRIu32 "\n", SDL_BITSPERPIXEL(mode.format));
-    SDL_Log("Swap Interval : %d\n", SDL_GL_GetSwapInterval());
+
+    ret_interval = SDL_GL_GetSwapInterval(&interval);
+    if (ret_interval < 0) {
+       SDL_Log("Swap Interval : %d error: %s\n", interval, SDL_GetError());
+    } else {
+       SDL_Log("Swap Interval : %d\n", interval);
+    }
+
     SDL_GetWindowSize(state->windows[0], &dw, &dh);
     SDL_Log("Window Size   : %d,%d\n", dw, dh);
     SDL_GL_GetDrawableSize(state->windows[0], &dw, &dh);