diff --git a/src/detection/gpu/d3dkmthk.h b/src/detection/gpu/d3dkmthk.h index 06a89b756..d5ce5428e 100644 --- a/src/detection/gpu/d3dkmthk.h +++ b/src/detection/gpu/d3dkmthk.h @@ -99,8 +99,7 @@ typedef struct _D3DKMT_SEGMENTSIZEINFO { typedef struct _D3DKMT_ADAPTERTYPE { union { - struct - { + struct { UINT RenderSupported : 1; // WDDM 1.2, Windows 8 UINT DisplaySupported : 1; UINT SoftwareDevice : 1; @@ -181,8 +180,11 @@ typedef enum _KMTQUERYADAPTERINFOTYPE { KMTQAITYPE_NODEMETADATA = 25, // WDDM 2.0, Windows 10 KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31, KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, // WDDM 2.4, Windows 10 (1803) - // This reports the GUID string used by the adapter's registry key (DirectX and Video) + + KMTQAITYPE_NODEPERFDATA = 61, + KMTQAITYPE_ADAPTERPERFDATA = 62, } KMTQUERYADAPTERINFOTYPE; +// `KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID` reports the GUID string used by the adapter's registry key (DirectX and Video) typedef struct _D3DKMT_QUERYADAPTERINFO { D3DKMT_HANDLE hAdapter; @@ -199,20 +201,9 @@ typedef enum _D3DKMT_MEMORY_SEGMENT_GROUP { } D3DKMT_MEMORY_SEGMENT_GROUP; typedef enum _D3DKMT_QUERYSTATISTICS_TYPE { - D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER = 10, // WDDM 2.4, Windows 10 April 2018 Update (version 1803) D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE = 17, // WDDM 3.1, Windows 11 2022 Update (version 22H2) - D3DKMT_QUERYSTATISTICS_NODE2 = 18, } D3DKMT_QUERYSTATISTICS_TYPE; -typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER { - ULONG PhysicalAdapterIndex; -} D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER; - -typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_NODE2 { - UINT16 PhysicalAdapterIndex; - UINT16 NodeOrdinal; -} D3DKMT_QUERYSTATISTICS_QUERY_NODE2; - typedef struct _D3DKMT_ADAPTER_PERFDATA { UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain D3DKMT_ALIGN64 ULONGLONG MemoryFrequency; // out: Clock frequency of the memory in hertz @@ -226,33 +217,6 @@ typedef struct _D3DKMT_ADAPTER_PERFDATA { UCHAR PowerStateOverride; // out: Overrides dxgkrnls power view of linked adapters. } D3DKMT_ADAPTER_PERFDATA; -typedef struct _D3DKMT_ADAPTER_PERFDATACAPS { - UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain - D3DKMT_ALIGN64 ULONGLONG MaxMemoryBandwidth; // out: Max memory bandwidth in bytes for 1 second - D3DKMT_ALIGN64 ULONGLONG MaxPCIEBandwidth; // out: Max pcie bandwidth in bytes for 1 second - ULONG MaxFanRPM; // out: Max fan rpm - ULONG TemperatureMax; // out: Max temperature before damage levels - ULONG TemperatureWarning; // out: The temperature level where throttling begins. -} D3DKMT_ADAPTER_PERFDATACAPS; - -#define DXGK_MAX_GPUVERSION_NAME_LENGTH 32 - -typedef struct _D3DKMT_GPUVERSION { - UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain - WCHAR BiosVersion[DXGK_MAX_GPUVERSION_NAME_LENGTH]; // out: The gpu bios version - WCHAR GpuArchitecture[DXGK_MAX_GPUVERSION_NAME_LENGTH]; // out: The gpu architectures name. -} D3DKMT_GPUVERSION; - -typedef struct _D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION { - D3DKMT_ADAPTER_PERFDATA AdapterPerfData; - D3DKMT_ADAPTER_PERFDATACAPS AdapterPerfDataCaps; - D3DKMT_GPUVERSION GpuVersion; -} D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION; - -typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION { - D3DKMT_ALIGN64 UINT64 Reserved[34]; -} D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION; - typedef struct _D3DKMT_NODE_PERFDATA { UINT32 NodeOrdinal; // in: Node ordinal of the requested engine. UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain @@ -266,13 +230,6 @@ typedef struct _D3DKMT_NODE_PERFDATA { D3DKMT_ALIGN64 ULONGLONG MaxTransitionLatency; // out: Max transition latency to change the frequency in 100 nanoseconds } D3DKMT_NODE_PERFDATA; -typedef struct _D3DKMT_QUERYSTATISTICS_NODE_INFORMATION { - D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; // Global statistics - D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; // Statistics for system thread - D3DKMT_NODE_PERFDATA NodePerfData; - UINT32 Reserved[3]; -} D3DKMT_QUERYSTATISTICS_NODE_INFORMATION; - typedef struct _D3DKMT_QUERYSTATISTICS_MEMORY_USAGE { D3DKMT_ALIGN64 UINT64 AllocatedBytes; D3DKMT_ALIGN64 UINT64 FreeBytes; @@ -282,8 +239,6 @@ typedef struct _D3DKMT_QUERYSTATISTICS_MEMORY_USAGE { } D3DKMT_QUERYSTATISTICS_MEMORY_USAGE; typedef union _D3DKMT_QUERYSTATISTICS_RESULT { - D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION PhysAdapterInformation; - D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation; D3DKMT_QUERYSTATISTICS_MEMORY_USAGE SegmentGroupUsageInformation; uint8_t Padding[776]; } D3DKMT_QUERYSTATISTICS_RESULT; @@ -300,9 +255,7 @@ typedef struct _D3DKMT_QUERYSTATISTICS { D3DKMT_QUERYSTATISTICS_RESULT QueryResult; // out: requested data union { - D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER QueryPhysAdapter; // in: id of physical adapter to get statistics for D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT_GROUP_USAGE QuerySegmentGroupUsage; - D3DKMT_QUERYSTATISTICS_QUERY_NODE2 QueryNode2; // in: id of node to get statistics for }; } D3DKMT_QUERYSTATISTICS; static_assert(sizeof(D3DKMT_QUERYSTATISTICS) == @@ -328,10 +281,10 @@ typedef enum { DXGK_ENGINE_TYPE_VIDEO_CODEC, DXGK_ENGINE_TYPE_MAX } DXGK_ENGINE_TYPE; + typedef struct _DXGK_NODEMETADATA_FLAGS { union { - struct - { + struct { UINT ContextSchedulingSupported : 1; // WDDM 2.2 UINT RingBufferFenceRelease : 1; // WDDM 2.5 UINT SupportTrackedWorkload : 1; diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index f3faf9871..37e603b82 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -1,270 +1,163 @@ -#include "gpu.h" +#include "detection/gpu/gpu.h" #include "detection/gpu/gpu_driver_specific.h" #include "common/windows/unicode.h" -#include "common/windows/registry.h" -#include "common/mallocHelper.h" #include "common/debug.h" -#include "common/windows/nt.h" -#include -#include +#include #include "d3dkmthk.h" -#define FF_EMPTY_GUID_STR L"{00000000-0000-0000-0000-000000000000}" -enum { FF_GUID_STRLEN = sizeof(FF_EMPTY_GUID_STR) / sizeof(wchar_t) - 1 }; - -wchar_t regDirectxKey[] = L"SOFTWARE\\Microsoft\\DirectX\\" FF_EMPTY_GUID_STR; -const uint32_t regDirectxKeyPrefixLength = (uint32_t) __builtin_strlen("SOFTWARE\\Microsoft\\DirectX\\"); -wchar_t regDriverKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Class\\" FF_EMPTY_GUID_STR L"\\0000"; -const uint32_t regDriverKeyPrefixLength = (uint32_t) __builtin_strlen("SYSTEM\\CurrentControlSet\\Control\\Class\\"); - -#define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in - -static inline void wrapRegCloseKey(HKEY* phKey) { - if (*phKey) { - RegCloseKey(*phKey); - } -} -#define FF_HKEY_AUTO_DESTROY __attribute__((__cleanup__(wrapRegCloseKey))) - -const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus) { - FF_DEBUG("Starting GPU detection"); - - ULONG devIdListSize = 0; - if (CM_Get_Device_ID_List_SizeW(&devIdListSize, GUID_DEVCLASS_DISPLAY_STRING, CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT) != CR_SUCCESS || devIdListSize <= 1) { - FF_DEBUG("No display devices found, list size: %lu", devIdListSize); - return "No display devices found"; +const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) { + D3DKMT_ADAPTERINFO adapters[64]; + D3DKMT_ENUMADAPTERS2 enumAdapters = { + .NumAdapters = ARRAY_SIZE(adapters), + .pAdapters = adapters, + }; + NTSTATUS status = D3DKMTEnumAdapters2(&enumAdapters); + if (!NT_SUCCESS(status)) { + FF_DEBUG("D3DKMTEnumAdapters2 failed: %s", ffDebugNtStatus(status)); + return "Failed to enumerate adapters with D3DKMTEnumAdapters2"; } - FF_DEBUG("Found device ID list size: %lu", devIdListSize); + FF_DEBUG("D3DKMTEnumAdapters2 succeeded, adapter count: %" PRIu32, (uint32_t) enumAdapters.NumAdapters); - FF_AUTO_FREE DEVINSTID_W devIdList = malloc(devIdListSize * sizeof(*devIdList)); + for (uint32_t i = 0; i < enumAdapters.NumAdapters; i++) { + const D3DKMT_ADAPTERINFO* adapter = &adapters[i]; + FF_DEBUG("Processing adapter #%u", i); - if (CM_Get_Device_ID_ListW(GUID_DEVCLASS_DISPLAY_STRING, devIdList, devIdListSize, CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT) != CR_SUCCESS) { - FF_DEBUG("CM_Get_Device_ID_ListW failed"); - return "CM_Get_Device_ID_ListW failed"; - } - - FF_MAYBE_UNUSED int deviceCount = 0; - for (wchar_t* devId = devIdList; *devId; devId += wcslen(devId) + 1) { - FF_DEBUG("Processing device ID: %ls", devId); - - DEVINST devInst = 0; - - if (CM_Locate_DevNodeW(&devInst, devId, CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS) { - FF_DEBUG("Failed to get device instance ID or locate device node"); + D3DKMT_ADAPTERTYPE adapterType; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_ADAPTERTYPE, + .pPrivateDriverData = &adapterType, + .PrivateDriverDataSize = sizeof(adapterType), + }); + if (!NT_SUCCESS(status)) { + FF_DEBUG("KMTQAITYPE_ADAPTERTYPE query failed for adapter #%u: %s", i, ffDebugNtStatus(status)); continue; } - FF_DEBUG("Device instance ID: %lu", devInst); - - for (wchar_t* p = devId; *p; p++) { - if (*p >= L'a' && *p <= L'z') { - *p -= L'a' - L'A'; - } + if (adapterType.SoftwareDevice) { + FF_DEBUG("Skipping software adapter #%u", i); + goto close_adapter; } - FFGPUResult* gpu = (FFGPUResult*) ffListAdd(gpus); - deviceCount++; - FF_DEBUG("Added GPU #%d to list", deviceCount); - + FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus); ffStrbufInit(&gpu->vendor); ffStrbufInit(&gpu->name); ffStrbufInit(&gpu->driver); + ffStrbufInit(&gpu->platformApi); ffStrbufInit(&gpu->memoryType); - ffStrbufInitStatic(&gpu->platformApi, "CM API"); gpu->index = FF_GPU_INDEX_UNSET; 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; + gpu->type = adapterType.HybridIntegrated + ? FF_GPU_TYPE_INTEGRATED + : adapterType.HybridDiscrete + ? FF_GPU_TYPE_DISCRETE + : FF_GPU_TYPE_UNKNOWN; - unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0; - if (swscanf(devId, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId) == 4) { - FF_DEBUG("Parsed PCI IDs - Vendor: 0x%x, Device: 0x%x, SubSystem: 0x%x, Rev: 0x%x", vendorId, deviceId, subSystemId, revId); - ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId)); + const char* vendorStr = NULL; + + D3DKMT_QUERY_DEVICE_IDS deviceIds = { .PhysicalAdapterIndex = 0 }; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_PHYSICALADAPTERDEVICEIDS, + .pPrivateDriverData = &deviceIds, + .PrivateDriverDataSize = sizeof(deviceIds), + }); + if (NT_SUCCESS(status)) { + vendorStr = ffGPUGetVendorString(deviceIds.DeviceIds.VendorID); + ffStrbufSetStatic(&gpu->vendor, vendorStr); + FF_DEBUG("Adapter #%u vendor/device IDs: vendor=0x%04x device=0x%04x", + i, + deviceIds.DeviceIds.VendorID, + deviceIds.DeviceIds.DeviceID); } else { - FF_DEBUG("Failed to parse PCI device information from instance ID"); + deviceIds.DeviceIds.VendorID = -1u; + FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS query failed for adapter #%u: %s", i, ffDebugNtStatus(status)); } - uint32_t pciBus = 0, pciAddr = 0, pciDev = 0, pciFunc = 0; - - ULONG pciBufLen = sizeof(pciBus); - if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_BUSNUMBER, NULL, &pciBus, &pciBufLen, 0) == CR_SUCCESS) { - pciBufLen = sizeof(pciAddr); - if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_ADDRESS, NULL, &pciAddr, &pciBufLen, 0) == CR_SUCCESS) { - pciDev = (pciAddr >> 16) & 0xFFFF; - pciFunc = pciAddr & 0xFFFF; - gpu->deviceId = ffGPUPciAddr2Id(0, pciBus, pciDev, pciFunc); - pciAddr = 1; // Set to 1 to indicate that the device is a PCI device - FF_DEBUG("PCI location - Bus: %u, Device: %u, Function: %u, DeviceID: %llu", pciBus, pciDev, pciFunc, gpu->deviceId); - } else { - FF_DEBUG("Failed to get PCI address"); - } + D3DKMT_ADAPTERADDRESS adapterAddress = {}; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_ADAPTERADDRESS, + .pPrivateDriverData = &adapterAddress, + .PrivateDriverDataSize = sizeof(adapterAddress), + }); + if (NT_SUCCESS(status)) { + gpu->deviceId = ffGPUPciAddr2Id(0, adapterAddress.BusNumber, adapterAddress.DeviceNumber, adapterAddress.FunctionNumber); + FF_DEBUG("Adapter #%u PCI address: bus=%u device=%u function=%u", + i, + adapterAddress.BusNumber, + adapterAddress.DeviceNumber, + adapterAddress.FunctionNumber); } else { - FF_DEBUG("Failed to get PCI bus number"); + adapterAddress.BusNumber = -1u; + gpu->deviceId = ffGPUGeneral2Id(((uint64_t) adapter->AdapterLuid.HighPart << 32) | (uint64_t) adapter->AdapterLuid.LowPart); + FF_DEBUG("KMTQAITYPE_ADAPTERADDRESS query failed for adapter #%u, fallback to LUID-based deviceId: %s", + i, + ffDebugNtStatus(status)); } - uint64_t adapterLuid = 0; - - FF_HKEY_AUTO_DESTROY HKEY hVideoIdKey = NULL; - - wchar_t buffer[256]; - ULONG bufferLen = 0; - - FF_DEBUG("Get device description as device name"); - bufferLen = sizeof(buffer); - if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DEVICEDESC, NULL, buffer, &bufferLen, 0) == CR_SUCCESS) { - ffStrbufSetWS(&gpu->name, buffer); - FF_DEBUG("Found device description: %s", gpu->name.chars); + D3DKMT_UMD_DRIVER_VERSION umdDriverVersion; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_UMD_DRIVER_VERSION, + .pPrivateDriverData = &umdDriverVersion, + .PrivateDriverDataSize = sizeof(umdDriverVersion), + }); + if (NT_SUCCESS(status)) { + ffStrbufSetF(&gpu->driver, + "%u.%u.%u.%u", + (uint32_t) (umdDriverVersion.DriverVersion.QuadPart >> 48ul & 0xFFFF), + (uint32_t) (umdDriverVersion.DriverVersion.QuadPart >> 32ul & 0xFFFF), + (uint32_t) (umdDriverVersion.DriverVersion.QuadPart >> 16ul & 0xFFFF), + (uint32_t) (umdDriverVersion.DriverVersion.QuadPart >> 0ul & 0xFFFF)); + FF_DEBUG("Adapter #%u UMD driver version: %08" PRIX64, i, (uint64_t) umdDriverVersion.DriverVersion.QuadPart); } else { - FF_DEBUG("Failed to get device description"); + FF_DEBUG("KMTQAITYPE_UMD_DRIVER_VERSION query failed for adapter #%u: %s", i, ffDebugNtStatus(status)); } - if (wcsncmp(devId, L"SWD\\", 4) == 0 || wcsncmp(devId, L"ROOT\\DISPLAY\\", 13) == 0) { - FF_DEBUG("Skipping virtual devices to avoid duplicates"); - continue; - } - - if (CM_Open_DevNode_Key(devInst, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hVideoIdKey, CM_REGISTRY_HARDWARE) == CR_SUCCESS) { - FF_DEBUG("Opened device node registry key"); - bufferLen = sizeof(buffer); - if (RegGetValueW(hVideoIdKey, NULL, L"VideoID", RRF_RT_REG_SZ, NULL, buffer, &bufferLen) == ERROR_SUCCESS && - bufferLen == (FF_GUID_STRLEN + 1) * sizeof(wchar_t)) { - FF_DEBUG("Found VideoID: %ls", buffer); - wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN); - FF_AUTO_CLOSE_FD HANDLE hDirectxKey = NULL; - if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL)) { - FF_DEBUG("Opened DirectX registry key"); - - if (gpu->vendor.length == 0) { - uint32_t vendorId = 0; - if (ffRegReadUint(hDirectxKey, L"VendorId", &vendorId, NULL) && vendorId) { - FF_DEBUG("Found vendor ID from DirectX registry: 0x%x", vendorId); - ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId)); - } - } - - if (gpu->name.length == 0) { - FF_DEBUG("Trying to get GPU name from DirectX registry"); - if (ffRegReadStrbuf(hDirectxKey, L"Description", &gpu->name, NULL)) { - FF_DEBUG("Found GPU description: %s", gpu->name.chars); - } - } - - if (ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &gpu->dedicated.total, NULL)) { - FF_DEBUG("Found dedicated video memory: %llu bytes", gpu->dedicated.total); - } - - if (ffRegReadUint64(hDirectxKey, L"DedicatedSystemMemory", &gpu->shared.total, NULL)) { - FF_DEBUG("Found dedicated system memory: %llu bytes", gpu->shared.total); - uint64_t sharedSystemMemory = 0; - if (ffRegReadUint64(hDirectxKey, L"SharedSystemMemory", &sharedSystemMemory, NULL)) { - gpu->shared.total += sharedSystemMemory; - FF_DEBUG("Added shared system memory: %llu bytes, total shared: %llu bytes", sharedSystemMemory, gpu->shared.total); - } - } - - if (ffRegReadUint64(hDirectxKey, L"AdapterLuid", &adapterLuid, NULL)) { - FF_DEBUG("Found adapter LUID: %llu", adapterLuid); - if (!gpu->deviceId) { - gpu->deviceId = ffGPUGeneral2Id(adapterLuid); - } - } - - uint32_t featureLevel = 0; - if (ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel) { - FF_DEBUG("Found D3D12 feature level: 0x%x", featureLevel); - ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8); - } else if (ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel) { - FF_DEBUG("Found D3D11 feature level: 0x%x", featureLevel); - ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8); - } - - uint64_t driverVersion = 0; - if (ffRegReadUint64(hDirectxKey, L"DriverVersion", &driverVersion, NULL) && driverVersion) { - FF_DEBUG("Found driver version: %llu", driverVersion); - ffStrbufSetF(&gpu->driver, "%u.%u.%u.%u", (unsigned) (driverVersion >> 48) & 0xFFFF, (unsigned) (driverVersion >> 32) & 0xFFFF, (unsigned) (driverVersion >> 16) & 0xFFFF, (unsigned) (driverVersion >> 0) & 0xFFFF); - } - } else { - FF_DEBUG("Failed to open DirectX registry key"); - } - } else { - FF_DEBUG("Failed to get VideoID or invalid buffer length"); - } + D3DKMT_DRIVERVERSION wddmVersion = KMT_DRIVERVERSION_WDDM_3_0; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_DRIVERVERSION, + .pPrivateDriverData = &wddmVersion, + .PrivateDriverDataSize = sizeof(wddmVersion), + }); + if (NT_SUCCESS(status)) { + ffStrbufSetF(&gpu->platformApi, "WDDM %u.%u", (uint32_t) wddmVersion / 1000, ((uint32_t) wddmVersion % 1000) / 100); + FF_DEBUG("Adapter #%u WDDM version: %u", i, (uint32_t) wddmVersion); } else { - FF_DEBUG("Failed to open device node registry key"); - } - - if (gpu->vendor.length == 0 || gpu->name.length == 0 || gpu->driver.length == 0 || gpu->dedicated.total == FF_GPU_VMEM_SIZE_UNSET) { - FF_DEBUG("Trying fallback registry method for vendor/name etc."); - bufferLen = sizeof(buffer); - if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DRIVER, NULL, buffer, &bufferLen, 0) == CR_SUCCESS && - bufferLen == (FF_GUID_STRLEN + strlen("\\0000") + 1) * 2) { - FF_DEBUG("Found driver GUID: %ls", buffer); - wmemcpy(regDriverKey + regDriverKeyPrefixLength, buffer, FF_GUID_STRLEN + strlen("\\0000")); - FF_AUTO_CLOSE_FD HANDLE hRegDriverKey = NULL; - if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDriverKey, &hRegDriverKey, NULL)) { - FF_DEBUG("Opened driver registry key"); - - if (gpu->vendor.length == 0 && ffRegReadStrbuf(hRegDriverKey, L"ProviderName", &gpu->vendor, NULL)) { - FF_DEBUG("Found provider name: %s", gpu->vendor.chars); - 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); - } - } - if (gpu->name.length == 0 && ffRegReadStrbuf(hRegDriverKey, L"DriverDesc", &gpu->name, NULL)) { - FF_DEBUG("Found driver description: %s", gpu->name.chars); - } - if (gpu->driver.length == 0 && ffRegReadStrbuf(hRegDriverKey, L"DriverVersion", &gpu->driver, NULL)) { - FF_DEBUG("Found driver version: %s", gpu->driver.chars); - } - if (gpu->dedicated.total == FF_GPU_VMEM_SIZE_UNSET) { - if (!ffRegReadUint64(hRegDriverKey, L"HardwareInformation.qwMemorySize", &gpu->dedicated.total, NULL)) { - uint32_t memorySize = 0; - if (ffRegReadUint(hRegDriverKey, L"HardwareInformation.MemorySize", &memorySize, NULL)) { - gpu->dedicated.total = memorySize; - FF_DEBUG("Found memory size from hardware info: %u bytes", memorySize); - } - } else { - FF_DEBUG("Found qwMemorySize from hardware info: %llu bytes", gpu->dedicated.total); - } - } - } else { - FF_DEBUG("Failed to open driver registry key"); - } - } else { - FF_DEBUG("Failed to get driver GUID or invalid buffer length"); - } + ffStrbufSetStatic(&gpu->platformApi, "WDDM"); + FF_DEBUG("KMTQAITYPE_DRIVERVERSION query failed for adapter #%u", i); } __typeof__(&ffDetectNvidiaGpuInfo) detectFn; const char* dllName; - if (options->driverSpecific && getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName)) { FF_DEBUG("Calling driver-specific detection function for vendor: %s, DLL: %s", gpu->vendor.chars, dllName); FF_MAYBE_UNUSED const char* error = detectFn( &(FFGpuDriverCondition) { - .type = (deviceId > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID : 0) | (adapterLuid > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_LUID : 0) | (pciAddr > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID : 0), + .type = FF_GPU_DRIVER_CONDITION_TYPE_LUID | + (deviceIds.DeviceIds.VendorID != -1u ? FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID : 0) | + (adapterAddress.BusNumber != -1u ? FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID : 0), .pciDeviceId = { - .deviceId = deviceId, - .vendorId = vendorId, - .subSystemId = subSystemId, - .revId = revId, + .deviceId = deviceIds.DeviceIds.DeviceID, + .vendorId = deviceIds.DeviceIds.VendorID, + .subSystemId = deviceIds.DeviceIds.SubSystemID, + .revId = deviceIds.DeviceIds.RevisionID, }, .pciBusId = { .domain = 0, - .bus = pciBus, - .device = pciDev, - .func = pciFunc, + .bus = adapterAddress.BusNumber, + .device = adapterAddress.DeviceNumber, + .func = adapterAddress.FunctionNumber, }, - .luid = adapterLuid, + .luid = ((uint64_t) adapter->AdapterLuid.HighPart << 32) | (uint64_t) adapter->AdapterLuid.LowPart, }, (FFGpuDriverResult) { .index = &gpu->index, @@ -284,123 +177,139 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* FF_DEBUG("No driver-specific detection function found for vendor: %s", gpu->vendor.chars); } - if (gpu->type == FF_GPU_TYPE_UNKNOWN && adapterLuid > 0) { - FF_DEBUG("Trying to determine GPU type using D3DKMT APIs"); - D3DKMT_OPENADAPTERFROMLUID openAdapterFromLuid = { .AdapterLuid = *(LUID*) &adapterLuid }; - if (NT_SUCCESS(D3DKMTOpenAdapterFromLuid(&openAdapterFromLuid))) { - FF_DEBUG("Successfully opened adapter from LUID"); - - D3DKMT_ADAPTERTYPE adapterType = {}; - D3DKMT_QUERYADAPTERINFO queryAdapterInfo = { - .hAdapter = openAdapterFromLuid.hAdapter, - .Type = KMTQAITYPE_ADAPTERTYPE, // Windows 8 and later - .pPrivateDriverData = &adapterType, - .PrivateDriverDataSize = sizeof(adapterType), - }; - if (NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) { - FF_DEBUG("Queried adapter type - HybridDiscrete: %d, HybridIntegrated: %d", adapterType.HybridDiscrete, adapterType.HybridIntegrated); - if (adapterType.HybridDiscrete) { - gpu->type = FF_GPU_TYPE_DISCRETE; - } else if (adapterType.HybridIntegrated) { - gpu->type = FF_GPU_TYPE_INTEGRATED; - } - } else { - FF_DEBUG("Failed to query adapter type"); - } - - if (gpu->frequency == FF_GPU_FREQUENCY_UNSET && ffIsWindows11OrGreater()) { - FF_DEBUG("Trying to get GPU frequency information"); - for (ULONG nodeIdx = 0;; nodeIdx++) { - D3DKMT_NODEMETADATA nodeMetadata = { - .NodeOrdinalAndAdapterIndex = (0 << 16) | nodeIdx, - }; - queryAdapterInfo = (D3DKMT_QUERYADAPTERINFO) { - .hAdapter = openAdapterFromLuid.hAdapter, - .Type = KMTQAITYPE_NODEMETADATA, // Windows 10 and later - .pPrivateDriverData = &nodeMetadata, - .PrivateDriverDataSize = sizeof(nodeMetadata), - }; - if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) { - FF_DEBUG("No more nodes to query (index %lu)", nodeIdx); - break; - } - if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D) { - FF_DEBUG("Skipping node %lu (not 3D engine)", nodeIdx); - continue; - } - - D3DKMT_QUERYSTATISTICS queryStatistics = { - .Type = D3DKMT_QUERYSTATISTICS_NODE2, // Windows 11 (22H2) and later - .AdapterLuid = *(LUID*) &adapterLuid, - .QueryNode2 = { .PhysicalAdapterIndex = 0, .NodeOrdinal = (UINT16) nodeIdx }, - }; - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { - gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000); - FF_DEBUG("Found GPU frequency: %u MHz", gpu->frequency); - break; - } else { - FF_DEBUG("Failed to query node statistics for node %lu", nodeIdx); - } - } - } - - D3DKMT_CLOSEADAPTER closeAdapter = { .hAdapter = openAdapterFromLuid.hAdapter }; - (void) D3DKMTCloseAdapter(&closeAdapter); - openAdapterFromLuid.hAdapter = (D3DKMT_HANDLE) {}; - FF_DEBUG("Closed adapter handle"); + if (gpu->name.length == 0) { + D3DKMT_ADAPTERREGISTRYINFO registryInfo; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_ADAPTERREGISTRYINFO, + .pPrivateDriverData = ®istryInfo, + .PrivateDriverDataSize = sizeof(registryInfo), + }); + if (NT_SUCCESS(status)) { + ffStrbufSetWS(&gpu->name, registryInfo.AdapterString); + FF_DEBUG("Adapter #%u adapter string: %s", i, gpu->name.chars); } else { - FF_DEBUG("Failed to open adapter from LUID"); + FF_DEBUG("KMTQAITYPE_ADAPTERREGISTRYINFO query failed for adapter #%u: %s", i, ffDebugNtStatus(status)); } + } - if (options->temp && gpu->temperature == FF_GPU_TEMP_UNSET && ffIsWindows10OrGreater()) { - FF_DEBUG("Trying to get GPU temperature"); - D3DKMT_QUERYSTATISTICS queryStatistics = { - .Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER, // Windows 10 (1803) and later - .AdapterLuid = *(LUID*) &adapterLuid, - .QueryPhysAdapter = { .PhysicalAdapterIndex = 0 }, - }; - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)) && - queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature != 0) { - gpu->temperature = queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature / 10.0; - FF_DEBUG("Found GPU temperature: %.1f°C", gpu->temperature); - } else { - FF_DEBUG("Failed to get GPU temperature or temperature is 0"); - } - } - - if (options->driverSpecific && gpu->dedicated.used == FF_GPU_VMEM_SIZE_UNSET && ffIsWindows11OrGreater()) { - FF_DEBUG("Trying to get used video memory from D3DKMT method"); + if (gpu->dedicated.total == FF_GPU_VMEM_SIZE_UNSET && gpu->shared.total == FF_GPU_VMEM_SIZE_UNSET) { + if (wddmVersion >= KMT_DRIVERVERSION_WDDM_3_1 && options->driverSpecific) { + // Supports memory usage query; requires Windows 11 (22H2) or later D3DKMT_QUERYSTATISTICS queryStatistics = { .Type = D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE, - .AdapterLuid = *(LUID*) &adapterLuid, + .AdapterLuid = adapter->AdapterLuid, .QuerySegmentGroupUsage = { .PhysicalAdapterIndex = 0, .SegmentGroup = D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL, }, }; - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { + status = D3DKMTQueryStatistics(&queryStatistics); + if (NT_SUCCESS(status)) { D3DKMT_QUERYSTATISTICS_MEMORY_USAGE* info = &queryStatistics.QueryResult.SegmentGroupUsageInformation; uint64_t used = info->AllocatedBytes + info->ModifiedBytes + info->StandbyBytes; uint64_t total = used + info->FreeBytes + info->ZeroBytes; gpu->dedicated.used = used; gpu->dedicated.total = total; - - FF_DEBUG("Found local memory size %llu / %llu", used, total); + FF_DEBUG("Adapter #%u local memory usage: used=%" PRIu64 " total=%" PRIu64, i, used, total); } else { - FF_DEBUG("Failed to query segment group usage for local memory"); + FF_DEBUG("D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE (LOCAL) failed for adapter #%u: %s", + i, + ffDebugNtStatus(status)); } queryStatistics.QuerySegmentGroupUsage.SegmentGroup = D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL; - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { + status = D3DKMTQueryStatistics(&queryStatistics); + if (NT_SUCCESS(status)) { D3DKMT_QUERYSTATISTICS_MEMORY_USAGE* info = &queryStatistics.QueryResult.SegmentGroupUsageInformation; uint64_t used = info->AllocatedBytes + info->ModifiedBytes + info->StandbyBytes; uint64_t total = used + info->FreeBytes + info->ZeroBytes; gpu->shared.used = used; gpu->shared.total = total; - - FF_DEBUG("Found non-local memory size %llu / %llu", used, total); + FF_DEBUG("Adapter #%u non-local memory usage: used=%" PRIu64 " total=%" PRIu64, i, used, total); } else { - FF_DEBUG("Failed to query segment group usage for non-local memory"); + FF_DEBUG("D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE (NON_LOCAL) failed for adapter #%u: %s", + i, + ffDebugNtStatus(status)); + } + } else { + // Supports basic segment (total) size query + D3DKMT_SEGMENTSIZEINFO segmentSizeInfo = {}; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_GETSEGMENTSIZE, + .pPrivateDriverData = &segmentSizeInfo, + .PrivateDriverDataSize = sizeof(segmentSizeInfo), + }); + if (NT_SUCCESS(status)) { + FF_DEBUG("Adapter #%u segment size - DedicatedVideoMemorySize: %" PRIu64 + ", DedicatedSystemMemorySize: %" PRIu64 ", SharedSystemMemorySize: %" PRIu64, + i, + (uint64_t) segmentSizeInfo.DedicatedVideoMemorySize, + (uint64_t) segmentSizeInfo.DedicatedSystemMemorySize, + (uint64_t) segmentSizeInfo.SharedSystemMemorySize); + gpu->dedicated.total = segmentSizeInfo.DedicatedVideoMemorySize; + gpu->shared.total = segmentSizeInfo.DedicatedSystemMemorySize + segmentSizeInfo.SharedSystemMemorySize; + } else { + FF_DEBUG("Failed to query segment size information for adapter #%u: %s", i, ffDebugNtStatus(status)); + } + } + } + + if (wddmVersion >= KMT_DRIVERVERSION_WDDM_2_4) { + if (gpu->frequency == FF_GPU_FREQUENCY_UNSET) { + for (uint32_t nodeIdx = 0;; nodeIdx++) { + D3DKMT_NODEMETADATA nodeMetadata = { + .NodeOrdinalAndAdapterIndex = (0 << 16) | nodeIdx, + }; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_NODEMETADATA, + .pPrivateDriverData = &nodeMetadata, + .PrivateDriverDataSize = sizeof(nodeMetadata), + }); + if (!NT_SUCCESS(status)) { break; } + + if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D) { continue; } + + D3DKMT_NODE_PERFDATA nodePerfData = { + .NodeOrdinal = nodeIdx, + .PhysicalAdapterIndex = 0, + }; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_NODEPERFDATA, + .pPrivateDriverData = &nodePerfData, + .PrivateDriverDataSize = sizeof(nodePerfData), + }); + if (NT_SUCCESS(status)) { + gpu->frequency = (uint32_t) (nodePerfData.MaxFrequency / 1000 / 1000); + FF_DEBUG("Adapter #%u max graphics frequency: %u MHz", i, gpu->frequency); + break; + } else { + FF_DEBUG("Failed to query node performance data for adapter #%u node #%u: %s", + i, + nodeIdx, + ffDebugNtStatus(status)); + } + } + } + + if (options->temp && gpu->temperature == FF_GPU_TEMP_UNSET) { + D3DKMT_ADAPTER_PERFDATA adapterPerfData = { + .PhysicalAdapterIndex = 0, + }; + status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { + .hAdapter = adapter->hAdapter, + .Type = KMTQAITYPE_ADAPTERPERFDATA, + .pPrivateDriverData = &adapterPerfData, + .PrivateDriverDataSize = sizeof(adapterPerfData), + }); + if (NT_SUCCESS(status)) { + gpu->temperature = adapterPerfData.Temperature / 10.0; + FF_DEBUG("Adapter #%u temperature: %.1f°C", i, gpu->temperature); + } else { + FF_DEBUG("Failed to query temperature for adapter #%u: %s", i, ffDebugNtStatus(status)); } } } @@ -414,9 +323,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpu->type = FF_GPU_TYPE_DISCRETE; } } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) { - gpu->type = FF_GPU_TYPE_DISCRETE; - } + if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) { gpu->type = FF_GPU_TYPE_DISCRETE; } } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) { // 0000:00:02.0 is reserved for Intel integrated graphics gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; @@ -424,18 +331,33 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* if (gpu->type != FF_GPU_TYPE_UNKNOWN) { FF_DEBUG("Determined GPU type based on vendor (%s) and name: %u", gpu->vendor.chars, gpu->type); - } else if (ffIsWindows10OrGreater()) { + } +#if _WIN32 + else if (ffIsWindows10OrGreater()) { const char* ffGPUDetectTypeWithDXCore(LUID adapterLuid, FFGPUResult * gpu); - FF_MAYBE_UNUSED const char* error = ffGPUDetectTypeWithDXCore(*(LUID*) &adapterLuid, gpu); + FF_MAYBE_UNUSED const char* error = ffGPUDetectTypeWithDXCore(adapter->AdapterLuid, gpu); FF_DEBUG("DXCore GPU type detection result: %s", error ?: "Success"); - } else { + } +#endif + else { FF_DEBUG("Unable to determine GPU type by any method for this adapter"); } } - FF_DEBUG("Completed processing GPU #%d - Vendor: %s, Name: %s, Type: %d", deviceCount, gpu->vendor.chars, gpu->name.chars, gpu->type); + FF_DEBUG("Adapter #%u summary: name='%s', vendor='%s', type=%u, deviceId=%" PRIu64, + i, + gpu->name.length ? gpu->name.chars : "unknown", + gpu->vendor.length ? gpu->vendor.chars : "unknown", + (uint32_t) gpu->type, + (uint64_t) gpu->deviceId); + + status = D3DKMTCloseAdapter(&(D3DKMT_CLOSEADAPTER) { .hAdapter = adapter->hAdapter }); + if (NT_SUCCESS(status)) { + FF_DEBUG("Closed adapter #%u successfully", i); + } else { + FF_DEBUG("Failed to close adapter #%u: %s", i, ffDebugNtStatus(status)); + } } - FF_DEBUG("GPU detection completed, found %d devices", deviceCount); return NULL; }