From 977060e92730a48646e0e432cd04ebb8758ae5b9 Mon Sep 17 00:00:00 2001 From: Vincent Maas Date: Sun, 2 Jan 2022 15:24:33 +0100 Subject: [PATCH] fix dithering issues --- ColorControl/ColorControl.csproj | 4 +- ColorControl/MainForm.Designer.cs | 3 +- ColorControl/MainForm.cs | 88 ++++++++++++++++++----------- ColorControl/NvService.cs | 93 +++++++++++++++++++------------ 4 files changed, 114 insertions(+), 74 deletions(-) diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj index aed9d6f..1c5b1c5 100644 --- a/ColorControl/ColorControl.csproj +++ b/ColorControl/ColorControl.csproj @@ -18,8 +18,8 @@ Maassoft Maassoft 0 - 5.2.0.0 - 5.2.0.0 + 5.3.0.0 + 5.3.0.0 false true false diff --git a/ColorControl/MainForm.Designer.cs b/ColorControl/MainForm.Designer.cs index 70f2a95..f561b11 100644 --- a/ColorControl/MainForm.Designer.cs +++ b/ColorControl/MainForm.Designer.cs @@ -1693,8 +1693,9 @@ this.chkDitheringEnabled.Size = new System.Drawing.Size(120, 19); this.chkDitheringEnabled.TabIndex = 3; this.chkDitheringEnabled.Text = "Dithering enabled"; + this.chkDitheringEnabled.ThreeState = true; this.chkDitheringEnabled.UseVisualStyleBackColor = true; - this.chkDitheringEnabled.CheckedChanged += new System.EventHandler(this.chkDitheringEnabled_CheckedChanged); + this.chkDitheringEnabled.CheckStateChanged += new System.EventHandler(this.chkDitheringEnabled_CheckStateChanged); // // pbGradient // diff --git a/ColorControl/MainForm.cs b/ColorControl/MainForm.cs index ab78e97..9f548d7 100644 --- a/ColorControl/MainForm.cs +++ b/ColorControl/MainForm.cs @@ -55,6 +55,7 @@ namespace ColorControl private FileVersionInfo _currentVersionInfo; private bool _checkedForUpdates = false; private string _updateHtmlUrl; + private bool _updatingDitherSettings; private LgGameBar _gameBarForm; @@ -1350,6 +1351,10 @@ namespace ColorControl { InitOptionsTab(); } + else if (tcMain.SelectedTab == tabNVIDIA) + { + UpdateDisplayInfoItems(); + } } private void InitLgTab() @@ -1371,39 +1376,42 @@ namespace ColorControl grpNvidiaOptions.Visible = _nvService != null; if (grpNvidiaOptions.Visible) { - var firstTime = cbxDitheringBitDepth.Items.Count == 0; - - if (firstTime) + if (cbxDitheringBitDepth.Items.Count == 0) { cbxDitheringBitDepth.Items.AddRange(Utils.GetDescriptions().ToArray()); cbxDitheringMode.Items.AddRange(Utils.GetDescriptions().ToArray()); - } - - var preset = _nvService.GetLastAppliedPreset() ?? GetSelectedNvPreset(); - if (firstTime || preset != null) - { - var ditheringEnabled = true; - int ditherBitsIndex; - int ditherModeIndex; - if (preset == null) - { - var hdrEnabled = _nvService.IsHDREnabled(); - var minBits = _nvService.GetPresets().Where(p => p.HDREnabled == hdrEnabled && p.applyDithering).DefaultIfEmpty().Min(p => p?.ditheringBits); - ditherBitsIndex = minBits.HasValue ? (int)minBits.Value : (int)(hdrEnabled ? NvDitherBits.Bits8 : NvDitherBits.Bits6); - ditherModeIndex = (int)NvDitherMode.Temporal; - } - else - { - ditheringEnabled = preset.ditheringEnabled; - ditherBitsIndex = (int)preset.ditheringBits; - ditherModeIndex = (int)preset.ditheringMode; - } - - chkDitheringEnabled.Checked = ditheringEnabled; - cbxDitheringBitDepth.SelectedIndex = ditherBitsIndex; - cbxDitheringMode.SelectedIndex = ditherModeIndex; FillGradient(); } + + UpdateDitherSettings(); + } + } + + private void UpdateDitherSettings() + { + var ditherInfo = _nvService.GetDithering(); + + if (ditherInfo.state == -1) + { + MessageForms.ErrorOk("Error retrieving dithering settings. See log for details."); + return; + } + + var state = (NvDitherState)ditherInfo.state; + + _updatingDitherSettings = true; + try + { + chkDitheringEnabled.CheckState = state switch { NvDitherState.Enabled => CheckState.Checked, NvDitherState.Disabled => CheckState.Unchecked, _ => CheckState.Indeterminate }; + cbxDitheringBitDepth.SelectedIndex = ditherInfo.bits; + cbxDitheringMode.SelectedIndex = ditherInfo.mode; + + cbxDitheringBitDepth.Enabled = state == NvDitherState.Enabled; + cbxDitheringMode.Enabled = state == NvDitherState.Enabled; + } + finally + { + _updatingDitherSettings = false; } } @@ -2061,17 +2069,21 @@ Do you want to continue?"; } } - private void chkDitheringEnabled_CheckedChanged(object sender, EventArgs e) - { - ApplyDitheringOptions(); - } - private void ApplyDitheringOptions() { + if (_updatingDitherSettings) + { + return; + } + + var state = chkDitheringEnabled.CheckState switch { CheckState.Checked => NvDitherState.Enabled, CheckState.Unchecked => NvDitherState.Disabled, _ => NvDitherState.Auto }; var bitDepth = cbxDitheringBitDepth.SelectedIndex; var mode = cbxDitheringMode.SelectedIndex; - _nvService.SetDithering(chkDitheringEnabled.Checked, (uint)bitDepth, (uint)(mode > -1 ? mode : (int)NvDitherMode.Temporal)); + if (_nvService.SetDithering(state, (uint)bitDepth, (uint)(mode > -1 ? mode : (int)NvDitherMode.Temporal)) && state == NvDitherState.Auto) + { + UpdateDitherSettings(); + } } private void cbxDitheringBitDepth_SelectedIndexChanged(object sender, EventArgs e) @@ -3034,5 +3046,13 @@ The InStart and Software Update items are now visible under the Expert-button." { ResumeLayout(true); } + + private void chkDitheringEnabled_CheckStateChanged(object sender, EventArgs e) + { + cbxDitheringBitDepth.Enabled = chkDitheringEnabled.CheckState == CheckState.Checked; + cbxDitheringMode.Enabled = chkDitheringEnabled.CheckState == CheckState.Checked; + + ApplyDitheringOptions(); + } } } \ No newline at end of file diff --git a/ColorControl/NvService.cs b/ColorControl/NvService.cs index ff27218..3e4dfea 100644 --- a/ColorControl/NvService.cs +++ b/ColorControl/NvService.cs @@ -13,6 +13,16 @@ using System.Windows.Forms; namespace ColorControl { + enum NvDitherState + { + [Description("Auto")] + Auto = 0, + [Description("Enabled")] + Enabled = 1, + [Description("Disabled")] + Disabled = 2 + } + enum NvDitherBits { [Description("6-bit")] @@ -45,7 +55,7 @@ namespace ColorControl PreserveSig = true)] private static extern IntPtr NvAPI64_QueryInterface(uint interfaceId); - public delegate long NvAPI_Disp_SetDitherControl( + public delegate int NvAPI_Disp_SetDitherControl( [In] PhysicalGPUHandle physicalGpu, [In] uint OutputId, [In] uint state, @@ -53,18 +63,19 @@ namespace ColorControl [In] uint mode ); - public delegate long NvAPI_Disp_GetDitherControl( - [In] PhysicalGPUHandle physicalGpu, - [In] uint OutputId, - [In] IntPtr ditherControl); + 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 int version; - public uint state; - public uint bits; - public uint mode; + public uint version; + public int state; + public int bits; + public int mode; + public uint bitsCaps; + public uint modeCaps; }; private Display _currentDisplay; @@ -233,7 +244,7 @@ namespace ColorControl if (preset.applyDithering) { - if (!SetDithering(preset.ditheringEnabled, preset: preset)) + if (!SetDithering(preset.ditheringEnabled ? NvDitherState.Enabled : NvDitherState.Disabled, preset: preset)) { result = false; } @@ -304,7 +315,7 @@ namespace ColorControl //} } - public bool SetDithering(bool enabled, uint bits = 1, uint mode = 4, NvPreset preset = null) + public bool SetDithering(NvDitherState state, uint bits = 1, uint mode = 4, NvPreset preset = null) { var result = true; @@ -317,14 +328,20 @@ namespace ColorControl var gpuHandle = displayDevice.PhysicalGPU.Handle; var displayId = displayDevice.DisplayId; - - if (preset != null) + + 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; } - var resultValue = delegateValue(gpuHandle, displayId, (uint)(enabled ? 1 : 2), bits, mode); + 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}"); @@ -340,40 +357,31 @@ namespace ColorControl return result; } - public bool GetDithering() + public NV_GPU_DITHER_CONTROL_V1 GetDithering() { - // Requires elevation, too bad :( - //Utils.GetRegistryKeyValue(@"SYSTEM\CurrentControlSet\Services\nvlddmkm\State\DisplayDatabase", "DitherRegistryKey"); + var dither = new NV_GPU_DITHER_CONTROL_V1 { version = 0x10018 }; - /* var ptr = NvAPI64_QueryInterface(0x932AC8FB); if (ptr != IntPtr.Zero) { var delegateValue = Marshal.GetDelegateForFunctionPointer(ptr, typeof(NvAPI_Disp_GetDitherControl)) as NvAPI_Disp_GetDitherControl; var displayDevice = GetCurrentDisplay().DisplayDevice; - - var gpuHandle = displayDevice.PhysicalGPU.Handle; var displayId = displayDevice.DisplayId; - NV_GPU_DITHER_CONTROL_V1 info = new NV_GPU_DITHER_CONTROL_V1(); - info.version = 1; - var size = Marshal.SizeOf(info.GetType()); - IntPtr bla = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(info, bla, false); - - // Does not work yet...What is the exact interface of NvAPI_Disp_GetDitherControl? - - var result = delegateValue(gpuHandle, displayId, bla); + 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 info.state == 1; } - */ - return false; + else + { + dither.state = -2; + } + + return dither; } public bool SetRefreshRate(uint refreshRate) @@ -458,16 +466,27 @@ namespace ColorControl values.Add($"{refreshRate}Hz"); - var lastPreset = GetLastAppliedPreset(); - if (lastPreset != null) + var ditherInfo = GetDithering(); + + string dithering; + if (ditherInfo.state == -1) { - values.Add(lastPreset.GetDitheringDescription()); + dithering = "Error"; } else { - values.Add(string.Empty); + var state = (NvDitherState)ditherInfo.state; + dithering = state switch { NvDitherState.Disabled => "Disabled", NvDitherState.Auto => "Auto: ", _ => string.Empty }; + if (state is NvDitherState.Enabled or NvDitherState.Auto) + { + var ditherBitsDescription = ((NvDitherBits)ditherInfo.bits).GetDescription(); + var ditherModeDescription = ((NvDitherMode)ditherInfo.mode).GetDescription(); + dithering = string.Format("{0}{1} {2}", dithering, ditherBitsDescription, ditherModeDescription); + } } + values.Add(dithering); + var hdrEnabled = IsHDREnabled(); values.Add(hdrEnabled ? "Yes" : "No");