DisplayMagician/DisplayMagicianShared/AMD/AMDLibrary.cs
Terry MacDonald cbdc810606 Updated AMDLibrary from AMDInfo
Made some improvements to SetActiveConfig from AMDInfo testing, so ported them back into DisplayMagician.
2021-09-20 18:41:25 +12:00

1871 lines
117 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
using DisplayMagicianShared;
using System.ComponentModel;
using DisplayMagicianShared.Windows;
namespace DisplayMagicianShared.AMD
{
[StructLayout(LayoutKind.Sequential)]
public struct AMD_ADAPTER_CONFIG : IEquatable<AMD_ADAPTER_CONFIG>
{
public int AdapterDeviceNumber;
public int AdapterBusNumber;
public int AdapterIndex;
public bool IsPrimaryAdapter;
public string DisplayName;
public int OSDisplayIndex;
public override bool Equals(object obj) => obj is AMD_ADAPTER_CONFIG other && this.Equals(other);
public bool Equals(AMD_ADAPTER_CONFIG other)
=> AdapterIndex == other.AdapterIndex &&
AdapterBusNumber == other.AdapterBusNumber &&
AdapterDeviceNumber == other.AdapterDeviceNumber &&
IsPrimaryAdapter == other.IsPrimaryAdapter &&
DisplayName == other.DisplayName &&
OSDisplayIndex == other.OSDisplayIndex;
public override int GetHashCode()
{
return (AdapterIndex, AdapterBusNumber, AdapterDeviceNumber, IsPrimaryAdapter, DisplayName, OSDisplayIndex).GetHashCode();
}
public static bool operator ==(AMD_ADAPTER_CONFIG lhs, AMD_ADAPTER_CONFIG rhs) => lhs.Equals(rhs);
public static bool operator !=(AMD_ADAPTER_CONFIG lhs, AMD_ADAPTER_CONFIG rhs) => !(lhs == rhs);
}
[StructLayout(LayoutKind.Sequential)]
public struct AMD_SLSMAP_CONFIG : IEquatable<AMD_SLSMAP_CONFIG>
{
public ADL_SLS_MAP SLSMap;
public List<ADL_SLS_TARGET> SLSTargets;
public List<ADL_SLS_MODE> NativeModes;
public List<ADL_SLS_OFFSET> NativeModeOffsets;
public List<ADL_BEZEL_TRANSIENT_MODE> BezelModes;
public List<ADL_BEZEL_TRANSIENT_MODE> TransientModes;
public List<ADL_SLS_OFFSET> SLSOffsets;
public int BezelModePercent;
public override bool Equals(object obj) => obj is AMD_SLS_CONFIG other && this.Equals(other);
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) &&
BezelModePercent == other.BezelModePercent;
public override int GetHashCode()
{
return (SLSMap, SLSTargets, NativeModes, NativeModeOffsets, BezelModes, TransientModes, SLSOffsets, BezelModePercent).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<AMD_SLS_CONFIG>
{
public bool IsSlsEnabled;
public List<AMD_SLSMAP_CONFIG> SLSMapConfigs;
public List<ADL_MODE> 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<AMD_HDR_CONFIG>
{
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<AMD_DISPLAY_CONFIG>
{
public List<AMD_ADAPTER_CONFIG> AdapterConfigs;
public AMD_SLS_CONFIG SlsConfig;
public List<ADL_DISPLAY_MAP> DisplayMaps;
public List<ADL_DISPLAY_TARGET> DisplayTargets;
public Dictionary<int, AMD_HDR_CONFIG> HdrConfigs;
public List<string> 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);
public static bool operator !=(AMD_DISPLAY_CONFIG lhs, AMD_DISPLAY_CONFIG rhs) => !(lhs == rhs);
}
class AMDLibrary : IDisposable
{
// Static members are 'eagerly initialized', that is,
// immediately when class is loaded for the first time.
// .NET guarantees thread safety for static initialization
private static AMDLibrary _instance = new AMDLibrary();
private static WinLibrary _winLibrary = new WinLibrary();
private bool _initialised = false;
// To detect redundant calls
private bool _disposed = false;
// Instantiate a SafeHandle instance.
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
private IntPtr _adlContextHandle = IntPtr.Zero;
static AMDLibrary() { }
public AMDLibrary()
{
try
{
SharedLogger.logger.Trace($"AMDLibrary/AMDLibrary: Attempting to load the AMD ADL DLL {ADLImport.ATI_ADL_DLL}");
// Attempt to prelink all of the NVAPI functions
Marshal.PrelinkAll(typeof(ADLImport));
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;
ADLRet = ADLImport.ADL2_Main_Control_Create(ADLImport.ADL_Main_Memory_Alloc, ADLImport.ADL_TRUE, out _adlContextHandle);
if (ADLRet == ADL_STATUS.ADL_OK)
{
_initialised = true;
SharedLogger.logger.Trace($"AMDLibrary/AMDLibrary: AMD ADL2 library was initialised successfully");
}
else
{
SharedLogger.logger.Trace($"AMDLibrary/AMDLibrary: Error intialising AMD ADL2 library. ADL2_Main_Control_Create() returned error code {ADLRet}");
}
}
catch (Exception ex)
{
SharedLogger.logger.Trace(ex, $"AMDLibrary/AMDLibrary: Exception intialising AMD ADL2 library. ADL2_Main_Control_Create() caused an exception.");
}
_winLibrary = WinLibrary.GetLibrary();
}
catch (DllNotFoundException ex)
{
// If we get here then the AMD ADL DLL wasn't found. We can't continue to use it, so we log the error and exit
SharedLogger.logger.Info(ex, $"AMDLibrary/AMDLibrary: Exception trying to load the AMD ADL DLL {ADLImport.ATI_ADL_DLL}. This generally means you don't have the AMD ADL driver installed.");
}
}
~AMDLibrary()
{
SharedLogger.logger.Trace("AMDLibrary/~AMDLibrary: Destroying AMD ADL2 library interface");
// If the ADL2 library was initialised, then we need to free it up.
if (_initialised)
{
try
{
ADLImport.ADL2_Main_Control_Destroy(_adlContextHandle);
SharedLogger.logger.Trace($"AMDLibrary/AMDLibrary: AMD ADL2 library was destroyed successfully");
}
catch (Exception ex)
{
SharedLogger.logger.Trace(ex, $"AMDLibrary/AMDLibrary: Exception destroying AMD ADL2 library. ADL2_Main_Control_Destroy() caused an exception.");
}
}
}
// Public implementation of Dispose pattern callable by consumers.
public void Dispose() => Dispose(true);
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
//ADLImport.ADL_Main_Control_Destroy();
// Dispose managed state (managed objects).
_safeHandle?.Dispose();
}
_disposed = true;
}
public bool IsInstalled
{
get
{
return _initialised;
}
}
public List<string> PCIVendorIDs
{
get
{
// A list of all the matching PCI Vendor IDs are per https://www.pcilookup.com/?ven=amd&dev=&action=submit
return new List<string>() { "1002" };
}
}
public static AMDLibrary GetLibrary()
{
return _instance;
}
public AMD_DISPLAY_CONFIG CreateDefaultConfig()
{
AMD_DISPLAY_CONFIG myDefaultConfig = new AMD_DISPLAY_CONFIG();
// Fill in the minimal amount we need to avoid null references
// so that we won't break json.net when we save a default config
myDefaultConfig.AdapterConfigs = new List<AMD_ADAPTER_CONFIG>();
myDefaultConfig.SlsConfig.SLSMapConfigs = new List<AMD_SLSMAP_CONFIG>();
myDefaultConfig.SlsConfig.SLSEnabledDisplayTargets = new List<ADL_MODE>();
myDefaultConfig.DisplayTargets = new List<ADL_DISPLAY_TARGET>();
myDefaultConfig.HdrConfigs = new Dictionary<int, AMD_HDR_CONFIG>();
myDefaultConfig.DisplayIdentifiers = new List<string>();
return myDefaultConfig;
}
public AMD_DISPLAY_CONFIG GetActiveConfig()
{
SharedLogger.logger.Trace($"AMDLibrary/GetActiveConfig: Getting the currently active config");
bool allDisplays = true;
return GetAMDDisplayConfig(allDisplays);
}
private AMD_DISPLAY_CONFIG GetAMDDisplayConfig(bool allDisplays = false)
{
AMD_DISPLAY_CONFIG myDisplayConfig = new AMD_DISPLAY_CONFIG();
myDisplayConfig.AdapterConfigs = new List<AMD_ADAPTER_CONFIG>();
// 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<ADL_MODE>();
if (_initialised)
{
// 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_AdapterInfoX4_Get returned information about all AMD Adapters.");
}
else
{
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;
}
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);
}
// Now go through each adapter and get the information we need from it
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);
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;
}
// 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.");
throw new AMDLibraryException($"ADL2_Display_DisplayMapConfig_Get returned ADL_STATUS {ADLRet} when trying to get the display target info from AMD adapter {adapterIndex} in the computer");
}
ADL_DISPLAY_MAP[] displayMapArray = { };
if (numDisplayMaps > 0)
{
IntPtr currentDisplayMapBuffer = displayMapBuffer;
displayMapArray = new ADL_DISPLAY_MAP[numDisplayMaps];
for (int i = 0; i < numDisplayMaps; i++)
{
// build a structure in the array slot
displayMapArray[i] = new ADL_DISPLAY_MAP();
// fill the array slot structure with the data from the buffer
displayMapArray[i] = (ADL_DISPLAY_MAP)Marshal.PtrToStructure(currentDisplayMapBuffer, typeof(ADL_DISPLAY_MAP));
// destroy the bit of memory we no longer need
Marshal.DestroyStructure(currentDisplayMapBuffer, typeof(ADL_DISPLAY_MAP));
// advance the buffer forwards to the next object
currentDisplayMapBuffer = (IntPtr)((long)currentDisplayMapBuffer + Marshal.SizeOf(displayMapArray[i]));
}
// Free the memory used by the buffer
Marshal.FreeCoTaskMem(displayMapBuffer);
// Save the item
myDisplayConfig.DisplayMaps = displayMapArray.ToList<ADL_DISPLAY_MAP>();
}
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);
// Save the item
//savedAdapterConfig.DisplayTargets = new ADL_DISPLAY_TARGET[numDisplayTargets];
myDisplayConfig.DisplayTargets = displayTargetArray.ToList<ADL_DISPLAY_TARGET>();
}
// Loop through all the displayTargets currently in use
foreach (var displayTarget in displayTargetArray)
{
if (displayTarget.DisplayID.DisplayLogicalAdapterIndex == oneAdapter.AdapterIndex)
{
// 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;
// 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);
}
}
}
// Prep the SLSMapConfig list
myDisplayConfig.SlsConfig.SLSMapConfigs = new List<AMD_SLSMAP_CONFIG>();
// If there are more than 1 display targets then eyefinity is possible
if (numDisplayTargets > 1)
{
// 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)
{
// 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.");
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;
int numNativeMode = 0;
IntPtr nativeModeBuffer = IntPtr.Zero;
int numNativeModeOffsets = 0;
IntPtr nativeModeOffsetsBuffer = IntPtr.Zero;
int numBezelMode = 0;
IntPtr bezelModeBuffer = IntPtr.Zero;
int numTransientMode = 0;
IntPtr transientModeBuffer = IntPtr.Zero;
int numSLSOffset = 0;
IntPtr slsOffsetBuffer = IntPtr.Zero;
ADL_SLS_MAP slsMap = new ADL_SLS_MAP();
ADLRet = ADLImport.ADL2_Display_SLSMapConfigX2_Get(
_adlContextHandle,
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}.");
}
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.");
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<ADL_SLS_TARGET>();
}
// 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<ADL_SLS_MODE>();
}
// 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<ADL_SLS_OFFSET>();
}
// 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<ADL_BEZEL_TRANSIENT_MODE>();
}
// 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<ADL_BEZEL_TRANSIENT_MODE>();
}
// 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<ADL_SLS_OFFSET>();
}
// 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<int, AMD_HDR_CONFIG>();
// 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: 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);
}
}
}
// Add the AMD Display Identifiers
myDisplayConfig.DisplayIdentifiers = GetCurrentDisplayIdentifiers();
}
else
{
SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ERROR - Tried to run GetAMDDisplayConfig but the AMD ADL library isn't initialised!");
throw new AMDLibraryException($"Tried to run GetAMDDisplayConfig but the AMD ADL library isn't initialised!");
}
// Return the configuration
return myDisplayConfig;
}
public string PrintActiveConfig()
{
string stringToReturn = "";
// Get the current config
AMD_DISPLAY_CONFIG displayConfig = GetActiveConfig();
stringToReturn += $"****** AMD VIDEO CARDS *******\n";
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);
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!");
}
stringToReturn += $"\n\n";
// Now we also get the Windows CCD Library info, and add it to the above
stringToReturn += WinLibrary.GetLibrary().PrintActiveConfig();
return stringToReturn;
}
public bool SetActiveConfig(AMD_DISPLAY_CONFIG displayConfig)
{
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();
// set the display locations
if (displayConfig.SlsConfig.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)
{
// Attempt to turn on this SLS Map Config if it exists in the AMD Radeon driver config database
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 {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 {slsMapConfig.SLSMap.SLSMapIndex} to TRUE for adapter { slsMapConfig.SLSMap.AdapterIndex}.");
// If we get an error with just tturning it on, then we need to actually try to created a new Eyefinity map and then enable it
// If we reach this stage, then the user has discarded the AMD Eyefinity mode in AMD due to a bad UI design, and we need to work around that slight issue.
// (BTW that's FAR to easy to do in the AMD Radeon GUI)
// Attempt to create am SLS Map Config in the AMD Radeon driver config database
int newSlsMapIndex;
ADL_SLS_TARGET[] slsTargetArray = slsMapConfig.SLSTargets.ToArray();
ADLRet = ADLImport.ADL2_Display_SLSMapConfig_Create(_adlContextHandle, slsMapConfig.SLSMap.AdapterIndex, slsMapConfig.SLSMap, displayConfig.DisplayTargets.Count, displayConfig.DisplayTargets.ToArray(), slsMapConfig.BezelModePercent, out newSlsMapIndex, ADLImport.ADL_DISPLAY_SLSMAPCONFIG_GET_OPTION_RELATIVETO_CURRENTANGLE);
if (ADLRet == ADL_STATUS.ADL_OK)
{
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: ADL2_Display_SLSMapConfig_Create successfully created a new SLSMAP with index {newSlsMapIndex} for adapter { slsMapConfig.SLSMap.AdapterIndex}.");
}
else
{
SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - ADL2_Display_SLSMapConfig_Create returned ADL_STATUS {ADLRet} when trying to create a new SLSMAP for adapter { slsMapConfig.SLSMap.AdapterIndex}.");
continue;
}
// If we get here, then we've successfully created the new SLSMAP, so now we need to turn it on.
ADLRet = ADLImport.ADL2_Display_SLSMapConfig_SetState(_adlContextHandle, slsMapConfig.SLSMap.AdapterIndex, newSlsMapIndex, ADLImport.ADL_TRUE);
if (ADLRet == ADL_STATUS.ADL_OK)
{
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: ADL2_Display_SLSMapConfig_SetState successfully enabled the new SLSMAP we just created with index {slsMapConfig.SLSMap.SLSMapIndex} to TRUE for adapter { slsMapConfig.SLSMap.AdapterIndex}.");
}
else
{
SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - ADL2_Display_SLSMapConfig_Create returned ADL_STATUS {ADLRet} when trying to enable the new SLSMAP we just created for adapter { slsMapConfig.SLSMap.AdapterIndex}.");
continue;
}
}
}
}
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)
{
// 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)
{
// Turn off 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;
}
}
}
}
// We want to set the AMD HDR settings now
// We got through each of the attached displays and set the HDR
// 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;
}
}
}
}
else
{
SharedLogger.logger.Error($"AMDLibrary/SetActiveConfig: ERROR - Tried to run SetActiveConfig but the AMD ADL library isn't initialised!");
throw new AMDLibraryException($"Tried to run SetActiveConfig but the AMD ADL library isn't initialised!");
}
return true;
}
public bool IsActiveConfig(AMD_DISPLAY_CONFIG displayConfig)
{
// Get the current windows display configs to compare to the one we loaded
bool allDisplays = false;
AMD_DISPLAY_CONFIG currentWindowsDisplayConfig = GetAMDDisplayConfig(allDisplays);
// Check whether the display config is in use now
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)");
return true;
}
else
{
SharedLogger.logger.Trace($"AMDLibrary/IsActiveConfig: The display configuration is NOT currently in use (supplied displayConfig Equals currentWindowsDisplayConfig)");
return false;
}
}
public bool IsValidConfig(AMD_DISPLAY_CONFIG displayConfig)
{
// We want to check the AMD Eyefinity (SLS) config is valid
SharedLogger.logger.Trace($"AMDLibrary/IsValidConfig: Testing whether the display configuration is valid");
//
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;
}
}
public bool IsPossibleConfig(AMD_DISPLAY_CONFIG displayConfig)
{
// 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 the currently available displays (include the ones not active)
List<string> currentAllIds = GetAllConnectedDisplayIdentifiers();
// Check that we have all the displayConfig DisplayIdentifiers we need available now
if (displayConfig.DisplayIdentifiers.All(value => currentAllIds.Contains(value)))
{
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 AMDdisplay configuration is possible cannot be used now");
return false;
}
}
public List<string> GetCurrentDisplayIdentifiers()
{
SharedLogger.logger.Trace($"AMDLibrary/GetCurrentDisplayIdentifiers: Getting the current display identifiers for the displays in use now");
bool allDisplays = false;
return GetSomeDisplayIdentifiers(allDisplays);
}
public List<string> GetAllConnectedDisplayIdentifiers()
{
SharedLogger.logger.Trace($"AMDLibrary/GetAllConnectedDisplayIdentifiers: Getting all the display identifiers that can possibly be used");
bool allDisplays = true;
return GetSomeDisplayIdentifiers(allDisplays);
}
private List<string> GetSomeDisplayIdentifiers(bool allDisplays = false)
{
SharedLogger.logger.Debug($"AMDLibrary/GetSomeDisplayIdentifiers: Generating unique Display Identifiers");
List<string> displayIdentifiers = new List<string>();
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);
if (ADLRet == ADL_STATUS.ADL_OK)
{
SharedLogger.logger.Trace($"AMDLibrary/GetSomeDisplayIdentifiers: ADL2_Adapter_NumberOfAdapters_Get returned the number of AMD Adapters the OS knows about ({numAdapters}).");
}
else
{
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");
}
// 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/ADL2_Adapter_Primary_Get: The primary adapter has index {primaryAdapterIndex}.");
}
else
{
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");
}
// 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/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;
}
// 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;
}
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<string> displayInfo = new List<string>();
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();
return displayIdentifiers;
}
}
[global::System.Serializable]
public class AMDLibraryException : Exception
{
public AMDLibraryException() { }
public AMDLibraryException(string message) : base(message) { }
public AMDLibraryException(string message, Exception inner) : base(message, inner) { }
protected AMDLibraryException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}