From c1f511c8f2d7f9f4af80af040125665cda564577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 29 Dec 2023 15:12:41 +0800 Subject: [PATCH] GPU: detect supported platform graphic API version --- CMakeLists.txt | 2 + src/detection/gpu/gpu.c | 1 + src/detection/gpu/gpu.h | 1 + src/detection/gpu/gpu_apple.c | 6 ++ src/detection/gpu/gpu_apple.m | 40 ++++++++++ src/detection/gpu/gpu_linux.c | 2 + src/detection/gpu/gpu_windows.c | 7 ++ src/detection/vulkan/vulkan.c | 1 + src/modules/gpu/gpu.c | 7 +- src/util/windows/unicode.hpp | 5 ++ src/util/windows/variant.hpp | 137 ++++++++++++++++++++++++++++++++ src/util/windows/wmi.hpp | 137 +------------------------------- 12 files changed, 210 insertions(+), 136 deletions(-) create mode 100644 src/detection/gpu/gpu_apple.m create mode 100644 src/util/windows/variant.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a10d9449..ab3b72a22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -575,6 +575,7 @@ elseif(APPLE) src/detection/displayserver/displayserver_apple.c src/detection/font/font_apple.m src/detection/gpu/gpu_apple.c + src/detection/gpu/gpu_apple.m src/detection/host/host_apple.c src/detection/lm/lm_nosupport.c src/detection/icons/icons_nosupport.c @@ -905,6 +906,7 @@ elseif(APPLE) PRIVATE "-framework CoreWLAN" PRIVATE "-framework IOBluetooth" PRIVATE "-framework IOKit" + PRIVATE "-framework Metal" PRIVATE "-framework OpenGL" PRIVATE "-framework OpenCL" PRIVATE "-framework SystemConfiguration" diff --git a/src/detection/gpu/gpu.c b/src/detection/gpu/gpu.c index ef423d7be..3fd82ca6b 100644 --- a/src/detection/gpu/gpu.c +++ b/src/detection/gpu/gpu.c @@ -62,6 +62,7 @@ const char* detectByOpenGL(FFlist* gpus) ffStrbufInitMove(&gpu->vendor, &result.vendor); ffStrbufInitMove(&gpu->name, &result.renderer); ffStrbufInit(&gpu->driver); + ffStrbufInitF(&gpu->platformApi, "OpenGL %s", result.version.chars); gpu->temperature = FF_GPU_TEMP_UNSET; gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; gpu->frequency = FF_GPU_FREQUENCY_UNSET; diff --git a/src/detection/gpu/gpu.h b/src/detection/gpu/gpu.h index 23ebcc7f2..440d175d7 100644 --- a/src/detection/gpu/gpu.h +++ b/src/detection/gpu/gpu.h @@ -29,6 +29,7 @@ typedef struct FFGPUResult FFstrbuf vendor; FFstrbuf name; FFstrbuf driver; + FFstrbuf platformApi; double temperature; int32_t coreCount; double frequency; // Real time clock frequency in GHz diff --git a/src/detection/gpu/gpu_apple.c b/src/detection/gpu/gpu_apple.c index 4b164bac2..b7db8c562 100644 --- a/src/detection/gpu/gpu_apple.c +++ b/src/detection/gpu/gpu_apple.c @@ -6,6 +6,8 @@ #include +const char* ffGpuDetectMetal(FFlist* gpus); + static double detectGpuTemp(const FFstrbuf* gpuName) { double result = 0; @@ -55,6 +57,8 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->type = FF_GPU_TYPE_UNKNOWN; gpu->frequency = FF_GPU_FREQUENCY_UNSET; + IORegistryEntryGetRegistryEntryID(registryEntry, &gpu->deviceId); + ffStrbufInitStatic(&gpu->platformApi, "Metal"); ffStrbufInit(&gpu->driver); // Ok for both Apple and Intel ffCfDictGetString(properties, CFSTR("CFBundleIdentifier"), &gpu->driver); @@ -103,5 +107,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) } IOObjectRelease(iterator); + + ffGpuDetectMetal(gpus); return NULL; } diff --git a/src/detection/gpu/gpu_apple.m b/src/detection/gpu/gpu_apple.m new file mode 100644 index 000000000..1079ff1e0 --- /dev/null +++ b/src/detection/gpu/gpu_apple.m @@ -0,0 +1,40 @@ +#include "gpu.h" + +#import + +#ifndef MAC_OS_VERSION_13_0 + #define MTLGPUFamilyMetal3 ((MTLGPUFamily) 5001) +#endif + +const char* ffGpuDetectMetal(FFlist* gpus) +{ + if (@available(macOS 10.15, *)) + { + for (id device in MTLCopyAllDevices()) + { + FFGPUResult* gpu = NULL; + FF_LIST_FOR_EACH(FFGPUResult, x, *gpus) + { + if (x->deviceId == device.registryID || ffStrbufEqualS(&x->name, device.name.UTF8String)) + { + gpu = x; + break; + } + } + if (!gpu) continue; + + if ([device supportsFamily:MTLGPUFamilyMetal3]) + ffStrbufSetStatic(&gpu->platformApi, "Metal 3"); + else if ([device supportsFamily:MTLGPUFamilyCommon3]) + ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3"); + else if ([device supportsFamily:MTLGPUFamilyCommon2]) + ffStrbufSetStatic(&gpu->platformApi, "Metal Common 2"); + else if ([device supportsFamily:MTLGPUFamilyCommon1]) + ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1"); + + gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; + } + } + + return NULL; +} diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index a838269a4..1a7a19607 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -221,6 +221,8 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* FFGPUResult* gpu = ffListAdd(results); + ffStrbufInit(&gpu->platformApi); + ffStrbufInit(&gpu->vendor); pciDetectVendorName(gpu, pci, device); diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index db8e59379..b4ddadd46 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -74,6 +74,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* ffStrbufInit(&gpu->vendor); ffStrbufInitWS(&gpu->name, displayDevice.DeviceString); ffStrbufInit(&gpu->driver); + ffStrbufInitStatic(&gpu->platformApi, "Direct3D"); gpu->temperature = FF_GPU_TEMP_UNSET; gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; gpu->type = FF_GPU_TYPE_UNKNOWN; @@ -114,6 +115,12 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* } 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); } else if (!ffRegReadUint64(hKey, L"HardwareInformation.qwMemorySize", &gpu->dedicated.total, NULL)) { diff --git a/src/detection/vulkan/vulkan.c b/src/detection/vulkan/vulkan.c index 5d7fe431b..6331f7d70 100644 --- a/src/detection/vulkan/vulkan.c +++ b/src/detection/vulkan/vulkan.c @@ -181,6 +181,7 @@ static const char* detectVulkan(FFVulkanResult* result) FFGPUResult* gpu = ffListAdd(&result->gpus); + ffStrbufInitF(&gpu->platformApi, "Vulkan %u.%u.%u", deviceAPIVersion.major, deviceAPIVersion.minor, deviceAPIVersion.patch); gpu->deviceId = physicalDeviceProperties.properties.deviceID; ffStrbufInitS(&gpu->name, physicalDeviceProperties.properties.deviceName); diff --git a/src/modules/gpu/gpu.c b/src/modules/gpu/gpu.c index a3360ad96..7646ad5bd 100644 --- a/src/modules/gpu/gpu.c +++ b/src/modules/gpu/gpu.c @@ -9,7 +9,7 @@ #include -#define FF_GPU_NUM_FORMAT_ARGS 11 +#define FF_GPU_NUM_FORMAT_ARGS 12 static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResult* gpu) { @@ -83,6 +83,7 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu {FF_FORMAT_ARG_TYPE_UINT64, &gpu->dedicated.used}, {FF_FORMAT_ARG_TYPE_UINT64, &gpu->shared.total}, {FF_FORMAT_ARG_TYPE_UINT64, &gpu->shared.used}, + {FF_FORMAT_ARG_TYPE_STRBUF, &gpu->platformApi}, {FF_FORMAT_ARG_TYPE_DOUBLE, &gpu->frequency}, }); } @@ -309,6 +310,8 @@ void ffGenerateGPUJsonResult(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_ yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &gpu->vendor); + yyjson_mut_obj_add_strbuf(doc, obj, "platformApi", &gpu->platformApi); + if (gpu->frequency == FF_GPU_FREQUENCY_UNSET) yyjson_mut_obj_add_null(doc, obj, "frequency"); else @@ -336,6 +339,8 @@ void ffPrintGPUHelpFormat(void) "GPU used dedicated memory", "GPU total shared memory", "GPU used shared memory", + "The platform API that GPU supports", + "Current frequency in GHz", }); } diff --git a/src/util/windows/unicode.hpp b/src/util/windows/unicode.hpp index 18441a50d..b6745572b 100644 --- a/src/util/windows/unicode.hpp +++ b/src/util/windows/unicode.hpp @@ -11,6 +11,11 @@ extern "C" { #include +static inline void ffStrbufInitWSV(FFstrbuf* result, const std::wstring_view source) +{ + return ffStrbufInitNWS(result, (uint32_t) source.size(), source.data()); +} + static inline void ffStrbufSetWSV(FFstrbuf* result, const std::wstring_view source) { return ffStrbufSetNWS(result, (uint32_t) source.size(), source.data()); diff --git a/src/util/windows/variant.hpp b/src/util/windows/variant.hpp new file mode 100644 index 000000000..8181bd776 --- /dev/null +++ b/src/util/windows/variant.hpp @@ -0,0 +1,137 @@ +#include +#include +#include +#include + +struct FFWmiVariant: VARIANT +{ + explicit FFWmiVariant() { VariantInit(this); } + ~FFWmiVariant() { VariantClear(this); } + + FFWmiVariant(const FFWmiVariant&) = delete; + FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization + + bool hasValue() { + return this->vt != VT_EMPTY; + } + + explicit operator bool() { + return this->hasValue(); + } + + template T get() + { + // boolean + if constexpr (std::is_same_v) { + assert(this->vt == VT_BOOL); + return this->boolVal != VARIANT_FALSE; + } + + // signed + else if constexpr (std::is_same_v) { + assert(this->vt == VT_I1); + return this->cVal; + } + else if constexpr (std::is_same_v) { + assert(vt == VT_I2); + return this->iVal; + } + else if constexpr (std::is_same_v) { + assert(this->vt == VT_I4 || vt == VT_INT); + return this->intVal; + } + else if constexpr (std::is_same_v) { + assert(this->vt == VT_I8); + return this->llVal; + } + + // unsigned + else if constexpr (std::is_same_v) { + assert(this->vt == VT_UI1); + return this->bVal; + } + else if constexpr (std::is_same_v) { + assert(this->vt == VT_UI2); + return this->uiVal; + } + else if constexpr (std::is_same_v) { + assert(this->vt == VT_UI4 || vt == VT_UINT); + return this->uintVal; + } + else if constexpr (std::is_same_v) { + assert(this->vt == VT_UI8); + return this->ullVal; + } + + // decimal + else if constexpr (std::is_same_v) { + assert(this->vt == VT_R4); + return this->fltVal; + } + else if constexpr (std::is_same_v) { + assert(this->vt == VT_R8); + return this->dblVal; + } + + // string + else if constexpr (std::is_same_v) { + assert(this->vt == VT_LPSTR); + return this->pcVal; + } + else if constexpr (std::is_same_v) { + assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR); + if (this->vt == VT_LPWSTR) + return this->bstrVal; + else + return { this->bstrVal, SysStringLen(this->bstrVal) }; + } + + // array signed + else if constexpr (std::is_same_v>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_I1); + return std::make_pair((int8_t*)this->parray->pvData, this->parray->cDims); + } + else if constexpr (std::is_same_v>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_I2); + return std::make_pair((int16_t*)this->parray->pvData, this->parray->cDims); + } + else if constexpr (std::is_same_v>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_I4); + return std::make_pair((int32_t*)this->parray->pvData, this->parray->cDims); + } + else if constexpr (std::is_same_v>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_I8); + return std::make_pair((int64_t*)this->parray->pvData, this->parray->cDims); + } + + // array unsigned + else if constexpr (std::is_same_v>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_UI1); + return std::make_pair((uint8_t*)this->parray->pvData, this->parray->cDims); + } + else if constexpr (std::is_same_v>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_UI2); + return std::make_pair((uint16_t*)this->parray->pvData, this->parray->cDims); + } + else if constexpr (std::is_same_v>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_UI4); + return std::make_pair((uint32_t*)this->parray->pvData, this->parray->cDims); + } + else if constexpr (std::is_same_v>) { + assert(this->vt & VT_ARRAY); + assert((this->vt & ~VT_ARRAY) == VT_UI8); + return std::make_pair((uint64_t*)this->parray->pvData, this->parray->cDims); + } + else { + assert(false && "unsupported type"); + __builtin_unreachable(); + } + } +}; diff --git a/src/util/windows/wmi.hpp b/src/util/windows/wmi.hpp index 561f1ff5e..f9e3e9ae3 100644 --- a/src/util/windows/wmi.hpp +++ b/src/util/windows/wmi.hpp @@ -8,10 +8,9 @@ extern "C" { #include #include -#include -#include #include -#include + +#include "variant.hpp" enum class FFWmiNamespace { CIMV2, @@ -19,138 +18,6 @@ enum class FFWmiNamespace { LAST, }; -struct FFWmiVariant: VARIANT { - explicit FFWmiVariant() { VariantInit(this); } - ~FFWmiVariant() { VariantClear(this); } - - FFWmiVariant(const FFWmiVariant&) = delete; - FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization - - bool hasValue() { - return this->vt != VT_EMPTY; - } - - explicit operator bool() { - return this->hasValue(); - } - - template T get() - { - // boolean - if constexpr (std::is_same_v) { - assert(this->vt == VT_BOOL); - return this->boolVal != VARIANT_FALSE; - } - - // signed - else if constexpr (std::is_same_v) { - assert(this->vt == VT_I1); - return this->cVal; - } - else if constexpr (std::is_same_v) { - assert(vt == VT_I2); - return this->iVal; - } - else if constexpr (std::is_same_v) { - assert(this->vt == VT_I4 || vt == VT_INT); - return this->intVal; - } - else if constexpr (std::is_same_v) { - assert(this->vt == VT_I8); - return this->llVal; - } - - // unsigned - else if constexpr (std::is_same_v) { - assert(this->vt == VT_UI1); - return this->bVal; - } - else if constexpr (std::is_same_v) { - assert(this->vt == VT_UI2); - return this->uiVal; - } - else if constexpr (std::is_same_v) { - assert(this->vt == VT_UI4 || vt == VT_UINT); - return this->uintVal; - } - else if constexpr (std::is_same_v) { - assert(this->vt == VT_UI8); - return this->ullVal; - } - - // decimal - else if constexpr (std::is_same_v) { - assert(this->vt == VT_R4); - return this->fltVal; - } - else if constexpr (std::is_same_v) { - assert(this->vt == VT_R8); - return this->dblVal; - } - - // string - else if constexpr (std::is_same_v) { - assert(this->vt == VT_LPSTR); - return this->pcVal; - } - else if constexpr (std::is_same_v) { - assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR); - if (this->vt == VT_LPWSTR) - return this->bstrVal; - else - return { this->bstrVal, SysStringLen(this->bstrVal) }; - } - - // array signed - else if constexpr (std::is_same_v>) { - assert(this->vt & VT_ARRAY); - assert((this->vt & ~VT_ARRAY) == VT_I1); - return std::make_pair((int8_t*)this->parray->pvData, this->parray->cDims); - } - else if constexpr (std::is_same_v>) { - assert(this->vt & VT_ARRAY); - assert((this->vt & ~VT_ARRAY) == VT_I2); - return std::make_pair((int16_t*)this->parray->pvData, this->parray->cDims); - } - else if constexpr (std::is_same_v>) { - assert(this->vt & VT_ARRAY); - assert((this->vt & ~VT_ARRAY) == VT_I4); - return std::make_pair((int32_t*)this->parray->pvData, this->parray->cDims); - } - else if constexpr (std::is_same_v>) { - assert(this->vt & VT_ARRAY); - assert((this->vt & ~VT_ARRAY) == VT_I8); - return std::make_pair((int64_t*)this->parray->pvData, this->parray->cDims); - } - - // array unsigned - else if constexpr (std::is_same_v>) { - assert(this->vt & VT_ARRAY); - assert((this->vt & ~VT_ARRAY) == VT_UI1); - return std::make_pair((uint8_t*)this->parray->pvData, this->parray->cDims); - } - else if constexpr (std::is_same_v>) { - assert(this->vt & VT_ARRAY); - assert((this->vt & ~VT_ARRAY) == VT_UI2); - return std::make_pair((uint16_t*)this->parray->pvData, this->parray->cDims); - } - else if constexpr (std::is_same_v>) { - assert(this->vt & VT_ARRAY); - assert((this->vt & ~VT_ARRAY) == VT_UI4); - return std::make_pair((uint32_t*)this->parray->pvData, this->parray->cDims); - } - else if constexpr (std::is_same_v>) { - assert(this->vt & VT_ARRAY); - assert((this->vt & ~VT_ARRAY) == VT_UI8); - return std::make_pair((uint64_t*)this->parray->pvData, this->parray->cDims); - } - else { - assert(false && "unsupported type"); - __builtin_unreachable(); - } - } -}; - struct FFWmiRecord { IWbemClassObject* obj;