[WIP] Building AMD library functions

There is a long road ahead of me, but
at least some of the structure is working
now! We can at least call the AMD ADL
library and get results returned back!
This commit is contained in:
Terry MacDonald 2021-06-14 21:42:16 +12:00
parent a8c0307ace
commit ee7c5fe1da
2 changed files with 319 additions and 106 deletions

View File

@ -5,153 +5,339 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using ATI.ADL; using ATI.ADL;
using Microsoft.Win32.SafeHandles;
using DisplayMagicianShared;
namespace DisplayMagicianShared.AMD namespace DisplayMagicianShared.AMD
{ {
class ADLWrapper public class ADLWrapper : 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 ADLWrapper _instance = new ADLWrapper();
private bool _initialised = false;
// To detect redundant calls
private bool _disposed = false;
// Instantiate a SafeHandle instance.
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
static ADLWrapper() { }
public ADLWrapper() public ADLWrapper()
{ {
int ADLRet = ADL.ADL_FAIL;
SharedLogger.logger.Trace("ADLWrapper/ADLWrapper: Intialising ADL library");
try
{
if (ADL.ADL_Main_Control_Create != null)
{
// Second parameter is 1: Get only the present adapters
ADLRet = ADL.ADL_Main_Control_Create(ADL.ADL_Main_Memory_Alloc, 1);
}
if (ADLRet == ADL.ADL_SUCCESS)
{
_initialised = true;
SharedLogger.logger.Trace("ADLWrapper/ADLWrapper: ADL library was initialised successfully");
}
else
{
SharedLogger.logger.Error("ADLWrapper/ADLWrapper: Error intialising ADL library. ADL_Main_Control_Create() returned error code " + ADLRet.ToString());
}
}
catch (Exception ex)
{
SharedLogger.logger.Error("ADLWrapper/ADLWrapper: Exception intialising ADL library. ADL_Main_Control_Create() caused an exception");
}
}
~ADLWrapper()
{
// If the ADL library was initialised, then we need to free it up.
if (_initialised)
{
if (null != ADL.ADL_Main_Control_Destroy)
ADL.ADL_Main_Control_Destroy();
}
}
// 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)
{
if (null != ADL.ADL_Main_Control_Destroy)
ADL.ADL_Main_Control_Destroy();
// Dispose managed state (managed objects).
_safeHandle?.Dispose();
}
_disposed = true;
}
public bool IsInstalled
{
get { return _initialised; }
}
public static ADLWrapper GetLibrary()
{
return _instance;
}
public List<string> GenerateDisplayProfilesIdentifiers()
{
SharedLogger.logger.Trace($"ADLWrapper/GenerateProfileDisplayIdentifiers: Getting AMD active adapter count");
int ADLRet = ADL.ADL_FAIL; int ADLRet = ADL.ADL_FAIL;
int NumberOfAdapters = 0; int NumberOfAdapters = 0;
int NumberOfDisplays = 0; int NumberOfDisplays = 0;
if (null != ADL.ADL_Main_Control_Create) if (null != ADL.ADL_Adapter_NumberOfAdapters_Get)
// Second parameter is 1: Get only the present adapters
ADLRet = ADL.ADL_Main_Control_Create(ADL.ADL_Main_Memory_Alloc, 1);
if (ADL.ADL_SUCCESS == ADLRet)
{ {
if (null != ADL.ADL_Adapter_NumberOfAdapters_Get) ADL.ADL_Adapter_NumberOfAdapters_Get(ref NumberOfAdapters);
{ SharedLogger.logger.Trace($"ADLWrapper/GenerateProfileDisplayIdentifiers: Number Of Adapters: {NumberOfAdapters.ToString()} ");
ADL.ADL_Adapter_NumberOfAdapters_Get(ref NumberOfAdapters); }
}
Console.WriteLine("Number Of Adapters: " + NumberOfAdapters.ToString() + "\n");
if (0 < NumberOfAdapters) if (NumberOfAdapters > 0)
{
// Get OS adpater info from ADL
ADLAdapterInfoArray OSAdapterInfoData;
OSAdapterInfoData = new ADLAdapterInfoArray();
if (ADL.ADL_Adapter_AdapterInfo_Get != null)
{ {
// Get OS adpater info from ADL IntPtr AdapterBuffer = IntPtr.Zero;
ADLAdapterInfoArray OSAdapterInfoData; int size = Marshal.SizeOf(OSAdapterInfoData);
OSAdapterInfoData = new ADLAdapterInfoArray(); AdapterBuffer = Marshal.AllocCoTaskMem((int)size);
Marshal.StructureToPtr(OSAdapterInfoData, AdapterBuffer, false);
if (null != ADL.ADL_Adapter_AdapterInfo_Get) if (null != ADL.ADL_Adapter_AdapterInfo_Get)
{ {
IntPtr AdapterBuffer = IntPtr.Zero; ADLRet = ADL.ADL_Adapter_AdapterInfo_Get(AdapterBuffer, size);
int size = Marshal.SizeOf(OSAdapterInfoData); if (ADLRet == ADL.ADL_SUCCESS)
AdapterBuffer = Marshal.AllocCoTaskMem((int)size);
Marshal.StructureToPtr(OSAdapterInfoData, AdapterBuffer, false);
if (null != ADL.ADL_Adapter_AdapterInfo_Get)
{ {
ADLRet = ADL.ADL_Adapter_AdapterInfo_Get(AdapterBuffer, size); OSAdapterInfoData = (ADLAdapterInfoArray)Marshal.PtrToStructure(AdapterBuffer, OSAdapterInfoData.GetType());
if (ADL.ADL_SUCCESS == ADLRet) int IsActive = 1; // We only want to search for active adapters
for (int i = 0; i < NumberOfAdapters; i++)
{ {
OSAdapterInfoData = (ADLAdapterInfoArray)Marshal.PtrToStructure(AdapterBuffer, OSAdapterInfoData.GetType()); // Check if the adapter is active
int IsActive = 0; if (null != ADL.ADL_Adapter_Active_Get)
ADLRet = ADL.ADL_Adapter_Active_Get(OSAdapterInfoData.ADLAdapterInfo[i].AdapterIndex, ref IsActive);
for (int i = 0; i < NumberOfAdapters; i++) if (ADL.ADL_SUCCESS == ADLRet)
{ {
// Check if the adapter is active Console.WriteLine("Adapter is : " + (0 == IsActive ? "DISABLED" : "ENABLED"));
if (null != ADL.ADL_Adapter_Active_Get) Console.WriteLine("Adapter Index: " + OSAdapterInfoData.ADLAdapterInfo[i].AdapterIndex.ToString());
ADLRet = ADL.ADL_Adapter_Active_Get(OSAdapterInfoData.ADLAdapterInfo[i].AdapterIndex, ref IsActive); Console.WriteLine("Adapter UDID : " + OSAdapterInfoData.ADLAdapterInfo[i].UDID);
Console.WriteLine("Bus No : " + OSAdapterInfoData.ADLAdapterInfo[i].BusNumber.ToString());
Console.WriteLine("Driver No : " + OSAdapterInfoData.ADLAdapterInfo[i].DriverNumber.ToString());
Console.WriteLine("Function No : " + OSAdapterInfoData.ADLAdapterInfo[i].FunctionNumber.ToString());
Console.WriteLine("Vendor ID : " + OSAdapterInfoData.ADLAdapterInfo[i].VendorID.ToString());
Console.WriteLine("Adapter Name : " + OSAdapterInfoData.ADLAdapterInfo[i].AdapterName);
Console.WriteLine("Display Name : " + OSAdapterInfoData.ADLAdapterInfo[i].DisplayName);
Console.WriteLine("Present : " + (0 == OSAdapterInfoData.ADLAdapterInfo[i].Present ? "No" : "Yes"));
Console.WriteLine("Exist : " + (0 == OSAdapterInfoData.ADLAdapterInfo[i].Exist ? "No" : "Yes"));
Console.WriteLine("Driver Path : " + OSAdapterInfoData.ADLAdapterInfo[i].DriverPath);
Console.WriteLine("Driver Path X: " + OSAdapterInfoData.ADLAdapterInfo[i].DriverPathExt);
Console.WriteLine("PNP String : " + OSAdapterInfoData.ADLAdapterInfo[i].PNPString);
if (ADL.ADL_SUCCESS == ADLRet) // Obtain information about displays
ADLDisplayInfo oneDisplayInfo = new ADLDisplayInfo();
if (null != ADL.ADL_Display_DisplayInfo_Get)
{ {
Console.WriteLine("Adapter is : " + (0 == IsActive ? "DISABLED" : "ENABLED")); IntPtr DisplayBuffer = IntPtr.Zero;
Console.WriteLine("Adapter Index: " + OSAdapterInfoData.ADLAdapterInfo[i].AdapterIndex.ToString()); int j = 0;
Console.WriteLine("Adapter UDID : " + OSAdapterInfoData.ADLAdapterInfo[i].UDID);
Console.WriteLine("Bus No : " + OSAdapterInfoData.ADLAdapterInfo[i].BusNumber.ToString());
Console.WriteLine("Driver No : " + OSAdapterInfoData.ADLAdapterInfo[i].DriverNumber.ToString());
Console.WriteLine("Function No : " + OSAdapterInfoData.ADLAdapterInfo[i].FunctionNumber.ToString());
Console.WriteLine("Vendor ID : " + OSAdapterInfoData.ADLAdapterInfo[i].VendorID.ToString());
Console.WriteLine("Adapter Name : " + OSAdapterInfoData.ADLAdapterInfo[i].AdapterName);
Console.WriteLine("Display Name : " + OSAdapterInfoData.ADLAdapterInfo[i].DisplayName);
Console.WriteLine("Present : " + (0 == OSAdapterInfoData.ADLAdapterInfo[i].Present ? "No" : "Yes"));
Console.WriteLine("Exist : " + (0 == OSAdapterInfoData.ADLAdapterInfo[i].Exist ? "No" : "Yes"));
Console.WriteLine("Driver Path : " + OSAdapterInfoData.ADLAdapterInfo[i].DriverPath);
Console.WriteLine("Driver Path X: " + OSAdapterInfoData.ADLAdapterInfo[i].DriverPathExt);
Console.WriteLine("PNP String : " + OSAdapterInfoData.ADLAdapterInfo[i].PNPString);
// Obtain information about displays // Force the display detection and get the Display Info. Use 0 as last parameter to NOT force detection
ADLDisplayInfo oneDisplayInfo = new ADLDisplayInfo(); ADLRet = ADL.ADL_Display_DisplayInfo_Get(OSAdapterInfoData.ADLAdapterInfo[i].AdapterIndex, ref NumberOfDisplays, out DisplayBuffer, 0);
if (ADL.ADL_SUCCESS == ADLRet)
if (null != ADL.ADL_Display_DisplayInfo_Get)
{ {
IntPtr DisplayBuffer = IntPtr.Zero;
int j = 0;
// Force the display detection and get the Display Info. Use 0 as last parameter to NOT force detection List<ADLDisplayInfo> DisplayInfoData = new List<ADLDisplayInfo>();
ADLRet = ADL.ADL_Display_DisplayInfo_Get(OSAdapterInfoData.ADLAdapterInfo[i].AdapterIndex, ref NumberOfDisplays, out DisplayBuffer, 0);
if (ADL.ADL_SUCCESS == ADLRet) try
{ {
List<ADLDisplayInfo> DisplayInfoData = new List<ADLDisplayInfo>();
try
{
for (j = 0; j < NumberOfDisplays; j++)
{
oneDisplayInfo = (ADLDisplayInfo)Marshal.PtrToStructure(new IntPtr(DisplayBuffer.ToInt64() + (j * Marshal.SizeOf(oneDisplayInfo))), oneDisplayInfo.GetType());
DisplayInfoData.Add(oneDisplayInfo);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception caused trying to access attached displays");
continue;
}
Console.WriteLine("\nTotal Number of Displays supported: " + NumberOfDisplays.ToString());
Console.WriteLine("\nDispID AdpID Type OutType CnctType Connected Mapped InfoValue DisplayName ");
for (j = 0; j < NumberOfDisplays; j++) for (j = 0; j < NumberOfDisplays; j++)
{ {
int InfoValue = DisplayInfoData[j].DisplayInfoValue; // NOTE: the ToInt64 work on 64 bit, need to change to ToInt32 for 32 bit OS
string StrConnected = (1 == (InfoValue & 1)) ? "Yes" : "No "; oneDisplayInfo = (ADLDisplayInfo)Marshal.PtrToStructure(new IntPtr(DisplayBuffer.ToInt64() + (j * Marshal.SizeOf(oneDisplayInfo))), oneDisplayInfo.GetType());
string StrMapped = (2 == (InfoValue & 2)) ? "Yes" : "No "; DisplayInfoData.Add(oneDisplayInfo);
int AdpID = DisplayInfoData[j].DisplayID.DisplayLogicalAdapterIndex;
string StrAdpID = (AdpID < 0) ? "--" : AdpID.ToString("d2");
Console.WriteLine(DisplayInfoData[j].DisplayID.DisplayLogicalIndex.ToString() + " " +
StrAdpID + " " +
DisplayInfoData[j].DisplayType.ToString() + " " +
DisplayInfoData[j].DisplayOutputType.ToString() + " " +
DisplayInfoData[j].DisplayConnector.ToString() + " " +
StrConnected + " " +
StrMapped + " " +
InfoValue.ToString("x4") + " " +
DisplayInfoData[j].DisplayName.ToString());
} }
Console.WriteLine();
} }
else catch (Exception ex)
{ {
Console.WriteLine("ADL_Display_DisplayInfo_Get() returned error code " + ADLRet.ToString()); Console.WriteLine("Exception caused trying to access attached displays");
continue;
} }
// Release the memory for the DisplayInfo structure Console.WriteLine("\nTotal Number of Displays supported: " + NumberOfDisplays.ToString());
if (IntPtr.Zero != DisplayBuffer) Console.WriteLine("\nDispID AdpID Type OutType CnctType Connected Mapped InfoValue DisplayName ");
Marshal.FreeCoTaskMem(DisplayBuffer);
for (j = 0; j < NumberOfDisplays; j++)
{
int InfoValue = DisplayInfoData[j].DisplayInfoValue;
string StrConnected = (1 == (InfoValue & 1)) ? "Yes" : "No ";
string StrMapped = (2 == (InfoValue & 2)) ? "Yes" : "No ";
int AdpID = DisplayInfoData[j].DisplayID.DisplayLogicalAdapterIndex;
string StrAdpID = (AdpID < 0) ? "--" : AdpID.ToString("d2");
Console.WriteLine(DisplayInfoData[j].DisplayID.DisplayLogicalIndex.ToString() + " " +
StrAdpID + " " +
DisplayInfoData[j].DisplayType.ToString() + " " +
DisplayInfoData[j].DisplayOutputType.ToString() + " " +
DisplayInfoData[j].DisplayConnector.ToString() + " " +
StrConnected + " " +
StrMapped + " " +
InfoValue.ToString("x4") + " " +
DisplayInfoData[j].DisplayName.ToString());
}
Console.WriteLine();
} }
else
{
Console.WriteLine("ADL_Display_DisplayInfo_Get() returned error code " + ADLRet.ToString());
}
// Release the memory for the DisplayInfo structure
if (IntPtr.Zero != DisplayBuffer)
Marshal.FreeCoTaskMem(DisplayBuffer);
} }
} }
} }
else
{
Console.WriteLine("ADL_Adapter_AdapterInfo_Get() returned error code " + ADLRet.ToString());
}
} }
// Release the memory for the AdapterInfo structure else
if (IntPtr.Zero != AdapterBuffer) {
Marshal.FreeCoTaskMem(AdapterBuffer); Console.WriteLine("ADL_Adapter_AdapterInfo_Get() returned error code " + ADLRet.ToString());
}
} }
// Release the memory for the AdapterInfo structure
if (IntPtr.Zero != AdapterBuffer)
Marshal.FreeCoTaskMem(AdapterBuffer);
} }
if (null != ADL.ADL_Main_Control_Destroy)
ADL.ADL_Main_Control_Destroy();
} }
else else
{ {
Console.WriteLine("ADL_Main_Control_Create() returned error code " + ADLRet.ToString()); SharedLogger.logger.Error($"ADLWrapper/GenerateProfileDisplayIdentifiers: There were no AMD adapters found by AMD ADL.");
Console.WriteLine("\nCheck if ADL is properly installed!\n"); return null;
} }
/*foreach (NvAPIWrapper.GPU.PhysicalGPU myPhysicalGPU in myPhysicalGPUs)
{
// get a list of all physical outputs attached to the GPUs
NvAPIWrapper.GPU.GPUOutput[] myGPUOutputs = myPhysicalGPU.ActiveOutputs;
foreach (NvAPIWrapper.GPU.GPUOutput aGPUOutput in myGPUOutputs)
{
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: We were able to detect {myGPUOutputs.Length} outputs");
// Figure out the displaydevice attached to the output
NvAPIWrapper.Display.DisplayDevice aConnectedDisplayDevice = myPhysicalGPU.GetDisplayDeviceByOutput(aGPUOutput);
// Create an array of all the important display info we need to record
List<string> displayInfo = new List<string>();
displayInfo.Add("NVIDIA");
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.ShortName.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture ShortName from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.Revision.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture Revision from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Board.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Board details from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Foundry.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Foundry from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUId from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUType from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aConnectedDisplayDevice.ConnectionType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Connection from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aConnectedDisplayDevice.DisplayId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA DisplayID 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
displayIdentifiers.Add(displayIdentifier);
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}");
}
}*/
return null;
} }
} }
} }

View File

@ -30,6 +30,7 @@ namespace DisplayMagicianShared
private static ProfileItem _currentProfile; private static ProfileItem _currentProfile;
private static List<string> _connectedDisplayIdentifiers = new List<string>(); private static List<string> _connectedDisplayIdentifiers = new List<string>();
private static bool notifiedEDIDErrorToUser = false; private static bool notifiedEDIDErrorToUser = false;
private static ADLWrapper AMDLibrary;
// Other constants that are useful // Other constants that are useful
public static string AppDataPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DisplayMagician"); public static string AppDataPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DisplayMagician");
@ -50,7 +51,25 @@ namespace DisplayMagicianShared
{ {
SharedLogger.logger.Debug($"ProfileRepository/ProfileRepository: Initialising the NvAPIWrapper.NVIDIA library."); SharedLogger.logger.Debug($"ProfileRepository/ProfileRepository: Initialising the NvAPIWrapper.NVIDIA library.");
NvAPIWrapper.NVIDIA.Initialize(); NvAPIWrapper.NVIDIA.Initialize();
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/ProfileRepository: Initialising NVIDIA NvAPIWrapper caused an exception.");
}
// Initialise the the AMD ADLWrapper
try
{
SharedLogger.logger.Debug($"ProfileRepository/ProfileRepository: Initialising the AMD ADL library.");
AMDLibrary = new ADLWrapper();
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/ProfileRepository: Initialising AMD ADL caused an exception.");
}
try
{
// Create the Profile Storage Path if it doesn't exist so that it's avilable for all the program // Create the Profile Storage Path if it doesn't exist so that it's avilable for all the program
if (!Directory.Exists(AppProfileStoragePath)) if (!Directory.Exists(AppProfileStoragePath))
{ {
@ -76,7 +95,7 @@ namespace DisplayMagicianShared
} }
catch (Exception ex) catch (Exception ex)
{ {
SharedLogger.logger.Warn(ex, $"ProfileRepository/ProfileRepository: Initialising NVIDIA NvAPIWrapper caused an exception."); SharedLogger.logger.Warn(ex, $"ProfileRepository/ProfileRepository: Exception creating the Profiles storage folder.");
} }
// Load the Profiles from storage // Load the Profiles from storage
LoadProfiles(); LoadProfiles();
@ -795,8 +814,16 @@ namespace DisplayMagicianShared
} }
// If the Video Card is an AMD, then we should generate specific AMD displayIdentifiers // If the Video Card is an AMD, then we should generate specific AMD displayIdentifiers
AMD.ADLWrapper thingy = new AMD.ADLWrapper(); bool isAMD = false;
if (AMDLibrary.IsInstalled)
{
isAMD = true;
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: The video card is an AMD video card.");
// Needs a lot of work here! We need to check if the AMD returned the right stuff, and then use Windows if there is an error.
return AMDLibrary.GenerateDisplayProfilesIdentifiers();
}
try try
{ {
myPhysicalGPUs = NvAPIWrapper.GPU.PhysicalGPU.GetPhysicalGPUs(); myPhysicalGPUs = NvAPIWrapper.GPU.PhysicalGPU.GetPhysicalGPUs();