From 285cd815090712bef883f806e31d324a3966fcd7 Mon Sep 17 00:00:00 2001
From: Serge <5920850+seerge@users.noreply.github.com>
Date: Sat, 24 Feb 2024 11:41:41 +0100
Subject: [PATCH] Flicker-free dimming slider for OLED models (#2109)
* Gamma Init
* Cleanup
* Show flicker-free dimming only on supported models
* Gamma ramp tweaks
* Gamma improvements
* Stronger dimming
* Added OLED model detection
---
app/AppConfig.cs | 5 +
app/Display/DisplayGammaRamp.cs | 112 ++++++++++++++++++++
app/Display/GammaRamp.cs | 56 ++++++++++
app/Display/ScreenControl.cs | 71 ++++++++++++-
app/Display/ScreenNative.cs | 12 ++-
app/Properties/Resources.Designer.cs | 10 ++
app/Properties/Resources.resx | 37 ++++---
app/Resources/icons8-brightness-32.png | Bin 0 -> 420 bytes
app/Settings.Designer.cs | 137 +++++++++++++++++++++----
app/Settings.cs | 10 ++
10 files changed, 408 insertions(+), 42 deletions(-)
create mode 100644 app/Display/DisplayGammaRamp.cs
create mode 100644 app/Display/GammaRamp.cs
create mode 100644 app/Resources/icons8-brightness-32.png
diff --git a/app/AppConfig.cs b/app/AppConfig.cs
index 6835da91..509bc9e5 100644
--- a/app/AppConfig.cs
+++ b/app/AppConfig.cs
@@ -395,6 +395,11 @@ public static class AppConfig
return ContainsModel("GA503") || IsSlash();
}
+ public static bool IsOLED()
+ {
+ return ContainsModel("OLED") || IsSlash() || ContainsModel("UX64") || ContainsModel("UX34") || ContainsModel("K360") || ContainsModel("X150");
+ }
+
public static bool IsStrix()
{
return ContainsModel("Strix") || ContainsModel("Scar") || ContainsModel("G703G");
diff --git a/app/Display/DisplayGammaRamp.cs b/app/Display/DisplayGammaRamp.cs
new file mode 100644
index 00000000..ca150f6f
--- /dev/null
+++ b/app/Display/DisplayGammaRamp.cs
@@ -0,0 +1,112 @@
+namespace GHelper.Display
+{
+
+ public class DisplayGammaRamp
+ {
+
+ public DisplayGammaRamp(ushort[] red, ushort[] green, ushort[] blue)
+ {
+ if (red?.Length != GammaRamp.DataPoints)
+ {
+ throw new ArgumentOutOfRangeException(nameof(red));
+ }
+
+ if (green?.Length != GammaRamp.DataPoints)
+ {
+ throw new ArgumentOutOfRangeException(nameof(green));
+ }
+
+ if (blue?.Length != GammaRamp.DataPoints)
+ {
+ throw new ArgumentOutOfRangeException(nameof(blue));
+ }
+
+ Red = red;
+ Green = green;
+ Blue = blue;
+ }
+
+ public DisplayGammaRamp(double brightness = 1, double contrast = 1, double gamma = 1)
+ : this(
+ CalculateLUT(brightness, contrast, gamma),
+ CalculateLUT(brightness, contrast, gamma),
+ CalculateLUT(brightness, contrast, gamma)
+ )
+ {
+ }
+
+ public DisplayGammaRamp(
+ double redBrightness,
+ double redContrast,
+ double redGamma,
+ double greenBrightness,
+ double greenContrast,
+ double greenGamma,
+ double blueBrightness,
+ double blueContrast,
+ double blueGamma
+ )
+ : this(
+ CalculateLUT(redBrightness, redContrast, redGamma),
+ CalculateLUT(greenBrightness, greenContrast, greenGamma),
+ CalculateLUT(blueBrightness, blueContrast, blueGamma)
+ )
+ {
+ }
+
+ internal DisplayGammaRamp(GammaRamp ramp) :
+ this(ramp.Red, ramp.Green, ramp.Blue)
+ {
+ }
+ public ushort[] Blue { get; }
+ public ushort[] Green { get; }
+ public ushort[] Red { get; }
+ private static ushort[] CalculateLUT(double brightness, double contrast, double gamma)
+ {
+ brightness = 0.5 + brightness / 2;
+ var result = new ushort[GammaRamp.DataPoints];
+ for (var i = 0; i < result.Length; i++)
+ {
+ result[i] = (ushort)(brightness * ushort.MaxValue * i / (float)(result.Length - 1));
+ }
+ return result;
+ }
+
+ public bool IsOriginal()
+ {
+ int MaxRed = Red[Red.Length - 1];
+ int MaxGreen = Green[Green.Length - 1];
+ int MaxBlue = Blue[Blue.Length - 1];
+ return (Math.Abs((MaxRed + MaxGreen + MaxBlue) / 3 - ushort.MaxValue) < 256);
+ }
+
+ private static ushort[] Brightness(ushort[] data, double brightness)
+ {
+ var result = new ushort[GammaRamp.DataPoints];
+ for (var i = 0; i < result.Length; i++)
+ {
+ if (brightness < 0.5)
+ result[i] = (ushort)(0.5 * ushort.MaxValue * Math.Pow((float)i/(result.Length - 1), 2 - brightness*2));
+ else
+ result[i] = (ushort)(data[i] * brightness);
+ }
+ return result;
+ }
+
+ internal GammaRamp AsBrightnessRamp(double brightness)
+ {
+ return new GammaRamp(
+ Brightness(Red, brightness),
+ Brightness(Green, brightness),
+ Brightness(Blue, brightness)
+ );
+ }
+
+ internal GammaRamp AsRamp()
+ {
+ return new GammaRamp(Red, Green, Blue);
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/app/Display/GammaRamp.cs b/app/Display/GammaRamp.cs
new file mode 100644
index 00000000..0b1321db
--- /dev/null
+++ b/app/Display/GammaRamp.cs
@@ -0,0 +1,56 @@
+using System.Runtime.InteropServices;
+
+namespace GHelper.Display
+{
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct GammaRamp
+ {
+ public const int DataPoints = 256;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = DataPoints)]
+ public readonly ushort[] Red;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = DataPoints)]
+ public readonly ushort[] Green;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = DataPoints)]
+ public readonly ushort[] Blue;
+
+ public GammaRamp(ushort[] red, ushort[] green, ushort[] blue)
+ {
+ if (red == null)
+ {
+ throw new ArgumentNullException(nameof(red));
+ }
+
+ if (green == null)
+ {
+ throw new ArgumentNullException(nameof(green));
+ }
+
+ if (blue == null)
+ {
+ throw new ArgumentNullException(nameof(blue));
+ }
+
+ if (red.Length != DataPoints)
+ {
+ throw new ArgumentOutOfRangeException(nameof(red));
+ }
+
+ if (green.Length != DataPoints)
+ {
+ throw new ArgumentOutOfRangeException(nameof(green));
+ }
+
+ if (blue.Length != DataPoints)
+ {
+ throw new ArgumentOutOfRangeException(nameof(blue));
+ }
+
+ Red = red;
+ Green = green;
+ Blue = blue;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/Display/ScreenControl.cs b/app/Display/ScreenControl.cs
index 6331baaf..4220f4a4 100644
--- a/app/Display/ScreenControl.cs
+++ b/app/Display/ScreenControl.cs
@@ -1,4 +1,4 @@
-using System.Diagnostics;
+using System.Runtime.InteropServices;
namespace GHelper.Display
{
@@ -7,6 +7,8 @@ namespace GHelper.Display
public const int MAX_REFRESH = 1000;
+ public static DisplayGammaRamp? gammaRamp;
+
public void AutoScreen(bool force = false)
{
if (force || AppConfig.Is("screen_auto"))
@@ -22,6 +24,70 @@ namespace GHelper.Display
}
}
+ public void SaveGamma()
+ {
+ var screenName = ScreenNative.FindLaptopScreen();
+ if (screenName is null) return;
+
+ try
+ {
+ var handle = ScreenNative.CreateDC(screenName, screenName, null, IntPtr.Zero);
+ var gammaRamp = new GammaRamp();
+ if (ScreenNative.GetDeviceGammaRamp(handle, ref gammaRamp))
+ {
+ var gamma = new DisplayGammaRamp(gammaRamp);
+ Logger.WriteLine("Gamma R: " + string.Join("-", gamma.Red));
+ Logger.WriteLine("Gamma G: " + string.Join("-", gamma.Green));
+ Logger.WriteLine("Gamma B: " + string.Join("-", gamma.Blue));
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.WriteLine(ex.ToString());
+ }
+ }
+
+ public void SetGamma(int brightness = 100)
+ {
+ var bright = Math.Round((float)brightness / 200 + 0.5, 2);
+
+ var screenName = ScreenNative.FindLaptopScreen();
+ if (screenName is null) return;
+
+ try
+ {
+ var handle = ScreenNative.CreateDC(screenName, screenName, null, IntPtr.Zero);
+ if (gammaRamp is null)
+ {
+ var gammaDump = new GammaRamp();
+ if (ScreenNative.GetDeviceGammaRamp(handle, ref gammaDump))
+ {
+ gammaRamp = new DisplayGammaRamp(gammaDump);
+ Logger.WriteLine("Gamma R: " + string.Join("-", gammaRamp.Red));
+ Logger.WriteLine("Gamma G: " + string.Join("-", gammaRamp.Green));
+ Logger.WriteLine("Gamma B: " + string.Join("-", gammaRamp.Blue));
+ }
+ }
+
+ if (gammaRamp is null || !gammaRamp.IsOriginal())
+ {
+ Logger.WriteLine("Default Gamma");
+ gammaRamp = new DisplayGammaRamp();
+ }
+
+ var ramp = gammaRamp.AsBrightnessRamp(bright);
+ bool result = ScreenNative.SetDeviceGammaRamp(handle, ref ramp);
+
+ Logger.WriteLine("Brightness " + bright.ToString() + ": " + result);
+
+ } catch (Exception ex)
+ {
+ Logger.WriteLine(ex.ToString());
+ }
+
+ //ScreenBrightness.Set(60 + (int)(40 * bright));
+ }
+
public void SetScreen(int frequency = -1, int overdrive = -1, int miniled = -1)
{
var laptopScreen = ScreenNative.FindLaptopScreen(true);
@@ -71,7 +137,8 @@ namespace GHelper.Display
if (miniled1 >= 0)
{
miniled = (miniled1 == 1) ? 0 : 1;
- } else
+ }
+ else
{
switch (miniled2)
{
diff --git a/app/Display/ScreenNative.cs b/app/Display/ScreenNative.cs
index 90cfdbf0..0b260fd3 100644
--- a/app/Display/ScreenNative.cs
+++ b/app/Display/ScreenNative.cs
@@ -32,6 +32,16 @@ namespace GHelper.Display
}
internal class ScreenNative
{
+
+ [DllImport("gdi32", CharSet = CharSet.Unicode)]
+ internal static extern IntPtr CreateDC(string driver, string device, string port, IntPtr deviceMode);
+
+ [DllImport("gdi32")]
+ internal static extern bool SetDeviceGammaRamp(IntPtr dcHandle, ref GammaRamp ramp);
+
+ [DllImport("gdi32")]
+ internal static extern bool GetDeviceGammaRamp(IntPtr dcHandle, ref GammaRamp ramp);
+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DEVMODE
{
@@ -146,7 +156,7 @@ namespace GHelper.Display
public const string defaultDevice = @"\\.\DISPLAY1";
- private static string? FindInternalName(bool log = false)
+ public static string? FindInternalName(bool log = false)
{
try
{
diff --git a/app/Properties/Resources.Designer.cs b/app/Properties/Resources.Designer.cs
index 8ff78342..971b35c6 100644
--- a/app/Properties/Resources.Designer.cs
+++ b/app/Properties/Resources.Designer.cs
@@ -210,6 +210,16 @@ namespace GHelper.Properties {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap icons8_brightness_32 {
+ get {
+ object obj = ResourceManager.GetObject("icons8-brightness-32", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
diff --git a/app/Properties/Resources.resx b/app/Properties/Resources.resx
index 7d0ca668..ea07c07c 100644
--- a/app/Properties/Resources.resx
+++ b/app/Properties/Resources.resx
@@ -136,6 +136,9 @@
..\Resources\icons8-bicycle-48 (1).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\standard.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
..\Resources\eco.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -163,9 +166,15 @@
..\Resources\icons8-automation-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\icons8-settings-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
..\Resources\brightness-up.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\brightness-down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
..\Resources\icons8-processor-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -187,15 +196,9 @@
..\Resources\icons8-laptop-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
- ..\Resources\ally.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
..\Resources\icons8-remove-64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
- ..\Resources\icons8-share-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
..\Resources\icons8-function-mac-96.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -229,14 +232,11 @@
..\Resources\icons8-xbox-rt-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
- ..\Resources\icons8-controller-96.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
..\Resources\icons8-fan-48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
- ..\Resources\icons8-settings-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\icons8-controller-96.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
..\Resources\icons8-maus-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -250,8 +250,11 @@
..\Resources\dot-ultimate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
- ..\Resources\brightness-down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\icons8-heartbeat-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\ally.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
..\Resources\backlight-up.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -319,8 +322,8 @@
..\Resources\icons8-software-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
- ..\Resources\standard.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\icons8-share-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
..\Resources\icons8-soonvibes-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -331,7 +334,7 @@
..\Resources\icons8-charging-battery-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
- ..\Resources\icons8-heartbeat-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\icons8-brightness-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
\ No newline at end of file
diff --git a/app/Resources/icons8-brightness-32.png b/app/Resources/icons8-brightness-32.png
new file mode 100644
index 0000000000000000000000000000000000000000..a1deb58f23c30a19b13c9d0de978aa0febe95a22
GIT binary patch
literal 420
zcmV;V0bBlwP)pqYHGhrreI&v+R^?*w0u+rLxzy{bg@~^m+
zcl9?-tbAuPZ#*Z!5;(L7>)Zni>C+a=842)eA*}O7GvSS;hq&TARD38?>T94**=>k{
zO@O%K+E=_UD?8M{&ag$lQD{`Siy*F;ozkl`Doi69m^9-4(5nmvCJ_zXpE6K%kb;p#
z%Fnh4>r=4Df82&KenfTO0fATq7