diff --git a/DisplayMagicianShared/AMD/ADL.cs b/DisplayMagicianShared/AMD/ADL.cs index bf4fae2..aed1745 100644 --- a/DisplayMagicianShared/AMD/ADL.cs +++ b/DisplayMagicianShared/AMD/ADL.cs @@ -99,6 +99,31 @@ namespace ATI.ADL /// return ADL Error Code internal delegate int ADL_Display_DeviceConfig_Get(int adapterIndex, int displayIndex, out ADLDisplayConfig displayConfig); + /// Function to retrieve current display map configurations. + /// This function retrieves the current display map configurations, including the controllers and adapters mapped to each display. + /// The ADL index handle of the desired adapter. A value of -1 returns all display configurations for the system across multiple GPUs. + /// Number of returned Display Maps + /// Array of ADLDisplayMap objects + /// Number of Display Targets + /// Array of ADLDisplayTarget objects + /// Options supplied + /// return ADL Error Code + internal delegate int ADL_Display_DisplayMapConfig_Get(int adapterIndex, out int numDisplayMap, out IntPtr displayMap, out int numDisplayTarget, out IntPtr displayTarget, int options); + + /// Function to validate a list of display configurations. + /// This function allows the user to input a potential displays map and its targets. The function can also be used to obtain a list of display targets that can be added to this given topology and a list of display targets that can be removed from this given topology. + /// The ADL index handle of the desired adapter. Cannot be set to -1 + /// Number of Display Map + /// Number of Display Map + /// Number of Display Map + /// Number of Display Map + /// Number of Display Map + /// Number of Display Map + /// Number of Display Map + /// Number of Display Map + /// return ADL Error Code + internal delegate int ADL_Display_DisplayMapConfig_PossibleAddAndRemove(int adapterIndex, int numDisplayMap, ADLDisplayMap displayMap, int numDisplayTarget, ADLDisplayTarget displayTarget, out int numPossibleAddTarget, out IntPtr possibleAddTarget, out int numPossibleRemoveTarget, out IntPtr possibleRemoveTarget); + /// Function to retrieve an SLS configuration. /// Adapter Index /// Specifies the SLS map index to be queried. @@ -155,7 +180,7 @@ namespace ATI.ADL #endregion ADLMode #region ADLDisplayTarget - /// ADLDisplayTarget Array + /// ADLDisplayTarget [StructLayout(LayoutKind.Sequential)] internal struct ADLDisplayTarget { @@ -168,6 +193,15 @@ namespace ATI.ADL /// The bit mask identifies the display status. internal int DisplayTargetValue; } + + /// ADLDisplayTargetArray Array + [StructLayout(LayoutKind.Sequential)] + internal struct ADLDisplayTargetArray + { + /// ADLDisplayTarget Array + [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)ADL.ADL_MAX_DISPLAYS)] + internal ADLDisplayTarget[] ADLDisplayTarget; + } #endregion ADLDisplayTarget #region ADLAdapterInfo @@ -291,6 +325,33 @@ namespace ATI.ADL internal long Size; } + /// ADLDisplayMap Structure + [StructLayout(LayoutKind.Sequential)] + internal struct ADLDisplayMap + { + /// The Display Mode for the current map. + internal ADLMode DisplayMode; + /// The current display map index. It is the OS desktop index. For example, if the OS index 1 is showing clone mode, the display map will be 1. + internal int DisplayMapIndex; + /// The bit mask identifies the number of bits DisplayMap is currently using. It is the sum of all the bit definitions defined in ADL_DISPLAY_DISPLAYMAP_MANNER_xxx. + internal int DisplayMapMask; + /// The bit mask identifies the display status. The detailed definition is in ADL_DISPLAY_DISPLAYMAP_MANNER_xxx. + internal int DisplayMapValue; + /// The first target array index in the Target array + internal int FirstDisplayTargetArrayIndex; + /// The number of display targets belongs to this map + internal int NumDisplayTarget; + } + + /// ADLDisplayMapArray Array + [StructLayout(LayoutKind.Sequential)] + internal struct ADLDisplayMapArray + { + /// ADLAdapterInfo Array + [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)ADL.ADL_MAX_DISPLAYS)] + internal ADLDisplayMap[] ADLDisplayMap; + } + /// ADLAdapterCaps Structure [StructLayout(LayoutKind.Sequential)] internal struct ADLAdapterCapsX2 @@ -478,6 +539,8 @@ namespace ATI.ADL internal static class ADL { #region Internal Constant + /// Selects all adapters instead of aparticular single adapter + internal const int ADL_ADAPTER_INDEX_ALL = -1; /// Define the maximum path internal const int ADL_MAX_PATH = 256; /// Define the maximum adapters @@ -626,13 +689,18 @@ namespace ATI.ADL [DllImport(Atiadlxx_FileName)] internal static extern int ADL_AdapterX2_Caps(int adapterIndex, out ADLAdapterCapsX2 adapterCapabilities); - [DllImport(Atiadlxx_FileName)] internal static extern int ADL_Display_DisplayInfo_Get(int adapterIndex, ref int numDisplays, out IntPtr displayInfoArray, int forceDetect); [DllImport(Atiadlxx_FileName)] internal static extern int ADL_Display_DeviceConfig_Get(int adapterIndex, int displayIndex, out ADLDisplayConfig displayConfig); + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL_Display_DisplayMapConfig_Get(int adapterIndex, out int numDisplayMap, out IntPtr displayMap, out int numDisplayTarget, out IntPtr displayTarget, int options); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL_Display_DisplayMapConfig_PossibleAddAndRemove(int adapterIndex, int numDisplayMap, ADLDisplayMap displayMap, int numDisplayTarget, ADLDisplayTarget displayTarget, out int numPossibleAddTarget, out IntPtr possibleAddTarget, out int numPossibleRemoveTarget, out IntPtr possibleRemoveTarget); + [DllImport(Atiadlxx_FileName)] internal static extern int ADL_Display_SLSMapConfig_Get(int adapterIndex, int SLSMapIndex, ref ADLSLSMap SLSMap, ref int NumSLSTarget, out IntPtr SLSTargetArray, ref int lpNumNativeMode, out IntPtr NativeMode, ref int NumBezelMode, out IntPtr BezelMode, ref int NumTransientMode, out IntPtr TransientMode, ref int NumSLSOffset, out IntPtr SLSOffset, int iOption); @@ -947,6 +1015,52 @@ namespace ATI.ADL private static bool ADL_Display_DeviceConfig_Get_Check = false; #endregion ADL_Display_DeviceConfig_Get + #region ADL_Display_DisplayMapConfig_Get + /// ADL_Display_DisplayMapConfig_Get Delegates + internal static ADL_Display_DisplayMapConfig_Get ADL_Display_DisplayMapConfig_Get + { + get + { + if (!ADL_Display_DisplayMapConfig_Get_Check && null == ADL_Display_DisplayMapConfig_Get_) + { + ADL_Display_DisplayMapConfig_Get_Check = true; + if (ADLCheckLibrary.IsFunctionValid("ADL_Display_DisplayMapConfig_Get")) + { + ADL_Display_DisplayMapConfig_Get_ = ADLImport.ADL_Display_DisplayMapConfig_Get; + } + } + return ADL_Display_DisplayMapConfig_Get_; + } + } + /// Private Delegate + private static ADL_Display_DisplayMapConfig_Get ADL_Display_DisplayMapConfig_Get_ = null; + /// check flag to indicate the delegate has been checked + private static bool ADL_Display_DisplayMapConfig_Get_Check = false; + #endregion ADL_Display_DisplayMapConfig_Get + + #region ADL_Display_DisplayMapConfig_PossibleAddAndRemove + /// ADL_Display_DisplayMapConfig_PossibleAddAndRemove Delegates + internal static ADL_Display_DisplayMapConfig_PossibleAddAndRemove ADL_Display_DisplayMapConfig_PossibleAddAndRemove + { + get + { + if (!ADL_Display_DisplayMapConfig_PossibleAddAndRemove_Check && null == ADL_Display_DisplayMapConfig_PossibleAddAndRemove_) + { + ADL_Display_DisplayMapConfig_PossibleAddAndRemove_Check = true; + if (ADLCheckLibrary.IsFunctionValid("ADL_Display_DisplayMapConfig_PossibleAddAndRemove")) + { + ADL_Display_DisplayMapConfig_PossibleAddAndRemove_ = ADLImport.ADL_Display_DisplayMapConfig_PossibleAddAndRemove; + } + } + return ADL_Display_DisplayMapConfig_PossibleAddAndRemove_; + } + } + /// Private Delegate + private static ADL_Display_DisplayMapConfig_PossibleAddAndRemove ADL_Display_DisplayMapConfig_PossibleAddAndRemove_ = null; + /// check flag to indicate the delegate has been checked + private static bool ADL_Display_DisplayMapConfig_PossibleAddAndRemove_Check = false; + #endregion ADL_Display_DisplayMapConfig_PossibleAddAndRemove + #region ADL_Display_DisplayInfo_Get /// ADL_Display_DisplayInfo_Get Delegates internal static ADL_Display_DisplayInfo_Get ADL_Display_DisplayInfo_Get @@ -970,6 +1084,7 @@ namespace ATI.ADL private static bool ADL_Display_DisplayInfo_Get_Check = false; #endregion ADL_Display_DisplayInfo_Get + #region ADL_Display_SLSMapConfig_Get /// ADL_Display_SLSMapConfig_Get Delegates internal static ADL_Display_SLSMapConfig_Get ADL_Display_SLSMapConfig_Get diff --git a/DisplayMagicianShared/AMD/ADLWrapper.cs b/DisplayMagicianShared/AMD/ADLWrapper.cs index 22d89d1..ac052ce 100644 --- a/DisplayMagicianShared/AMD/ADLWrapper.cs +++ b/DisplayMagicianShared/AMD/ADLWrapper.cs @@ -112,6 +112,86 @@ namespace DisplayMagicianShared.AMD List displayIdentifiers = new List(); + // Keep a list of things we want to track + List allDisplayMaps = new List(); + List allDisplayTargets = new List(); + + if (ADL.ADL_Display_DisplayMapConfig_Get != null) + { + IntPtr DisplayMapBuffer = IntPtr.Zero; + IntPtr DisplayTargetBuffer = IntPtr.Zero; + int numDisplayMaps = 0; + int numDisplayTargets = 0; + + // Get the DisplayMap info for all adapters on the machine in one go + ADLRet = ADL.ADL_Display_DisplayMapConfig_Get(-1, out numDisplayMaps, out DisplayMapBuffer, out numDisplayTargets, out DisplayTargetBuffer, 0); + if (ADLRet == ADL.ADL_SUCCESS) + { + SharedLogger.logger.Trace($"ADLWrapper/GenerateProfileDisplayIdentifiers: Number Of DisplayMaps: {numDisplayMaps.ToString()} "); + + // Marshal the Display Maps + ADLDisplayMap oneDisplayMap = new ADLDisplayMap(); + + for (int displayMapNum = 0; displayMapNum < numDisplayMaps; displayMapNum++) + { + // NOTE: the ToInt64 work on 64 bit, need to change to ToInt32 for 32 bit OS + oneDisplayMap = (ADLDisplayMap)Marshal.PtrToStructure(new IntPtr(DisplayMapBuffer.ToInt64() + (displayMapNum * Marshal.SizeOf(oneDisplayMap))), oneDisplayMap.GetType()); + allDisplayMaps.Add(oneDisplayMap); + } + + //Marshall the DisplayTargets + ADLDisplayTarget oneDisplayTarget = new ADLDisplayTarget(); + + for (int displayTargetNum = 0; displayTargetNum < numDisplayTargets; displayTargetNum++) + { + // NOTE: the ToInt64 work on 64 bit, need to change to ToInt32 for 32 bit OS + oneDisplayTarget = (ADLDisplayTarget)Marshal.PtrToStructure(new IntPtr(DisplayMapBuffer.ToInt64() + (displayTargetNum * Marshal.SizeOf(oneDisplayTarget))), oneDisplayTarget.GetType()); + allDisplayTargets.Add(oneDisplayTarget); + } + + } + } + + if (ADL.ADL_Display_DisplayMapConfig_PossibleAddAndRemove != null) + { + int numDisplayMap = 1; + int numDisplayTarget = 1; + + IntPtr PossibleAddTargetBuffer = IntPtr.Zero; + IntPtr PossibleRemoveTargetBuffer = IntPtr.Zero; + int numPossibleAddTargets = 0; + int numPossibleRemoveTargets = 0; + + List allPossibleAddDisplayTargets = new List(); + List allPossibleRemoveDisplayTargets = new List(); + + // Force the display detection and get the Display Info. Use 0 as last parameter to NOT force detection + ADLRet = ADL.ADL_Display_DisplayMapConfig_PossibleAddAndRemove(0, numDisplayMap, allDisplayMaps[0], numDisplayTarget, allDisplayTargets[0], out numPossibleAddTargets, out PossibleAddTargetBuffer, out numPossibleRemoveTargets, out PossibleRemoveTargetBuffer); + if (ADLRet == ADL.ADL_SUCCESS) + { + // Marshal the Possible Add Targets + ADLDisplayTarget oneDisplayTarget = new ADLDisplayTarget(); + + for (int displayTargetNum = 0; displayTargetNum < numPossibleAddTargets; displayTargetNum++) + { + // NOTE: the ToInt64 work on 64 bit, need to change to ToInt32 for 32 bit OS + oneDisplayTarget = (ADLDisplayTarget)Marshal.PtrToStructure(new IntPtr(PossibleAddTargetBuffer.ToInt64() + (displayTargetNum * Marshal.SizeOf(oneDisplayTarget))), oneDisplayTarget.GetType()); + allPossibleAddDisplayTargets.Add(oneDisplayTarget); + } + + // Marshal the Possible Remove Targets + // oneDisplayTarget = new ADLDisplayTarget(); + + for (int displayTargetNum = 0; displayTargetNum < numPossibleRemoveTargets; displayTargetNum++) + { + // NOTE: the ToInt64 work on 64 bit, need to change to ToInt32 for 32 bit OS + oneDisplayTarget = (ADLDisplayTarget)Marshal.PtrToStructure(new IntPtr(PossibleRemoveTargetBuffer.ToInt64() + (displayTargetNum * Marshal.SizeOf(oneDisplayTarget))), oneDisplayTarget.GetType()); + allPossibleAddDisplayTargets.Add(oneDisplayTarget); + } + } + } + + if (null != ADL.ADL_Adapter_NumberOfAdapters_Get) { ADL.ADL_Adapter_NumberOfAdapters_Get(ref NumberOfAdapters); @@ -222,7 +302,7 @@ namespace DisplayMagicianShared.AMD continue; } - // Skip connected but non-mapped displays (not mapped in windows) + // Skip connected but non-mapped displays (not mapped in windows) - wae want all displays currently visible in the OS if ((DisplayInfoData[j].DisplayInfoValue & 2) != 2) { SharedLogger.logger.Trace($"ADLWrapper/GenerateProfileDisplayIdentifiers: AMD Adapter #{i} ({OSAdapterInfoData.ADLAdapterInfo[i].AdapterName}) AdapterID display ID#{j} is not connected"); @@ -369,6 +449,7 @@ namespace DisplayMagicianShared.AMD List displayIdentifiers = new List(); + if (null != ADL.ADL_Adapter_NumberOfAdapters_Get) { ADL.ADL_Adapter_NumberOfAdapters_Get(ref NumberOfAdapters); @@ -472,7 +553,7 @@ namespace DisplayMagicianShared.AMD for (j = 0; j < NumberOfDisplays; j++) { - // Skip non connected displays + // Skip non connected displays - we want only connected displays that could potentially be used now (thats both mapped and non-mapped displays) if ((DisplayInfoData[j].DisplayInfoValue & 1) != 1) { SharedLogger.logger.Trace($"ADLWrapper/GenerateProfileDisplayIdentifiers: AMD Adapter #{i} ({OSAdapterInfoData.ADLAdapterInfo[i].AdapterName}) AdapterID display ID#{j} is not connected"); @@ -537,8 +618,6 @@ namespace DisplayMagicianShared.AMD { ADL.ADLConnectionType connector = (ADL.ADLConnectionType)DisplayInfoData[j].DisplayOutputType; displayInfoIdentifierSection.Add(connector.ToString()); - - ADL.ADLConnectionType connector = (ADL.ADLConnectionType)DisplayInfoData[j].DisplayType; } catch (Exception ex) {