diff --git a/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs b/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs
new file mode 100644
index 0000000000..60c176f836
--- /dev/null
+++ b/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Ryujinx.Common.GraphicsDriver
+{
+    public static class DriverUtilities
+    {
+        public static void ToggleOGLThreading(bool enabled)
+        {
+            Environment.SetEnvironmentVariable("mesa_glthread", enabled.ToString());
+            Environment.SetEnvironmentVariable("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
+
+            try
+            {
+                NVThreadedOptimization.SetThreadedOptimization(enabled);
+            }
+            catch
+            {
+                // NVAPI is not available, or couldn't change the application profile.
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Common/GraphicsDriver/NVAPI/Nvapi.cs b/Ryujinx.Common/GraphicsDriver/NVAPI/Nvapi.cs
new file mode 100644
index 0000000000..99eaa68f46
--- /dev/null
+++ b/Ryujinx.Common/GraphicsDriver/NVAPI/Nvapi.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.Common.GraphicsDriver.NVAPI
+{
+    enum Nvapi : uint
+    {
+        OglThreadControlId = 0x20C1221E,
+
+        OglThreadControlDefault = 0,
+        OglThreadControlEnable = 1,
+        OglThreadControlDisable = 2
+    }
+}
diff --git a/Ryujinx.Common/GraphicsDriver/NVAPI/NvapiUnicodeString.cs b/Ryujinx.Common/GraphicsDriver/NVAPI/NvapiUnicodeString.cs
new file mode 100644
index 0000000000..bfa039b892
--- /dev/null
+++ b/Ryujinx.Common/GraphicsDriver/NVAPI/NvapiUnicodeString.cs
@@ -0,0 +1,42 @@
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Ryujinx.Common.GraphicsDriver.NVAPI
+{
+    [StructLayout(LayoutKind.Sequential, Pack = 4)]
+    public unsafe struct NvapiUnicodeString
+    {
+        public fixed byte Data[4096];
+
+        public NvapiUnicodeString(string text)
+        {
+            Set(text);
+        }
+
+        public string Get()
+        {
+            fixed (byte* data = Data)
+            {
+                string text = Encoding.Unicode.GetString(data, 4096);
+
+                int index = text.IndexOf('\0');
+                if (index > -1)
+                {
+                    text = text.Remove(index);
+                }
+
+                return text;
+            }
+        }
+
+        public void Set(string text)
+        {
+            text += '\0';
+            fixed (char* textPtr = text)
+            fixed (byte* data = Data)
+            {
+                int written = Encoding.Unicode.GetBytes(textPtr, text.Length, data, 4096);
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsApplicationV4.cs b/Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsApplicationV4.cs
new file mode 100644
index 0000000000..8b472cd161
--- /dev/null
+++ b/Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsApplicationV4.cs
@@ -0,0 +1,17 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Common.GraphicsDriver.NVAPI
+{
+    [StructLayout(LayoutKind.Sequential, Pack = 4)]
+    unsafe struct NvdrsApplicationV4
+    {
+        public uint Version;
+        public uint IsPredefined;
+        public NvapiUnicodeString AppName;
+        public NvapiUnicodeString UserFriendlyName;
+        public NvapiUnicodeString Launcher;
+        public NvapiUnicodeString FileInFolder;
+        public uint Flags;
+        public NvapiUnicodeString CommandLine;
+    }
+}
diff --git a/Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsProfile.cs b/Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsProfile.cs
new file mode 100644
index 0000000000..5a325d082e
--- /dev/null
+++ b/Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsProfile.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Common.GraphicsDriver.NVAPI
+{
+    [StructLayout(LayoutKind.Sequential, Pack = 1)]
+    unsafe struct NvdrsProfile
+    {
+        public uint Version;
+        public NvapiUnicodeString ProfileName;
+        public uint GpuSupport;
+        public uint IsPredefined;
+        public uint NumOfApps;
+        public uint NumOfSettings;
+    }
+}
diff --git a/Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsSetting.cs b/Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsSetting.cs
new file mode 100644
index 0000000000..ac188b35d2
--- /dev/null
+++ b/Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsSetting.cs
@@ -0,0 +1,49 @@
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Common.GraphicsDriver.NVAPI
+{
+    enum NvdrsSettingType : uint
+    {
+        NvdrsDwordType,
+        NvdrsBinaryType,
+        NvdrsStringType,
+        NvdrsWstringType,
+    }
+
+    enum NvdrsSettingLocation : uint
+    {
+        NvdrsCurrentProfileLocation,
+        NvdrsGlobalProfileLocation,
+        NvdrsBaseProfileLocation,
+        NvdrsDefaultProfileLocation,
+    }
+
+    [StructLayout(LayoutKind.Explicit, Size = 0x3020)]
+    unsafe struct NvdrsSetting
+    {
+        [FieldOffset(0x0)]
+        public uint Version;
+        [FieldOffset(0x4)]
+        public NvapiUnicodeString SettingName;
+        [FieldOffset(0x1004)]
+        public Nvapi SettingId;
+        [FieldOffset(0x1008)]
+        public NvdrsSettingType SettingType;
+        [FieldOffset(0x100C)]
+        public NvdrsSettingLocation SettingLocation;
+        [FieldOffset(0x1010)]
+        public uint IsCurrentPredefined;
+        [FieldOffset(0x1014)]
+        public uint IsPredefinedValid;
+
+        [FieldOffset(0x1018)]
+        public uint PredefinedValue;
+        [FieldOffset(0x1018)]
+        public NvapiUnicodeString PredefinedString;
+
+        [FieldOffset(0x201C)]
+        public uint CurrentValue;
+        [FieldOffset(0x201C)]
+        public NvapiUnicodeString CurrentString;
+    }
+}
diff --git a/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs b/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs
new file mode 100644
index 0000000000..fee8336c64
--- /dev/null
+++ b/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs
@@ -0,0 +1,163 @@
+using Ryujinx.Common.GraphicsDriver.NVAPI;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Common.GraphicsDriver
+{
+    static class NVThreadedOptimization
+    {
+        private const string ProfileName = "Ryujinx Nvidia Profile";
+
+        private const uint NvAPI_Initialize_ID = 0x0150E828;
+        private const uint NvAPI_DRS_CreateSession_ID = 0x0694D52E;
+        private const uint NvAPI_DRS_LoadSettings_ID = 0x375DBD6B;
+        private const uint NvAPI_DRS_FindProfileByName_ID = 0x7E4A9A0B;
+        private const uint NvAPI_DRS_CreateProfile_ID = 0x0CC176068;
+        private const uint NvAPI_DRS_CreateApplication_ID = 0x4347A9DE;
+        private const uint NvAPI_DRS_SetSetting_ID = 0x577DD202;
+        private const uint NvAPI_DRS_SaveSettings_ID = 0xFCBC7E14;
+        private const uint NvAPI_DRS_DestroySession_ID = 0x0DAD9CFF8;
+
+        [DllImport("nvapi64")]
+        private static extern IntPtr nvapi_QueryInterface(uint id);
+
+        private delegate int NvAPI_InitializeDelegate();
+        private static NvAPI_InitializeDelegate NvAPI_Initialize;
+
+        private delegate int NvAPI_DRS_CreateSessionDelegate(out long handle);
+        private static NvAPI_DRS_CreateSessionDelegate NvAPI_DRS_CreateSession;
+
+        private delegate int NvAPI_DRS_LoadSettingsDelegate(long handle);
+        private static NvAPI_DRS_LoadSettingsDelegate NvAPI_DRS_LoadSettings;
+
+        private delegate int NvAPI_DRS_FindProfileByNameDelegate(long handle, NvapiUnicodeString profileName, out long profileHandle);
+        private static NvAPI_DRS_FindProfileByNameDelegate NvAPI_DRS_FindProfileByName;
+
+        private delegate int NvAPI_DRS_CreateProfileDelegate(long handle, ref NvdrsProfile profileInfo, out long profileHandle);
+        private static NvAPI_DRS_CreateProfileDelegate NvAPI_DRS_CreateProfile;
+
+        private delegate int NvAPI_DRS_CreateApplicationDelegate(long handle, long profileHandle, ref NvdrsApplicationV4 app);
+        private static NvAPI_DRS_CreateApplicationDelegate NvAPI_DRS_CreateApplication;
+
+        private delegate int NvAPI_DRS_SetSettingDelegate(long handle, long profileHandle, ref NvdrsSetting setting);
+        private static NvAPI_DRS_SetSettingDelegate NvAPI_DRS_SetSetting;
+
+        private delegate int NvAPI_DRS_SaveSettingsDelegate(long handle);
+        private static NvAPI_DRS_SaveSettingsDelegate NvAPI_DRS_SaveSettings;
+
+        private delegate int NvAPI_DRS_DestroySessionDelegate(long handle);
+        private static NvAPI_DRS_DestroySessionDelegate NvAPI_DRS_DestroySession;
+
+        private static bool _initialized;
+
+        private static void Check(int status)
+        {
+            if (status != 0)
+            {
+                throw new Exception($"NVAPI Error: {status}");
+            }
+        }
+
+        private static void Initialize()
+        {
+            if (!_initialized)
+            {
+                NvAPI_Initialize = NvAPI_Delegate<NvAPI_InitializeDelegate>(NvAPI_Initialize_ID);
+
+                Check(NvAPI_Initialize());
+
+                NvAPI_DRS_CreateSession = NvAPI_Delegate<NvAPI_DRS_CreateSessionDelegate>(NvAPI_DRS_CreateSession_ID);
+                NvAPI_DRS_LoadSettings = NvAPI_Delegate<NvAPI_DRS_LoadSettingsDelegate>(NvAPI_DRS_LoadSettings_ID);
+                NvAPI_DRS_FindProfileByName = NvAPI_Delegate<NvAPI_DRS_FindProfileByNameDelegate>(NvAPI_DRS_FindProfileByName_ID);
+                NvAPI_DRS_CreateProfile = NvAPI_Delegate<NvAPI_DRS_CreateProfileDelegate>(NvAPI_DRS_CreateProfile_ID);
+                NvAPI_DRS_CreateApplication = NvAPI_Delegate<NvAPI_DRS_CreateApplicationDelegate>(NvAPI_DRS_CreateApplication_ID);
+                NvAPI_DRS_SetSetting = NvAPI_Delegate<NvAPI_DRS_SetSettingDelegate>(NvAPI_DRS_SetSetting_ID);
+                NvAPI_DRS_SaveSettings = NvAPI_Delegate<NvAPI_DRS_SaveSettingsDelegate>(NvAPI_DRS_SaveSettings_ID);
+                NvAPI_DRS_DestroySession = NvAPI_Delegate<NvAPI_DRS_DestroySessionDelegate>(NvAPI_DRS_DestroySession_ID);
+
+                _initialized = true;
+            }
+        }
+
+        private static uint MakeVersion<T>(uint version) where T : unmanaged
+        {
+            return (uint)Unsafe.SizeOf<T>() | version << 16;
+        }
+
+        public static unsafe void SetThreadedOptimization(bool enabled)
+        {
+            Initialize();
+
+            uint targetValue = (uint)(enabled ? Nvapi.OglThreadControlEnable : Nvapi.OglThreadControlDisable);
+
+            Check(NvAPI_Initialize());
+
+            Check(NvAPI_DRS_CreateSession(out long handle));
+
+            Check(NvAPI_DRS_LoadSettings(handle));
+
+            long profileHandle;
+
+            // Check if the profile already exists.
+
+            int status = NvAPI_DRS_FindProfileByName(handle, new NvapiUnicodeString(ProfileName), out profileHandle);
+
+            if (status != 0)
+            {
+                NvdrsProfile profile = new NvdrsProfile { 
+                    Version = MakeVersion<NvdrsProfile>(1), 
+                    IsPredefined = 0, 
+                    GpuSupport = uint.MaxValue 
+                };
+                profile.ProfileName.Set(ProfileName);
+                Check(NvAPI_DRS_CreateProfile(handle, ref profile, out profileHandle));
+
+                NvdrsApplicationV4 application = new NvdrsApplicationV4
+                {
+                    Version = MakeVersion<NvdrsApplicationV4>(4),
+                    IsPredefined = 0,
+                    Flags = 3 // IsMetro, IsCommandLine
+                };
+                application.AppName.Set("Ryujinx.exe");
+                application.UserFriendlyName.Set("Ryujinx");
+                application.Launcher.Set("");
+                application.FileInFolder.Set("");
+
+                Check(NvAPI_DRS_CreateApplication(handle, profileHandle, ref application));
+            }
+
+            NvdrsSetting setting = new NvdrsSetting
+            {
+                Version = MakeVersion<NvdrsSetting>(1),
+                SettingId = Nvapi.OglThreadControlId,
+                SettingType = NvdrsSettingType.NvdrsDwordType,
+                SettingLocation = NvdrsSettingLocation.NvdrsCurrentProfileLocation,
+                IsCurrentPredefined = 0,
+                IsPredefinedValid = 0,
+                CurrentValue = targetValue,
+                PredefinedValue = targetValue
+            };
+
+            Check(NvAPI_DRS_SetSetting(handle, profileHandle, ref setting));
+
+            Check(NvAPI_DRS_SaveSettings(handle));
+
+            NvAPI_DRS_DestroySession(handle);
+        }
+
+        private static T NvAPI_Delegate<T>(uint id) where T : class
+        {
+            IntPtr ptr = nvapi_QueryInterface(id);
+
+            if (ptr != IntPtr.Zero)
+            {
+                return Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T;
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }
+}
diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs
index 4df82da66a..db31a2e563 100644
--- a/Ryujinx/Program.cs
+++ b/Ryujinx/Program.cs
@@ -1,6 +1,7 @@
 using ARMeilleure.Translation.PTC;
 using Gtk;
 using Ryujinx.Common.Configuration;
+using Ryujinx.Common.GraphicsDriver;
 using Ryujinx.Common.Logging;
 using Ryujinx.Common.System;
 using Ryujinx.Common.SystemInfo;
@@ -136,6 +137,12 @@ namespace Ryujinx
             // Logging system information.
             PrintSystemInfo();
 
+            // Force dedicated GPU if we can.
+            ForceDedicatedGpu.Nvidia();
+
+            // Enable OGL multithreading on the driver, when available.
+            DriverUtilities.ToggleOGLThreading(true);
+
             // Initialize Gtk.
             Application.Init();
 
@@ -147,9 +154,6 @@ namespace Ryujinx
                 UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys);
             }
 
-            // Force dedicated GPU if we can.
-            ForceDedicatedGpu.Nvidia();
-
             // Show the main window UI.
             MainWindow mainWindow = new MainWindow();
             mainWindow.Show();