From 1591fd534e541e36dc1d0c2f99b39a829075d24b Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 18 Sep 2021 21:55:43 +1200 Subject: [PATCH] Upgraded AMDLibrary to v1.0.0 This is the first actual working version of the AMDLibrary from AMDInfo v1.0.0. This is the first time that all 3 different video libraries are in DisplayMagician and working (mostly). The AMD Screens structu creation logic in ProfileItem still needs to be updated to cope with the AMD Eyefinity configuration, but it at least defaults to the windows one at the moment so it doesn't crash (whew). Also managed to bugfix the recent libraryfolder.vdf parsing change that a recent Steam Library change oforced on us. The logic wasn't working, and so the parsing didn't work, which in turn caused an exception when it came time to look up the game shortcut validity. --- DisplayMagician/GameLibraries/SteamLibrary.cs | 47 +- DisplayMagicianShared/AMD/ADL.cs | 238 +- DisplayMagicianShared/AMD/AMDLibrary.cs | 2371 ++++++++++------- DisplayMagicianShared/NVIDIA/NVAPI.cs | 1 + DisplayMagicianShared/ProfileItem.cs | 10 +- 5 files changed, 1567 insertions(+), 1100 deletions(-) diff --git a/DisplayMagician/GameLibraries/SteamLibrary.cs b/DisplayMagician/GameLibraries/SteamLibrary.cs index 5f07048..92e1d0b 100644 --- a/DisplayMagician/GameLibraries/SteamLibrary.cs +++ b/DisplayMagician/GameLibraries/SteamLibrary.cs @@ -623,7 +623,7 @@ namespace DisplayMagician.GameLibraries // Now we have to parse the config.vdf looking for the location of any additional SteamLibraries // We look for lines similar to this: "BaseInstallFolder_1" "E:\\SteamLibrary" // There may be multiple so we need to check the whole file - Regex steamLibrariesRegex = new Regex(@"\t""\d+""\t\t""(.*?)""\n", RegexOptions.IgnoreCase); + Regex steamLibrariesRegex = new Regex(@"\t""path""\t\t""(.*?)""\n", RegexOptions.IgnoreCase); // Try to match all lines against the Regex. MatchCollection steamLibrariesMatches = steamLibrariesRegex.Matches(steamLibraryFoldersText); // If at least one of them matched! @@ -640,17 +640,18 @@ namespace DisplayMagician.GameLibraries } else { - logger.Trace($"SteamLibrary/LoadInstalledGames: Found what it thought was an additional steam library {steamLibraryPath}, but it didn't exist on the file system"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Found what it thought was an additional steam library {steamLibraryPath} in {_steamLibraryFoldersVdfFile}, but it didn't exist on the file system"); } } } } - else + + _steamConfigVdfFile = Path.Combine(_steamPath, "config", "config.vdf"); + if (File.Exists(_steamConfigVdfFile)) { - logger.Trace($"SteamLibrary/LoadInstalledGames: There was no {_steamLibraryFoldersVdfFile } VDF file, so processing the {_steamConfigVdfFile} VDF file instead"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Processing the {_steamConfigVdfFile} VDF file as well as it was found too"); // Now we access the config.vdf that lives in the Steam Config file, as that lists all - // the SteamLibraries. We need to find out where they areso we can interrogate them - _steamConfigVdfFile = Path.Combine(_steamPath, "config", "config.vdf"); + // the SteamLibraries. We need to find out where they areso we can interrogate them string steamConfigVdfText = File.ReadAllText(_steamConfigVdfFile, Encoding.UTF8); logger.Trace($"SteamLibrary/LoadInstalledGames: Processing the {_steamConfigVdfFile} VDF file"); @@ -671,11 +672,15 @@ namespace DisplayMagician.GameLibraries if (Directory.Exists(steamLibraryPath)) { logger.Info($"SteamLibrary/LoadInstalledGames: Found additional steam library {steamLibraryPath}"); - steamLibrariesPaths.Add(steamLibraryPath); + // Check if the steam library is already in the list! + if (!steamLibrariesPaths.Contains(steamLibraryPath)) + { + steamLibrariesPaths.Add(steamLibraryPath); + } } else { - logger.Trace($"SteamLibrary/LoadInstalledGames: Found what it thought was an additional steam library {steamLibraryPath}, but it didn't exist on the file system"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Found what it thought was an additional steam library {steamLibraryPath} in {_steamConfigVdfFile}, but it didn't exist on the file system"); } } } @@ -717,23 +722,23 @@ namespace DisplayMagician.GameLibraries // Construct the full path to the game dir from the appInfo and libraryAppManifest data string steamGameInstallDir = Path.Combine(steamLibraryPath, @"steamapps", @"common", steamAppInfo[steamGameId].GameInstallDir); - logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game ID {steamGameId} at {steamGameInstallDir }"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game ID {steamGameId} at {steamGameInstallDir }"); - // And finally we try to populate the 'where', to see what gets run - // And so we can extract the process name - if (steamAppInfo[steamGameId].GameExes.Count > 0) + // And finally we try to populate the 'where', to see what gets run + // And so we can extract the process name + if (steamAppInfo[steamGameId].GameExes.Count > 0) + { + foreach (string gameExe in steamAppInfo[steamGameId].GameExes) { - foreach (string gameExe in steamAppInfo[steamGameId].GameExes) + steamGameExe = Path.Combine(steamGameInstallDir, gameExe); + logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }"); + // If the game executable exists, then we can proceed + if (File.Exists(steamGameExe)) { - steamGameExe = Path.Combine(steamGameInstallDir, gameExe); - logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }"); - // If the game executable exists, then we can proceed - if (File.Exists(steamGameExe)) - { - logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }"); - break; - } + logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }"); + break; } + } } diff --git a/DisplayMagicianShared/AMD/ADL.cs b/DisplayMagicianShared/AMD/ADL.cs index d7897e9..a42b7e6 100644 --- a/DisplayMagicianShared/AMD/ADL.cs +++ b/DisplayMagicianShared/AMD/ADL.cs @@ -7,7 +7,7 @@ namespace DisplayMagicianShared.AMD { public delegate IntPtr ADL_Main_Memory_Alloc_Delegate(int size); - public enum ADL_STATUS + public enum ADL_STATUS : int { // Result Codes /// ADL function completed successfully. @@ -50,7 +50,7 @@ namespace DisplayMagicianShared.AMD ADL_OK_WARNING = 1, } - public enum ADL_CONNECTION_TYPE + public enum ADL_CONNECTION_TYPE : int { VGA = 0, DVI = 1, @@ -68,7 +68,7 @@ namespace DisplayMagicianShared.AMD Virtual = 13 } - public enum ADL_DISPLAY_CONNECTION_TYPE + public enum ADL_DISPLAY_CONNECTION_TYPE : int { Unknown = 0, VGA = 1, @@ -91,7 +91,8 @@ namespace DisplayMagicianShared.AMD USBTypeC = 18 } - public enum ADL_DISPLAY_MODE_FLAG + [Flags] + public enum ADL_DISPLAY_MODE_FLAG : int { ColourFormat565 = 1, ColourFormat8888 = 2, @@ -102,12 +103,24 @@ namespace DisplayMagicianShared.AMD ExactRefreshRate = 80, RoundedRefreshRate = 40 } - public enum ADL_DISPLAY_MODE_INTERLACING + public enum ADL_DISPLAY_MODE_INTERLACING : int { Progressive = 0, Interlaced = 2 } + public enum ADL_COLORDEPTH : int + { + ColorDepth_Unknown = 0, + ColorDepth_666 = 1, + ColorDepth_888 = 2, + ColorDepth_101010 = 3, + ColorDepth_121212 = 4, + ColorDepth_141414 = 5, + ColorDepth_161616 = 6, + } + + /// ADLAdapterInfo Array [StructLayout(LayoutKind.Sequential)] public struct ADL_MODE : IEquatable @@ -161,6 +174,7 @@ namespace DisplayMagicianShared.AMD public bool ProgressiveSet => ModeValue == 0x0; public bool InterlacedSet => ModeValue == 0x2; + public override bool Equals(object obj) => obj is ADL_MODE other && this.Equals(other); public bool Equals(ADL_MODE other) => AdapterIndex == other.AdapterIndex && DisplayID.Equals(other.DisplayID) && @@ -180,6 +194,10 @@ namespace DisplayMagicianShared.AMD return (AdapterIndex, DisplayID, XPos, YPos, XRes, YRes, ColourDepth, RefreshRate, Orientation, ModeFlag, ModeMask, ModeValue).GetHashCode(); } + public static bool operator ==(ADL_MODE lhs, ADL_MODE rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_MODE lhs, ADL_MODE rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -202,6 +220,7 @@ namespace DisplayMagicianShared.AMD // DisplayTarget Value settings public bool DisplayTargetPreferredSet => (DisplayTargetValue & 0x1) == 0x1; + public override bool Equals(object obj) => obj is ADL_DISPLAY_TARGET other && this.Equals(other); public bool Equals(ADL_DISPLAY_TARGET other) => DisplayID.Equals(other.DisplayID) && DisplayMapIndex == other.DisplayMapIndex && @@ -213,6 +232,10 @@ namespace DisplayMagicianShared.AMD return (DisplayID, DisplayMapIndex, DisplayTargetMask, DisplayTargetValue).GetHashCode(); } + public static bool operator ==(ADL_DISPLAY_TARGET lhs, ADL_DISPLAY_TARGET rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_DISPLAY_TARGET lhs, ADL_DISPLAY_TARGET rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -265,6 +288,8 @@ namespace DisplayMagicianShared.AMD #define ADL_ADAPTER_DISPLAYCAP_PREFERDISPLAY_SUPPORTED 0x00000100 #define ADL_ADAPTER_DISPLAYCAP_BEZEL_SUPPORTED 0x00000200*/ + + public override bool Equals(object obj) => obj is ADL_ADAPTER_DISPLAY_CAP other && this.Equals(other); public bool Equals(ADL_ADAPTER_DISPLAY_CAP other) => AdapterIndex == other.AdapterIndex && AdapterDisplayCapMask == other.AdapterDisplayCapMask && @@ -274,6 +299,9 @@ namespace DisplayMagicianShared.AMD { return (AdapterIndex, AdapterDisplayCapMask, AdapterDisplayCapValue).GetHashCode(); } + public static bool operator ==(ADL_ADAPTER_DISPLAY_CAP lhs, ADL_ADAPTER_DISPLAY_CAP rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_ADAPTER_DISPLAY_CAP lhs, ADL_ADAPTER_DISPLAY_CAP rhs) => !(lhs == rhs); //public override string ToString() => $"{type.ToString("G")}"; } @@ -319,6 +347,7 @@ namespace DisplayMagicianShared.AMD /// OS Display Index public int OSDisplayIndex; + public override bool Equals(object obj) => obj is ADL_ADAPTER_INFO other && this.Equals(other); public bool Equals(ADL_ADAPTER_INFO other) => Size == other.Size && AdapterIndex == other.AdapterIndex && @@ -341,6 +370,9 @@ namespace DisplayMagicianShared.AMD return (Size, AdapterIndex, UDID, BusNumber, DriverNumber, FunctionNumber, VendorID, AdapterName, DisplayName, Present, Exist, DriverPath, DriverPathExt, PNPString, OSDisplayIndex).GetHashCode(); } + public static bool operator ==(ADL_ADAPTER_INFO lhs, ADL_ADAPTER_INFO rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_ADAPTER_INFO lhs, ADL_ADAPTER_INFO rhs) => !(lhs == rhs); //public override string ToString() => $"{type.ToString("G")}"; } @@ -430,6 +462,7 @@ namespace DisplayMagicianShared.AMD public bool MannerReserved3Set => (InfoValue & 0x80000) == 0x80000; public bool ShowTypeProjectorSet => (InfoValue & 0x100000) == 0x100000; + public override bool Equals(object obj) => obj is ADL_ADAPTER_INFOX2 other && this.Equals(other); public bool Equals(ADL_ADAPTER_INFOX2 other) => Size == other.Size && AdapterIndex == other.AdapterIndex && @@ -454,6 +487,10 @@ namespace DisplayMagicianShared.AMD return (Size, AdapterIndex, UDID, BusNumber, DeviceNumber, FunctionNumber, VendorID, AdapterName, DisplayName, Present, Exist, DriverPath, DriverPathExt, PNPString, OSDisplayIndex).GetHashCode(); } + public static bool operator ==(ADL_ADAPTER_INFOX2 lhs, ADL_ADAPTER_INFOX2 rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_ADAPTER_INFOX2 lhs, ADL_ADAPTER_INFOX2 rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -475,6 +512,7 @@ namespace DisplayMagicianShared.AMD [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public int[] Reserved; + public override bool Equals(object obj) => obj is ADL_DISPLAY_EDID_DATA other && this.Equals(other); public bool Equals(ADL_DISPLAY_EDID_DATA other) => Size == other.Size && Flag == other.Flag && @@ -487,6 +525,10 @@ namespace DisplayMagicianShared.AMD return (Size, Flag, EDIDSize, BlockIndex, EDIDData).GetHashCode(); } + public static bool operator ==(ADL_DISPLAY_EDID_DATA lhs, ADL_DISPLAY_EDID_DATA rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_DISPLAY_EDID_DATA lhs, ADL_DISPLAY_EDID_DATA rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -625,6 +667,7 @@ namespace DisplayMagicianShared.AMD public bool FreeSyncHDRBacklightSupported => (SupportedHDR & 0x1) == 0x1; public bool FreeSyncHDRLocalDimmingSupported => (SupportedHDR & 0x2) == 0x2; + public override bool Equals(object obj) => obj is ADL_DDC_INFO2 other && this.Equals(other); public bool Equals(ADL_DDC_INFO2 other) => Size == other.Size && SupportsDDC == other.SupportsDDC && @@ -674,6 +717,10 @@ namespace DisplayMagicianShared.AMD MinBacklightMaxLuminanceData, MaxBacklightMinLuminanceData, MinBacklightMinLuminanceData).GetHashCode(); } + public static bool operator ==(ADL_DDC_INFO2 lhs, ADL_DDC_INFO2 rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_DDC_INFO2 lhs, ADL_DDC_INFO2 rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -690,6 +737,7 @@ namespace DisplayMagicianShared.AMD /// Adapter Physical Index public int DisplayPhysicalAdapterIndex; + public override bool Equals(object obj) => obj is ADL_DISPLAY_ID other && this.Equals(other); public bool Equals(ADL_DISPLAY_ID other) => DisplayLogicalIndex == other.DisplayLogicalIndex && DisplayPhysicalIndex == other.DisplayPhysicalIndex && @@ -701,6 +749,10 @@ namespace DisplayMagicianShared.AMD return (DisplayLogicalIndex, DisplayPhysicalIndex, DisplayLogicalAdapterIndex, DisplayPhysicalAdapterIndex).GetHashCode(); } + public static bool operator ==(ADL_DISPLAY_ID lhs, ADL_DISPLAY_ID rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_DISPLAY_ID lhs, ADL_DISPLAY_ID rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -721,9 +773,9 @@ namespace DisplayMagicianShared.AMD /// Display Type : The Display type. CRT, TV,CV,DFP are some of display types, public int DisplayType; /// Display output type - public int DisplayOutputType; - /// Connector type - public int DisplayConnector; + public ADL_CONNECTION_TYPE DisplayOutputType; + /// Connector type Indicating the display info bits' mask. public int DisplayInfoMask; /// Indicating the display info value. @@ -731,25 +783,25 @@ namespace DisplayMagicianShared.AMD // Display Type - no idea what the settings are - // Display Output Type settings - public bool DisplayOutputTypeIsUnknown => DisplayOutputType == 0; - public bool DisplayOutputTypeIsVGA => DisplayOutputType == 1; - public bool DisplayOutputTypeIsDVI_D => DisplayOutputType == 2; - public bool DisplayOutputTypeIsDVI_I => DisplayOutputType == 3; - public bool DisplayOutputTypeIsATICVDongleNTSC => DisplayOutputType == 4; - public bool DisplayOutputTypeIsATICVDongleJPN => DisplayOutputType == 5; - public bool DisplayOutputTypeIsATICVDongleNonI2CJPN => DisplayOutputType == 6; - public bool DisplayOutputTypeIsATICVDongleNonI2CNTSC => DisplayOutputType == 7; - public bool DisplayOutputTypeIsProprietary => DisplayOutputType == 8; - public bool DisplayOutputTypeIsHDMITypeA => DisplayOutputType == 10; - public bool DisplayOutputTypeIsHDMITypeB => DisplayOutputType == 11; - public bool DisplayOutputTypeIsSVideo => DisplayOutputType == 12; - public bool DisplayOutputTypeIsComposite => DisplayOutputType == 13; - public bool DisplayOutputTypeIsRCA3Component => DisplayOutputType == 14; - public bool DisplayOutputTypeIsDisplayPort => DisplayOutputType == 15; - public bool DisplayOutputTypeIsEDP => DisplayOutputType == 16; - public bool DisplayOutputTypeIsWirelessDisplay => DisplayOutputType == 17; - public bool DisplayOutputTypeIsUSBTypeC => DisplayOutputType == 18; + // Display Output Type settings + public bool DisplayConnectorIsUnknown => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.Unknown; + public bool DisplayConnectorIsVGA => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.VGA; + public bool DisplayConnectorIsDVI_D => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.DVI_D; + public bool DisplayConnectorIsDVI_I => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.DVI_I; + public bool DisplayConnectorIsATICVDongleNTSC => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.ATICV_NTSC_Dongle; + public bool DisplayConnectorIsATICVDongleJPN => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.ATICV_JPN_Dongle; + public bool DisplayConnectorIsATICVDongleNonI2CJPN => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.ATICV_NONI2C_JPN_Dongle; + public bool DisplayConnectorIsATICVDongleNonI2CNTSC => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.ATICV_NONI2C_NTSC_Dongle; + public bool DisplayConnectorIsProprietary => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.Proprietary; + public bool DisplayConnectorIsHDMITypeA => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.HDMITypeA; + public bool DisplayConnectorIsHDMITypeB => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.HTMITypeB; + public bool DisplayConnectorIsSVideo => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.SVideo; + public bool DisplayConnectorIsComposite => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.Composite; + public bool DisplayConnectorIsRCA3Component => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.RCA_3Component; + public bool DisplayConnectorIsDisplayPort => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.DisplayPort; + public bool DisplayConnectorIsEDP => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.EDP; + public bool DisplayConnectorIsWirelessDisplay => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.WirelessDisplay; + public bool DisplayConnectorIsUSBTypeC => DisplayConnector == ADL_DISPLAY_CONNECTION_TYPE.USBTypeC; /*#define ADL_DISPLAY_CONTYPE_UNKNOWN 0 @@ -773,20 +825,20 @@ namespace DisplayMagicianShared.AMD // Display Connector - public bool DisplayConnectorIsVGA => DisplayConnector == 0; - public bool DisplayConnectorIsDVI => DisplayConnector == 1; - public bool DisplayConnectorIsDVI_SL => DisplayConnector == 2; - public bool DisplayConnectorIsHDMI => DisplayConnector == 3; - public bool DisplayConnectorIsDisplayPort => DisplayConnector == 4; - public bool DisplayConnectorIsActiveDongleDP_DVI_SL => DisplayConnector == 5; - public bool DisplayConnectorIsActiveDongleDP_DVI_DL => DisplayConnector == 6; - public bool DisplayConnectorIsActiveDongleDP_HDMI => DisplayConnector == 7; - public bool DisplayConnectorIsActiveDongleDP_VGA => DisplayConnector == 8; - public bool DisplayConnectorIsPassiveDongleDP_HDMI => DisplayConnector == 9; - public bool DisplayConnectorIsPassiveDongleDP_DVI => DisplayConnector == 10; - public bool DisplayConnectorIsMST => DisplayConnector == 11; - public bool DisplayConnectorIsActiveDongle => DisplayConnector == 12; - public bool DisplayConnectorIsVirtual => DisplayConnector == 13; + public bool DisplayOutputTypeIsVGA => DisplayOutputType == ADL_CONNECTION_TYPE.VGA; + public bool DisplayOutputTypeIsDVI => DisplayOutputType == ADL_CONNECTION_TYPE.DVI; + public bool DisplayOutputTypeIsDVI_SL => DisplayOutputType == ADL_CONNECTION_TYPE.DVI_SL; + public bool DisplayOutputTypeIsHDMI => DisplayOutputType == ADL_CONNECTION_TYPE.HDMI; + public bool DisplayOutputTypeIsDisplayPort => DisplayOutputType == ADL_CONNECTION_TYPE.DisplayPort; + public bool DisplayOutputTypeIsActiveDongleDP_DVI_SL => DisplayOutputType == ADL_CONNECTION_TYPE.ActiveDongleDPToDVI_SL; + public bool DisplayOutputTypeIsActiveDongleDP_DVI_DL => DisplayOutputType == ADL_CONNECTION_TYPE.ActiveDongleDPToDVI_DL; + public bool DisplayOutputTypeIsActiveDongleDP_HDMI => DisplayOutputType == ADL_CONNECTION_TYPE.ActiveDongleDPToHDMI; + public bool DisplayOutputTypeIsActiveDongleDP_VGA => DisplayOutputType == ADL_CONNECTION_TYPE.ActiveDongleDPToVGA; + public bool DisplayOutputTypeIsPassiveDongleDP_HDMI => DisplayOutputType == ADL_CONNECTION_TYPE.PassiveDongleDPToHDMI; + public bool DisplayOutputTypeIsPassiveDongleDP_DVI => DisplayOutputType == ADL_CONNECTION_TYPE.PassiveDongleDPToDVI; + public bool DisplayOutputTypeIsMST => DisplayOutputType == ADL_CONNECTION_TYPE.MST; + public bool DisplayOutputTypeIsActiveDongle => DisplayOutputType == ADL_CONNECTION_TYPE.ActiveDongle; + public bool DisplayOutputTypeIsVirtual => DisplayOutputType == ADL_CONNECTION_TYPE.Virtual; /*#define ADL_CONNECTION_TYPE_VGA 0 #define ADL_CONNECTION_TYPE_DVI 1 @@ -844,6 +896,7 @@ namespace DisplayMagicianShared.AMD public bool MannerReserved3Set => (DisplayInfoValue & 0x80000) == 0x80000; public bool ShowTypeProjectorSet => (DisplayInfoValue & 0x100000) == 0x100000; + public override bool Equals(object obj) => obj is ADL_DISPLAY_INFO other && this.Equals(other); public bool Equals(ADL_DISPLAY_INFO other) => DisplayID.Equals(other.DisplayID) && DisplayControllerIndex == other.DisplayControllerIndex && @@ -860,6 +913,9 @@ namespace DisplayMagicianShared.AMD return (DisplayID, DisplayControllerIndex, DisplayName, DisplayID, DisplayType, DisplayOutputType, DisplayConnector, DisplayInfoMask, DisplayInfoValue).GetHashCode(); } + public static bool operator ==(ADL_DISPLAY_INFO lhs, ADL_DISPLAY_INFO rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_DISPLAY_INFO lhs, ADL_DISPLAY_INFO rhs) => !(lhs == rhs); //public override string ToString() => $"{type.ToString("G")}"; } @@ -892,6 +948,7 @@ namespace DisplayMagicianShared.AMD public bool ConnectorTypeIsHDMITypeB => ConnectorType == 9; public bool ConnectorTypeIsDisplayPort => ConnectorType == 10; + public override bool Equals(object obj) => obj is ADL_DISPLAY_CONFIG other && this.Equals(other); public bool Equals(ADL_DISPLAY_CONFIG other) => Size == other.Size && ConnectorType == other.ConnectorType && @@ -903,6 +960,10 @@ namespace DisplayMagicianShared.AMD return (Size, ConnectorType, DeviceData, OverriddedDeviceData).GetHashCode(); } + public static bool operator ==(ADL_DISPLAY_CONFIG lhs, ADL_DISPLAY_CONFIG rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_DISPLAY_CONFIG lhs, ADL_DISPLAY_CONFIG rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -943,6 +1004,7 @@ namespace DisplayMagicianShared.AMD public bool DisplayMapVStretchSet => (DisplayMapValue & 0x40) == 0x40; public bool DisplayMapVLDSet => (DisplayMapValue & 0x80) == 0x80; + public override bool Equals(object obj) => obj is ADL_DISPLAY_MAP other && this.Equals(other); public bool Equals(ADL_DISPLAY_MAP other) => DisplayMapIndex == other.DisplayMapIndex && DisplayMode.Equals(other.DisplayMode) && @@ -956,6 +1018,10 @@ namespace DisplayMagicianShared.AMD return (DisplayMapIndex, DisplayMode, NumDisplayTarget, FirstDisplayTargetArrayIndex, DisplayMapMask, DisplayMapValue).GetHashCode(); } + public static bool operator ==(ADL_DISPLAY_MAP lhs, ADL_DISPLAY_MAP rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_DISPLAY_MAP lhs, ADL_DISPLAY_MAP rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1004,6 +1070,7 @@ namespace DisplayMagicianShared.AMD public bool CapPreferredDisplaySet => (CapsValue & 0x100) == 0x100; public bool CapBezelSet => (CapsValue & 0x200) == 0x200; + public override bool Equals(object obj) => obj is ADL_ADAPTER_CAPSX2 other && this.Equals(other); public bool Equals(ADL_ADAPTER_CAPSX2 other) => AdapterID == other.AdapterID && NumControllers == other.NumControllers && @@ -1019,6 +1086,10 @@ namespace DisplayMagicianShared.AMD return (AdapterID, NumControllers, NumDisplays, NumOverlays, NumOfGLSyncConnectors, CapsMask, CapsValue, NumConnectors).GetHashCode(); } + public static bool operator ==(ADL_ADAPTER_CAPSX2 lhs, ADL_ADAPTER_CAPSX2 rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_ADAPTER_CAPSX2 lhs, ADL_ADAPTER_CAPSX2 rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1039,6 +1110,7 @@ namespace DisplayMagicianShared.AMD /// The DisplayTargets being tested public ADL_DISPLAY_TARGET DisplayTargets; + public override bool Equals(object obj) => obj is ADL_POSSIBLE_MAP other && this.Equals(other); public bool Equals(ADL_POSSIBLE_MAP other) => Index == other.Index && AdapterIndex == other.AdapterIndex && @@ -1052,6 +1124,10 @@ namespace DisplayMagicianShared.AMD return (Index, AdapterIndex, NumDisplayMap, DisplayMaps, NumDisplayTarget, DisplayTargets).GetHashCode(); } + public static bool operator ==(ADL_POSSIBLE_MAP lhs, ADL_POSSIBLE_MAP rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_POSSIBLE_MAP lhs, ADL_POSSIBLE_MAP rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1088,6 +1164,7 @@ namespace DisplayMagicianShared.AMD #define ADL_DISPLAY_DISPLAYMAP_MANNER_VSTRETCH 0x00000040 #define ADL_DISPLAY_DISPLAYMAP_MANNER_VLD 0x00000080*/ + public override bool Equals(object obj) => obj is ADL_POSSIBLE_MAPPING other && this.Equals(other); public bool Equals(ADL_POSSIBLE_MAPPING other) => DisplayIndex == other.DisplayIndex && DisplayControllerIndex == other.DisplayControllerIndex && @@ -1098,6 +1175,10 @@ namespace DisplayMagicianShared.AMD return (DisplayIndex, DisplayControllerIndex, DisplayMannerSupported).GetHashCode(); } + public static bool operator ==(ADL_POSSIBLE_MAPPING lhs, ADL_POSSIBLE_MAPPING rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_POSSIBLE_MAPPING lhs, ADL_POSSIBLE_MAPPING rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1131,6 +1212,7 @@ namespace DisplayMagicianShared.AMD #define ADL_DISPLAY_POSSIBLEMAPRESULT_BEZELSUPPORTED 0x00000002 #define ADL_DISPLAY_POSSIBLEMAPRESULT_OVERLAPSUPPORTED 0x00000004*/ + public override bool Equals(object obj) => obj is ADL_POSSIBLE_MAP_RESULT other && this.Equals(other); public bool Equals(ADL_POSSIBLE_MAP_RESULT other) => Index == other.Index && PossibleMapResultMask == other.PossibleMapResultMask && @@ -1141,6 +1223,10 @@ namespace DisplayMagicianShared.AMD return (Index, PossibleMapResultMask, PossibleMapResultValue).GetHashCode(); } + public static bool operator ==(ADL_POSSIBLE_MAP_RESULT lhs, ADL_POSSIBLE_MAP_RESULT rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_POSSIBLE_MAP_RESULT lhs, ADL_POSSIBLE_MAP_RESULT rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1191,6 +1277,7 @@ namespace DisplayMagicianShared.AMD #define ADL_DISPLAY_SLSGRID_DISPLAYROTATION_SUPPORT 0x00000040 #define ADL_DISPLAY_SLSGRID_DESKTOPROTATION_SUPPORT 0x00000080*/ + public override bool Equals(object obj) => obj is ADL_SLS_GRID other && this.Equals(other); public bool Equals(ADL_SLS_GRID other) => AdapterIndex == other.AdapterIndex && SLSGridIndex == other.SLSGridIndex && @@ -1203,6 +1290,9 @@ namespace DisplayMagicianShared.AMD { return (AdapterIndex, SLSGridIndex, SLSGridRow, SLSGridColumn, SLSGridMask, SLSGridValue).GetHashCode(); } + public static bool operator ==(ADL_SLS_GRID lhs, ADL_SLS_GRID rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_SLS_GRID lhs, ADL_SLS_GRID rhs) => !(lhs == rhs); //public override string ToString() => $"{type.ToString("G")}"; } @@ -1243,19 +1333,19 @@ namespace DisplayMagicianShared.AMD public int SLSMapValue; // SLS Orientation settings - /*public bool Orientation000 => (Orientation & 0x1) == 0x1; + public bool Orientation000 => (Orientation & 0x1) == 0x1; public bool Orientation090 => (Orientation & 0x2) == 0x2; public bool Orientation180 => (Orientation & 0x4) == 0x4; public bool Orientation270 => (Orientation & 0x8) == 0x8; - *//*#define ADL_DISPLAY_SLSGRID_ORIENTATION_000 0x00000001 + /*#define ADL_DISPLAY_SLSGRID_ORIENTATION_000 0x00000001 #define ADL_DISPLAY_SLSGRID_ORIENTATION_090 0x00000002 #define ADL_DISPLAY_SLSGRID_ORIENTATION_180 0x00000004 - #define ADL_DISPLAY_SLSGRID_ORIENTATION_270 0x00000008*//* + #define ADL_DISPLAY_SLSGRID_ORIENTATION_270 0x00000008*/ // SLS Map Mask settings public bool SLSMapDisplayArrangedSupported => (SLSMapMask & 0x2) == 0x2; - public bool SLSMapCurrentConfigSupported => (SLSMapMask & 0x4) == 0x4; + public bool SLSMapCurrentInUseSupported => (SLSMapMask & 0x4) == 0x4; public bool SLSMapBezelModeSupported => (SLSMapMask & 0x10) == 0x10; public bool SLSMapLayoutModeFitSupported => (SLSMapMask & 0x100) == 0x100; public bool SLSMapLayoutModeFillSupported => (SLSMapMask & 0x200) == 0x200; @@ -1266,7 +1356,7 @@ namespace DisplayMagicianShared.AMD // SLS Map Value settings public bool SLSMapDisplayArrangedSet => (SLSMapValue & 0x2) == 0x2; - public bool SLSMapCurrentConfigSet => (SLSMapValue & 0x4) == 0x4; + public bool SLSMapCurrentInUseSet => (SLSMapValue & 0x4) == 0x4; public bool SLSMapBezelModeSet => (SLSMapValue & 0x10) == 0x10; public bool SLSMapLayoutModeFitSet => (SLSMapValue & 0x100) == 0x100; public bool SLSMapLayoutModeFillSet => (SLSMapValue & 0x200) == 0x200; @@ -1275,7 +1365,7 @@ namespace DisplayMagicianShared.AMD public bool SLSMapIsSLSBuilderSet => (SLSMapValue & 0x2000) == 0x2000; public bool SLSMapIsCloneVTSet => (SLSMapValue & 0x4000) == 0x4000; -*/ + /*#define ADL_DISPLAY_SLSMAP_DISPLAYARRANGED 0x0002 #define ADL_DISPLAY_SLSMAP_CURRENTCONFIG 0x0004 #define ADL_DISPLAY_SLSMAP_BEZELMODE 0x0010 @@ -1284,8 +1374,10 @@ namespace DisplayMagicianShared.AMD #define ADL_DISPLAY_SLSMAP_SLSLAYOUTMODE_EXPAND 0x0400 #define ADL_DISPLAY_SLSMAP_IS_SLS 0x1000 #define ADL_DISPLAY_SLSMAP_IS_SLSBUILDER 0x2000 - #define ADL_DISPLAY_SLSMAP_IS_CLONEVT 0x4000*/ + #define ADL_DISPLAY_SLSMAP_IS_CLONEVT 0x4000 + */ + public override bool Equals(object obj) => obj is ADL_SLS_MAP other && this.Equals(other); public bool Equals(ADL_SLS_MAP other) => AdapterIndex == other.AdapterIndex && SLSMapIndex == other.SLSMapIndex && @@ -1309,6 +1401,10 @@ namespace DisplayMagicianShared.AMD NumBezelOffset, FirstBezelOffsetArrayIndex, SLSMapMask, SLSMapValue).GetHashCode(); } + public static bool operator ==(ADL_SLS_MAP lhs, ADL_SLS_MAP rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_SLS_MAP lhs, ADL_SLS_MAP rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1340,6 +1436,7 @@ namespace DisplayMagicianShared.AMD // SLSTargetValue settings public bool SLSTargetNotSLSBuilderSet => (SLSTargetValue & 0x1) == 0x1; + public override bool Equals(object obj) => obj is ADL_SLS_TARGET other && this.Equals(other); public bool Equals(ADL_SLS_TARGET other) => AdapterIndex == other.AdapterIndex && SLSMapIndex == other.SLSMapIndex && @@ -1355,6 +1452,10 @@ namespace DisplayMagicianShared.AMD return (AdapterIndex, SLSMapIndex, DisplayTarget, SLSGridPositionX, SLSGridPositionY, ViewSize, SLSTargetMask, SLSTargetValue).GetHashCode(); } + public static bool operator ==(ADL_SLS_TARGET lhs, ADL_SLS_TARGET rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_SLS_TARGET lhs, ADL_SLS_TARGET rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1375,6 +1476,7 @@ namespace DisplayMagicianShared.AMD /// The bit mask identifies the display status. public int SLSNativeModeValue; + public override bool Equals(object obj) => obj is ADL_SLS_MODE other && this.Equals(other); public bool Equals(ADL_SLS_MODE other) => AdapterIndex == other.AdapterIndex && SLSMapIndex == other.SLSMapIndex && @@ -1388,6 +1490,10 @@ namespace DisplayMagicianShared.AMD return (AdapterIndex, SLSMapIndex, SLSModeIndex, DisplayMode, SLSNativeModeMask, SLSNativeModeValue).GetHashCode(); } + public static bool operator ==(ADL_SLS_MODE lhs, ADL_SLS_MODE rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_SLS_MODE lhs, ADL_SLS_MODE rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1412,6 +1518,7 @@ namespace DisplayMagicianShared.AMD /// The bit mask identifies the display status. public int SLSBezelTransientModeValue; + public override bool Equals(object obj) => obj is ADL_BEZEL_TRANSIENT_MODE other && this.Equals(other); public bool Equals(ADL_BEZEL_TRANSIENT_MODE other) => AdapterIndex == other.AdapterIndex && SLSMapIndex == other.SLSMapIndex && @@ -1427,6 +1534,10 @@ namespace DisplayMagicianShared.AMD return (AdapterIndex, SLSMapIndex, SLSModeIndex, DisplayMode, NumBezelOffset, FirstBezelOffsetArrayIndex, SLSBezelTransientModeMask, SLSBezelTransientModeValue).GetHashCode(); } + public static bool operator ==(ADL_BEZEL_TRANSIENT_MODE lhs, ADL_BEZEL_TRANSIENT_MODE rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_BEZEL_TRANSIENT_MODE lhs, ADL_BEZEL_TRANSIENT_MODE rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1445,6 +1556,7 @@ namespace DisplayMagicianShared.AMD /// The SLS Target List. public ADL_SLS_TARGET[] SLSTargets; // Not quite sure this is right + public override bool Equals(object obj) => obj is ADL_POSSIBLE_SLS_MAP other && this.Equals(other); public bool Equals(ADL_POSSIBLE_SLS_MAP other) => SLSMapIndex == other.SLSMapIndex && NumSLSMap == other.NumSLSMap && @@ -1457,6 +1569,10 @@ namespace DisplayMagicianShared.AMD return (SLSMapIndex, NumSLSMap, SLSMaps, NumSLSTarget, SLSTargets).GetHashCode(); } + public static bool operator ==(ADL_POSSIBLE_SLS_MAP lhs, ADL_POSSIBLE_SLS_MAP rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_POSSIBLE_SLS_MAP lhs, ADL_POSSIBLE_SLS_MAP rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1497,6 +1613,7 @@ namespace DisplayMagicianShared.AMD /*#define ADL_DISPLAY_BEZELOFFSET_STEPBYSTEPSET 0x00000004 #define ADL_DISPLAY_BEZELOFFSET_COMMIT 0x00000008*/ + public override bool Equals(object obj) => obj is ADL_SLS_OFFSET other && this.Equals(other); public bool Equals(ADL_SLS_OFFSET other) => AdapterIndex == other.AdapterIndex && SLSMapIndex == other.SLSMapIndex && @@ -1514,6 +1631,10 @@ namespace DisplayMagicianShared.AMD return (AdapterIndex, SLSMapIndex, DisplayID, BezelModeIndex, BezelOffsetX, BezelOffsetY, DisplayWidth, DisplayHeight, BezelOffsetMask, BezelOffsetValue).GetHashCode(); } + public static bool operator ==(ADL_SLS_OFFSET lhs, ADL_SLS_OFFSET rhs) => lhs.Equals(rhs); + + public static bool operator !=(ADL_SLS_OFFSET lhs, ADL_SLS_OFFSET rhs) => !(lhs == rhs); + //public override string ToString() => $"{type.ToString("G")}"; } @@ -1895,6 +2016,12 @@ namespace DisplayMagicianShared.AMD [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] public static extern ADL_STATUS ADL2_Display_HDRState_Get(IntPtr ADLContextHandle, int adapterIndex, ADL_DISPLAY_ID displayID, out int support, out int enable); + [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] + public static extern ADL_STATUS ADL2_Display_HDRState_Set(IntPtr ADLContextHandle, int adapterIndex, ADL_DISPLAY_ID displayID, int enable); + + [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] + public static extern ADL_STATUS ADL2_Display_ColorDepth_Get(IntPtr ADLContextHandle, int adapterIndex, ADL_DISPLAY_ID displayID, out ADL_COLORDEPTH colourDepth); + [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] public static extern ADL_STATUS ADL2_Display_DisplayMapConfig_PossibleAddAndRemove(IntPtr ADLContextHandle, int adapterIndex, int numDisplayMap, in ADL_DISPLAY_MAP displayMap, int numDisplayTarget, in ADL_DISPLAY_TARGET displayTarget, out int numPossibleAddTarget, out IntPtr possibleAddTarget, out int numPossibleRemoveTarget, out IntPtr possibleRemoveTarget); @@ -1908,12 +2035,12 @@ namespace DisplayMagicianShared.AMD // Function to get the current supported SLS grid patterns (MxN) for a GPU. // This function gets a list of supported SLS grids for a specified input adapter based on display devices currently connected to the GPU. [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] - public static extern ADL_STATUS ADL2_Display_SLSGrid_Caps(IntPtr ADLContextHandle, int adapterIndex, ref int NumSLSGrid, out IntPtr SLSGrid, int option); + public static extern ADL_STATUS ADL2_Display_SLSGrid_Caps(IntPtr ADLContextHandle, int adapterIndex, out int NumSLSGrid, out IntPtr SLSGrid, int option); // Function to get the active SLS map index list for a given GPU. // This function retrieves a list of active SLS map indexes for a specified input GPU. [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] - public static extern ADL_STATUS ADL2_Display_SLSMapIndexList_Get(IntPtr ADLContextHandle, int adapterIndex, ref int numSLSMapIndexList, out IntPtr SLSMapIndexList, int option); + public static extern ADL_STATUS ADL2_Display_SLSMapIndexList_Get(IntPtr ADLContextHandle, int adapterIndex, out int numSLSMapIndexList, out IntPtr SLSMapIndexList, int option); // Definitions of the used function pointers. Add more if you use other ADL APIs // SLS functions @@ -1930,11 +2057,11 @@ namespace DisplayMagicianShared.AMD //typedef int (* ADL2_DISPLAY_SLSMAPCONFIG_GET) (ADL_CONTEXT_HANDLE, int, int, ADLSLSMap*, int*, ADLSLSTarget**, int*, ADLSLSMode**, int*, ADLBezelTransientMode**, int*, ADLBezelTransientMode**, int*, ADLSLSOffset**, int); // This function retrieves an SLS configuration, which includes the, SLS map, SLS targets, SLS standard modes, bezel modes or a transient mode, and offsets. [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] - public static extern ADL_STATUS ADL2_Display_SLSMapConfig_Get(IntPtr ADLContextHandle, int adapterIndex, int SLSMapIndex, out ADL_SLS_MAP SLSMap, out int NumSLSTarget, out IntPtr SLSTargetArray, out int lpNumNativeMode, out IntPtr NativeMode, out int NumBezelMode, out IntPtr BezelMode, out int NumTransientMode, out IntPtr TransientMode, out int NumSLSOffset, out IntPtr SLSOffset, int iOption); + public static extern ADL_STATUS ADL2_Display_SLSMapConfig_Get(IntPtr ADLContextHandle, int adapterIndex, int SLSMapIndex, out ADL_SLS_MAP slsMap, out int NumSLSTarget, out IntPtr SLSTargetArrayBuffer, out int lpNumNativeMode, out IntPtr NativeModeBuffer, out int NumBezelMode, out IntPtr BezelModeBuffer, out int NumTransientMode, out IntPtr TransientModeBuffer, out int NumSLSOffset, out IntPtr SLSOffsetBuffer, int iOption); // typedef int ADL2_Display_SLSMapConfigX2_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int iSLSMapIndex, ADLSLSMap* lpSLSMap, int* lpNumSLSTarget, ADLSLSTarget** lppSLSTarget, int* lpNumNativeMode, ADLSLSMode** lppNativeMode, int* lpNumNativeModeOffsets, ADLSLSOffset** lppNativeModeOffsets, int* lpNumBezelMode, ADLBezelTransientMode** lppBezelMode, int* lpNumTransientMode, ADLBezelTransientMode** lppTransientMode, int* lpNumSLSOffset, ADLSLSOffset** lppSLSOffset, int iOption) [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] - public static extern ADL_STATUS ADL2_Display_SLSMapConfigX2_Get(IntPtr ADLContextHandle, int adapterIndex, int SLSMapIndex, out ADL_SLS_MAP SLSMap, out int NumSLSTarget, out IntPtr SLSTargetArray, out int lpNumNativeMode, out IntPtr NativeMode, out int NumNativeModeOffsets, out IntPtr NativeModeOffsets, out int NumBezelMode, out IntPtr BezelMode, out int NumTransientMode, out IntPtr TransientMode, out int NumSLSOffset, out IntPtr SLSOffset, int option); + public static extern ADL_STATUS ADL2_Display_SLSMapConfigX2_Get(IntPtr ADLContextHandle, int adapterIndex, int SLSMapIndex, ref ADL_SLS_MAP slsMap, out int NumSLSTarget, out IntPtr SLSTargetBuffer, out int lpNumNativeMode, out IntPtr NativeModeBuffer, out int NumNativeModeOffsets, out IntPtr NativeModeOffsetsBuffer, out int NumBezelMode, out IntPtr BezelModeBuffer, out int NumTransientMode, out IntPtr TransientModeBuffer, out int NumSLSOffset, out IntPtr SLSOffsetBuffer, int option); //typedef int (* ADL2_DISPLAY_SLSMAPCONFIG_DELETE) (ADL_CONTEXT_HANDLE context, int iAdapterIndex, int iSLSMapIndex); // This function deletes an SLS map from the driver database based on the input SLS map index. @@ -2000,6 +2127,11 @@ namespace DisplayMagicianShared.AMD [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] public static extern ADL_STATUS ADL2_Display_DisplayMapConfig_Validate(IntPtr ADLContextHandle, int adapterIndex, int numPossibleMap, ref ADL_POSSIBLE_MAP possibleMaps, out int numPossibleMapResult, out IntPtr possibleMapResult); + // Function to indicate whether displays are physically connected to an adapter. + // This function indicates whether displays are physically connected to a specified adapter. + [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] + public static extern ADL_STATUS ADL2_Display_ConnectedDisplays_Get(IntPtr context, int adapterIndex, out int connections); + // ====================================== @@ -2068,7 +2200,7 @@ namespace DisplayMagicianShared.AMD // Function to get the active SLS map index list for a given GPU. // This function retrieves a list of active SLS map indexes for a specified input GPU. [DllImport(ATI_ADL_DLL, CallingConvention = CallingConvention.Cdecl)] - public static extern ADL_STATUS ADL_Display_SLSMapIndexList_Get(int adapterIndex, ref int numSLSMapIndexList, out IntPtr SLSMapIndexList, int options); + public static extern ADL_STATUS ADL_Display_SLSMapIndexList_Get(int adapterIndex, out int numSLSMapIndexList, out IntPtr SLSMapIndexList, int options); // Function to get the active SLS map index list for a given GPU. // This function retrieves a list of active SLS map indexes for a specified input GPU. diff --git a/DisplayMagicianShared/AMD/AMDLibrary.cs b/DisplayMagicianShared/AMD/AMDLibrary.cs index 4447dad..52d5982 100644 --- a/DisplayMagicianShared/AMD/AMDLibrary.cs +++ b/DisplayMagicianShared/AMD/AMDLibrary.cs @@ -17,11 +17,8 @@ namespace DisplayMagicianShared.AMD public int AdapterBusNumber; public int AdapterIndex; public bool IsPrimaryAdapter; - //public ADL_DISPLAY_MAP[] DisplayMaps; - //public ADL_DISPLAY_TARGET[] DisplayTargets; - public int SLSMapIndex; - public bool IsSLSEnabled; - //public ADL_SLS_MAP[] SLSMap; + public string DisplayName; + public int OSDisplayIndex; public override bool Equals(object obj) => obj is AMD_ADAPTER_CONFIG other && this.Equals(other); @@ -30,14 +27,12 @@ namespace DisplayMagicianShared.AMD AdapterBusNumber == other.AdapterBusNumber && AdapterDeviceNumber == other.AdapterDeviceNumber && IsPrimaryAdapter == other.IsPrimaryAdapter && - //DisplayMaps.SequenceEqual(other.DisplayMaps) && - //DisplayTargets.SequenceEqual(other.DisplayTargets); - SLSMapIndex == other.SLSMapIndex && - IsSLSEnabled == other.IsSLSEnabled; + DisplayName == other.DisplayName && + OSDisplayIndex == other.OSDisplayIndex; public override int GetHashCode() { - return (AdapterIndex, AdapterBusNumber, AdapterDeviceNumber, IsPrimaryAdapter, SLSMapIndex, IsSLSEnabled).GetHashCode(); + return (AdapterIndex, AdapterBusNumber, AdapterDeviceNumber, IsPrimaryAdapter, DisplayName, OSDisplayIndex).GetHashCode(); } public static bool operator ==(AMD_ADAPTER_CONFIG lhs, AMD_ADAPTER_CONFIG rhs) => lhs.Equals(rhs); @@ -46,19 +41,104 @@ namespace DisplayMagicianShared.AMD } [StructLayout(LayoutKind.Sequential)] - public struct AMD_DISPLAY_CONFIG : IEquatable + public struct AMD_SLSMAP_CONFIG : IEquatable { - public List AdapterConfigs; - public List DisplayIdentifiers; + public ADL_SLS_MAP SLSMap; + public List SLSTargets; + public List NativeModes; + public List NativeModeOffsets; + public List BezelModes; + public List TransientModes; + public List SLSOffsets; - public override bool Equals(object obj) => obj is AMD_DISPLAY_CONFIG other && this.Equals(other); + public override bool Equals(object obj) => obj is AMD_SLS_CONFIG other && this.Equals(other); - public bool Equals(AMD_DISPLAY_CONFIG other) - => AdapterConfigs.SequenceEqual(other.AdapterConfigs); + public bool Equals(AMD_SLSMAP_CONFIG other) + => SLSMap == other.SLSMap && + SLSTargets.SequenceEqual(other.SLSTargets) && + NativeModes.SequenceEqual(other.NativeModes) && + NativeModeOffsets.SequenceEqual(other.NativeModeOffsets) && + BezelModes.SequenceEqual(other.BezelModes) && + TransientModes.SequenceEqual(other.TransientModes) && + SLSOffsets.SequenceEqual(other.SLSOffsets); public override int GetHashCode() { - return (AdapterConfigs).GetHashCode(); + return (SLSMap, SLSTargets, NativeModes, NativeModeOffsets, BezelModes, TransientModes, SLSOffsets).GetHashCode(); + } + public static bool operator ==(AMD_SLSMAP_CONFIG lhs, AMD_SLSMAP_CONFIG rhs) => lhs.Equals(rhs); + + public static bool operator !=(AMD_SLSMAP_CONFIG lhs, AMD_SLSMAP_CONFIG rhs) => !(lhs == rhs); + } + + [StructLayout(LayoutKind.Sequential)] + public struct AMD_SLS_CONFIG : IEquatable + { + public bool IsSlsEnabled; + public List SLSMapConfigs; + public List SLSEnabledDisplayTargets; + + public override bool Equals(object obj) => obj is AMD_SLS_CONFIG other && this.Equals(other); + + public bool Equals(AMD_SLS_CONFIG other) + => IsSlsEnabled == other.IsSlsEnabled && + SLSMapConfigs.SequenceEqual(other.SLSMapConfigs) && + SLSEnabledDisplayTargets.SequenceEqual(other.SLSEnabledDisplayTargets); + + public override int GetHashCode() + { + return (IsSlsEnabled, SLSMapConfigs, SLSEnabledDisplayTargets).GetHashCode(); + } + public static bool operator ==(AMD_SLS_CONFIG lhs, AMD_SLS_CONFIG rhs) => lhs.Equals(rhs); + + public static bool operator !=(AMD_SLS_CONFIG lhs, AMD_SLS_CONFIG rhs) => !(lhs == rhs); + } + + [StructLayout(LayoutKind.Sequential)] + public struct AMD_HDR_CONFIG : IEquatable + { + public int AdapterIndex; + public bool HDRSupported; + public bool HDREnabled; + + public override bool Equals(object obj) => obj is AMD_HDR_CONFIG other && this.Equals(other); + public bool Equals(AMD_HDR_CONFIG other) + => AdapterIndex == other.AdapterIndex && + HDRSupported == other.HDRSupported && + HDREnabled == other.HDREnabled; + + public override int GetHashCode() + { + return (AdapterIndex, HDRSupported, HDREnabled).GetHashCode(); + } + public static bool operator ==(AMD_HDR_CONFIG lhs, AMD_HDR_CONFIG rhs) => lhs.Equals(rhs); + + public static bool operator !=(AMD_HDR_CONFIG lhs, AMD_HDR_CONFIG rhs) => !(lhs == rhs); + } + + + [StructLayout(LayoutKind.Sequential)] + public struct AMD_DISPLAY_CONFIG : IEquatable + { + public List AdapterConfigs; + public AMD_SLS_CONFIG SlsConfig; + public List DisplayMaps; + public List DisplayTargets; + public Dictionary HdrConfigs; + public List DisplayIdentifiers; + public override bool Equals(object obj) => obj is AMD_DISPLAY_CONFIG other && this.Equals(other); + + public bool Equals(AMD_DISPLAY_CONFIG other) + => AdapterConfigs.SequenceEqual(other.AdapterConfigs) && + SlsConfig.Equals(other.SlsConfig) && + DisplayMaps.SequenceEqual(other.DisplayMaps) && + DisplayTargets.SequenceEqual(other.DisplayTargets) && + HdrConfigs.SequenceEqual(other.HdrConfigs) && + DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers); + + public override int GetHashCode() + { + return (AdapterConfigs, SlsConfig, DisplayMaps, DisplayTargets, DisplayIdentifiers).GetHashCode(); } public static bool operator ==(AMD_DISPLAY_CONFIG lhs, AMD_DISPLAY_CONFIG rhs) => lhs.Equals(rhs); @@ -66,7 +146,7 @@ namespace DisplayMagicianShared.AMD public static bool operator !=(AMD_DISPLAY_CONFIG lhs, AMD_DISPLAY_CONFIG rhs) => !(lhs == rhs); } - public class AMDLibrary : IDisposable + class AMDLibrary : IDisposable { // Static members are 'eagerly initialized', that is, @@ -97,6 +177,11 @@ namespace DisplayMagicianShared.AMD SharedLogger.logger.Trace("AMDLibrary/AMDLibrary: Intialising AMD ADL2 library interface"); // Second parameter is 1 so that we only the get connected adapters in use now + + // We set the environment variable as a workaround so that ADL2_Display_SLSMapConfigX2_Get works :( + // This is a weird thing that AMD even set in their own code! WTF! Who programmed that as a feature? + Environment.SetEnvironmentVariable("ADL_4KWORKAROUND_CANCEL", "TRUE"); + try { ADL_STATUS ADLRet; @@ -205,37 +290,67 @@ namespace DisplayMagicianShared.AMD AMD_DISPLAY_CONFIG myDisplayConfig = new AMD_DISPLAY_CONFIG(); myDisplayConfig.AdapterConfigs = new List(); + // We set up the default for this display config as SLS disabled + // (We will change this later if it turns out we're using SLS) + myDisplayConfig.SlsConfig.IsSlsEnabled = false; + myDisplayConfig.SlsConfig.SLSEnabledDisplayTargets = new List(); + if (_initialised) { - // Get the number of AMD adapters that the OS knows about - int numAdapters = 0; - ADL_STATUS ADLRet = ADLImport.ADL2_Adapter_NumberOfAdapters_Get(_adlContextHandle, out numAdapters); + + // Get the Adapter info for ALL adapter and put it in the AdapterBuffer + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: Running ADL2_Adapter_AdapterInfoX4_Get to get the information about all AMD Adapters."); + int numAdaptersInfo = 0; + IntPtr adapterInfoBuffer = IntPtr.Zero; + ADL_STATUS ADLRet = ADLImport.ADL2_Adapter_AdapterInfoX4_Get(_adlContextHandle, -1, out numAdaptersInfo, out adapterInfoBuffer); if (ADLRet == ADL_STATUS.ADL_OK) { - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Adapter_NumberOfAdapters_Get returned the number of AMD Adapters the OS knows about ({numAdapters})."); + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Adapter_AdapterInfoX4_Get returned information about all AMD Adapters."); } else { - SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Adapter_NumberOfAdapters_Get returned ADL_STATUS {ADLRet} when trying to get number of AMD adapters in the computer."); - throw new AMDLibraryException($"ADL2_Adapter_NumberOfAdapters_Get returned ADL_STATUS {ADLRet} when trying to get number of AMD adapters in the computer"); + SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Adapter_AdapterInfoX4_Get returned ADL_STATUS {ADLRet} when trying to get the adapter info about all AMD Adapters. Trying to skip this adapter so something at least works."); + return myDisplayConfig; } - // Figure out primary adapter - int primaryAdapterIndex = 0; - ADLRet = ADLImport.ADL2_Adapter_Primary_Get(_adlContextHandle, out primaryAdapterIndex); - if (ADLRet == ADL_STATUS.ADL_OK) + ADL_ADAPTER_INFOX2[] adapterArray = new ADL_ADAPTER_INFOX2[numAdaptersInfo]; + if (numAdaptersInfo > 0) { - SharedLogger.logger.Trace($"AMDLibrary/ADL2_Adapter_Primary_Get: The primary adapter has index {primaryAdapterIndex}."); - } - else - { - SharedLogger.logger.Error($"AMDLibrary/ADL2_Adapter_Primary_Get: ERROR - ADL2_Adapter_Primary_Get returned ADL_STATUS {ADLRet} when trying to get the primary adapter info from all the AMD adapters in the computer."); - throw new AMDLibraryException($"ADL2_Adapter_Primary_Get returned ADL_STATUS {ADLRet} when trying to get the adapter info from all the AMD adapters in the computer"); + IntPtr currentDisplayTargetBuffer = adapterInfoBuffer; + for (int i = 0; i < numAdaptersInfo; i++) + { + // build a structure in the array slot + adapterArray[i] = new ADL_ADAPTER_INFOX2(); + // fill the array slot structure with the data from the buffer + adapterArray[i] = (ADL_ADAPTER_INFOX2)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(adapterArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(adapterInfoBuffer); } // Now go through each adapter and get the information we need from it - for (int adapterIndex = 0; adapterIndex < numAdapters; adapterIndex++) + for (int adapterIndex = 0; adapterIndex < numAdaptersInfo; adapterIndex++) { + // Skip this adapter if it isn't active + ADL_ADAPTER_INFOX2 oneAdapter = adapterArray[adapterIndex]; // There is always just one as we asked for a specific one! + if (oneAdapter.Exist != ADLImport.ADL_TRUE) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} doesn't exist at present so skipping detection for this adapter."); + continue; + } + + // Only skip non-present displays if we want all displays information + if (oneAdapter.Present != ADLImport.ADL_TRUE) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} isn't enabled at present so skipping detection for this adapter."); + continue; + } + + // Check if the adapter is active // Skip this adapter if it isn't active int adapterActiveStatus = ADLImport.ADL_FALSE; ADLRet = ADLImport.ADL2_Adapter_Active_Get(_adlContextHandle, adapterIndex, out adapterActiveStatus); @@ -243,86 +358,21 @@ namespace DisplayMagicianShared.AMD { if (adapterActiveStatus == ADLImport.ADL_TRUE) { - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Adapter_Active_Get returned ADL_TRUE - AMD Adapter #{adapterIndex} is active! We can continue."); + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: ADL2_Adapter_Active_Get returned ADL_TRUE - AMD Adapter #{adapterIndex} is active! We can continue."); } else { - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Adapter_Active_Get returned ADL_FALSE - AMD Adapter #{adapterIndex} is NOT active, so skipping."); + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: ADL2_Adapter_Active_Get returned ADL_FALSE - AMD Adapter #{adapterIndex} is NOT active, so skipping."); continue; } } else { - SharedLogger.logger.Warn($"AMDLibrary/GetAMDDisplayConfig: WARNING - ADL2_Adapter_Active_Get returned ADL_STATUS {ADLRet} when trying to see if AMD Adapter #{adapterIndex} is active. Trying to skip this adapter so something at least works."); + SharedLogger.logger.Warn($"AMDLibrary/GetSomeDisplayIdentifiers: WARNING - ADL2_Adapter_Active_Get returned ADL_STATUS {ADLRet} when trying to see if AMD Adapter #{adapterIndex} is active. Trying to skip this adapter so something at least works."); continue; } - // Get the Adapter info for this adapter and put it in the AdapterBuffer - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: Running ADL2_Adapter_AdapterInfoX4_Get to get the information about AMD Adapter #{adapterIndex}."); - int numAdaptersInfo = 0; - IntPtr adapterInfoBuffer = IntPtr.Zero; - ADLRet = ADLImport.ADL2_Adapter_AdapterInfoX4_Get(_adlContextHandle, adapterIndex, out numAdaptersInfo, out adapterInfoBuffer); - if (ADLRet == ADL_STATUS.ADL_OK) - { - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Adapter_AdapterInfoX4_Get returned information about AMD Adapter #{adapterIndex}."); - } - else - { - SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Adapter_AdapterInfoX4_Get returned ADL_STATUS {ADLRet} when trying to get the adapter info from AMD Adapter #{adapterIndex}. Trying to skip this adapter so something at least works."); - continue; - } - - ADL_ADAPTER_INFOX2[] adapterArray = new ADL_ADAPTER_INFOX2[numAdaptersInfo]; - if (numAdaptersInfo > 0) - { - IntPtr currentDisplayTargetBuffer = adapterInfoBuffer; - for (int i = 0; i < numAdaptersInfo; i++) - { - // build a structure in the array slot - adapterArray[i] = new ADL_ADAPTER_INFOX2(); - // fill the array slot structure with the data from the buffer - adapterArray[i] = (ADL_ADAPTER_INFOX2)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); - // destroy the bit of memory we no longer need - Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); - // advance the buffer forwards to the next object - currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(adapterArray[i])); - } - // Free the memory used by the buffer - Marshal.FreeCoTaskMem(adapterInfoBuffer); - } - - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: Converted ADL2_Adapter_AdapterInfoX4_Get memory buffer into a {adapterArray.Length} long array about AMD Adapter #{adapterIndex}."); - - AMD_ADAPTER_CONFIG savedAdapterConfig = new AMD_ADAPTER_CONFIG(); - ADL_ADAPTER_INFOX2 oneAdapter = adapterArray[0]; - if (oneAdapter.Exist != 1) - { - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} doesn't exist at present so skipping detection for this adapter."); - continue; - } - - // Only skip non-present displays if we want all displays information - if (allDisplays && oneAdapter.Present != 1) - { - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} isn't enabled at present so skipping detection for this adapter."); - continue; - } - - - savedAdapterConfig.AdapterBusNumber = oneAdapter.BusNumber; - savedAdapterConfig.AdapterDeviceNumber = oneAdapter.DeviceNumber; - savedAdapterConfig.AdapterIndex = oneAdapter.AdapterIndex; - if (oneAdapter.AdapterIndex == primaryAdapterIndex) - { - savedAdapterConfig.IsPrimaryAdapter = true; - } - else - { - savedAdapterConfig.IsPrimaryAdapter = false; - } - - - // Go grab the DisplayMaps and DisplayTargets + // Go grab the DisplayMaps and DisplayTargets as that is useful infor for creating screens int numDisplayTargets = 0; int numDisplayMaps = 0; IntPtr displayTargetBuffer = IntPtr.Zero; @@ -358,28 +408,28 @@ namespace DisplayMagicianShared.AMD // Free the memory used by the buffer Marshal.FreeCoTaskMem(displayMapBuffer); // Save the item - //savedAdapterConfig.DisplayMaps = displayMapArray; + myDisplayConfig.DisplayMaps = displayMapArray.ToList(); } - ADL_DISPLAY_TARGET[] retrievedDisplayTargets = { }; + ADL_DISPLAY_TARGET[] displayTargetArray = { }; if (numDisplayTargets > 0) { IntPtr currentDisplayTargetBuffer = displayTargetBuffer; //displayTargetArray = new ADL_DISPLAY_TARGET[numDisplayTargets]; - retrievedDisplayTargets = new ADL_DISPLAY_TARGET[numDisplayTargets]; + displayTargetArray = new ADL_DISPLAY_TARGET[numDisplayTargets]; for (int i = 0; i < numDisplayTargets; i++) { // build a structure in the array slot - retrievedDisplayTargets[i] = new ADL_DISPLAY_TARGET(); + displayTargetArray[i] = new ADL_DISPLAY_TARGET(); //displayTargetArray[i] = new ADL_DISPLAY_TARGET(); // fill the array slot structure with the data from the buffer - retrievedDisplayTargets[i] = (ADL_DISPLAY_TARGET)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); + displayTargetArray[i] = (ADL_DISPLAY_TARGET)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); //displayTargetArray[i] = (ADL_DISPLAY_TARGET)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); // destroy the bit of memory we no longer need Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); // advance the buffer forwards to the next object - currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(retrievedDisplayTargets[i])); + currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(displayTargetArray[i])); //currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(displayTargetArray[i])); } @@ -387,126 +437,51 @@ namespace DisplayMagicianShared.AMD Marshal.FreeCoTaskMem(displayTargetBuffer); // Save the item //savedAdapterConfig.DisplayTargets = new ADL_DISPLAY_TARGET[numDisplayTargets]; - //savedAdapterConfig.DisplayTargets = displayTargetArray; + myDisplayConfig.DisplayTargets = displayTargetArray.ToList(); } - for (int displayMapIndex = 0; displayMapIndex < numDisplayMaps; displayMapIndex++) + // Loop through all the displayTargets currently in use + foreach (var displayTarget in displayTargetArray) { - int foundDisplays = 0; - ADL_DISPLAY_MAP oneAdlDesktop = displayMapArray[displayMapIndex]; - ADL_DISPLAY_ID preferredDisplay; - - for (int displayTargetIndex = 0; displayTargetIndex < numDisplayTargets; displayTargetIndex++) + if (displayTarget.DisplayID.DisplayLogicalAdapterIndex == oneAdapter.AdapterIndex) { - ADL_DISPLAY_TARGET oneAdlDisplay = retrievedDisplayTargets[displayTargetIndex]; + // we only want to record the adapters that are currently in use as displayTargets + AMD_ADAPTER_CONFIG savedAdapterConfig = new AMD_ADAPTER_CONFIG(); + savedAdapterConfig.AdapterBusNumber = oneAdapter.BusNumber; + savedAdapterConfig.AdapterDeviceNumber = oneAdapter.DeviceNumber; + savedAdapterConfig.AdapterIndex = oneAdapter.AdapterIndex; + savedAdapterConfig.DisplayName = oneAdapter.DisplayName; + savedAdapterConfig.OSDisplayIndex = oneAdapter.OSDisplayIndex; - if (oneAdlDesktop.DisplayMode.Orientation090Set || oneAdlDesktop.DisplayMode.Orientation270Set) + // Save the AMD Adapter Config + if (!myDisplayConfig.AdapterConfigs.Contains(savedAdapterConfig)) { - int oldXRes = oneAdlDesktop.DisplayMode.XRes; - oneAdlDesktop.DisplayMode.XRes = oneAdlDesktop.DisplayMode.YRes; - oneAdlDesktop.DisplayMode.YRes = oldXRes; + // Save the new adapter config only if we haven't already + myDisplayConfig.AdapterConfigs.Add(savedAdapterConfig); } - // By default non-SLS; one row, one column - int rows = 1, cols = 1; - // By default SLsMapIndex is -1 and SLS Mode is fill - int slsMapIndex = -1, slsMode = ADLImport.ADL_DISPLAY_SLSMAP_SLSLAYOUTMODE_FILL; - - if (oneAdlDisplay.DisplayMapIndex == oneAdlDesktop.DisplayMapIndex) - { - if (primaryAdapterIndex == oneAdlDisplay.DisplayID.DisplayPhysicalAdapterIndex) - { - //add a display in list. For SLS this info will be updated later - /*displays.push_back(TopologyDisplay(oneAdlDisplay.displayID, 0, - oneAdlDesktop.displayMode.iXRes, oneAdlDesktop.displayMode.iYRes, //size - 0, 0, //offset in desktop - 0, 0)); //grid location (0-based)*/ - - // count it and bail out of we found enough - foundDisplays++; - if (foundDisplays == oneAdlDesktop.NumDisplayTarget) - break; - } - } } } - // Only check for SLS if there is more than one displaytarget (screen) + // Prep the SLSMapConfig list + myDisplayConfig.SlsConfig.SLSMapConfigs = new List(); + + // If there are more than 1 display targets then eyefinity is possible if (numDisplayTargets > 1) { - - int numSLSMapIDs = -1; - IntPtr SLSMapIDBuffer = IntPtr.Zero; - int[] SLSMapIDArray; - ADLRet = ADLImport.ADL2_Display_SLSMapIndexList_Get(_adlContextHandle, oneAdapter.AdapterIndex, ref numSLSMapIDs, out SLSMapIDBuffer, ADLImport.ADL_DISPLAY_SLSMAPINDEXLIST_OPTION_ACTIVE); - if (ADLRet == ADL_STATUS.ADL_OK) + // Check if SLS is enabled for this adapter! + int matchingSLSMapIndex = -1; + ADLRet = ADLImport.ADL2_Display_SLSMapIndex_Get(_adlContextHandle, oneAdapter.AdapterIndex, numDisplayTargets, displayTargetArray, out matchingSLSMapIndex); + if (ADLRet == ADL_STATUS.ADL_OK && matchingSLSMapIndex != -1) { - SLSMapIDArray = new int[numSLSMapIDs]; - if (numSLSMapIDs > 0) - { - IntPtr currentSLSMapsBuffer = SLSMapIDBuffer; - SLSMapIDArray = new int[numSLSMapIDs]; - for (int i = 0; i < numSLSMapIDs; i++) - { - // build a structure in the array slot - SLSMapIDArray[i] = 0; - // fill the array slot structure with the data from the buffer - SLSMapIDArray[i] = (int)Marshal.PtrToStructure(currentSLSMapsBuffer, typeof(int)); - // destroy the bit of memory we no longer need - Marshal.DestroyStructure(currentSLSMapsBuffer, typeof(ADL_SLS_MAP)); - // advance the buffer forwards to the next object - currentSLSMapsBuffer = (IntPtr)((long)currentSLSMapsBuffer + Marshal.SizeOf(SLSMapIDArray[i])); - } - // Free the memory used by the buffer - Marshal.FreeCoTaskMem(SLSMapIDBuffer); - } - } + // We have a matching SLS index! + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} has one or more SLS Maps that could be used with this display configuration! Eyefinity (SLS) could be enabled."); - /*int numSLSRecords = -1; - IntPtr SLSRecordBuffer = IntPtr.Zero; - int[] SLSRecordArray; - ADLRet = ADLImport.ADL2_Display_SLSRecords_Get(_adlContextHandle, oneAdapter.AdapterIndex, savedAdapterConfig.DisplayTargets[0].DisplayID, out numSLSRecords, out SLSRecordBuffer); - if (ADLRet == ADL_STATUS.ADL_OK) - { - SLSRecordArray = new int[numSLSRecords]; - if (numSLSRecords > 0) - { - IntPtr currentSLSBuffer = SLSRecordBuffer; - SLSRecordArray = new int[numSLSRecords]; - for (int i = 0; i < numSLSMapIDs; i++) - { - // build a structure in the array slot - SLSRecordArray[i] = 0; - // fill the array slot structure with the data from the buffer - SLSRecordArray[i] = (int)Marshal.PtrToStructure(currentSLSBuffer, typeof(int)); - // destroy the bit of memory we no longer need - Marshal.DestroyStructure(currentSLSBuffer, typeof(ADL_SLS_MAP)); - // advance the buffer forwards to the next object - currentSLSBuffer = (IntPtr)((long)currentSLSBuffer + Marshal.SizeOf(SLSRecordArray[i])); - } - // Free the memory used by the buffer - Marshal.FreeCoTaskMem(SLSRecordBuffer); - } - }*/ - - - int SLSMapIndex = -1; - ADLRet = ADLImport.ADL2_Display_SLSMapIndex_Get(_adlContextHandle, oneAdapter.AdapterIndex, numDisplayTargets, retrievedDisplayTargets, out SLSMapIndex); - //ADLRet = ADLImport.ADL2_Display_SLSMapIndexList_Get(_adlContextHandle, adapterNum, ref numSLSMapIDs, out SLSMapIDBuffer, ADLImport.ADL_DISPLAY_SLSMAPINDEXLIST_OPTION_ACTIVE); - if (ADLRet == ADL_STATUS.ADL_OK) - { - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: SLS (Eyfinity) is enabled on AMD adapter {adapterIndex}."); - - // Set the SLS Map Index if there is Eyefinity - //savedAdapterConfig.IsSLSPossible = true; - savedAdapterConfig.SLSMapIndex = SLSMapIndex; - /*for (int slsMapIdx = 0; slsMapIdx < SLSMapIndex; slsMapIdx++) - {*/ - //bool isActiveSLS = false; - // TODO Get the SLS Map Config X2?? + AMD_SLSMAP_CONFIG mySLSMapConfig = new AMD_SLSMAP_CONFIG(); + // We want to get the SLSMapConfig for this matching SLS Map to see if it is actually in use int numSLSTargets = 0; - IntPtr SLSTargetBuffer = IntPtr.Zero; + IntPtr slsTargetBuffer = IntPtr.Zero; int numNativeMode = 0; IntPtr nativeModeBuffer = IntPtr.Zero; int numNativeModeOffsets = 0; @@ -514,32 +489,28 @@ namespace DisplayMagicianShared.AMD int numBezelMode = 0; IntPtr bezelModeBuffer = IntPtr.Zero; int numTransientMode = 0; - IntPtr TransientModeBuffer = IntPtr.Zero; + IntPtr transientModeBuffer = IntPtr.Zero; int numSLSOffset = 0; - IntPtr SLSOffsetBuffer = IntPtr.Zero; - //ADL2_Display_SLSMapConfigX2_Get(IntPtr ADLContextHandle, int adapterIndex, int SLSMapIndex, ref ADL_SLS_MAP[] SLSMap, ref int NumSLSTarget, out IntPtr SLSTargetArray, ref int lpNumNativeMode, out IntPtr NativeMode, ref int NumNativeModeOffsets, out IntPtr NativeModeOffsets, ref int NumBezelMode, out IntPtr BezelMode, ref int NumTransientMode, out IntPtr TransientMode, ref int NumSLSOffset, out IntPtr SLSOffset, int option); - ADL_SLS_MAP SLSMap = new ADL_SLS_MAP(); - //int SLSMapIndex = SLSMapIDArray[slsMapIdx]; - //ADLRet = ADLImport.ADL2_Display_SLSMapConfigX2_Get(_adlContextHandle, adapterNum, SLSMapIndex, out SLSMap, out numSLSTargets, out SLSTargetBuffer, out numNativeMode, out nativeModeBuffer, out numNativeModeOffsets, - // out nativeModeOffsetsBuffer, out numBezelMode, out bezelModeBuffer, out numTransientMode, out TransientModeBuffer, out numSLSOffset, out SLSOffsetBuffer, (int)2); + IntPtr slsOffsetBuffer = IntPtr.Zero; + ADL_SLS_MAP slsMap = new ADL_SLS_MAP(); ADLRet = ADLImport.ADL2_Display_SLSMapConfigX2_Get( _adlContextHandle, - oneAdapter.AdapterIndex, - SLSMapIndex, - out SLSMap, - out numSLSTargets, - out SLSTargetBuffer, - out numNativeMode, - out nativeModeBuffer, - out numNativeModeOffsets, - out nativeModeOffsetsBuffer, - out numBezelMode, - out bezelModeBuffer, - out numTransientMode, - out TransientModeBuffer, - out numSLSOffset, - out SLSOffsetBuffer, - ADLImport.ADL_DISPLAY_SLSGRID_CAP_OPTION_RELATIVETO_CURRENTANGLE); + oneAdapter.AdapterIndex, + matchingSLSMapIndex, + ref slsMap, + out numSLSTargets, + out slsTargetBuffer, + out numNativeMode, + out nativeModeBuffer, + out numNativeModeOffsets, + out nativeModeOffsetsBuffer, + out numBezelMode, + out bezelModeBuffer, + out numTransientMode, + out transientModeBuffer, + out numSLSOffset, + out slsOffsetBuffer, + ADLImport.ADL_DISPLAY_SLSGRID_CAP_OPTION_RELATIVETO_CURRENTANGLE); if (ADLRet == ADL_STATUS.ADL_OK) { SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_SLSMapConfigX2_Get returned information about the SLS Info connected to AMD adapter {adapterIndex}."); @@ -547,29 +518,367 @@ namespace DisplayMagicianShared.AMD else { SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Display_SLSMapConfigX2_Get returned ADL_STATUS {ADLRet} when trying to get the SLS Info from AMD adapter {adapterIndex} in the computer."); - //throw new AMDLibraryException($"ADL2_Display_DisplayMapConfig_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from AMD adapter {adapterNum} in the computer"); + continue; + } + + // First check that the number of grid entries is equal to the number + // of display targets associated with this adapter & SLS surface. + if (numDisplayTargets != (slsMap.Grid.SLSGridColumn * slsMap.Grid.SLSGridRow)) + { + //Number of display targets returned is not equal to the SLS grid size, so SLS can't be enabled fo this display + //myDisplayConfig.SlsConfig.IsSlsEnabled = false; // This is already set to false at the start! + break; + } + + // Add the slsMap to the config we want to store + mySLSMapConfig.SLSMap = slsMap; + + // Process the slsTargetBuffer + ADL_SLS_TARGET[] slsTargetArray = new ADL_SLS_TARGET[numSLSTargets]; + if (numSLSTargets > 0) + { + IntPtr currentSLSTargetBuffer = slsTargetBuffer; + for (int i = 0; i < numSLSTargets; i++) + { + // build a structure in the array slot + slsTargetArray[i] = new ADL_SLS_TARGET(); + // fill the array slot structure with the data from the buffer + slsTargetArray[i] = (ADL_SLS_TARGET)Marshal.PtrToStructure(currentSLSTargetBuffer, typeof(ADL_SLS_TARGET)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentSLSTargetBuffer = (IntPtr)((long)currentSLSTargetBuffer + Marshal.SizeOf(slsTargetArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(slsTargetBuffer); + + // Add the slsTarget to the config we want to store + mySLSMapConfig.SLSTargets = slsTargetArray.ToList(); + + } + else + { + // Add the slsTarget to the config we want to store + mySLSMapConfig.SLSTargets = new List(); + } + + // Process the nativeModeBuffer + ADL_SLS_MODE[] nativeModeArray = new ADL_SLS_MODE[numNativeMode]; + if (numNativeMode > 0) + { + IntPtr currentNativeModeBuffer = nativeModeBuffer; + for (int i = 0; i < numNativeMode; i++) + { + // build a structure in the array slot + nativeModeArray[i] = new ADL_SLS_MODE(); + // fill the array slot structure with the data from the buffer + nativeModeArray[i] = (ADL_SLS_MODE)Marshal.PtrToStructure(currentNativeModeBuffer, typeof(ADL_SLS_MODE)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentNativeModeBuffer = (IntPtr)((long)currentNativeModeBuffer + Marshal.SizeOf(nativeModeArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(nativeModeBuffer); + + // Add the nativeMode to the config we want to store + mySLSMapConfig.NativeModes = nativeModeArray.ToList(); + + } + else + { + // Add the slsTarget to the config we want to store + mySLSMapConfig.NativeModes = new List(); + } + + // Process the nativeModeOffsetsBuffer + ADL_SLS_OFFSET[] nativeModeOffsetArray = new ADL_SLS_OFFSET[numNativeModeOffsets]; + if (numNativeModeOffsets > 0) + { + IntPtr currentNativeModeOffsetsBuffer = nativeModeOffsetsBuffer; + for (int i = 0; i < numNativeModeOffsets; i++) + { + // build a structure in the array slot + nativeModeOffsetArray[i] = new ADL_SLS_OFFSET(); + // fill the array slot structure with the data from the buffer + nativeModeOffsetArray[i] = (ADL_SLS_OFFSET)Marshal.PtrToStructure(currentNativeModeOffsetsBuffer, typeof(ADL_SLS_OFFSET)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentNativeModeOffsetsBuffer = (IntPtr)((long)currentNativeModeOffsetsBuffer + Marshal.SizeOf(nativeModeOffsetArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(nativeModeOffsetsBuffer); + + // Add the nativeModeOffsets to the config we want to store + mySLSMapConfig.NativeModeOffsets = nativeModeOffsetArray.ToList(); + + } + else + { + // Add the empty list to the config we want to store + mySLSMapConfig.NativeModeOffsets = new List(); + } + + // Process the bezelModeBuffer + ADL_BEZEL_TRANSIENT_MODE[] bezelModeArray = new ADL_BEZEL_TRANSIENT_MODE[numBezelMode]; + if (numBezelMode > 0) + { + IntPtr currentBezelModeBuffer = bezelModeBuffer; + for (int i = 0; i < numBezelMode; i++) + { + // build a structure in the array slot + bezelModeArray[i] = new ADL_BEZEL_TRANSIENT_MODE(); + // fill the array slot structure with the data from the buffer + bezelModeArray[i] = (ADL_BEZEL_TRANSIENT_MODE)Marshal.PtrToStructure(currentBezelModeBuffer, typeof(ADL_BEZEL_TRANSIENT_MODE)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentBezelModeBuffer = (IntPtr)((long)currentBezelModeBuffer + Marshal.SizeOf(bezelModeArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(bezelModeBuffer); + + // Add the bezelModes to the config we want to store + mySLSMapConfig.BezelModes = bezelModeArray.ToList(); + + } + else + { + // Add the slsTarget to the config we want to store + mySLSMapConfig.BezelModes = new List(); + } + + // Process the transientModeBuffer + ADL_BEZEL_TRANSIENT_MODE[] transientModeArray = new ADL_BEZEL_TRANSIENT_MODE[numTransientMode]; + if (numTransientMode > 0) + { + IntPtr currentTransientModeBuffer = transientModeBuffer; + for (int i = 0; i < numTransientMode; i++) + { + // build a structure in the array slot + transientModeArray[i] = new ADL_BEZEL_TRANSIENT_MODE(); + // fill the array slot structure with the data from the buffer + transientModeArray[i] = (ADL_BEZEL_TRANSIENT_MODE)Marshal.PtrToStructure(currentTransientModeBuffer, typeof(ADL_BEZEL_TRANSIENT_MODE)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentTransientModeBuffer = (IntPtr)((long)currentTransientModeBuffer + Marshal.SizeOf(transientModeArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(transientModeBuffer); + + // Add the transientModes to the config we want to store + mySLSMapConfig.TransientModes = transientModeArray.ToList(); + } + else + { + // Add the slsTarget to the config we want to store + mySLSMapConfig.TransientModes = new List(); + } + + // Process the slsOffsetBuffer + ADL_SLS_OFFSET[] slsOffsetArray = new ADL_SLS_OFFSET[numSLSOffset]; + if (numSLSOffset > 0) + { + IntPtr currentSLSOffsetBuffer = slsOffsetBuffer; + for (int i = 0; i < numSLSOffset; i++) + { + // build a structure in the array slot + slsOffsetArray[i] = new ADL_SLS_OFFSET(); + // fill the array slot structure with the data from the buffer + slsOffsetArray[i] = (ADL_SLS_OFFSET)Marshal.PtrToStructure(currentSLSOffsetBuffer, typeof(ADL_SLS_OFFSET)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentSLSOffsetBuffer = (IntPtr)((long)currentSLSOffsetBuffer + Marshal.SizeOf(slsOffsetArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(slsOffsetBuffer); + + // Add the slsOffsets to the config we want to store + mySLSMapConfig.SLSOffsets = slsOffsetArray.ToList(); + + } + else + { + // Add the slsTarget to the config we want to store + mySLSMapConfig.SLSOffsets = new List(); + } + + // Now we try to calculate whether SLS is enabled + // NFI why they don't just add a ADL2_Display_SLSMapConfig_GetState function to make this easy for ppl :( + // NVIDIA make it easy, why can't you AMD? + + // Logic cribbed from https://github.com/elitak/amd-adl-sdk/blob/master/Sample/Eyefinity/ati_eyefinity.c + // Go through each display Target + foreach (var displayTarget in displayTargetArray) + { + // Get the current Display Modes for this adapter/display combination + int numDisplayModes; + IntPtr displayModeBuffer; + ADLRet = ADLImport.ADL2_Display_Modes_Get( + _adlContextHandle, + oneAdapter.AdapterIndex, + displayTarget.DisplayID.DisplayLogicalIndex, + out numDisplayModes, + out displayModeBuffer); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_Modes_Get returned information about the display modes used by display #{displayTarget.DisplayID.DisplayLogicalAdapterIndex} connected to AMD adapter {adapterIndex}."); + } + else + { + SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Display_Modes_Get returned ADL_STATUS {ADLRet} when trying to get the display modes from AMD adapter {adapterIndex} in the computer."); + continue; + } + + ADL_MODE[] displayModeArray = new ADL_MODE[numDisplayModes]; + if (numDisplayModes > 0) + { + IntPtr currentDisplayModeBuffer = displayModeBuffer; + for (int i = 0; i < numDisplayModes; i++) + { + // build a structure in the array slot + displayModeArray[i] = new ADL_MODE(); + // fill the array slot structure with the data from the buffer + displayModeArray[i] = (ADL_MODE)Marshal.PtrToStructure(currentDisplayModeBuffer, typeof(ADL_MODE)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentDisplayModeBuffer = (IntPtr)((long)currentDisplayModeBuffer + Marshal.SizeOf(displayModeArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(displayModeBuffer); + + // Add the slsOffsets to the config we want to store + //mySLSMapConfig.SLSOffsets = displayModeArray.ToList(); + + } + + // If Eyefinity is enabled for this adapter, then the display mode of an + // attached display target will match one of the SLS display modes reported by + // ADL_Display_SLSMapConfig_Get(). The match will either be with "native" SLS + // modes (which are not bezel-compensated), or with "bezel" SLS modes which are. + // + // So, simply compare current display mode against all the ones listed for the + // SLS native or bezel-compensated modes: if there is a match, then the mode + // currently used by this adapter is an Eyefinity/SLS mode, and Eyefinity is enabled. + // First check the native SLS mode list + // Process the slsOffsetBuffer + bool isSlsEnabled = false; + bool isBezelCompensatedDisplay = false; + foreach (var displayMode in displayModeArray) + { + foreach (var nativeMode in nativeModeArray) + { + if (nativeMode.DisplayMode.XRes == displayMode.XRes && nativeMode.DisplayMode.YRes == displayMode.YRes) + { + isSlsEnabled = true; + break; + } + + } + + // If no match was found, check the bezel-compensated SLS mode list + if (!isSlsEnabled) + { + foreach (var bezelMode in bezelModeArray) + { + if (bezelMode.DisplayMode.XRes == displayMode.XRes && bezelMode.DisplayMode.YRes == displayMode.YRes) + { + isSlsEnabled = true; + isBezelCompensatedDisplay = true; + break; + } + } + } + + // Now we check which slot we need to put this display into + if (isSlsEnabled) + { + // SLS is enabled for this display + if (!myDisplayConfig.SlsConfig.SLSEnabledDisplayTargets.Contains(displayMode)) + { + myDisplayConfig.SlsConfig.SLSEnabledDisplayTargets.Add(displayMode); + } + // we also update the main IsSLSEnabled so that it is indicated at the top level too + + myDisplayConfig.SlsConfig.IsSlsEnabled = true; + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} has a matching SLS grid set! Eyefinity (SLS) is enabled. Setting IsSlsEnabled to true"); + + } + } + + } + + // Only Add the mySLSMapConfig to the displayConfig if SLS is enabled + if (myDisplayConfig.SlsConfig.IsSlsEnabled) + { + myDisplayConfig.SlsConfig.SLSMapConfigs.Add(mySLSMapConfig); + } + + } + else + { + // If we get here then there there was no active SLSGrid, meaning Eyefinity is disabled! + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} has no active SLS grids set! Eyefinity (SLS) hasn't even been setup yet. Keeping the default IsSlsEnabled value of false."); + } + } + else + { + // If we get here then there are less than two displays connected. Eyefinity cannot be enabled in this case! + SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: There are less than two displays connected to this adapter so Eyefinity cannot be enabled."); + } + + + myDisplayConfig.HdrConfigs = new Dictionary(); + // Now we need to get all the displays connected to this adapter so that we can get their HDR state + foreach (var displayTarget in displayTargetArray) + { + // Go through each display and see if HDR is supported + int supported = 0; + int enabled = 0; + ADLRet = ADLImport.ADL2_Display_HDRState_Get(_adlContextHandle, adapterIndex, displayTarget.DisplayID, out supported, out enabled); + if (ADLRet == ADL_STATUS.ADL_OK) + { + if (supported > 0 && enabled > 0) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Get says that display {displayTarget.DisplayID.DisplayLogicalIndex} on adapter {adapterIndex} supports HDR and HDR is enabled."); + } + else if (supported > 0 && enabled == 0) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Get says that display {displayTarget.DisplayID.DisplayLogicalIndex} on adapter {adapterIndex} supports HDR and HDR is NOT enabled."); + } + else + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Get says that display {displayTarget.DisplayID.DisplayLogicalIndex} on adapter {adapterIndex} does NOT support HDR."); } } else { - SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: SLS (Eyfinity) is NOT enabled on AMD adapter {adapterIndex} (can't be as there is only one display!)."); - // Set the SLS Map Index if there is NOT Eyefinity - savedAdapterConfig.IsSLSEnabled = false; - savedAdapterConfig.SLSMapIndex = -1; + SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Display_HDRState_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from AMD adapter {adapterIndex} in the computer."); + throw new AMDLibraryException($"ADL2_Display_HDRState_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from AMD adapter {adapterIndex} in the computer"); + } + AMD_HDR_CONFIG hdrConfig = new AMD_HDR_CONFIG(); + hdrConfig.AdapterIndex = displayTarget.DisplayID.DisplayPhysicalAdapterIndex; + hdrConfig.HDREnabled = enabled > 0 ? true : false; + hdrConfig.HDRSupported = supported > 0 ? true : false; + + // Now add this to the HDR config list. + if (!myDisplayConfig.HdrConfigs.ContainsKey(displayTarget.DisplayID.DisplayLogicalIndex)) + { + // Save the new display config only if we haven't already + myDisplayConfig.HdrConfigs.Add(displayTarget.DisplayID.DisplayLogicalIndex, hdrConfig); } } - // We want to get the AMD HDR information and store it for later - //ADL2_Display_HDRState_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLDisplayID displayID, int * iSupport, int * iEnable) - // Save the AMD Adapter Config - if (!myDisplayConfig.AdapterConfigs.Contains(savedAdapterConfig)) - { - // Save the new adapter config only if we haven't already - myDisplayConfig.AdapterConfigs.Add(savedAdapterConfig); - } - + } + + // Add the AMD Display Identifiers + myDisplayConfig.DisplayIdentifiers = GetCurrentDisplayIdentifiers(); } else { @@ -586,258 +895,375 @@ namespace DisplayMagicianShared.AMD { string stringToReturn = ""; - // Get the size of the largest Active Paths and Modes arrays - int pathCount = 0; - int modeCount = 0; - WIN32STATUS err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount); - if (err != WIN32STATUS.ERROR_SUCCESS) + // Get the current config + AMD_DISPLAY_CONFIG displayConfig = GetActiveConfig(); + + stringToReturn += $"****** AMD VIDEO CARDS *******\n"; + + + if (_initialised) { - SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes"); - throw new AMDLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes"); + // Get the number of AMD adapters that the OS knows about + int numAdapters = 0; + ADL_STATUS ADLRet = ADLImport.ADL2_Adapter_NumberOfAdapters_Get(_adlContextHandle, out numAdapters); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Adapter_NumberOfAdapters_Get returned the number of AMD Adapters the OS knows about ({numAdapters})."); + } + else + { + SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - ADL2_Adapter_NumberOfAdapters_Get returned ADL_STATUS {ADLRet} when trying to get number of AMD adapters in the computer."); + } + + // Figure out primary adapter + int primaryAdapterIndex = 0; + ADLRet = ADLImport.ADL2_Adapter_Primary_Get(_adlContextHandle, out primaryAdapterIndex); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: The primary adapter has index {primaryAdapterIndex}."); + } + else + { + SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - ADL2_Adapter_Primary_Get returned ADL_STATUS {ADLRet} when trying to get the primary adapter info from all the AMD adapters in the computer."); + } + + // Now go through each adapter and get the information we need from it + for (int adapterIndex = 0; adapterIndex < numAdapters; adapterIndex++) + { + // Skip this adapter if it isn't active + int adapterActiveStatus = ADLImport.ADL_FALSE; + ADLRet = ADLImport.ADL2_Adapter_Active_Get(_adlContextHandle, adapterIndex, out adapterActiveStatus); + if (ADLRet == ADL_STATUS.ADL_OK) + { + if (adapterActiveStatus == ADLImport.ADL_TRUE) + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Adapter_Active_Get returned ADL_TRUE - AMD Adapter #{adapterIndex} is active! We can continue."); + } + else + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Adapter_Active_Get returned ADL_FALSE - AMD Adapter #{adapterIndex} is NOT active, so skipping."); + continue; + } + } + else + { + SharedLogger.logger.Warn($"AMDLibrary/PrintActiveConfig: WARNING - ADL2_Adapter_Active_Get returned ADL_STATUS {ADLRet} when trying to see if AMD Adapter #{adapterIndex} is active. Trying to skip this adapter so something at least works."); + continue; + } + + // Get the Adapter info for this adapter and put it in the AdapterBuffer + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Running ADL2_Adapter_AdapterInfoX4_Get to get the information about AMD Adapter #{adapterIndex}."); + int numAdaptersInfo = 0; + IntPtr adapterInfoBuffer = IntPtr.Zero; + ADLRet = ADLImport.ADL2_Adapter_AdapterInfoX4_Get(_adlContextHandle, adapterIndex, out numAdaptersInfo, out adapterInfoBuffer); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Adapter_AdapterInfoX4_Get returned information about AMD Adapter #{adapterIndex}."); + } + else + { + SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - ADL2_Adapter_AdapterInfoX4_Get returned ADL_STATUS {ADLRet} when trying to get the adapter info from AMD Adapter #{adapterIndex}. Trying to skip this adapter so something at least works."); + continue; + } + + ADL_ADAPTER_INFOX2[] adapterArray = new ADL_ADAPTER_INFOX2[numAdaptersInfo]; + if (numAdaptersInfo > 0) + { + IntPtr currentDisplayTargetBuffer = adapterInfoBuffer; + for (int i = 0; i < numAdaptersInfo; i++) + { + // build a structure in the array slot + adapterArray[i] = new ADL_ADAPTER_INFOX2(); + // fill the array slot structure with the data from the buffer + adapterArray[i] = (ADL_ADAPTER_INFOX2)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(adapterArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(adapterInfoBuffer); + } + + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Converted ADL2_Adapter_AdapterInfoX4_Get memory buffer into a {adapterArray.Length} long array about AMD Adapter #{adapterIndex}."); + + AMD_ADAPTER_CONFIG savedAdapterConfig = new AMD_ADAPTER_CONFIG(); + ADL_ADAPTER_INFOX2 oneAdapter = adapterArray[0]; + if (oneAdapter.Exist != 1) + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} doesn't exist at present so skipping detection for this adapter."); + continue; + } + + // Print out what we need + stringToReturn += $"Adapter #{adapterIndex}\n"; + stringToReturn += $"Adapter Exists: {oneAdapter.Exist}\n"; + stringToReturn += $"Adapter Present: {oneAdapter.Present}\n"; + stringToReturn += $"Adapter Name: {oneAdapter.AdapterName}\n"; + stringToReturn += $"Adapter Display Name: {oneAdapter.DisplayName}\n"; + stringToReturn += $"Adapter Driver Path: {oneAdapter.DriverPath}\n"; + stringToReturn += $"Adapter Driver Path Extension: {oneAdapter.DriverPathExt}\n"; + stringToReturn += $"Adapter UDID: {oneAdapter.UDID}\n"; + stringToReturn += $"Adapter Vendor ID: {oneAdapter.VendorID}\n"; + stringToReturn += $"Adapter PNP String: {oneAdapter.PNPString}\n"; + stringToReturn += $"Adapter PCI Device Number: {oneAdapter.DeviceNumber}\n"; + stringToReturn += $"Adapter PCI Bus Number: {oneAdapter.BusNumber}\n"; + stringToReturn += $"Adapter Windows OS Display Index: {oneAdapter.OSDisplayIndex}\n"; + stringToReturn += $"Adapter Display Connected: {oneAdapter.DisplayConnectedSet}\n"; + stringToReturn += $"Adapter Display Mapped in Windows: {oneAdapter.DisplayMappedSet}\n"; + stringToReturn += $"Adapter Is Forcibly Enabled: {oneAdapter.ForcibleSet}\n"; + stringToReturn += $"Adapter GetLock is Set: {oneAdapter.GenLockSet}\n"; + stringToReturn += $"Adapter LDA Display is Set: {oneAdapter.LDADisplaySet}\n"; + stringToReturn += $"Adapter Display Configuration is stretched horizontally across two displays: {oneAdapter.Manner2HStretchSet}\n"; + stringToReturn += $"Adapter Display Configuration is stretched vertically across two displays: {oneAdapter.Manner2VStretchSet}\n"; + stringToReturn += $"Adapter Display Configuration is a clone of another display: {oneAdapter.MannerCloneSet}\n"; + stringToReturn += $"Adapter Display Configuration is an extension of another display: {oneAdapter.MannerExtendedSet}\n"; + stringToReturn += $"Adapter Display Configuration is an N Strech across 1 GPU: {oneAdapter.MannerNStretch1GPUSet}\n"; + stringToReturn += $"Adapter Display Configuration is an N Strech across more than one GPU: {oneAdapter.MannerNStretchNGPUSet}\n"; + stringToReturn += $"Adapter Display Configuration is a single display: {oneAdapter.MannerSingleSet}\n"; + stringToReturn += $"Adapter timing override: {oneAdapter.ModeTimingOverrideSet}\n"; + stringToReturn += $"Adapter has MultiVPU set: {oneAdapter.MultiVPUSet}\n"; + stringToReturn += $"Adapter has non-local set (it is a remote display): {oneAdapter.NonLocalSet}\n"; + stringToReturn += $"Adapter is a Show Type Projector: {oneAdapter.ShowTypeProjectorSet}\n\n"; + + } + + // Now we still try to get the information from each display we need to print + int numDisplayTargets = 0; + int numDisplayMaps = 0; + IntPtr displayTargetBuffer = IntPtr.Zero; + IntPtr displayMapBuffer = IntPtr.Zero; + ADLRet = ADLImport.ADL2_Display_DisplayMapConfig_Get(_adlContextHandle, -1, out numDisplayMaps, out displayMapBuffer, out numDisplayTargets, out displayTargetBuffer, ADLImport.ADL_DISPLAY_DISPLAYMAP_OPTION_GPUINFO); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Display_DisplayMapConfig_Get returned information about all displaytargets connected to all AMD adapters."); + + // Free the memory used by the buffer to avoid heap corruption + Marshal.FreeCoTaskMem(displayMapBuffer); + + ADL_DISPLAY_TARGET[] displayTargetArray = { }; + if (numDisplayTargets > 0) + { + IntPtr currentDisplayTargetBuffer = displayTargetBuffer; + //displayTargetArray = new ADL_DISPLAY_TARGET[numDisplayTargets]; + displayTargetArray = new ADL_DISPLAY_TARGET[numDisplayTargets]; + for (int i = 0; i < numDisplayTargets; i++) + { + // build a structure in the array slot + displayTargetArray[i] = new ADL_DISPLAY_TARGET(); + //displayTargetArray[i] = new ADL_DISPLAY_TARGET(); + // fill the array slot structure with the data from the buffer + displayTargetArray[i] = (ADL_DISPLAY_TARGET)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); + //displayTargetArray[i] = (ADL_DISPLAY_TARGET)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); + // destroy the bit of memory we no longer need + Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); + // advance the buffer forwards to the next object + currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(displayTargetArray[i])); + //currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(displayTargetArray[i])); + + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(displayTargetBuffer); + } + + foreach (var displayTarget in displayTargetArray) + { + int forceDetect = 0; + int numDisplays; + IntPtr displayInfoBuffer; + ADLRet = ADLImport.ADL2_Display_DisplayInfo_Get(_adlContextHandle, displayTarget.DisplayID.DisplayLogicalAdapterIndex, out numDisplays, out displayInfoBuffer, forceDetect); + if (ADLRet == ADL_STATUS.ADL_OK) + { + if (displayTarget.DisplayID.DisplayLogicalAdapterIndex == -1) + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Display_DisplayInfo_Get returned information about all displaytargets connected to all AMD adapters."); + continue; + } + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Display_DisplayInfo_Get returned information about all displaytargets connected to all AMD adapters."); + } + else if (ADLRet == ADL_STATUS.ADL_ERR_NULL_POINTER || ADLRet == ADL_STATUS.ADL_ERR_NOT_SUPPORTED) + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Display_DisplayInfo_Get returned ADL_ERR_NULL_POINTER so skipping getting display info from all AMD adapters."); + continue; + } + else + { + SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - ADL2_Display_DisplayInfo_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from all AMD adapters in the computer."); + } + + ADL_DISPLAY_INFO[] displayInfoArray = { }; + if (numDisplays > 0) + { + IntPtr currentDisplayInfoBuffer = displayInfoBuffer; + displayInfoArray = new ADL_DISPLAY_INFO[numDisplays]; + for (int i = 0; i < numDisplays; i++) + { + // build a structure in the array slot + displayInfoArray[i] = new ADL_DISPLAY_INFO(); + // fill the array slot structure with the data from the buffer + displayInfoArray[i] = (ADL_DISPLAY_INFO)Marshal.PtrToStructure(currentDisplayInfoBuffer, typeof(ADL_DISPLAY_INFO)); + // destroy the bit of memory we no longer need + Marshal.DestroyStructure(currentDisplayInfoBuffer, typeof(ADL_DISPLAY_INFO)); + // advance the buffer forwards to the next object + currentDisplayInfoBuffer = (IntPtr)((long)currentDisplayInfoBuffer + Marshal.SizeOf(displayInfoArray[i])); + //currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(displayTargetArray[i])); + + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(displayInfoBuffer); + } + + // Now we need to get all the displays connected to this adapter so that we can get their HDR state + foreach (var displayInfoItem in displayInfoArray) + { + + // Ignore the display if it isn't connected (note: we still need to see if it's actively mapped to windows!) + if (!displayInfoItem.DisplayConnectedSet) + { + continue; + } + + // If the display is not mapped in windows then we only want to skip this display if all alldisplays is false + if (!displayInfoItem.DisplayMappedSet) + { + continue; + } + + stringToReturn += $"\n****** AMD DISPLAY INFO *******\n"; + stringToReturn += $"Display #{displayInfoItem.DisplayID.DisplayLogicalIndex}\n"; + stringToReturn += $"Display connected via Adapter #{displayInfoItem.DisplayID.DisplayLogicalAdapterIndex}\n"; + stringToReturn += $"Display Name: {displayInfoItem.DisplayName}\n"; + stringToReturn += $"Display Manufacturer Name: {displayInfoItem.DisplayManufacturerName}\n"; + stringToReturn += $"Display Type: {displayInfoItem.DisplayType.ToString("G")}\n"; + stringToReturn += $"Display connector: {displayInfoItem.DisplayConnector.ToString("G")}\n"; + stringToReturn += $"Display controller index: {displayInfoItem.DisplayControllerIndex}\n"; + stringToReturn += $"Display Connected: {displayInfoItem.DisplayConnectedSet}\n"; + stringToReturn += $"Display Mapped in Windows: {displayInfoItem.DisplayMappedSet}\n"; + stringToReturn += $"Display Is Forcibly Enabled: {displayInfoItem.ForcibleSet}\n"; + stringToReturn += $"Display GetLock is Set: {displayInfoItem.GenLockSet}\n"; + stringToReturn += $"LDA Display is Set: {displayInfoItem.LDADisplaySet}\n"; + stringToReturn += $"Display Configuration is stretched horizontally across two displays: {displayInfoItem.Manner2HStretchSet}\n"; + stringToReturn += $"Display Configuration is stretched vertically across two displays: {displayInfoItem.Manner2VStretchSet}\n"; + stringToReturn += $"Display Configuration is a clone of another display: {displayInfoItem.MannerCloneSet}\n"; + stringToReturn += $"Display Configuration is an extension of another display: {displayInfoItem.MannerExtendedSet}\n"; + stringToReturn += $"Display Configuration is an N Strech across 1 GPU: {displayInfoItem.MannerNStretch1GPUSet}\n"; + stringToReturn += $"Display Configuration is an N Strech across more than one GPU: {displayInfoItem.MannerNStretchNGPUSet}\n"; + stringToReturn += $"Display Configuration is a single display: {displayInfoItem.MannerSingleSet}\n"; + stringToReturn += $"Display timing override: {displayInfoItem.ModeTimingOverrideSet}\n"; + stringToReturn += $"Display has MultiVPU set: {displayInfoItem.MultiVPUSet}\n"; + stringToReturn += $"Display has non-local set (it is a remote display): {displayInfoItem.NonLocalSet}\n"; + stringToReturn += $"Display is a Show Type Projector: {displayInfoItem.ShowTypeProjectorSet}\n\n"; + + // Get some more Display Info (if we can!) + ADL_DDC_INFO2 ddcInfo; + ADLRet = ADLImport.ADL2_Display_DDCInfo2_Get(_adlContextHandle, displayInfoItem.DisplayID.DisplayLogicalAdapterIndex, displayInfoItem.DisplayID.DisplayLogicalIndex, out ddcInfo); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Display_DDCInfo2_Get returned information about DDC Information for display {displayInfoItem.DisplayID.DisplayLogicalIndex} connected to AMD adapter {displayInfoItem.DisplayID.DisplayLogicalAdapterIndex}."); + if (ddcInfo.SupportsDDC == 1) + { + // The display supports DDC and returned some data! + SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: ADL2_Display_DDCInfo2_Get returned information about DDC Information for display {displayInfoItem.DisplayID.DisplayLogicalIndex} connected to AMD adapter {displayInfoItem.DisplayID.DisplayLogicalAdapterIndex}."); + stringToReturn += $"DDC Information: \n"; + stringToReturn += $"- Display Name: {ddcInfo.DisplayName}\n"; + stringToReturn += $"- Display Manufacturer ID: {ddcInfo.ManufacturerID}\n"; + stringToReturn += $"- Display Product ID: {ddcInfo.ProductID}\n"; + stringToReturn += $"- Display Serial ID: {ddcInfo.SerialID}\n"; + stringToReturn += $"- Display FreeSync Flags: {ddcInfo.FreesyncFlags}\n"; + stringToReturn += $"- Display FreeSync HDR Supported: {ddcInfo.FreeSyncHDRSupported}\n"; + stringToReturn += $"- Display FreeSync HDR Backlight Supported: {ddcInfo.FreeSyncHDRBacklightSupported}\n"; + stringToReturn += $"- Display FreeSync HDR Local Dimming Supported: {ddcInfo.FreeSyncHDRLocalDimmingSupported}\n"; + stringToReturn += $"- Display is Digital Device: {ddcInfo.IsDigitalDevice}\n"; + stringToReturn += $"- Display is HDMI Audio Device: {ddcInfo.IsHDMIAudioDevice}\n"; + stringToReturn += $"- Display is Projector Device: {ddcInfo.IsProjectorDevice}\n"; + stringToReturn += $"- Display Supported Colourspace: {ddcInfo.SupportedColorSpace}\n"; + stringToReturn += $"- Display Supported HDR: {ddcInfo.SupportedHDR}\n"; + stringToReturn += $"- Display Supported Transfer Function: {ddcInfo.SupportedTransferFunction}\n"; + stringToReturn += $"- Display Supports AI: {ddcInfo.SupportsAI}\n"; + stringToReturn += $"- Display Supports DDC: {ddcInfo.SupportsDDC}\n"; + stringToReturn += $"- Display Supports DolbyVision: {ddcInfo.DolbyVisionSupported}\n"; + stringToReturn += $"- Display Supports CEA861_3: {ddcInfo.CEA861_3Supported}\n"; + stringToReturn += $"- Display Supports sxvYCC601: {ddcInfo.SupportsxvYCC601}\n"; + stringToReturn += $"- Display Supports sxvYCC709: {ddcInfo.SupportsxvYCC709}\n"; + stringToReturn += $"- Display Average Luminance Data: {ddcInfo.AvgLuminanceData}\n"; + stringToReturn += $"- Display Diffuse Screen Reflectance: {ddcInfo.DiffuseScreenReflectance}\n"; + stringToReturn += $"- Display Specular Screen Reflectance: {ddcInfo.SpecularScreenReflectance}\n"; + stringToReturn += $"- Display Max Backlight Min Luminance: {ddcInfo.MaxBacklightMinLuminanceData}\n"; + stringToReturn += $"- Display Max Backlight Max Luminance: {ddcInfo.MaxBacklightMaxLuminanceData}\n"; + stringToReturn += $"- Display Min Luminance: {ddcInfo.MinLuminanceData}\n"; + stringToReturn += $"- Display Max Luminance: {ddcInfo.MaxLuminanceData}\n"; + stringToReturn += $"- Display Min Backlight Min Luminance: {ddcInfo.MinBacklightMinLuminanceData}\n"; + stringToReturn += $"- Display Min Backlight Max Luminance: {ddcInfo.MinBacklightMaxLuminanceData}\n"; + stringToReturn += $"- Display Min Luminance No Dimming: {ddcInfo.MinLuminanceNoDimmingData}\n"; + stringToReturn += $"- Display Native Chromacity Red X: {ddcInfo.NativeDisplayChromaticityRedX}\n"; + stringToReturn += $"- Display Native Chromacity Red Y: {ddcInfo.NativeDisplayChromaticityRedY}\n"; + stringToReturn += $"- Display Native Chromacity Green X: {ddcInfo.NativeDisplayChromaticityGreenX}\n"; + stringToReturn += $"- Display Native Chromacity Green Y: {ddcInfo.NativeDisplayChromaticityGreenY}\n"; + stringToReturn += $"- Display Native Chromacity Blue X: {ddcInfo.NativeDisplayChromaticityBlueX}\n"; + stringToReturn += $"- Display Native Chromacity Blue Y: {ddcInfo.NativeDisplayChromaticityBlueY}\n"; + stringToReturn += $"- Display Native Chromacity White X: {ddcInfo.NativeDisplayChromaticityWhiteX}\n"; + stringToReturn += $"- Display Native Chromacity White Y: {ddcInfo.NativeDisplayChromaticityWhiteY}\n"; + stringToReturn += $"- Display Packed Pixel Supported: {ddcInfo.PackedPixelSupported}\n"; + stringToReturn += $"- Display Panel Pixel Format: {ddcInfo.PanelPixelFormat}\n"; + stringToReturn += $"- Display Pixel Format Limited Range: {ddcInfo.PixelFormatLimitedRange}\n"; + stringToReturn += $"- Display PTMCx: {ddcInfo.PTMCx}\n"; + stringToReturn += $"- Display PTMCy: {ddcInfo.PTMCy}\n"; + stringToReturn += $"- Display PTM Refresh Rate: {ddcInfo.PTMRefreshRate}\n"; + + stringToReturn += $"- Display Serial ID: {ddcInfo.SerialID}\n"; + } + + } + + } + } + + } + + stringToReturn += $"\n****** AMD EYEFINITY (SLS) *******\n"; + if (displayConfig.SlsConfig.IsSlsEnabled) + { + stringToReturn += $"AMD Eyefinity is Enabled\n"; + if (displayConfig.SlsConfig.SLSMapConfigs.Count > 1) + { + stringToReturn += $"There are {displayConfig.SlsConfig.SLSMapConfigs.Count} AMD Eyefinity (SLS) configurations in use.\n"; + } + if (displayConfig.SlsConfig.SLSMapConfigs.Count == 1) + { + stringToReturn += $"There is 1 AMD Eyefinity (SLS) configurations in use.\n"; + } + else + { + stringToReturn += $"There are no AMD Eyefinity (SLS) configurations in use.\n"; + } + + int count = 0; + foreach (var slsMap in displayConfig.SlsConfig.SLSMapConfigs) + { + stringToReturn += $"NOTE: This Eyefinity (SLS) screen will be treated as a single display by Windows.\n"; + stringToReturn += $"The AMD Eyefinity (SLS) Grid Topology #{count} is {slsMap.SLSMap.Grid.SLSGridColumn} Columns x {slsMap.SLSMap.Grid.SLSGridRow} Rows\n"; + stringToReturn += $"The AMD Eyefinity (SLS) Grid Topology #{count} involves {slsMap.SLSMap.NumSLSTarget} Displays\n"; + } + + } + else + { + stringToReturn += $"AMD Eyefinity (SLS) is Disabled\n"; + } + + } + else + { + SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - Tried to run GetSomeDisplayIdentifiers but the AMD ADL library isn't initialised!"); + throw new AMDLibraryException($"Tried to run PrintActiveConfig but the AMD ADL library isn't initialised!"); } - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Getting the current Display Config path and mode arrays"); - var paths = new DISPLAYCONFIG_PATH_INFO[pathCount]; - var modes = new DISPLAYCONFIG_MODE_INFO[modeCount]; - err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero); - if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER) - { - SharedLogger.logger.Warn($"AMDLibrary/PrintActiveConfig: The displays were modified between GetDisplayConfigBufferSizes and QueryDisplayConfig so we need to get the buffer sizes again."); - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Getting the size of the largest Active Paths and Modes arrays"); - // Screen changed in between GetDisplayConfigBufferSizes and QueryDisplayConfig, so we need to get buffer sizes again - // as per https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-querydisplayconfig - err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount); - if (err != WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again"); - throw new AMDLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again"); - } - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Getting the current Display Config path and mode arrays"); - paths = new DISPLAYCONFIG_PATH_INFO[pathCount]; - modes = new DISPLAYCONFIG_MODE_INFO[modeCount]; - err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero); - if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER) - { - SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong."); - throw new AMDLibraryException($"The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong."); - } - else if (err != WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again"); - throw new AMDLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again."); - } - } - else if (err != WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays"); - throw new AMDLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays."); - } - - foreach (var path in paths) - { - stringToReturn += $"----++++==== Path ====++++----\n"; - - // get display source name - var sourceInfo = new DISPLAYCONFIG_SOURCE_DEVICE_NAME(); - sourceInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; - sourceInfo.Header.Size = (uint)Marshal.SizeOf(); - sourceInfo.Header.AdapterId = path.SourceInfo.AdapterId; - sourceInfo.Header.Id = path.SourceInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref sourceInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Found Display Source {sourceInfo.ViewGdiDeviceName} for source {path.SourceInfo.Id}."); - stringToReturn += $"****** Interrogating Display Source {path.SourceInfo.Id} *******\n"; - stringToReturn += $"Found Display Source {sourceInfo.ViewGdiDeviceName}\n"; - stringToReturn += $"\n"; - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/PrintActiveConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the source info for source adapter #{path.SourceInfo.AdapterId}"); - } - // get display target name - var targetInfo = new DISPLAYCONFIG_TARGET_DEVICE_NAME(); - targetInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; - targetInfo.Header.Size = (uint)Marshal.SizeOf(); - targetInfo.Header.AdapterId = path.TargetInfo.AdapterId; - targetInfo.Header.Id = path.TargetInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref targetInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Connector Instance: {targetInfo.ConnectorInstance} for source {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: EDID Manufacturer ID: {targetInfo.EdidManufactureId} for source {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: EDID Product Code ID: {targetInfo.EdidProductCodeId} for source {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Flags Friendly Name from EDID: {targetInfo.Flags.FriendlyNameFromEdid} for source {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Flags Friendly Name Forced: {targetInfo.Flags.FriendlyNameForced} for source {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Flags EDID ID is Valid: {targetInfo.Flags.EdidIdsValid} for source {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Monitor Device Path: {targetInfo.MonitorDevicePath} for source {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Monitor Friendly Device Name: {targetInfo.MonitorFriendlyDeviceName} for source {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Output Technology: {targetInfo.OutputTechnology} for source {path.TargetInfo.Id}."); + stringToReturn += $"\n\n"; + // Now we also get the Windows CCD Library info, and add it to the above + stringToReturn += WinLibrary.GetLibrary().PrintActiveConfig(); - stringToReturn += $"****** Interrogating Display Target {targetInfo.MonitorFriendlyDeviceName} *******\n"; - stringToReturn += $" Connector Instance: {targetInfo.ConnectorInstance}\n"; - stringToReturn += $" EDID Manufacturer ID: {targetInfo.EdidManufactureId}\n"; - stringToReturn += $" EDID Product Code ID: {targetInfo.EdidProductCodeId}\n"; - stringToReturn += $" Flags Friendly Name from EDID: {targetInfo.Flags.FriendlyNameFromEdid}\n"; - stringToReturn += $" Flags Friendly Name Forced: {targetInfo.Flags.FriendlyNameForced}\n"; - stringToReturn += $" Flags EDID ID is Valid: {targetInfo.Flags.EdidIdsValid}\n"; - stringToReturn += $" Monitor Device Path: {targetInfo.MonitorDevicePath}\n"; - stringToReturn += $" Monitor Friendly Device Name: {targetInfo.MonitorFriendlyDeviceName}\n"; - stringToReturn += $" Output Technology: {targetInfo.OutputTechnology}\n"; - stringToReturn += $"\n"; - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/PrintActiveConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{path.TargetInfo.Id}"); - } - - - // get display adapter name - var adapterInfo = new DISPLAYCONFIG_ADAPTER_NAME(); - adapterInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME; - adapterInfo.Header.Size = (uint)Marshal.SizeOf(); - adapterInfo.Header.AdapterId = path.TargetInfo.AdapterId; - adapterInfo.Header.Id = path.TargetInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref adapterInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/PrintActiveConfig: Found Adapter Device Path {adapterInfo.AdapterDevicePath} for source {path.TargetInfo.AdapterId}."); - stringToReturn += $"****** Interrogating Display Adapter {adapterInfo.AdapterDevicePath} *******\n"; - stringToReturn += $" Display Adapter {adapterInfo.AdapterDevicePath}\n"; - stringToReturn += $"\n"; - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the adapter device path for target #{path.TargetInfo.AdapterId}"); - } - - // get display target preferred mode - var targetPreferredInfo = new DISPLAYCONFIG_TARGET_PREFERRED_MODE(); - targetPreferredInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE; - targetPreferredInfo.Header.Size = (uint)Marshal.SizeOf(); - targetPreferredInfo.Header.AdapterId = path.TargetInfo.AdapterId; - targetPreferredInfo.Header.Id = path.TargetInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref targetPreferredInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Target Preferred Width {targetPreferredInfo.Width} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Target Preferred Height {targetPreferredInfo.Height} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Active Size: ({targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ActiveSize.Cx}x{targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ActiveSize.Cy} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Total Size: ({targetPreferredInfo.TargetMode.TargetVideoSignalInfo.TotalSize.Cx}x{targetPreferredInfo.TargetMode.TargetVideoSignalInfo.TotalSize.Cy} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info HSync Frequency: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.HSyncFreq} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info VSync Frequency: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.VSyncFreq} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Pixel Rate: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.PixelRate} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Scan Line Ordering: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ScanLineOrdering} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Video Standard: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.VideoStandard} for target {path.TargetInfo.Id}."); - - stringToReturn += $"****** Interrogating Target Preferred Mode for Display {path.TargetInfo.Id} *******\n"; - stringToReturn += $" Target Preferred Width {targetPreferredInfo.Width} for target {path.TargetInfo.Id}\n"; - stringToReturn += $" Target Preferred Height {targetPreferredInfo.Height} for target {path.TargetInfo.Id}\n"; - stringToReturn += $" Target Video Signal Info Active Size: ({targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ActiveSize.Cx}x{targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ActiveSize.Cy}\n"; - stringToReturn += $" Target Video Signal Info Total Size: ({targetPreferredInfo.TargetMode.TargetVideoSignalInfo.TotalSize.Cx}x{targetPreferredInfo.TargetMode.TargetVideoSignalInfo.TotalSize.Cy}\n"; - stringToReturn += $" Target Video Signal Info HSync Frequency: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.HSyncFreq}\n"; - stringToReturn += $" Target Video Signal Info VSync Frequency: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.VSyncFreq}\n"; - stringToReturn += $" Target Video Signal Info Pixel Rate: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.PixelRate}\n"; - stringToReturn += $" Target Video Signal Info Scan Line Ordering: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ScanLineOrdering}\n"; - stringToReturn += $" Target Video Signal Info Video Standard: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.VideoStandard}\n"; - stringToReturn += $"\n"; - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the preferred target name for display #{path.TargetInfo.Id}"); - } - - // get display target base type - var targetBaseTypeInfo = new DISPLAYCONFIG_TARGET_BASE_TYPE(); - targetBaseTypeInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE; - targetBaseTypeInfo.Header.Size = (uint)Marshal.SizeOf(); - targetBaseTypeInfo.Header.AdapterId = path.TargetInfo.AdapterId; - targetBaseTypeInfo.Header.Id = path.TargetInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref targetBaseTypeInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Virtual Resolution is Disabled: {targetBaseTypeInfo.BaseOutputTechnology} for target {path.TargetInfo.Id}."); - - stringToReturn += $"****** Interrogating Target Base Type for Display {path.TargetInfo.Id} *******\n"; - stringToReturn += $" Base Output Technology: {targetBaseTypeInfo.BaseOutputTechnology}\n"; - stringToReturn += $"\n"; - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target base type for display #{path.TargetInfo.Id}"); - } - - // get display support virtual resolution - var supportVirtResInfo = new DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION(); - supportVirtResInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION; - supportVirtResInfo.Header.Size = (uint)Marshal.SizeOf(); - supportVirtResInfo.Header.AdapterId = path.TargetInfo.AdapterId; - supportVirtResInfo.Header.Id = path.TargetInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref supportVirtResInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Base Output Technology: {supportVirtResInfo.IsMonitorVirtualResolutionDisabled} for target {path.TargetInfo.Id}."); - stringToReturn += $"****** Interrogating Target Supporting virtual resolution for Display {path.TargetInfo.Id} *******\n"; - stringToReturn += $" Virtual Resolution is Disabled: {supportVirtResInfo.IsMonitorVirtualResolutionDisabled}\n"; - stringToReturn += $"\n"; - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to find out the virtual resolution support for display #{path.TargetInfo.Id}"); - } - - //get advanced color info - 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 = (uint)Marshal.SizeOf(); - colorInfo.Header.AdapterId = path.TargetInfo.AdapterId; - colorInfo.Header.Id = path.TargetInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref colorInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Advanced Color Supported: {colorInfo.AdvancedColorSupported} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Advanced Color Enabled: {colorInfo.AdvancedColorEnabled} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Advanced Color Force Disabled: {colorInfo.AdvancedColorForceDisabled} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Bits per Color Channel: {colorInfo.BitsPerColorChannel} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Color Encoding: {colorInfo.ColorEncoding} for target {path.TargetInfo.Id}."); - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found Wide Color Enforced: {colorInfo.WideColorEnforced} for target {path.TargetInfo.Id}."); - - stringToReturn += $"****** Interrogating Advanced Color Info for Display {path.TargetInfo.Id} *******\n"; - stringToReturn += $" Advanced Color Supported: {colorInfo.AdvancedColorSupported}\n"; - stringToReturn += $" Advanced Color Enabled: {colorInfo.AdvancedColorEnabled}\n"; - stringToReturn += $" Advanced Color Force Disabled: {colorInfo.AdvancedColorForceDisabled}\n"; - stringToReturn += $" Bits per Color Channel: {colorInfo.BitsPerColorChannel}\n"; - stringToReturn += $" Color Encoding: {colorInfo.ColorEncoding}\n"; - stringToReturn += $" Wide Color Enforced: {colorInfo.WideColorEnforced}\n"; - stringToReturn += $"\n"; - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to find out the virtual resolution support for display #{path.TargetInfo.Id}"); - } - - // get SDR white levels - var whiteLevelInfo = new DISPLAYCONFIG_SDR_WHITE_LEVEL(); - whiteLevelInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL; - whiteLevelInfo.Header.Size = (uint)Marshal.SizeOf(); - whiteLevelInfo.Header.AdapterId = path.TargetInfo.AdapterId; - whiteLevelInfo.Header.Id = path.TargetInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref whiteLevelInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/GetWindowsDisplayConfig: Found SDR White Level: {whiteLevelInfo.SDRWhiteLevel} for target {path.TargetInfo.Id}."); - - stringToReturn += $"****** Interrogating SDR Whilte Level for Display {path.TargetInfo.Id} *******\n"; - stringToReturn += $" SDR White Level: {whiteLevelInfo.SDRWhiteLevel}\n"; - stringToReturn += $"\n"; - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to find out the SDL white level for display #{path.TargetInfo.Id}"); - } - } return stringToReturn; } @@ -846,113 +1272,105 @@ namespace DisplayMagicianShared.AMD if (_initialised) { - + // Set the initial state of the ADL_STATUS ADL_STATUS ADLRet = 0; - // We want to get the current config - //AMD_DISPLAY_CONFIG currentDisplayConfig = GetAMDDisplayConfig(QDC.QDC_ALL_PATHS); - // We want to check the AMD Eyefinity (SLS) config is valid - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Testing whether the display configuration is valid"); - //ADL2_Display_SLSMapConfig_Valid(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLSLSMap slsMap, int iNumDisplayTarget, ADLSLSTarget * lpSLSTarget, int * lpSupportedSLSLayoutImageMode, int * lpReasonForNotSupportSLS, int iOption) - foreach (var adapter in displayConfig.AdapterConfigs) + // We want to get the current config + AMD_DISPLAY_CONFIG currentDisplayConfig = GetAMDDisplayConfig(); + + // set the display locations + if (displayConfig.SlsConfig.IsSlsEnabled) { - // set the display locations - if (adapter.IsSLSEnabled) + // We need to change to an Eyefinity (SLS) profile, so we need to apply the new SLS Topologies + SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: SLS is enabled in the new display configuration, so we need to set it"); + + foreach (AMD_SLSMAP_CONFIG slsMapConfig in displayConfig.SlsConfig.SLSMapConfigs) { - // Turn the SLS based display map on - ADLRet = ADLImport.ADL2_Display_SLSMapConfig_SetState(_adlContextHandle, adapter.AdapterIndex, adapter.SLSMapIndex, ADLImport.ADL_TRUE); + // Turn on this SLS Map Config + ADLRet = ADLImport.ADL2_Display_SLSMapConfig_SetState(_adlContextHandle, slsMapConfig.SLSMap.AdapterIndex, slsMapConfig.SLSMap.SLSMapIndex, ADLImport.ADL_TRUE); if (ADLRet == ADL_STATUS.ADL_OK) { - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: ADL2_Display_SLSMapConfig_SetState successfully set the SLSMAP with index {adapter.SLSMapIndex} to TRUE for adapter {adapter.AdapterIndex}."); + SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: ADL2_Display_SLSMapConfig_SetState successfully set the SLSMAP with index {slsMapConfig.SLSMap.SLSMapIndex} to TRUE for adapter { slsMapConfig.SLSMap.AdapterIndex}."); } else { - SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - ADL2_Display_SLSMapConfig_SetState returned ADL_STATUS {ADLRet} when trying to set the SLSMAP with index {adapter.SLSMapIndex} to TRUE for adapter {adapter.AdapterIndex}."); - throw new AMDLibraryException($"ADL2_Display_SLSMapConfig_SetState returned ADL_STATUS {ADLRet} when trying to set the SLSMAP with index {adapter.SLSMapIndex} to TRUE for adapter {adapter.AdapterIndex}"); + SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - ADL2_Display_SLSMapConfig_SetState returned ADL_STATUS {ADLRet} when trying to set the SLSMAP with index {slsMapConfig.SLSMap.SLSMapIndex} to TRUE for adapter { slsMapConfig.SLSMap.AdapterIndex}."); + return false; } - /* - - foreach (var slsMap in adapter.SLSMap) - { - // Check the SLS config is valid - int numDisplayTargets = 0; - int supportedSLSLayoutImageMode = 0; - int reasonForNotSupportingSLS = 0; - ADL_DISPLAY_TARGET[] displayTargetArray = { new ADL_DISPLAY_TARGET() }; - IntPtr displayTargetBuffer = IntPtr.Zero; - int option = ADLImport.ADL_DISPLAY_SLSGRID_CAP_OPTION_RELATIVETO_LANDSCAPE; - ADLRet = ADLImport.ADL2_Display_SLSMapConfig_Valid(_adlContextHandle, adapter.AdapterIndex, slsMap, slsMap.NumSLSTarget, displayTargetArray, out supportedSLSLayoutImageMode, out reasonForNotSupportingSLS, option); - if (ADLRet == ADL_STATUS.ADL_OK) - { - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_SLSMapConfig_Valid confirmed the SLS configuration is valid for AMD adapter {adapter.AdapterIndex}."); - } - else - { - SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Display_SLSMapConfig_Valid returned ADL_STATUS {ADLRet} when trying to validate the SLS configuration for AMD adapter {adapter.AdapterIndex} in the computer."); - throw new AMDLibraryException($"ADL2_Display_SLSMapConfig_Valid returned ADL_STATUS {ADLRet}when trying to validate the SLS configuration for AMD adapter {adapter.AdapterIndex} in the computer"); - } - - if (numDisplayTargets > 0) - { - IntPtr currentDisplayTargetBuffer = displayTargetBuffer; - displayTargetArray = new ADL_DISPLAY_TARGET[numDisplayTargets]; - for (int i = 0; i < numDisplayTargets; i++) - { - // build a structure in the array slot - displayTargetArray[i] = new ADL_DISPLAY_TARGET(); - // fill the array slot structure with the data from the buffer - displayTargetArray[i] = (ADL_DISPLAY_TARGET)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); - // destroy the bit of memory we no longer need - Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); - // advance the buffer forwards to the next object - currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(displayTargetArray[i])); - } - // Free the memory used by the buffer - Marshal.FreeCoTaskMem(displayTargetBuffer); - } - }*/ } - /*else + + } + else + { + // We need to change to a plain, non-Eyefinity (SLS) profile, so we need to disable any SLS Topologies if they are being used + SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: SLS is not used in the new display configuration, so we need to set it to disabled if it's configured currently"); + + if (currentDisplayConfig.SlsConfig.IsSlsEnabled) { - *//*// Do the non-SLS based display setup - AMD_ADAPTER_CONFIG amdAdapterConfig = adapter; - //int numPossibleMapResult = 0; - //IntPtr possibleMapResultBuffer = IntPtr.Zero; - ADLRet = ADLImport.ADL2_Display_DisplayMapConfig_Set(_adlContextHandle, amdAdapterConfig.AdapterIndex, amdAdapterConfig.DisplayMaps.Length, amdAdapterConfig.DisplayMaps, amdAdapterConfig.DisplayTargets.Length, amdAdapterConfig.DisplayTargets); - if (ADLRet == ADL_STATUS.ADL_OK) + // We need to disable the current Eyefinity (SLS) profile to turn it off + SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: SLS is enabled in the current display configuration, so we need to turn it off"); + + foreach (AMD_SLSMAP_CONFIG slsMapConfig in currentDisplayConfig.SlsConfig.SLSMapConfigs) { - SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_DisplayMapConfig_Set returned information about all displaytargets connected to AMD adapter {amdAdapterConfig.AdapterIndex}."); - } - else - { - SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Display_DisplayMapConfig_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from AMD adapter {amdAdapterConfig.AdapterIndex} in the computer."); - throw new AMDLibraryException($"ADL2_Display_DisplayMapConfig_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from AMD adapter {amdAdapterConfig.AdapterIndex} in the computer"); - }*//* - }*/ - else - { - // Turn the SLS based display map off - ADLRet = ADLImport.ADL2_Display_SLSMapConfig_SetState(_adlContextHandle, adapter.AdapterIndex, adapter.SLSMapIndex, ADLImport.ADL_FALSE); - if (ADLRet == ADL_STATUS.ADL_OK) - { - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: ADL2_Display_SLSMapConfig_SetState successfully set the SLSMAP with index {adapter.SLSMapIndex} to FALSE for adapter {adapter.AdapterIndex}."); - } - else - { - SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - ADL2_Display_SLSMapConfig_SetState returned ADL_STATUS {ADLRet} when trying to set the SLSMAP with index {adapter.SLSMapIndex} to FALSE for adapter {adapter.AdapterIndex}."); - throw new AMDLibraryException($"ADL2_Display_SLSMapConfig_SetState returned ADL_STATUS {ADLRet} when trying to set the SLSMAP with index {adapter.SLSMapIndex} to FALSE for adapter {adapter.AdapterIndex}"); + // Turn on this SLS Map Config + ADLRet = ADLImport.ADL2_Display_SLSMapConfig_SetState(_adlContextHandle, slsMapConfig.SLSMap.AdapterIndex, slsMapConfig.SLSMap.SLSMapIndex, ADLImport.ADL_FALSE); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: ADL2_Display_SLSMapConfig_SetState successfully disabled the SLSMAP with index {slsMapConfig.SLSMap.SLSMapIndex} for adapter { slsMapConfig.SLSMap.AdapterIndex}."); + } + else + { + SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - ADL2_Display_SLSMapConfig_SetState returned ADL_STATUS {ADLRet} when trying to set the SLSMAP with index {slsMapConfig.SLSMap.SLSMapIndex} to FALSE for adapter { slsMapConfig.SLSMap.AdapterIndex}."); + return false; + } } } } - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Waiting 0.5 seconds to let the display change take place before adjusting the AMD HDR settings"); - System.Threading.Thread.Sleep(500); + // We want to set the AMD HDR settings now + // We got through each of the attached displays and set the HDR - // We want to set the AMD HDR settings + // Go through each of the HDR configs we have + foreach (var hdrConfig in displayConfig.HdrConfigs) + { + // Try and find the HDR config displays in the list of currently connected displays + foreach (var displayInfoItem in currentDisplayConfig.DisplayTargets) + { + // If we find the HDR config display in the list of currently connected displays then try to set the HDR setting we recorded earlier + if (hdrConfig.Key == displayInfoItem.DisplayID.DisplayLogicalIndex) + { + if (hdrConfig.Value.HDREnabled) + { + ADLRet = ADLImport.ADL2_Display_HDRState_Set(_adlContextHandle, hdrConfig.Value.AdapterIndex, displayInfoItem.DisplayID, 1); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Set was able to turn on HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}."); + } + else + { + SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Set was NOT able to turn on HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}."); + } + } + else + { + ADLRet = ADLImport.ADL2_Display_HDRState_Set(_adlContextHandle, hdrConfig.Value.AdapterIndex, displayInfoItem.DisplayID, 0); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Set was able to turn off HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}."); + } + else + { + SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Set was NOT able to turn off HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}."); + } + } + break; + } + } + + } - // We want to apply the Windows CCD layout info and HDR } else { @@ -960,92 +1378,6 @@ namespace DisplayMagicianShared.AMD throw new AMDLibraryException($"Tried to run SetActiveConfig but the AMD ADL library isn't initialised!"); } - - /* - // Get the all possible windows display configs - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Generating a list of all the current display configs"); - WINDOWS_DISPLAY_CONFIG allWindowsDisplayConfig = GetWindowsDisplayConfig(QDC.QDC_ALL_PATHS); - - // Now we go through the Paths to update the LUIDs as per Soroush's suggestion - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Patching the adapter IDs to make the saved config valid"); - PatchAdapterIDs(ref displayConfig, allWindowsDisplayConfig.displayAdapters); - - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Testing whether the display configuration is valid"); - // Test whether a specified display configuration is supported on the computer - uint myPathsCount = (uint)displayConfig.displayConfigPaths.Length; - uint myModesCount = (uint)displayConfig.displayConfigModes.Length; - WIN32STATUS err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.displayConfigPaths, myModesCount, displayConfig.displayConfigModes, SDC.DISPLAYMAGICIAN_VALIDATE); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Successfully validated that the display configuration supplied would work!"); - } - else - { - SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - SetDisplayConfig couldn't validate the display configuration supplied. This display configuration wouldn't work."); - return false; - } - - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Yay! The display configuration is valid! Attempting to set the Display Config now"); - // Now set the specified display configuration for this computer - err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.displayConfigPaths, myModesCount, displayConfig.displayConfigModes, SDC.DISPLAYMAGICIAN_SET); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Successfully set the display configuration to the settings supplied!"); - } - else - { - SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - SetDisplayConfig couldn't set the display configuration using the settings supplied. Something is wrong."); - throw new AMDLibraryException($"SetDisplayConfig couldn't set the display configuration using the settings supplied. Something is wrong."); - } - - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: SUCCESS! The display configuration has been successfully applied"); - - foreach (ADVANCED_HDR_INFO_PER_PATH myHDRstate in displayConfig.displayHDRStates) - { - SharedLogger.logger.Trace($"Trying to get information whether HDR color is in use now on Display {myHDRstate.Id}."); - // Get advanced HDR info - 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 = (uint)Marshal.SizeOf(); - colorInfo.Header.AdapterId = myHDRstate.AdapterId; - colorInfo.Header.Id = myHDRstate.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref colorInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Advanced Color Info gathered from Display {myHDRstate.Id}"); - - if (myHDRstate.AdvancedColorInfo.AdvancedColorSupported && colorInfo.AdvancedColorEnabled != myHDRstate.AdvancedColorInfo.AdvancedColorEnabled) - { - SharedLogger.logger.Trace($"HDR is available for use on Display {myHDRstate.Id}, and we want it set to {myHDRstate.AdvancedColorInfo.AdvancedColorEnabled} but is currently {colorInfo.AdvancedColorEnabled}."); - - var setColorState = new DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE(); - setColorState.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE; - setColorState.Header.Size = (uint)Marshal.SizeOf(); - setColorState.Header.AdapterId = myHDRstate.AdapterId; - setColorState.Header.Id = myHDRstate.Id; - setColorState.EnableAdvancedColor = myHDRstate.AdvancedColorInfo.AdvancedColorEnabled; - err = CCDImport.DisplayConfigSetDeviceInfo(ref setColorState); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: SUCCESS! Set HDR successfully to {myHDRstate.AdvancedColorInfo.AdvancedColorEnabled} on Display {myHDRstate.Id}"); - } - else - { - SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to set the HDR settings for display #{myHDRstate.Id}"); - return false; - } - } - else - { - SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: Skipping setting HDR on Display {myHDRstate.Id} as it does not support HDR"); - } - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to find out if HDR is supported for display #{myHDRstate.Id}"); - } - - }*/ return true; } @@ -1059,12 +1391,12 @@ namespace DisplayMagicianShared.AMD SharedLogger.logger.Trace($"AMDLibrary/IsActiveConfig: Checking whether the display configuration is already being used."); if (displayConfig.Equals(currentWindowsDisplayConfig)) { - SharedLogger.logger.Trace($"AMDLibrary/IsActiveConfig: The display configuration is already being used (supplied displayConfig Equals currentWindowsDisplayConfig"); + SharedLogger.logger.Trace($"AMDLibrary/IsActiveConfig: The display configuration is already being used (supplied displayConfig Equals currentWindowsDisplayConfig)"); return true; } else { - SharedLogger.logger.Trace($"AMDLibrary/IsActiveConfig: The display configuration is NOT currently in use (supplied displayConfig Equals currentWindowsDisplayConfig"); + SharedLogger.logger.Trace($"AMDLibrary/IsActiveConfig: The display configuration is NOT currently in use (supplied displayConfig Equals currentWindowsDisplayConfig)"); return false; } @@ -1072,207 +1404,19 @@ namespace DisplayMagicianShared.AMD public bool IsValidConfig(AMD_DISPLAY_CONFIG displayConfig) { - // We want to check the NVIDIA Surround (Mosaic) config is valid - SharedLogger.logger.Trace($"NVIDIALibrary/IsValidConfig: Testing whether the display configuration is valid"); + // We want to check the AMD Eyefinity (SLS) config is valid + SharedLogger.logger.Trace($"AMDLibrary/IsValidConfig: Testing whether the display configuration is valid"); // - return true; - - //if (displayConfig.MosaicConfig.IsMosaicEnabled) - //{ - - // =================================================================================================================================== - // Important! ValidateDisplayGrids does not work at the moment. It errors when supplied with a Grid Topology that works in SetDisplaGrids - // We therefore cannot use ValidateDisplayGrids to actually validate the config before it's use. We instead need to rely on SetDisplaGrids reporting an - // error if it is unable to apply the requested configuration. While this works fine, it's not optimal. - // TODO: Test ValidateDisplayGrids in a future NVIDIA driver release to see if they fixed it. - // =================================================================================================================================== - //return true; - - /*// Figure out how many Mosaic Grid topoligies there are - uint mosaicGridCount = 0; - NVAPI_STATUS NVStatus = NVImport.NvAPI_Mosaic_EnumDisplayGrids(ref mosaicGridCount); - if (NVStatus == NVAPI_STATUS.NVAPI_OK) - { - SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); - } - - // Get Current Mosaic Grid settings using the Grid topologies fnumbers we got before - //NV_MOSAIC_GRID_TOPO_V2[] mosaicGridTopos = new NV_MOSAIC_GRID_TOPO_V2[mosaicGridCount]; - NV_MOSAIC_GRID_TOPO_V1[] mosaicGridTopos = new NV_MOSAIC_GRID_TOPO_V1[mosaicGridCount]; - NVStatus = NVImport.NvAPI_Mosaic_EnumDisplayGrids(ref mosaicGridTopos, ref mosaicGridCount); - if (NVStatus == NVAPI_STATUS.NVAPI_OK) - { - SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) - { - SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) - { - SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) - { - SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) - { - SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) - { - SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); - } - else - { - SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); - } - */ - - /*NV_MOSAIC_SETDISPLAYTOPO_FLAGS setTopoFlags = NV_MOSAIC_SETDISPLAYTOPO_FLAGS.NONE; - bool topoValid = false; - NV_MOSAIC_DISPLAY_TOPO_STATUS_V1[] topoStatuses = new NV_MOSAIC_DISPLAY_TOPO_STATUS_V1[displayConfig.MosaicConfig.MosaicGridCount]; - NVAPI_STATUS NVStatus = NVImport.NvAPI_Mosaic_ValidateDisplayGrids(setTopoFlags, ref displayConfig.MosaicConfig.MosaicGridTopos, ref topoStatuses, displayConfig.MosaicConfig.MosaicGridCount); - //NV_MOSAIC_DISPLAY_TOPO_STATUS_V1[] topoStatuses = new NV_MOSAIC_DISPLAY_TOPO_STATUS_V1[mosaicGridCount]; - //NVStatus = NVImport.NvAPI_Mosaic_ValidateDisplayGrids(setTopoFlags, ref mosaicGridTopos, ref topoStatuses, mosaicGridCount); - if (NVStatus == NVAPI_STATUS.NVAPI_OK) - { - SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); - - for (int i = 0; i < topoStatuses.Length; i++) - { - // If there is an error then we need to log it! - // And make it not be used - if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.OK) - { - SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Congratulations! No error flags for GridTopology #{i}"); - topoValid = true; - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.DISPLAY_ON_INVALID_GPU) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: Display is on an invalid GPU"); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.DISPLAY_ON_WRONG_CONNECTOR) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: Display is on the wrong connection. It was on a different connection when the display profile was saved."); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.ECC_ENABLED) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: ECC has been enabled, and Mosaic/Surround doesn't work with ECC"); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.GPU_TOPOLOGY_NOT_SUPPORTED) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: This GPU topology is not supported."); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.MISMATCHED_OUTPUT_TYPE) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: The output type has changed for the display. The display was connected through another output type when the display profile was saved."); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NOT_SUPPORTED) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: This Grid Topology is not supported on this video card."); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_COMMON_TIMINGS) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: Couldn't find common timings that suit all the displays in this Grid Topology."); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_DISPLAY_CONNECTED) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: No display connected."); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_EDID_AVAILABLE) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: Your display didn't provide any information when we attempted to query it. Your display either doesn't support support EDID querying or has it a fault. "); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_GPU_TOPOLOGY) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: There is no GPU topology provided."); - } - else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_SLI_BRIDGE) - { - SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: There is no SLI bridge, and there was one when the display profile was created."); - } - - // And now we also check to see if there are any warnings we also need to log - if (topoStatuses[i].WarningFlags == NV_MOSAIC_DISPLAYTOPO_WARNING_FLAGS.NONE) - { - SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Congratulations! No warning flags for GridTopology #{i}"); - } - else if (topoStatuses[i].WarningFlags == NV_MOSAIC_DISPLAYTOPO_WARNING_FLAGS.DISPLAY_POSITION) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Warning for the GridTopology #{i}: The display position has changed, and this may affect your display view."); - } - else if (topoStatuses[i].WarningFlags == NV_MOSAIC_DISPLAYTOPO_WARNING_FLAGS.DRIVER_RELOAD_REQUIRED) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Warning for the GridTopology #{i}: Your computer needs to be restarted before your NVIDIA device driver can use this Grid Topology."); - } - } - - } - else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Mosaic is not supported with the existing hardware. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_NO_ACTIVE_SLI_TOPOLOGY) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: No matching GPU topologies could be found. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_TOPO_NOT_POSSIBLE) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The topology passed in is not currently possible. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The version of the structure passed in is not compatible with this entrypoint. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_MODE_CHANGE_FAILED) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: There was an error changing the display mode. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) - { - SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - else - { - SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); - } - - - // Cancel the screen change if there was an error with anything above this. - if (topoValid) - { - // If there was an issue then we need to return false - // to indicate that the display profile can't be applied - SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: The display settings are valid."); - return true; - } - else - { - // If there was an issue then we need to return false - // to indicate that the display profile can't be applied - SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: There was an error when validating the requested grid topology that prevents us from using the display settings provided. THe display setttings are NOT valid."); - return false; - }*/ - //} - //else - //{ + if (displayConfig.SlsConfig.IsSlsEnabled) + { + // At the moment we just assume the config is true so we try to use it + return true; + } + else + { // Its not a Mosaic topology, so we just let it pass, as it's windows settings that matter. - //return true; - //} + return true; + } } public bool IsPossibleConfig(AMD_DISPLAY_CONFIG displayConfig) @@ -1280,207 +1424,384 @@ namespace DisplayMagicianShared.AMD // We want to check the AMD profile can be used now SharedLogger.logger.Trace($"AMDLibrary/IsPossibleConfig: Testing whether the AMD display configuration is possible to be used now"); - // check what the currently available displays are (include the ones not active) + // Check the currently available displays (include the ones not active) List currentAllIds = GetAllConnectedDisplayIdentifiers(); - // CHeck that we have all the displayConfig DisplayIdentifiers we need available now + // Check that we have all the displayConfig DisplayIdentifiers we need available now if (displayConfig.DisplayIdentifiers.All(value => currentAllIds.Contains(value))) - //if (currentAllIds.Intersect(displayConfig.DisplayIdentifiers).Count() == displayConfig.DisplayIdentifiers.Count) { SharedLogger.logger.Trace($"AMDLibrary/IsPossibleConfig: Success! The AMD display configuration is possible to be used now"); return true; } else { - SharedLogger.logger.Trace($"AMDLibrary/IsPossibleConfig: Uh oh! The AMD display configuration is possible cannot be used now"); + SharedLogger.logger.Trace($"AMDLibrary/IsPossibleConfig: Uh oh! The AMDdisplay configuration is possible cannot be used now"); return false; } - } public List GetCurrentDisplayIdentifiers() { SharedLogger.logger.Trace($"AMDLibrary/GetCurrentDisplayIdentifiers: Getting the current display identifiers for the displays in use now"); - return GetSomeDisplayIdentifiers(QDC.QDC_ONLY_ACTIVE_PATHS); + bool allDisplays = false; + return GetSomeDisplayIdentifiers(allDisplays); } public List GetAllConnectedDisplayIdentifiers() { SharedLogger.logger.Trace($"AMDLibrary/GetAllConnectedDisplayIdentifiers: Getting all the display identifiers that can possibly be used"); - return GetSomeDisplayIdentifiers(QDC.QDC_ALL_PATHS); + bool allDisplays = true; + return GetSomeDisplayIdentifiers(allDisplays); } - private List GetSomeDisplayIdentifiers(QDC selector = QDC.QDC_ONLY_ACTIVE_PATHS) + private List GetSomeDisplayIdentifiers(bool allDisplays = false) { - SharedLogger.logger.Debug($"AMDLibrary/GetCurrentDisplayIdentifiers: Generating the unique Display Identifiers for the currently active configuration"); + SharedLogger.logger.Debug($"AMDLibrary/GetSomeDisplayIdentifiers: Generating unique Display Identifiers"); List displayIdentifiers = new List(); - SharedLogger.logger.Trace($"AMDLibrary/GetCurrentDisplayIdentifiers: Testing whether the display configuration is valid (allowing tweaks)."); - // Get the size of the largest Active Paths and Modes arrays - int pathCount = 0; - int modeCount = 0; - WIN32STATUS err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount); - if (err != WIN32STATUS.ERROR_SUCCESS) + if (_initialised) { - SharedLogger.logger.Error($"AMDLibrary/PrintActiveConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes"); - throw new AMDLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes"); - } - - SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: Getting the current Display Config path and mode arrays"); - var paths = new DISPLAYCONFIG_PATH_INFO[pathCount]; - var modes = new DISPLAYCONFIG_MODE_INFO[modeCount]; - err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero); - if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER) - { - SharedLogger.logger.Warn($"AMDLibrary/GetSomeDisplayIdentifiers: The displays were modified between GetDisplayConfigBufferSizes and QueryDisplayConfig so we need to get the buffer sizes again."); - SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: Getting the size of the largest Active Paths and Modes arrays"); - // Screen changed in between GetDisplayConfigBufferSizes and QueryDisplayConfig, so we need to get buffer sizes again - // as per https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-querydisplayconfig - err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount); - if (err != WIN32STATUS.ERROR_SUCCESS) + // Get the number of AMD adapters that the OS knows about + int numAdapters = 0; + ADL_STATUS ADLRet = ADLImport.ADL2_Adapter_NumberOfAdapters_Get(_adlContextHandle, out numAdapters); + if (ADLRet == ADL_STATUS.ADL_OK) { - SharedLogger.logger.Error($"AMDLibrary/GetSomeDisplayIdentifiers: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again"); - throw new AMDLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again"); - } - SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: Getting the current Display Config path and mode arrays"); - paths = new DISPLAYCONFIG_PATH_INFO[pathCount]; - modes = new DISPLAYCONFIG_MODE_INFO[modeCount]; - err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero); - if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER) - { - SharedLogger.logger.Error($"AMDLibrary/GetSomeDisplayIdentifiers: ERROR - The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong."); - throw new AMDLibraryException($"The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong."); - } - else if (err != WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Error($"AMDLibrary/GetSomeDisplayIdentifiers: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again"); - throw new AMDLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again."); - } - } - else if (err != WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Error($"AMDLibrary/GetSomeDisplayIdentifiers: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays"); - throw new AMDLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays."); - } - - foreach (var path in paths) - { - if (path.TargetInfo.TargetAvailable == false) - { - // We want to skip this one cause it's not valid - SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: Skipping path due to TargetAvailable not existing in display #{path.TargetInfo.Id}"); - continue; - } - - // get display source name - var sourceInfo = new DISPLAYCONFIG_SOURCE_DEVICE_NAME(); - sourceInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; - sourceInfo.Header.Size = (uint)Marshal.SizeOf(); - sourceInfo.Header.AdapterId = path.SourceInfo.AdapterId; - sourceInfo.Header.Id = path.SourceInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref sourceInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) - { - SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: Successfully got the source info from {path.SourceInfo.Id}."); + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: ADL2_Adapter_NumberOfAdapters_Get returned the number of AMD Adapters the OS knows about ({numAdapters})."); } else { - SharedLogger.logger.Warn($"AMDLibrary/GetSomeDisplayIdentifiers: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{path.SourceInfo.Id}"); + SharedLogger.logger.Error($"AMDLibrary/GetSomeDisplayIdentifiers: ERROR - ADL2_Adapter_NumberOfAdapters_Get returned ADL_STATUS {ADLRet} when trying to get number of AMD adapters in the computer."); + throw new AMDLibraryException($"GetSomeDisplayIdentifiers returned ADL_STATUS {ADLRet} when trying to get number of AMD adapters in the computer"); } - // get display target name - var targetInfo = new DISPLAYCONFIG_TARGET_DEVICE_NAME(); - targetInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; - targetInfo.Header.Size = (uint)Marshal.SizeOf(); - targetInfo.Header.AdapterId = path.TargetInfo.AdapterId; - targetInfo.Header.Id = path.TargetInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref targetInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) + // Figure out primary adapter + int primaryAdapterIndex = 0; + ADLRet = ADLImport.ADL2_Adapter_Primary_Get(_adlContextHandle, out primaryAdapterIndex); + if (ADLRet == ADL_STATUS.ADL_OK) { - SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: Successfully got the target info from {path.TargetInfo.Id}."); + SharedLogger.logger.Trace($"AMDLibrary/ADL2_Adapter_Primary_Get: The primary adapter has index {primaryAdapterIndex}."); } else { - SharedLogger.logger.Warn($"AMDLibrary/GetSomeDisplayIdentifiers: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{path.TargetInfo.Id}"); + SharedLogger.logger.Error($"AMDLibrary/GetSomeDisplayIdentifiers: ERROR - ADL2_Adapter_Primary_Get returned ADL_STATUS {ADLRet} when trying to get the primary adapter info from all the AMD adapters in the computer."); + throw new AMDLibraryException($"GetSomeDisplayIdentifiers returned ADL_STATUS {ADLRet} when trying to get the adapter info from all the AMD adapters in the computer"); } - // get display adapter name - var adapterInfo = new DISPLAYCONFIG_ADAPTER_NAME(); - adapterInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME; - adapterInfo.Header.Size = (uint)Marshal.SizeOf(); - adapterInfo.Header.AdapterId = path.TargetInfo.AdapterId; - adapterInfo.Header.Id = path.TargetInfo.Id; - err = CCDImport.DisplayConfigGetDeviceInfo(ref adapterInfo); - if (err == WIN32STATUS.ERROR_SUCCESS) + // Now go through each adapter and get the information we need from it + for (int adapterIndex = 0; adapterIndex < numAdapters; adapterIndex++) { - SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: Successfully got the display name info from {path.TargetInfo.Id}."); - } - else - { - SharedLogger.logger.Warn($"AMDLibrary/GetSomeDisplayIdentifiers: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{path.TargetInfo.Id}"); - } + // Skip this adapter if it isn't active + int adapterActiveStatus = ADLImport.ADL_FALSE; + ADLRet = ADLImport.ADL2_Adapter_Active_Get(_adlContextHandle, adapterIndex, out adapterActiveStatus); + if (ADLRet == ADL_STATUS.ADL_OK) + { + if (adapterActiveStatus == ADLImport.ADL_TRUE) + { + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: ADL2_Adapter_Active_Get returned ADL_TRUE - AMD Adapter #{adapterIndex} is active! We can continue."); + } + else + { + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: ADL2_Adapter_Active_Get returned ADL_FALSE - AMD Adapter #{adapterIndex} is NOT active, so skipping."); + continue; + } + } + else + { + SharedLogger.logger.Warn($"AMDLibrary/GetSomeDisplayIdentifiers: WARNING - ADL2_Adapter_Active_Get returned ADL_STATUS {ADLRet} when trying to see if AMD Adapter #{adapterIndex} is active. Trying to skip this adapter so something at least works."); + continue; + } - // Create an array of all the important display info we need to record - List displayInfo = new List(); - displayInfo.Add("WINAPI"); - try - { - displayInfo.Add(adapterInfo.AdapterDevicePath.ToString()); - } - catch (Exception ex) - { - SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display Adapter Device Path from video card. Substituting with a # instead"); - displayInfo.Add("#"); - } - try - { - displayInfo.Add(targetInfo.OutputTechnology.ToString()); - } - catch (Exception ex) - { - SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display Connector Instance from video card. Substituting with a # instead"); - displayInfo.Add("#"); - } - try - { - displayInfo.Add(targetInfo.EdidManufactureId.ToString()); - } - catch (Exception ex) - { - SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display EDID Manufacturer Code from video card. Substituting with a # instead"); - displayInfo.Add("#"); - } - try - { - displayInfo.Add(targetInfo.EdidProductCodeId.ToString()); - } - catch (Exception ex) - { - SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display EDID Product Code from video card. Substituting with a # instead"); - displayInfo.Add("#"); - } - try - { - displayInfo.Add(targetInfo.MonitorFriendlyDeviceName.ToString()); - } - catch (Exception ex) - { - SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display Target Friendly name from video card. Substituting with a # instead"); - displayInfo.Add("#"); - } + // Get the Adapter info for this adapter and put it in the AdapterBuffer + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: Running ADL2_Adapter_AdapterInfoX4_Get to get the information about AMD Adapter #{adapterIndex}."); + int numAdaptersInfo = 0; + IntPtr adapterInfoBuffer = IntPtr.Zero; + ADLRet = ADLImport.ADL2_Adapter_AdapterInfoX4_Get(_adlContextHandle, adapterIndex, out numAdaptersInfo, out adapterInfoBuffer); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: ADL2_Adapter_AdapterInfoX4_Get returned information about AMD Adapter #{adapterIndex}."); + } + else + { + SharedLogger.logger.Error($"AMDLibrary/GetSomeDisplayIdentifiers: ERROR - ADL2_Adapter_AdapterInfoX4_Get returned ADL_STATUS {ADLRet} when trying to get the adapter info from AMD Adapter #{adapterIndex}. Trying to skip this adapter so something at least works."); + continue; + } - // Create a display identifier out of it - string displayIdentifier = String.Join("|", displayInfo); - // Add it to the list of display identifiers so we can return it - // but only add it if it doesn't already exist. Otherwise we get duplicates :/ - if (!displayIdentifiers.Contains(displayIdentifier)) - { - displayIdentifiers.Add(displayIdentifier); - SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}"); - } + ADL_ADAPTER_INFOX2[] adapterArray = new ADL_ADAPTER_INFOX2[numAdaptersInfo]; + if (numAdaptersInfo > 0) + { + IntPtr currentDisplayTargetBuffer = adapterInfoBuffer; + for (int i = 0; i < numAdaptersInfo; i++) + { + // build a structure in the array slot + adapterArray[i] = new ADL_ADAPTER_INFOX2(); + // fill the array slot structure with the data from the buffer + adapterArray[i] = (ADL_ADAPTER_INFOX2)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // destroy the bit of memory we no longer need + //Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_ADAPTER_INFOX2)); + // advance the buffer forwards to the next object + currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(adapterArray[i])); + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(adapterInfoBuffer); + } + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: Converted ADL2_Adapter_AdapterInfoX4_Get memory buffer into a {adapterArray.Length} long array about AMD Adapter #{adapterIndex}."); + + AMD_ADAPTER_CONFIG savedAdapterConfig = new AMD_ADAPTER_CONFIG(); + ADL_ADAPTER_INFOX2 oneAdapter = adapterArray[0]; + if (oneAdapter.Exist != 1) + { + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} doesn't exist at present so skipping detection for this adapter."); + continue; + } + + // Only skip non-present displays if we want all displays information + if (allDisplays && oneAdapter.Present != 1) + { + SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: AMD Adapter #{oneAdapter.AdapterIndex.ToString()} isn't enabled at present so skipping detection for this adapter."); + continue; + } + + // Now we still try to get the information we need for the Display Identifiers + // Go grab the DisplayMaps and DisplayTargets as that is useful infor for creating screens + int numDisplayTargets = 0; + int numDisplayMaps = 0; + IntPtr displayTargetBuffer = IntPtr.Zero; + IntPtr displayMapBuffer = IntPtr.Zero; + ADLRet = ADLImport.ADL2_Display_DisplayMapConfig_Get(_adlContextHandle, adapterIndex, out numDisplayMaps, out displayMapBuffer, out numDisplayTargets, out displayTargetBuffer, ADLImport.ADL_DISPLAY_DISPLAYMAP_OPTION_GPUINFO); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_DisplayMapConfig_Get returned information about all displaytargets connected to AMD adapter {adapterIndex}."); + } + else + { + SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Display_DisplayMapConfig_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from AMD adapter {adapterIndex} in the computer."); + continue; + } + + ADL_DISPLAY_TARGET[] displayTargetArray = { }; + if (numDisplayTargets > 0) + { + IntPtr currentDisplayTargetBuffer = displayTargetBuffer; + //displayTargetArray = new ADL_DISPLAY_TARGET[numDisplayTargets]; + displayTargetArray = new ADL_DISPLAY_TARGET[numDisplayTargets]; + for (int i = 0; i < numDisplayTargets; i++) + { + // build a structure in the array slot + displayTargetArray[i] = new ADL_DISPLAY_TARGET(); + //displayTargetArray[i] = new ADL_DISPLAY_TARGET(); + // fill the array slot structure with the data from the buffer + displayTargetArray[i] = (ADL_DISPLAY_TARGET)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); + //displayTargetArray[i] = (ADL_DISPLAY_TARGET)Marshal.PtrToStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); + // destroy the bit of memory we no longer need + Marshal.DestroyStructure(currentDisplayTargetBuffer, typeof(ADL_DISPLAY_TARGET)); + // advance the buffer forwards to the next object + currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(displayTargetArray[i])); + //currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(displayTargetArray[i])); + + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(displayTargetBuffer); + } + + int forceDetect = 0; + int numDisplays; + IntPtr displayInfoBuffer; + ADLRet = ADLImport.ADL2_Display_DisplayInfo_Get(_adlContextHandle, adapterIndex, out numDisplays, out displayInfoBuffer, forceDetect); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_DisplayInfo_Get returned information about all displaytargets connected to AMD adapter {adapterIndex}."); + } + else if (ADLRet == ADL_STATUS.ADL_ERR_NULL_POINTER || ADLRet == ADL_STATUS.ADL_ERR_NOT_SUPPORTED) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_DisplayInfo_Get returned ADL_ERR_NULL_POINTER so skipping getting display info from this AMD adapter {adapterIndex}."); + continue; + } + else + { + SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Display_DisplayInfo_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from AMD adapter {adapterIndex} in the computer."); + } + + ADL_DISPLAY_INFO[] displayInfoArray = { }; + if (numDisplays > 0) + { + IntPtr currentDisplayInfoBuffer = displayInfoBuffer; + displayInfoArray = new ADL_DISPLAY_INFO[numDisplays]; + for (int i = 0; i < numDisplays; i++) + { + // build a structure in the array slot + displayInfoArray[i] = new ADL_DISPLAY_INFO(); + // fill the array slot structure with the data from the buffer + displayInfoArray[i] = (ADL_DISPLAY_INFO)Marshal.PtrToStructure(currentDisplayInfoBuffer, typeof(ADL_DISPLAY_INFO)); + // destroy the bit of memory we no longer need + Marshal.DestroyStructure(currentDisplayInfoBuffer, typeof(ADL_DISPLAY_INFO)); + // advance the buffer forwards to the next object + currentDisplayInfoBuffer = (IntPtr)((long)currentDisplayInfoBuffer + Marshal.SizeOf(displayInfoArray[i])); + //currentDisplayTargetBuffer = (IntPtr)((long)currentDisplayTargetBuffer + Marshal.SizeOf(displayTargetArray[i])); + + } + // Free the memory used by the buffer + Marshal.FreeCoTaskMem(displayInfoBuffer); + } + + + // Now we need to get all the displays connected to this adapter so that we can get their HDR state + foreach (var displayInfoItem in displayInfoArray) + { + + // Ignore the display if it isn't connected (note: we still need to see if it's actively mapped to windows!) + if (!displayInfoItem.DisplayConnectedSet) + { + continue; + } + + // If the display is not mapped in windows then we only want to skip this display if all alldisplays is false + if (!displayInfoItem.DisplayMappedSet && !allDisplays) + { + continue; + } + + // Create an array of all the important display info we need to create the display identifier + List displayInfo = new List(); + displayInfo.Add("AMD"); + try + { + displayInfo.Add(oneAdapter.DeviceNumber.ToString()); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting AMD Adapter Device Number from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + try + { + displayInfo.Add(oneAdapter.AdapterName); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting AMD Adapter Name from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + try + { + displayInfo.Add(displayInfoItem.DisplayConnector.ToString("G")); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting Display Connector from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + + // Get some more Display Info (if we can!) + ADL_DDC_INFO2 ddcInfo = new ADL_DDC_INFO2(); + ADLRet = ADLImport.ADL2_Display_DDCInfo2_Get(_adlContextHandle, adapterIndex, displayInfoItem.DisplayID.DisplayLogicalIndex, out ddcInfo); + if (ADLRet == ADL_STATUS.ADL_OK) + { + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_DDCInfo2_Get returned information about DDC Information for display {displayInfoItem.DisplayID.DisplayLogicalIndex} connected to AMD adapter {adapterIndex}."); + if (ddcInfo.SupportsDDC == 1) + { + // The display supports DDC and returned some data! + SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_DDCInfo2_Get returned information about DDC Information for display {displayInfoItem.DisplayID.DisplayLogicalIndex} connected to AMD adapter {adapterIndex}."); + + try + { + displayInfo.Add(ddcInfo.ManufacturerID.ToString()); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting AMD Display EDID Manufacturer Code from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + try + { + displayInfo.Add(ddcInfo.ProductID.ToString()); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting AMD Display EDID Product Code from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + try + { + displayInfo.Add(ddcInfo.DisplayName.ToString()); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting AMD Display Name from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + } + else + { + // The display does NOT support DDC and nothing was returned! We need to find the information some other way! + + try + { + displayInfo.Add(displayInfoItem.DisplayManufacturerName.ToString()); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting AMD Display Manufacturer Name 2 from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + try + { + displayInfo.Add(displayInfoItem.DisplayName.ToString()); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting AMD Display Name 2 from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + } + } + else + { + SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - ADL2_Display_DDCInfo2_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from AMD adapter {adapterIndex} in the computer."); + + // ADL2_Display_DDCInfo2_Get had a problem and nothing was returned! We need to find the information some other way! + + try + { + displayInfo.Add(displayInfoItem.DisplayManufacturerName.ToString()); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting AMD Display Manufacturer Name 2 from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + try + { + displayInfo.Add(displayInfoItem.DisplayName.ToString()); + } + catch (Exception ex) + { + SharedLogger.logger.Warn(ex, $"AMDLibrary/GetSomeDisplayIdentifiers: Exception getting AMD Display Name 2 from video card. Substituting with a # instead"); + displayInfo.Add("#"); + } + } + + + + // Create a display identifier out of it + string displayIdentifier = String.Join("|", displayInfo); + // Add it to the list of display identifiers so we can return it + // but only add it if it doesn't already exist. Otherwise we get duplicates :/ + if (!displayIdentifiers.Contains(displayIdentifier)) + { + displayIdentifiers.Add(displayIdentifier); + SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}"); + } + } + } } + else + { + SharedLogger.logger.Error($"AMDLibrary/GetSomeDisplayIdentifiers: ERROR - Tried to run GetSomeDisplayIdentifiers but the AMD ADL library isn't initialised!"); + throw new AMDLibraryException($"Tried to run GetSomeDisplayIdentifiers but the AMD ADL library isn't initialised!"); + } + // Sort the display identifiers displayIdentifiers.Sort(); diff --git a/DisplayMagicianShared/NVIDIA/NVAPI.cs b/DisplayMagicianShared/NVIDIA/NVAPI.cs index f023624..e1b6b3f 100644 --- a/DisplayMagicianShared/NVIDIA/NVAPI.cs +++ b/DisplayMagicianShared/NVIDIA/NVAPI.cs @@ -2062,6 +2062,7 @@ namespace DisplayMagicianShared.NVIDIA catch (DllNotFoundException) { return; } catch (EntryPointNotFoundException) { return; } catch (ArgumentNullException) { return; } + catch (NullReferenceException) { return; } if (InitializeInternal() == NVAPI_STATUS.NVAPI_OK) { diff --git a/DisplayMagicianShared/ProfileItem.cs b/DisplayMagicianShared/ProfileItem.cs index 258a6d3..657d31d 100644 --- a/DisplayMagicianShared/ProfileItem.cs +++ b/DisplayMagicianShared/ProfileItem.cs @@ -601,7 +601,15 @@ namespace DisplayMagicianShared public virtual void RefreshPossbility() { - // Check whether this profile is possible + // Check whether this profile is the same as the video mode, otherwise it's not possible + if (ProfileRepository.CurrentVideoMode != VideoMode) + { + SharedLogger.logger.Debug($"ProfileRepository/IsPossibleRefresh: The NVIDIA profile {Name} is NOT possible!"); + _isPossible = false; + return; + } + + // Otherwise actually check the possibility if (ProfileRepository.CurrentVideoMode == VIDEO_MODE.NVIDIA && NVIDIALibrary.GetLibrary().IsInstalled) { if (NVIDIALibrary.GetLibrary().IsPossibleConfig(_nvidiaDisplayConfig))