SDL: Added support for SDL_RENDERER_PRESENTVSYNC to the software renderer

From fcfd19db862b60159577720f46d31a35a03e7888 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 10 Aug 2021 12:02:17 -0700
Subject: [PATCH] Added support for SDL_RENDERER_PRESENTVSYNC to the software
 renderer

This fixes https://github.com/libsdl-org/SDL/issues/4612
---
 src/render/SDL_render.c             |  3 +-
 src/render/software/SDL_render_sw.c | 15 ++++++-
 src/video/SDL_video.c               | 68 ++++++++++++++---------------
 3 files changed, 50 insertions(+), 36 deletions(-)

diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 75adfab5a..25be260a1 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -833,7 +833,8 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
         goto error;
     }
 
-    if (SDL_GetHint(SDL_HINT_RENDER_VSYNC)) {
+    hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC);
+    if (hint && *hint) {
         if (SDL_GetHintBoolean(SDL_HINT_RENDER_VSYNC, SDL_TRUE)) {
             flags |= SDL_RENDERER_PRESENTVSYNC;
         } else {
diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c
index 35f70d3b3..518308ce7 100644
--- a/src/render/software/SDL_render_sw.c
+++ b/src/render/software/SDL_render_sw.c
@@ -859,9 +859,22 @@ SW_CreateRendererForSurface(SDL_Surface * surface)
 static SDL_Renderer *
 SW_CreateRenderer(SDL_Window * window, Uint32 flags)
 {
+    const char *hint;
     SDL_Surface *surface;
 
+    /* Set the vsync hint based on our flags, if it's not already set */
+    hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC);
+    if (!hint || !*hint) {
+        SDL_SetHint(SDL_HINT_RENDER_VSYNC, (flags & SDL_RENDERER_PRESENTVSYNC) ? "1" : "0");
+    }
+
     surface = SDL_GetWindowSurface(window);
+
+    /* Reset the vsync hint if we set it above */
+    if (!hint || !*hint) {
+        SDL_SetHint(SDL_HINT_RENDER_VSYNC, "");
+    }
+
     if (!surface) {
         return NULL;
     }
@@ -872,7 +885,7 @@ SDL_RenderDriver SW_RenderDriver = {
     SW_CreateRenderer,
     {
      "software",
-     SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE,
+     SDL_RENDERER_SOFTWARE | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE,
      8,
      {
       SDL_PIXELFORMAT_ARGB8888,
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 057dce09f..1994c56f5 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -172,6 +172,39 @@ typedef struct {
     int bytes_per_pixel;
 } SDL_WindowTextureData;
 
+#if SDL_VIDEO_OPENGL
+static SDL_bool
+HasAcceleratedOpenGL()
+{
+    SDL_Window *window;
+    SDL_GLContext context;
+    SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
+
+    window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN);
+    if (window) {
+        context = SDL_GL_CreateContext(window);
+        if (context) {
+            const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
+            const char *vendor = NULL;
+
+            glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
+            if (glGetStringFunc) {
+                vendor = (const char *) glGetStringFunc(GL_VENDOR);
+            }
+            /* Add more vendors here at will... */
+            if (vendor &&
+                (SDL_strstr(vendor, "ATI Technologies") ||
+                 SDL_strstr(vendor, "NVIDIA"))) {
+                hasAcceleratedOpenGL = SDL_TRUE;
+            }
+            SDL_GL_DeleteContext(context);
+        }
+        SDL_DestroyWindow(window);
+    }
+    return hasAcceleratedOpenGL;
+}
+#endif /* SDL_VIDEO_OPENGL */
+
 static SDL_bool
 ShouldUseTextureFramebuffer()
 {
@@ -187,14 +220,6 @@ ShouldUseTextureFramebuffer()
         return SDL_FALSE;
     }
 
-    /* If the user has specified a software renderer we can't use a
-       texture framebuffer, or renderer creation will go recursive.
-     */
-    hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
-    if (hint && SDL_strcasecmp(hint, "software") == 0) {
-        return SDL_FALSE;
-    }
-
     /* See if the user or application wants a specific behavior */
     hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
     if (hint) {
@@ -218,33 +243,8 @@ ShouldUseTextureFramebuffer()
 #elif defined(__LINUX__)
     /* Properly configured OpenGL drivers are faster than MIT-SHM */
 #if SDL_VIDEO_OPENGL
-    /* Ugh, find a way to cache this value! */
     {
-        SDL_Window *window;
-        SDL_GLContext context;
-        SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
-
-        window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN);
-        if (window) {
-            context = SDL_GL_CreateContext(window);
-            if (context) {
-                const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
-                const char *vendor = NULL;
-
-                glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
-                if (glGetStringFunc) {
-                    vendor = (const char *) glGetStringFunc(GL_VENDOR);
-                }
-                /* Add more vendors here at will... */
-                if (vendor &&
-                    (SDL_strstr(vendor, "ATI Technologies") ||
-                     SDL_strstr(vendor, "NVIDIA"))) {
-                    hasAcceleratedOpenGL = SDL_TRUE;
-                }
-                SDL_GL_DeleteContext(context);
-            }
-            SDL_DestroyWindow(window);
-        }
+        static SDL_bool hasAcceleratedOpenGL = HasAcceleratedOpenGL();
         return hasAcceleratedOpenGL;
     }
 #elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2