diff --git a/ColorControl.UI/Components/Pages/AMD/AmdPresetPage.razor b/ColorControl.UI/Components/Pages/AMD/AmdPresetPage.razor index 53dde96..770c4dd 100644 --- a/ColorControl.UI/Components/Pages/AMD/AmdPresetPage.razor +++ b/ColorControl.UI/Components/Pages/AMD/AmdPresetPage.razor @@ -93,7 +93,7 @@ { } - @@ -157,7 +157,7 @@ -
+
@@ -356,7 +356,7 @@ if (Preset.IsDisplayPreset) { - //Preset.UpdateAutoApplySettings(PresetParam); + Preset.UpdateAutoApplySettings(PresetParam); await ApplyDisplayPreset(); return; diff --git a/ColorControl.UI/Components/Pages/AMD/AmdSummary.razor b/ColorControl.UI/Components/Pages/AMD/AmdSummary.razor index f949df8..27234e5 100644 --- a/ColorControl.UI/Components/Pages/AMD/AmdSummary.razor +++ b/ColorControl.UI/Components/Pages/AMD/AmdSummary.razor @@ -38,31 +38,35 @@ else {
-
- @if (!DisplayPresets.Any()) - { - No displays found - } - @foreach (var preset in DisplayPresets) - { -
-
- @preset.displayName - @if (preset.DisplayConfig.IsPrimary == true) - { - Primary - } - + @if (!DisplayPresets.Any()) + { + No displays found + } + @foreach (var preset in DisplayPresets) + { +
+
+
+ + @preset.displayName + @if (preset.DisplayConfig.IsPrimary == true) + { + Primary + } + +
+ +
@preset.DisplayConfig.Resolution.ToString() @@ @preset.DisplayConfig.RefreshRate.ToString()Hz @preset.colorDepth, @preset.pixelFormat
- } -
+
+ }
} @@ -157,6 +161,7 @@ else private async Task PresetOnCloneClick(AmdPreset preset) { CurrentPreset = new AmdPreset(preset); + CurrentPreset.name = preset.name; CurrentPreset.SetCloneValues(); } diff --git a/ColorControl.UI/Components/Pages/Generic/StepsInput.razor b/ColorControl.UI/Components/Pages/Generic/StepsInput.razor index 1cbe04e..49d4d4c 100644 --- a/ColorControl.UI/Components/Pages/Generic/StepsInput.razor +++ b/ColorControl.UI/Components/Pages/Generic/StepsInput.razor @@ -27,7 +27,7 @@
- + @foreach (var preset in SamsungPresets) { @@ -53,7 +53,7 @@
- + @foreach (var item in customItem.Items) { @@ -84,7 +84,7 @@
- - - - +
Elevation is needed in some cases where ColorControl needs administrator rights. @@ -186,12 +186,10 @@ else @code { private Config? config; - private string elevationMethod = "0"; protected override async Task OnInitializedAsync() { config = await _rpcClientService.CallAsync("OptionsService", "GetConfig"); - elevationMethod = ((int)config.ElevationMethod).ToString(); } private async Task SaveConfig() @@ -299,8 +297,6 @@ else { var value = e.Value != null ? (ElevationMethod)int.Parse((string)e.Value) : ElevationMethod.None; await _rpcClientService.CallAsync("OptionsService", "SetElevationMethod", value); - - config!.ElevationMethod = value; } private async Task UiTypeOnInput(ChangeEventArgs e) diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj index e9e6611..6204318 100644 --- a/ColorControl/ColorControl.csproj +++ b/ColorControl/ColorControl.csproj @@ -18,8 +18,8 @@ Maassoft Maassoft 0 - 10.0.0.0 - 10.0.0.0 + 10.0.0.1 + 10.0.0.1 false true false diff --git a/ColorControl/MainWorker.cs b/ColorControl/MainWorker.cs index b1118ff..bdc653e 100644 --- a/ColorControl/MainWorker.cs +++ b/ColorControl/MainWorker.cs @@ -107,6 +107,11 @@ internal class MainWorker _keyboardShortcutDispatcher.RegisterShortcut(SHORTCUTID_SCREENSAVER, _config.ScreenSaverShortcut); _keyboardShortcutDispatcher.RegisterEventHandler(KeyboardShortcutDispatcher.Event_HotKey, HandleHotKeyEvent); + + if (_config.UiType != UiType.WinForms) + { + await Program.StartUiServer(); + } } private bool _startupSent = false; diff --git a/ColorControl/Program.cs b/ColorControl/Program.cs index fe130f7..56ce1fe 100644 --- a/ColorControl/Program.cs +++ b/ColorControl/Program.cs @@ -29,430 +29,436 @@ using System.Windows.Forms; namespace ColorControl { - static class Program - { - public const string TS_TASKNAME = "ColorControl"; - public static string DataDir { get; private set; } - public static string ConfigFilename { get; private set; } - public static string LogFilename { get; private set; } - public static Config Config { get; private set; } - public static GlobalContext AppContext { get; private set; } - - public static bool IsRestarting { get; private set; } - public static bool UserExit = false; - - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private static Mutex _mutex; - public static MainForm _mainForm; - private static LoggingRule _loggingRule; - - /// - /// The main entry point for the application. - /// - [STAThread] // autogenerated - public static void Main(string[] args) - { - // STA - MainAsync(args).GetAwaiter().GetResult(); - } - - static async Task MainAsync(string[] args) - { - DataDir = Utils.GetDataPath(); - - var runAsService = args.Contains("--service") || WinApiService.IsAdministratorStatic() && Process.GetCurrentProcess().Parent()?.ProcessName?.Equals("services", StringComparison.InvariantCultureIgnoreCase) == true; - var runElevated = args.Contains("--elevated"); - - InitLogger(runAsService, runElevated); - - Logger.Debug($"Using data path: {DataDir}"); - //Logger.Debug("Parent process: " + Process.GetCurrentProcess().Parent()?.ProcessName); - - if (runAsService) - { - await RunService(args); - return; - } - - await RunApp(args); - } - - static async Task RunApp(string[] args) - { - var startTime = DateTime.Now; - var currentDomain = AppDomain.CurrentDomain; - // Handler for unhandled exceptions. - currentDomain.UnhandledException += GlobalUnhandledExceptionHandler; - // Handler for exceptions in threads behind forms. - Application.ThreadException += GlobalThreadExceptionHandler; - - LoadConfig(); - - if (Config.UseGdiScaling) - { - var result = Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled); - - Logger.Debug($"Result of setting SetHighDpiMode: {result}"); - } - - var mutexId = $"Global\\{typeof(MainForm).GUID}"; - - var startUpParams = StartUpParams.Parse(args); - - AppContext = new GlobalContext(Config, startUpParams, DataDir, _loggingRule, null, startTime, mutexId); - - var host = CreateHostBuilder().Build(); - ServiceProvider = host.Services; - AppContext.ServiceProvider = ServiceProvider; - - MessageForms.Title = AppContext.ApplicationTitle; - - var existingProcess = Utils.GetProcessByName("ColorControl"); - - try - { - if (await CommandLineHandler.HandleStartupParams(startUpParams, existingProcess)) - { - return; - } - } - finally - { - Utils.CloseConsole(); - } - - _mutex = new Mutex(true, AppContext.MutexId, out var mutexCreated); - try - { - if (!mutexCreated) - { - if (existingProcess != null && existingProcess.Threads.Count > 0) - { - var thread = existingProcess.Threads[0]; - NativeMethods.EnumThreadWindows((uint)thread.Id, EnumThreadWindows, IntPtr.Zero); - - return; - } - - MessageBox.Show("Only one instance of this program can be active.", "ColorControl"); - } - else - { - _mutex.WaitOne(); - try - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - - if (Debugger.IsAttached) - { - //Utils.StartService(); - var winApiService = ServiceProvider.GetRequiredService(); - - if (winApiService.IsAdministrator()) - { - var backgroundService = ServiceProvider.GetRequiredService(); - backgroundService.PipeName = PipeUtils.ElevatedPipe; - - Task.Run(async () => await backgroundService.StartAsync(CancellationToken.None)); - } - } - - var worker = ServiceProvider.GetRequiredService(); - - await worker.DoWork(); - - if (Debugger.IsAttached && !IsRestarting) - { - var winApiAdminService = ServiceProvider.GetRequiredService(); - winApiAdminService.StopService(); - } - } - catch (Exception ex) - { - MessageBox.Show("Error while initializing application: " + ex.ToLogString(Environment.StackTrace), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - } - finally - { - if (mutexCreated) - { - _mutex?.Close(); - } - } - } - - public static void OpenDefaultUi() - { - var _ = Config.UiType switch - { - UiType.WebDefaultBrowser => OpenNewUi(), - UiType.WebEmbedded => OpenNewUiEmbedded(), - _ => OpenMainForm() - }; - } - - public static async Task OpenMainForm() - { - _mainForm ??= ServiceProvider.GetRequiredService(); - _mainForm.OpenForm(); - } - - public static void Exit() - { - UserExit = true; - _mainForm?.Close(); - - if (AppContext.MainHandle != 0) - { - NativeMethods.SendMessageW(AppContext.MainHandle, NativeConstants.WM_CLOSE, 0, 0); - } - } - - public static void Restart() - { - IsRestarting = true; - - _mainForm?.CloseForRestart(); - - _mutex?.Close(); - _mutex = null; - - Application.Restart(); - Environment.Exit(0); - } - - public static async Task OpenNewUi() - { - await StartUiServer(); - - var winApi = AppContext.ServiceProvider.GetRequiredService(); - - winApi.StartProcess(GetNewUiUrl()); - } - - public static string GetNewUiUrl() - { - return $"http://localhost:{(Config.UiPort > 0 ? Config.UiPort : 5000)}"; - } - - public static async Task OpenNewUiEmbedded() - { - await StartUiServer(); - - BrowserWindow.CreateAndShow(GetNewUiUrl()); - } - - private static bool UiServerStarted; - - private static async Task StartUiServer() - { - if (UiServerStarted) - { - return; - } - - var backgroundService = ServiceProvider.GetRequiredService(); - - backgroundService.PipeName = PipeUtils.MainPipe; - - await backgroundService.StartAsync(CancellationToken.None); - - var _ = Task.Run(() => ColorControl.UI.Blazor.Start(Config)); - UiServerStarted = true; - - await Task.Delay(500); - } - - private static void InitLogger(bool runAsService, bool runElevated) - { - var config = new LoggingConfiguration(); - - // Targets where to log to: File and Console - var logFileAppendix = runAsService ? "_svc" : runElevated ? "_elevated" : ""; - - LogFilename = Path.Combine(DataDir, $"LogFile{logFileAppendix}.txt"); - - var logfile = new NLog.Targets.FileTarget("logfile") { FileName = LogFilename }; - - _loggingRule = new LoggingRule("*", LogLevel.Trace, LogLevel.Fatal, logfile); - _loggingRule.RuleName = "ColorControl"; - - // Rules for mapping loggers to targets - config.AddRule(_loggingRule); - - // Apply config - LogManager.Configuration = config; - } - - private static void LoadConfig() - { - ConfigFilename = Path.Combine(DataDir, "Settings.json"); - - try - { - if (File.Exists(ConfigFilename)) - { - var data = File.ReadAllText(ConfigFilename); - Config = JsonConvert.DeserializeObject(data); - } - } - catch (Exception ex) - { - Logger.Error($"LoadConfig: {ex.Message}"); - } - Config ??= new Config(); - - var minLogLevel = LogLevel.FromString(Config.LogLevel); - - if (minLogLevel != LogLevel.Trace) - { - _loggingRule.SetLoggingLevels(minLogLevel, LogLevel.Fatal); - LogManager.ReconfigExistingLoggers(); - } - } - - public static IServiceProvider ServiceProvider { get; private set; } - private static IHostBuilder CreateHostBuilder() - { - return Host.CreateDefaultBuilder() - .ConfigureServices((context, services) => - { - //services.AddSingleton(); - services.RegisterSharedServices(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddTransient(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - }); - } - private static async Task RunService(string[] args) - { - var startTime = DateTime.Now; - - Logger.Debug("RUNNING SERVICE"); - - AppContext = new GlobalContext(null, new StartUpParams(), DataDir, _loggingRule, null, startTime); - - using IHost host = Host.CreateDefaultBuilder(args) - .UseWindowsService(options => - { - options.ServiceName = "ColorControl Service"; - }) - .ConfigureServices(services => - { - services.RegisterSharedServices(); - services.AddSingleton(); - services.AddHostedService(); - }) - .Build(); - - ServiceProvider = host.Services; - AppContext.ServiceProvider = ServiceProvider; - - await host.RunAsync(); - } - - private static void RegisterSharedServices(this IServiceCollection services) - { - services.AddSingleton(AppContext); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - RpcServerService.ServiceTypes.Add(typeof(NvService)); - RpcServerService.ServiceTypes.Add(typeof(GameService)); - RpcServerService.ServiceTypes.Add(typeof(OptionsService)); - RpcServerService.ServiceTypes.Add(typeof(LoggingService)); - RpcServerService.ServiceTypes.Add(typeof(SamsungService)); - RpcServerService.ServiceTypes.Add(typeof(LgService)); - RpcServerService.ServiceTypes.Add(typeof(AmdService)); - } - - public static int EnumThreadWindows(IntPtr handle, IntPtr param) - { - NativeMethods.SendMessageW(handle, Utils.WM_BRINGTOFRONT, UIntPtr.Zero, IntPtr.Zero); - - return 1; - } - - private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e) - { - GlobalHandleException((Exception)e.ExceptionObject, "Unhandled exception"); - } - - private static void GlobalThreadExceptionHandler(object sender, ThreadExceptionEventArgs e) - { - GlobalHandleException(e.Exception, "Exception in thread"); - } - - private static void GlobalHandleException(Exception exception, string type) - { - if (UserExit) - { - return; - } - - var trace = exception.ToLogString(Environment.StackTrace); - var message = $"{type}: {trace}"; - - Logger.Error(message); - - MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - - internal static void SetTheme(bool useDarkMode) - { - DarkModeUtils.SetDarkMode(useDarkMode); - - WinApi.RefreshImmersiveColorPolicyState(); - - DarkModeUtils.InitWpfTheme(); - - var notifyIconManager = ServiceProvider.GetRequiredService(); - - DarkModeUtils.SetContextMenuForeColor(notifyIconManager.NotifyIcon.ContextMenuStrip, FormUtils.CurrentForeColor); - - _mainForm?.SetTheme(useDarkMode); - } - - internal static NotifyIcon GetNotifyIcon() - { - var notifyIconManager = ServiceProvider.GetRequiredService(); - - return notifyIconManager.NotifyIcon; - } - } + static class Program + { + public const string TS_TASKNAME = "ColorControl"; + public static string DataDir { get; private set; } + public static string ConfigFilename { get; private set; } + public static string LogFilename { get; private set; } + public static Config Config { get; private set; } + public static GlobalContext AppContext { get; private set; } + + public static bool IsRestarting { get; private set; } + public static bool UserExit = false; + + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + private static Mutex _mutex; + public static MainForm _mainForm; + private static LoggingRule _loggingRule; + + /// + /// The main entry point for the application. + /// + [STAThread] // autogenerated + public static void Main(string[] args) + { + // STA + MainAsync(args).GetAwaiter().GetResult(); + } + + static async Task MainAsync(string[] args) + { + DataDir = Utils.GetDataPath(); + + var runAsService = args.Contains("--service") || WinApiService.IsAdministratorStatic() && Process.GetCurrentProcess().Parent()?.ProcessName?.Equals("services", StringComparison.InvariantCultureIgnoreCase) == true; + var runElevated = args.Contains("--elevated"); + + InitLogger(runAsService, runElevated); + + Logger.Debug($"Using data path: {DataDir}"); + //Logger.Debug("Parent process: " + Process.GetCurrentProcess().Parent()?.ProcessName); + + if (runAsService) + { + await RunService(args); + return; + } + + await RunApp(args); + } + + static async Task RunApp(string[] args) + { + var startTime = DateTime.Now; + var currentDomain = AppDomain.CurrentDomain; + // Handler for unhandled exceptions. + currentDomain.UnhandledException += GlobalUnhandledExceptionHandler; + // Handler for exceptions in threads behind forms. + Application.ThreadException += GlobalThreadExceptionHandler; + + LoadConfig(); + + if (Config.UseGdiScaling) + { + var result = Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled); + + Logger.Debug($"Result of setting SetHighDpiMode: {result}"); + } + + var mutexId = $"Global\\{typeof(MainForm).GUID}"; + + var startUpParams = StartUpParams.Parse(args); + + AppContext = new GlobalContext(Config, startUpParams, DataDir, _loggingRule, null, startTime, mutexId); + + var host = CreateHostBuilder().Build(); + ServiceProvider = host.Services; + AppContext.ServiceProvider = ServiceProvider; + + MessageForms.Title = AppContext.ApplicationTitle; + + var existingProcess = Utils.GetProcessByName("ColorControl"); + + try + { + if (await CommandLineHandler.HandleStartupParams(startUpParams, existingProcess)) + { + return; + } + } + finally + { + Utils.CloseConsole(); + } + + _mutex = new Mutex(true, AppContext.MutexId, out var mutexCreated); + try + { + if (!mutexCreated) + { + if (existingProcess != null && existingProcess.Threads.Count > 0) + { + var thread = existingProcess.Threads[0]; + NativeMethods.EnumThreadWindows((uint)thread.Id, EnumThreadWindows, IntPtr.Zero); + + return; + } + + MessageBox.Show("Only one instance of this program can be active.", "ColorControl"); + } + else + { + _mutex.WaitOne(); + try + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + if (Debugger.IsAttached) + { + //Utils.StartService(); + var winApiService = ServiceProvider.GetRequiredService(); + + if (winApiService.IsAdministrator()) + { + var backgroundService = ServiceProvider.GetRequiredService(); + backgroundService.PipeName = PipeUtils.ElevatedPipe; + + Task.Run(async () => await backgroundService.StartAsync(CancellationToken.None)); + } + } + + var worker = ServiceProvider.GetRequiredService(); + + await worker.DoWork(); + + if (Debugger.IsAttached && !IsRestarting) + { + var winApiAdminService = ServiceProvider.GetRequiredService(); + winApiAdminService.StopService(); + } + } + catch (Exception ex) + { + MessageBox.Show("Error while initializing application: " + ex.ToLogString(Environment.StackTrace), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + finally + { + if (mutexCreated) + { + _mutex?.Close(); + } + } + } + + public static void OpenDefaultUi() + { + var _ = Config.UiType switch + { + UiType.WebDefaultBrowser => OpenNewUi(), + UiType.WebEmbedded => OpenNewUiEmbedded(), + _ => OpenMainForm() + }; + } + + public static async Task OpenMainForm() + { + _mainForm ??= ServiceProvider.GetRequiredService(); + _mainForm.OpenForm(); + } + + public static void Exit() + { + UserExit = true; + _mainForm?.Close(); + + if (AppContext.MainHandle != 0) + { + NativeMethods.SendMessageW(AppContext.MainHandle, NativeConstants.WM_CLOSE, 0, 0); + } + } + + public static void Restart() + { + IsRestarting = true; + + _mainForm?.CloseForRestart(); + + _mutex?.Close(); + _mutex = null; + + Application.Restart(); + Environment.Exit(0); + } + + public static async Task OpenNewUi() + { + if (await StartUiServer()) + { + await Task.Delay(500); + } + + var winApi = AppContext.ServiceProvider.GetRequiredService(); + + winApi.StartProcess(GetNewUiUrl()); + } + + public static string GetNewUiUrl() + { + return $"http://localhost:{(Config.UiPort > 0 ? Config.UiPort : 5000)}"; + } + + public static async Task OpenNewUiEmbedded() + { + if (await StartUiServer()) + { + await Task.Delay(500); + } + + BrowserWindow.CreateAndShow(GetNewUiUrl()); + } + + private static bool UiServerStarted; + + public static async Task StartUiServer() + { + if (UiServerStarted) + { + return false; + } + + var backgroundService = ServiceProvider.GetRequiredService(); + + backgroundService.PipeName = PipeUtils.MainPipe; + + await backgroundService.StartAsync(CancellationToken.None); + + var _ = Task.Run(() => ColorControl.UI.Blazor.Start(Config)); + UiServerStarted = true; + + return true; + } + + private static void InitLogger(bool runAsService, bool runElevated) + { + var config = new LoggingConfiguration(); + + // Targets where to log to: File and Console + var logFileAppendix = runAsService ? "_svc" : runElevated ? "_elevated" : ""; + + LogFilename = Path.Combine(DataDir, $"LogFile{logFileAppendix}.txt"); + + var logfile = new NLog.Targets.FileTarget("logfile") { FileName = LogFilename }; + + _loggingRule = new LoggingRule("*", LogLevel.Trace, LogLevel.Fatal, logfile); + _loggingRule.RuleName = "ColorControl"; + + // Rules for mapping loggers to targets + config.AddRule(_loggingRule); + + // Apply config + LogManager.Configuration = config; + } + + private static void LoadConfig() + { + ConfigFilename = Path.Combine(DataDir, "Settings.json"); + + try + { + if (File.Exists(ConfigFilename)) + { + var data = File.ReadAllText(ConfigFilename); + Config = JsonConvert.DeserializeObject(data); + } + } + catch (Exception ex) + { + Logger.Error($"LoadConfig: {ex.Message}"); + } + Config ??= new Config(); + + var minLogLevel = LogLevel.FromString(Config.LogLevel); + + if (minLogLevel != LogLevel.Trace) + { + _loggingRule.SetLoggingLevels(minLogLevel, LogLevel.Fatal); + LogManager.ReconfigExistingLoggers(); + } + } + + public static IServiceProvider ServiceProvider { get; private set; } + private static IHostBuilder CreateHostBuilder() + { + return Host.CreateDefaultBuilder() + .ConfigureServices((context, services) => + { + //services.AddSingleton(); + services.RegisterSharedServices(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddTransient(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + }); + } + private static async Task RunService(string[] args) + { + var startTime = DateTime.Now; + + Logger.Debug("RUNNING SERVICE"); + + AppContext = new GlobalContext(null, new StartUpParams(), DataDir, _loggingRule, null, startTime); + + using IHost host = Host.CreateDefaultBuilder(args) + .UseWindowsService(options => + { + options.ServiceName = "ColorControl Service"; + }) + .ConfigureServices(services => + { + services.RegisterSharedServices(); + services.AddSingleton(); + services.AddHostedService(); + }) + .Build(); + + ServiceProvider = host.Services; + AppContext.ServiceProvider = ServiceProvider; + + await host.RunAsync(); + } + + private static void RegisterSharedServices(this IServiceCollection services) + { + services.AddSingleton(AppContext); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + RpcServerService.ServiceTypes.Add(typeof(NvService)); + RpcServerService.ServiceTypes.Add(typeof(GameService)); + RpcServerService.ServiceTypes.Add(typeof(OptionsService)); + RpcServerService.ServiceTypes.Add(typeof(LoggingService)); + RpcServerService.ServiceTypes.Add(typeof(SamsungService)); + RpcServerService.ServiceTypes.Add(typeof(LgService)); + RpcServerService.ServiceTypes.Add(typeof(AmdService)); + } + + public static int EnumThreadWindows(IntPtr handle, IntPtr param) + { + NativeMethods.SendMessageW(handle, Utils.WM_BRINGTOFRONT, UIntPtr.Zero, IntPtr.Zero); + + return 1; + } + + private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e) + { + GlobalHandleException((Exception)e.ExceptionObject, "Unhandled exception"); + } + + private static void GlobalThreadExceptionHandler(object sender, ThreadExceptionEventArgs e) + { + GlobalHandleException(e.Exception, "Exception in thread"); + } + + private static void GlobalHandleException(Exception exception, string type) + { + if (UserExit) + { + return; + } + + var trace = exception.ToLogString(Environment.StackTrace); + var message = $"{type}: {trace}"; + + Logger.Error(message); + + MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + internal static void SetTheme(bool useDarkMode) + { + DarkModeUtils.SetDarkMode(useDarkMode); + + WinApi.RefreshImmersiveColorPolicyState(); + + DarkModeUtils.InitWpfTheme(); + + var notifyIconManager = ServiceProvider.GetRequiredService(); + + DarkModeUtils.SetContextMenuForeColor(notifyIconManager.NotifyIcon.ContextMenuStrip, FormUtils.CurrentForeColor); + + _mainForm?.SetTheme(useDarkMode); + } + + internal static NotifyIcon GetNotifyIcon() + { + var notifyIconManager = ServiceProvider.GetRequiredService(); + + return notifyIconManager.NotifyIcon; + } + } } diff --git a/ColorControl/Services/AMD/AmdService.cs b/ColorControl/Services/AMD/AmdService.cs index 186897e..2b946e9 100644 --- a/ColorControl/Services/AMD/AmdService.cs +++ b/ColorControl/Services/AMD/AmdService.cs @@ -16,617 +16,539 @@ using System.Windows.Forms; namespace ColorControl.Services.AMD { - class AmdService : GraphicsService - { - private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); - - public override string ServiceName => "AMD"; - - protected override string PresetsBaseFilename => "AmdPresets.json"; - - private ADLDisplayInfo _currentDisplay; - - public static readonly int SHORTCUTID_AMDQA = -201; - - private string _configFilename; - public AmdServiceConfig Config { get; private set; } - - public AmdService(GlobalContext globalContext) : base(globalContext) - { - LoadPresets(); - LoadConfig(); - } - - public static async Task ExecutePresetAsync(string idOrName) - { - try - { - var globalContext = Program.ServiceProvider.GetRequiredService(); - - var service = new AmdService(globalContext); - - var result = await service.ApplyPreset(idOrName); - - if (!result) - { - Console.WriteLine("Preset not found or error while executing."); - } - - return result; - } - catch (Exception ex) - { - Console.WriteLine("Error executing preset: " + ex.ToLogString()); - return false; - } - } - - public override void InstallEventHandlers() - { - base.InstallEventHandlers(); - - SetShortcuts(SHORTCUTID_AMDQA, Config.QuickAccessShortcut); - } - - private void LoadConfig() - { - _configFilename = Path.Combine(_dataPath, "AmdConfig.json"); - try - { - if (File.Exists(_configFilename)) - { - Config = JsonConvert.DeserializeObject(File.ReadAllText(_configFilename)); - } - } - catch (Exception ex) - { - Logger.Error($"LoadConfig: {ex.Message}"); - } - Config ??= new AmdServiceConfig(); - } - - protected override List GetDefaultPresets() - { - return AmdPreset.GetDefaultPresets(); - } - - public override List GetInfo() - { - return [$"{_presets.Count} presets"]; - } - - private void SavePresets() - { - Utils.WriteObject(_presetsFilename, _presets); - } - - public void GlobalSave() - { - SavePresets(); - SaveConfig(); - } - - public override bool HasDisplaysAttached(bool reinitialize = false) - { - try - { - return GetDisplays().Any(); - } - catch (Exception) - { - return false; - } - } - - public void SetCurrentDisplay(AmdPreset preset) - { - var displays = GetDisplays(); - if (preset.primaryDisplay) - { - _currentDisplay = displays.FirstOrDefault(); - } - else - { - _currentDisplay = displays.FirstOrDefault(x => x.DisplayName.Equals(preset.displayName)); - } - } - - public ADLDisplayInfo GetCurrentDisplay() - { - if (string.IsNullOrEmpty(_currentDisplay.DisplayName)) - { - _currentDisplay = GetDisplays().FirstOrDefault(); - } - - return _currentDisplay; - } - - public override async Task ApplyPreset(AmdPreset preset) - { - SetCurrentDisplay(preset); - - if (string.IsNullOrEmpty(_currentDisplay.DisplayName)) - { - Logger.Error("Could not set current display"); - return false; - } - - var result = true; - - if (preset.applyHDR) - { - var hdrEnabled = IsHDREnabled(); - if (preset.toggleHDR) - { - result = ADLWrapper.SetDisplayHDRState(_currentDisplay, !hdrEnabled); - } - else - { - result = ADLWrapper.SetDisplayHDRState(_currentDisplay, preset.HDREnabled); - } - - //if (preset.toggleHDR || preset.HDREnabled != hdrEnabled) - //{ - // ToggleHDR(config.DisplaySettingsDelay); - //} - - if (preset.SDRBrightness.HasValue) - { - var deviceName = GetDisplayDeviceName(_currentDisplay); - - SetSDRBrightness(deviceName, preset.SDRBrightness.Value); - } - } - - if (preset.DisplayConfig.ApplyRefreshRate || preset.DisplayConfig.ApplyResolution) - { - if (!SetMode(preset.DisplayConfig, true)) - { - result = false; - } - } - - if (preset.applyColorData) - { - if (!ADLWrapper.SetDisplayColorDepth(_currentDisplay, preset.colorDepth)) - { - Logger.Error("Could not set color depth"); - result = false; - } - if (preset.pixelFormat != ADLPixelFormat.UNKNOWN && !ADLWrapper.SetDisplayPixelFormat(_currentDisplay, preset.pixelFormat)) - { - Logger.Error("Could not set pixel format"); - result = false; - } - } - - if (preset.applyDithering) - { - if (!SetDithering(preset.ditherState)) - { - result = false; - } - } - - _lastAppliedPreset = preset; - - PresetApplied(); - - return result; - } - - public bool SetDithering(ADLDitherState ditherState) - { - var display = GetCurrentDisplay(); - - return ADLWrapper.SetDisplayDitherState(display, ditherState); - } - - public ADLDitherState GetDithering(ADLDisplayInfo display = default(ADLDisplayInfo)) - { - if (string.IsNullOrEmpty(display.DisplayName)) - { - display = GetCurrentDisplay(); - } - - var ditherState = ADLDitherState.DRIVER_DEFAULT; - - if (ADLWrapper.GetDisplayDitherState(display, ref ditherState)) - { - return ditherState; - } - - return ditherState; - } - - public string GetDisplayDeviceName(ADLDisplayInfo display) - { - return Screen.PrimaryScreen.DeviceName; - } - - public bool SetMode(DisplayConfig displayConfig, bool updateRegistry = false) - { - var display = GetCurrentDisplay(); - - return SetMode(GetDisplayDeviceName(display), displayConfig, updateRegistry); - } - - public List GetAvailableRefreshRates(AmdPreset preset = null) - { - if (preset != null) - { - SetCurrentDisplay(preset); - } - - var horizontal = 3840; - var vertical = 2160; - var display = GetCurrentDisplay(); - - ADLWrapper.GetDisplayResolution(display, ref horizontal, ref vertical); - - return GetAvailableRefreshRatesV2(GetDisplayDeviceName(display), horizontal, vertical); - } - - public List GetAvailableResolutionsV2(AmdPreset preset = null) - { - if (preset != null) - { - SetCurrentDisplay(preset); - } - - var display = GetCurrentDisplay(); - var deviceName = GetDisplayDeviceName(display); - if (deviceName == null) - { - return []; - } - - return GetAvailableResolutionsInternalV2(deviceName); - } - - public bool SetMode(VirtualResolution resolution = null, Rational refreshRate = null, bool updateRegistry = false, AmdPreset preset = null) - { - var display = preset == null ? GetCurrentDisplay() : GetPresetDisplay(preset); - if (display.Equals(default(ADLDisplayInfo))) - { - return false; - } - - return SetMode(GetDisplayDeviceName(display), resolution, refreshRate, updateRegistry); - } - - public bool SetMode(DisplayConfig displayConfig, bool updateRegistry = false, AmdPreset preset = null) - { - var display = preset == null ? GetCurrentDisplay() : GetPresetDisplay(preset); - if (display.DisplayID.DisplayPhysicalIndex == 0) - { - return false; - } - - return SetMode(GetDisplayDeviceName(display), displayConfig, updateRegistry); - } - - public ADLDisplayInfo GetPresetDisplay(AmdPreset preset) - { - return GetCurrentDisplay(); - } - - public List GetAvailableRefreshRatesV2(AmdPreset preset = null) - { - if (preset != null) - { - SetCurrentDisplay(preset); - } - - var display = _currentDisplay; - if (_currentDisplay.DisplayID.DisplayLogicalAdapterIndex == 0) - { - return []; - } - - var desktopRect = preset?.DisplayConfig.ApplyResolution == true && preset?.DisplayConfig.Resolution.ActiveWidth > 0 ? - new Rectangle(0, 0, (int)preset.DisplayConfig.Resolution.ActiveWidth, (int)preset.DisplayConfig.Resolution.ActiveHeight) : - GetDesktopRect(display); - - return GetAvailableRefreshRatesV2(Screen.PrimaryScreen.DeviceName, desktopRect.Width, desktopRect.Height); - } - - private Rectangle GetDesktopRect(ADLDisplayInfo display) - { - // TODO: improve this - var screen = Screen.AllScreens.First(); - - return screen.Bounds; - } - - public bool IsHDREnabled(ADLDisplayInfo display = default) - { - if (display.Equals(default(ADLDisplayInfo))) - { - display = GetCurrentDisplay(); - } - - var supported = false; - var enabled = false; - ADLWrapper.GetDisplayHDRState(display, ref supported, ref enabled); - - Logger.Debug($"IsHDREnabled: supported {supported}, enabled {enabled}"); - - return enabled; - } - - public List GetDisplays() - { - var displays = ADLWrapper.GetAllDisplays(); - - //if (!displays.Any()) - //{ - // displays.Add(new ADLDisplayInfo - // { - // DisplayName = "Dummy" - // }); - //} - - return displays; - } - - public string GetFullDisplayName(ADLDisplayInfo display) - { - var name = display.DisplayName; - - var screen = GetScreenForDisplay(display); - if (screen != null) - { - name = $"{screen.DeviceName} ({name})"; - } - - return name; - } - - public Screen GetScreenForDisplay(ADLDisplayInfo display) - { - var index = 0; - foreach (var screen in Screen.AllScreens) - { - var info = CCD.GetDisplayInfo(screen.DeviceName); - Logger.Debug($"SCREEN[{index}]: {screen.DeviceName}, {info?.FriendlyName}, {screen.Primary}"); - index++; - } - return Screen.AllScreens.FirstOrDefault(x => CCD.GetDisplayInfo(x.DeviceName)?.FriendlyName.Equals(display.DisplayName) ?? false); - } - - public List GetSimpleDisplayInfos() - { - List displays; - try - { - displays = GetDisplays(); - } - catch (Exception e) - { - Logger.Error("Error while getting displays: " + e.ToLogString()); - return null; - } - - return displays.Select(d => new AmdDisplayInfo(d, null, null)).ToList(); - - //var list = new List(); - - //foreach (var display in displays) - //{ - // var values = new List - // { - // "Current settings" - // }; - - // var screen = GetScreenForDisplay(display); - - // var name = GetFullDisplayName(display); - // values.Add(name); - - // var colorDepth = ADLColorDepth.UNKNOWN; - // ADLWrapper.GetDisplayColorDepth(display, ref colorDepth); - - // var pixelFormat = ADLPixelFormat.UNKNOWN; - // ADLWrapper.GetDisplayPixelFormat(display, ref pixelFormat); - - // var colorSettings = $"{colorDepth.GetDescription()}, {pixelFormat.GetDescription()}"; - // values.Add(colorSettings); - - // var displayConfig = CCD.GetDisplayConfig(screen?.DeviceName); - - // values.Add($"{displayConfig.RefreshRate}Hz"); - - // values.Add($"{displayConfig.GetResolutionDesc()}"); - - // var ditherState = GetDithering(display); - // values.Add(ditherState.GetDescription()); - - // var hdrEnabled = IsHDREnabled(); - // values.Add(hdrEnabled ? "Yes" : "No"); - - // var infoLine = string.Format("{0}: {1}, {2}Hz, {3}, HDR: {4}", name, colorSettings, displayConfig.RefreshRate, displayConfig.GetResolutionDesc(), hdrEnabled ? "Yes" : "No"); - - // var displayInfo = new AmdDisplayInfo(display, values, infoLine); - - // list.Add(displayInfo); - //} - - //return list; - } - - public List GetDisplayInfos() - { - var list = new List(); - - var displayInfos = GetSimpleDisplayInfos(); - - foreach (var displayInfo in displayInfos) - { - var preset = GetPresetForDisplay(displayInfo, displayInfos.Count()); - - displayInfo.Values = preset.GetDisplayValues(_globalContext.Config); - displayInfo.InfoLine = preset.InfoLine; - - list.Add(displayInfo); - } - - return list; - - //List displays; - //try - //{ - // displays = GetDisplays(); - //} - //catch (Exception e) - //{ - // Logger.Error("Error while getting displays: " + e.ToLogString()); - // return null; - //} - - //var list = new List(); - - //foreach (var display in displays) - //{ - // var values = new List - // { - // "Current settings" - // }; - - // var screen = GetScreenForDisplay(display); - - // var name = GetFullDisplayName(display); - // values.Add(name); - - // var colorDepth = ADLColorDepth.UNKNOWN; - // ADLWrapper.GetDisplayColorDepth(display, ref colorDepth); - - // var pixelFormat = ADLPixelFormat.UNKNOWN; - // ADLWrapper.GetDisplayPixelFormat(display, ref pixelFormat); - - // var colorSettings = $"{colorDepth.GetDescription()}, {pixelFormat.GetDescription()}"; - // values.Add(colorSettings); - - // var displayConfig = CCD.GetDisplayConfig(screen?.DeviceName); - - // values.Add($"{displayConfig.RefreshRate}Hz"); - - // values.Add($"{displayConfig.GetResolutionDesc()}"); - - // var ditherState = GetDithering(display); - // values.Add(ditherState.GetDescription()); - - // var hdrEnabled = IsHDREnabled(); - // values.Add(hdrEnabled ? "Yes" : "No"); - - // var infoLine = string.Format("{0}: {1}, {2}Hz, {3}, HDR: {4}", name, colorSettings, displayConfig.RefreshRate, displayConfig.GetResolutionDesc(), hdrEnabled ? "Yes" : "No"); - - // var displayInfo = new AmdDisplayInfo(display, values, infoLine); - - // list.Add(displayInfo); - //} - - //return list; - } - - protected override void Initialize() - { - if (!ADLWrapper.Initialize()) - { - //throw new InvalidOperationException("Cannot load AMD API"); - } - } - - protected override void Uninitialize() - { - ADLWrapper.Uninitialze(); - } - - public List GetDisplayPresets() - { - try - { - var list = new List(); - - var displayInfos = GetSimpleDisplayInfos(); - - foreach (var displayInfo in displayInfos) - { - var preset = GetPresetForDisplay(displayInfo, displayInfos.Count()); - - displayInfo.Values = preset.GetDisplayValues(_globalContext.Config); - displayInfo.InfoLine = preset.InfoLine; - - list.Add(preset); - } - - return list; - } - catch (Exception e) - { - Logger.Error("Error while getting displays: " + e.ToLogString()); - return null; - } - } - - public AmdPreset GetPresetForDisplay(AmdDisplayInfo displayInfo, int displayCount = 1) - { - if (displayInfo == null) - { - return null; - } - - var display = displayInfo.Display; - - var colorDepth = ADLColorDepth.UNKNOWN; - ADLWrapper.GetDisplayColorDepth(display, ref colorDepth); - - var pixelFormat = ADLPixelFormat.UNKNOWN; - ADLWrapper.GetDisplayPixelFormat(display, ref pixelFormat); - - var ditherState = GetDithering(display); - - var screen = GetScreenForDisplay(display); - var displayConfig = CCD.GetDisplayConfig(screen?.DeviceName); - - var ccdDisplay = screen != null ? CCD.GetDisplayInfo(screen.DeviceName) : null; - - var hdrEnabled = IsHDREnabled(display); - - var preset = new AmdPreset - { - IsDisplayPreset = true, - displayName = display.DisplayName, - DisplayId = ccdDisplay?.DisplayId, - primaryDisplay = screen?.Primary == true, - colorDepth = colorDepth, - pixelFormat = pixelFormat, - ditherState = ditherState, - DisplayConfig = displayConfig, - SDRBrightness = hdrEnabled ? GetSDRBrightness(screen?.DeviceName) : null, - HDREnabled = hdrEnabled, - }; - - return preset; - } - - private void SaveConfig() - { - Utils.WriteObject(_configFilename, Config); - } - - public AmdServiceConfig GetConfig() - { - return Config; - } - - public bool UpdateConfig(AmdServiceConfig config) - { - Config.Update(config); - - SetShortcuts(SHORTCUTID_AMDQA, Config.QuickAccessShortcut); - - return true; - } - } + class AmdService : GraphicsService + { + private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + public override string ServiceName => "AMD"; + + protected override string PresetsBaseFilename => "AmdPresets.json"; + + private ADLDisplayInfo _currentDisplay; + + public static readonly int SHORTCUTID_AMDQA = -201; + + private string _configFilename; + public AmdServiceConfig Config { get; private set; } + + public AmdService(GlobalContext globalContext) : base(globalContext) + { + LoadPresets(); + LoadConfig(); + } + + public static async Task ExecutePresetAsync(string idOrName) + { + try + { + var globalContext = Program.ServiceProvider.GetRequiredService(); + + var service = new AmdService(globalContext); + + var result = await service.ApplyPreset(idOrName); + + if (!result) + { + Console.WriteLine("Preset not found or error while executing."); + } + + return result; + } + catch (Exception ex) + { + Console.WriteLine("Error executing preset: " + ex.ToLogString()); + return false; + } + } + + public override void InstallEventHandlers() + { + base.InstallEventHandlers(); + + SetShortcuts(SHORTCUTID_AMDQA, Config.QuickAccessShortcut); + } + + private void LoadConfig() + { + _configFilename = Path.Combine(_dataPath, "AmdConfig.json"); + try + { + if (File.Exists(_configFilename)) + { + Config = JsonConvert.DeserializeObject(File.ReadAllText(_configFilename)); + } + } + catch (Exception ex) + { + Logger.Error($"LoadConfig: {ex.Message}"); + } + Config ??= new AmdServiceConfig(); + } + + protected override List GetDefaultPresets() + { + return AmdPreset.GetDefaultPresets(); + } + + public override List GetInfo() + { + return [$"{_presets.Count} presets"]; + } + + private void SavePresets() + { + Utils.WriteObject(_presetsFilename, _presets); + } + + public void GlobalSave() + { + SavePresets(); + SaveConfig(); + } + + public override bool HasDisplaysAttached(bool reinitialize = false) + { + try + { + return GetDisplays().Any(); + } + catch (Exception) + { + return false; + } + } + + public void SetCurrentDisplay(AmdPreset preset) + { + var displays = GetDisplays(); + if (preset.primaryDisplay) + { + _currentDisplay = displays.FirstOrDefault(); + } + else + { + _currentDisplay = displays.FirstOrDefault(x => x.DisplayName.Equals(preset.displayName)); + } + } + + public ADLDisplayInfo GetCurrentDisplay() + { + if (string.IsNullOrEmpty(_currentDisplay.DisplayName)) + { + _currentDisplay = GetDisplays().FirstOrDefault(); + } + + return _currentDisplay; + } + + public override async Task ApplyPreset(AmdPreset preset) + { + SetCurrentDisplay(preset); + + if (string.IsNullOrEmpty(_currentDisplay.DisplayName)) + { + Logger.Error("Could not set current display"); + return false; + } + + var result = true; + + if (preset.applyHDR) + { + var hdrEnabled = IsHDREnabled(); + if (preset.toggleHDR) + { + result = ADLWrapper.SetDisplayHDRState(_currentDisplay, !hdrEnabled); + } + else + { + result = ADLWrapper.SetDisplayHDRState(_currentDisplay, preset.HDREnabled); + } + + //if (preset.toggleHDR || preset.HDREnabled != hdrEnabled) + //{ + // ToggleHDR(config.DisplaySettingsDelay); + //} + + if (preset.SDRBrightness.HasValue) + { + var deviceName = GetDisplayDeviceName(_currentDisplay); + + SetSDRBrightness(deviceName, preset.SDRBrightness.Value); + } + } + + if (preset.DisplayConfig.ApplyRefreshRate || preset.DisplayConfig.ApplyResolution) + { + if (!SetMode(preset.DisplayConfig, true)) + { + result = false; + } + } + + if (preset.applyColorData) + { + if (!ADLWrapper.SetDisplayColorDepth(_currentDisplay, preset.colorDepth)) + { + Logger.Error("Could not set color depth"); + result = false; + } + if (preset.pixelFormat != ADLPixelFormat.UNKNOWN && !ADLWrapper.SetDisplayPixelFormat(_currentDisplay, preset.pixelFormat)) + { + Logger.Error("Could not set pixel format"); + result = false; + } + } + + if (preset.applyDithering) + { + if (!SetDithering(preset.ditherState)) + { + result = false; + } + } + + _lastAppliedPreset = preset; + + PresetApplied(); + + return result; + } + + public bool SetDithering(ADLDitherState ditherState) + { + var display = GetCurrentDisplay(); + + return ADLWrapper.SetDisplayDitherState(display, ditherState); + } + + public ADLDitherState GetDithering(ADLDisplayInfo display = default(ADLDisplayInfo)) + { + if (string.IsNullOrEmpty(display.DisplayName)) + { + display = GetCurrentDisplay(); + } + + var ditherState = ADLDitherState.DRIVER_DEFAULT; + + if (ADLWrapper.GetDisplayDitherState(display, ref ditherState)) + { + return ditherState; + } + + return ditherState; + } + + public string GetDisplayDeviceName(ADLDisplayInfo display) + { + return Screen.PrimaryScreen.DeviceName; + } + + public bool SetMode(DisplayConfig displayConfig, bool updateRegistry = false) + { + var display = GetCurrentDisplay(); + + return SetMode(GetDisplayDeviceName(display), displayConfig, updateRegistry); + } + + public List GetAvailableRefreshRates(AmdPreset preset = null) + { + if (preset != null) + { + SetCurrentDisplay(preset); + } + + var horizontal = 3840; + var vertical = 2160; + var display = GetCurrentDisplay(); + + ADLWrapper.GetDisplayResolution(display, ref horizontal, ref vertical); + + return GetAvailableRefreshRatesV2(GetDisplayDeviceName(display), horizontal, vertical); + } + + public List GetAvailableResolutionsV2(AmdPreset preset = null) + { + if (preset != null) + { + SetCurrentDisplay(preset); + } + + var display = GetCurrentDisplay(); + var deviceName = GetDisplayDeviceName(display); + if (deviceName == null) + { + return []; + } + + return GetAvailableResolutionsInternalV2(deviceName); + } + + public bool SetMode(VirtualResolution resolution = null, Rational refreshRate = null, bool updateRegistry = false, AmdPreset preset = null) + { + var display = preset == null ? GetCurrentDisplay() : GetPresetDisplay(preset); + if (display.Equals(default(ADLDisplayInfo))) + { + return false; + } + + return SetMode(GetDisplayDeviceName(display), resolution, refreshRate, updateRegistry); + } + + public bool SetMode(DisplayConfig displayConfig, bool updateRegistry = false, AmdPreset preset = null) + { + var display = preset == null ? GetCurrentDisplay() : GetPresetDisplay(preset); + if (display.DisplayID.DisplayPhysicalIndex == 0) + { + return false; + } + + return SetMode(GetDisplayDeviceName(display), displayConfig, updateRegistry); + } + + public ADLDisplayInfo GetPresetDisplay(AmdPreset preset) + { + return GetCurrentDisplay(); + } + + public List GetAvailableRefreshRatesV2(AmdPreset preset = null) + { + if (preset != null) + { + SetCurrentDisplay(preset); + } + + var display = _currentDisplay; + if (_currentDisplay.DisplayID.DisplayLogicalAdapterIndex == 0) + { + return []; + } + + var desktopRect = preset?.DisplayConfig.ApplyResolution == true && preset?.DisplayConfig.Resolution.ActiveWidth > 0 ? + new Rectangle(0, 0, (int)preset.DisplayConfig.Resolution.ActiveWidth, (int)preset.DisplayConfig.Resolution.ActiveHeight) : + GetDesktopRect(display); + + return GetAvailableRefreshRatesV2(Screen.PrimaryScreen.DeviceName, desktopRect.Width, desktopRect.Height); + } + + private Rectangle GetDesktopRect(ADLDisplayInfo display) + { + // TODO: improve this + var screen = Screen.AllScreens.First(); + + return screen.Bounds; + } + + public bool IsHDREnabled(ADLDisplayInfo display = default) + { + if (display.Equals(default(ADLDisplayInfo))) + { + display = GetCurrentDisplay(); + } + + var supported = false; + var enabled = false; + ADLWrapper.GetDisplayHDRState(display, ref supported, ref enabled); + + Logger.Debug($"IsHDREnabled: supported {supported}, enabled {enabled}"); + + return enabled; + } + + public List GetDisplays() + { + var displays = ADLWrapper.GetAllDisplays(); + + //if (!displays.Any()) + //{ + // displays.Add(new ADLDisplayInfo + // { + // DisplayName = "Dummy" + // }); + //} + + return displays; + } + + public string GetFullDisplayName(ADLDisplayInfo display) + { + var name = display.DisplayName; + + var screen = GetScreenForDisplay(display); + if (screen != null) + { + name = $"{screen.DeviceName} ({name})"; + } + + return name; + } + + public Screen GetScreenForDisplay(ADLDisplayInfo display) + { + var index = 0; + foreach (var screen in Screen.AllScreens) + { + var info = CCD.GetDisplayInfo(screen.DeviceName); + Logger.Debug($"SCREEN[{index}]: {screen.DeviceName}, {info?.FriendlyName}, {screen.Primary}"); + index++; + } + return Screen.AllScreens.FirstOrDefault(x => CCD.GetDisplayInfo(x.DeviceName)?.FriendlyName.Equals(display.DisplayName) ?? false); + } + + public List GetSimpleDisplayInfos() + { + List displays; + try + { + displays = GetDisplays(); + } + catch (Exception e) + { + Logger.Error("Error while getting displays: " + e.ToLogString()); + return null; + } + + return displays.Select(d => new AmdDisplayInfo(d, null, null)).ToList(); + } + + public List GetDisplayInfos() + { + var list = new List(); + + var displayInfos = GetSimpleDisplayInfos(); + + foreach (var displayInfo in displayInfos) + { + var preset = GetPresetForDisplay(displayInfo, displayInfos.Count()); + + displayInfo.Values = preset.GetDisplayValues(_globalContext.Config); + displayInfo.InfoLine = preset.InfoLine; + + list.Add(displayInfo); + } + + return list; + } + + protected override void Initialize() + { + if (!ADLWrapper.Initialize()) + { + //throw new InvalidOperationException("Cannot load AMD API"); + } + } + + protected override void Uninitialize() + { + ADLWrapper.Uninitialze(); + } + + public List GetDisplayPresets() + { + try + { + var list = new List(); + + var displayInfos = GetSimpleDisplayInfos(); + + foreach (var displayInfo in displayInfos) + { + var preset = GetPresetForDisplay(displayInfo, displayInfos.Count()); + + displayInfo.Values = preset.GetDisplayValues(_globalContext.Config); + displayInfo.InfoLine = preset.InfoLine; + + list.Add(preset); + } + + return list; + } + catch (Exception e) + { + Logger.Error("Error while getting displays: " + e.ToLogString()); + return null; + } + } + + public AmdPreset GetPresetForDisplay(AmdDisplayInfo displayInfo, int displayCount = 1) + { + if (displayInfo == null) + { + return null; + } + + var display = displayInfo.Display; + + var colorDepth = ADLColorDepth.UNKNOWN; + ADLWrapper.GetDisplayColorDepth(display, ref colorDepth); + + var pixelFormat = ADLPixelFormat.UNKNOWN; + ADLWrapper.GetDisplayPixelFormat(display, ref pixelFormat); + + var ditherState = GetDithering(display); + + var screen = GetScreenForDisplay(display); + var displayConfig = CCD.GetDisplayConfig(screen?.DeviceName); + + var ccdDisplay = screen != null ? CCD.GetDisplayInfo(screen.DeviceName) : null; + + var hdrEnabled = IsHDREnabled(display); + + var preset = new AmdPreset + { + IsDisplayPreset = true, + displayName = display.DisplayName, + DisplayId = ccdDisplay?.DisplayId, + primaryDisplay = screen?.Primary == true, + colorDepth = colorDepth, + pixelFormat = pixelFormat, + ditherState = ditherState, + DisplayConfig = displayConfig, + SDRBrightness = hdrEnabled ? GetSDRBrightness(screen?.DeviceName) : null, + HDREnabled = hdrEnabled, + }; + + return preset; + } + + private void SaveConfig() + { + Utils.WriteObject(_configFilename, Config); + } + + public AmdServiceConfig GetConfig() + { + return Config; + } + + public bool UpdateConfig(AmdServiceConfig config) + { + Config.Update(config); + + SetShortcuts(SHORTCUTID_AMDQA, Config.QuickAccessShortcut); + + return true; + } + + public bool UpdatePreset(AmdPreset specPreset) + { + var currentPreset = _presets.FirstOrDefault(p => p.id == specPreset.id); + + if (currentPreset != null) + { + currentPreset.name = specPreset.name; + currentPreset.shortcut = specPreset.shortcut; + currentPreset.Update(specPreset); + return true; + } + + var newPreset = new AmdPreset(specPreset); + newPreset.name = specPreset.name; + newPreset.shortcut = specPreset.shortcut; + + _presets.Add(newPreset); + + return true; + } + } } diff --git a/ColorControl/Services/NVIDIA/NvService.cs b/ColorControl/Services/NVIDIA/NvService.cs index 5455a55..2aae778 100644 --- a/ColorControl/Services/NVIDIA/NvService.cs +++ b/ColorControl/Services/NVIDIA/NvService.cs @@ -36,1802 +36,1804 @@ using static ColorControl.Shared.Native.CCD; namespace ColorControl.Services.NVIDIA { - class NvService : GraphicsService - { - private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); - - [DllImport(@"nvapi64", EntryPoint = @"nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, - PreserveSig = true)] - private static extern IntPtr NvAPI64_QueryInterface(uint interfaceId); - - [FunctionId(FunctionId.NvAPI_GPU_SetDitherControl)] - public delegate int NvAPI_Disp_SetDitherControl( - [In] PhysicalGPUHandle physicalGpu, - [In] uint OutputId, - [In] uint state, - [In] uint bits, - [In] uint mode - ); - - [FunctionId(FunctionId.NvAPI_GPU_GetDitherControl)] - public delegate int NvAPI_Disp_GetDitherControl( - [In] uint DisplayId, - [MarshalAs(UnmanagedType.Struct)] ref NV_GPU_DITHER_CONTROL_V1 ditherControl); - - [StructLayout(LayoutKind.Sequential)] - public struct NV_GPU_DITHER_CONTROL_V1 - { - public uint version; - public int state; - public int bits; - public int mode; - public uint bitsCaps; - public uint modeCaps; - }; - - [FunctionId(FunctionId.NvAPI_Disp_SetOutputMode)] - public delegate int NvAPI_Disp_SetOutputMode( - [In] uint DisplayId, - ref NV_DISPLAY_OUTPUT_MODE pDisplayMode - ); - - [FunctionId(FunctionId.NvAPI_Disp_GetOutputMode)] - public delegate int NvAPI_Disp_GetOutputMode( - [In] uint DisplayId, - ref NV_DISPLAY_OUTPUT_MODE pDisplayMode - ); - - [FunctionId(FunctionId.NvAPI_RestartDisplayDriver)] - public delegate void NvAPI_RestartDisplayDriver(); - - // NvAPI_RestartDisplayDriver B4B26B65 - - //public struct NV_HDR_METADATA_V1 - //{ - // public uint version; //!< Version of this structure - - // public short displayPrimary_x0; //!< x coordinate of color primary 0 (e.g. Red) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) - // public short displayPrimary_y0; //!< y coordinate of color primary 0 (e.g. Red) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) - - // public short displayPrimary_x1; //!< x coordinate of color primary 1 (e.g. Green) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) - // public short displayPrimary_y1; //!< y coordinate of color primary 1 (e.g. Green) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) - - // public short displayPrimary_x2; //!< x coordinate of color primary 2 (e.g. Blue) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) - // public short displayPrimary_y2; //!< y coordinate of color primary 2 (e.g. Blue) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) - - // public short displayWhitePoint_x; //!< x coordinate of white point of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) - // public short displayWhitePoint_y; //!< y coordinate of white point of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) - - // public short max_display_mastering_luminance; //!< Maximum display mastering luminance ([0x0000-0xFFFF] = [0.0 - 65535.0] cd/m^2, in units of 1 cd/m^2) - // public short min_display_mastering_luminance; //!< Minimum display mastering luminance ([0x0000-0xFFFF] = [0.0 - 6.55350] cd/m^2, in units of 0.0001 cd/m^2) - - // public short max_content_light_level; //!< Maximum Content Light level (MaxCLL) ([0x0000-0xFFFF] = [0.0 - 65535.0] cd/m^2, in units of 1 cd/m^2) - // public short max_frame_average_light_level; //!< Maximum Frame-Average Light Level (MaxFALL) ([0x0000-0xFFFF] = [0.0 - 65535.0] cd/m^2, in units of 1 cd/m^2) - //} - - //public delegate int NvAPI_Disp_GetSourceHdrMetadata( - // [In] uint DisplayId, - // [MarshalAs(UnmanagedType.Struct)] ref NV_HDR_METADATA_V1 pMetadata, - // [In] long sourcePID - //); - - public override string ServiceName => "NVIDIA"; - - protected override string PresetsBaseFilename => "NvPresets.json"; - - private Display _currentDisplay; - private string _baseProfileName = ""; - private string _configFilename; - public NvServiceConfig Config { get; private set; } - private NV_DISPLAY_OUTPUT_MODE? Hdr10OutputModeForced { get; set; } - - private DrsSettingsService _drs; - private DrsSettingsMetaService _meta; - private List _settings = new List(); - - private SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); - private SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1); - - public uint DriverVersion { get; private set; } - public bool OutputModeAvailable => DriverVersion >= 52500; - - private static readonly List _driverSettingIds = new(); - private readonly WinApiService _winApiService; - private readonly RpcClientService _rpcClientService; - private readonly PowerEventDispatcher _powerEventDispatcher; - private readonly ServiceManager _serviceManager; - private static NvService ServiceInstance; - - public static readonly int SHORTCUTID_NVQA = -200; - - public NvService(GlobalContext globalContext, WinApiService winApiService, RpcClientService rpcClientService, PowerEventDispatcher powerEventDispatcher, ServiceManager serviceManager) : base(globalContext) - { - _winApiService = winApiService; - _rpcClientService = rpcClientService; - _powerEventDispatcher = powerEventDispatcher; - _serviceManager = serviceManager; - _rpcClientService.Name = nameof(NvService); - NvPreset.GetDriverSettingsDescription += GetDriverSettingsDescription; - - AddJsonConverter(new ColorDataConverter()); - LoadConfig(); - LoadPresets(); - } - - public override void InstallEventHandlers() - { - SetShortcuts(SHORTCUTID_NVQA, Config.QuickAccessShortcut); - - GetDisplayInfos(false); - - MainViewModel.ConfigPath = _globalContext.DataPath; - if (Config.ApplyNovideoOnStartup) - { - MainWindow.CreateAndShow(false); - } - - // TODO: implement later - //_powerEventDispatcher.RegisterEventHandler(PowerEventDispatcher.Event_Suspend, PowerModeChanged); - //_powerEventDispatcher.RegisterAsyncEventHandler(PowerEventDispatcher.Event_Resume, PowerModeResume); - //_powerEventDispatcher.RegisterEventHandler(PowerEventDispatcher.Event_Shutdown, PowerModeChanged); - } - - public override List GetInfo() - { - return [$"{_presets.Count} presets"]; - } - - public static async Task ExecutePresetAsync(string idOrName) - { - try - { - var nvService = Program.ServiceProvider.GetRequiredService(); - - var result = await nvService.ApplyPreset(idOrName); - - if (!result) - { - Console.WriteLine("Preset not found or error while executing."); - } - - return result; - } - catch (Exception ex) - { - Console.WriteLine("Error executing preset: " + ex.ToLogString()); - return false; - } - } - - public Display GetCurrentDisplay(bool checkDisplays = true) - { - if (checkDisplays && !HasDisplaysAttached()) - { - _currentDisplay = null; - return null; - } - - if (_currentDisplay == null) - { - _currentDisplay = Display.GetDisplays()[0]; - } - - return _currentDisplay; - } - - public override bool HasDisplaysAttached(bool reinitialize = false) - { - if (reinitialize) - { - try - { - Initialize(); - } - catch (Exception ex) - { - Logger.Error($"Could not reinitialize NVIDIA API: {ex.Message}"); - return false; - } - } - - try - { - return DisplayDevice.GetGDIPrimaryDisplayDevice() != null; - } - catch (Exception) - { - return reinitialize ? false : HasDisplaysAttached(true); - } - } - - public void GlobalSave() - { - SavePresets(); - SaveConfig(); - } - - protected override List GetDefaultPresets() - { - return NvPreset.GetDefaultPresets(); - } - - private void SavePresets() - { - Utils.WriteObject(_presetsFilename, _presets); - } - - private Display SetCurrentDisplay(NvPreset preset) - { - _currentDisplay = GetPresetDisplay(preset); - - return _currentDisplay; - } - - private Display GetPresetDisplay(NvPreset preset) - { - if (preset.Display != null) - { - return preset.Display; - } - - if (preset.primaryDisplay) - { - return GetPrimaryDisplay(); - } - - var displays = GetSimpleDisplayInfos(); - - return displays.FirstOrDefault(d => d.DisplayId == preset.DisplayId)?.Display; - } - - public Display GetPrimaryDisplay() - { - try - { - var displayId = DisplayDevice.GetGDIPrimaryDisplayDevice().DisplayId; - return Display.GetDisplays().FirstOrDefault(x => x.DisplayDevice.DisplayId == displayId); - } - catch (Exception ex) - { - Logger.Error(ex, "Error while getting primary display device"); - - return null; - } - } - - public bool UpdatePreset(NvPreset specPreset) - { - var currentPreset = _presets.FirstOrDefault(p => p.id == specPreset.id); - - if (currentPreset != null) - { - currentPreset.name = specPreset.name; - currentPreset.Update(specPreset); - return true; - } - - var newPreset = new NvPreset(specPreset); - newPreset.name = specPreset.name; - - _presets.Add(newPreset); - - return true; - } - - private async Task WaitForDisplayAsync(NvPreset preset) - { - var attempt = 0; - Display display = null; - - while (attempt < 20) - { - if (HasDisplaysAttached()) - { - display = SetCurrentDisplay(preset); - } - - if (display != null) - { - break; - } - - if (preset.IsStartupPreset) - { - await Task.Delay(1000); - attempt++; - } - else - { - break; - } - } - - return display; - } - - public override async Task ApplyPreset(NvPreset preset) - { - var result = true; - - var display = await WaitForDisplayAsync(preset); - - if (display == null) - { - Logger.Warn($"Cannot apply preset {preset.IdOrName} because the associated display is not active/found"); - - return false; - } - - var hdrEnabled = IsHDREnabled(); - - var newHdrEnabled = preset.applyHDR && (preset.HDREnabled || (preset.toggleHDR && !hdrEnabled)); - var applyHdr = preset.applyHDR && (preset.toggleHDR || preset.HDREnabled != hdrEnabled); - - if (preset.applyColorData && (ColorDataDiffers(preset.colorData) || (!newHdrEnabled && preset.applyColorData && preset.colorData.Colorimetry != ColorDataColorimetry.Auto))) - { - if (preset.DisplayConfig.ApplyRefreshRate || preset.DisplayConfig.ApplyResolution) - { - var timing = display.DisplayDevice.CurrentTiming; - if ((preset.DisplayConfig.ApplyRefreshRate && preset.DisplayConfig.RefreshRate.MilliValue < timing.Extra.FrequencyInMillihertz) || - (preset.DisplayConfig.ApplyResolution && preset.DisplayConfig.Resolution.ActiveWidth < timing.HorizontalVisible)) - { - SetMode(preset.DisplayConfig, true); - } - } - - SetColorData(display, preset.colorData); - } - - if (preset.applyHDR) - { - if (applyHdr) - { - if (newHdrEnabled && !hdrEnabled) - { - MainWindow.BeforeDisplaySettingsChange(); - } - - SetHDRState(display, newHdrEnabled); - } - - if (newHdrEnabled && preset.HdrSettings.OutputMode.HasValue) - { - SetOutputMode(preset.HdrSettings.OutputMode.Value, display); - } - - if (preset.SDRBrightness.HasValue) - { - SetSDRBrightness(display.Name, preset.SDRBrightness.Value); - } - } - - if (preset.DisplayConfig.ApplyRefreshRate || preset.DisplayConfig.ApplyResolution) - { - if (!SetMode(preset.DisplayConfig, true)) - { - result = false; - } - } - - if (preset.applyOther) - { - if (preset.ColorProfileSettings.ProfileName != null) - { - CCD.SetDisplayDefaultColorProfile(display.Name, preset.ColorProfileSettings.ProfileName, _globalContext.Config.SetMinTmlAndMaxTml); - } - - if (preset.scaling.HasValue) - { - SetScaling(display, preset.scaling.Value); - } - } - - if (preset.applyHdmiSettings) - { - SetHdmiSettings(display, preset.HdmiInfoFrameSettings); - } - - if (preset.applyDithering) - { - if (!SetDithering(preset.DitherState, preset: preset)) - { - result = false; - } - } - - if (preset.ApplyColorEnhancements) - { - SetDigitalVibranceLevel(display, preset.ColorEnhancementSettings.DigitalVibranceLevel); - SetHueAngle(display, preset.ColorEnhancementSettings.HueAngle); - } - - if (preset.applyDriverSettings) - { - SetDriverSettings(preset.driverSettings); - } - - if (preset.ApplyNovideoSettings && !newHdrEnabled) - { - SetNovideoSettings(preset.DisplayId, preset.NovideoSettings); - } - - if (preset.applyOverclocking) - { - result = ApplyOverclocking(preset.ocSettings); - } - - _lastAppliedPreset = preset; - - preset.IsStartupPreset = false; - - PresetApplied(); - GetDisplayInfos(false); - - return result; - } - - private void SetNovideoSettings(string displayId, NovideoSettings novideoSettings) - { - MainWindow.ApplySettings(displayId, novideoSettings.ApplyClamp, (int)novideoSettings.ColorSpace); - } - - public bool ApplyOverclocking(List settings) - { - if (!_winApiService.IsAdministrator()) - { - var message = new SvcRpcSetNvOverclockingMessage - { - MethodName = nameof(ApplyOverclocking), - OverclockingSettings = settings - }; - - var result = _rpcClientService.Call(message); - - if (result == null) - { - return false; - } - - return true; - } - - var result2 = true; - - foreach (var ocSetting in settings) - { - var gpuInfo = NvGpuInfo.GetGpuInfo(ocSetting.PCIIdentifier); - - if (gpuInfo == null) - { - continue; - } - - result2 = gpuInfo.ApplyOcSettings(ocSetting); - } - - return result2; - } - - public bool SetColorData(Display display, ColorData colorData) - { - try - { - display.DisplayDevice.SetColorData(colorData); - - return true; - } - catch (Exception ex) - { - Logger.Error($"SetColorData threw an exception: {ex.Message}"); - return false; - } - } - - public void ApplyDriverSettings(string profileName, List> settings) - { - RefreshProfileSettings(); - - _drs.StoreSettingsToProfile(profileName, settings); - } - - public bool RestoreDriverSettings(string profileName, List> settings) - { - var result = false; - - foreach (var keyValuePair in settings) - { - var settingId = keyValuePair.Key; - _drs.ResetValue(profileName, settingId, out result); - } - - return result; - } - - public bool SetDriverSettings(Dictionary settings, string profileName = null) - { - var convertedSettings = new List>(); - - foreach (var keyValue in settings) - { - var setting = ConvertDriverSetting(keyValue.Key, keyValue.Value); - - if (setting.Key == keyValue.Key) - { - convertedSettings.Add(setting); - } - } - - _drs.StoreSettingsToProfile(profileName ?? _baseProfileName, convertedSettings); - - return true; - } - - public void SetDriverSetting(uint settingId, uint value) - { - SetDriverSettings(new Dictionary { { settingId, value } }); - } - - private KeyValuePair ConvertDriverSetting(uint settingId, uint settingValue) - { - var convertedSetting = new KeyValuePair(0, string.Empty); - - var settingMeta = _meta.GetSettingMeta(settingId); - - if (settingMeta == null) - { - return convertedSetting; - } - - if (settingMeta.SettingType == nspector.Native.NVAPI2.NVDRS_SETTING_TYPE.NVDRS_DWORD_TYPE) - { - var value = settingMeta.DwordValues?.FirstOrDefault(v => v.Value == settingValue); - - if (value != null) - { - return new KeyValuePair(settingId, value.ValueName); - } - } - else if (settingMeta.SettingType == nspector.Native.NVAPI2.NVDRS_SETTING_TYPE.NVDRS_BINARY_TYPE) - { - var value = "0x" + settingValue.ToString("x16"); + class NvService : GraphicsService + { + private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + + [DllImport(@"nvapi64", EntryPoint = @"nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, + PreserveSig = true)] + private static extern IntPtr NvAPI64_QueryInterface(uint interfaceId); + + [FunctionId(FunctionId.NvAPI_GPU_SetDitherControl)] + public delegate int NvAPI_Disp_SetDitherControl( + [In] PhysicalGPUHandle physicalGpu, + [In] uint OutputId, + [In] uint state, + [In] uint bits, + [In] uint mode + ); + + [FunctionId(FunctionId.NvAPI_GPU_GetDitherControl)] + public delegate int NvAPI_Disp_GetDitherControl( + [In] uint DisplayId, + [MarshalAs(UnmanagedType.Struct)] ref NV_GPU_DITHER_CONTROL_V1 ditherControl); + + [StructLayout(LayoutKind.Sequential)] + public struct NV_GPU_DITHER_CONTROL_V1 + { + public uint version; + public int state; + public int bits; + public int mode; + public uint bitsCaps; + public uint modeCaps; + }; + + [FunctionId(FunctionId.NvAPI_Disp_SetOutputMode)] + public delegate int NvAPI_Disp_SetOutputMode( + [In] uint DisplayId, + ref NV_DISPLAY_OUTPUT_MODE pDisplayMode + ); + + [FunctionId(FunctionId.NvAPI_Disp_GetOutputMode)] + public delegate int NvAPI_Disp_GetOutputMode( + [In] uint DisplayId, + ref NV_DISPLAY_OUTPUT_MODE pDisplayMode + ); + + [FunctionId(FunctionId.NvAPI_RestartDisplayDriver)] + public delegate void NvAPI_RestartDisplayDriver(); + + // NvAPI_RestartDisplayDriver B4B26B65 + + //public struct NV_HDR_METADATA_V1 + //{ + // public uint version; //!< Version of this structure + + // public short displayPrimary_x0; //!< x coordinate of color primary 0 (e.g. Red) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) + // public short displayPrimary_y0; //!< y coordinate of color primary 0 (e.g. Red) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) + + // public short displayPrimary_x1; //!< x coordinate of color primary 1 (e.g. Green) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) + // public short displayPrimary_y1; //!< y coordinate of color primary 1 (e.g. Green) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) + + // public short displayPrimary_x2; //!< x coordinate of color primary 2 (e.g. Blue) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) + // public short displayPrimary_y2; //!< y coordinate of color primary 2 (e.g. Blue) of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) + + // public short displayWhitePoint_x; //!< x coordinate of white point of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) + // public short displayWhitePoint_y; //!< y coordinate of white point of mastering display ([0x0000-0xC350] = [0.0 - 1.0]) + + // public short max_display_mastering_luminance; //!< Maximum display mastering luminance ([0x0000-0xFFFF] = [0.0 - 65535.0] cd/m^2, in units of 1 cd/m^2) + // public short min_display_mastering_luminance; //!< Minimum display mastering luminance ([0x0000-0xFFFF] = [0.0 - 6.55350] cd/m^2, in units of 0.0001 cd/m^2) + + // public short max_content_light_level; //!< Maximum Content Light level (MaxCLL) ([0x0000-0xFFFF] = [0.0 - 65535.0] cd/m^2, in units of 1 cd/m^2) + // public short max_frame_average_light_level; //!< Maximum Frame-Average Light Level (MaxFALL) ([0x0000-0xFFFF] = [0.0 - 65535.0] cd/m^2, in units of 1 cd/m^2) + //} + + //public delegate int NvAPI_Disp_GetSourceHdrMetadata( + // [In] uint DisplayId, + // [MarshalAs(UnmanagedType.Struct)] ref NV_HDR_METADATA_V1 pMetadata, + // [In] long sourcePID + //); + + public override string ServiceName => "NVIDIA"; + + protected override string PresetsBaseFilename => "NvPresets.json"; + + private Display _currentDisplay; + private string _baseProfileName = ""; + private string _configFilename; + public NvServiceConfig Config { get; private set; } + private NV_DISPLAY_OUTPUT_MODE? Hdr10OutputModeForced { get; set; } + + private DrsSettingsService _drs; + private DrsSettingsMetaService _meta; + private List _settings = new List(); + + private SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); + private SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1); + + public uint DriverVersion { get; private set; } + public bool OutputModeAvailable => DriverVersion >= 52500; + + private static readonly List _driverSettingIds = new(); + private readonly WinApiService _winApiService; + private readonly RpcClientService _rpcClientService; + private readonly PowerEventDispatcher _powerEventDispatcher; + private readonly ServiceManager _serviceManager; + private static NvService ServiceInstance; + + public static readonly int SHORTCUTID_NVQA = -200; + + public NvService(GlobalContext globalContext, WinApiService winApiService, RpcClientService rpcClientService, PowerEventDispatcher powerEventDispatcher, ServiceManager serviceManager) : base(globalContext) + { + _winApiService = winApiService; + _rpcClientService = rpcClientService; + _powerEventDispatcher = powerEventDispatcher; + _serviceManager = serviceManager; + _rpcClientService.Name = nameof(NvService); + NvPreset.GetDriverSettingsDescription += GetDriverSettingsDescription; + + AddJsonConverter(new ColorDataConverter()); + LoadConfig(); + LoadPresets(); + } + + public override void InstallEventHandlers() + { + SetShortcuts(SHORTCUTID_NVQA, Config.QuickAccessShortcut); + + GetDisplayInfos(false); + + MainViewModel.ConfigPath = _globalContext.DataPath; + if (Config.ApplyNovideoOnStartup) + { + MainWindow.CreateAndShow(false); + } + + // TODO: implement later + //_powerEventDispatcher.RegisterEventHandler(PowerEventDispatcher.Event_Suspend, PowerModeChanged); + //_powerEventDispatcher.RegisterAsyncEventHandler(PowerEventDispatcher.Event_Resume, PowerModeResume); + //_powerEventDispatcher.RegisterEventHandler(PowerEventDispatcher.Event_Shutdown, PowerModeChanged); + } + + public override List GetInfo() + { + return [$"{_presets.Count} presets"]; + } + + public static async Task ExecutePresetAsync(string idOrName) + { + try + { + var nvService = Program.ServiceProvider.GetRequiredService(); + + var result = await nvService.ApplyPreset(idOrName); + + if (!result) + { + Console.WriteLine("Preset not found or error while executing."); + } + + return result; + } + catch (Exception ex) + { + Console.WriteLine("Error executing preset: " + ex.ToLogString()); + return false; + } + } + + public Display GetCurrentDisplay(bool checkDisplays = true) + { + if (checkDisplays && !HasDisplaysAttached()) + { + _currentDisplay = null; + return null; + } + + if (_currentDisplay == null) + { + _currentDisplay = Display.GetDisplays()[0]; + } + + return _currentDisplay; + } + + public override bool HasDisplaysAttached(bool reinitialize = false) + { + if (reinitialize) + { + try + { + Initialize(); + } + catch (Exception ex) + { + Logger.Error($"Could not reinitialize NVIDIA API: {ex.Message}"); + return false; + } + } + + try + { + return DisplayDevice.GetGDIPrimaryDisplayDevice() != null; + } + catch (Exception) + { + return reinitialize ? false : HasDisplaysAttached(true); + } + } + + public void GlobalSave() + { + SavePresets(); + SaveConfig(); + } + + protected override List GetDefaultPresets() + { + return NvPreset.GetDefaultPresets(); + } + + private void SavePresets() + { + Utils.WriteObject(_presetsFilename, _presets); + } + + private Display SetCurrentDisplay(NvPreset preset) + { + _currentDisplay = GetPresetDisplay(preset); + + return _currentDisplay; + } + + private Display GetPresetDisplay(NvPreset preset) + { + if (preset.Display != null) + { + return preset.Display; + } + + if (preset.primaryDisplay) + { + return GetPrimaryDisplay(); + } + + var displays = GetSimpleDisplayInfos(); + + return displays.FirstOrDefault(d => d.DisplayId == preset.DisplayId)?.Display; + } + + public Display GetPrimaryDisplay() + { + try + { + var displayId = DisplayDevice.GetGDIPrimaryDisplayDevice().DisplayId; + return Display.GetDisplays().FirstOrDefault(x => x.DisplayDevice.DisplayId == displayId); + } + catch (Exception ex) + { + Logger.Error(ex, "Error while getting primary display device"); + + return null; + } + } + + public bool UpdatePreset(NvPreset specPreset) + { + var currentPreset = _presets.FirstOrDefault(p => p.id == specPreset.id); + + if (currentPreset != null) + { + currentPreset.name = specPreset.name; + currentPreset.shortcut = specPreset.shortcut; + currentPreset.Update(specPreset); + return true; + } + + var newPreset = new NvPreset(specPreset); + newPreset.name = specPreset.name; + newPreset.shortcut = specPreset.shortcut; + + _presets.Add(newPreset); + + return true; + } + + private async Task WaitForDisplayAsync(NvPreset preset) + { + var attempt = 0; + Display display = null; + + while (attempt < 20) + { + if (HasDisplaysAttached()) + { + display = SetCurrentDisplay(preset); + } + + if (display != null) + { + break; + } + + if (preset.IsStartupPreset) + { + await Task.Delay(1000); + attempt++; + } + else + { + break; + } + } + + return display; + } + + public override async Task ApplyPreset(NvPreset preset) + { + var result = true; + + var display = await WaitForDisplayAsync(preset); + + if (display == null) + { + Logger.Warn($"Cannot apply preset {preset.IdOrName} because the associated display is not active/found"); + + return false; + } + + var hdrEnabled = IsHDREnabled(); + + var newHdrEnabled = preset.applyHDR && (preset.HDREnabled || (preset.toggleHDR && !hdrEnabled)); + var applyHdr = preset.applyHDR && (preset.toggleHDR || preset.HDREnabled != hdrEnabled); + + if (preset.applyColorData && (ColorDataDiffers(preset.colorData) || (!newHdrEnabled && preset.applyColorData && preset.colorData.Colorimetry != ColorDataColorimetry.Auto))) + { + if (preset.DisplayConfig.ApplyRefreshRate || preset.DisplayConfig.ApplyResolution) + { + var timing = display.DisplayDevice.CurrentTiming; + if ((preset.DisplayConfig.ApplyRefreshRate && preset.DisplayConfig.RefreshRate.MilliValue < timing.Extra.FrequencyInMillihertz) || + (preset.DisplayConfig.ApplyResolution && preset.DisplayConfig.Resolution.ActiveWidth < timing.HorizontalVisible)) + { + SetMode(preset.DisplayConfig, true); + } + } + + SetColorData(display, preset.colorData); + } + + if (preset.applyHDR) + { + if (applyHdr) + { + if (newHdrEnabled && !hdrEnabled) + { + MainWindow.BeforeDisplaySettingsChange(); + } + + SetHDRState(display, newHdrEnabled); + } + + if (newHdrEnabled && preset.HdrSettings.OutputMode.HasValue) + { + SetOutputMode(preset.HdrSettings.OutputMode.Value, display); + } + + if (preset.SDRBrightness.HasValue) + { + SetSDRBrightness(display.Name, preset.SDRBrightness.Value); + } + } + + if (preset.DisplayConfig.ApplyRefreshRate || preset.DisplayConfig.ApplyResolution) + { + if (!SetMode(preset.DisplayConfig, true)) + { + result = false; + } + } + + if (preset.applyOther) + { + if (preset.ColorProfileSettings.ProfileName != null) + { + CCD.SetDisplayDefaultColorProfile(display.Name, preset.ColorProfileSettings.ProfileName, _globalContext.Config.SetMinTmlAndMaxTml); + } + + if (preset.scaling.HasValue) + { + SetScaling(display, preset.scaling.Value); + } + } + + if (preset.applyHdmiSettings) + { + SetHdmiSettings(display, preset.HdmiInfoFrameSettings); + } + + if (preset.applyDithering) + { + if (!SetDithering(preset.DitherState, preset: preset)) + { + result = false; + } + } + + if (preset.ApplyColorEnhancements) + { + SetDigitalVibranceLevel(display, preset.ColorEnhancementSettings.DigitalVibranceLevel); + SetHueAngle(display, preset.ColorEnhancementSettings.HueAngle); + } + + if (preset.applyDriverSettings) + { + SetDriverSettings(preset.driverSettings); + } + + if (preset.ApplyNovideoSettings && !newHdrEnabled) + { + SetNovideoSettings(preset.DisplayId, preset.NovideoSettings); + } + + if (preset.applyOverclocking) + { + result = ApplyOverclocking(preset.ocSettings); + } + + _lastAppliedPreset = preset; + + preset.IsStartupPreset = false; + + PresetApplied(); + GetDisplayInfos(false); + + return result; + } + + private void SetNovideoSettings(string displayId, NovideoSettings novideoSettings) + { + MainWindow.ApplySettings(displayId, novideoSettings.ApplyClamp, (int)novideoSettings.ColorSpace); + } + + public bool ApplyOverclocking(List settings) + { + if (!_winApiService.IsAdministrator()) + { + var message = new SvcRpcSetNvOverclockingMessage + { + MethodName = nameof(ApplyOverclocking), + OverclockingSettings = settings + }; + + var result = _rpcClientService.Call(message); + + if (result == null) + { + return false; + } + + return true; + } + + var result2 = true; + + foreach (var ocSetting in settings) + { + var gpuInfo = NvGpuInfo.GetGpuInfo(ocSetting.PCIIdentifier); + + if (gpuInfo == null) + { + continue; + } + + result2 = gpuInfo.ApplyOcSettings(ocSetting); + } + + return result2; + } + + public bool SetColorData(Display display, ColorData colorData) + { + try + { + display.DisplayDevice.SetColorData(colorData); + + return true; + } + catch (Exception ex) + { + Logger.Error($"SetColorData threw an exception: {ex.Message}"); + return false; + } + } + + public void ApplyDriverSettings(string profileName, List> settings) + { + RefreshProfileSettings(); + + _drs.StoreSettingsToProfile(profileName, settings); + } + + public bool RestoreDriverSettings(string profileName, List> settings) + { + var result = false; + + foreach (var keyValuePair in settings) + { + var settingId = keyValuePair.Key; + _drs.ResetValue(profileName, settingId, out result); + } + + return result; + } + + public bool SetDriverSettings(Dictionary settings, string profileName = null) + { + var convertedSettings = new List>(); + + foreach (var keyValue in settings) + { + var setting = ConvertDriverSetting(keyValue.Key, keyValue.Value); + + if (setting.Key == keyValue.Key) + { + convertedSettings.Add(setting); + } + } + + _drs.StoreSettingsToProfile(profileName ?? _baseProfileName, convertedSettings); + + return true; + } + + public void SetDriverSetting(uint settingId, uint value) + { + SetDriverSettings(new Dictionary { { settingId, value } }); + } + + private KeyValuePair ConvertDriverSetting(uint settingId, uint settingValue) + { + var convertedSetting = new KeyValuePair(0, string.Empty); + + var settingMeta = _meta.GetSettingMeta(settingId); + + if (settingMeta == null) + { + return convertedSetting; + } + + if (settingMeta.SettingType == nspector.Native.NVAPI2.NVDRS_SETTING_TYPE.NVDRS_DWORD_TYPE) + { + var value = settingMeta.DwordValues?.FirstOrDefault(v => v.Value == settingValue); + + if (value != null) + { + return new KeyValuePair(settingId, value.ValueName); + } + } + else if (settingMeta.SettingType == nspector.Native.NVAPI2.NVDRS_SETTING_TYPE.NVDRS_BINARY_TYPE) + { + var value = "0x" + settingValue.ToString("x16"); - return new KeyValuePair(settingId, value); - } - - return convertedSetting; - } + return new KeyValuePair(settingId, value); + } + + return convertedSetting; + } - private ColorData GetCurrentColorData(Display display) - { - try - { - return display.DisplayDevice.CurrentColorData; - } - catch (Exception e) - { - Logger.Error("Error while reading current color data: " + e.Message); - return new ColorData(); - } - } - - private bool ColorDataDiffers(ColorData colorData) - { - var display = GetCurrentDisplay(); + private ColorData GetCurrentColorData(Display display) + { + try + { + return display.DisplayDevice.CurrentColorData; + } + catch (Exception e) + { + Logger.Error("Error while reading current color data: " + e.Message); + return new ColorData(); + } + } + + private bool ColorDataDiffers(ColorData colorData) + { + var display = GetCurrentDisplay(); - var currentColorData = GetCurrentColorData(display); - - return currentColorData.IsDifferent(colorData); - } + var currentColorData = GetCurrentColorData(display); + + return currentColorData.IsDifferent(colorData); + } - public void SetHDRState(Display display, bool enabled) - { - if (!enabled && Hdr10OutputModeForced.HasValue) - { - SetOutputMode(NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_SDR, display); - Hdr10OutputModeForced = null; - } + public void SetHDRState(Display display, bool enabled) + { + if (!enabled && Hdr10OutputModeForced.HasValue) + { + SetOutputMode(NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_SDR, display); + Hdr10OutputModeForced = null; + } - CCD.SetHDRState(enabled, display.Name); - } + CCD.SetHDRState(enabled, display.Name); + } - public void SetDigitalVibranceLevel(Display display, int level) - { - var dvControl = display.DigitalVibranceControl; + public void SetDigitalVibranceLevel(Display display, int level) + { + var dvControl = display.DigitalVibranceControl; - dvControl.CurrentLevel = level; - } + dvControl.CurrentLevel = level; + } - public int GetDigitalVibranceLevel(Display display) - { - return display.DigitalVibranceControl.CurrentLevel; - } + public int GetDigitalVibranceLevel(Display display) + { + return display.DigitalVibranceControl.CurrentLevel; + } - public void SetHueAngle(Display display, int angle) - { - display.HUEControl.CurrentAngle = angle; - } + public void SetHueAngle(Display display, int angle) + { + display.HUEControl.CurrentAngle = angle; + } - public int GetHueAngle(Display display) - { - return display.HUEControl.CurrentAngle; - } + public int GetHueAngle(Display display) + { + return display.HUEControl.CurrentAngle; + } - //public NV_HDR_METADATA_V1? GetHdrMetaData(Display display = null) - //{ - // var ptr = NvAPI64_QueryInterface(0x0D3F52DA); - // if (ptr != IntPtr.Zero) - // { - // var delegateValue = Marshal.GetDelegateForFunctionPointer(ptr, typeof(NvAPI_Disp_GetSourceHdrMetadata)) as NvAPI_Disp_GetSourceHdrMetadata; + //public NV_HDR_METADATA_V1? GetHdrMetaData(Display display = null) + //{ + // var ptr = NvAPI64_QueryInterface(0x0D3F52DA); + // if (ptr != IntPtr.Zero) + // { + // var delegateValue = Marshal.GetDelegateForFunctionPointer(ptr, typeof(NvAPI_Disp_GetSourceHdrMetadata)) as NvAPI_Disp_GetSourceHdrMetadata; - // display ??= GetCurrentDisplay(); + // display ??= GetCurrentDisplay(); - // var displayDevice = display.DisplayDevice; + // var displayDevice = display.DisplayDevice; - // var displayId = displayDevice.DisplayId; + // var displayId = displayDevice.DisplayId; - // var metadata = new NV_HDR_METADATA_V1(); - // metadata.version = MAKE_NVAPI_VERSION(1); + // var metadata = new NV_HDR_METADATA_V1(); + // metadata.version = MAKE_NVAPI_VERSION(1); - // var processId = Process.GetCurrentProcess().Id; + // var processId = Process.GetCurrentProcess().Id; - // var resultValue = delegateValue(displayId, ref metadata, processId); + // var resultValue = delegateValue(displayId, ref metadata, processId); - // return resultValue == 0 ? metadata : null; - // } + // return resultValue == 0 ? metadata : null; + // } - // return null; - //} + // return null; + //} - public bool SetOutputMode(NV_DISPLAY_OUTPUT_MODE outputMode, Display display = null) - { - var delegateValue = DelegateFactory.GetDelegate(); + public bool SetOutputMode(NV_DISPLAY_OUTPUT_MODE outputMode, Display display = null) + { + var delegateValue = DelegateFactory.GetDelegate(); - if (delegateValue == null) - { - return false; - } + if (delegateValue == null) + { + return false; + } - display ??= GetCurrentDisplay(); + display ??= GetCurrentDisplay(); - var displayDevice = display.DisplayDevice; + var displayDevice = display.DisplayDevice; - var displayId = displayDevice.DisplayId; + var displayId = displayDevice.DisplayId; - var newOutputMode = outputMode; - var previousOutputMode = Hdr10OutputModeForced; + var newOutputMode = outputMode; + var previousOutputMode = Hdr10OutputModeForced; - var resultValue = delegateValue(displayId, ref outputMode); + var resultValue = delegateValue(displayId, ref outputMode); - if (resultValue == 0) - { - Hdr10OutputModeForced = newOutputMode > NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_SDR ? newOutputMode : null; - } + if (resultValue == 0) + { + Hdr10OutputModeForced = newOutputMode > NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_SDR ? newOutputMode : null; + } - if (previousOutputMode == NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_HDR10PLUS_GAMING && newOutputMode == NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_HDR10) - { - // HDR10+ will not be disabled properly when setting output mode to HDR10, just disable and enable HDR again - SetHDRState(display, false); - SetHDRState(display, true); - } + if (previousOutputMode == NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_HDR10PLUS_GAMING && newOutputMode == NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_HDR10) + { + // HDR10+ will not be disabled properly when setting output mode to HDR10, just disable and enable HDR again + SetHDRState(display, false); + SetHDRState(display, true); + } - return resultValue == 0; - } + return resultValue == 0; + } - public NV_DISPLAY_OUTPUT_MODE? GetOutputMode(Display display = null) - { - var delegateValue = DelegateFactory.GetDelegate(); + public NV_DISPLAY_OUTPUT_MODE? GetOutputMode(Display display = null) + { + var delegateValue = DelegateFactory.GetDelegate(); - if (delegateValue == null) - { - return null; - } + if (delegateValue == null) + { + return null; + } - display ??= GetCurrentDisplay(); + display ??= GetCurrentDisplay(); - var displayDevice = display.DisplayDevice; + var displayDevice = display.DisplayDevice; - var displayId = displayDevice.DisplayId; + var displayId = displayDevice.DisplayId; - var outputMode = NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_SDR; + var outputMode = NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_SDR; - var resultValue = delegateValue(displayId, ref outputMode); + var resultValue = delegateValue(displayId, ref outputMode); - return resultValue == 0 ? outputMode : null; - } + return resultValue == 0 ? outputMode : null; + } - public bool SetDitherRegistryKey(string displayRegId, uint state, uint bits = 1, uint mode = 4) - { - if (!_winApiService.IsAdministrator()) - { - var result = _rpcClientService.Call(nameof(SetDitherRegistryKey), displayRegId, state, bits, mode); + public bool SetDitherRegistryKey(string displayRegId, uint state, uint bits = 1, uint mode = 4) + { + if (!_winApiService.IsAdministrator()) + { + var result = _rpcClientService.Call(nameof(SetDitherRegistryKey), displayRegId, state, bits, mode); - return result; - } + return result; + } - const string DOMAIN_ALIAS_RID_ADMINS = "S-1-5-32-544"; + const string DOMAIN_ALIAS_RID_ADMINS = "S-1-5-32-544"; - var registryPath = "SYSTEM\\CurrentControlSet\\Services\\nvlddmkm\\State\\DisplayDatabase"; + var registryPath = "SYSTEM\\CurrentControlSet\\Services\\nvlddmkm\\State\\DisplayDatabase"; - var displayDbKey = Registry.LocalMachine.OpenSubKey(registryPath); + var displayDbKey = Registry.LocalMachine.OpenSubKey(registryPath); - var subKeyNames = displayDbKey.GetSubKeyNames().Where(n => n.Contains(displayRegId)).ToList(); + var subKeyNames = displayDbKey.GetSubKeyNames().Where(n => n.Contains(displayRegId)).ToList(); - foreach (var subKeyName in subKeyNames) - { - var keyPath = $"{registryPath}\\{subKeyName}"; + foreach (var subKeyName in subKeyNames) + { + var keyPath = $"{registryPath}\\{subKeyName}"; - try - { - var subKey = Registry.LocalMachine.OpenSubKey(keyPath); + try + { + var subKey = Registry.LocalMachine.OpenSubKey(keyPath); - var ditherValueName = subKey.GetValueNames().FirstOrDefault(n => n == "DitherRegistryKey"); + var ditherValueName = subKey.GetValueNames().FirstOrDefault(n => n == "DitherRegistryKey"); - if (ditherValueName == null) - { - continue; - } + if (ditherValueName == null) + { + continue; + } - subKey = Registry.LocalMachine.OpenSubKey(keyPath, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.ChangePermissions); + subKey = Registry.LocalMachine.OpenSubKey(keyPath, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.ChangePermissions); - var accessControl = subKey.GetAccessControl(); + var accessControl = subKey.GetAccessControl(); - var rules = accessControl.GetAccessRules(true, true, typeof(SecurityIdentifier)); - var accessRules = new RegistryAccessRule[rules.Count]; - rules.CopyTo(accessRules, 0); + var rules = accessControl.GetAccessRules(true, true, typeof(SecurityIdentifier)); + var accessRules = new RegistryAccessRule[rules.Count]; + rules.CopyTo(accessRules, 0); - if (!accessRules.Any(r => r.RegistryRights == RegistryRights.FullControl && r.IdentityReference.Value == DOMAIN_ALIAS_RID_ADMINS && r.AccessControlType == AccessControlType.Allow)) - { - var ownerIdentity = accessControl.GetOwner(typeof(SecurityIdentifier)); + if (!accessRules.Any(r => r.RegistryRights == RegistryRights.FullControl && r.IdentityReference.Value == DOMAIN_ALIAS_RID_ADMINS && r.AccessControlType == AccessControlType.Allow)) + { + var ownerIdentity = accessControl.GetOwner(typeof(SecurityIdentifier)); - var adminFullControlRule = new RegistryAccessRule(ownerIdentity, RegistryRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow); + var adminFullControlRule = new RegistryAccessRule(ownerIdentity, RegistryRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow); - accessControl.SetAccessRule(adminFullControlRule); + accessControl.SetAccessRule(adminFullControlRule); - subKey.SetAccessControl(accessControl); - } + subKey.SetAccessControl(accessControl); + } - subKey = Registry.LocalMachine.OpenSubKey(keyPath, true); + subKey = Registry.LocalMachine.OpenSubKey(keyPath, true); - var value = subKey.GetValue(ditherValueName) as byte[]; + var value = subKey.GetValue(ditherValueName) as byte[]; - if (value == null) - { - continue; - } + if (value == null) + { + continue; + } - value[9] = (byte)state; - value[10] = (byte)bits; - value[11] = (byte)mode; + value[9] = (byte)state; + value[10] = (byte)bits; + value[11] = (byte)mode; - // Checksum - value[12] = (byte)value.Take(12).Sum(v => (uint)v); + // Checksum + value[12] = (byte)value.Take(12).Sum(v => (uint)v); - subKey.SetValue(ditherValueName, value, RegistryValueKind.Binary); + subKey.SetValue(ditherValueName, value, RegistryValueKind.Binary); - break; - } - catch (Exception ex) - { - Logger.Debug($"Cannot get access to registry key: {keyPath} because: {ex.Message}"); - } - } + break; + } + catch (Exception ex) + { + Logger.Debug($"Cannot get access to registry key: {keyPath} because: {ex.Message}"); + } + } - return true; - } + return true; + } - public bool SetDithering(NvDitherState state, uint bits = 1, uint mode = 4, NvPreset preset = null, Display currentDisplay = null, bool setRegistryKey = false, bool restartDriver = false) - { - var result = true; + public bool SetDithering(NvDitherState state, uint bits = 1, uint mode = 4, NvPreset preset = null, Display currentDisplay = null, bool setRegistryKey = false, bool restartDriver = false) + { + var result = true; - var display = currentDisplay ?? GetCurrentDisplay(); - if (display == null) - { - return false; - } + var display = currentDisplay ?? GetCurrentDisplay(); + if (display == null) + { + return false; + } - var displayDevice = display.DisplayDevice; + var displayDevice = display.DisplayDevice; - var gpuHandle = displayDevice.PhysicalGPU.Handle; - var displayId = displayDevice.DisplayId; + var gpuHandle = displayDevice.PhysicalGPU.Handle; + var displayId = displayDevice.DisplayId; - if (state == NvDitherState.Auto) - { - // These seem to be ignored in Auto-state - bits = 0; - mode = 0; - } - else if (preset != null) - { - bits = preset.ditheringBits; - mode = preset.ditheringMode; + if (state == NvDitherState.Auto) + { + // These seem to be ignored in Auto-state + bits = 0; + mode = 0; + } + else if (preset != null) + { + bits = preset.ditheringBits; + mode = preset.ditheringMode; - setRegistryKey |= preset.SetDitherRegistryKey; - restartDriver |= preset.RestartDriver; - } + setRegistryKey |= preset.SetDitherRegistryKey; + restartDriver |= preset.RestartDriver; + } - if (setRegistryKey) - { - var info = CCD.GetDisplayInfo(display.Name); - var regId = info?.DisplayId; - - if (regId.IsNullOrEmpty()) - { - return false; - } - - result = SetDitherRegistryKey(regId, (uint)state, bits, mode); - - if (restartDriver) - { - RestartDriver(); - } - } - else - { - var delegateValue = DelegateFactory.GetDelegate(); - - if (delegateValue == null) - { - return false; - } - - var resultValue = delegateValue(gpuHandle, displayId, (uint)state, bits, mode); - if (resultValue != 0) - { - Logger.Error($"Could not set dithering because NvAPI_Disp_SetDitherControl returned a non-zero return code: {resultValue}"); - result = false; - } - } - - return result; - } - - public bool RestartDriver() - { - if (!_winApiService.IsAdministrator()) - { - return _rpcClientService.Call(nameof(RestartDriver)); - } - - var restartDelegate = DelegateFactory.GetDelegate(); - - if (restartDelegate != null) - { - restartDelegate(); - - return true; - } - - return false; - } - - public NV_GPU_DITHER_CONTROL_V1 GetDithering(Display currentDisplay = null) - { - var version = MAKE_NVAPI_VERSION(1); - var dither = new NV_GPU_DITHER_CONTROL_V1 { version = version }; - - var delegateValue = DelegateFactory.GetDelegate(); - - if (delegateValue == null) - { - dither.state = -2; - return dither; - } - - var display = currentDisplay ?? GetCurrentDisplay(); - if (display == null) - { - dither.state = -1; - return dither; - } - - var displayDevice = display.DisplayDevice; - var displayId = displayDevice.DisplayId; - - var result = delegateValue(displayId, ref dither); - if (result != 0) - { - Logger.Error($"Could not get dithering because NvAPI_Disp_GetDitherControl returned a non-zero return code: {result}"); - dither.state = -1; - } - - return dither; - } - - public bool SetMode(VirtualResolution resolution = null, Rational refreshRate = null, bool updateRegistry = false, NvPreset preset = null) - { - var display = preset == null ? GetCurrentDisplay() : GetPresetDisplay(preset); - if (display == null) - { - return false; - } - - return SetMode(display.Name, resolution, refreshRate, updateRegistry); - } - - public bool SetMode(DisplayConfig displayConfig, bool updateRegistry = false, NvPreset preset = null) - { - var display = preset == null ? GetCurrentDisplay() : GetPresetDisplay(preset); - if (display == null) - { - return false; - } - - return SetMode(display.Name, displayConfig, updateRegistry); - } - - public List GetAvailableRefreshRatesV2(NvPreset preset = null) - { - if (preset != null) - { - SetCurrentDisplay(preset); - } - - var display = GetCurrentDisplay(false); - if (display == null) - { - return []; - } - - var desktopRect = preset?.DisplayConfig.ApplyResolution == true && preset?.DisplayConfig.Resolution.ActiveWidth > 0 ? - new Rectangle(0, 0, (int)preset.DisplayConfig.Resolution.ActiveWidth, (int)preset.DisplayConfig.Resolution.ActiveHeight) : - GetDesktopRect(display); - - return GetAvailableRefreshRatesV2(display.Name, desktopRect.Width, desktopRect.Height); - } - - public List GetAvailableResolutionsV2(NvPreset preset = null) - { - if (preset != null) - { - SetCurrentDisplay(preset); - } - - var display = GetCurrentDisplay(false); - if (display == null) - { - return []; - } - - return GetAvailableResolutionsInternalV2(display.Name); - } - - private Rectangle GetDesktopRect(Display display) - { - try - { - return display.DisplayDevice.ScanOutInformation.SourceDesktopRectangle; - } - catch (Exception) - { - var timing = display.DisplayDevice.CurrentTiming; - - return new Rectangle(0, 0, timing.HorizontalActive, timing.VerticalActive); - } - } - - private bool IsDisplayInPortraitMode(Display display) - { - try - { - return new[] { Rotate.Degree90, Rotate.Degree270 }.Contains(display.DisplayDevice.ScanOutInformation.SourceToTargetRotation); - } - catch (Exception) - { - return false; - } - } - - public bool IsHDREnabled(Display currentDisplay = null) - { - var display = currentDisplay ?? GetCurrentDisplay(); - if (display == null) - { - return false; - } - - var displayDevice = display.DisplayDevice; - var hdr = Logger.Swallow(() => displayDevice.HDRColorData?.HDRMode == ColorDataHDRMode.UHDA); - return hdr; - } - - public void SetHdmiSettings(Display display, NvHdmiInfoFrameSettings settings) - { - var displayDevice = display.DisplayDevice; - - var info = displayDevice.HDMIVideoFrameOverrideInformation ?? displayDevice.HDMIVideoFrameCurrentInformation; - - if (!info.HasValue) - { - return; - } - - var infoValue = info.Value; - - var newInfo = new InfoFrameVideo( - infoValue.VideoIdentificationCode ?? 0xFF, - InfoFrameVideoPixelRepetition.None, - settings.ColorFormat ?? infoValue.ColorFormat, - settings.Colorimetry ?? infoValue.Colorimetry, - settings.ExtendedColorimetry ?? infoValue.ExtendedColorimetry ?? InfoFrameVideoExtendedColorimetry.Auto, - settings.RGBQuantization ?? infoValue.RGBQuantization, - settings.YCCQuantization ?? infoValue.YCCQuantization, - settings.ContentMode ?? infoValue.ContentMode, - settings.ContentType ?? infoValue.ContentType, - InfoFrameVideoScanInfo.NoData, - InfoFrameBoolean.Auto, - InfoFrameVideoAspectRatioActivePortion.Auto, - InfoFrameVideoAspectRatioCodedFrame.Auto, - InfoFrameVideoNonUniformPictureScaling.NoData, - InfoFrameVideoBarData.NotPresent, - null, - null, - null, - null - ); - - displayDevice.SetHDMIVideoFrameInformation(newInfo, true); - } - - public void SetHDMIContentType(Display display, InfoFrameVideoContentType contentType) - { - var displayDevice = display.DisplayDevice; - - var info = displayDevice.HDMIVideoFrameCurrentInformation; - - if (info.HasValue) - { - var infoValue = info.Value; - - infoValue.SetContentType(contentType); - - displayDevice.SetHDMIVideoFrameInformation(infoValue, true); - } - } - - public InfoFrameVideoContentType GetHDMIContentType(Display display) - { - var info = GetInfoFrameVideo(display); - - return info.HasValue ? info.Value.ContentType : InfoFrameVideoContentType.Auto; - } - - public NvHdmiInfoFrameSettings GetHdmiSettings(Display display) - { - var info = GetInfoFrameVideo(display); - - if (!info.HasValue) - { - return new NvHdmiInfoFrameSettings(); - } - - var infoValue = info.Value; - - return new NvHdmiInfoFrameSettings - { - ColorFormat = infoValue.ColorFormat, - Colorimetry = infoValue.Colorimetry, - ExtendedColorimetry = infoValue.ExtendedColorimetry, - RGBQuantization = infoValue.RGBQuantization, - YCCQuantization = infoValue.YCCQuantization, - ContentMode = infoValue.ContentMode, - ContentType = infoValue.ContentType - }; - } + if (setRegistryKey) + { + var info = CCD.GetDisplayInfo(display.Name); + var regId = info?.DisplayId; + + if (regId.IsNullOrEmpty()) + { + return false; + } + + result = SetDitherRegistryKey(regId, (uint)state, bits, mode); + + if (restartDriver) + { + RestartDriver(); + } + } + else + { + var delegateValue = DelegateFactory.GetDelegate(); + + if (delegateValue == null) + { + return false; + } + + var resultValue = delegateValue(gpuHandle, displayId, (uint)state, bits, mode); + if (resultValue != 0) + { + Logger.Error($"Could not set dithering because NvAPI_Disp_SetDitherControl returned a non-zero return code: {resultValue}"); + result = false; + } + } + + return result; + } + + public bool RestartDriver() + { + if (!_winApiService.IsAdministrator()) + { + return _rpcClientService.Call(nameof(RestartDriver)); + } + + var restartDelegate = DelegateFactory.GetDelegate(); + + if (restartDelegate != null) + { + restartDelegate(); + + return true; + } + + return false; + } + + public NV_GPU_DITHER_CONTROL_V1 GetDithering(Display currentDisplay = null) + { + var version = MAKE_NVAPI_VERSION(1); + var dither = new NV_GPU_DITHER_CONTROL_V1 { version = version }; + + var delegateValue = DelegateFactory.GetDelegate(); + + if (delegateValue == null) + { + dither.state = -2; + return dither; + } + + var display = currentDisplay ?? GetCurrentDisplay(); + if (display == null) + { + dither.state = -1; + return dither; + } + + var displayDevice = display.DisplayDevice; + var displayId = displayDevice.DisplayId; + + var result = delegateValue(displayId, ref dither); + if (result != 0) + { + Logger.Error($"Could not get dithering because NvAPI_Disp_GetDitherControl returned a non-zero return code: {result}"); + dither.state = -1; + } + + return dither; + } + + public bool SetMode(VirtualResolution resolution = null, Rational refreshRate = null, bool updateRegistry = false, NvPreset preset = null) + { + var display = preset == null ? GetCurrentDisplay() : GetPresetDisplay(preset); + if (display == null) + { + return false; + } + + return SetMode(display.Name, resolution, refreshRate, updateRegistry); + } + + public bool SetMode(DisplayConfig displayConfig, bool updateRegistry = false, NvPreset preset = null) + { + var display = preset == null ? GetCurrentDisplay() : GetPresetDisplay(preset); + if (display == null) + { + return false; + } + + return SetMode(display.Name, displayConfig, updateRegistry); + } + + public List GetAvailableRefreshRatesV2(NvPreset preset = null) + { + if (preset != null) + { + SetCurrentDisplay(preset); + } + + var display = GetCurrentDisplay(false); + if (display == null) + { + return []; + } + + var desktopRect = preset?.DisplayConfig.ApplyResolution == true && preset?.DisplayConfig.Resolution.ActiveWidth > 0 ? + new Rectangle(0, 0, (int)preset.DisplayConfig.Resolution.ActiveWidth, (int)preset.DisplayConfig.Resolution.ActiveHeight) : + GetDesktopRect(display); + + return GetAvailableRefreshRatesV2(display.Name, desktopRect.Width, desktopRect.Height); + } + + public List GetAvailableResolutionsV2(NvPreset preset = null) + { + if (preset != null) + { + SetCurrentDisplay(preset); + } + + var display = GetCurrentDisplay(false); + if (display == null) + { + return []; + } + + return GetAvailableResolutionsInternalV2(display.Name); + } + + private Rectangle GetDesktopRect(Display display) + { + try + { + return display.DisplayDevice.ScanOutInformation.SourceDesktopRectangle; + } + catch (Exception) + { + var timing = display.DisplayDevice.CurrentTiming; + + return new Rectangle(0, 0, timing.HorizontalActive, timing.VerticalActive); + } + } + + private bool IsDisplayInPortraitMode(Display display) + { + try + { + return new[] { Rotate.Degree90, Rotate.Degree270 }.Contains(display.DisplayDevice.ScanOutInformation.SourceToTargetRotation); + } + catch (Exception) + { + return false; + } + } + + public bool IsHDREnabled(Display currentDisplay = null) + { + var display = currentDisplay ?? GetCurrentDisplay(); + if (display == null) + { + return false; + } + + var displayDevice = display.DisplayDevice; + var hdr = Logger.Swallow(() => displayDevice.HDRColorData?.HDRMode == ColorDataHDRMode.UHDA); + return hdr; + } + + public void SetHdmiSettings(Display display, NvHdmiInfoFrameSettings settings) + { + var displayDevice = display.DisplayDevice; + + var info = displayDevice.HDMIVideoFrameOverrideInformation ?? displayDevice.HDMIVideoFrameCurrentInformation; + + if (!info.HasValue) + { + return; + } + + var infoValue = info.Value; + + var newInfo = new InfoFrameVideo( + infoValue.VideoIdentificationCode ?? 0xFF, + InfoFrameVideoPixelRepetition.None, + settings.ColorFormat ?? infoValue.ColorFormat, + settings.Colorimetry ?? infoValue.Colorimetry, + settings.ExtendedColorimetry ?? infoValue.ExtendedColorimetry ?? InfoFrameVideoExtendedColorimetry.Auto, + settings.RGBQuantization ?? infoValue.RGBQuantization, + settings.YCCQuantization ?? infoValue.YCCQuantization, + settings.ContentMode ?? infoValue.ContentMode, + settings.ContentType ?? infoValue.ContentType, + InfoFrameVideoScanInfo.NoData, + InfoFrameBoolean.Auto, + InfoFrameVideoAspectRatioActivePortion.Auto, + InfoFrameVideoAspectRatioCodedFrame.Auto, + InfoFrameVideoNonUniformPictureScaling.NoData, + InfoFrameVideoBarData.NotPresent, + null, + null, + null, + null + ); + + displayDevice.SetHDMIVideoFrameInformation(newInfo, true); + } + + public void SetHDMIContentType(Display display, InfoFrameVideoContentType contentType) + { + var displayDevice = display.DisplayDevice; + + var info = displayDevice.HDMIVideoFrameCurrentInformation; + + if (info.HasValue) + { + var infoValue = info.Value; + + infoValue.SetContentType(contentType); + + displayDevice.SetHDMIVideoFrameInformation(infoValue, true); + } + } + + public InfoFrameVideoContentType GetHDMIContentType(Display display) + { + var info = GetInfoFrameVideo(display); + + return info.HasValue ? info.Value.ContentType : InfoFrameVideoContentType.Auto; + } + + public NvHdmiInfoFrameSettings GetHdmiSettings(Display display) + { + var info = GetInfoFrameVideo(display); + + if (!info.HasValue) + { + return new NvHdmiInfoFrameSettings(); + } + + var infoValue = info.Value; + + return new NvHdmiInfoFrameSettings + { + ColorFormat = infoValue.ColorFormat, + Colorimetry = infoValue.Colorimetry, + ExtendedColorimetry = infoValue.ExtendedColorimetry, + RGBQuantization = infoValue.RGBQuantization, + YCCQuantization = infoValue.YCCQuantization, + ContentMode = infoValue.ContentMode, + ContentType = infoValue.ContentType + }; + } - private static InfoFrameVideo? GetInfoFrameVideo(Display display) - { - var displayDevice = display.DisplayDevice; + private static InfoFrameVideo? GetInfoFrameVideo(Display display) + { + var displayDevice = display.DisplayDevice; - if (displayDevice.ConnectionType != NvAPIWrapper.Native.GPU.MonitorConnectionType.HDMI) - { - return null; - } + if (displayDevice.ConnectionType != NvAPIWrapper.Native.GPU.MonitorConnectionType.HDMI) + { + return null; + } - return Logger.Swallow(() => displayDevice.HDMIVideoFrameOverrideInformation) ?? Logger.Swallow(() => displayDevice.HDMIVideoFrameCurrentInformation); - } + return Logger.Swallow(() => displayDevice.HDMIVideoFrameOverrideInformation) ?? Logger.Swallow(() => displayDevice.HDMIVideoFrameCurrentInformation); + } - public Scaling GetScaling(Display display) - { - var pathTargetInfo = GetTargetInfoForDisplay(display); + public Scaling GetScaling(Display display) + { + var pathTargetInfo = GetTargetInfoForDisplay(display); - if (pathTargetInfo?.Details == null) - { - return Scaling.Default; - } + if (pathTargetInfo?.Details == null) + { + return Scaling.Default; + } - var details = pathTargetInfo.Details.Value; + var details = pathTargetInfo.Details.Value; - return details.Scaling; - } + return details.Scaling; + } - public void SetScaling(Display display, Scaling scaling) - { - var pathInfos = DisplayApi.GetDisplayConfig().ToList(); + public void SetScaling(Display display, Scaling scaling) + { + var pathInfos = DisplayApi.GetDisplayConfig().ToList(); - var pathInfo = pathInfos.FirstOrDefault(c => c.TargetsInfo.Any(ti => ti.DisplayId == display.DisplayDevice.DisplayId)); - var pathInfoIndex = pathInfos.IndexOf(pathInfo); + var pathInfo = pathInfos.FirstOrDefault(c => c.TargetsInfo.Any(ti => ti.DisplayId == display.DisplayDevice.DisplayId)); + var pathInfoIndex = pathInfos.IndexOf(pathInfo); - var pathTargetInfo = pathInfo.TargetsInfo.FirstOrDefault(ti => ti.DisplayId == display.DisplayDevice.DisplayId); + var pathTargetInfo = pathInfo.TargetsInfo.FirstOrDefault(ti => ti.DisplayId == display.DisplayDevice.DisplayId); - if (pathTargetInfo?.Details == null) - { - return; - } + if (pathTargetInfo?.Details == null) + { + return; + } - var details = pathTargetInfo.Details.Value; + var details = pathTargetInfo.Details.Value; - var newDetails = new PathAdvancedTargetInfo(details.Rotation, scaling); + var newDetails = new PathAdvancedTargetInfo(details.Rotation, scaling); - var newPathTargetInfo = new PathTargetInfoV2(pathTargetInfo.DisplayId, newDetails); + var newPathTargetInfo = new PathTargetInfoV2(pathTargetInfo.DisplayId, newDetails); - var newPathInfo = new PathInfoV2(new[] { newPathTargetInfo }, pathInfo.SourceModeInfo); + var newPathInfo = new PathInfoV2(new[] { newPathTargetInfo }, pathInfo.SourceModeInfo); - var newPathInfos = pathInfos.ToArray(); - newPathInfos[pathInfoIndex] = newPathInfo; + var newPathInfos = pathInfos.ToArray(); + newPathInfos[pathInfoIndex] = newPathInfo; - DisplayApi.SetDisplayConfig(newPathInfos, DisplayConfigFlags.SaveToPersistence); - } + DisplayApi.SetDisplayConfig(newPathInfos, DisplayConfigFlags.SaveToPersistence); + } - private IPathTargetInfo? GetTargetInfoForDisplay(Display display) - { - var pathInfos = DisplayApi.GetDisplayConfig(); + private IPathTargetInfo? GetTargetInfoForDisplay(Display display) + { + var pathInfos = DisplayApi.GetDisplayConfig(); - var pathInfo = pathInfos.FirstOrDefault(c => c.TargetsInfo.Any(ti => ti.DisplayId == display.DisplayDevice.DisplayId)); + var pathInfo = pathInfos.FirstOrDefault(c => c.TargetsInfo.Any(ti => ti.DisplayId == display.DisplayDevice.DisplayId)); - if (pathInfo == null) - { - return null; - } + if (pathInfo == null) + { + return null; + } - var pathTargetInfo = pathInfo.TargetsInfo.FirstOrDefault(ti => ti.DisplayId == display.DisplayDevice.DisplayId); + var pathTargetInfo = pathInfo.TargetsInfo.FirstOrDefault(ti => ti.DisplayId == display.DisplayDevice.DisplayId); - return pathTargetInfo; - } + return pathTargetInfo; + } - private IPathInfo? GetPathInfoForDisplay(Display display) - { - var pathInfos = DisplayApi.GetDisplayConfig(); + private IPathInfo? GetPathInfoForDisplay(Display display) + { + var pathInfos = DisplayApi.GetDisplayConfig(); - return pathInfos.FirstOrDefault(c => c.TargetsInfo.Any(ti => ti.DisplayId == display.DisplayDevice.DisplayId)); - } + return pathInfos.FirstOrDefault(c => c.TargetsInfo.Any(ti => ti.DisplayId == display.DisplayDevice.DisplayId)); + } - public void SetColorProfile(Display display, string name) - { - CCD.SetDisplayDefaultColorProfile(display.Name, name, _globalContext.Config.SetMinTmlAndMaxTml); - } + public void SetColorProfile(Display display, string name) + { + CCD.SetDisplayDefaultColorProfile(display.Name, name, _globalContext.Config.SetMinTmlAndMaxTml); + } - public void TestResolution() - { - //CCD.SetDisplayConfig(); + public void TestResolution() + { + //CCD.SetDisplayConfig(); - //var dxWrapper = new DXWrapper(); + //var dxWrapper = new DXWrapper(); - //dxWrapper.Test(); + //dxWrapper.Test(); - //var display = GetCurrentDisplay(); + //var display = GetCurrentDisplay(); - //var configs = DisplayApi.GetDisplayConfig(); + //var configs = DisplayApi.GetDisplayConfig(); - //var displayDevice = display.DisplayDevice; + //var displayDevice = display.DisplayDevice; - //var output = displayDevice.Output; - //var bytes = File.ReadAllBytes(@"d:\S95C_mod.bin"); + //var output = displayDevice.Output; + //var bytes = File.ReadAllBytes(@"d:\S95C_mod.bin"); - //displayDevice.PhysicalGPU.WriteEDIDData(output, bytes); + //displayDevice.PhysicalGPU.WriteEDIDData(output, bytes); - //SetDithering(NvDitherState.Enabled, 1, 4, setRegistryKey: true); + //SetDithering(NvDitherState.Enabled, 1, 4, setRegistryKey: true); - //GetHdrMetaData(); + //GetHdrMetaData(); - //SetOutputMode(NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_HDR10PLUS_GAMING); + //SetOutputMode(NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_HDR10PLUS_GAMING); - //var display = GetCurrentDisplay(); + //var display = GetCurrentDisplay(); - //CCD.GetUsePerUserDisplayProfiles(display.Name); + //CCD.GetUsePerUserDisplayProfiles(display.Name); - //CCD.GetDisplayColorProfiles(display.Name); + //CCD.GetDisplayColorProfiles(display.Name); - //CCD.InstallColorProfile(@"H:\srgb2000.icm"); + //CCD.InstallColorProfile(@"H:\srgb2000.icm"); - //CCD.AddDisplayColorProfile(display.Name, "srgb2000.icm"); + //CCD.AddDisplayColorProfile(display.Name, "srgb2000.icm"); - //CCD.SetDisplayDefaultColorProfile(display.Name, "srgb2000.icm"); + //CCD.SetDisplayDefaultColorProfile(display.Name, "srgb2000.icm"); - //var displayDevice = display.DisplayDevice; + //var displayDevice = display.DisplayDevice; - //var config = DisplayApi.GetDisplayConfig(); + //var config = DisplayApi.GetDisplayConfig(); - //var config1 = config[0]; + //var config1 = config[0]; - //var pathInfo1 = config1.TargetsInfo.First(); + //var pathInfo1 = config1.TargetsInfo.First(); - //var details = pathInfo1.Details.Value; + //var details = pathInfo1.Details.Value; - //var newDetails = new PathAdvancedTargetInfo(details.Rotation, Scaling.GPUScanOutToNative); + //var newDetails = new PathAdvancedTargetInfo(details.Rotation, Scaling.GPUScanOutToNative); - //var newPathTargetInfo = new PathTargetInfoV2(pathInfo1.DisplayId, newDetails); + //var newPathTargetInfo = new PathTargetInfoV2(pathInfo1.DisplayId, newDetails); - //var newPathInfo = new PathInfoV2(new[] { newPathTargetInfo }, config1.SourceModeInfo); + //var newPathInfo = new PathInfoV2(new[] { newPathTargetInfo }, config1.SourceModeInfo); - //DisplayApi.SetDisplayConfig(new IPathInfo[] { newPathInfo }, DisplayConfigFlags.SaveToPersistence); + //DisplayApi.SetDisplayConfig(new IPathInfo[] { newPathInfo }, DisplayConfigFlags.SaveToPersistence); - //var info = DisplayApi.GetScanOutConfiguration(displayDevice.DisplayId); + //var info = DisplayApi.GetScanOutConfiguration(displayDevice.DisplayId); - //var vertices = new float[] { - // 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - // 0.0f, 2160.0f, 0.0f, 2160.0f, 0.0f, 0.0f, - // 3840.0f, 0.0f, 3840.0f, 0.0f, 0.0f, 0.0f, - // 3840.0f, 2160.0f, 3840.0f, 2160.0f, 0.0f, 0.0f, - //}; + //var vertices = new float[] { + // 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + // 0.0f, 2160.0f, 0.0f, 2160.0f, 0.0f, 0.0f, + // 3840.0f, 0.0f, 3840.0f, 0.0f, 0.0f, 0.0f, + // 3840.0f, 2160.0f, 3840.0f, 2160.0f, 0.0f, 0.0f, + //}; - //var warp = new ScanOutWarpingV1(WarpingVerticeFormat.TriangleStripXYUVRQ, vertices, info.TargetViewPortRectangle); - //var verticesCount = 4; - //var isSticky = false; + //var warp = new ScanOutWarpingV1(WarpingVerticeFormat.TriangleStripXYUVRQ, vertices, info.TargetViewPortRectangle); + //var verticesCount = 4; + //var isSticky = false; - //DisplayApi.SetScanOutWarping(displayDevice.DisplayId, warp, ref verticesCount, out isSticky); + //DisplayApi.SetScanOutWarping(displayDevice.DisplayId, warp, ref verticesCount, out isSticky); - //var timing = displayDevice.CurrentTiming; + //var timing = displayDevice.CurrentTiming; - //var res = new CustomResolution(3840, 2160, ColorFormat.A8R8G8B8, timing); + //var res = new CustomResolution(3840, 2160, ColorFormat.A8R8G8B8, timing); - //displayDevice.TrialCustomResolution(res); + //displayDevice.TrialCustomResolution(res); - //var hdrColorData = displayDevice.HDRColorData; - //var mastering = hdrColorData.MasteringDisplayData; + //var hdrColorData = displayDevice.HDRColorData; + //var mastering = hdrColorData.MasteringDisplayData; - //var newMastering = new MasteringDisplayColorData( - // new ColorDataColorCoordinate(0.2f, 0.2f), - // mastering.SecondColorCoordinate, - // mastering.ThirdColorCoordinate, - // mastering.WhiteColorCoordinate, - // 120, - // mastering.MinimumMasteringLuminance, - // mastering.MaximumContentLightLevel, - // mastering.MaximumFrameAverageLightLevel); + //var newMastering = new MasteringDisplayColorData( + // new ColorDataColorCoordinate(0.2f, 0.2f), + // mastering.SecondColorCoordinate, + // mastering.ThirdColorCoordinate, + // mastering.WhiteColorCoordinate, + // 120, + // mastering.MinimumMasteringLuminance, + // mastering.MaximumContentLightLevel, + // mastering.MaximumFrameAverageLightLevel); - //var newHdrColorData = new HDRColorData(hdrColorData.HDRMode, newMastering); + //var newHdrColorData = new HDRColorData(hdrColorData.HDRMode, newMastering); - //displayDevice.SetHDRColorData(newHdrColorData); + //displayDevice.SetHDRColorData(newHdrColorData); - //var info = displayDevice.HDMIVideoFrameOverrideInformation ?? displayDevice.HDMIVideoFrameCurrentInformation; + //var info = displayDevice.HDMIVideoFrameOverrideInformation ?? displayDevice.HDMIVideoFrameCurrentInformation; - //if (info.HasValue) - //{ - // var infoValue = info.Value; + //if (info.HasValue) + //{ + // var infoValue = info.Value; - // var newInfo = new InfoFrameVideo( - // infoValue.VideoIdentificationCode.Value, - // InfoFrameVideoPixelRepetition.None, - // InfoFrameVideoColorFormat.RGB, - // InfoFrameVideoColorimetry.UseExtendedColorimetry, - // InfoFrameVideoExtendedColorimetry.BT2020, - // infoValue.RGBQuantization, - // infoValue.YCCQuantization, - // InfoFrameVideoITC.ITContent, - // infoValue.ContentType, - // InfoFrameVideoScanInfo.NoData, - // InfoFrameBoolean.Auto, - // InfoFrameVideoAspectRatioActivePortion.Auto, - // InfoFrameVideoAspectRatioCodedFrame.Auto, - // InfoFrameVideoNonUniformPictureScaling.NoData, - // InfoFrameVideoBarData.NotPresent, - // null, - // null, - // null, - // null - // ); + // var newInfo = new InfoFrameVideo( + // infoValue.VideoIdentificationCode.Value, + // InfoFrameVideoPixelRepetition.None, + // InfoFrameVideoColorFormat.RGB, + // InfoFrameVideoColorimetry.UseExtendedColorimetry, + // InfoFrameVideoExtendedColorimetry.BT2020, + // infoValue.RGBQuantization, + // infoValue.YCCQuantization, + // InfoFrameVideoITC.ITContent, + // infoValue.ContentType, + // InfoFrameVideoScanInfo.NoData, + // InfoFrameBoolean.Auto, + // InfoFrameVideoAspectRatioActivePortion.Auto, + // InfoFrameVideoAspectRatioCodedFrame.Auto, + // InfoFrameVideoNonUniformPictureScaling.NoData, + // InfoFrameVideoBarData.NotPresent, + // null, + // null, + // null, + // null + // ); - // displayDevice.SetHDMIVideoFrameInformation(newInfo, true); - //} - } + // displayDevice.SetHDMIVideoFrameInformation(newInfo, true); + //} + } - public Display[] GetDisplays() - { - return Display.GetDisplays(); - } + public Display[] GetDisplays() + { + return Display.GetDisplays(); + } - public List GetGPUs() - { - var gpuHandles = GPUApi.EnumPhysicalGPUs(); + public List GetGPUs() + { + var gpuHandles = GPUApi.EnumPhysicalGPUs(); - var gpus = gpuHandles.Select(h => new PhysicalGPU(h)).ToList(); + var gpus = gpuHandles.Select(h => new PhysicalGPU(h)).ToList(); - return gpus; - } + return gpus; + } - public List GetSimpleDisplayInfos() - { - var displays = GetDisplays(); - var list = new List(); - - foreach (var display in displays) - { - var displayInfo = new NvDisplayInfo(display, null, null); - - list.Add(displayInfo); - } - - return list; - } - - public List GetDisplayInfos(bool refreshSettings = true) - { - try - { - var list = new List(); - - if (refreshSettings) - { - RefreshProfileSettings(); - } - - var displayInfos = GetSimpleDisplayInfos(); - - foreach (var displayInfo in displayInfos) - { - var preset = GetPresetForDisplay(displayInfo, true, displayInfos.Count()); - var values = preset.GetDisplayValues(_globalContext.Config); - - displayInfo.Values = values; - displayInfo.InfoLine = preset.InfoLine; - - list.Add(displayInfo); - } - - var notifyIconManager = _globalContext.ServiceProvider.GetService(); - - if (notifyIconManager != null) - { - notifyIconManager.SetText(string.Join("\n", list.Select(i => i.InfoLine))); - } - - return list; - } - catch (Exception e) - { - Logger.Error("Error while getting displays: " + e.ToLogString()); - return null; - } - } - - public List GetDisplayPresets() - { - try - { - var list = new List(); - - var displayInfos = GetSimpleDisplayInfos(); - - foreach (var displayInfo in displayInfos) - { - var preset = GetPresetForDisplay(displayInfo, true, displayInfos.Count()); - preset.MonitorConnectionType = preset?.Display?.DisplayDevice?.ConnectionType ?? NvAPIWrapper.Native.GPU.MonitorConnectionType.Unknown; - list.Add(preset); - } - - return list; - } - catch (Exception e) - { - Logger.Error("Error while getting displays: " + e.ToLogString()); - return null; - } - } - - public NvPreset GetPresetForDisplay(string name, bool driverSettings = false) - { - var displays = GetSimpleDisplayInfos(); - var display = displays.FirstOrDefault(d => name.StartsWith(d.Name)); - - return GetPresetForDisplay(display, driverSettings, displays.Count()); - } - - public NvPreset GetPresetForDisplay(NvDisplayInfo displayInfo, bool driverSettings = false, int displayCount = 1) - { - if (displayInfo == null) - { - return null; - } - - var display = displayInfo.Display; - - var isPrimaryDisplay = displayCount == 1 || display.DisplayDevice.DisplayId == DisplayDevice.GetGDIPrimaryDisplayDevice()?.DisplayId; - var preset = new NvPreset { Display = display, IsDisplayPreset = true, applyColorData = false, primaryDisplay = isPrimaryDisplay }; - - preset.HDREnabled = IsHDREnabled(display); - preset.HdrSettings.OutputMode = preset.HDREnabled && OutputModeAvailable ? GetOutputMode(display) : null; - - preset.DisplayId = displayInfo.DisplayId; - preset.displayName = displayInfo.Name; - preset.colorData = GetCurrentColorData(display); - preset.ColorEnhancementSettings = GetCurrentColorEnhancements(display); - preset.HdmiInfoFrameSettings = GetHdmiSettings(display); - preset.SDRBrightness = GetSDRBrightness(display.Name); - preset.scaling = GetScaling(display); - preset.ColorProfileSettings.ProfileName = CCD.GetDisplayDefaultColorProfile(display.Name, preset.HDREnabled ? COLORPROFILESUBTYPE.CPST_EXTENDED_DISPLAY_COLOR_MODE : COLORPROFILESUBTYPE.CPST_STANDARD_DISPLAY_COLOR_MODE); - - preset.DisplayConfig = CCD.GetDisplayConfig(display.Name); - - var ditherInfo = GetDithering(display); - - if (ditherInfo.state == -1) - { - preset.ditheringEnabled = true; - preset.ditheringBits = (uint)NvDitherBits.Bits8; - preset.ditheringMode = (uint)NvDitherMode.Temporal; - } - else - { - preset.ditheringEnabled = ditherInfo.state == 0 ? null : ditherInfo.state != (int)NvDitherState.Disabled; - preset.ditheringBits = (uint)ditherInfo.bits; - preset.ditheringMode = (uint)ditherInfo.mode; - } - - if (Config.ShowOverclocking) - { - var gpus = GetGPUs(); - - foreach (var gpu in gpus) - { - var gpuInfo = NvGpuInfo.GetGpuInfo(gpu); - - var settings = gpuInfo.GetOverclockSettings(); - - preset.ocSettings.Add(settings); - } - } - - if (driverSettings) - { - var settings = GetVisibleSettings(); - - foreach (var setting in settings) - { - var settingMeta = GetSettingMeta(setting.SettingId); - - if (settingMeta == null) - { - continue; - } - - var (presetSetting, isDefault, _) = settingMeta.ToIntValue(setting.ValueText); - - if (isDefault) - { - continue; - } - - preset.driverSettings.Add(setting.SettingId, presetSetting); - } - } - - return preset; - } - - private NvColorEnhancementSettings GetCurrentColorEnhancements(Display display) - { - return new NvColorEnhancementSettings - { - DigitalVibranceLevel = GetDigitalVibranceLevel(display), - HueAngle = GetHueAngle(display) - }; - } - - public List GetVisibleSettings() - { - return GetSettings().Where(s => _driverSettingIds.Contains(s.SettingId)).ToList(); - } - - public SettingMeta GetSettingMeta(uint settingId) - { - return _meta.GetSettingMeta(settingId); - } - - public List GetDriverSettings(string profileName = null) - { - if (profileName == null) - { - _drs.GetProfileNames(ref profileName, false); - } - - var applications = new Dictionary(); - var settings = profileName == null ? GetVisibleSettings() : _drs.GetSettingsForProfile(profileName, SettingViewMode.Normal, ref applications, true); - - return settings.Where(s => s.GroupName != null).Select(s => - { - var settingMeta = _meta.GetSettingMeta(s.SettingId); - var intValue = settingMeta.ToIntValue(s.ValueText); - var type = settingMeta.SettingType == nspector.Native.NVAPI2.NVDRS_SETTING_TYPE.NVDRS_BINARY_TYPE ? NvSettingType.BinaryType : NvSettingType.DwordType; - var values = type == NvSettingType.BinaryType ? - settingMeta.BinaryValues?.Select(bv => new NvSettingItemValue { Value = BitConverter.ToUInt32(bv.Value), ValueName = bv.ValueName }) : - settingMeta.DwordValues?.Select(bv => new NvSettingItemValue { Value = bv.Value, ValueName = bv.ValueName }); - - return new NvSettingItemDto - { - GroupName = s.GroupName, - IsApiExposed = s.IsApiExposed, - IsSettingHidden = s.IsSettingHidden, - IsStringValue = s.IsStringValue, - SettingId = s.SettingId, - SettingText = s.SettingText, - State = (int)s.State, - ValueRaw = s.ValueRaw, - ValueText = s.ValueText, - Value = intValue.intValue, - DefaultValue = intValue.defaultValue, - SettingType = type, - Values = values?.ToList() - }; - }).ToList(); - } - - public List GetDriverProfileNames() - { - var baseProfileName = ""; - - return DrsServiceLocator.SettingService.GetProfileNames(ref baseProfileName).Where(s => !s.StartsWith("0x")).OrderBy(s => s).ToList(); - } - - public bool IsGsyncEnabled() - { - var setting = GetSettings().FirstOrDefault(s => s.SettingId == NvSettingConstants.DRS_GSYNC_APPLICATION_MODE); - if (setting == null) - { - return false; - } - - var settingMeta = GetSettingMeta(setting.SettingId); - var settingValue = settingMeta.DwordValues?.FirstOrDefault(s => s.ValueName == setting.ValueText); - - return settingValue.Value >= 1; - } - - protected List GetSettings() - { - _semaphore.Wait(); - try - { - if (!_settings.Any()) - { - RefreshProfileSettings(); - } - - return _settings; - } - finally - { - _semaphore.Release(); - } - } - - protected override void Initialize() - { - NvAPIWrapper.NVIDIA.Initialize(); - _initialized = true; - - var version = default(string); - DriverVersion = GeneralApi.GetDriverAndBranchVersion(out version); - - _drs = DrsServiceLocator.SettingService; - _meta = DrsServiceLocator.MetaService; - - _drs.GetProfileNames(ref _baseProfileName, false); - - //if (!WinApiService.IsAdministratorStatic()) - //{ - _drs.ApplySettings += HandleDrsApplySettings; - _drs.RestoreSetting += HandleDrsRestoreSetting; - //} - - //SetGpuClocks(); - - //Task.Run(() => - //{ - // RefreshProfileSettings(); - //}); - } - - public void RefreshProfileSettings() - { - _refreshSemaphore.Wait(); - try - { - var firstTime = _settings?.Any() != true; - - DrsSessionScope.DestroyGlobalSession(); - - var applications = default(Dictionary); - var normalSettings = _drs.GetSettingsForProfile(_baseProfileName, SettingViewMode.IncludeScannedSetttings, ref applications, true); - - _settings = new List(normalSettings); - - _driverSettingIds.Clear(); - _driverSettingIds.AddRange(_settings.Where(s => !s.IsStringValue && !s.SettingText.Contains("SLI") && s.GroupName != null && s.GroupName != "Unknown").Select(s => s.SettingId)); - - if (firstTime) - { - DrsServiceLocator.ScannerService.ScanProfileSettings(false, null); - _meta.ResetMetaCache(); - } - } - finally - { - _refreshSemaphore.Release(); - } - } - - private bool HasPrivilegesForUnexposedApis() - { - return _winApiService.IsAdministrator() || !_winApiService.IsServiceRunning(); - } - - private void HandleDrsApplySettings(object sender, DrsEvent drsEvent) - { - if (HasPrivilegesForUnexposedApis()) - { - return; - } - - var message = new SvcRpcSetNvDriverSettingsMessage - { - MethodName = nameof(ApplyDriverSettings), - ProfileName = drsEvent.ProfileName, - DriverSettings = drsEvent.Settings - }; - - _rpcClientService.Call(message); - - drsEvent.Handled = true; - } - - private void HandleDrsRestoreSetting(object sender, DrsEvent drsEvent) - { - if (HasPrivilegesForUnexposedApis()) - { - return; - } - - var message = new SvcRpcSetNvDriverSettingsMessage - { - MethodName = nameof(RestoreDriverSettings), - ProfileName = drsEvent.ProfileName, - DriverSettings = drsEvent.Settings - }; - - _rpcClientService.Call(message); - - drsEvent.Handled = true; - } - - protected override void Uninitialize() - { - if (_initialized) - { - NvAPIWrapper.NVIDIA.Unload(); - } - } - - private void LoadConfig() - { - _configFilename = Path.Combine(_dataPath, "NvConfig.json"); - try - { - if (File.Exists(_configFilename)) - { - Config = JsonConvert.DeserializeObject(File.ReadAllText(_configFilename)); - } - } - catch (Exception ex) - { - Logger.Error($"LoadConfig: {ex.Message}"); - } - Config ??= new NvServiceConfig(); - } - - private void SaveConfig() - { - Utils.WriteObject(_configFilename, Config); - } - - public NvServiceConfig GetConfig() - { - return Config; - } - - public bool UpdateConfig(NvServiceConfig config) - { - Config.Update(config); - - SetShortcuts(SHORTCUTID_NVQA, Config.QuickAccessShortcut); - - return true; - } - - internal Display ResolveDisplay(NvPreset preset) - { - if (preset.Display == null) - { - preset.Display = GetPresetDisplay(preset); - } - - return preset.Display; - } - - private async Task PowerModeResume(object sender, PowerStateChangedEventArgs e, CancellationToken _) - { - Logger.Debug($"PowerModeChanged: {e.State}"); - - // Wait - await Task.Delay(30000); - - await ExecutePresetsForEvent(PresetTriggerType.Resume); - } - - private void PowerModeChanged(object sender, PowerStateChangedEventArgs e) - { - Logger.Debug($"PowerModeChanged: {e.State}"); - - switch (e.State) - { - case PowerOnOffState.StandBy: - { - _ = ExecutePresetsForEvent(PresetTriggerType.Standby); - break; - } - case PowerOnOffState.ShutDown: - { - _ = ExecutePresetsForEvent(PresetTriggerType.Shutdown); - break; - } - } - } - - private async Task ExecutePresetsForEvent(PresetTriggerType triggerType) - { - Logger.Debug($"Executing presets for event {triggerType}"); - - var presets = _presets.Where(p => p.Triggers.Any(t => t.Trigger == triggerType)).ToList(); - - if (!presets.Any()) - { - return; - } - - await ExecuteEventPresets(_serviceManager, new[] { triggerType }).ConfigureAwait(true); - } - - private static uint MAKE_NVAPI_VERSION(int version) - { - return (uint)((Marshal.SizeOf(typeof(T))) | version << 16); - } - - private string GetDriverSettingsDescription(Dictionary driverSettings, bool useNewLines = false) - { - if (driverSettings.Count == 0) - { - return "None"; - } - - var values = new List(); - - foreach (var driverSetting in driverSettings) - { - var settingMeta = GetSettingMeta(driverSetting.Key); - - var value = settingMeta.ToFriendlyName(intValue: driverSetting.Value, displayDefault: true); - - if (value == null) - { - continue; - } - - values.Add($"{settingMeta.SettingName}: {value}"); - } - - return string.Join(useNewLines ? "\r\n" : ", ", values); - } - - } + public List GetSimpleDisplayInfos() + { + var displays = GetDisplays(); + var list = new List(); + + foreach (var display in displays) + { + var displayInfo = new NvDisplayInfo(display, null, null); + + list.Add(displayInfo); + } + + return list; + } + + public List GetDisplayInfos(bool refreshSettings = true) + { + try + { + var list = new List(); + + if (refreshSettings) + { + RefreshProfileSettings(); + } + + var displayInfos = GetSimpleDisplayInfos(); + + foreach (var displayInfo in displayInfos) + { + var preset = GetPresetForDisplay(displayInfo, true, displayInfos.Count()); + var values = preset.GetDisplayValues(_globalContext.Config); + + displayInfo.Values = values; + displayInfo.InfoLine = preset.InfoLine; + + list.Add(displayInfo); + } + + var notifyIconManager = _globalContext.ServiceProvider.GetService(); + + if (notifyIconManager != null) + { + notifyIconManager.SetText(string.Join("\n", list.Select(i => i.InfoLine))); + } + + return list; + } + catch (Exception e) + { + Logger.Error("Error while getting displays: " + e.ToLogString()); + return null; + } + } + + public List GetDisplayPresets() + { + try + { + var list = new List(); + + var displayInfos = GetSimpleDisplayInfos(); + + foreach (var displayInfo in displayInfos) + { + var preset = GetPresetForDisplay(displayInfo, true, displayInfos.Count()); + preset.MonitorConnectionType = preset?.Display?.DisplayDevice?.ConnectionType ?? NvAPIWrapper.Native.GPU.MonitorConnectionType.Unknown; + list.Add(preset); + } + + return list; + } + catch (Exception e) + { + Logger.Error("Error while getting displays: " + e.ToLogString()); + return null; + } + } + + public NvPreset GetPresetForDisplay(string name, bool driverSettings = false) + { + var displays = GetSimpleDisplayInfos(); + var display = displays.FirstOrDefault(d => name.StartsWith(d.Name)); + + return GetPresetForDisplay(display, driverSettings, displays.Count()); + } + + public NvPreset GetPresetForDisplay(NvDisplayInfo displayInfo, bool driverSettings = false, int displayCount = 1) + { + if (displayInfo == null) + { + return null; + } + + var display = displayInfo.Display; + + var isPrimaryDisplay = displayCount == 1 || display.DisplayDevice.DisplayId == DisplayDevice.GetGDIPrimaryDisplayDevice()?.DisplayId; + var preset = new NvPreset { Display = display, IsDisplayPreset = true, applyColorData = false, primaryDisplay = isPrimaryDisplay }; + + preset.HDREnabled = IsHDREnabled(display); + preset.HdrSettings.OutputMode = preset.HDREnabled && OutputModeAvailable ? GetOutputMode(display) : null; + + preset.DisplayId = displayInfo.DisplayId; + preset.displayName = displayInfo.Name; + preset.colorData = GetCurrentColorData(display); + preset.ColorEnhancementSettings = GetCurrentColorEnhancements(display); + preset.HdmiInfoFrameSettings = GetHdmiSettings(display); + preset.SDRBrightness = GetSDRBrightness(display.Name); + preset.scaling = GetScaling(display); + preset.ColorProfileSettings.ProfileName = CCD.GetDisplayDefaultColorProfile(display.Name, preset.HDREnabled ? COLORPROFILESUBTYPE.CPST_EXTENDED_DISPLAY_COLOR_MODE : COLORPROFILESUBTYPE.CPST_STANDARD_DISPLAY_COLOR_MODE); + + preset.DisplayConfig = CCD.GetDisplayConfig(display.Name); + + var ditherInfo = GetDithering(display); + + if (ditherInfo.state == -1) + { + preset.ditheringEnabled = true; + preset.ditheringBits = (uint)NvDitherBits.Bits8; + preset.ditheringMode = (uint)NvDitherMode.Temporal; + } + else + { + preset.ditheringEnabled = ditherInfo.state == 0 ? null : ditherInfo.state != (int)NvDitherState.Disabled; + preset.ditheringBits = (uint)ditherInfo.bits; + preset.ditheringMode = (uint)ditherInfo.mode; + } + + if (Config.ShowOverclocking) + { + var gpus = GetGPUs(); + + foreach (var gpu in gpus) + { + var gpuInfo = NvGpuInfo.GetGpuInfo(gpu); + + var settings = gpuInfo.GetOverclockSettings(); + + preset.ocSettings.Add(settings); + } + } + + if (driverSettings) + { + var settings = GetVisibleSettings(); + + foreach (var setting in settings) + { + var settingMeta = GetSettingMeta(setting.SettingId); + + if (settingMeta == null) + { + continue; + } + + var (presetSetting, isDefault, _) = settingMeta.ToIntValue(setting.ValueText); + + if (isDefault) + { + continue; + } + + preset.driverSettings.Add(setting.SettingId, presetSetting); + } + } + + return preset; + } + + private NvColorEnhancementSettings GetCurrentColorEnhancements(Display display) + { + return new NvColorEnhancementSettings + { + DigitalVibranceLevel = GetDigitalVibranceLevel(display), + HueAngle = GetHueAngle(display) + }; + } + + public List GetVisibleSettings() + { + return GetSettings().Where(s => _driverSettingIds.Contains(s.SettingId)).ToList(); + } + + public SettingMeta GetSettingMeta(uint settingId) + { + return _meta.GetSettingMeta(settingId); + } + + public List GetDriverSettings(string profileName = null) + { + if (profileName == null) + { + _drs.GetProfileNames(ref profileName, false); + } + + var applications = new Dictionary(); + var settings = profileName == null ? GetVisibleSettings() : _drs.GetSettingsForProfile(profileName, SettingViewMode.Normal, ref applications, true); + + return settings.Where(s => s.GroupName != null).Select(s => + { + var settingMeta = _meta.GetSettingMeta(s.SettingId); + var intValue = settingMeta.ToIntValue(s.ValueText); + var type = settingMeta.SettingType == nspector.Native.NVAPI2.NVDRS_SETTING_TYPE.NVDRS_BINARY_TYPE ? NvSettingType.BinaryType : NvSettingType.DwordType; + var values = type == NvSettingType.BinaryType ? + settingMeta.BinaryValues?.Select(bv => new NvSettingItemValue { Value = BitConverter.ToUInt32(bv.Value), ValueName = bv.ValueName }) : + settingMeta.DwordValues?.Select(bv => new NvSettingItemValue { Value = bv.Value, ValueName = bv.ValueName }); + + return new NvSettingItemDto + { + GroupName = s.GroupName, + IsApiExposed = s.IsApiExposed, + IsSettingHidden = s.IsSettingHidden, + IsStringValue = s.IsStringValue, + SettingId = s.SettingId, + SettingText = s.SettingText, + State = (int)s.State, + ValueRaw = s.ValueRaw, + ValueText = s.ValueText, + Value = intValue.intValue, + DefaultValue = intValue.defaultValue, + SettingType = type, + Values = values?.ToList() + }; + }).ToList(); + } + + public List GetDriverProfileNames() + { + var baseProfileName = ""; + + return DrsServiceLocator.SettingService.GetProfileNames(ref baseProfileName).Where(s => !s.StartsWith("0x")).OrderBy(s => s).ToList(); + } + + public bool IsGsyncEnabled() + { + var setting = GetSettings().FirstOrDefault(s => s.SettingId == NvSettingConstants.DRS_GSYNC_APPLICATION_MODE); + if (setting == null) + { + return false; + } + + var settingMeta = GetSettingMeta(setting.SettingId); + var settingValue = settingMeta.DwordValues?.FirstOrDefault(s => s.ValueName == setting.ValueText); + + return settingValue.Value >= 1; + } + + protected List GetSettings() + { + _semaphore.Wait(); + try + { + if (!_settings.Any()) + { + RefreshProfileSettings(); + } + + return _settings; + } + finally + { + _semaphore.Release(); + } + } + + protected override void Initialize() + { + NvAPIWrapper.NVIDIA.Initialize(); + _initialized = true; + + var version = default(string); + DriverVersion = GeneralApi.GetDriverAndBranchVersion(out version); + + _drs = DrsServiceLocator.SettingService; + _meta = DrsServiceLocator.MetaService; + + _drs.GetProfileNames(ref _baseProfileName, false); + + //if (!WinApiService.IsAdministratorStatic()) + //{ + _drs.ApplySettings += HandleDrsApplySettings; + _drs.RestoreSetting += HandleDrsRestoreSetting; + //} + + //SetGpuClocks(); + + //Task.Run(() => + //{ + // RefreshProfileSettings(); + //}); + } + + public void RefreshProfileSettings() + { + _refreshSemaphore.Wait(); + try + { + var firstTime = _settings?.Any() != true; + + DrsSessionScope.DestroyGlobalSession(); + + var applications = default(Dictionary); + var normalSettings = _drs.GetSettingsForProfile(_baseProfileName, SettingViewMode.Normal, ref applications, true); + + _settings = new List(normalSettings); + + _driverSettingIds.Clear(); + _driverSettingIds.AddRange(_settings.Where(s => !s.IsStringValue && !s.SettingText.Contains("SLI") && s.GroupName != null && s.GroupName != "Unknown").Select(s => s.SettingId)); + + if (firstTime) + { + DrsServiceLocator.ScannerService.ScanProfileSettings(false, null); + _meta.ResetMetaCache(); + } + } + finally + { + _refreshSemaphore.Release(); + } + } + + private bool HasPrivilegesForUnexposedApis() + { + return _winApiService.IsAdministrator() || !_winApiService.IsServiceRunning(); + } + + private void HandleDrsApplySettings(object sender, DrsEvent drsEvent) + { + if (HasPrivilegesForUnexposedApis()) + { + return; + } + + var message = new SvcRpcSetNvDriverSettingsMessage + { + MethodName = nameof(ApplyDriverSettings), + ProfileName = drsEvent.ProfileName, + DriverSettings = drsEvent.Settings + }; + + _rpcClientService.Call(message); + + drsEvent.Handled = true; + } + + private void HandleDrsRestoreSetting(object sender, DrsEvent drsEvent) + { + if (HasPrivilegesForUnexposedApis()) + { + return; + } + + var message = new SvcRpcSetNvDriverSettingsMessage + { + MethodName = nameof(RestoreDriverSettings), + ProfileName = drsEvent.ProfileName, + DriverSettings = drsEvent.Settings + }; + + _rpcClientService.Call(message); + + drsEvent.Handled = true; + } + + protected override void Uninitialize() + { + if (_initialized) + { + NvAPIWrapper.NVIDIA.Unload(); + } + } + + private void LoadConfig() + { + _configFilename = Path.Combine(_dataPath, "NvConfig.json"); + try + { + if (File.Exists(_configFilename)) + { + Config = JsonConvert.DeserializeObject(File.ReadAllText(_configFilename)); + } + } + catch (Exception ex) + { + Logger.Error($"LoadConfig: {ex.Message}"); + } + Config ??= new NvServiceConfig(); + } + + private void SaveConfig() + { + Utils.WriteObject(_configFilename, Config); + } + + public NvServiceConfig GetConfig() + { + return Config; + } + + public bool UpdateConfig(NvServiceConfig config) + { + Config.Update(config); + + SetShortcuts(SHORTCUTID_NVQA, Config.QuickAccessShortcut); + + return true; + } + + internal Display ResolveDisplay(NvPreset preset) + { + if (preset.Display == null) + { + preset.Display = GetPresetDisplay(preset); + } + + return preset.Display; + } + + private async Task PowerModeResume(object sender, PowerStateChangedEventArgs e, CancellationToken _) + { + Logger.Debug($"PowerModeChanged: {e.State}"); + + // Wait + await Task.Delay(30000); + + await ExecutePresetsForEvent(PresetTriggerType.Resume); + } + + private void PowerModeChanged(object sender, PowerStateChangedEventArgs e) + { + Logger.Debug($"PowerModeChanged: {e.State}"); + + switch (e.State) + { + case PowerOnOffState.StandBy: + { + _ = ExecutePresetsForEvent(PresetTriggerType.Standby); + break; + } + case PowerOnOffState.ShutDown: + { + _ = ExecutePresetsForEvent(PresetTriggerType.Shutdown); + break; + } + } + } + + private async Task ExecutePresetsForEvent(PresetTriggerType triggerType) + { + Logger.Debug($"Executing presets for event {triggerType}"); + + var presets = _presets.Where(p => p.Triggers.Any(t => t.Trigger == triggerType)).ToList(); + + if (!presets.Any()) + { + return; + } + + await ExecuteEventPresets(_serviceManager, new[] { triggerType }).ConfigureAwait(true); + } + + private static uint MAKE_NVAPI_VERSION(int version) + { + return (uint)((Marshal.SizeOf(typeof(T))) | version << 16); + } + + private string GetDriverSettingsDescription(Dictionary driverSettings, bool useNewLines = false) + { + if (driverSettings.Count == 0) + { + return "None"; + } + + var values = new List(); + + foreach (var driverSetting in driverSettings) + { + var settingMeta = GetSettingMeta(driverSetting.Key); + + var value = settingMeta.ToFriendlyName(intValue: driverSetting.Value, displayDefault: true); + + if (value == null) + { + continue; + } + + values.Add($"{settingMeta.SettingName}: {value}"); + } + + return string.Join(useNewLines ? "\r\n" : ", ", values); + } + + } } diff --git a/Shared/Contracts/AMD/AmdPreset.cs b/Shared/Contracts/AMD/AmdPreset.cs index a484a80..e9108d9 100644 --- a/Shared/Contracts/AMD/AmdPreset.cs +++ b/Shared/Contracts/AMD/AmdPreset.cs @@ -23,9 +23,11 @@ public class AmdPreset : PresetBase [JsonIgnore] public string InfoLine { get; private set; } + public static AmdPreset DefaultPreset = new AmdPreset(); + public AmdPreset() : base() { - applyColorData = true; + applyColorData = false; applyDithering = false; ditherState = ADLDitherState.DRIVER_DEFAULT; applyHDR = false; @@ -39,22 +41,7 @@ public class AmdPreset : PresetBase { id = GetNewId(); - primaryDisplay = preset.primaryDisplay; - displayName = preset.displayName; - DisplayId = preset.DisplayId; - - applyColorData = preset.applyColorData; - colorDepth = preset.colorDepth; - pixelFormat = preset.pixelFormat; - - applyHDR = preset.applyHDR; - HDREnabled = preset.HDREnabled; - toggleHDR = preset.toggleHDR; - SDRBrightness = preset.SDRBrightness; - - applyDithering = preset.applyDithering; - ditherState = preset.ditherState; - DisplayConfig = new DisplayConfig(DisplayConfig); + Update(preset); } public AmdPreset Clone() @@ -74,6 +61,38 @@ public class AmdPreset : PresetBase return preset; } + public void Update(AmdPreset preset) + { + primaryDisplay = preset.primaryDisplay; + displayName = preset.displayName; + DisplayId = preset.DisplayId; + + applyColorData = preset.applyColorData; + colorDepth = preset.colorDepth; + pixelFormat = preset.pixelFormat; + + applyHDR = preset.applyHDR; + HDREnabled = preset.HDREnabled; + toggleHDR = preset.toggleHDR; + SDRBrightness = preset.SDRBrightness; + + applyDithering = preset.applyDithering; + ditherState = preset.ditherState; + DisplayConfig = new DisplayConfig(preset.DisplayConfig); + } + + public void UpdateAutoApplySettings(AmdPreset currentSettings = null, bool keepChanges = false) + { + currentSettings ??= DefaultPreset; + + applyColorData = keepChanges && applyColorData || colorDepth != currentSettings.colorDepth || pixelFormat != currentSettings.pixelFormat; + applyDithering = keepChanges && applyDithering || ditherState != currentSettings.ditherState; + applyHDR = keepChanges && applyHDR || (HDREnabled != currentSettings.HDREnabled || toggleHDR || SDRBrightness != currentSettings.SDRBrightness); + DisplayConfig.ApplyResolution = keepChanges && DisplayConfig.ApplyResolution || (DisplayConfig.Resolution.IsDifferent(currentSettings.DisplayConfig.Resolution) || + DisplayConfig.Scaling != currentSettings.DisplayConfig.Scaling || DisplayConfig.Rotation != currentSettings.DisplayConfig.Rotation || DisplayConfig.IsPrimary != null && DisplayConfig.IsPrimary != currentSettings.DisplayConfig.IsPrimary); + DisplayConfig.ApplyRefreshRate = keepChanges && DisplayConfig.ApplyRefreshRate || !DisplayConfig.RefreshRate.Equals(currentSettings.DisplayConfig.RefreshRate); + } + public static string[] GetColumnNames() { return new[] { "Name", "Display|140", "Color settings (BPC, format)|260", "Refresh rate|100", "Resolution|120", "Dithering", "HDR", "Shortcut", "Apply on startup" }; diff --git a/Shared/Contracts/Config.cs b/Shared/Contracts/Config.cs index 85052ed..5c1ae71 100644 --- a/Shared/Contracts/Config.cs +++ b/Shared/Contracts/Config.cs @@ -1,115 +1,122 @@  +using System.ComponentModel; + namespace ColorControl.Shared.Contracts { - public enum ElevationMethod - { - None = 0, - RunAsAdmin = 1, - UseService = 2, - UseElevatedProcess = 3 - } + public enum ElevationMethod + { + None = 0, + [Description("Run as administrator")] + RunAsAdmin = 1, + [Description("Use service")] + UseService = 2, + [Description("Use elevated process")] + UseElevatedProcess = 3 + } - public enum UiType - { - WinForms = 0, - WebDefaultBrowser = 1, - WebEmbedded = 2 - } + public enum UiType + { + WinForms = 0, + [Description("Web (default browser)")] + WebDefaultBrowser = 1, + [Description("Web (embedded browser)")] + WebEmbedded = 2 + } - public class Config - { - public bool AutoStart { get; set; } - public bool StartMinimized { get; set; } - public bool MinimizeOnClose { get; set; } - public bool MinimizeToTray { get; set; } - public bool CheckForUpdates { get; set; } - public bool AutoInstallUpdates { get; set; } - public bool UseDarkMode { get; set; } - public int DisplaySettingsDelay { get; set; } - public string ScreenSaverShortcut { get; set; } - public int FormWidth { get; set; } - public int FormHeight { get; set; } - public double XFormWidth { get; set; } - public double XFormHeight { get; set; } - public int NvPresetId_ApplyOnStartup { get; set; } - public int AmdPresetId_ApplyOnStartup { get; set; } - public bool FixChromeFonts { get; set; } - public bool UseGdiScaling { get; set; } - public ListViewSortState NvPresetsSortState { get; set; } - public ListViewSortState AmdPresetsSortState { get; set; } - public ListViewSortState LgPresetsSortState { get; set; } - public ListViewSortState SamsungPresetsSortState { get; set; } - public ListViewSortState GamePresetsSortState { get; set; } - public string AmdQuickAccessShortcut { get; set; } - public string LgQuickAccessShortcut { get; set; } - public bool UseDedicatedElevatedProcess { get; set; } - public ElevationMethod ElevationMethod { get; set; } - public bool ElevationMethodAsked { get; set; } - public int ProcessMonitorPollingInterval { get; set; } - public string LogLevel { get; set; } - public List Modules { get; set; } - public bool UseRawInput { get; set; } - public bool SetMinTmlAndMaxTml { get; set; } - public bool DisableErrorPopupWhenApplyingPreset { get; set; } - public UiType UiType { get; set; } - public int UiPort { get; set; } + public class Config + { + public bool AutoStart { get; set; } + public bool StartMinimized { get; set; } + public bool MinimizeOnClose { get; set; } + public bool MinimizeToTray { get; set; } + public bool CheckForUpdates { get; set; } + public bool AutoInstallUpdates { get; set; } + public bool UseDarkMode { get; set; } + public int DisplaySettingsDelay { get; set; } + public string ScreenSaverShortcut { get; set; } + public int FormWidth { get; set; } + public int FormHeight { get; set; } + public double XFormWidth { get; set; } + public double XFormHeight { get; set; } + public int NvPresetId_ApplyOnStartup { get; set; } + public int AmdPresetId_ApplyOnStartup { get; set; } + public bool FixChromeFonts { get; set; } + public bool UseGdiScaling { get; set; } + public ListViewSortState NvPresetsSortState { get; set; } + public ListViewSortState AmdPresetsSortState { get; set; } + public ListViewSortState LgPresetsSortState { get; set; } + public ListViewSortState SamsungPresetsSortState { get; set; } + public ListViewSortState GamePresetsSortState { get; set; } + public string AmdQuickAccessShortcut { get; set; } + public string LgQuickAccessShortcut { get; set; } + public bool UseDedicatedElevatedProcess { get; set; } + public ElevationMethod ElevationMethod { get; set; } + public bool ElevationMethodAsked { get; set; } + public int ProcessMonitorPollingInterval { get; set; } + public string LogLevel { get; set; } + public List Modules { get; set; } + public bool UseRawInput { get; set; } + public bool SetMinTmlAndMaxTml { get; set; } + public bool DisableErrorPopupWhenApplyingPreset { get; set; } + public UiType UiType { get; set; } + public int UiPort { get; set; } - public Config() - { - AutoStart = false; - LogLevel = "DEBUG"; - DisplaySettingsDelay = 1000; - ScreenSaverShortcut = string.Empty; - FormWidth = 900; - FormHeight = 600; - XFormWidth = 1280; - XFormHeight = 720; - MinimizeToTray = true; - CheckForUpdates = true; - FixChromeFonts = false; - UseGdiScaling = true; - UseDedicatedElevatedProcess = false; - ElevationMethod = ElevationMethod.None; - ElevationMethodAsked = false; - ProcessMonitorPollingInterval = 1000; - UiType = UiType.WinForms; - UiPort = 5000; - LgPresetsSortState = new ListViewSortState(); - NvPresetsSortState = new ListViewSortState(); - AmdPresetsSortState = new ListViewSortState(); - SamsungPresetsSortState = new ListViewSortState(); - GamePresetsSortState = new ListViewSortState(); - Modules = new List(); - } + public Config() + { + AutoStart = false; + LogLevel = "DEBUG"; + DisplaySettingsDelay = 1000; + ScreenSaverShortcut = string.Empty; + FormWidth = 900; + FormHeight = 600; + XFormWidth = 1280; + XFormHeight = 720; + MinimizeToTray = true; + CheckForUpdates = true; + FixChromeFonts = false; + UseGdiScaling = true; + UseDedicatedElevatedProcess = false; + ElevationMethod = ElevationMethod.None; + ElevationMethodAsked = false; + ProcessMonitorPollingInterval = 1000; + UiType = UiType.WinForms; + UiPort = 5000; + LgPresetsSortState = new ListViewSortState(); + NvPresetsSortState = new ListViewSortState(); + AmdPresetsSortState = new ListViewSortState(); + SamsungPresetsSortState = new ListViewSortState(); + GamePresetsSortState = new ListViewSortState(); + Modules = new List(); + } - public Config(Config config) : this() - { - Update(config); - } + public Config(Config config) : this() + { + Update(config); + } - public void Update(Config config) - { - AutoStart = config.AutoStart; - StartMinimized = config.StartMinimized; - MinimizeOnClose = config.MinimizeOnClose; - MinimizeToTray = config.MinimizeToTray; - CheckForUpdates = config.CheckForUpdates; - AutoInstallUpdates = config.AutoInstallUpdates; - UseDarkMode = config.UseDarkMode; - ScreenSaverShortcut = config.ScreenSaverShortcut; - FixChromeFonts = config.FixChromeFonts; - UseGdiScaling = config.UseGdiScaling; - ProcessMonitorPollingInterval = config.ProcessMonitorPollingInterval; - UseRawInput = config.UseRawInput; - SetMinTmlAndMaxTml = config.SetMinTmlAndMaxTml; - DisableErrorPopupWhenApplyingPreset = config.DisableErrorPopupWhenApplyingPreset; - UiType = config.UiType; - UiPort = config.UiPort; - } + public void Update(Config config) + { + AutoStart = config.AutoStart; + StartMinimized = config.StartMinimized; + MinimizeOnClose = config.MinimizeOnClose; + MinimizeToTray = config.MinimizeToTray; + CheckForUpdates = config.CheckForUpdates; + AutoInstallUpdates = config.AutoInstallUpdates; + UseDarkMode = config.UseDarkMode; + ScreenSaverShortcut = config.ScreenSaverShortcut; + FixChromeFonts = config.FixChromeFonts; + UseGdiScaling = config.UseGdiScaling; + ProcessMonitorPollingInterval = config.ProcessMonitorPollingInterval; + UseRawInput = config.UseRawInput; + SetMinTmlAndMaxTml = config.SetMinTmlAndMaxTml; + DisableErrorPopupWhenApplyingPreset = config.DisableErrorPopupWhenApplyingPreset; + UiType = config.UiType; + UiPort = config.UiPort; + } - public bool HasModule(string name) - { - return Modules?.Any(m => m.DisplayName == name) == true; - } - } + public bool HasModule(string name) + { + return Modules?.Any(m => m.DisplayName == name) == true; + } + } }