diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuFifo.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuFifo.cs index 0bc682a70f..7ced9e9ecc 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuFifo.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuFifo.cs @@ -1,5 +1,6 @@ using Ryujinx.HLE.Gpu.Memory; using System.Collections.Concurrent; +using System.Threading; namespace Ryujinx.HLE.Gpu.Engines { @@ -18,6 +19,8 @@ namespace Ryujinx.HLE.Gpu.Engines private NvGpuEngine[] SubChannels; + public ManualResetEvent Event { get; private set; } + private struct CachedMacro { public int Position { get; private set; } @@ -60,6 +63,8 @@ namespace Ryujinx.HLE.Gpu.Engines Macros = new CachedMacro[MacrosCount]; Mme = new int[MmeWords]; + + Event = new ManualResetEvent(false); } public void PushBuffer(NvGpuVmm Vmm, NvGpuPBEntry[] Buffer) @@ -68,6 +73,8 @@ namespace Ryujinx.HLE.Gpu.Engines { BufferQueue.Enqueue((Vmm, PBEntry)); } + + Event.Set(); } public void DispatchCalls() diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index f7b263cd0f..43e94d533a 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -71,9 +71,16 @@ namespace Ryujinx.HLE Os.LoadProgram(FileName); } + public bool WaitFifo() + { + return Gpu.Fifo.Event.WaitOne(1); + } + public void ProcessFrame() { Gpu.Fifo.DispatchCalls(); + + Gpu.Fifo.Event.Reset(); } internal virtual void OnFinish(EventArgs e) diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index 7a4e42e9e2..0e36f01646 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -5,6 +5,9 @@ using Ryujinx.Graphics.Gal; using Ryujinx.HLE; using Ryujinx.HLE.Input; using System; +using System.Threading; + +using Stopwatch = System.Diagnostics.Stopwatch; namespace Ryujinx { @@ -16,6 +19,8 @@ namespace Ryujinx private const float TouchScreenRatioX = (float)TouchScreenWidth / TouchScreenHeight; private const float TouchScreenRatioY = (float)TouchScreenHeight / TouchScreenWidth; + private const int TargetFPS = 60; + private Switch Ns; private IGalRenderer Renderer; @@ -24,6 +29,8 @@ namespace Ryujinx private MouseState? Mouse = null; + private Thread RenderThread; + public GLScreen(Switch Ns, IGalRenderer Renderer) : base(1280, 720, new GraphicsMode(), "Ryujinx", 0, @@ -38,11 +45,66 @@ namespace Ryujinx (DisplayDevice.Default.Height / 2) - (Height / 2)); } - protected override void OnLoad(EventArgs e) + private void RenderLoop() { - VSync = VSyncMode.On; + MakeCurrent(); + + Stopwatch Chrono = new Stopwatch(); + + Chrono.Start(); + + long TicksPerFrame = Stopwatch.Frequency / TargetFPS; + + long Ticks = 0; + + while (!IsExiting) + { + //Sleeping until Fifo event improves performance, but it deadlocks most games + //should not be uncommented until it's found why it happens + //if (Ns.WaitFifo()) + { + Ns.ProcessFrame(); + + Renderer.RunActions(); + } + + Ticks += Chrono.ElapsedTicks; + + Chrono.Restart(); + + if (Ticks >= TicksPerFrame) + { + RenderFrame(); + + Ticks -= TicksPerFrame; + } + } + } + + public void MainLoop() + { + VSync = VSyncMode.Off; + + Visible = true; Renderer.FrameBuffer.SetWindowSize(Width, Height); + + Context.MakeCurrent(null); + + //OpenTK doesn't like sleeps in its thread, to avoid these a renderer thread is created + RenderThread = new Thread(RenderLoop); + + RenderThread.Start(); + + while (Exists && !IsExiting) + { + ProcessEvents(); + + if (!IsExiting) + { + UpdateFrame(); + } + } } private bool IsGamePadButtonPressedFromString(GamePadState GamePad, string Button) @@ -99,7 +161,7 @@ namespace Ryujinx } } - protected override void OnUpdateFrame(FrameEventArgs e) + private new void UpdateFrame() { HidControllerButtons CurrentButton = 0; HidJoystickPosition LeftJoystick; @@ -278,13 +340,9 @@ namespace Ryujinx CurrentButton, LeftJoystick, RightJoystick); - - Ns.ProcessFrame(); - - Renderer.RunActions(); } - protected override void OnRenderFrame(FrameEventArgs e) + private new void RenderFrame() { Renderer.FrameBuffer.Render(); @@ -300,6 +358,13 @@ namespace Ryujinx Ns.Os.SignalVsync(); } + protected override void OnUnload(EventArgs e) + { + RenderThread.Join(); + + base.OnUnload(e); + } + protected override void OnResize(EventArgs e) { Renderer.FrameBuffer.SetWindowSize(Width, Height); diff --git a/Ryujinx/Ui/Program.cs b/Ryujinx/Ui/Program.cs index b14897695d..5cacc6228b 100644 --- a/Ryujinx/Ui/Program.cs +++ b/Ryujinx/Ui/Program.cs @@ -67,7 +67,7 @@ namespace Ryujinx Screen.Exit(); }; - Screen.Run(0.0, 60.0); + Screen.MainLoop(); } Environment.Exit(0);