From 8bf1aca7fc2b94b1e1e5b6a5937e7fbbb89393a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 16 Jul 2026 19:03:43 +0800 Subject: [PATCH] GPU (Windows): correctly report virtual GPUs Fixes #2461 --- src/detection/gpu/gpu_windows.c | 537 +++++++++++++++++--------------- 1 file changed, 283 insertions(+), 254 deletions(-) diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index 9a6b95ad7..526ff66a5 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -17,12 +17,16 @@ #include #include #include + #include #include #define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in -static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds, bool queryPcieGen) { - FF_DEBUG("Query PCI device info: %08llX", gpu->deviceId); +// https://wine-devel.winehq.narkive.com/vKO2Bkgj/patch-1-2-dxgi-tests-add-test-for-enumerating-display-adapters-using-setupapi +DEFINE_DEVPROPKEY(DEVPROPKEY_DISPLAY_ADAPTER_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2); + +static bool queryDeviceInfoCM(FFGPUResult* gpu, uint64_t luid, D3DKMT_DEVICE_IDS* outDeviceIds, bool queryPcieGen) { + FF_DEBUG("Query PCI device info: %08llX with LUID: %08llX", gpu->deviceId, luid); static FFlist deviceIdsCache; static bool initialized; @@ -32,7 +36,10 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds uint32_t maxLinkSpeed; uint32_t maxLinkWidth; D3DKMT_DEVICE_IDS deviceIds; - uint64_t adapterAddress; + uint64_t pciAddr; + uint64_t luid; + FFstrbuf vendor; + FFstrbuf name; } CacheEntry; if (!initialized) { @@ -71,13 +78,36 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds } } - if (wcsncmp(devId, L"PCI\\", 4) != 0) { - FF_DEBUG("Skipping non-PCI device ID: %ls", devId); - continue; - } - CacheEntry* entry = FF_LIST_ADD(CacheEntry, deviceIdsCache); - *entry = (CacheEntry) {}; + *entry = (CacheEntry){}; + + ULONG bufLen = sizeof(entry->luid); + DEVPROPTYPE type; + CONFIGRET ret = CM_Get_DevNode_PropertyW(devInst, &DEVPROPKEY_DISPLAY_ADAPTER_LUID, &type, (PBYTE) &entry->luid, &bufLen, 0); + if (ret != CR_SUCCESS) { // Not available on Windows 8.1 + FF_DEBUG("Failed to get device LUID: %s", ffDebugConfigRet(ret)); + + uint32_t pciBus = 0; + ULONG pciBufLen = sizeof(pciBus); + if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_BUSNUMBER, nullptr, &pciBus, &pciBufLen, 0) == CR_SUCCESS) { + uint32_t pciAddr = 0; + pciBufLen = sizeof(pciAddr); + if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_ADDRESS, nullptr, &pciAddr, &pciBufLen, 0) == CR_SUCCESS) { + entry->pciAddr = ffGPUPciAddr2Id(0, pciBus, (pciAddr >> 16) & 0xFFFF, pciAddr & 0xFFFF); + FF_DEBUG("Cached device IDs for PCI bus %u: vendor=0x%04x device=0x%04x", pciBus, entry->deviceIds.VendorID, entry->deviceIds.DeviceID); + } else { + FF_DEBUG("Failed to get PCI address"); + } + } else { + FF_DEBUG("Failed to get PCI bus number"); + } + + if (entry->pciAddr == 0) { + FF_DEBUG("Skipping device ID: %ls due to missing LUID and PCI address", devId); + deviceIdsCache.length--; + continue; + } + } // L"PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1\\4&3674a6b9&0&0008" if (swscanf(devId + 4, L"VEN_%x&DEV_%x&SUBSYS_%4x%4x&REV_%x", &entry->deviceIds.VendorID, &entry->deviceIds.DeviceID, &entry->deviceIds.SubSystemID, &entry->deviceIds.SubVendorID, &entry->deviceIds.RevisionID) >= 2) { @@ -87,32 +117,44 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds // And yeah, DXGKMDT_OPM_BUS_TYPE_PCIEXPRESS (3) exists entry->deviceIds.BusType = 1; } else { - FF_DEBUG("Failed to parse PCI IDs from device ID string"); - deviceIdsCache.length--; // remove the cache entry since it's not valid - continue; + FF_DEBUG("Failed to parse PCI IDs from device ID: %ls", devId); + entry->deviceIds.VendorID = -1u; } - uint32_t pciBus = 0; - ULONG pciBufLen = sizeof(pciBus); - if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_BUSNUMBER, nullptr, &pciBus, &pciBufLen, 0) == CR_SUCCESS) { - uint32_t pciAddr = 0; - pciBufLen = sizeof(pciAddr); - if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_ADDRESS, nullptr, &pciAddr, &pciBufLen, 0) == CR_SUCCESS) { - entry->adapterAddress = ffGPUPciAddr2Id(0, pciBus, (pciAddr >> 16) & 0xFFFF, pciAddr & 0xFFFF); - FF_DEBUG("Cached device IDs for PCI bus %u: vendor=0x%04x device=0x%04x", pciBus, entry->deviceIds.VendorID, entry->deviceIds.DeviceID); - } else { - FF_DEBUG("Failed to get PCI address"); - } + wchar_t wstr[256]; + bufLen = sizeof(wstr); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Device_FriendlyName, &type, (PBYTE) wstr, &bufLen, 0); + if (ret == CR_SUCCESS) { + ffStrbufSetNWS(&entry->name, (bufLen - 1) / sizeof(wchar_t), wstr); + FF_DEBUG("Device friendly name: %ls", wstr); } else { - FF_DEBUG("Failed to get PCI bus number"); + FF_DEBUG("Failed to get device friendly name: %s", ffDebugConfigRet(ret)); + + bufLen = sizeof(wstr); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Device_DeviceDesc, &type, (PBYTE) wstr, &bufLen, 0); + if (ret == CR_SUCCESS) { + ffStrbufSetNWS(&entry->name, (bufLen - 1) / sizeof(wchar_t), wstr); + FF_DEBUG("Device description: %ls", wstr); + } else { + FF_DEBUG("Failed to get device description: %s", ffDebugConfigRet(ret)); + } } - if (queryPcieGen) { + bufLen = sizeof(wstr); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Device_Manufacturer, &type, (PBYTE) wstr, &bufLen, 0); + if (ret == CR_SUCCESS) { + ffStrbufSetNWS(&entry->vendor, (bufLen - 1) / sizeof(wchar_t), wstr); + FF_DEBUG("Device vendor name: %ls", wstr); + } else { + FF_DEBUG("Failed to get device vendor name: %s", ffDebugConfigRet(ret)); + } + + if (queryPcieGen && entry->deviceIds.VendorID != -1u) { DEVPROPTYPE propType; - pciBufLen = sizeof(entry->maxLinkSpeed); + bufLen = sizeof(entry->maxLinkSpeed); // Reports PCIe gen despite the PKEY name - CONFIGRET ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkSpeed, &propType, (PBYTE) &entry->maxLinkSpeed, &pciBufLen, 0); + CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkSpeed, &propType, (PBYTE) &entry->maxLinkSpeed, &bufLen, 0); if (ret == CR_SUCCESS) { FF_DEBUG("PCIe max GEN: %u", entry->maxLinkSpeed); } else { @@ -120,8 +162,8 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds } if (entry->maxLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) { - pciBufLen = sizeof(entry->maxLinkWidth); - ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkWidth, &propType, (PBYTE) &entry->maxLinkWidth, &pciBufLen, 0); + bufLen = sizeof(entry->maxLinkWidth); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkWidth, &propType, (PBYTE) &entry->maxLinkWidth, &bufLen, 0); if (ret == CR_SUCCESS) { FF_DEBUG("PCIe max link width: %u", entry->maxLinkWidth); } else { @@ -129,8 +171,8 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds } } - pciBufLen = sizeof(entry->currentLinkSpeed); - ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkSpeed, &propType, (PBYTE) &entry->currentLinkSpeed, &pciBufLen, 0); + bufLen = sizeof(entry->currentLinkSpeed); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkSpeed, &propType, (PBYTE) &entry->currentLinkSpeed, &bufLen, 0); if (ret == CR_SUCCESS) { FF_DEBUG("PCIe GEN: %u", entry->currentLinkSpeed); } else { @@ -138,8 +180,8 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds } if (entry->currentLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) { - pciBufLen = sizeof(entry->currentLinkWidth); - ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkWidth, &propType, (PBYTE) &entry->currentLinkWidth, &pciBufLen, 0); + bufLen = sizeof(entry->currentLinkWidth); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkWidth, &propType, (PBYTE) &entry->currentLinkWidth, &bufLen, 0); if (ret == CR_SUCCESS) { FF_DEBUG("PCIe current link width: %u", entry->currentLinkWidth); } else { @@ -151,12 +193,31 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds } FF_LIST_FOR_EACH (CacheEntry, entry, deviceIdsCache) { - if (gpu->deviceId == entry->adapterAddress) { - FF_DEBUG("Cache hit for adapter address: %08llX", gpu->deviceId); + if (luid == entry->luid || entry->pciAddr == gpu->deviceId) { + FF_DEBUG("Cache hit for adapter LUID: %08llX", luid); if (outDeviceIds->VendorID == -1u) { *outDeviceIds = entry->deviceIds; } + if (gpu->vendor.length == 0) { + if (entry->deviceIds.VendorID != -1u) { + ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(entry->deviceIds.VendorID)); + } + if (gpu->vendor.length == 0 && entry->vendor.length > 0) { + ffStrbufDestroy(&gpu->vendor); + ffStrbufInitMove(&gpu->vendor, &entry->vendor); + } + } else if (gpu->name.length == 0 && entry->deviceIds.VendorID == -1u) { + // Some Indirect display adapters reports fake Device IDs + ffStrbufDestroy(&gpu->vendor); + ffStrbufInitMove(&gpu->vendor, &entry->vendor); + } + + if (gpu->name.length == 0) { + ffStrbufDestroy(&gpu->name); + ffStrbufInitMove(&gpu->name, &entry->name); + } + if (queryPcieGen) { gpu->psMax.gen = (uint16_t) entry->maxLinkSpeed; gpu->psMax.lanes = (uint16_t) entry->maxLinkWidth; @@ -167,37 +228,10 @@ static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds } } - FF_DEBUG("Cache miss for adapter address: %08llX", gpu->deviceId); + FF_DEBUG("Cache miss for adapter LUID: %08llX", luid); return false; } -static bool queryVendorNameViaRegistry(FFstrbuf* vendor, D3DKMT_HANDLE hAdapter) { - // `KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID` reports the GUID value used by the adapter's registry key (DirectX and Video) - - GUID guid; - NTSTATUS status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { - .hAdapter = hAdapter, - .Type = KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID, - .pPrivateDriverData = &guid, - .PrivateDriverDataSize = sizeof(guid), - }); - if (!NT_SUCCESS(status)) { - FF_DEBUG("Failed to query adapter unique GUID: %s", ffDebugNtStatus(status)); - return false; - } - - wchar_t path[PATH_MAX]; - swprintf(path, ARRAY_SIZE(path), L"SYSTEM\\CurrentControlSet\\Control\\Video\\{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\\0000", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); - - FF_DEBUG("Querying registry: HKEY_LOCAL_MACHINE\\%ls\\ProviderName", path); - FF_AUTO_CLOSE_FD HANDLE key = nullptr; - if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, path, &key, nullptr)) { - return false; - } - - return ffRegReadStrbuf(key, L"ProviderName", vendor, nullptr); -} - #else #include #include @@ -301,6 +335,8 @@ ffGPUDetectWsl2 goto close_adapter; } + uint64_t luid = ((uint64_t) adapter->AdapterLuid.HighPart << 32) | (uint64_t) adapter->AdapterLuid.LowPart; + FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus); ffStrbufInit(&gpu->vendor); ffStrbufInit(&gpu->name); @@ -321,7 +357,7 @@ ffGPUDetectWsl2 : FF_GPU_TYPE_UNKNOWN; gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; - D3DKMT_DRIVERVERSION wddmVersion = KMT_DRIVERVERSION_WDDM_2_0; + D3DKMT_DRIVERVERSION wddmVersion; status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { .hAdapter = adapter->hAdapter, .Type = KMTQAITYPE_DRIVERVERSION, @@ -332,6 +368,7 @@ ffGPUDetectWsl2 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 { + wddmVersion = KMT_DRIVERVERSION_WDDM_1_3; // Smallest supported WDDM version, used for fallback ffStrbufSetStatic(&gpu->platformApi, "WDDM"); FF_DEBUG("KMTQAITYPE_DRIVERVERSION query failed for adapter #%u", i); } @@ -352,7 +389,7 @@ ffGPUDetectWsl2 adapterAddress.FunctionNumber); } else { adapterAddress.BusNumber = -1u; - gpu->deviceId = ffGPUGeneral2Id(((uint64_t) adapter->AdapterLuid.HighPart << 32) | (uint64_t) adapter->AdapterLuid.LowPart); + gpu->deviceId = ffGPUGeneral2Id(luid); FF_DEBUG("KMTQAITYPE_ADAPTERADDRESS query failed for adapter #%u, fallback to LUID-based deviceId: %s", i, ffDebugNtStatus(status)); @@ -376,14 +413,6 @@ ffGPUDetectWsl2 FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS query failed for adapter #%u: %s", i, ffDebugNtStatus(status)); } - #if _WIN32 && FF_WIN81_COMPAT - if (adapterAddress.BusNumber != -1u && (deviceIds.DeviceIds.VendorID == -1u || options->driverSpecific)) { - if (queryPciDeviceInfo(gpu, &deviceIds.DeviceIds, options->driverSpecific) && gpu->vendor.length == 0) { - ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(deviceIds.DeviceIds.VendorID)); - } - } - #endif - D3DKMT_UMD_DRIVER_VERSION umdDriverVersion; status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { .hAdapter = adapter->hAdapter, @@ -403,63 +432,55 @@ ffGPUDetectWsl2 FF_DEBUG("KMTQAITYPE_UMD_DRIVER_VERSION query failed for adapter #%u: %s", i, ffDebugNtStatus(status)); } - 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); - [[maybe_unused]] const char* error = detectFn( - &(FFGpuDriverCondition) { - .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 = deviceIds.DeviceIds.DeviceID, - .vendorId = deviceIds.DeviceIds.VendorID, - .subSystemId = deviceIds.DeviceIds.SubSystemID, - .revId = deviceIds.DeviceIds.RevisionID, - }, - .pciBusId = { - .domain = 0, - .bus = adapterAddress.BusNumber, - .device = adapterAddress.DeviceNumber, - .func = adapterAddress.FunctionNumber, - }, - .luid = ((uint64_t) adapter->AdapterLuid.HighPart << 32) | (uint64_t) adapter->AdapterLuid.LowPart, - }, - (FFGpuDriverResult) { - .index = &gpu->index, - .temp = options->temp ? &gpu->temperature : nullptr, - .memory = options->driverSpecific ? &gpu->dedicated : nullptr, - .sharedMemory = options->driverSpecific ? &gpu->shared : nullptr, - .memoryType = options->driverSpecific ? &gpu->memoryType : nullptr, - .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : nullptr, - .coreUsage = options->driverSpecific ? &gpu->coreUsage : nullptr, - .type = &gpu->type, - .frequency = options->driverSpecific ? &gpu->frequency : nullptr, - .name = &gpu->name, - .psCurr = options->driverSpecific ? &gpu->psCurr : nullptr, - .psMax = options->driverSpecific ? &gpu->psMax : nullptr, - }, - dllName); - FF_DEBUG("Driver-specific detection completed: %s", error ?: "Success"); - } else if (options->driverSpecific) { - FF_DEBUG("No driver-specific detection function found for vendor: %s", gpu->vendor.chars); + bool isIndirectDisplayDevice = gpu->type == FF_GPU_TYPE_UNKNOWN && adapterType.IndirectDisplayDevice; + if (isIndirectDisplayDevice) { + FF_DEBUG("Adapter #%u is an indirect display device", i); } -#if _WIN32 - // Put this after the driver-specific detection, as `getDriverSpecificDetectionFn` never succeeds - if (gpu->vendor.length == 0 && wddmVersion >= KMT_DRIVERVERSION_WDDM_2_4) { - // For non-PCI devices - FF_DEBUG("Attempting to query vendor name via registry for adapter #%u", i); - queryVendorNameViaRegistry(&gpu->vendor, adapter->hAdapter); - } - - #if !FF_WIN81_COMPAT - if (adapterAddress.BusNumber != -1u && options->driverSpecific && gpu->pcieSpeed == FF_GPU_PCIE_SPEED_UNSET) { - queryPciDeviceInfo(gpu, &deviceIds.DeviceIds, options->driverSpecific); - } - #endif -#endif + if (!isIndirectDisplayDevice) { + 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); + [[maybe_unused]] const char* error = detectFn( + &(FFGpuDriverCondition) { + .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 = deviceIds.DeviceIds.DeviceID, + .vendorId = deviceIds.DeviceIds.VendorID, + .subSystemId = deviceIds.DeviceIds.SubSystemID, + .revId = deviceIds.DeviceIds.RevisionID, + }, + .pciBusId = { + .domain = 0, + .bus = adapterAddress.BusNumber, + .device = adapterAddress.DeviceNumber, + .func = adapterAddress.FunctionNumber, + }, + .luid = luid, + }, + (FFGpuDriverResult) { + .index = &gpu->index, + .temp = options->temp ? &gpu->temperature : nullptr, + .memory = options->driverSpecific ? &gpu->dedicated : nullptr, + .sharedMemory = options->driverSpecific ? &gpu->shared : nullptr, + .memoryType = options->driverSpecific ? &gpu->memoryType : nullptr, + .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : nullptr, + .coreUsage = options->driverSpecific ? &gpu->coreUsage : nullptr, + .type = &gpu->type, + .frequency = options->driverSpecific ? &gpu->frequency : nullptr, + .name = &gpu->name, + .psCurr = options->driverSpecific ? &gpu->psCurr : nullptr, + .psMax = options->driverSpecific ? &gpu->psMax : nullptr, + }, + dllName); + FF_DEBUG("Driver-specific detection completed: %s", error ?: "Success"); + } else if (options->driverSpecific) { + FF_DEBUG("No driver-specific detection function found for vendor: %s", gpu->vendor.chars); + } + }; if (gpu->name.length == 0) { D3DKMT_ADAPTERREGISTRYINFO registryInfo; @@ -477,148 +498,156 @@ ffGPUDetectWsl2 } } - 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 = adapter->AdapterLuid, - .QuerySegmentGroupUsage = { - .PhysicalAdapterIndex = 0, - .SegmentGroup = D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL, - }, - }; - 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("Adapter #%u local memory usage: used=%" PRIu64 " total=%" PRIu64, i, used, total); - } else { - 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; - 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("Adapter #%u non-local memory usage: used=%" PRIu64 " total=%" PRIu64, i, used, total); - } else { - 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 _WIN32 + if (gpu->name.length == 0 || gpu->vendor.length == 0 || (options->driverSpecific && gpu->pcieSpeed == FF_GPU_PCIE_SPEED_UNSET)) { + queryDeviceInfoCM(gpu, luid, &deviceIds.DeviceIds, options->driverSpecific); } + #endif - 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, + if (!isIndirectDisplayDevice) { + 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 = adapter->AdapterLuid, + .QuerySegmentGroupUsage = { + .PhysicalAdapterIndex = 0, + .SegmentGroup = D3DKMT_MEMORY_SEGMENT_GROUP_LOCAL, + }, }; - 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), - }); + status = D3DKMTQueryStatistics(&queryStatistics); if (NT_SUCCESS(status)) { - if (nodePerfData.MaxFrequency != 0) { - gpu->frequency = (uint32_t) (nodePerfData.MaxFrequency / 1000 / 1000); - FF_DEBUG("Adapter #%u max graphics frequency: %u MHz", i, gpu->frequency); - } else { - FF_DEBUG("Adapter #%u does not report max graphics frequency", i); - } - break; + 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("Adapter #%u local memory usage: used=%" PRIu64 " total=%" PRIu64, i, used, total); } else { - FF_DEBUG("Failed to query node performance data for adapter #%u node #%u: %s", + FF_DEBUG("D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE (LOCAL) failed for adapter #%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)) { - if (adapterPerfData.Temperature != 0) { - gpu->temperature = adapterPerfData.Temperature / 10.0; - FF_DEBUG("Adapter #%u temperature: %.1f°C", i, gpu->temperature); + queryStatistics.QuerySegmentGroupUsage.SegmentGroup = D3DKMT_MEMORY_SEGMENT_GROUP_NON_LOCAL; + 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("Adapter #%u non-local memory usage: used=%" PRIu64 " total=%" PRIu64, i, used, total); } else { - FF_DEBUG("Adapter #%u does not report temperature data", i); + FF_DEBUG("D3DKMT_QUERYSTATISTICS_SEGMENT_GROUP_USAGE (NON_LOCAL) failed for adapter #%u: %s", + i, + ffDebugNtStatus(status)); } } else { - FF_DEBUG("Failed to query temperature for adapter #%u: %s", i, ffDebugNtStatus(status)); + // 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 (gpu->type == FF_GPU_TYPE_UNKNOWN) { - if (ffGPUDetectTypeByVendorAndName(gpu)) { - // OK + 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)) { + if (nodePerfData.MaxFrequency != 0) { + gpu->frequency = (uint32_t) (nodePerfData.MaxFrequency / 1000 / 1000); + FF_DEBUG("Adapter #%u max graphics frequency: %u MHz", i, gpu->frequency); + } else { + FF_DEBUG("Adapter #%u does not report max graphics frequency", i); + } + 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)) { + if (adapterPerfData.Temperature != 0) { + gpu->temperature = adapterPerfData.Temperature / 10.0; + FF_DEBUG("Adapter #%u temperature: %.1f°C", i, gpu->temperature); + } else { + FF_DEBUG("Adapter #%u does not report temperature data", i); + } + } else { + FF_DEBUG("Failed to query temperature for adapter #%u: %s", i, ffDebugNtStatus(status)); + } + } } -#if _WIN32 - else if (ffIsWindows10OrGreater()) { - const char* ffGPUDetectTypeWithDXCore(LUID adapterLuid, FFGPUResult * gpu); - [[maybe_unused]] const char* error = ffGPUDetectTypeWithDXCore(adapter->AdapterLuid, gpu); - FF_DEBUG("DXCore GPU type detection result: %s", error ?: "Success"); - } -#endif - else { - FF_DEBUG("Unable to determine GPU type by any method for this adapter"); + + if (gpu->type == FF_GPU_TYPE_UNKNOWN) { + if (ffGPUDetectTypeByVendorAndName(gpu)) { + // OK + } + #if _WIN32 + else if (ffIsWindows10OrGreater()) { + const char* ffGPUDetectTypeWithDXCore(LUID adapterLuid, FFGPUResult * gpu); + [[maybe_unused]] const char* error = ffGPUDetectTypeWithDXCore(adapter->AdapterLuid, gpu); + FF_DEBUG("DXCore GPU type detection result: %s", error ?: "Success"); + } + #endif + else { + FF_DEBUG("Unable to determine GPU type by any method for this adapter"); + } } }