diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuFifo.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuFifo.cs
index 0bc682a70f..7b999eaed1 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 AutoResetEvent 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 AutoResetEvent(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..1946b187ba 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -71,6 +71,11 @@ namespace Ryujinx.HLE
             Os.LoadProgram(FileName);
         }
 
+        public bool WaitFifo()
+        {
+            return Gpu.Fifo.Event.WaitOne(8);
+        }
+
         public void ProcessFrame()
         {
             Gpu.Fifo.DispatchCalls();
diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs
index 7a4e42e9e2..9b5dda4f0c 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,14 @@ namespace Ryujinx
 
         private MouseState? Mouse = null;
 
+        private Thread RenderThread;
+
+        private bool ResizeEvent;
+
+        private bool TitleEvent;
+
+        private string NewTitle;
+
         public GLScreen(Switch Ns, IGalRenderer Renderer)
             : base(1280, 720,
             new GraphicsMode(), "Ryujinx", 0,
@@ -36,13 +49,85 @@ namespace Ryujinx
             Location = new Point(
                 (DisplayDevice.Default.Width  / 2) - (Width  / 2),
                 (DisplayDevice.Default.Height / 2) - (Height / 2));
+
+            ResizeEvent = false;
+
+            TitleEvent = false;
         }
 
-        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 (Exists && !IsExiting)
+            {
+                if (Ns.WaitFifo())
+                {
+                    Ns.ProcessFrame();
+                }
+
+                Renderer.RunActions();
+
+                if (ResizeEvent)
+                {
+                    ResizeEvent = false;
+
+                    Renderer.FrameBuffer.SetWindowSize(Width, Height);
+                }
+
+                Ticks += Chrono.ElapsedTicks;
+
+                Chrono.Restart();
+
+                if (Ticks >= TicksPerFrame)
+                {
+                    RenderFrame();
+
+                    //Queue max. 1 vsync
+                    Ticks = Math.Min(Ticks - TicksPerFrame, 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 this a renderer thread is created
+            RenderThread = new Thread(RenderLoop);
+
+            RenderThread.Start();
+
+            while (Exists && !IsExiting)
+            {
+                ProcessEvents();
+
+                if (!IsExiting)
+                {
+                    UpdateFrame();
+
+                    if (TitleEvent)
+                    {
+                        TitleEvent = false;
+
+                        Title = NewTitle;
+                    }
+                }
+            }
         }
         
         private bool IsGamePadButtonPressedFromString(GamePadState GamePad, string Button)
@@ -99,7 +184,7 @@ namespace Ryujinx
             }
         }
 
-        protected override void OnUpdateFrame(FrameEventArgs e)
+        private new void UpdateFrame()
         {
             HidControllerButtons CurrentButton = 0;
             HidJoystickPosition  LeftJoystick;
@@ -278,13 +363,9 @@ namespace Ryujinx
                 CurrentButton,
                 LeftJoystick,
                 RightJoystick);
-
-            Ns.ProcessFrame();
-
-            Renderer.RunActions();
         }
 
-        protected override void OnRenderFrame(FrameEventArgs e)
+        private new void RenderFrame()
         {
             Renderer.FrameBuffer.Render();
 
@@ -293,16 +374,25 @@ namespace Ryujinx
             double HostFps = Ns.Statistics.GetSystemFrameRate();
             double GameFps = Ns.Statistics.GetGameFrameRate();
 
-            Title = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}";
+            NewTitle = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}";
+
+            TitleEvent = true;
 
             SwapBuffers();
 
             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);
+            ResizeEvent = true;
         }
 
         protected override void OnKeyDown(KeyboardKeyEventArgs e)
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);