2021-04-07 12:19:02 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
private delegate int NvAPI_DRS_CreateSessionDelegate(out IntPtr handle);
|
2021-04-07 12:19:02 +00:00
|
|
|
|
private static NvAPI_DRS_CreateSessionDelegate NvAPI_DRS_CreateSession;
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
private delegate int NvAPI_DRS_LoadSettingsDelegate(IntPtr handle);
|
2021-04-07 12:19:02 +00:00
|
|
|
|
private static NvAPI_DRS_LoadSettingsDelegate NvAPI_DRS_LoadSettings;
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
private delegate int NvAPI_DRS_FindProfileByNameDelegate(IntPtr handle, NvapiUnicodeString profileName, out IntPtr profileHandle);
|
2021-04-07 12:19:02 +00:00
|
|
|
|
private static NvAPI_DRS_FindProfileByNameDelegate NvAPI_DRS_FindProfileByName;
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
private delegate int NvAPI_DRS_CreateProfileDelegate(IntPtr handle, ref NvdrsProfile profileInfo, out IntPtr profileHandle);
|
2021-04-07 12:19:02 +00:00
|
|
|
|
private static NvAPI_DRS_CreateProfileDelegate NvAPI_DRS_CreateProfile;
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
private delegate int NvAPI_DRS_CreateApplicationDelegate(IntPtr handle, IntPtr profileHandle, ref NvdrsApplicationV4 app);
|
2021-04-07 12:19:02 +00:00
|
|
|
|
private static NvAPI_DRS_CreateApplicationDelegate NvAPI_DRS_CreateApplication;
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
private delegate int NvAPI_DRS_SetSettingDelegate(IntPtr handle, IntPtr profileHandle, ref NvdrsSetting setting);
|
2021-04-07 12:19:02 +00:00
|
|
|
|
private static NvAPI_DRS_SetSettingDelegate NvAPI_DRS_SetSetting;
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
private delegate int NvAPI_DRS_SaveSettingsDelegate(IntPtr handle);
|
2021-04-07 12:19:02 +00:00
|
|
|
|
private static NvAPI_DRS_SaveSettingsDelegate NvAPI_DRS_SaveSettings;
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
private delegate int NvAPI_DRS_DestroySessionDelegate(IntPtr handle);
|
2021-04-07 12:19:02 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
public static void SetThreadedOptimization(bool enabled)
|
2021-04-07 12:19:02 +00:00
|
|
|
|
{
|
|
|
|
|
Initialize();
|
|
|
|
|
|
|
|
|
|
uint targetValue = (uint)(enabled ? Nvapi.OglThreadControlEnable : Nvapi.OglThreadControlDisable);
|
|
|
|
|
|
|
|
|
|
Check(NvAPI_Initialize());
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
Check(NvAPI_DRS_CreateSession(out IntPtr handle));
|
2021-04-07 12:19:02 +00:00
|
|
|
|
|
|
|
|
|
Check(NvAPI_DRS_LoadSettings(handle));
|
|
|
|
|
|
2021-04-07 17:15:17 +00:00
|
|
|
|
IntPtr profileHandle;
|
2021-04-07 12:19:02 +00:00
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|