sdl12-compat: Time presentation of partial screen updates based on refresh rate

From 9e43523acab0d282fffb3a0dbe53aa7eb3b4273a Mon Sep 17 00:00:00 2001
From: David Gow <[EMAIL REDACTED]>
Date: Mon, 22 Nov 2021 12:28:09 +0800
Subject: [PATCH] Time presentation of partial screen updates based on refresh
 rate

Currently, for applications which update only part of the screen, we
present the screen every 15ms. Instead, update based on the refresh
rate. For fullscreen applications, this will be the refresh rate of the
screen they're on, for windowed applications, we use the refresh rate of
the display selected with SDL_VIDEO_FULLSCREEN_DISPLAY.

The calculation is split out into the GetDesiredMillisecondsPerFrame()
function, which is then used for both YUV and UpdateRects() updates.
---
 src/SDL12_compat.c | 26 ++++++++++++++++++++++----
 src/SDL20_syms.h   |  1 +
 2 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/src/SDL12_compat.c b/src/SDL12_compat.c
index 06032f5..aa42a2c 100644
--- a/src/SDL12_compat.c
+++ b/src/SDL12_compat.c
@@ -5581,6 +5581,26 @@ UpdateRect12to20(SDL12_Surface *surface12, const SDL12_Rect *rect12, SDL_Rect *r
     }
 }
 
+/* For manual throttling of screen updates. */
+static int
+GetDesiredMillisecondsPerFrame()
+{
+    SDL_DisplayMode mode;
+    if (VideoSurface12->flags & SDL12_FULLSCREEN) {
+       if (SDL20_GetWindowDisplayMode(VideoWindow20, &mode) == 0) {
+           if (mode.refresh_rate) {
+               return 1000 / mode.refresh_rate;
+           }
+       }
+    } else if (SDL20_GetCurrentDisplayMode(VideoDisplayIndex, &mode) == 0) {
+        /* If we're windowed, assume we're on the default screen. */
+        if (mode.refresh_rate) {
+            return 1000 / mode.refresh_rate;
+        }
+    }
+    return 15;
+}
+
 /* SDL_OPENGLBLIT support APIs. https://discourse.libsdl.org/t/ogl-and-sdl/2775/3 */
 DECLSPEC void SDLCALL
 SDL_GL_Lock(void)
@@ -5767,9 +5787,7 @@ SDL_UpdateRects(SDL12_Surface *surface12, int numrects, SDL12_Rect *rects12)
         if (whole_screen) {
             PresentScreen();  /* flip it now. */
         } else {
-            FIXME("Don't hardcode 15, do this based on display refresh rate.");
-            FIXME("Maybe just flip it immediately in PumpEvents if this flag is set, instead?");
-            VideoSurfacePresentTicks = VideoSurfaceLastPresentTicks + 15;  /* flip it later. */
+            VideoSurfacePresentTicks = VideoSurfaceLastPresentTicks + GetDesiredMillisecondsPerFrame();  /* flip it later. */
         }
     }
 }
@@ -6327,7 +6345,7 @@ SDL_DisplayYUVOverlay(SDL12_Overlay *overlay12, SDL12_Rect *dstrect12)
     FIXME("is it legal to display multiple yuv overlays?");  /* if so, this will need to be a list instead of a single pointer. */
     QueuedDisplayOverlay12 = overlay12;
     SDL20_memcpy(&QueuedDisplayOverlayDstRect12, dstrect12, sizeof (SDL12_Rect));
-    VideoSurfacePresentTicks = VideoSurfaceLastPresentTicks + 15;  /* flip it later. */
+    VideoSurfacePresentTicks = VideoSurfaceLastPresentTicks + GetDesiredMillisecondsPerFrame();  /* flip it later. */
 
     return 0;
 }
diff --git a/src/SDL20_syms.h b/src/SDL20_syms.h
index c30114f..77cc48e 100644
--- a/src/SDL20_syms.h
+++ b/src/SDL20_syms.h
@@ -79,6 +79,7 @@ SDL20_SYM(int,GetNumDisplayModes,(int a),(a),return)
 SDL20_SYM(int,GetDisplayMode,(int a, int b, SDL_DisplayMode *c),(a,b,c),return)
 SDL20_SYM(int,GetDesktopDisplayMode,(int a, SDL_DisplayMode *b),(a,b),return)
 SDL20_SYM(int,GetCurrentDisplayMode,(int a, SDL_DisplayMode *b),(a,b),return)
+SDL20_SYM(int,GetWindowDisplayMode,(SDL_Window *a, SDL_DisplayMode *b),(a,b),return)
 
 SDL20_SYM(void,EnableScreenSaver,(void),(),)
 SDL20_SYM(void,DisableScreenSaver,(void),(),)