2023-03-25 13:04:44 +08:00
|
|
|
#include "gpu.h"
|
2024-06-22 22:03:28 +08:00
|
|
|
#include "detection/gpu/gpu_driver_specific.h"
|
2023-03-25 13:04:44 +08:00
|
|
|
#include "util/windows/unicode.h"
|
|
|
|
|
#include "util/windows/registry.h"
|
|
|
|
|
|
2024-08-02 21:52:24 +08:00
|
|
|
#define INITGUID
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include <setupapi.h>
|
|
|
|
|
#include <devguid.h>
|
2023-03-25 13:04:44 +08:00
|
|
|
|
2024-08-02 21:52:24 +08:00
|
|
|
static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev)
|
2023-07-01 20:27:04 +08:00
|
|
|
{
|
2024-08-02 21:52:24 +08:00
|
|
|
if(*hdev)
|
|
|
|
|
SetupDiDestroyDeviceInfoList(*hdev);
|
2023-07-01 20:27:04 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-02 21:52:24 +08:00
|
|
|
#define FF_EMPTY_GUID_STR L"{00000000-0000-0000-0000-000000000000}"
|
2024-08-13 14:51:41 +08:00
|
|
|
enum { FF_GUID_STRLEN = sizeof(FF_EMPTY_GUID_STR) / sizeof(wchar_t) - 1 };
|
2024-08-02 21:52:24 +08:00
|
|
|
|
2023-06-24 10:59:53 +08:00
|
|
|
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
2023-03-25 13:04:44 +08:00
|
|
|
{
|
2024-08-02 21:52:24 +08:00
|
|
|
HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) =
|
|
|
|
|
SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, DIGCF_PRESENT);
|
|
|
|
|
|
|
|
|
|
if(hdev == INVALID_HANDLE_VALUE)
|
|
|
|
|
return "SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY) failed";
|
|
|
|
|
|
|
|
|
|
wchar_t regDirectxKey[] = L"SOFTWARE\\Microsoft\\DirectX\\" FF_EMPTY_GUID_STR;
|
|
|
|
|
const uint32_t regDirectxKeyPrefixLength = (uint32_t) strlen("SOFTWARE\\Microsoft\\DirectX\\");
|
|
|
|
|
wchar_t regControlVideoKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Video\\" FF_EMPTY_GUID_STR L"\\0000";
|
|
|
|
|
const uint32_t regControlVideoKeyPrefixLength = (uint32_t) strlen("SYSTEM\\CurrentControlSet\\Control\\Video\\");
|
|
|
|
|
|
|
|
|
|
SP_DEVINFO_DATA did = { .cbSize = sizeof(did) };
|
|
|
|
|
for (DWORD idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); ++idev)
|
2023-03-25 13:04:44 +08:00
|
|
|
{
|
2024-08-13 06:32:13 +08:00
|
|
|
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
|
|
|
|
|
ffStrbufInit(&gpu->vendor);
|
|
|
|
|
ffStrbufInit(&gpu->name);
|
|
|
|
|
ffStrbufInit(&gpu->driver);
|
2024-08-13 14:51:41 +08:00
|
|
|
ffStrbufInitStatic(&gpu->platformApi, "SetupAPI");
|
2024-08-13 06:32:13 +08:00
|
|
|
gpu->temperature = FF_GPU_TEMP_UNSET;
|
|
|
|
|
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
|
|
|
|
|
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
|
|
|
|
|
gpu->type = FF_GPU_TYPE_UNKNOWN;
|
|
|
|
|
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
|
|
|
|
|
gpu->deviceId = 0;
|
|
|
|
|
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
|
|
|
|
|
2024-08-13 14:51:41 +08:00
|
|
|
wchar_t buffer[256];
|
|
|
|
|
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_DEVICEDESC, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
|
|
|
|
|
ffStrbufSetWS(&gpu->name, buffer);
|
2024-08-13 06:32:13 +08:00
|
|
|
|
2024-08-13 14:51:41 +08:00
|
|
|
if (!SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_HARDWAREID, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
|
2024-08-02 21:52:24 +08:00
|
|
|
continue;
|
2023-03-25 13:04:44 +08:00
|
|
|
|
2024-08-13 06:32:13 +08:00
|
|
|
unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
|
2024-08-13 14:51:41 +08:00
|
|
|
swscanf(buffer, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId);
|
2024-08-13 06:32:13 +08:00
|
|
|
ffStrbufSetStatic(&gpu->vendor, ffGetGPUVendorString(vendorId));
|
|
|
|
|
|
2024-08-13 14:51:41 +08:00
|
|
|
FF_HKEY_AUTO_DESTROY hVideoIdKey = SetupDiOpenDevRegKey(hdev, &did, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
|
|
|
|
|
if (!hVideoIdKey) continue;
|
|
|
|
|
DWORD videoIdLength = sizeof(buffer);
|
|
|
|
|
if (RegGetValueW(hVideoIdKey, NULL, L"VideoID", RRF_RT_REG_SZ, NULL, buffer, &videoIdLength) != ERROR_SUCCESS)
|
|
|
|
|
continue;
|
2023-03-25 13:04:44 +08:00
|
|
|
|
2024-08-13 14:51:41 +08:00
|
|
|
if (videoIdLength != (FF_GUID_STRLEN + 1) * sizeof(wchar_t))
|
|
|
|
|
continue; // Should not happen
|
2024-08-02 21:52:24 +08:00
|
|
|
|
2024-08-13 14:51:41 +08:00
|
|
|
wmemcpy(regControlVideoKey + regControlVideoKeyPrefixLength, buffer, FF_GUID_STRLEN);
|
|
|
|
|
FF_HKEY_AUTO_DESTROY hRegControlVideoKey = NULL;
|
|
|
|
|
if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regControlVideoKey, &hRegControlVideoKey, NULL)) continue;
|
2023-03-25 14:19:58 +08:00
|
|
|
|
2024-08-13 14:51:41 +08:00
|
|
|
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN);
|
2024-08-02 21:52:24 +08:00
|
|
|
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
|
|
|
|
|
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL))
|
|
|
|
|
{
|
|
|
|
|
uint64_t dedicatedVideoMemory = 0;
|
|
|
|
|
if(ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &dedicatedVideoMemory, NULL))
|
|
|
|
|
gpu->type = dedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
|
2023-03-25 14:19:58 +08:00
|
|
|
|
2024-08-02 21:52:24 +08:00
|
|
|
uint64_t dedicatedSystemMemory, sharedSystemMemory;
|
|
|
|
|
if(ffRegReadUint64(hDirectxKey, L"DedicatedSystemMemory", &dedicatedSystemMemory, NULL) &&
|
|
|
|
|
ffRegReadUint64(hDirectxKey, L"SharedSystemMemory", &sharedSystemMemory, NULL))
|
2023-10-18 10:52:29 +08:00
|
|
|
{
|
2024-08-02 21:52:24 +08:00
|
|
|
gpu->dedicated.total = dedicatedVideoMemory + dedicatedSystemMemory;
|
|
|
|
|
gpu->shared.total = sharedSystemMemory;
|
2023-03-25 14:19:58 +08:00
|
|
|
}
|
2023-12-29 23:00:50 +08:00
|
|
|
|
2024-08-02 21:52:24 +08:00
|
|
|
ffRegReadUint64(hDirectxKey, L"AdapterLuid", &gpu->deviceId, NULL);
|
|
|
|
|
|
|
|
|
|
uint32_t featureLevel = 0;
|
|
|
|
|
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
|
|
|
|
|
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
|
|
|
|
|
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
|
|
|
|
|
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
|
|
|
|
|
}
|
2024-08-13 14:51:41 +08:00
|
|
|
else if (!ffRegReadUint64(hRegControlVideoKey, L"HardwareInformation.qwMemorySize", &gpu->dedicated.total, NULL))
|
2024-08-02 21:52:24 +08:00
|
|
|
{
|
|
|
|
|
uint32_t vmem = 0;
|
2024-08-13 14:51:41 +08:00
|
|
|
if (ffRegReadUint(hRegControlVideoKey, L"HardwareInformation.MemorySize", &vmem, NULL))
|
2024-08-02 21:52:24 +08:00
|
|
|
gpu->dedicated.total = vmem;
|
|
|
|
|
gpu->type = gpu->dedicated.total > 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gpu->vendor.length == 0)
|
|
|
|
|
{
|
2024-08-13 14:51:41 +08:00
|
|
|
ffRegReadStrbuf(hRegControlVideoKey, L"ProviderName", &gpu->vendor, NULL);
|
2024-08-02 21:52:24 +08:00
|
|
|
if (ffStrbufContainS(&gpu->vendor, "Intel"))
|
|
|
|
|
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
|
|
|
|
|
else if (ffStrbufContainS(&gpu->vendor, "NVIDIA"))
|
|
|
|
|
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
|
|
|
|
|
else if (ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
|
|
|
|
|
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
|
2023-03-25 13:04:44 +08:00
|
|
|
}
|
2023-10-27 21:05:03 +08:00
|
|
|
|
2023-12-21 14:53:35 +08:00
|
|
|
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
|
|
|
|
|
const char* dllName;
|
|
|
|
|
|
|
|
|
|
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName) && (options->temp || options->driverSpecific))
|
2023-12-20 00:49:56 +08:00
|
|
|
{
|
2024-08-02 21:52:24 +08:00
|
|
|
uint32_t pciBus, pciAddr;
|
|
|
|
|
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_BUSNUMBER, NULL, (PBYTE) &pciBus, sizeof(pciBus), NULL) &&
|
|
|
|
|
SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_ADDRESS, NULL, (PBYTE) &pciAddr, sizeof(pciAddr), NULL))
|
2023-12-20 00:49:56 +08:00
|
|
|
{
|
2024-08-02 21:52:24 +08:00
|
|
|
uint32_t pciDev = (pciAddr >> 16) & 0xFFFF;
|
|
|
|
|
uint32_t pciFunc = pciAddr & 0xFFFF;
|
2024-07-31 22:23:19 +08:00
|
|
|
|
2023-12-21 14:53:35 +08:00
|
|
|
detectFn(
|
2023-12-20 14:45:27 +08:00
|
|
|
&(FFGpuDriverCondition) {
|
2024-07-31 22:23:19 +08:00
|
|
|
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID
|
2024-08-02 21:52:24 +08:00
|
|
|
| (gpu->deviceId > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_LUID : 0)
|
|
|
|
|
| FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
|
2023-12-20 14:45:27 +08:00
|
|
|
.pciDeviceId = {
|
|
|
|
|
.deviceId = deviceId,
|
|
|
|
|
.vendorId = vendorId,
|
|
|
|
|
.subSystemId = subSystemId,
|
|
|
|
|
.revId = revId,
|
|
|
|
|
},
|
2024-07-31 22:23:19 +08:00
|
|
|
.pciBusId = {
|
|
|
|
|
.domain = 0,
|
2024-08-02 21:52:24 +08:00
|
|
|
.bus = pciBus,
|
|
|
|
|
.device = pciDev,
|
|
|
|
|
.func = pciFunc,
|
2024-07-31 22:23:19 +08:00
|
|
|
},
|
2023-12-20 19:09:18 +08:00
|
|
|
.luid = gpu->deviceId,
|
2023-12-21 14:53:35 +08:00
|
|
|
},
|
|
|
|
|
(FFGpuDriverResult) {
|
2023-12-20 14:45:27 +08:00
|
|
|
.temp = options->temp ? &gpu->temperature : NULL,
|
2023-12-20 14:59:27 +08:00
|
|
|
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
|
|
|
|
|
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
|
2024-08-01 13:54:03 +08:00
|
|
|
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
|
2023-12-20 19:09:18 +08:00
|
|
|
.type = &gpu->type,
|
2024-06-28 22:17:37 +08:00
|
|
|
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
|
2023-12-21 14:53:35 +08:00
|
|
|
},
|
|
|
|
|
dllName
|
2023-12-20 00:49:56 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-25 13:04:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|