GPU (Windows): rewrite implementation for AMD GPUs using ADL SDK

Detect more information including memory type
This commit is contained in:
李通洲
2025-03-24 15:24:53 +08:00
committed by 李通洲
parent c9a1765f29
commit 8dafd8f300
6 changed files with 166 additions and 434 deletions
+39 -6
View File
@@ -4,11 +4,44 @@
// https://gpuopen-librariesandsdks.github.io/adl/modules.html
// ADLOD6CurrentStatus ADL2_Overdrive6_Temperature_Get
// https://gpuopen-librariesandsdks.github.io/adl/group__OVERDRIVE6API.html#ga10021644bfab0e3910e10caaa7c0053c
// Function to initialize the ADL2 interface and to obtain client's context handle.
extern int ADL2_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK callback, int iEnumConnectedAdapters, ADL_CONTEXT_HANDLE* context);
// ADL2_Adapter_DedicatedVRAMUsage_Get ADL2_Adapter_VRAMUsage_Get
// https://gpuopen-librariesandsdks.github.io/adl/group__ADAPTERMAINAPI.html#ga9c41c3740ddd76ee4f8a33a3ccc55e7f
// Destroy client's ADL context.
extern int ADL2_Main_Control_Destroy(ADL_CONTEXT_HANDLE context);
// ADL_ASIC_DISCRETE ADL_Adapter_ASICFamilyType_Get
// https://gpuopen-librariesandsdks.github.io/adl/group__ADAPTERMAINAPI.html#ga345082fdc7c14fc5179605732085d272
// Retrieves adapter information for given adapter or all OS-known adapters.
// Return 1 on success
extern int ADL2_Adapter_AdapterInfoX3_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* numAdapters, AdapterInfo** lppAdapterInfo);
// Function to retrieve Graphic Core Info.
// Return ADL_OK on success
extern int ADL2_Adapter_Graphic_Core_Info_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLGraphicCoreInfo* pGraphicCoreInfo);
// Function to retrieve memory information from the adapter. Version 2
// Return ADL_OK on success
extern int ADL2_Adapter_MemoryInfo2_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLMemoryInfo2* lpMemoryInfo2);
// This function retrieves the VRAM usage of given adapter.
// Return ADL_OK on success
extern int ADL2_Adapter_VRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
// This function retrieves the Dedicated VRAM usage of given adapter.
// Return ADL_OK on success
extern int ADL2_Adapter_DedicatedVRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
// Function to get the ASICFamilyType from the adapter.
// Return ADL_OK on success
extern int ADL2_Adapter_ASICFamilyType_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* lpAsicTypes, int* lpValids);
// Function to retrieve current Overdrive and performance-related activity.
// Return ADL_OK on success
extern int ADL2_Overdrive6_CurrentStatus_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLOD6CurrentStatus* lpCurrentStatus);
// Function to retrieve GPU temperature from the thermal controller.
// Return ADL_OK on success
extern int ADL2_Overdrive6_Temperature_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* lpTemperature);
// Function to retrieve the current or default Overdrive clock ranges.
// Return ADL_OK on success
extern int ADL2_Overdrive6_StateInfo_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int iStateType, ADLOD6StateInfo* lpStateInfo);
+125 -33
View File
@@ -1,47 +1,84 @@
#include "gpu_driver_specific.h"
// Everything detected in this file is static.
// The real time monitoring requires ADLX, whose interface is much more complicated than AGS
// Whoever has AMD graphic cards interested in this may contribute
// * ADLX (AMD Device Library eXtra): https://github.com/GPUOpen-LibrariesAndSDKs/ADLX
#include "3rdparty/ags/amd_ags.h"
#include "adl.h"
#include "common/library.h"
#include "util/mallocHelper.h"
// Memory allocation function
void* __attribute__((__stdcall__)) ADL_Main_Memory_Alloc(int iSize)
{
return malloc((size_t) iSize);
}
struct FFAdlData {
FF_LIBRARY_SYMBOL(ADL2_Main_Control_Destroy)
FF_LIBRARY_SYMBOL(ADL2_Adapter_AdapterInfoX3_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_Graphic_Core_Info_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_MemoryInfo2_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_DedicatedVRAMUsage_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_VRAMUsage_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_ASICFamilyType_Get)
FF_LIBRARY_SYMBOL(ADL2_Overdrive6_CurrentStatus_Get)
FF_LIBRARY_SYMBOL(ADL2_Overdrive6_Temperature_Get)
FF_LIBRARY_SYMBOL(ADL2_Overdrive6_StateInfo_Get)
bool inited;
ADL_CONTEXT_HANDLE apiHandle;
} adlData;
static void shutdownAdl()
{
if (adlData.apiHandle)
{
adlData.ffADL2_Main_Control_Destroy(adlData.apiHandle);
adlData.apiHandle = NULL;
}
}
const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName)
{
static bool inited = false;
static AGSGPUInfo gpuInfo;
if (!inited)
if (!adlData.inited)
{
inited = true;
FF_LIBRARY_LOAD(libags, "dlopen amd_ags failed", soName , 1);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libags, agsInitialize)
adlData.inited = true;
FF_LIBRARY_LOAD(atiadl, "dlopen atiadlxx failed", soName , 1);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(atiadl, ADL2_Main_Control_Create)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Main_Control_Destroy)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_AdapterInfoX3_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_Graphic_Core_Info_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_MemoryInfo2_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_DedicatedVRAMUsage_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_VRAMUsage_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ASICFamilyType_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive6_CurrentStatus_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive6_Temperature_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive6_StateInfo_Get)
struct AGSContext* apiHandle;
if (ffagsInitialize(AGS_CURRENT_VERSION, NULL, &apiHandle, &gpuInfo) != AGS_SUCCESS)
return "loading ags library failed";
if (ffADL2_Main_Control_Create(ADL_Main_Memory_Alloc, 1 /*iEnumConnectedAdapters*/, &adlData.apiHandle) != ADL_OK)
return "ffADL2_Main_Control_Create() failed";
// agsDeInitialize will free pointers allocated in gpuInfo. Just leak them.
atexit(shutdownAdl);
atiadl = NULL; // don't close atiadl
}
if (gpuInfo.numDevices == 0)
return "loading ags library failed or no AMD gpus found";
if (!adlData.apiHandle)
return "ffADL2_Main_Control_Create() failed";
AGSDeviceInfo* device = NULL;
FF_AUTO_FREE AdapterInfo* devices = NULL;
int numDevices = 0;
if (adlData.ffADL2_Adapter_AdapterInfoX3_Get(adlData.apiHandle, -1, &numDevices, &devices) == 0)
return "ffADL2_Adapter_AdapterInfoX3_Get() failed";
for (int iDev = 0; iDev < gpuInfo.numDevices; iDev++)
const AdapterInfo* device = NULL;
for (int iDev = 0; iDev < numDevices; iDev++)
{
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID)
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
{
if (
cond->pciDeviceId.deviceId == (uint32_t) gpuInfo.devices[iDev].deviceId &&
cond->pciDeviceId.vendorId == (uint32_t) gpuInfo.devices[iDev].vendorId &&
cond->pciDeviceId.revId == (uint32_t) gpuInfo.devices[iDev].revisionId)
cond->pciBusId.bus == (uint32_t) devices[iDev].iBusNumber &&
cond->pciBusId.device == (uint32_t) devices[iDev].iDeviceNumber &&
cond->pciBusId.func == (uint32_t) devices[iDev].iFunctionNumber)
{
device = &gpuInfo.devices[iDev];
device = &devices[iDev];
break;
}
}
@@ -51,25 +88,80 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
return "Device not found";
if (result.coreCount)
*result.coreCount = (uint32_t) device->numCUs;
{
ADLGraphicCoreInfo coreInfo;
if (adlData.ffADL2_Adapter_Graphic_Core_Info_Get(adlData.apiHandle, device->iAdapterIndex, &coreInfo) == ADL_OK)
*result.coreCount = (uint32_t) coreInfo.iNumCUs;
}
if (result.memory)
{
result.memory->total = device->localMemoryInBytes;
result.memory->used = FF_GPU_VMEM_SIZE_UNSET;
int vramUsage = 0;
if (adlData.ffADL2_Adapter_DedicatedVRAMUsage_Get(adlData.apiHandle, device->iAdapterIndex, &vramUsage) == ADL_OK)
result.memory->used = (uint64_t) vramUsage * 1024 * 1024;
if (result.sharedMemory)
{
vramUsage = 0;
if (adlData.ffADL2_Adapter_VRAMUsage_Get(adlData.apiHandle, device->iAdapterIndex, &vramUsage) == ADL_OK)
result.sharedMemory->used = (uint64_t) vramUsage * 1024 * 1024 - result.memory->used;
}
}
if (result.memoryType)
{
ADLMemoryInfo2 memoryInfo;
if (adlData.ffADL2_Adapter_MemoryInfo2_Get(adlData.apiHandle, device->iAdapterIndex, &memoryInfo) == ADL_OK)
ffStrbufSetS(result.memoryType, memoryInfo.strMemoryType);
}
if (result.frequency)
*result.frequency = (uint32_t) device->coreClock; // Maximum frequency
{
ADLOD6StateInfo stateInfo;
if (adlData.ffADL2_Overdrive6_StateInfo_Get(adlData.apiHandle, device->iAdapterIndex, ADL_OD6_GETSTATEINFO_CUSTOM_PERFORMANCE, &stateInfo) == ADL_OK)
{
int clock = 0; // assume in 10 kHz
for (int i = 0; i < stateInfo.iNumberOfPerformanceLevels; i++)
{
if (stateInfo.aLevels[i].iEngineClock > clock)
clock = stateInfo.aLevels[i].iEngineClock;
}
*result.frequency = (uint32_t) clock / 100;
}
}
if (result.coreUsage)
{
ADLOD6CurrentStatus status;
if (adlData.ffADL2_Overdrive6_CurrentStatus_Get(adlData.apiHandle, device->iAdapterIndex, &status) == ADL_OK)
{
if (result.coreUsage)
*result.coreUsage = status.iActivityPercent;
}
}
if (result.type)
*result.type = device->isAPU ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
{
int asicTypes = 0;
int valids = 0;
if (adlData.ffADL2_Adapter_ASICFamilyType_Get(adlData.apiHandle, device->iAdapterIndex, &asicTypes, &valids) == ADL_OK)
{
asicTypes &= valids; // This design is strange
*result.type = asicTypes & ADL_ASIC_INTEGRATED ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
if (result.index)
*result.index = (uint32_t) device->adlAdapterIndex;
*result.index = (uint32_t) device->iAdapterIndex;
if (result.name)
ffStrbufSetS(result.name, device->adapterString);
ffStrbufSetS(result.name, device->strAdapterName);
if (result.temp)
{
int milliDegrees = 0;
if (adlData.ffADL2_Overdrive6_Temperature_Get(adlData.apiHandle, device->iAdapterIndex, &milliDegrees) == ADL_OK)
*result.temp = milliDegrees / 1000.0;
}
return NULL;
}
+2 -2
View File
@@ -89,9 +89,9 @@ FF_MAYBE_UNUSED static inline bool getDriverSpecificDetectionFn(const char* vend
{
*pDetectFn = ffDetectAmdGpuInfo;
#ifdef _WIN64
*pDllName = "amd_ags_x64.dll";
*pDllName = "atiadlxx.dll";
#else
*pDllName = "amd_ags_x86.dll";
*pDllName = "atiadlxy.dll";
#endif
}
#endif