From 9c0cd1511539f9fcad4c84ac0f2dde1e660e651f Mon Sep 17 00:00:00 2001 From: Serge <5920850+seerge@users.noreply.github.com> Date: Tue, 19 Sep 2023 12:52:35 +0200 Subject: [PATCH] HDR Detection / Multi-Zone switch improvements https://github.com/seerge/g-helper/issues/1319 --- app/Display/ScreenCCD.cs | 388 ++++++++++++++++++++++++++++ app/Display/ScreenControl.cs | 1 + app/Display/ScreenNative.cs | 1 - app/Helpers/ClamshellModeControl.cs | 4 + app/Program.cs | 6 +- app/Settings.cs | 2 +- 6 files changed, 397 insertions(+), 5 deletions(-) create mode 100644 app/Display/ScreenCCD.cs diff --git a/app/Display/ScreenCCD.cs b/app/Display/ScreenCCD.cs new file mode 100644 index 00000000..c979bef6 --- /dev/null +++ b/app/Display/ScreenCCD.cs @@ -0,0 +1,388 @@ +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace GHelper.Display +{ + public class ScreenCCD + { + + public static bool GetHDRStatus() + { + var err = GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out var pathCount, out var modeCount); + if (err != 0) + throw new Win32Exception(err); + + var paths = new DISPLAYCONFIG_PATH_INFO[pathCount]; + var modes = new DISPLAYCONFIG_MODE_INFO[modeCount]; + err = QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero); + if (err != 0) + throw new Win32Exception(err); + + string internalName = AppConfig.GetString("internal_display"); + + foreach (var path in paths) + { + // get display name + var info = new DISPLAYCONFIG_TARGET_DEVICE_NAME(); + info.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + info.header.size = Marshal.SizeOf(); + info.header.adapterId = path.targetInfo.adapterId; + info.header.id = path.targetInfo.id; + err = DisplayConfigGetDeviceInfo(ref info); + if (err != 0) + throw new Win32Exception(err); + + var colorInfo = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO(); + colorInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO; + colorInfo.header.size = Marshal.SizeOf(); + colorInfo.header.adapterId = path.targetInfo.adapterId; + colorInfo.header.id = path.targetInfo.id; + err = DisplayConfigGetDeviceInfo(ref colorInfo); + if (err != 0) + throw new Win32Exception(err); + + + if (info.outputTechnology == DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY.DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL || + info.outputTechnology == DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY.DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED || + info.monitorFriendlyDeviceName == internalName) + { + Logger.WriteLine(info.monitorFriendlyDeviceName + " HDR: " + colorInfo.advancedColorEnabled); + return colorInfo.advancedColorEnabled; + } + + } + + return false; + + } + + private enum DISPLAYCONFIG_DEVICE_INFO_TYPE + { + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3, + DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4, + DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6, + DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7, + DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8, + DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9, + DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10, + DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11, + } + + private enum DISPLAYCONFIG_COLOR_ENCODING + { + DISPLAYCONFIG_COLOR_ENCODING_RGB = 0, + DISPLAYCONFIG_COLOR_ENCODING_YCBCR444 = 1, + DISPLAYCONFIG_COLOR_ENCODING_YCBCR422 = 2, + DISPLAYCONFIG_COLOR_ENCODING_YCBCR420 = 3, + DISPLAYCONFIG_COLOR_ENCODING_INTENSITY = 4, + } + + private enum DISPLAYCONFIG_SCALING + { + DISPLAYCONFIG_SCALING_IDENTITY = 1, + DISPLAYCONFIG_SCALING_CENTERED = 2, + DISPLAYCONFIG_SCALING_STRETCHED = 3, + DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4, + DISPLAYCONFIG_SCALING_CUSTOM = 5, + DISPLAYCONFIG_SCALING_PREFERRED = 128, + } + + private enum DISPLAYCONFIG_ROTATION + { + DISPLAYCONFIG_ROTATION_IDENTITY = 1, + DISPLAYCONFIG_ROTATION_ROTATE90 = 2, + DISPLAYCONFIG_ROTATION_ROTATE180 = 3, + } + + private enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY + { + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = -1, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED = 16, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_VIRTUAL = 17, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = unchecked((int)0x80000000), + } + + private enum DISPLAYCONFIG_TOPOLOGY_ID + { + DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001, + DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002, + DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004, + DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008, + } + + private enum DISPLAYCONFIG_PATH + { + DISPLAYCONFIG_PATH_ACTIVE = 0x00000001, + DISPLAYCONFIG_PATH_PREFERRED_UNSCALED = 0x00000004, + DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE = 0x00000008, + } + + private enum DISPLAYCONFIG_SOURCE_FLAGS + { + DISPLAYCONFIG_SOURCE_IN_USE = 0x00000001, + } + + private enum DISPLAYCONFIG_TARGET_FLAGS + { + DISPLAYCONFIG_TARGET_IN_USE = 0x00000001, + DISPLAYCONFIG_TARGET_FORCIBLE = 0x00000002, + DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_BOOT = 0x00000004, + DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_PATH = 0x00000008, + DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_SYSTEM = 0x00000010, + DISPLAYCONFIG_TARGET_IS_HMD = 0x00000020, + } + + private enum QDC + { + QDC_ALL_PATHS = 0x00000001, + QDC_ONLY_ACTIVE_PATHS = 0x00000002, + QDC_DATABASE_CURRENT = 0x00000004, + QDC_VIRTUAL_MODE_AWARE = 0x00000010, + QDC_INCLUDE_HMD = 0x00000020, + } + + private enum DISPLAYCONFIG_SCANLINE_ORDERING + { + DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0, + DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3, + } + + private enum DISPLAYCONFIG_PIXELFORMAT + { + DISPLAYCONFIG_PIXELFORMAT_8BPP = 1, + DISPLAYCONFIG_PIXELFORMAT_16BPP = 2, + DISPLAYCONFIG_PIXELFORMAT_24BPP = 3, + DISPLAYCONFIG_PIXELFORMAT_32BPP = 4, + DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5, + } + + private enum DISPLAYCONFIG_MODE_INFO_TYPE + { + DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1, + DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2, + DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3, + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_DEVICE_INFO_HEADER + { + public DISPLAYCONFIG_DEVICE_INFO_TYPE type; + public int size; + public LUID adapterId; + public uint id; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO + { + public DISPLAYCONFIG_DEVICE_INFO_HEADER header; + public uint value; + public DISPLAYCONFIG_COLOR_ENCODING colorEncoding; + public int bitsPerColorChannel; + + public bool advancedColorSupported => (value & 0x1) == 0x1; + public bool advancedColorEnabled => (value & 0x2) == 0x2; + public bool wideColorEnforced => (value & 0x4) == 0x4; + public bool advancedColorForceDisabled => (value & 0x8) == 0x8; + } + + [StructLayout(LayoutKind.Sequential)] + private struct POINTL + { + public int x; + public int y; + } + + [StructLayout(LayoutKind.Sequential)] + private struct LUID + { + public uint LowPart; + public int HighPart; + + public long Value => ((long)HighPart << 32) | LowPart; + public override string ToString() => Value.ToString(); + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_SOURCE_MODE + { + public uint width; + public uint height; + public DISPLAYCONFIG_PIXELFORMAT pixelFormat; + public POINTL position; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_RATIONAL + { + public uint Numerator; + public uint Denominator; + + public override string ToString() => Numerator + " / " + Denominator; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_2DREGION + { + public uint cx; + public uint cy; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO + { + public POINTL PathSourceSize; + public RECT DesktopImageRegion; + public RECT DesktopImageClip; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO + { + public ulong pixelRate; + public DISPLAYCONFIG_RATIONAL hSyncFreq; + public DISPLAYCONFIG_RATIONAL vSyncFreq; + public DISPLAYCONFIG_2DREGION activeSize; + public DISPLAYCONFIG_2DREGION totalSize; + public uint videoStandard; + public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_TARGET_MODE + { + public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo; + } + + [StructLayout(LayoutKind.Explicit)] + private struct DISPLAYCONFIG_MODE_INFO_union + { + [FieldOffset(0)] + public DISPLAYCONFIG_TARGET_MODE targetMode; + + [FieldOffset(0)] + public DISPLAYCONFIG_SOURCE_MODE sourceMode; + + [FieldOffset(0)] + public DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_PATH_SOURCE_INFO + { + public LUID adapterId; + public uint id; + public uint modeInfoIdx; + public DISPLAYCONFIG_SOURCE_FLAGS statusFlags; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_PATH_TARGET_INFO + { + public LUID adapterId; + public uint id; + public uint modeInfoIdx; + public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology; + public DISPLAYCONFIG_ROTATION rotation; + public DISPLAYCONFIG_SCALING scaling; + public DISPLAYCONFIG_RATIONAL refreshRate; + public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; + public bool targetAvailable; + public DISPLAYCONFIG_TARGET_FLAGS statusFlags; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_PATH_INFO + { + public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo; + public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo; + public DISPLAYCONFIG_PATH flags; + } + + [StructLayout(LayoutKind.Sequential)] + private struct DISPLAYCONFIG_MODE_INFO + { + public DISPLAYCONFIG_MODE_INFO_TYPE infoType; + public uint id; + public LUID adapterId; + public DISPLAYCONFIG_MODE_INFO_union info; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct DISPLAYCONFIG_SOURCE_DEVICE_NAME + { + public DISPLAYCONFIG_DEVICE_INFO_HEADER header; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string viewGdiDeviceName; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS + { + public uint value; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct DISPLAYCONFIG_TARGET_DEVICE_NAME + { + public DISPLAYCONFIG_DEVICE_INFO_HEADER header; + public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags; + public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology; + public ushort edidManufactureId; + public ushort edidProductCodeId; + public uint connectorInstance; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string monitorFriendlyDeviceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string monitorDevicePat; + } + + [StructLayout(LayoutKind.Sequential)] + private struct RECT + { + public int left; + public int top; + public int right; + public int bottom; + } + + [DllImport("user32")] + private static extern int GetDisplayConfigBufferSizes(QDC flags, out int numPathArrayElements, out int numModeInfoArrayElements); + + [DllImport("user32")] + private static extern int QueryDisplayConfig(QDC flags, ref int numPathArrayElements, [In, Out] DISPLAYCONFIG_PATH_INFO[] pathArray, ref int numModeInfoArrayElements, [In, Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, out DISPLAYCONFIG_TOPOLOGY_ID currentTopologyId); + + [DllImport("user32")] + private static extern int QueryDisplayConfig(QDC flags, ref int numPathArrayElements, [In, Out] DISPLAYCONFIG_PATH_INFO[] pathArray, ref int numModeInfoArrayElements, [In, Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, IntPtr currentTopologyId); + + [DllImport("user32")] + private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO requestPacket); + + [DllImport("user32")] + private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SOURCE_DEVICE_NAME requestPacket); + + [DllImport("user32")] + private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_DEVICE_NAME requestPacket); + } +} diff --git a/app/Display/ScreenControl.cs b/app/Display/ScreenControl.cs index b9505f78..03fdb7fa 100644 --- a/app/Display/ScreenControl.cs +++ b/app/Display/ScreenControl.cs @@ -82,6 +82,7 @@ namespace GHelper.Display if (miniled >= 0) { AppConfig.Set("miniled", miniled); + hdr = ScreenCCD.GetHDRStatus(); } bool screenEnabled = (frequency >= 0); diff --git a/app/Display/ScreenNative.cs b/app/Display/ScreenNative.cs index 8911567e..43d32b1e 100644 --- a/app/Display/ScreenNative.cs +++ b/app/Display/ScreenNative.cs @@ -1,5 +1,4 @@ using System.Collections; -using System.Diagnostics; using System.Runtime.InteropServices; using static GHelper.Display.ScreenInterrogatory; diff --git a/app/Helpers/ClamshellModeControl.cs b/app/Helpers/ClamshellModeControl.cs index b5c39831..e3565533 100644 --- a/app/Helpers/ClamshellModeControl.cs +++ b/app/Helpers/ClamshellModeControl.cs @@ -95,6 +95,10 @@ namespace GHelper.Helpers if (IsClamshellEnabled()) ToggleLidAction(); + + if (Program.settingsForm.Visible) + Program.screenControl.InitScreen(); + } private static int CheckAndSaveLidAction() diff --git a/app/Program.cs b/app/Program.cs index 88c41d79..a903a3fd 100644 --- a/app/Program.cs +++ b/app/Program.cs @@ -29,9 +29,9 @@ namespace GHelper public static SettingsForm settingsForm = new SettingsForm(); public static ModeControl modeControl = new ModeControl(); - static GPUModeControl gpuControl = new GPUModeControl(settingsForm); - static ScreenControl screenControl = new ScreenControl(); - static ClamshellModeControl clamshellControl = new ClamshellModeControl(); + public static GPUModeControl gpuControl = new GPUModeControl(settingsForm); + public static ScreenControl screenControl = new ScreenControl(); + public static ClamshellModeControl clamshellControl = new ClamshellModeControl(); public static ToastForm toast = new ToastForm(); diff --git a/app/Settings.cs b/app/Settings.cs index ff93dca7..48603c00 100644 --- a/app/Settings.cs +++ b/app/Settings.cs @@ -799,7 +799,7 @@ namespace GHelper if (miniled >= 0) { - buttonMiniled.Activated = (miniled == 1); + buttonMiniled.Activated = (miniled == 1) || hdr; buttonMiniled.Enabled = !hdr; } else