Skip to content

Commit

Permalink
Added support for querying and modifying the Digital Vibrance Control…
Browse files Browse the repository at this point in the history
…'s saturation level
  • Loading branch information
falahati committed Mar 21, 2020
1 parent fbb75e1 commit 2d64527
Show file tree
Hide file tree
Showing 9 changed files with 729 additions and 2 deletions.
2 changes: 2 additions & 0 deletions NvAPIWrapper.Net.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DPMST/@EntryIndexedValue">DPMST</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DRS/@EntryIndexedValue">DRS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DRSGPU/@EntryIndexedValue">DRSGPU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DVC/@EntryIndexedValue">DVC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DWM/@EntryIndexedValue">DWM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DX/@EntryIndexedValue">DX</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ECID/@EntryIndexedValue">ECID</s:String>
Expand Down Expand Up @@ -110,4 +111,5 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GPC/@EntryIndexedValue">GPC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=VPE/@EntryIndexedValue">VPE</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TPC/@EntryIndexedValue">TPC</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vibrance/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>
325 changes: 325 additions & 0 deletions NvAPIWrapper/Display/DVIInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
using System;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.Display;

namespace NvAPIWrapper.Display
{
/// <summary>
/// This class contains and provides a way to modify the Digital Vibrance Control information regarding the
/// saturation level of the display or the output
/// </summary>
public class DVIInformation : IDisplayDVCInfo
{
private readonly DisplayHandle _displayHandle = DisplayHandle.DefaultHandle;
private readonly OutputId _outputId = OutputId.Invalid;
private bool? _isLegacy;

/// <summary>
/// Creates a new instance of the class using a DisplayHandle
/// </summary>
/// <param name="displayHandle">The handle of the display.</param>
public DVIInformation(DisplayHandle displayHandle)
{
_displayHandle = displayHandle;
}

/// <summary>
/// Creates a new instance of this class using a OutputId
/// </summary>
/// <param name="outputId">The output identification of a display or an output</param>
public DVIInformation(OutputId outputId)
{
_outputId = outputId;
}

/// <summary>
/// Gets and sets the normalized saturation level in the [-1,1] inclusive range.
/// a -1 value corresponds to the minimum saturation level and maximum under-saturation and the
/// a 1 value corresponds to the maximum saturation level and maximum over-saturation.
/// The value of 0 indicates the default saturation level.
/// </summary>
public double NormalizedLevel
{
get
{
var info = GetInfo();

if (info == null)
{
return double.NaN;
}

var deviance = info.CurrentLevel - info.DefaultLevel;
var range = deviance >= 0
? info.MaximumLevel - info.DefaultLevel
: info.DefaultLevel - info.MinimumLevel;

if (deviance == 0 || range == 0)
{
return 0;
}

return Math.Max(Math.Min((double) deviance / range, 1), -1);
}
set
{
if (double.IsNaN(value) || double.IsInfinity(value))
{
throw new ArgumentOutOfRangeException(nameof(value));
}

var info = GetInfo();

if (info == null)
{
return;
}

var range = value >= 0 ? info.MaximumLevel - info.DefaultLevel : info.DefaultLevel - info.MinimumLevel;
var level = Math.Max(Math.Min((int) (value * range) + info.DefaultLevel, info.MaximumLevel), info.MinimumLevel);

if (level == info.CurrentLevel)
{
return;
}

SetLevel(level);
}
}

/// <summary>
/// Gets and sets the current saturation level
/// </summary>
public int CurrentLevel
{
get => GetInfo()?.CurrentLevel ?? 0;
set
{
var info = GetInfo();

if (info == null)
{
return;
}

value = Math.Max(Math.Min(value, info.MaximumLevel), info.MinimumLevel);

if (info.CurrentLevel == value)
{
return;
}

SetLevel(value);
}
}

/// <inheritdoc />
public int DefaultLevel
{
get => GetInfo()?.DefaultLevel ?? 0;
}

/// <inheritdoc />
public int MaximumLevel
{
get => GetInfo()?.MaximumLevel ?? 0;
}

/// <inheritdoc />
public int MinimumLevel
{
get => GetInfo()?.MinimumLevel ?? 0;
}

/// <inheritdoc />
public override string ToString()
{
return
$"{CurrentLevel:D} @ [{MinimumLevel:D} <= {DefaultLevel:D} <= {MaximumLevel:D}] = {NormalizedLevel:F2}";
}

private IDisplayDVCInfo GetInfo()
{
if (_isLegacy == true)
{
return GetLegacyInfo();
}

if (_isLegacy == false)
{
return GetModernInfo();
}

var info = GetModernInfo() ?? GetLegacyInfo();

if (info == null)
{
// exception occured on both, force a mode
_isLegacy = false;

return GetInfo();
}

return info;
}

private IDisplayDVCInfo GetLegacyInfo()
{
try
{
var info = _outputId == OutputId.Invalid
? DisplayApi.GetDVCInfo(_displayHandle)
: DisplayApi.GetDVCInfo(_outputId);

if (info.MaximumLevel == 0 && info.MinimumLevel == 0 && info.CurrentLevel == 0)
{
return null;
}

if (!_isLegacy.HasValue)
{
_isLegacy = true;
}


return info;
}
catch (Exception)
{
if (_isLegacy == true)
{
throw;
}

// ignore
}

return null;
}

private IDisplayDVCInfo GetModernInfo()
{
try
{
var info = _outputId == OutputId.Invalid
? DisplayApi.GetDVCInfoEx(_displayHandle)
: DisplayApi.GetDVCInfoEx(_outputId);

if (info.MaximumLevel == 0 && info.MinimumLevel == 0 && info.CurrentLevel == 0)
{
return null;
}

if (!_isLegacy.HasValue)
{
_isLegacy = false;
}

return info;
}
catch (Exception)
{
if (_isLegacy == false)
{
throw;
}

// ignore
}

return null;
}

private bool SetLegacyLevel(int level)
{
try
{
if (_outputId == OutputId.Invalid)
{
DisplayApi.SetDVCLevel(_displayHandle, level);
}
else
{
DisplayApi.SetDVCLevel(_outputId, level);
}

if (!_isLegacy.HasValue)
{
_isLegacy = true;
}

return true;
}
catch (Exception)
{
if (_isLegacy == true)
{
throw;
}

// ignore
}

return false;
}

private void SetLevel(int level)
{
if (_isLegacy == true)
{
SetLegacyLevel(level);
}
else if (_isLegacy == false)
{
SetModernLevel(level);
}
else
{
var success = SetModernLevel(level) || SetLegacyLevel(level);

if (!success)
{
// exception occured on both, force a mode
_isLegacy = false;

SetLevel(level);
}
}
}

private bool SetModernLevel(int level)
{
try
{
if (_outputId == OutputId.Invalid)
{
DisplayApi.SetDVCLevelEx(_displayHandle, level);
}
else
{
DisplayApi.SetDVCLevelEx(_outputId, level);
}

if (!_isLegacy.HasValue)
{
_isLegacy = false;
}

return true;
}
catch (Exception)
{
if (_isLegacy == false)
{
throw;
}

// ignore
}

return false;
}
}
}
8 changes: 8 additions & 0 deletions NvAPIWrapper/Display/Display.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ public DisplayDevice DisplayDevice
get => new DisplayDevice(Name);
}

/// <summary>
/// Gets the corresponding Digital Vibrance Control information
/// </summary>
public DVIInformation DigitalVibranceControl
{
get => new DVIInformation(Handle);
}

/// <summary>
/// Gets display driver build title
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions NvAPIWrapper/GPU/GPUOutput.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using NvAPIWrapper.Display;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
Expand Down Expand Up @@ -33,6 +34,14 @@ internal GPUOutput(OutputId outputId, PhysicalGPU gpu)
/// </summary>
public OutputType OutputType { get; }

/// <summary>
/// Gets the corresponding Digital Vibrance Control information
/// </summary>
public DVIInformation DigitalVibranceControl
{
get => new DVIInformation(OutputId);
}

/// <summary>
/// Gets the corresponding physical GPU
/// </summary>
Expand Down
Loading

0 comments on commit 2d64527

Please sign in to comment.