Forcibly enable threaded optimization on boot.

This commit is contained in:
riperiperi 2021-04-07 13:19:02 +01:00
parent b1c3e01691
commit 1239c82d2f
8 changed files with 327 additions and 3 deletions

View file

@ -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.
}
}
}
}

View file

@ -0,0 +1,11 @@
namespace Ryujinx.Common.GraphicsDriver.NVAPI
{
enum Nvapi : uint
{
OglThreadControlId = 0x20C1221E,
OglThreadControlDefault = 0,
OglThreadControlEnable = 1,
OglThreadControlDisable = 2
}
}

View file

@ -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);
}
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}
}

View file

@ -1,6 +1,7 @@
using ARMeilleure.Translation.PTC; using ARMeilleure.Translation.PTC;
using Gtk; using Gtk;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.System; using Ryujinx.Common.System;
using Ryujinx.Common.SystemInfo; using Ryujinx.Common.SystemInfo;
@ -136,6 +137,12 @@ namespace Ryujinx
// Logging system information. // Logging system information.
PrintSystemInfo(); PrintSystemInfo();
// Force dedicated GPU if we can.
ForceDedicatedGpu.Nvidia();
// Enable OGL multithreading on the driver, when available.
DriverUtilities.ToggleOGLThreading(true);
// Initialize Gtk. // Initialize Gtk.
Application.Init(); Application.Init();
@ -147,9 +154,6 @@ namespace Ryujinx
UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys); UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys);
} }
// Force dedicated GPU if we can.
ForceDedicatedGpu.Nvidia();
// Show the main window UI. // Show the main window UI.
MainWindow mainWindow = new MainWindow(); MainWindow mainWindow = new MainWindow();
mainWindow.Show(); mainWindow.Show();