From a0aa09912cb8f35ae06834b08308a128886f207f Mon Sep 17 00:00:00 2001
From: riperiperi <rhy3756547@hotmail.com>
Date: Fri, 2 Apr 2021 23:05:55 +0100
Subject: [PATCH] Use event to wake the main thread on task completion

---
 Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs       | 12 +++++++++---
 Ryujinx.Graphics.Gpu/Shader/ShaderCompileTask.cs | 13 +++++++++++++
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index 35908cb918..5ee41cdfbf 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -110,6 +110,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
                 int programIndex = 0;
                 List<ShaderCompileTask> activeTasks = new List<ShaderCompileTask>();
 
+                AutoResetEvent taskDoneEvent = new AutoResetEvent(false);
+
                 // This thread dispatches tasks to do shader translation, and creates programs that OpenGL will link in the background.
                 // The program link status is checked in a non-blocking manner so that multiple shaders can be compiled at once.
                 
@@ -158,7 +160,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
                                 hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
                             }
 
-                            ShaderCompileTask task = new ShaderCompileTask();
+                            ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
                             activeTasks.Add(task);
 
                             task.OnCompiled(hostProgram, (bool isHostProgramValid, ShaderCompileTask task) =>
@@ -261,7 +263,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
                                 hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
                             }
 
-                            ShaderCompileTask task = new ShaderCompileTask();
+                            ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
                             activeTasks.Add(task);
 
                             GuestShaderCacheEntry[] entries = cachedShaderEntries.ToArray();
@@ -412,7 +414,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
 
                     if (activeTasks.Count == maxTaskCount)
                     {
-                        Thread.Sleep(1);
+                        // Wait for a task to be done, or for 1ms.
+                        // Host shader compilation cannot signal when it is done, 
+                        // so the 1ms timeout is required to poll status.
+
+                        taskDoneEvent.WaitOne(1);
                     }
                 }
 
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCompileTask.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCompileTask.cs
index cc1b322ba6..ff48fab001 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCompileTask.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCompileTask.cs
@@ -1,5 +1,6 @@
 using Ryujinx.Graphics.GAL;
 using System;
+using System.Threading;
 using System.Threading.Tasks;
 
 namespace Ryujinx.Graphics.Gpu.Shader
@@ -17,6 +18,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
         private IProgram _program;
 
         private ShaderCompileTaskCallback _action;
+        private AutoResetEvent _taskDoneEvent;
+
+        /// <summary>
+        /// Create a new shader compile task, with an event to signal whenever a subtask completes.
+        /// </summary>
+        /// <param name="taskDoneEvent">Event to signal when a subtask completes</param>
+        public ShaderCompileTask(AutoResetEvent taskDoneEvent)
+        {
+            _taskDoneEvent = taskDoneEvent;
+        }
 
         /// <summary>
         /// Check the completion status of the shader compile task, and run callbacks on step completion.
@@ -58,6 +69,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
 
             _programsTask = task;
             _action = action;
+
+            task.ContinueWith(task => _taskDoneEvent.Set());
         }
 
         /// <summary>