using ATI.ADL; using System.ComponentModel; using System.Runtime.InteropServices; using ADL_CONTEXT_HANDLE = nint; namespace ColorControl.Shared.Contracts.AMD; public enum ADLPixelFormat { [Description("Unknown/unsupported")] UNKNOWN = 0, RGB_FULL_RANGE = 1, YCRCB444 = 2, YCRCB422 = 3, RGB_LIMITED_RANGE = 4, YCRCB420 = 8 } public enum ADLColorDepth { [Description("Unknown/unsupported")] UNKNOWN = 0, BPC6 = 1, BPC8 = 2, BPC10 = 3, BPC12 = 4, BPC14 = 5, BPC16 = 6 } public enum ADLDitherState { DISABLED = 0, DRIVER_DEFAULT = 1, FM6 = 2, FM8 = 3, FM10 = 4, DITH6 = 5, DITH8 = 6, DITH10 = 7, DITH6_NO_FRAME_RAND = 8, DITH8_NO_FRAME_RAND = 9, DITH10_NO_FRAME_RAND = 10, TRUN6 = 11, TRUN8 = 12, TRUN10 = 13, TRUN8_DITH8 = 14, TRUN10_DITH6 = 15, TRUN10_FM8 = 16, TRUN10_FM6 = 17, TRUN10_DITH8_FM6 = 18, DITH10_FM8 = 19, DITH10_FM6 = 20, TRUN8_DITH6 = 21, TRUN8_FM6 = 22, DITH8_FM6 = 23 } public class ADLWrapper { private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); private static ADL_CONTEXT_HANDLE context = ADL_CONTEXT_HANDLE.Zero; public static bool Initialize() { int ADLRet = -1; //Logger.Debug("Initialize"); var del = ADL.GetDelegate(); if (del != null) { // Second parameter is 1: Get only the present adapters ADLRet = del(ADL.ADL_Main_Memory_Alloc_Func, 1); CheckError(ADLRet, nameof(ADL.ADL_Main_Control_Create)); } var del2 = ADL.GetDelegate(); if (del2 != null) { // Second parameter is 1: Get only the present adapters ADLRet = del2(ADL.ADL_Main_Memory_Alloc_Func, 1, ref context); CheckError(ADLRet, nameof(ADL.ADL2_Main_Control_Create)); } return ADL.ADL_SUCCESS == ADLRet; } public static void Uninitialze() { if (!ADL.ADLDelegates.Any()) { return; } var del = ADL.GetDelegate(); if (null != del) { del(); } var del2 = ADL.GetDelegate(); if (null != del2 && context != ADL_CONTEXT_HANDLE.Zero) { del2(context); } } public static ADLAdapterInfoArray? GetAdapters() { int ADLRet = -1; int NumberOfAdapters = 0; var delNumberOfAdapters = ADL.GetDelegate(); if (null != delNumberOfAdapters) { delNumberOfAdapters(context, ref NumberOfAdapters); } Logger.Debug("Number Of Adapters: " + NumberOfAdapters.ToString() + "\n"); if (NumberOfAdapters > 0) { // Get OS adpater info from ADL ADLAdapterInfoArray OSAdapterInfoData; OSAdapterInfoData = new ADLAdapterInfoArray(); var delAdapterInfo = ADL.GetDelegate(); if (null != delAdapterInfo) { ADL_CONTEXT_HANDLE AdapterBuffer = ADL_CONTEXT_HANDLE.Zero; int size = Marshal.SizeOf(OSAdapterInfoData); AdapterBuffer = Marshal.AllocCoTaskMem(size); Marshal.StructureToPtr(OSAdapterInfoData, AdapterBuffer, false); ADLRet = delAdapterInfo(context, AdapterBuffer, size); if (ADL.ADL_SUCCESS == ADLRet) { OSAdapterInfoData = (ADLAdapterInfoArray)Marshal.PtrToStructure(AdapterBuffer, OSAdapterInfoData.GetType()); int IsActive = 0; var delActive = ADL.GetDelegate(); for (int i = 0; i < NumberOfAdapters; i++) { // Check if the adapter is active if (null != delActive) ADLRet = delActive(context, OSAdapterInfoData.ADLAdapterInfo[i].AdapterIndex, ref IsActive); if (ADL.ADL_SUCCESS == ADLRet) { } } } else { Logger.Debug("ADL_Adapter_AdapterInfo_Get() returned error code " + ADLRet.ToString()); } // Release the memory for the AdapterInfo structure if (ADL_CONTEXT_HANDLE.Zero != AdapterBuffer) { Marshal.FreeCoTaskMem(AdapterBuffer); } } return OSAdapterInfoData; } return null; } public static List GetAllDisplays(bool connected = true) { int ADLRet; int NumberOfDisplays = 0; var DisplayInfoData = new List(); var OSAdapterInfoData = GetAdapters(); if (OSAdapterInfoData == null || !OSAdapterInfoData.Value.ADLAdapterInfo.Any()) { return DisplayInfoData; } var primaryAdapter = OSAdapterInfoData.Value.ADLAdapterInfo.First(); ADLDisplayInfo oneDisplayInfo = new ADLDisplayInfo(); var del = ADL.GetDelegate(); if (null != del) { ADL_CONTEXT_HANDLE DisplayBuffer = ADL_CONTEXT_HANDLE.Zero; int j = 0; // Force the display detection and get the Display Info. Use 0 as last parameter to NOT force detection ADLRet = del(context, primaryAdapter.AdapterIndex, ref NumberOfDisplays, out DisplayBuffer, 1); if (ADL.ADL_SUCCESS == ADLRet) { for (j = 0; j < NumberOfDisplays; j++) { oneDisplayInfo = (ADLDisplayInfo)Marshal.PtrToStructure(new ADL_CONTEXT_HANDLE(DisplayBuffer.ToInt64() + j * Marshal.SizeOf(oneDisplayInfo)), oneDisplayInfo.GetType()); if (!connected || 1 == (oneDisplayInfo.DisplayInfoValue & 1)) { DisplayInfoData.Add(oneDisplayInfo); } } Logger.Debug("Total Number of Displays supported: " + NumberOfDisplays.ToString()); Logger.Debug("DispID DispPhyId AdpID Type OutType CnctType Connected Mapped InfoValue DisplayName "); for (j = 0; j < DisplayInfoData.Count; 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"); Logger.Debug(DisplayInfoData[j].DisplayID.DisplayLogicalIndex.ToString() + " " + DisplayInfoData[j].DisplayID.DisplayPhysicalIndex.ToString() + " " + StrAdpID + " " + DisplayInfoData[j].DisplayType.ToString() + " " + DisplayInfoData[j].DisplayOutputType.ToString() + " " + DisplayInfoData[j].DisplayConnector.ToString() + " " + StrConnected + " " + StrMapped + " " + InfoValue.ToString("x4") + " " + DisplayInfoData[j].DisplayName.ToString()); } } else { Logger.Debug("ADL_Display_DisplayInfo_Get() returned error code " + ADLRet.ToString()); } // Release the memory for the DisplayInfo structure if (ADL_CONTEXT_HANDLE.Zero != DisplayBuffer) Marshal.FreeCoTaskMem(DisplayBuffer); } return DisplayInfoData; } private static bool CheckError(int ADLRet, string functionName) { var result = ADLRet == ADL.ADL_SUCCESS; if (!result) { Logger.Error($"Error calling ADL ({functionName}): {ADLRet}"); } return result; } public static bool GetDisplayResolution(ADLDisplayInfo display, ref int horizontal, ref int vertical) { var screen = Screen.PrimaryScreen; var bounds = screen.Bounds; horizontal = bounds.Width; vertical = bounds.Height; Logger.Debug($"GetDisplayResolution: {horizontal}x{vertical}"); //var del = ADL.GetDelegate(); //if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null) //{ // int lpDefaultWidth, lpDefaultHeight, lpMinWidth, lpMinHeight, lpMaxWidth, lpMaxHeight, lpStepWidth, lpStepHeight; // lpDefaultWidth = lpDefaultHeight = lpMinWidth = lpMinHeight = lpMaxWidth = lpMaxHeight = lpStepWidth = lpStepHeight = 0; // var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, ref horizontal, ref vertical, ref lpDefaultWidth, ref lpDefaultHeight, ref lpMinWidth, ref lpMinHeight, ref lpMaxWidth, ref lpMaxHeight, ref lpStepWidth, ref lpStepHeight); // return CheckError(ADLRet, nameof(ADL.ADL2_Display_Size_Get)); //} return true; } public static bool GetDisplayPixelFormat(ADLDisplayInfo display, ref ADLPixelFormat pixelFormat) { var del = ADL.GetDelegate(); if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null) { int pixelFormatInt = 0; var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, ref pixelFormatInt); pixelFormat = (ADLPixelFormat)pixelFormatInt; return CheckError(ADLRet, nameof(ADL.ADL2_Display_PixelFormat_Get)); } return false; } public static bool SetDisplayPixelFormat(ADLDisplayInfo display, ADLPixelFormat pixelFormat) { var del = ADL.GetDelegate(); if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null) { var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, (int)pixelFormat); return CheckError(ADLRet, nameof(ADL.ADL2_Display_PixelFormat_Set)); } return false; } public static bool GetDisplayColorDepth(ADLDisplayInfo display, ref ADLColorDepth colorDepth) { var del = ADL.GetDelegate(); if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null) { int colorDepthInt = 0; var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, ref colorDepthInt); colorDepth = (ADLColorDepth)colorDepthInt; return CheckError(ADLRet, nameof(ADL.ADL2_Display_ColorDepth_Get)); } return false; } public static bool SetDisplayColorDepth(ADLDisplayInfo display, ADLColorDepth colorDepth) { var del = ADL.GetDelegate(); if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null) { var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, (int)colorDepth); return CheckError(ADLRet, nameof(ADL.ADL2_Display_ColorDepth_Set)); } return false; } public static bool GetDisplayDitherState(ADLDisplayInfo display, ref ADLDitherState ditherState) { var del = ADL.GetDelegate(); if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null) { var ditherStateInt = 0; var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, ref ditherStateInt); ditherState = (ADLDitherState)ditherStateInt; return CheckError(ADLRet, nameof(ADL.ADL2_Display_DitherState_Get)); } return false; } public static bool SetDisplayDitherState(ADLDisplayInfo display, ADLDitherState ditherState) { var del = ADL.GetDelegate(); if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null) { var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, (int)ditherState); return CheckError(ADLRet, nameof(ADL.ADL2_Display_DitherState_Set)); } return false; } public static bool GetDisplayHDRState(ADLDisplayInfo display, ref bool supported, ref bool enabled) { var del = ADL.GetDelegate(); if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null) { var supportedInt = 0; var enabledInt = 0; var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID, ref supportedInt, ref enabledInt); supported = supportedInt != 0; enabled = enabledInt != 0; return CheckError(ADLRet, nameof(ADL.ADL2_Display_HDRState_Get)); } return false; } public static bool SetDisplayHDRState(ADLDisplayInfo display, bool enabled) { var del = ADL.GetDelegate(); if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null) { var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID, enabled ? 1 : 0); return CheckError(ADLRet, nameof(ADL.ADL2_Display_HDRState_Set)); } return false; } }