diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj index 1734ca6dd..0bccf5719 100644 --- a/Ryujinx/Ryujinx.csproj +++ b/Ryujinx/Ryujinx.csproj @@ -1,4 +1,4 @@ - + net5.0 @@ -6,6 +6,8 @@ Exe true 1.0.0-dirty + false + false diff --git a/Ryujinx/Ui/GLRenderer.cs b/Ryujinx/Ui/GLRenderer.cs index c8887544c..755121c67 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;