diff --git a/ColorControl/MainForm.Designer.cs b/ColorControl/MainForm.Designer.cs index 5ac7bc8..19ca421 100644 --- a/ColorControl/MainForm.Designer.cs +++ b/ColorControl/MainForm.Designer.cs @@ -52,6 +52,16 @@ private void InitializeComponent() this.miNvPresetDithering = new System.Windows.Forms.ToolStripMenuItem(); this.miNvPresetApplyDithering = new System.Windows.Forms.ToolStripMenuItem(); this.miNvPresetDitheringEnabled = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuNvDitheringBitDepth = new System.Windows.Forms.ToolStripMenuItem(); + this.miNvDithering6bit = new System.Windows.Forms.ToolStripMenuItem(); + this.miNvDithering8bit = new System.Windows.Forms.ToolStripMenuItem(); + this.miNvDithering10bit = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuNvDitheringMode = new System.Windows.Forms.ToolStripMenuItem(); + this.spatial1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.spatial2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.spatialDynamic2x2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.spatialStatic2x2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.temporalToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.miNvHDR = new System.Windows.Forms.ToolStripMenuItem(); this.miHDRIncluded = new System.Windows.Forms.ToolStripMenuItem(); this.miToggleHDR = new System.Windows.Forms.ToolStripMenuItem(); @@ -61,6 +71,7 @@ private void InitializeComponent() this.tabAMD = new System.Windows.Forms.TabPage(); this.lblErrorAMD = new System.Windows.Forms.Label(); this.tabLG = new System.Windows.Forms.TabPage(); + this.btnLgDeviceFilterRefresh = new System.Windows.Forms.Button(); this.clbLgPower = new System.Windows.Forms.CheckedListBox(); this.btnLgAddButton = new System.Windows.Forms.Button(); this.mnuLgButtons = new System.Windows.Forms.ContextMenuStrip(this.components); @@ -85,6 +96,13 @@ private void InitializeComponent() this.btnApplyLg = new System.Windows.Forms.Button(); this.lvLgPresets = new System.Windows.Forms.ListView(); this.tabOptions = new System.Windows.Forms.TabPage(); + this.grpNvidiaOptions = new System.Windows.Forms.GroupBox(); + this.lblDitheringMode = new System.Windows.Forms.Label(); + this.cbxDitheringMode = new System.Windows.Forms.ComboBox(); + this.lblDitheringBitDepth = new System.Windows.Forms.Label(); + this.cbxDitheringBitDepth = new System.Windows.Forms.ComboBox(); + this.chkDitheringEnabled = new System.Windows.Forms.CheckBox(); + this.pbGradient = new System.Windows.Forms.PictureBox(); this.grpMiscellaneousOptions = new System.Windows.Forms.GroupBox(); this.btnSetShortcutScreenSaver = new System.Windows.Forms.Button(); this.label11 = new System.Windows.Forms.Label(); @@ -114,13 +132,14 @@ private void InitializeComponent() this.lbPlugins = new System.Windows.Forms.ListBox(); this.label7 = new System.Windows.Forms.Label(); this.lblInfo = new System.Windows.Forms.Label(); - this.btnLgDeviceFilterRefresh = new System.Windows.Forms.Button(); this.tcMain.SuspendLayout(); this.tabNVIDIA.SuspendLayout(); this.mnuNvPresets.SuspendLayout(); this.tabAMD.SuspendLayout(); this.tabLG.SuspendLayout(); this.tabOptions.SuspendLayout(); + this.grpNvidiaOptions.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pbGradient)).BeginInit(); this.grpMiscellaneousOptions.SuspendLayout(); this.grpLGOptions.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.edtLgPowerOnAfterResumeDelay)).BeginInit(); @@ -340,7 +359,9 @@ private void InitializeComponent() // this.miNvPresetDithering.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.miNvPresetApplyDithering, - this.miNvPresetDitheringEnabled}); + this.miNvPresetDitheringEnabled, + this.mnuNvDitheringBitDepth, + this.mnuNvDitheringMode}); this.miNvPresetDithering.Name = "miNvPresetDithering"; this.miNvPresetDithering.Size = new System.Drawing.Size(147, 22); this.miNvPresetDithering.Text = "Dithering"; @@ -348,17 +369,103 @@ private void InitializeComponent() // miNvPresetApplyDithering // this.miNvPresetApplyDithering.Name = "miNvPresetApplyDithering"; - this.miNvPresetApplyDithering.Size = new System.Drawing.Size(120, 22); + this.miNvPresetApplyDithering.Size = new System.Drawing.Size(122, 22); this.miNvPresetApplyDithering.Text = "Included"; this.miNvPresetApplyDithering.Click += new System.EventHandler(this.miNvPresetApplyDithering_Click); // // miNvPresetDitheringEnabled // this.miNvPresetDitheringEnabled.Name = "miNvPresetDitheringEnabled"; - this.miNvPresetDitheringEnabled.Size = new System.Drawing.Size(120, 22); + this.miNvPresetDitheringEnabled.Size = new System.Drawing.Size(122, 22); this.miNvPresetDitheringEnabled.Text = "Enabled"; this.miNvPresetDitheringEnabled.Click += new System.EventHandler(this.miNvPresetDitheringEnabled_Click); // + // mnuNvDitheringBitDepth + // + this.mnuNvDitheringBitDepth.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.miNvDithering6bit, + this.miNvDithering8bit, + this.miNvDithering10bit}); + this.mnuNvDitheringBitDepth.Name = "mnuNvDitheringBitDepth"; + this.mnuNvDitheringBitDepth.Size = new System.Drawing.Size(122, 22); + this.mnuNvDitheringBitDepth.Text = "Bit depth"; + // + // miNvDithering6bit + // + this.miNvDithering6bit.Name = "miNvDithering6bit"; + this.miNvDithering6bit.Size = new System.Drawing.Size(105, 22); + this.miNvDithering6bit.Tag = "0"; + this.miNvDithering6bit.Text = "6-bit"; + this.miNvDithering6bit.Click += new System.EventHandler(this.miNvDithering6bit_Click); + // + // miNvDithering8bit + // + this.miNvDithering8bit.Name = "miNvDithering8bit"; + this.miNvDithering8bit.Size = new System.Drawing.Size(105, 22); + this.miNvDithering8bit.Tag = "1"; + this.miNvDithering8bit.Text = "8-bit"; + this.miNvDithering8bit.Click += new System.EventHandler(this.miNvDithering6bit_Click); + // + // miNvDithering10bit + // + this.miNvDithering10bit.Name = "miNvDithering10bit"; + this.miNvDithering10bit.Size = new System.Drawing.Size(105, 22); + this.miNvDithering10bit.Tag = "2"; + this.miNvDithering10bit.Text = "10-bit"; + this.miNvDithering10bit.Click += new System.EventHandler(this.miNvDithering6bit_Click); + // + // mnuNvDitheringMode + // + this.mnuNvDitheringMode.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.spatial1ToolStripMenuItem, + this.spatial2ToolStripMenuItem, + this.spatialDynamic2x2ToolStripMenuItem, + this.spatialStatic2x2ToolStripMenuItem, + this.temporalToolStripMenuItem}); + this.mnuNvDitheringMode.Name = "mnuNvDitheringMode"; + this.mnuNvDitheringMode.Size = new System.Drawing.Size(122, 22); + this.mnuNvDitheringMode.Text = "Mode"; + // + // spatial1ToolStripMenuItem + // + this.spatial1ToolStripMenuItem.Name = "spatial1ToolStripMenuItem"; + this.spatial1ToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.spatial1ToolStripMenuItem.Tag = "0"; + this.spatial1ToolStripMenuItem.Text = "Spatial Dynamic"; + this.spatial1ToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click); + // + // spatial2ToolStripMenuItem + // + this.spatial2ToolStripMenuItem.Name = "spatial2ToolStripMenuItem"; + this.spatial2ToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.spatial2ToolStripMenuItem.Tag = "1"; + this.spatial2ToolStripMenuItem.Text = "Spatial Static"; + this.spatial2ToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click); + // + // spatialDynamic2x2ToolStripMenuItem + // + this.spatialDynamic2x2ToolStripMenuItem.Name = "spatialDynamic2x2ToolStripMenuItem"; + this.spatialDynamic2x2ToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.spatialDynamic2x2ToolStripMenuItem.Tag = "2"; + this.spatialDynamic2x2ToolStripMenuItem.Text = "Spatial Dynamic 2x2"; + this.spatialDynamic2x2ToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click); + // + // spatialStatic2x2ToolStripMenuItem + // + this.spatialStatic2x2ToolStripMenuItem.Name = "spatialStatic2x2ToolStripMenuItem"; + this.spatialStatic2x2ToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.spatialStatic2x2ToolStripMenuItem.Tag = "3"; + this.spatialStatic2x2ToolStripMenuItem.Text = "Spatial Static 2x2"; + this.spatialStatic2x2ToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click); + // + // temporalToolStripMenuItem + // + this.temporalToolStripMenuItem.Name = "temporalToolStripMenuItem"; + this.temporalToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.temporalToolStripMenuItem.Tag = "4"; + this.temporalToolStripMenuItem.Text = "Temporal"; + this.temporalToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click); + // // miNvHDR // this.miNvHDR.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -474,6 +581,16 @@ private void InitializeComponent() this.tabLG.Text = "LG controller"; this.tabLG.UseVisualStyleBackColor = true; // + // btnLgDeviceFilterRefresh + // + this.btnLgDeviceFilterRefresh.Location = new System.Drawing.Point(594, 5); + this.btnLgDeviceFilterRefresh.Name = "btnLgDeviceFilterRefresh"; + this.btnLgDeviceFilterRefresh.Size = new System.Drawing.Size(75, 23); + this.btnLgDeviceFilterRefresh.TabIndex = 35; + this.btnLgDeviceFilterRefresh.Text = "Refresh"; + this.btnLgDeviceFilterRefresh.UseVisualStyleBackColor = true; + this.btnLgDeviceFilterRefresh.Click += new System.EventHandler(this.btnLgDeviceFilterRefresh_Click); + // // clbLgPower // this.clbLgPower.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) @@ -732,6 +849,7 @@ private void InitializeComponent() // // tabOptions // + this.tabOptions.Controls.Add(this.grpNvidiaOptions); this.tabOptions.Controls.Add(this.grpMiscellaneousOptions); this.tabOptions.Controls.Add(this.grpLGOptions); this.tabOptions.Controls.Add(this.grpHDROptions); @@ -744,6 +862,88 @@ private void InitializeComponent() this.tabOptions.Text = "Options"; this.tabOptions.UseVisualStyleBackColor = true; // + // grpNvidiaOptions + // + this.grpNvidiaOptions.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.grpNvidiaOptions.Controls.Add(this.lblDitheringMode); + this.grpNvidiaOptions.Controls.Add(this.cbxDitheringMode); + this.grpNvidiaOptions.Controls.Add(this.lblDitheringBitDepth); + this.grpNvidiaOptions.Controls.Add(this.cbxDitheringBitDepth); + this.grpNvidiaOptions.Controls.Add(this.chkDitheringEnabled); + this.grpNvidiaOptions.Controls.Add(this.pbGradient); + this.grpNvidiaOptions.Location = new System.Drawing.Point(412, 6); + this.grpNvidiaOptions.Name = "grpNvidiaOptions"; + this.grpNvidiaOptions.Size = new System.Drawing.Size(400, 297); + this.grpNvidiaOptions.TabIndex = 6; + this.grpNvidiaOptions.TabStop = false; + this.grpNvidiaOptions.Text = "NVIDIA options - test dithering"; + // + // lblDitheringMode + // + this.lblDitheringMode.AutoSize = true; + this.lblDitheringMode.Location = new System.Drawing.Point(6, 70); + this.lblDitheringMode.Name = "lblDitheringMode"; + this.lblDitheringMode.Size = new System.Drawing.Size(37, 13); + this.lblDitheringMode.TabIndex = 7; + this.lblDitheringMode.Text = "Mode:"; + // + // cbxDitheringMode + // + this.cbxDitheringMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbxDitheringMode.FormattingEnabled = true; + this.cbxDitheringMode.Location = new System.Drawing.Point(64, 65); + this.cbxDitheringMode.Name = "cbxDitheringMode"; + this.cbxDitheringMode.Size = new System.Drawing.Size(117, 21); + this.cbxDitheringMode.TabIndex = 6; + this.cbxDitheringMode.SelectedIndexChanged += new System.EventHandler(this.cbxDitheringMode_SelectedIndexChanged); + // + // lblDitheringBitDepth + // + this.lblDitheringBitDepth.AutoSize = true; + this.lblDitheringBitDepth.Location = new System.Drawing.Point(6, 43); + this.lblDitheringBitDepth.Name = "lblDitheringBitDepth"; + this.lblDitheringBitDepth.Size = new System.Drawing.Size(52, 13); + this.lblDitheringBitDepth.TabIndex = 5; + this.lblDitheringBitDepth.Text = "Bit-depth:"; + // + // cbxDitheringBitDepth + // + this.cbxDitheringBitDepth.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbxDitheringBitDepth.FormattingEnabled = true; + this.cbxDitheringBitDepth.Location = new System.Drawing.Point(64, 38); + this.cbxDitheringBitDepth.Name = "cbxDitheringBitDepth"; + this.cbxDitheringBitDepth.Size = new System.Drawing.Size(117, 21); + this.cbxDitheringBitDepth.TabIndex = 4; + this.cbxDitheringBitDepth.SelectedIndexChanged += new System.EventHandler(this.cbxDitheringBitDepth_SelectedIndexChanged); + // + // chkDitheringEnabled + // + this.chkDitheringEnabled.AutoSize = true; + this.chkDitheringEnabled.Checked = true; + this.chkDitheringEnabled.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkDitheringEnabled.Location = new System.Drawing.Point(6, 19); + this.chkDitheringEnabled.Name = "chkDitheringEnabled"; + this.chkDitheringEnabled.Size = new System.Drawing.Size(109, 17); + this.chkDitheringEnabled.TabIndex = 3; + this.chkDitheringEnabled.Text = "Dithering enabled"; + this.chkDitheringEnabled.UseVisualStyleBackColor = true; + this.chkDitheringEnabled.CheckedChanged += new System.EventHandler(this.chkDitheringEnabled_CheckedChanged); + // + // pbGradient + // + this.pbGradient.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.pbGradient.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.pbGradient.Location = new System.Drawing.Point(6, 92); + this.pbGradient.Name = "pbGradient"; + this.pbGradient.Size = new System.Drawing.Size(388, 198); + this.pbGradient.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pbGradient.TabIndex = 0; + this.pbGradient.TabStop = false; + // // grpMiscellaneousOptions // this.grpMiscellaneousOptions.Controls.Add(this.btnSetShortcutScreenSaver); @@ -1073,16 +1273,6 @@ private void InitializeComponent() this.lblInfo.TabIndex = 1; this.lblInfo.Text = "Info"; // - // btnLgDeviceFilterRefresh - // - this.btnLgDeviceFilterRefresh.Location = new System.Drawing.Point(594, 5); - this.btnLgDeviceFilterRefresh.Name = "btnLgDeviceFilterRefresh"; - this.btnLgDeviceFilterRefresh.Size = new System.Drawing.Size(75, 23); - this.btnLgDeviceFilterRefresh.TabIndex = 35; - this.btnLgDeviceFilterRefresh.Text = "Refresh"; - this.btnLgDeviceFilterRefresh.UseVisualStyleBackColor = true; - this.btnLgDeviceFilterRefresh.Click += new System.EventHandler(this.btnLgDeviceFilterRefresh_Click); - // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1109,6 +1299,9 @@ private void InitializeComponent() this.tabLG.ResumeLayout(false); this.tabLG.PerformLayout(); this.tabOptions.ResumeLayout(false); + this.grpNvidiaOptions.ResumeLayout(false); + this.grpNvidiaOptions.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pbGradient)).EndInit(); this.grpMiscellaneousOptions.ResumeLayout(false); this.grpMiscellaneousOptions.PerformLayout(); this.grpLGOptions.ResumeLayout(false); @@ -1216,6 +1409,23 @@ private void InitializeComponent() private System.Windows.Forms.Label lblErrorAMD; private System.Windows.Forms.Button btnClearLog; private System.Windows.Forms.Button btnLgDeviceFilterRefresh; + private System.Windows.Forms.GroupBox grpNvidiaOptions; + private System.Windows.Forms.PictureBox pbGradient; + private System.Windows.Forms.Label lblDitheringMode; + private System.Windows.Forms.ComboBox cbxDitheringMode; + private System.Windows.Forms.Label lblDitheringBitDepth; + private System.Windows.Forms.ComboBox cbxDitheringBitDepth; + private System.Windows.Forms.CheckBox chkDitheringEnabled; + private System.Windows.Forms.ToolStripMenuItem mnuNvDitheringBitDepth; + private System.Windows.Forms.ToolStripMenuItem miNvDithering6bit; + private System.Windows.Forms.ToolStripMenuItem miNvDithering8bit; + private System.Windows.Forms.ToolStripMenuItem miNvDithering10bit; + private System.Windows.Forms.ToolStripMenuItem mnuNvDitheringMode; + private System.Windows.Forms.ToolStripMenuItem spatial1ToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem spatial2ToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem spatialDynamic2x2ToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem spatialStatic2x2ToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem temporalToolStripMenuItem; } } diff --git a/ColorControl/MainForm.cs b/ColorControl/MainForm.cs index ba03eb5..17ba10b 100644 --- a/ColorControl/MainForm.cs +++ b/ColorControl/MainForm.cs @@ -1029,6 +1029,21 @@ private void mnuNvPresets_Opening(object sender, CancelEventArgs e) miNvPresetApplyDithering.Checked = preset.applyDithering; miNvPresetDitheringEnabled.Checked = preset.ditheringEnabled; + foreach (var item in mnuNvDitheringBitDepth.DropDownItems.OfType()) + { + if (item.Tag != null) + { + item.Checked = uint.Parse(item.Tag.ToString()) == preset.ditheringBits; + } + } + foreach (var item in mnuNvDitheringMode.DropDownItems.OfType()) + { + if (item.Tag != null) + { + item.Checked = uint.Parse(item.Tag.ToString()) == preset.ditheringMode; + } + } + miHDRIncluded.Checked = preset.applyHDR; miHDREnabled.Checked = preset.HDREnabled; miToggleHDR.Checked = preset.toggleHDR; @@ -1437,6 +1452,25 @@ private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) { LoadInfo(); } + else if (tcMain.SelectedTab == tabOptions) + { + grpNvidiaOptions.Visible = _nvService != null; + if (grpNvidiaOptions.Visible) + { + if (cbxDitheringBitDepth.Items.Count == 0) + { + cbxDitheringBitDepth.Items.AddRange(Utils.GetDescriptions().ToArray()); + cbxDitheringMode.Items.AddRange(Utils.GetDescriptions().ToArray()); + } + + + var preset = _nvService.GetLastAppliedPreset() ?? GetSelectedNvPreset(); + chkDitheringEnabled.Checked = preset?.ditheringEnabled ?? true; + cbxDitheringBitDepth.SelectedIndex = (int)(preset?.ditheringBits ?? 1); + cbxDitheringMode.SelectedIndex = (int)(preset?.ditheringMode ?? 4); + FillGradient(); + } + } } private void FillLgDevices() @@ -1909,5 +1943,59 @@ private void RefreshLgDevices() { _lgService.RefreshDevices(false).ContinueWith((task) => BeginInvoke(new Action(FillLgDevices))); } + + private void FillGradient() + { + if (pbGradient.Image == null) + { + pbGradient.Image = Utils.GenerateGradientBitmap(pbGradient.Width, pbGradient.Height); + } + } + + private void chkDitheringEnabled_CheckedChanged(object sender, EventArgs e) + { + ApplyDitheringOptions(); + } + + private void ApplyDitheringOptions() + { + var bitDepth = cbxDitheringBitDepth.SelectedIndex; + var mode = cbxDitheringMode.SelectedIndex; + + _nvService.SetDithering(chkDitheringEnabled.Checked, (uint)bitDepth, (uint)mode); + } + + private void cbxDitheringBitDepth_SelectedIndexChanged(object sender, EventArgs e) + { + ApplyDitheringOptions(); + } + + private void cbxDitheringMode_SelectedIndexChanged(object sender, EventArgs e) + { + ApplyDitheringOptions(); + } + + private void miNvDithering6bit_Click(object sender, EventArgs e) + { + var item = sender as ToolStripMenuItem; + + var preset = GetSelectedNvPreset(); + + preset.ditheringBits = uint.Parse(item.Tag.ToString()); + + AddOrUpdateItem(); + } + + private void spatial1ToolStripMenuItem_Click(object sender, EventArgs e) + { + var item = sender as ToolStripMenuItem; + + var preset = GetSelectedNvPreset(); + + preset.ditheringBits = uint.Parse(item.Tag.ToString()); + + AddOrUpdateItem(); + + } } } \ No newline at end of file diff --git a/ColorControl/NvPreset.cs b/ColorControl/NvPreset.cs index 9fc09ce..dd11a5a 100644 --- a/ColorControl/NvPreset.cs +++ b/ColorControl/NvPreset.cs @@ -19,6 +19,8 @@ class NvPreset : PresetBase public uint refreshRate { get; set; } public bool primaryDisplay { get; set; } public string displayName { get; set; } + public uint ditheringBits { get; set; } + public uint ditheringMode { get; set; } public NvPreset() { @@ -31,6 +33,8 @@ public NvPreset() applyRefreshRate = false; refreshRate = 60; primaryDisplay = true; + ditheringBits = 1; + ditheringMode = 4; } public NvPreset(ColorData colorData) : this() @@ -83,7 +87,16 @@ public List GetDisplayValues() values.Add(colorSettings); values.Add(string.Format("{0}: {1}Hz", applyRefreshRate ? "Included" : "Excluded", refreshRate)); - values.Add(string.Format("{0}: {1}", applyDithering ? "Included" : "Excluded", ditheringEnabled ? "Enabled" : "Disabled")); + + var dithering = ditheringEnabled ? string.Empty : "Disabled"; + if (ditheringEnabled) + { + var ditherBitsDescription = ((NvDitherBits)ditheringBits).GetDescription(); + var ditherModeDescription = ((NvDitherMode)ditheringMode).GetDescription(); + dithering = string.Format("{0} {1}", ditherBitsDescription, ditherModeDescription); + } + + values.Add(string.Format("{0}: {1}", applyDithering ? "Included" : "Excluded", dithering)); values.Add(string.Format("{0}: {1}", applyHDR ? "Included" : "Excluded", toggleHDR ? "Toggle" : HDREnabled ? "Enabled" : "Disabled")); //values.Add(colorData.ColorDepth.ToString()); @@ -138,7 +151,14 @@ public string GetTextForMenuItem() } if (applyDithering) { - sb.AppendFormat("Dithering: {0}", ditheringEnabled ? "Yes" : "No"); + var dithering = ditheringEnabled ? string.Empty : "No"; + sb.AppendFormat("Dithering: {0}", dithering); + if (ditheringEnabled) + { + var ditherBitsDescription = ((NvDitherBits)ditheringBits).GetDescription(); + var ditherModeDescription = ((NvDitherMode)ditheringMode).GetDescription(); + sb.AppendFormat("{0} {1}", ditherBitsDescription, ditherModeDescription); + } sb.Append(" / "); } if (applyHDR) diff --git a/ColorControl/NvService.cs b/ColorControl/NvService.cs index de8586a..aa006be 100644 --- a/ColorControl/NvService.cs +++ b/ColorControl/NvService.cs @@ -1,14 +1,40 @@ using NvAPIWrapper; using NvAPIWrapper.Display; using NvAPIWrapper.Native.Display; +using NvAPIWrapper.Native.Display.Structures; using NvAPIWrapper.Native.GPU.Structures; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Runtime.InteropServices; namespace ColorControl { + enum NvDitherBits + { + [Description("6-bit")] + Bits6 = 0, + [Description("8-bit")] + Bits8 = 1, + [Description("10-bit")] + Bits10 = 2 + } + + enum NvDitherMode + { + [Description("Spatial Dynamic")] + SpatialDynamic = 0, + [Description("Spatial Static")] + SpatialStatic = 1, + [Description("Spatial Dynamic 2x2")] + SpatialDynamic2x2 = 2, + [Description("Spatial Static 2x2")] + SpatialStatic2x2 = 3, + [Description("Temporal")] + Temporal = 4 + } + class NvService : GraphicsService { [DllImport(@"nvapi64", EntryPoint = @"nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, @@ -26,9 +52,9 @@ [In] uint mode public delegate long NvAPI_Disp_GetDitherControl( [In] PhysicalGPUHandle physicalGpu, [In] uint OutputId, - [In][Out] IntPtr ditherControl); + [In] IntPtr ditherControl); - [StructLayout(LayoutKind.Sequential, Pack = 8)] + [StructLayout(LayoutKind.Sequential)] public struct NV_GPU_DITHER_CONTROL_V1 { public int version; @@ -39,6 +65,7 @@ public struct NV_GPU_DITHER_CONTROL_V1 private Display _currentDisplay; private bool _initialized = false; + private NvPreset _lastAppliedPreset; public NvService() { @@ -72,46 +99,88 @@ public bool ApplyPreset(NvPreset preset, Config config) { SetCurrentDisplay(preset); - if (preset.applyHDR) - { - if (preset.toggleHDR || preset.HDREnabled != IsHDREnabled()) - { - ToggleHDR(config.DisplaySettingsDelay); - } - } + var hdrEnabled = IsHDREnabled(); - if (preset.applyRefreshRate) - { - SetRefreshRate(preset.refreshRate); - } + var newHdrEnabled = preset.applyHDR && (preset.HDREnabled || (preset.toggleHDR && !hdrEnabled)); + var applyHdr = preset.applyHDR && (preset.toggleHDR || preset.HDREnabled != hdrEnabled); - if (preset.applyColorData) + if (preset.applyColorData && ColorDataDiffers(preset.colorData)) { var display = GetCurrentDisplay(); - //var data = new ColorData(ColorDataFormat.YUV444, ColorDataColorimetry.Auto, ColorDataDynamicRange.Auto, ColorDataDepth.BPC10, preset.colorData.SelectionPolicy, ColorDataDesktopDepth.Default); + if (hdrEnabled) + { + SetHDRState(display, false); + + applyHdr = false; + } + try { display.DisplayDevice.SetColorData(preset.colorData); } catch (Exception ex) { + Logger.Error($"SetColorData threw an exception: {ex.Message}"); } - //var master = display.DisplayDevice.HDRColorData.MasteringDisplayData; - //var newMaster = new MasteringDisplayColorData(master.FirstColorCoordinate, master.SecondColorCoordinate, master.ThirdColorCoordinate, new ColorDataColorCoordinate(0.25f, 0.25f), 50, 0, 50, 50); - //var hdr = new HDRColorData(ColorDataHDRMode.UHDA, newMaster, ColorDataFormat.YUV444, ColorDataDynamicRange.Auto, ColorDataDepth.BPC8); - //display.DisplayDevice.SetHDRColorData(hdr); + if (hdrEnabled && newHdrEnabled) + { + SetHDRState(display, true); + + applyHdr = false; + } + } + + if (applyHdr) + { + var display = GetCurrentDisplay(); + + var colorData = preset.applyColorData ? preset.colorData : display.DisplayDevice.CurrentColorData; + + SetHDRState(display, newHdrEnabled, colorData); + } + + if (preset.applyRefreshRate) + { + SetRefreshRate(preset.refreshRate); } if (preset.applyDithering) { - SetDithering(preset.ditheringEnabled); + SetDithering(preset.ditheringEnabled, preset: preset); } + _lastAppliedPreset = preset; + return true; } - public void SetDithering(bool enabled) + private bool ColorDataDiffers(ColorData colorData) + { + var display = GetCurrentDisplay(); + + var currentColorData = display.DisplayDevice.CurrentColorData; + + var settingRange = colorData.DynamicRange == ColorDataDynamicRange.Auto ? colorData.ColorFormat == ColorDataFormat.RGB ? ColorDataDynamicRange.VESA : ColorDataDynamicRange.CEA : colorData.DynamicRange; + + return colorData.ColorFormat != currentColorData.ColorFormat || colorData.ColorDepth != currentColorData.ColorDepth || settingRange != currentColorData.DynamicRange; + } + + private void SetHDRState(Display display, bool enabled, ColorData colorData = null) + { + var newMaster = new MasteringDisplayColorData(); + var hdr = new HDRColorData(enabled ? ColorDataHDRMode.UHDA : ColorDataHDRMode.Off, newMaster, colorData?.ColorFormat, colorData?.DynamicRange, colorData?.ColorDepth); + + display.DisplayDevice.SetHDRColorData(hdr); + + // HDR will not always be disabled this way, then we can only disable it through the display settings + if (!enabled && IsHDREnabled()) + { + ToggleHDR(); + } + } + + public void SetDithering(bool enabled, uint bits = 1, uint mode = 4, NvPreset preset = null) { var ptr = NvAPI64_QueryInterface(0xDF0DFCDD); if (ptr != IntPtr.Zero) @@ -123,7 +192,13 @@ public void SetDithering(bool enabled) var gpuHandle = displayDevice.PhysicalGPU.Handle; var displayId = displayDevice.DisplayId; - var result = delegateValue(gpuHandle, displayId, (uint)(enabled ? 1 : 2), 1, 4); + if (preset != null) + { + bits = preset.ditheringBits; + mode = preset.ditheringMode; + } + + var result = delegateValue(gpuHandle, displayId, (uint)(enabled ? 1 : 2), bits, mode); if (result != 0) { Logger.Error($"Could not set dithering because NvAPI_Disp_SetDitherControl returned a non-zero return code: {result}"); @@ -133,6 +208,10 @@ public void SetDithering(bool enabled) public bool GetDithering() { + // Requires elevation, too bad :( + // Utils.GetRegistryKeyValue(@"SYSTEM\CurrentControlSet\Services\nvlddmkm\State\DisplayDatabase", "DitherRegistryKey"); + + /* var ptr = NvAPI64_QueryInterface(0x932AC8FB); if (ptr != IntPtr.Zero) { @@ -145,7 +224,8 @@ public bool GetDithering() NV_GPU_DITHER_CONTROL_V1 info = new NV_GPU_DITHER_CONTROL_V1(); info.version = 1; - IntPtr bla = Marshal.AllocHGlobal(Marshal.SizeOf(info.GetType())); + 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? @@ -158,16 +238,22 @@ public bool GetDithering() return info.state == 1; } - + */ return false; } public bool SetRefreshRate(uint refreshRate) { var display = GetCurrentDisplay(); - var portrait = new[] { Rotate.Degree90, Rotate.Degree270 }.Contains(display.DisplayDevice.ScanOutInformation.SourceToTargetRotation); var timing = display.DisplayDevice.CurrentTiming; + if (timing.Extra.RefreshRate == refreshRate) + { + return true; + } + + var portrait = new[] { Rotate.Degree90, Rotate.Degree270 }.Contains(display.DisplayDevice.ScanOutInformation.SourceToTargetRotation); + return SetRefreshRateInternal(display.Name, refreshRate, portrait, timing.HorizontalVisible, timing.VerticalVisible); } @@ -197,6 +283,11 @@ public Display[] GetDisplays() return Display.GetDisplays(); } + public NvPreset GetLastAppliedPreset() + { + return _lastAppliedPreset; + } + protected override void Initialize() { NVIDIA.Initialize(); diff --git a/ColorControl/Utils.cs b/ColorControl/Utils.cs index a423299..a7a8363 100644 --- a/ColorControl/Utils.cs +++ b/ColorControl/Utils.cs @@ -1,8 +1,10 @@ using Microsoft.Win32; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Drawing; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -14,7 +16,7 @@ namespace ColorControl { - class Utils + static class Utils { [Flags] public enum ModKeys : int @@ -188,6 +190,21 @@ internal static bool IsChromeInstalled() return key != null; } + internal static void GetRegistryKeyValue(string keyname, string valueName, bool deepSearch = false) + { + var key = Registry.LocalMachine.OpenSubKey(keyname); + + foreach (var subKeyName in key.GetSubKeyNames()) + { + var subKey = key.OpenSubKey(subKeyName); + if (subKey.GetValueNames().Contains(valueName)) + { + Thread.Sleep(0); + } + } + + } + internal static bool UpdateShortcut(string path, string arguments, bool removeArguments = false) { if (File.Exists(path)) @@ -302,5 +319,60 @@ public static void SetNotifyIconText(NotifyIcon ni, string text) if ((bool)t.GetField("added", hidden).GetValue(ni)) t.GetMethod("UpdateIcon", hidden).Invoke(ni, new object[] { true }); } + + internal static Image GenerateGradientBitmap(int width, int height) + { + var bitmap = new Bitmap(512, height); + + for (var i = 0; i < 256; i++) + { + var pixel = Color.FromArgb(i, i, i); + + for (var h = 0; h < height; h++) + { + bitmap.SetPixel(i * 2, h, pixel); + bitmap.SetPixel(i * 2 + 1, h, pixel); + } + } + + return bitmap; + } + + public static string GetDescription(this T e) where T : IConvertible + { + if (e is Enum) + { + var type = e.GetType(); + var values = Enum.GetValues(type); + + foreach (int val in values) + { + if (val == e.ToInt32(CultureInfo.InvariantCulture)) + { + var memInfo = type.GetMember(type.GetEnumName(val)); + var descriptionAttribute = memInfo[0] + .GetCustomAttributes(typeof(DescriptionAttribute), false) + .FirstOrDefault() as DescriptionAttribute; + + if (descriptionAttribute != null) + { + return descriptionAttribute.Description; + } + } + } + } + + return null; // could also return string.Empty + } + + public static List GetDescriptions() where T : IConvertible + { + var list = new List(); + foreach (var enumValue in Enum.GetValues(typeof(T))) + { + list.Add(((T)enumValue).GetDescription()); + } + return list; + } } }