aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2021-04-07 13:19:02 +0100
committerriperiperi <rhy3756547@hotmail.com>2021-04-18 17:34:00 +0100
commit1239c82d2f2fa59a42561a4a278a9cdca5eca462 (patch)
tree2885fc1498de539d9c27878ed9788bb6ecf081c5
parentb1c3e01691507709bc4a6a23f02396f3b97803e5 (diff)
Forcibly enable threaded optimization on boot.
-rw-r--r--Ryujinx.Common/GraphicsDriver/DriverUtilities.cs22
-rw-r--r--Ryujinx.Common/GraphicsDriver/NVAPI/Nvapi.cs11
-rw-r--r--Ryujinx.Common/GraphicsDriver/NVAPI/NvapiUnicodeString.cs42
-rw-r--r--Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsApplicationV4.cs17
-rw-r--r--Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsProfile.cs16
-rw-r--r--Ryujinx.Common/GraphicsDriver/NVAPI/NvdrsSetting.cs49
-rw-r--r--Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs163
-rw-r--r--Ryujinx/Program.cs10
8 files changed, 327 insertions, 3 deletions
diff --git a/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs b/Ryujinx.Common/GraphicsDriver/DriverUtilities.cs
new file mode 100644
index 00000000..60c176f8
--- /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 00000000..99eaa68f
--- /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 00000000..bfa039b8
--- /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 00000000..8b472cd1
--- /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 00000000..5a325d08
--- /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 00000000..ac188b35
--- /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 00000000..fee8336c
--- /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 4df82da6..db31a2e5 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();