GPU (Windows): use a faster implementation

This commit is contained in:
李通洲 2023-03-25 13:04:44 +08:00
parent 945b5f1b15
commit a524302ea7
No known key found for this signature in database
GPG Key ID: 6E72B663408769DE
4 changed files with 63 additions and 177 deletions

View File

@ -508,7 +508,7 @@ elseif(WIN32)
src/detection/disk/disk_windows.c
src/detection/displayserver/displayserver_windows.c
src/detection/font/font_windows.c
src/detection/gpu/gpu_windows.cpp
src/detection/gpu/gpu_windows.c
src/detection/host/host_windows.c
src/detection/localip/localip_windows.c
src/detection/gamepad/gamepad_windows.c
@ -728,7 +728,6 @@ elseif(WIN32)
PRIVATE "ntdll"
PRIVATE "version"
PRIVATE "setupapi"
PRIVATE "dxgi"
PRIVATE "hid"
PRIVATE "wtsapi32"
PRIVATE "powrprof"

View File

@ -36,11 +36,11 @@ static void pciDetectVendorName(FFGPUResult* gpu, PCIData* pci, struct pci_dev*
pci->ffpci_lookup_name(pci->access, gpu->vendor.chars, (int) gpu->vendor.allocated, PCI_LOOKUP_VENDOR, device->vendor_id);
ffStrbufRecalculateLength(&gpu->vendor);
if(ffStrbufFirstIndexS(&gpu->vendor, "AMD") < gpu->vendor.length || ffStrbufFirstIndexS(&gpu->vendor, "ATI") < gpu->vendor.length)
if(ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
ffStrbufSetS(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
else if(ffStrbufFirstIndexS(&gpu->vendor, "Intel") < gpu->vendor.length)
else if(ffStrbufContainS(&gpu->vendor, "Intel"))
ffStrbufSetS(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
else if(ffStrbufFirstIndexS(&gpu->vendor, "NVIDIA") < gpu->vendor.length)
else if(ffStrbufContainS(&gpu->vendor, "NVIDIA"))
ffStrbufSetS(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
}

View File

@ -0,0 +1,59 @@
#include "gpu.h"
#include "util/windows/unicode.h"
#include "util/windows/registry.h"
#include <inttypes.h>
const char* ffDetectGPUImpl(FFlist* gpus, FF_MAYBE_UNUSED const FFinstance* instance)
{
DISPLAY_DEVICEW displayDevice = {.cb = sizeof(displayDevice) };
wchar_t regKey[MAX_PATH] = L"SYSTEM\\CurrentControlSet\\Control\\Video\\{";
const uint32_t regKeyPrefixLength = strlen("SYSTEM\\CurrentControlSet\\Control\\Video\\{");
const uint32_t deviceKeyPrefixLength = strlen("\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\{");
for (DWORD i = 0; EnumDisplayDevicesW(NULL, i, &displayDevice, 0); ++i)
{
if (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue;
assert(wcslen(displayDevice.DeviceKey) == 100);
assert(wmemcmp(displayDevice.DeviceKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\{", deviceKeyPrefixLength) == 0);
assert(displayDevice.DeviceKey[95] == L'\\');
if (wmemcmp(&displayDevice.DeviceKey[96], L"0000", 4) != 0) continue;
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->id = 0;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
ffStrbufSetWS(&gpu->name, displayDevice.DeviceString);
wmemcpy(regKey + regKeyPrefixLength, displayDevice.DeviceKey + deviceKeyPrefixLength, 100 - regKeyPrefixLength + 1);
FF_HKEY_AUTO_DESTROY hKey = NULL;
if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regKey, &hKey, NULL)) continue;
ffRegReadStrbuf(hKey, L"DriverVersion", &gpu->driver, NULL);
ffRegReadStrbuf(hKey, L"ProviderName", &gpu->vendor, NULL);
if(ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
ffStrbufSetS(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
else if(ffStrbufContainS(&gpu->vendor, "Intel"))
ffStrbufSetS(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
else if(ffStrbufContainS(&gpu->vendor, "NVIDIA"))
ffStrbufSetS(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
if (!ffRegReadUint64(hKey, L"HardwareInformation.qwMemorySize", &gpu->dedicated.total, NULL))
{
uint32_t vmem = 0;
if (ffRegReadUint(hKey, L"HardwareInformation.MemorySize", &vmem, NULL))
gpu->dedicated.total = vmem;
}
gpu->type = gpu->dedicated.total > 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
return NULL;
}

View File

@ -1,172 +0,0 @@
extern "C" {
#include "gpu.h"
#include "util/windows/unicode.h"
#include "util/windows/registry.h"
}
#include "util/windows/wmi.hpp"
#include <dxgi.h>
#include <wchar.h>
#include <inttypes.h>
static const char* detectWithRegistry(FFlist* gpus)
{
// Ref: https://github.com/lptstr/winfetch/pull/155
FF_HKEY_AUTO_DESTROY hKey = NULL;
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\DirectX", &hKey, nullptr))
return "Open \"HKLM\\SOFTWARE\\Microsoft\\DirectX\" failed";
uint64_t lastSeen;
if(!ffRegReadUint64(hKey, L"LastSeen", &lastSeen, nullptr))
return "Read \"HKLM\\SOFTWARE\\Microsoft\\DirectX\\LastSeen\" failed";
DWORD index = 0;
wchar_t subKeyName[64];
while(true)
{
DWORD subKeySize = sizeof(subKeyName) / sizeof(*subKeyName);
if(RegEnumKeyExW(hKey, index++, subKeyName, &subKeySize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS)
break;
FF_HKEY_AUTO_DESTROY hSubKey = NULL;
if(!ffRegOpenKeyForRead(hKey, subKeyName, &hSubKey, nullptr))
continue;
uint64_t adapterLastSeen;
if(!ffRegReadUint64(hSubKey, L"LastSeen", &adapterLastSeen, nullptr) || lastSeen != adapterLastSeen)
continue;
uint32_t softwareAdapter;
if(!ffRegReadUint(hSubKey, L"SoftwareAdapter", &softwareAdapter, nullptr) || softwareAdapter)
continue;
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->id = 0;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
ffRegReadUint64(hSubKey, L"AdapterLuid", &gpu->id, nullptr);
ffRegReadStrbuf(hSubKey, L"Description", &gpu->name, nullptr);
uint32_t vendorId;
if(ffRegReadUint(hSubKey, L"VendorId", &vendorId, nullptr))
ffStrbufAppendS(&gpu->vendor, ffGetGPUVendorString(vendorId));
uint64_t dedicatedVideoMemory = 0;
if(ffRegReadUint64(hSubKey, L"DedicatedVideoMemory", &dedicatedVideoMemory, nullptr))
gpu->type = dedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
uint64_t dedicatedSystemMemory, sharedSystemMemory;
if(ffRegReadUint64(hSubKey, L"DedicatedSystemMemory", &dedicatedSystemMemory, nullptr) &&
ffRegReadUint64(hSubKey, L"SharedSystemMemory", &sharedSystemMemory, nullptr))
{
gpu->dedicated.total = dedicatedVideoMemory + dedicatedSystemMemory;
gpu->shared.total = sharedSystemMemory;
}
uint64_t driverVersion;
if(ffRegReadUint64(hSubKey, L"DriverVersion", &driverVersion, nullptr))
{
ffStrbufSetF(&gpu->driver, "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".%" PRIu64,
(driverVersion >> 48) & 0xFFFF,
(driverVersion >> 32) & 0xFFFF,
(driverVersion >> 16) & 0xFFFF,
(driverVersion >> 0) & 0xFFFF);
}
}
return nullptr;
}
static const char* detectWithDxgi(FFlist* gpus)
{
IDXGIFactory1* pFactory;
if(FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory))))
return "CreateDXGIFactory1() failed";
for(unsigned iAdapter = 0;; ++iAdapter)
{
IDXGIAdapter1* adapter;
if(FAILED(pFactory->EnumAdapters1(iAdapter, &adapter)))
break;
DXGI_ADAPTER_DESC1 desc;
if(FAILED(adapter->GetDesc1(&desc)) || (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE))
continue;
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
ffStrbufInit(&gpu->vendor);
ffStrbufAppendS(&gpu->vendor, ffGetGPUVendorString(desc.VendorId));
gpu->id = (uint64_t&)desc.AdapterLuid;
ffStrbufInit(&gpu->name);
ffStrbufSetWS(&gpu->name, desc.Description);
ffStrbufInit(&gpu->driver);
gpu->type = desc.DedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
gpu->dedicated.total = desc.DedicatedVideoMemory + desc.DedicatedSystemMemory;
gpu->shared.total = desc.SharedSystemMemory;
adapter->Release();
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
}
pFactory->Release();
return nullptr;
}
static const char* detectMemoryUsage(FFlist* gpus)
{
FFWmiQuery query(L"SELECT Name, DedicatedUsage, SharedUsage FROM Win32_PerfRawData_GPUPerformanceCounters_GPUAdapterMemory", nullptr);
if(!query)
return "Query WMI service failed";
FF_STRBUF_AUTO_DESTROY name;
ffStrbufInit(&name);
while(FFWmiRecord record = query.next())
{
record.getString(L"Name", &name); // luid_0x00000000_0x000146E8_phys_0
assert(name.length == strlen("luid_0x00000000_0x000146E8_phys_0"));
ffStrbufSubstrBefore(&name, strlen("luid_0x00000000_0x000146E8")); // luid_0x00000000_0x000146E8
ffStrbufSubstrAfter(&name, strlen("luid_0x00000000_0x") - 1); // 000146E8
uint64_t luid = strtoull(name.chars, nullptr, 16);
FF_LIST_FOR_EACH(FFGPUResult, gpu, *gpus)
{
if (gpu->id != luid) continue;
record.getUnsigned(L"DedicatedUsage", &gpu->dedicated.used);
record.getUnsigned(L"SharedUsage", &gpu->shared.used);
break;
}
}
return nullptr;
}
extern "C"
const char* ffDetectGPUImpl(FFlist* gpus, FF_MAYBE_UNUSED const FFinstance* instance)
{
const char* error = detectWithRegistry(gpus);
if (error)
error = detectWithDxgi(gpus);
if (!error && gpus->length > 0 && instance->config.allowSlowOperations)
detectMemoryUsage(gpus);
return error;
}