NVThreadedOptimization.cs
1 using Ryujinx.Common.GraphicsDriver.NVAPI; 2 using System; 3 using System.Runtime.CompilerServices; 4 using System.Runtime.InteropServices; 5 6 namespace Ryujinx.Common.GraphicsDriver 7 { 8 static partial class NVThreadedOptimization 9 { 10 private const string ProfileName = "Ryujinx Nvidia Profile"; 11 12 private const uint NvAPI_Initialize_ID = 0x0150E828; 13 private const uint NvAPI_DRS_CreateSession_ID = 0x0694D52E; 14 private const uint NvAPI_DRS_LoadSettings_ID = 0x375DBD6B; 15 private const uint NvAPI_DRS_FindProfileByName_ID = 0x7E4A9A0B; 16 private const uint NvAPI_DRS_CreateProfile_ID = 0x0CC176068; 17 private const uint NvAPI_DRS_CreateApplication_ID = 0x4347A9DE; 18 private const uint NvAPI_DRS_SetSetting_ID = 0x577DD202; 19 private const uint NvAPI_DRS_SaveSettings_ID = 0xFCBC7E14; 20 private const uint NvAPI_DRS_DestroySession_ID = 0x0DAD9CFF8; 21 22 [LibraryImport("nvapi64")] 23 private static partial IntPtr nvapi_QueryInterface(uint id); 24 25 private delegate int NvAPI_InitializeDelegate(); 26 private static NvAPI_InitializeDelegate NvAPI_Initialize; 27 28 private delegate int NvAPI_DRS_CreateSessionDelegate(out IntPtr handle); 29 private static NvAPI_DRS_CreateSessionDelegate NvAPI_DRS_CreateSession; 30 31 private delegate int NvAPI_DRS_LoadSettingsDelegate(IntPtr handle); 32 private static NvAPI_DRS_LoadSettingsDelegate NvAPI_DRS_LoadSettings; 33 34 private delegate int NvAPI_DRS_FindProfileByNameDelegate(IntPtr handle, NvapiUnicodeString profileName, out IntPtr profileHandle); 35 private static NvAPI_DRS_FindProfileByNameDelegate NvAPI_DRS_FindProfileByName; 36 37 private delegate int NvAPI_DRS_CreateProfileDelegate(IntPtr handle, ref NvdrsProfile profileInfo, out IntPtr profileHandle); 38 private static NvAPI_DRS_CreateProfileDelegate NvAPI_DRS_CreateProfile; 39 40 private delegate int NvAPI_DRS_CreateApplicationDelegate(IntPtr handle, IntPtr profileHandle, ref NvdrsApplicationV4 app); 41 private static NvAPI_DRS_CreateApplicationDelegate NvAPI_DRS_CreateApplication; 42 43 private delegate int NvAPI_DRS_SetSettingDelegate(IntPtr handle, IntPtr profileHandle, ref NvdrsSetting setting); 44 private static NvAPI_DRS_SetSettingDelegate NvAPI_DRS_SetSetting; 45 46 private delegate int NvAPI_DRS_SaveSettingsDelegate(IntPtr handle); 47 private static NvAPI_DRS_SaveSettingsDelegate NvAPI_DRS_SaveSettings; 48 49 private delegate int NvAPI_DRS_DestroySessionDelegate(IntPtr handle); 50 private static NvAPI_DRS_DestroySessionDelegate NvAPI_DRS_DestroySession; 51 52 private static bool _initialized; 53 54 private static void Check(int status) 55 { 56 if (status != 0) 57 { 58 throw new Exception($"NVAPI Error: {status}"); 59 } 60 } 61 62 private static void Initialize() 63 { 64 if (!_initialized) 65 { 66 NvAPI_Initialize = NvAPI_Delegate<NvAPI_InitializeDelegate>(NvAPI_Initialize_ID); 67 68 Check(NvAPI_Initialize()); 69 70 NvAPI_DRS_CreateSession = NvAPI_Delegate<NvAPI_DRS_CreateSessionDelegate>(NvAPI_DRS_CreateSession_ID); 71 NvAPI_DRS_LoadSettings = NvAPI_Delegate<NvAPI_DRS_LoadSettingsDelegate>(NvAPI_DRS_LoadSettings_ID); 72 NvAPI_DRS_FindProfileByName = NvAPI_Delegate<NvAPI_DRS_FindProfileByNameDelegate>(NvAPI_DRS_FindProfileByName_ID); 73 NvAPI_DRS_CreateProfile = NvAPI_Delegate<NvAPI_DRS_CreateProfileDelegate>(NvAPI_DRS_CreateProfile_ID); 74 NvAPI_DRS_CreateApplication = NvAPI_Delegate<NvAPI_DRS_CreateApplicationDelegate>(NvAPI_DRS_CreateApplication_ID); 75 NvAPI_DRS_SetSetting = NvAPI_Delegate<NvAPI_DRS_SetSettingDelegate>(NvAPI_DRS_SetSetting_ID); 76 NvAPI_DRS_SaveSettings = NvAPI_Delegate<NvAPI_DRS_SaveSettingsDelegate>(NvAPI_DRS_SaveSettings_ID); 77 NvAPI_DRS_DestroySession = NvAPI_Delegate<NvAPI_DRS_DestroySessionDelegate>(NvAPI_DRS_DestroySession_ID); 78 79 _initialized = true; 80 } 81 } 82 83 private static uint MakeVersion<T>(uint version) where T : unmanaged 84 { 85 return (uint)Unsafe.SizeOf<T>() | version << 16; 86 } 87 88 public static void SetThreadedOptimization(bool enabled) 89 { 90 Initialize(); 91 92 uint targetValue = (uint)(enabled ? Nvapi.OglThreadControlEnable : Nvapi.OglThreadControlDisable); 93 94 Check(NvAPI_Initialize()); 95 96 Check(NvAPI_DRS_CreateSession(out IntPtr handle)); 97 98 Check(NvAPI_DRS_LoadSettings(handle)); 99 100 // Check if the profile already exists. 101 102 int status = NvAPI_DRS_FindProfileByName(handle, new NvapiUnicodeString(ProfileName), out nint profileHandle); 103 104 if (status != 0) 105 { 106 NvdrsProfile profile = new() 107 { 108 Version = MakeVersion<NvdrsProfile>(1), 109 IsPredefined = 0, 110 GpuSupport = uint.MaxValue, 111 }; 112 profile.ProfileName.Set(ProfileName); 113 Check(NvAPI_DRS_CreateProfile(handle, ref profile, out profileHandle)); 114 115 NvdrsApplicationV4 application = new() 116 { 117 Version = MakeVersion<NvdrsApplicationV4>(4), 118 IsPredefined = 0, 119 Flags = 3, // IsMetro, IsCommandLine 120 }; 121 application.AppName.Set("Ryujinx.exe"); 122 application.UserFriendlyName.Set("Ryujinx"); 123 application.Launcher.Set(""); 124 application.FileInFolder.Set(""); 125 126 Check(NvAPI_DRS_CreateApplication(handle, profileHandle, ref application)); 127 } 128 129 NvdrsSetting setting = new() 130 { 131 Version = MakeVersion<NvdrsSetting>(1), 132 SettingId = Nvapi.OglThreadControlId, 133 SettingType = NvdrsSettingType.NvdrsDwordType, 134 SettingLocation = NvdrsSettingLocation.NvdrsCurrentProfileLocation, 135 IsCurrentPredefined = 0, 136 IsPredefinedValid = 0, 137 CurrentValue = targetValue, 138 PredefinedValue = targetValue, 139 }; 140 141 Check(NvAPI_DRS_SetSetting(handle, profileHandle, ref setting)); 142 143 Check(NvAPI_DRS_SaveSettings(handle)); 144 145 NvAPI_DRS_DestroySession(handle); 146 } 147 148 private static T NvAPI_Delegate<T>(uint id) where T : class 149 { 150 IntPtr ptr = nvapi_QueryInterface(id); 151 152 if (ptr != IntPtr.Zero) 153 { 154 return Marshal.GetDelegateForFunctionPointer<T>(ptr); 155 } 156 157 return null; 158 } 159 } 160 }