From c9b6be1ef830ee50c50b95bb4b435cb4b4f4f0f7 Mon Sep 17 00:00:00 2001
From: riperiperi <rhy3756547@hotmail.com>
Date: Wed, 9 Dec 2020 22:36:08 +0000
Subject: [PATCH] NVIDIA Thread create/delete stutter workarounds (#1760)

* Thread create/delete stutter workarounds Pt 1

* As tiered compilation is disabled, disable quick jit too

Should result in tier 1 compilation all the time

* Fix rebase.
---
 Ryujinx/Ryujinx.csproj   |  4 +++-
 Ryujinx/Ui/GLRenderer.cs | 26 ++++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj
index 1734ca6dd8..0bccf57197 100644
--- a/Ryujinx/Ryujinx.csproj
+++ b/Ryujinx/Ryujinx.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <TargetFramework>net5.0</TargetFramework>
@@ -6,6 +6,8 @@
     <OutputType>Exe</OutputType>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <Version>1.0.0-dirty</Version>
+    <TieredCompilation>false</TieredCompilation>
+    <TieredCompilationQuickJit>false</TieredCompilationQuickJit>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/Ryujinx/Ui/GLRenderer.cs b/Ryujinx/Ui/GLRenderer.cs
index c8887544ce..755121c676 100644
--- a/Ryujinx/Ui/GLRenderer.cs
+++ b/Ryujinx/Ui/GLRenderer.cs
@@ -240,13 +240,39 @@ namespace Ryujinx.Ui
             };
             renderLoopThread.Start();
 
+            Thread nvStutterWorkaround = new Thread(NVStutterWorkaround)
+            {
+                Name = "GUI.NVStutterWorkaround"
+            };
+            nvStutterWorkaround.Start();
+
             MainLoop();
 
             renderLoopThread.Join();
+            nvStutterWorkaround.Join();
 
             Exit();
         }
 
+        private void NVStutterWorkaround()
+        {
+            while (_isActive)
+            {
+                // When NVIDIA Threaded Optimization is on, the driver will snapshot all threads in the system whenever the application creates any new ones.
+                // The ThreadPool has something called a "GateThread" which terminates itself after some inactivity.
+                // However, it immediately starts up again, since the rules regarding when to terminate and when to start differ.
+                // This creates a new thread every second or so.
+                // The main problem with this is that the thread snapshot can take 70ms, is on the OpenGL thread and will delay rendering any graphics.
+                // This is a little over budget on a frame time of 16ms, so creates a large stutter.
+                // The solution is to keep the ThreadPool active so that it never has a reason to terminate the GateThread.
+
+                // TODO: This should be removed when the issue with the GateThread is resolved.
+
+                ThreadPool.QueueUserWorkItem((state) => { });
+                Thread.Sleep(300);
+            }
+        }
+
         protected override bool OnButtonPressEvent(EventButton evnt)
         {
             _mouseX = evnt.X;