From 22ae2bc1782f5a5db1de77c59e9af83674dffac6 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sun, 12 Dec 2021 09:23:24 +1300 Subject: [PATCH] Fixed multiple adapters and unsupported HDR parsing Now supports multiple display adapters. Has been tested by @matthex with his 7 screens and 2 display adapters and works. Should fix #60 finally. Also changed the way that cloned display configurations are patched. Was using the HDR structure previously as that contains a direct mapping, but of course it completely breaks if HDR information isn't supported by the monitor, or provided over the connection technology used. So the changes I made now use the display path priority order to figure out which cloned monitor belongs to which item. Firstly, the UID's are pulled from the physical displays so that we have a list of them. We then go through the paths, and for each target we check if there is a matching physical UID. If there is NOT a matching physical ID, then it is a cloned display target. We store that for later. Next, we go through the paths again, and we figure out which physical displays are NOT in use as display targets. When we have that list, we then map the left over physical displays to the cloned displays in path priority order. Finally, we then go through each cloned display target in the paths array, and set it to the configuration that windows needs so it will make a cloned display. We also go through the modes array, and set the physical display id to the corresponding mapped physical UID we calculated earlier. All of this results in Windows accepting the cloned display configuration as expected. --- DisplayMagician/Properties/AssemblyInfo.cs | 4 +- DisplayMagicianShared/Windows/WinLibrary.cs | 49 ++++++++++++--------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/DisplayMagician/Properties/AssemblyInfo.cs b/DisplayMagician/Properties/AssemblyInfo.cs index 8283356..d79bce4 100644 --- a/DisplayMagician/Properties/AssemblyInfo.cs +++ b/DisplayMagician/Properties/AssemblyInfo.cs @@ -26,8 +26,8 @@ using System.Resources; [assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")] // Version information -[assembly: AssemblyVersion("2.1.1.38")] -[assembly: AssemblyFileVersion("2.1.1.38")] +[assembly: AssemblyVersion("2.1.1.40")] +[assembly: AssemblyFileVersion("2.1.1.40")] [assembly: NeutralResourcesLanguageAttribute( "en" )] [assembly: CLSCompliant(true)] diff --git a/DisplayMagicianShared/Windows/WinLibrary.cs b/DisplayMagicianShared/Windows/WinLibrary.cs index 54c5cbb..bcb07ee 100644 --- a/DisplayMagicianShared/Windows/WinLibrary.cs +++ b/DisplayMagicianShared/Windows/WinLibrary.cs @@ -37,7 +37,7 @@ namespace DisplayMagicianShared.Windows public Dictionary DisplayAdapters; public DISPLAYCONFIG_PATH_INFO[] DisplayConfigPaths; public DISPLAYCONFIG_MODE_INFO[] DisplayConfigModes; - public ADVANCED_HDR_INFO_PER_PATH[] DisplayHDRStates; + public List DisplayHDRStates; public Dictionary GdiDisplaySettings; public bool IsCloned; // Note: We purposely have left out the DisplaySources from the Equals as it's order keeps changing after each reboot and after each profile swap @@ -159,7 +159,7 @@ namespace DisplayMagicianShared.Windows myDefaultConfig.DisplayAdapters = new Dictionary(); myDefaultConfig.DisplayConfigModes = new DISPLAYCONFIG_MODE_INFO[0]; myDefaultConfig.DisplayConfigPaths = new DISPLAYCONFIG_PATH_INFO[0]; - myDefaultConfig.DisplayHDRStates = new ADVANCED_HDR_INFO_PER_PATH[0]; + myDefaultConfig.DisplayHDRStates = new List(); myDefaultConfig.DisplayIdentifiers = new List(); myDefaultConfig.DisplaySources = new Dictionary>(); myDefaultConfig.IsCloned = false; @@ -245,18 +245,19 @@ namespace DisplayMagicianShared.Windows SharedLogger.logger.Trace($"WinLibrary/PatchAdapterIDs: Going through the display config HDR info to update the adapter id"); // Update the HDRInfo with the current adapter id - for (int i = 0; i < savedDisplayConfig.DisplayHDRStates.Length; i++) + for (int i = 0; i < savedDisplayConfig.DisplayHDRStates.Count; i++) { + ADVANCED_HDR_INFO_PER_PATH hdrInfo = savedDisplayConfig.DisplayHDRStates[i]; // Change the Mode AdapterID if (adapterOldToNewMap.ContainsKey(savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value)) { // We get here if there is a matching adapter newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value]; - savedDisplayConfig.DisplayHDRStates[i].AdapterId = AdapterValueToLUID(newAdapterValue); + hdrInfo.AdapterId = AdapterValueToLUID(newAdapterValue); newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayHDRStates[i].AdvancedColorInfo.Header.AdapterId.Value]; - savedDisplayConfig.DisplayHDRStates[i].AdvancedColorInfo.Header.AdapterId = AdapterValueToLUID(newAdapterValue); + hdrInfo.AdvancedColorInfo.Header.AdapterId = AdapterValueToLUID(newAdapterValue); newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayHDRStates[i].SDRWhiteLevel.Header.AdapterId.Value]; - savedDisplayConfig.DisplayHDRStates[i].SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue); + hdrInfo.SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue); } else { @@ -264,9 +265,9 @@ namespace DisplayMagicianShared.Windows // (it is highly likely to... its only if the user has multiple graphics cards with some weird config it may break) newAdapterValue = currentAdapterMap.First().Key; SharedLogger.logger.Warn($"WinLibrary/PatchAdapterIDs: Uh Oh. Adapter {savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value} didn't have a current match! It's possible the adapter was swapped or disabled. Attempting to use adapter {newAdapterValue} instead."); - savedDisplayConfig.DisplayHDRStates[i].AdapterId = AdapterValueToLUID(newAdapterValue); - savedDisplayConfig.DisplayHDRStates[i].AdvancedColorInfo.Header.AdapterId = AdapterValueToLUID(newAdapterValue); - savedDisplayConfig.DisplayHDRStates[i].SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue); + hdrInfo.AdapterId = AdapterValueToLUID(newAdapterValue); + hdrInfo.AdvancedColorInfo.Header.AdapterId = AdapterValueToLUID(newAdapterValue); + hdrInfo.SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue); } } @@ -349,7 +350,7 @@ namespace DisplayMagicianShared.Windows // Prepare the empty windows display config WINDOWS_DISPLAY_CONFIG windowsDisplayConfig = new WINDOWS_DISPLAY_CONFIG(); windowsDisplayConfig.DisplayAdapters = new Dictionary(); - windowsDisplayConfig.DisplayHDRStates = new ADVANCED_HDR_INFO_PER_PATH[pathCount]; + windowsDisplayConfig.DisplayHDRStates = new List(); windowsDisplayConfig.DisplaySources = new Dictionary>(); windowsDisplayConfig.IsCloned = false; @@ -376,8 +377,6 @@ namespace DisplayMagicianShared.Windows List targetIdsFound = new List(); List replacementIds = new List(); bool isClonedProfile = false; - var hdrInfos = new ADVANCED_HDR_INFO_PER_PATH[pathCount]; - int hdrInfoCount = 0; for (int i = 0; i < paths.Length; i++) { bool gotSourceDeviceName = false; @@ -465,6 +464,11 @@ namespace DisplayMagicianShared.Windows SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to query the adapter name for adapter {paths[i].TargetInfo.AdapterId.Value}."); } } + else + { + // We already have the adapter name + gotAdapterName = true; + } // Get advanced color info SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get advanced color info for display {paths[i].TargetInfo.Id}."); @@ -518,18 +522,20 @@ namespace DisplayMagicianShared.Windows SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - Unabled to get SDR White levels for display {paths[i].TargetInfo.Id}."); } - hdrInfos[hdrInfoCount] = new ADVANCED_HDR_INFO_PER_PATH(); - hdrInfos[hdrInfoCount].AdapterId = paths[i].TargetInfo.AdapterId; - hdrInfos[hdrInfoCount].Id = paths[i].TargetInfo.Id; + // Only create and add the ADVANCED_HDR_INFO_PER_PATH if the info is there if (gotAdvancedColorInfo) { - hdrInfos[hdrInfoCount].AdvancedColorInfo = colorInfo; + ADVANCED_HDR_INFO_PER_PATH hdrInfo = new ADVANCED_HDR_INFO_PER_PATH(); + hdrInfo.AdapterId = paths[i].TargetInfo.AdapterId; + hdrInfo.Id = paths[i].TargetInfo.Id; + hdrInfo.AdvancedColorInfo = colorInfo; + if (gotSdrWhiteLevel) + { + hdrInfo.SDRWhiteLevel = whiteLevelInfo; + } + windowsDisplayConfig.DisplayHDRStates.Add(hdrInfo); } - if (gotSdrWhiteLevel) - { - hdrInfos[hdrInfoCount].SDRWhiteLevel = whiteLevelInfo; - } - hdrInfoCount++; + } @@ -622,7 +628,6 @@ namespace DisplayMagicianShared.Windows // Store the active paths and modes in our display config object windowsDisplayConfig.DisplayConfigPaths = paths; windowsDisplayConfig.DisplayConfigModes = modes; - windowsDisplayConfig.DisplayHDRStates = hdrInfos; windowsDisplayConfig.GdiDisplaySettings = GetGdiDisplaySettings(); return windowsDisplayConfig;