diff --git a/CHANGELOG.md b/CHANGELOG.md index 61326e9f4..2eb3331e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Bugfixes: Other: * Simplified wmtheme output format (Windows) +* Improved GPU detection performance on Windows 11 # 1.9.1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d1c0eae1..e60e6b26f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -726,9 +726,6 @@ elseif(WIN32) if(USE_WIN_NTAPI) target_compile_definitions(libfastfetch PRIVATE FF_USE_WIN_NTAPI) endif() - if(USE_WIN_GPU_DXGI) - target_compile_definitions(libfastfetch PRIVATE FF_USE_WIN_GPU_DXGI) - endif() endif() target_include_directories(libfastfetch diff --git a/presets/verbose b/presets/verbose index 1d4823259..5d8a675bb 100644 --- a/presets/verbose +++ b/presets/verbose @@ -17,7 +17,7 @@ --terminal-font-format Pretty: {}; Name: {}; Size: {}; Styles: {} --cpu-format Name: {}, Vendor: {}, CoresPhysical: {}, CoresLogical: {}, CoresOnline: {}, FrequencyMin: {}, FrequencyMax: {}, Temperature: {} --cpu-usage-format Percentage: {} ---gpu-format Vendor: {}; Name: {}; Driver: {}; Temperature: {}; CoreCount: {} +--gpu-format Vendor: {}; Name: {}; Driver: {}; Temperature: {}; CoreCount: {}; Type: {} --memory-format Used: {}; Total: {}; Percentage: {} --disk-format SizeUsed: {}; SizeTotal: {}; SizePercentage: {}; FilesUsed: {}; FilesTotal: {}; FilesPercentage: {}; Removable: {}; Hidden: {}; Filesystem: {}; Name: {} --battery-format Manufactor: {}; Model: {}; Technology: {}; Capacity: {}; Status: {} diff --git a/src/detection/gpu/gpu_windows.cpp b/src/detection/gpu/gpu_windows.cpp index 07b711205..ccfd187a7 100644 --- a/src/detection/gpu/gpu_windows.cpp +++ b/src/detection/gpu/gpu_windows.cpp @@ -1,13 +1,75 @@ extern "C" { #include "gpu.h" #include "util/windows/unicode.h" +#include "util/windows/registry.h" } -#ifdef FF_USE_WIN_GPU_DXGI - #include #include +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 \"SOFTWARE\\Microsoft\\DirectX\" failed"; + + uint64_t lastSeen; + if(!ffRegReadUint64(hKey, L"LastSeen", &lastSeen, nullptr)) + return "Read \"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; + + ffRegReadStrbuf(hSubKey, L"Description", &gpu->name, nullptr); + + uint32_t vendorId; + if(ffRegReadUint(hSubKey, L"VendorId", &vendorId, nullptr)) + { + if(wmemchr((const wchar_t[]) {0x1002, 0x1022}, (wchar_t)vendorId, 2)) + ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD); + else if(wmemchr((const wchar_t[]) {0x03e7, 0x8086, 0x8087}, (wchar_t)vendorId, 3)) + ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL); + else if(wmemchr((const wchar_t[]) {0x0955, 0x10de, 0x12d2}, (wchar_t)vendorId, 3)) + ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA); + } + + uint64_t dedicatedVideoMemory; + if(ffRegReadUint64(hSubKey, L"DedicatedVideoMemory", &dedicatedVideoMemory, nullptr)) + { + gpu->type = dedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED; + } + } + + return nullptr; +} + static const char* detectWithDxgi(FFlist* gpus) { IDXGIFactory1* pFactory; @@ -50,56 +112,13 @@ static const char* detectWithDxgi(FFlist* gpus) pFactory->Release(); - return NULL; -} - -#else - -#include "util/windows/wmi.hpp" - -static const char* detectWithWmi(FFlist* gpus) -{ - FFWmiQuery query(L"SELECT Name, AdapterCompatibility, DriverVersion FROM Win32_VideoController", nullptr); - if(!query) - return "Query WMI service failed"; - - while(FFWmiRecord record = query.next()) - { - FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus); - - gpu->type = FF_GPU_TYPE_UNKNOWN; - - ffStrbufInit(&gpu->vendor); - record.getString(L"AdapterCompatibility", &gpu->vendor); - if(ffStrbufStartsWithS(&gpu->vendor, "Intel ")) - { - //Intel returns "Intel Corporation", not sure about AMD - ffStrbufSetS(&gpu->vendor, "Intel"); - } - - ffStrbufInit(&gpu->name); - record.getString(L"Name", &gpu->name); - - ffStrbufInit(&gpu->driver); - record.getString(L"DriverVersion", &gpu->driver); - - gpu->temperature = FF_GPU_TEMP_UNSET; - gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; - } - return nullptr; } -#endif - extern "C" -const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) +const char* ffDetectGPUImpl(FFlist* gpus, FF_MAYBE_UNUSED const FFinstance* instance) { - FF_UNUSED(instance); - - #ifdef FF_USE_WIN_GPU_DXGI + if (!detectWithRegistry(gpus)) + return nullptr; return detectWithDxgi(gpus); - #else - return detectWithWmi(gpus); - #endif } diff --git a/src/util/windows/registry.c b/src/util/windows/registry.c index 2257e1963..0a80781d3 100644 --- a/src/util/windows/registry.c +++ b/src/util/windows/registry.c @@ -1,82 +1,99 @@ -#include "registry.h" -#include "unicode.h" -#include "util/mallocHelper.h" - -static const char* hKey2Str(HKEY hKey) -{ - #define HKEY_CASE(compareKey) if(hKey == compareKey) return #compareKey; - HKEY_CASE(HKEY_CLASSES_ROOT) - HKEY_CASE(HKEY_CURRENT_USER) - HKEY_CASE(HKEY_LOCAL_MACHINE) - HKEY_CASE(HKEY_USERS) - HKEY_CASE(HKEY_PERFORMANCE_DATA) - HKEY_CASE(HKEY_PERFORMANCE_TEXT) - HKEY_CASE(HKEY_PERFORMANCE_NLSTEXT) - HKEY_CASE(HKEY_CURRENT_CONFIG) - HKEY_CASE(HKEY_DYN_DATA) - HKEY_CASE(HKEY_CURRENT_USER_LOCAL_SETTINGS) - #undef HKEY_CASE - - return "UNKNOWN"; -} - -bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error) -{ - if(RegOpenKeyExW(hKey, subKeyW, 0, KEY_READ, result) != ERROR_SUCCESS) - { - if(error) - { - FF_STRBUF_AUTO_DESTROY subKeyA = ffStrbufCreateWS(subKeyW); - ffStrbufAppendF(error, "RegOpenKeyExW(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars); - } - return false; - } - return true; -} - -bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error) -{ - DWORD bufSize; //with tailing '\0' - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, NULL, &bufSize) != ERROR_SUCCESS) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueA(%s, NULL, RRF_RT_REG_SZ) failed", valueNameA.chars); - } - return false; - } - wchar_t* FF_AUTO_FREE resultW = (wchar_t*)malloc(bufSize); - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, resultW, &bufSize) != ERROR_SUCCESS) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueA(%s, result, RRF_RT_REG_SZ) failed", valueNameA.chars); - } - return false; - } - ffStrbufSetWS(result, resultW); - return true; -} - -bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error) -{ - DWORD bufSize = sizeof(*result); - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_DWORD, NULL, result, &bufSize) != ERROR_SUCCESS) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueA(%s, result, RRF_RT_DWORD) failed", valueNameA.chars); - } - return false; - } - return true; -} +#include "registry.h" +#include "unicode.h" +#include "util/mallocHelper.h" + +static const char* hKey2Str(HKEY hKey) +{ + #define HKEY_CASE(compareKey) if(hKey == compareKey) return #compareKey; + HKEY_CASE(HKEY_CLASSES_ROOT) + HKEY_CASE(HKEY_CURRENT_USER) + HKEY_CASE(HKEY_LOCAL_MACHINE) + HKEY_CASE(HKEY_USERS) + HKEY_CASE(HKEY_PERFORMANCE_DATA) + HKEY_CASE(HKEY_PERFORMANCE_TEXT) + HKEY_CASE(HKEY_PERFORMANCE_NLSTEXT) + HKEY_CASE(HKEY_CURRENT_CONFIG) + HKEY_CASE(HKEY_DYN_DATA) + HKEY_CASE(HKEY_CURRENT_USER_LOCAL_SETTINGS) + #undef HKEY_CASE + + return "UNKNOWN"; +} + +bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error) +{ + if(RegOpenKeyExW(hKey, subKeyW, 0, KEY_READ, result) != ERROR_SUCCESS) + { + if(error) + { + FF_STRBUF_AUTO_DESTROY subKeyA = ffStrbufCreateWS(subKeyW); + ffStrbufAppendF(error, "RegOpenKeyExW(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars); + } + return false; + } + return true; +} + +bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error) +{ + DWORD bufSize; //with tailing '\0' + if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, NULL, &bufSize) != ERROR_SUCCESS) + { + if(error) + { + if(!valueNameW) + valueNameW = L"(default)"; + FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); + ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_SZ) failed", valueNameA.chars); + } + return false; + } + wchar_t* FF_AUTO_FREE resultW = (wchar_t*)malloc(bufSize); + if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, resultW, &bufSize) != ERROR_SUCCESS) + { + if(error) + { + if(!valueNameW) + valueNameW = L"(default)"; + FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); + ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_REG_SZ) failed", valueNameA.chars); + } + return false; + } + ffStrbufSetWS(result, resultW); + return true; +} + +bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error) +{ + DWORD bufSize = sizeof(*result); + if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_DWORD, NULL, result, &bufSize) != ERROR_SUCCESS) + { + if(error) + { + if(!valueNameW) + valueNameW = L"(default)"; + FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); + ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_DWORD) failed", valueNameA.chars); + } + return false; + } + return true; +} + +bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error) +{ + DWORD bufSize = sizeof(*result); + if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_QWORD, NULL, result, &bufSize) != ERROR_SUCCESS) + { + if(error) + { + if(!valueNameW) + valueNameW = L"(default)"; + FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); + ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_QWORD) failed", valueNameA.chars); + } + return false; + } + return true; +} diff --git a/src/util/windows/registry.h b/src/util/windows/registry.h index e21dfdb66..d9eb67666 100644 --- a/src/util/windows/registry.h +++ b/src/util/windows/registry.h @@ -18,5 +18,6 @@ static inline void wrapRegCloseKey(HKEY* phKey) bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error); bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error); bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error); +bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error); #endif