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.
This commit is contained in:
Terry MacDonald 2021-12-12 09:23:24 +13:00
parent 9416ac3346
commit 22ae2bc178
2 changed files with 29 additions and 24 deletions

View File

@ -26,8 +26,8 @@ using System.Resources;
[assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")] [assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")]
// Version information // Version information
[assembly: AssemblyVersion("2.1.1.38")] [assembly: AssemblyVersion("2.1.1.40")]
[assembly: AssemblyFileVersion("2.1.1.38")] [assembly: AssemblyFileVersion("2.1.1.40")]
[assembly: NeutralResourcesLanguageAttribute( "en" )] [assembly: NeutralResourcesLanguageAttribute( "en" )]
[assembly: CLSCompliant(true)] [assembly: CLSCompliant(true)]

View File

@ -37,7 +37,7 @@ namespace DisplayMagicianShared.Windows
public Dictionary<ulong, string> DisplayAdapters; public Dictionary<ulong, string> DisplayAdapters;
public DISPLAYCONFIG_PATH_INFO[] DisplayConfigPaths; public DISPLAYCONFIG_PATH_INFO[] DisplayConfigPaths;
public DISPLAYCONFIG_MODE_INFO[] DisplayConfigModes; public DISPLAYCONFIG_MODE_INFO[] DisplayConfigModes;
public ADVANCED_HDR_INFO_PER_PATH[] DisplayHDRStates; public List<ADVANCED_HDR_INFO_PER_PATH> DisplayHDRStates;
public Dictionary<string, GDI_DISPLAY_SETTING> GdiDisplaySettings; public Dictionary<string, GDI_DISPLAY_SETTING> GdiDisplaySettings;
public bool IsCloned; 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 // 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<ulong, string>(); myDefaultConfig.DisplayAdapters = new Dictionary<ulong, string>();
myDefaultConfig.DisplayConfigModes = new DISPLAYCONFIG_MODE_INFO[0]; myDefaultConfig.DisplayConfigModes = new DISPLAYCONFIG_MODE_INFO[0];
myDefaultConfig.DisplayConfigPaths = new DISPLAYCONFIG_PATH_INFO[0]; myDefaultConfig.DisplayConfigPaths = new DISPLAYCONFIG_PATH_INFO[0];
myDefaultConfig.DisplayHDRStates = new ADVANCED_HDR_INFO_PER_PATH[0]; myDefaultConfig.DisplayHDRStates = new List<ADVANCED_HDR_INFO_PER_PATH>();
myDefaultConfig.DisplayIdentifiers = new List<string>(); myDefaultConfig.DisplayIdentifiers = new List<string>();
myDefaultConfig.DisplaySources = new Dictionary<string, List<uint>>(); myDefaultConfig.DisplaySources = new Dictionary<string, List<uint>>();
myDefaultConfig.IsCloned = false; 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"); 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 // 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 // Change the Mode AdapterID
if (adapterOldToNewMap.ContainsKey(savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value)) if (adapterOldToNewMap.ContainsKey(savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value))
{ {
// We get here if there is a matching adapter // We get here if there is a matching adapter
newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value]; 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]; 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]; newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayHDRStates[i].SDRWhiteLevel.Header.AdapterId.Value];
savedDisplayConfig.DisplayHDRStates[i].SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue); hdrInfo.SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue);
} }
else 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) // (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; 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."); 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); hdrInfo.AdapterId = AdapterValueToLUID(newAdapterValue);
savedDisplayConfig.DisplayHDRStates[i].AdvancedColorInfo.Header.AdapterId = AdapterValueToLUID(newAdapterValue); hdrInfo.AdvancedColorInfo.Header.AdapterId = AdapterValueToLUID(newAdapterValue);
savedDisplayConfig.DisplayHDRStates[i].SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue); hdrInfo.SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue);
} }
} }
@ -349,7 +350,7 @@ namespace DisplayMagicianShared.Windows
// Prepare the empty windows display config // Prepare the empty windows display config
WINDOWS_DISPLAY_CONFIG windowsDisplayConfig = new WINDOWS_DISPLAY_CONFIG(); WINDOWS_DISPLAY_CONFIG windowsDisplayConfig = new WINDOWS_DISPLAY_CONFIG();
windowsDisplayConfig.DisplayAdapters = new Dictionary<ulong, string>(); windowsDisplayConfig.DisplayAdapters = new Dictionary<ulong, string>();
windowsDisplayConfig.DisplayHDRStates = new ADVANCED_HDR_INFO_PER_PATH[pathCount]; windowsDisplayConfig.DisplayHDRStates = new List<ADVANCED_HDR_INFO_PER_PATH>();
windowsDisplayConfig.DisplaySources = new Dictionary<string, List<uint>>(); windowsDisplayConfig.DisplaySources = new Dictionary<string, List<uint>>();
windowsDisplayConfig.IsCloned = false; windowsDisplayConfig.IsCloned = false;
@ -376,8 +377,6 @@ namespace DisplayMagicianShared.Windows
List<uint> targetIdsFound = new List<uint>(); List<uint> targetIdsFound = new List<uint>();
List<uint> replacementIds = new List<uint>(); List<uint> replacementIds = new List<uint>();
bool isClonedProfile = false; bool isClonedProfile = false;
var hdrInfos = new ADVANCED_HDR_INFO_PER_PATH[pathCount];
int hdrInfoCount = 0;
for (int i = 0; i < paths.Length; i++) for (int i = 0; i < paths.Length; i++)
{ {
bool gotSourceDeviceName = false; 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}."); 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 // Get advanced color info
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get advanced color info for display {paths[i].TargetInfo.Id}."); 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}."); 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(); // Only create and add the ADVANCED_HDR_INFO_PER_PATH if the info is there
hdrInfos[hdrInfoCount].AdapterId = paths[i].TargetInfo.AdapterId;
hdrInfos[hdrInfoCount].Id = paths[i].TargetInfo.Id;
if (gotAdvancedColorInfo) 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 // Store the active paths and modes in our display config object
windowsDisplayConfig.DisplayConfigPaths = paths; windowsDisplayConfig.DisplayConfigPaths = paths;
windowsDisplayConfig.DisplayConfigModes = modes; windowsDisplayConfig.DisplayConfigModes = modes;
windowsDisplayConfig.DisplayHDRStates = hdrInfos;
windowsDisplayConfig.GdiDisplaySettings = GetGdiDisplaySettings(); windowsDisplayConfig.GdiDisplaySettings = GetGdiDisplaySettings();
return windowsDisplayConfig; return windowsDisplayConfig;