SDL: render: Update the size/scale/viewport on moves, in addition to resizes.

From cb8163081685fd97deba3c800bb8f10841b555a1 Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Fri, 8 Apr 2022 02:21:52 -0400
Subject: [PATCH] render: Update the size/scale/viewport on moves, in addition
 to resizes.

For OpenGL this means resetting the viewport state shadowing flag too.

Fixes #1504
---
 src/render/SDL_render.c           | 12 +++++++++++-
 src/render/opengl/SDL_render_gl.c | 22 +++++++++++++++-------
 2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 471e8c050ae..9bb953eddeb 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -698,7 +698,17 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
                 renderer->WindowEvent(renderer, &event->window);
             }
 
-            if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
+            /* In addition to size changes, we also want to do this block for
+             * moves as well, for two reasons:
+             *
+             * 1. The window could be moved to a new display, which has a new
+             *    DPI and therefore a new window/drawable ratio
+             * 2. For whatever reason, the viewport can get messed up during
+             *    window movement (this has been observed on macOS), so this is
+             *    also a good opportunity to force viewport updates
+             */
+            if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED ||
+                event->window.event == SDL_WINDOWEVENT_MOVED) {
                 /* Make sure we're operating on the default render target */
                 SDL_Texture *saved_target = SDL_GetRenderTarget(renderer);
                 if (saved_target) {
diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c
index e7c5169eb1e..a0ff1e272f6 100644
--- a/src/render/opengl/SDL_render_gl.c
+++ b/src/render/opengl/SDL_render_gl.c
@@ -324,6 +324,20 @@ GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
     return result;
 }
 
+static void
+GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
+{
+    /* If the window x/y/w/h changed at all, assume the viewport has been
+     * changed behind our backs. x/y changes might seem weird but viewport
+     * resets have been observed on macOS at minimum!
+     */
+    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
+        event->event == SDL_WINDOWEVENT_MOVED) {
+        GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
+        data->drawstate.viewport_dirty = SDL_TRUE;
+    }
+}
+
 static int
 GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
 {
@@ -1216,13 +1230,6 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
         }
     }
 
-#ifdef __MACOSX__
-    // On macOS, moving the window seems to invalidate the OpenGL viewport state,
-    // so don't bother trying to persist it across frames; always reset it.
-    // Workaround for: https://github.com/libsdl-org/SDL/issues/1504
-    data->drawstate.viewport_dirty = SDL_TRUE;
-#endif
-
     while (cmd) {
         switch (cmd->command) {
             case SDL_RENDERCMD_SETDRAWCOLOR: {
@@ -1767,6 +1774,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
         goto error;
     }
 
+    renderer->WindowEvent = GL_WindowEvent;
     renderer->GetOutputSize = GL_GetOutputSize;
     renderer->SupportsBlendMode = GL_SupportsBlendMode;
     renderer->CreateTexture = GL_CreateTexture;