sdl12-compat: Defer YUV overlay display until it's unlocked.

From 7a14f952a2c555f98210bde754e0923e2288f2b7 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sun, 2 May 2021 10:35:31 -0400
Subject: [PATCH] Defer YUV overlay display until it's unlocked.

SMPEG locks the overlay, calls SDL_DisplayYUVOverlay on it, copies new
data into the locked overlay, and then unlocks it. It's not clear if this
is an SMPEG bug, but it definitely works on the real SDL 1.2, so we take
pains to deal with this case.

Fixes #48.
---
 src/SDL12_compat.c | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/src/SDL12_compat.c b/src/SDL12_compat.c
index 0ca2f17..72b2e78 100644
--- a/src/SDL12_compat.c
+++ b/src/SDL12_compat.c
@@ -4208,6 +4208,8 @@ SDL_GetWMInfo(SDL_SysWMinfo * info)
 typedef struct SDL12_YUVData
 {
     SDL_Texture *texture20;
+    SDL_bool display_requested;
+    SDL12_Rect display_rect;
     Uint8 *pixelbuf;
     Uint8 *pixels[3];
     Uint16 pitches[3];
@@ -4304,6 +4306,9 @@ SDL_LockYUVOverlay(SDL12_Overlay *overlay12)
     return 0;  /* success */
 }
 
+DECLSPEC int SDLCALL
+SDL_DisplayYUVOverlay(SDL12_Overlay *overlay12, SDL12_Rect *dstrect12);
+
 DECLSPEC void SDLCALL
 SDL_UnlockYUVOverlay(SDL12_Overlay *overlay12)
 {
@@ -4327,6 +4332,12 @@ SDL_UnlockYUVOverlay(SDL12_Overlay *overlay12)
             SDL20_UpdateTexture(hwdata->texture20, &rect, hwdata->pixels[0], hwdata->pitches[0]);
         }
         overlay12->pixels = NULL;
+
+        /* See comments about SMPEG in SDL_DisplayYUVOverlay() */
+        if (hwdata->display_requested) {
+            hwdata->display_requested = SDL_FALSE;
+            SDL_DisplayYUVOverlay(overlay12, &hwdata->display_rect);
+        }
     }
 }
 
@@ -4334,7 +4345,6 @@ DECLSPEC int SDLCALL
 SDL_DisplayYUVOverlay(SDL12_Overlay *overlay12, SDL12_Rect *dstrect12)
 {
     SDL12_YUVData *hwdata;
-    SDL_Rect dstrect20;
 
     if (!overlay12) {
         return SDL20_InvalidParamError("overlay");
@@ -4344,14 +4354,22 @@ SDL_DisplayYUVOverlay(SDL12_Overlay *overlay12, SDL12_Rect *dstrect12)
         return SDL20_SetError("No software screen surface available");
     }
 
+    /* SMPEG locks the YUV overlay, calls SDL_DisplayYUVOverlay() on it, copies
+       data to it then unlocks it, in that order, which _seems_ like an app
+       bug, but it works in 1.2, so we tapdance to make that order work here. */
     hwdata = (SDL12_YUVData *) overlay12->hwdata;
-
-    SDL20_RenderClear(VideoRenderer20);
-    SDL20_RenderCopy(VideoRenderer20, VideoTexture20, NULL, NULL);
-    SDL20_RenderCopy(VideoRenderer20, hwdata->texture20, NULL, Rect12to20(dstrect12, &dstrect20));
-    SDL20_RenderPresent(VideoRenderer20);
-    VideoSurfaceLastPresentTicks = SDL20_GetTicks();
-    VideoSurfacePresentTicks = 0;
+    if (overlay12->pixels == NULL) {   /* NULL == not locked, present now */
+        SDL_Rect dstrect20;
+        SDL20_RenderClear(VideoRenderer20);
+        SDL20_RenderCopy(VideoRenderer20, VideoTexture20, NULL, NULL);
+        SDL20_RenderCopy(VideoRenderer20, hwdata->texture20, NULL, Rect12to20(dstrect12, &dstrect20));
+        SDL20_RenderPresent(VideoRenderer20);
+        VideoSurfaceLastPresentTicks = SDL20_GetTicks();
+        VideoSurfacePresentTicks = 0;
+    } else {  /* locked! Note that we should display as soon as it unlocks. */
+        hwdata->display_requested = SDL_TRUE;
+        SDL20_memcpy(&hwdata->display_rect, dstrect12, sizeof (SDL12_Rect));
+    }
 
     return 0;
 }