From a40282013b207032d98daffc0bcf58ddbee683fa Mon Sep 17 00:00:00 2001
From: Toni Spets <toni.spets@iki.fi>
Date: Wed, 29 Jun 2011 22:47:29 +0300
Subject: [PATCH] Use a semaphore object to synchronize rendering thread with
 the game

---
 main.c        |  3 +++
 main.h        |  1 +
 palette.c     |  2 ++
 render.c      |  2 +-
 render_soft.c |  2 +-
 surface.c     | 18 ++++++++++++------
 6 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/main.c b/main.c
index b5f28d1..eee6d81 100644
--- a/main.c
+++ b/main.c
@@ -154,6 +154,7 @@ HRESULT __stdcall ddraw_RestoreDisplayMode(IDirectDrawImpl *This)
 
     EnterCriticalSection(&This->cs);
     This->render.run = FALSE;
+    ReleaseSemaphore(ddraw->render.sem, 1, NULL);
     LeaveCriticalSection(&This->cs);
 
     WaitForSingleObject(This->render.thread, INFINITE);
@@ -446,6 +447,7 @@ ULONG __stdcall ddraw_Release(IDirectDrawImpl *This)
             EnterCriticalSection(&This->cs);
 
             This->render.run = FALSE;
+            ReleaseSemaphore(ddraw->render.sem, 1, NULL);
             WaitForSingleObject(This->render.thread, INFINITE);
             This->render.thread = NULL;
 
@@ -561,6 +563,7 @@ HRESULT WINAPI DirectDrawCreate(GUID FAR* lpGUID, LPDIRECTDRAW FAR* lplpDD, IUnk
 
     InitializeCriticalSection(&This->cs);
     This->render.ev = CreateEvent(NULL, TRUE, FALSE, NULL);
+    This->render.sem = CreateSemaphore(NULL, 0, 1, NULL);
 
     /* load configuration options from ddraw.ini */
     char cwd[MAX_PATH];
diff --git a/main.h b/main.h
index 6017acb..23bfd84 100644
--- a/main.h
+++ b/main.h
@@ -62,6 +62,7 @@ typedef struct IDirectDrawImpl
         HANDLE thread;
         BOOL run;
         HANDLE ev;
+        HANDLE sem;
         DEVMODE mode;
 
     } render;
diff --git a/palette.c b/palette.c
index 22b0941..c2df589 100644
--- a/palette.c
+++ b/palette.c
@@ -44,6 +44,8 @@ HRESULT __stdcall ddraw_palette_SetEntries(IDirectDrawPaletteImpl *This, DWORD d
         }
     }
 
+    ReleaseSemaphore(ddraw->render.sem, 1, NULL);
+
     return DD_OK;
 }
 
diff --git a/render.c b/render.c
index a78ff48..64190d5 100644
--- a/render.c
+++ b/render.c
@@ -87,7 +87,7 @@ DWORD WINAPI render_main(void)
 
     glEnable(GL_TEXTURE_2D);
 
-    while(ddraw->render.run)
+    while(ddraw->render.run && WaitForSingleObject(ddraw->render.sem, INFINITE) == WAIT_OBJECT_0)
     {
         scale_w = (float)ddraw->width/tex_width;
         scale_h = (float)ddraw->height/tex_height;
diff --git a/render_soft.c b/render_soft.c
index 7d919b3..95547ef 100644
--- a/render_soft.c
+++ b/render_soft.c
@@ -50,7 +50,7 @@ DWORD WINAPI render_soft_main(void)
         frame_len = 1000.0f / ddraw->render.maxfps;
     }
 
-    while (ddraw->render.run)
+    while (ddraw->render.run && WaitForSingleObject(ddraw->render.sem, INFINITE) == WAIT_OBJECT_0)
     {
         if(ddraw->render.maxfps > 0)
         {
diff --git a/surface.c b/surface.c
index 75192ab..ec4576a 100644
--- a/surface.c
+++ b/surface.c
@@ -93,12 +93,6 @@ HRESULT __stdcall ddraw_surface_Blt(IDirectDrawSurfaceImpl *This, LPRECT lpDestR
     }
 #endif
 
-    if(This->caps & DDSCAPS_PRIMARYSURFACE && ddraw->render.run)
-    {
-        WaitForSingleObject(ddraw->render.ev, INFINITE);
-        ResetEvent(ddraw->render.ev);
-    }
-
     if(Source)
     {
         int dx=0,dy=0; 
@@ -126,6 +120,13 @@ HRESULT __stdcall ddraw_surface_Blt(IDirectDrawSurfaceImpl *This, LPRECT lpDestR
         } 
     }
 
+    if(This->caps & DDSCAPS_PRIMARYSURFACE && ddraw->render.run)
+    {
+        ReleaseSemaphore(ddraw->render.sem, 1, NULL);
+        WaitForSingleObject(ddraw->render.ev, INFINITE);
+        ResetEvent(ddraw->render.ev);
+    }
+
     return DD_OK;
 }
 
@@ -334,6 +335,11 @@ HRESULT __stdcall ddraw_surface_Unlock(IDirectDrawSurfaceImpl *This, LPVOID lpRe
     printf("DirectDrawSurface::Unlock(This=%p, lpRect=%p)\n", This, lpRect);
 #endif
 
+    if(This->caps & DDSCAPS_PRIMARYSURFACE && ddraw->render.run)
+    {
+        ReleaseSemaphore(ddraw->render.sem, 1, NULL);
+    }
+
     return DD_OK;
 }