GPUs
Demonstrates how to enumerate GPUs, get GPU information, receive notifications when GPUs are enabled and disabled, and maintain GPU change event when programming with ADLX.
Sample Path
/Samples/CPP/Generic/GPUs
Code
//
// Copyright (c) 2021 - 2024 Advanced Micro Devices, Inc. All rights reserved.
//
//-------------------------------------------------------------------------------------------------
#include "SDK/ADLXHelper/Windows/Cpp/ADLXHelper.h"
#include "SDK/Include/ISystem1.h"
#include <chrono>
#include <iostream>
#include <thread>
// Use ADLX namespace
using namespace adlx;
// ADLXHelper instance
// No outstanding interfaces from ADLX must exist when ADLX is destroyed.
// Use global variables to ensure validity of the interface.
static ADLXHelper g_ADLXHelp;
// Display GPU information
void ShowGPUInfo(const IADLXGPUPtr& gpu);
// Display GPU hybrid graphic type
void ShowHybridGraphicType();
// Display Driver Version
void ShowDriverInfo(const IADLXGPUPtr& gpu);
// Add GPU change event listener
void AddGPUEventListener(const IADLXGPUPtr& gpu);
// Main menu
void MainMenu();
// Menu action control
void MenuControl(const IADLXGPUPtr& gpu);
// Wait for exit with error message
int WaitAndExit(const char* msg, const int retCode);
// GPU event change handler definition
class GPUEventListener : public IADLXGPUsEventListener
{
adlx_bool ADLX_STD_CALL OnGPUListChanged(IADLXGPUList* pNewGPUs)
{
std::cout << "GPU list change event received" << std::endl;
if (pNewGPUs == nullptr)
{
std::cout << "GPU list does not exist" << std::endl;
return false;
}
std::cout << "GPU list size: " << pNewGPUs->Size() << std::endl;
return true;
}
};
int main()
{
// Define return code
ADLX_RESULT res = ADLX_FAIL ;
// Initialize ADLX
res = g_ADLXHelp.Initialize();
if (ADLX_SUCCEEDED (res))
{
// Get GPU list
IADLXGPUListPtr gpus;
res = g_ADLXHelp.GetSystemServices()->GetGPUs(&gpus);
if (ADLX_SUCCEEDED (res) && !gpus->Empty())
{
// Inspect for the first GPU in the list
IADLXGPUPtr gpu;
res = gpus->At(0, &gpu);
if (ADLX_SUCCEEDED (res))
{
// Display main menu options
MainMenu();
// Get and parse the selection
MenuControl(gpu);
}
}
else
{
std::cout << "Failed to get the GPU list" << std::endl;
}
}
else
{
return WaitAndExit("ADLX initialization failed", 0);
}
// Destroy ADLX
res = g_ADLXHelp.Terminate();
std::cout << "Destroy ADLX res: " << res << std::endl;
// Pause to see the print out
system("pause");
return 0;
}
// Display GPU information
void ShowGPUInfo(const IADLXGPUPtr& gpu)
{
std::cout << "\\n==== GPU info ====" << std::endl;
// Display GPU info
const char* vendorId = nullptr;
ADLX_RESULT ret = gpu->VendorId(&vendorId);
std::cout << "VendorId: " << vendorId << ", return code is: "<< ret << "(0 means success)" << std::endl;
ADLX_ASIC_FAMILY_TYPE asicFamilyType = ASIC_UNDEFINED ;
ret = gpu->ASICFamilyType(&asicFamilyType);
std::cout << "ASICFamilyType: " << asicFamilyType << ", return code is: "<< ret << "(0 means success)" << std::endl;
ADLX_GPU_TYPE gpuType = GPUTYPE_UNDEFINED ;
ret = gpu->Type(&gpuType);
std::cout << "Type: " << gpuType << std::endl;
adlx_bool isExternal = false;
ret = gpu->IsExternal(&isExternal);
std::cout << "IsExternal: " << isExternal << ", return code is: "<< ret << "(0 means success)" << std::endl;
const char* gpuName = nullptr;
ret = gpu->Name(&gpuName);
std::cout << "Name: " << gpuName << ", return code is: "<< ret << "(0 means success)" << std::endl;
const char* driverPath = nullptr;
ret = gpu->DriverPath(&driverPath);
std::cout << "DriverPath: " << driverPath << ", return code is: "<< ret << "(0 means success)" << std::endl;
const char* pnpString = nullptr;
ret = gpu->PNPString(&pnpString);
std::cout << "PNPString: " << pnpString << ", return code is: "<< ret << "(0 means success)" << std::endl;
adlx_bool hasDesktops = false;
ret = gpu->HasDesktops(&hasDesktops);
std::cout << "HasDesktops: " << hasDesktops << ", return code is: "<< ret << "(0 means success)" << std::endl;
adlx_uint totalVRAM;
ret = gpu->TotalVRAM(&totalVRAM);
std::cout << "TotalVRAM: " << totalVRAM << " MB" << ", return code is: "<< ret << "(0 means success)" << std::endl;
adlx_int id;
ret = gpu->UniqueId(&id);
std::cout << "UniqueId: " << id << std::endl;
ShowDriverInfo(gpu);
IADLXGPU1Ptr gpu1(gpu);
if (gpu1)
{
const char* productName = nullptr;
ret = gpu1->ProductName(&productName);
std::cout << "ProductName: " << productName << std::endl;
ADLX_MGPU_MODE mode = MGPU_NONE ;
ret = gpu1->MultiGPUMode(&mode);
printf("Multi-GPU Mode: ");
if (mode == MGPU_PRIMARY )
std::cout << "GPU is the primary GPU" << std::endl;
else if (mode == MGPU_SECONDARY )
std::cout << "GPU is the secondary GPU" << std::endl;
else
std::cout << "GPU is not in Multi-GPU" << std::endl;
ADLX_PCI_BUS_TYPE busType = UNDEFINED ;
ret = gpu1->PCIBusType(&busType);
std::cout << "PCIBusType: " << busType << std::endl;
adlx_uint laneWidth = 0;
ret = gpu1->PCIBusLaneWidth(&laneWidth);
std::cout << "PCIBusLaneWidth: " << laneWidth << std::endl;
}
}
bool GetStringFromLocalMachine(const wchar_t* szKeyPath_, const wchar_t* szValueName_, wchar_t* szValue_, DWORD dwSize_)
{
if ((szKeyPath_ == NULL) || (szValueName_ == NULL))
return false;
bool bRetVal = false;
bool bKeyOpenStatus = false;
DWORD dwValueType = REG_SZ;
HKEY hKeyRes;
//Opens the specified key, returning a handle object.
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyPath_, 0, KEY_QUERY_VALUE, &hKeyRes) == ERROR_SUCCESS)
bKeyOpenStatus = true;
if (bKeyOpenStatus)
{
//Retrieves the type and data for a specified value name associated with an open registry key
if (RegQueryValueEx(hKeyRes, szValueName_, 0, &dwValueType, (LPBYTE)szValue_, &dwSize_) == ERROR_SUCCESS)
{
//If the value type is string return true otherwise false
if (dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ)
bRetVal = true;
}
RegCloseKey(hKeyRes);
}
return bRetVal;
}
int Char2WChar(const char* pStr, wchar_t* pWStr)
{
if (pStr == nullptr || pWStr == nullptr)
{
return 0;
}
int len = MultiByteToWideChar(CP_ACP, 0, pStr, strlen(pStr), NULL, 0);
MultiByteToWideChar(CP_ACP, 0, pStr, strlen(pStr), pWStr, len);
pWStr[len] = '\\0';
return len;
}
void ShowDriverInfo(const IADLXGPUPtr& gpu)
{
ADLX_ASIC_FAMILY_TYPE asicFamilyType = ASIC_UNDEFINED ;
ADLX_RESULT ret = gpu->ASICFamilyType(&asicFamilyType);
wchar_t RSVersion[MAX_PATH] = L"";
wchar_t RSEdition[MAX_PATH] = L"";
switch (asicFamilyType)
{
case ASIC_RADEON :
wcscpy_s(RSVersion, MAX_PATH, L"RadeonSoftwareVersion");
wcscpy_s(RSEdition, MAX_PATH, L"RadeonSoftwareEdition");
break;
case ASIC_FIREPRO :
case ASIC_FIREMV :
case ASIC_FIRESTREAM :
wcscpy_s(RSVersion, MAX_PATH, L"FireproSoftwareVersion");
wcscpy_s(RSEdition, MAX_PATH, L"FireproSoftwareEdition");
break;
default:
wcscpy_s(RSVersion, MAX_PATH, L"RadeonSoftwareVersion");
wcscpy_s(RSEdition, MAX_PATH, L"RadeonSoftwareEdition");
break;
}
const char* driverPath = nullptr;
ret = gpu->DriverPath(&driverPath);
if (ADLX_SUCCEEDED (ret))
{
wchar_t driverPathW[MAX_PATH] = { 0 };
Char2WChar(driverPath, driverPathW);
// The full path of driver reg
wchar_t driverRegistryPath[MAX_PATH] = { 0 };
swprintf_s(driverRegistryPath, L"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Class\\\\%s", driverPathW);
wchar_t value[MAX_PATH] = L"";
// Get AMD Software Version from the registry
GetStringFromLocalMachine(driverRegistryPath, RSVersion, value, sizeof(value));
std::wcout << "AMD Software version: " << value << std::endl;
// Get AMD Software Edition from the registry
GetStringFromLocalMachine(driverRegistryPath, RSEdition, value, sizeof(value));
std::wcout << value << std::endl;
// Get AMD Software Release Date from the registry
GetStringFromLocalMachine(driverRegistryPath, L"DriverDate", value, sizeof(value));
std::wcout << "AMD Software Release Date: " << value << std::endl;
// Get Driver Version from the registry
GetStringFromLocalMachine(driverRegistryPath, L"DriverVersion", value, sizeof(value));
std::wcout << "Driver Version: " << value << std::endl;
// Get AMD Windows Driver Version from the registry
GetStringFromLocalMachine(driverRegistryPath, L"ReleaseVersion", value, sizeof(value));
std::wcout << "AMD Windows Driver Version: " << value << std::endl;
}
}
void ShowHybridGraphicType()
{
ADLX_HG_TYPE hgType = ADLX_HG_TYPE::NONE ;
ADLX_RESULT res = g_ADLXHelp.GetSystemServices()->HybridGraphicsType(&hgType);
if (ADLX_SUCCEEDED (res))
{
switch (hgType)
{
case ADLX_HG_TYPE::NONE :
std::cout << "GPU hybrid type is: "
<< "ADLX_HG_TYPE::NONE" << std::endl;
break;
case ADLX_HG_TYPE::AMD :
std::cout << "GPU hybrid type is: "
<< "ADLX_HG_TYPE::AMD" << std::endl;
break;
case ADLX_HG_TYPE::OTHER :
std::cout << "GPU hybrid type is: "
<< "ADLX_HG_TYPE::OTHER" << std::endl;
break;
}
}
}
// Add GPU change event listener
void AddGPUEventListener(const IADLXGPUPtr& gpu)
{
GPUEventListener gpuListener;
IADLXGPUsChangedHandlingPtr gpusChangedHandling;
ADLX_RESULT res = g_ADLXHelp.GetSystemServices()->GetGPUsChangedHandling(&gpusChangedHandling);
if (ADLX_SUCCEEDED (res) && gpusChangedHandling)
{
res = gpusChangedHandling->AddGPUsListEventListener(&gpuListener);
if (ADLX_SUCCEEDED (res))
{
std::cout << "Addition of GPU event listener successful" << std::endl;
}
// Enable or disable a GPU device using Windows Device Manager
std::this_thread::sleep_for(std::chrono::seconds(15));
res = gpusChangedHandling->RemoveGPUsListEventListener(&gpuListener);
if (ADLX_SUCCEEDED (res))
{
std::cout << "Removal of GPU event listener successful" << std::endl;
}
}
}
void MainMenu()
{
std::cout << "\\tChoose one from the following options" << std::endl;
std::cout << "\\t->Press 1 to display GPU information" << std::endl;
std::cout << "\\t->Press 2 to add GPU event listener" << std::endl;
std::cout << "\\t->Press 3 to display GPU hybrid graphic type" << std::endl;
std::cout << "\\t->Press Q/q to terminate the application" << std::endl;
std::cout << "\\t->Press M/m to display the main menu options" << std::endl;
}
// Menu action control
void MenuControl(const IADLXGPUPtr& gpu)
{
int num = 0;
while ((num = getchar()) != 'q' && num != 'Q')
{
switch (num)
{
// Display GPU information
case '1':
ShowGPUInfo(gpu);
break;
// Add GPU change event listener
case '2':
AddGPUEventListener(gpu);
break;
// Display GPU hybrid graphic type
case '3':
ShowHybridGraphicType();
break;
// Display main menu options
case 'm':
case 'M':
MainMenu();
break;
default:
break;
}
}
}
// Wait for exit with error message
int WaitAndExit(const char* msg, const int retCode)
{
// Printout the message and pause to see it before returning the desired code
if (nullptr != msg)
std::cout << msg << std::endl;
system("pause");
return retCode;
}