From c12772e4c6c367629bce22c7d171b3ab24102a44 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Sun, 17 Apr 2016 11:21:36 -0700 Subject: [PATCH] GPU identification utilities --- libraries/shared/CMakeLists.txt | 4 + libraries/shared/src/GPUIdent.cpp | 109 ++++++++++++++++++++++++++++ libraries/shared/src/GPUIdent.h | 36 +++++++++ libraries/shared/src/SharedUtil.cpp | 8 ++ 4 files changed, 157 insertions(+) create mode 100644 libraries/shared/src/GPUIdent.cpp create mode 100644 libraries/shared/src/GPUIdent.h diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 489819747f..da345d1970 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -3,5 +3,9 @@ set(TARGET_NAME shared) # TODO: there isn't really a good reason to have Script linked here - let's get what is requiring it out (RegisteredMetaTypes.cpp) setup_hifi_library(Gui Network Script Widgets) +if (WIN32) + target_link_libraries(${TARGET_NAME} Wbemuuid.lib) +endif() + target_zlib() target_nsight() diff --git a/libraries/shared/src/GPUIdent.cpp b/libraries/shared/src/GPUIdent.cpp new file mode 100644 index 0000000000..c7cadea821 --- /dev/null +++ b/libraries/shared/src/GPUIdent.cpp @@ -0,0 +1,109 @@ +// +// GPUIdent.cpp +// libraries/shared/src +// +// Created by Howard Stearns on 4/16/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +#include +#ifdef Q_OS_WIN +#include +#include +#endif + +#include "SharedLogging.h" +#include "GPUIdent.h" + +GPUIdent GPUIdent::_instance {}; + +GPUIdent* GPUIdent::ensureQuery() { + if (_isQueried) { + return this; + } + _isQueried = true; // Don't try again, even if not _isValid; +#ifdef Q_OS_WIN + // COM must be initialized already using CoInitialize. E.g., by the audio subsystem. + CComPtr spLoc = NULL; + HRESULT hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_SERVER, IID_IWbemLocator, (LPVOID *)&spLoc); + if (hr != S_OK || spLoc == NULL) { + qCDebug(shared) << "Unable to connect to WMI"; + return this; + } + + CComBSTR bstrNamespace(_T("\\\\.\\root\\CIMV2")); + CComPtr spServices; + + // Connect to CIM + hr = spLoc->ConnectServer(bstrNamespace, NULL, NULL, 0, NULL, 0, 0, &spServices); + if (hr != WBEM_S_NO_ERROR) { + qCDebug(shared) << "Unable to connect to CIM"; + return this; + } + + // Switch the security level to IMPERSONATE so that provider will grant access to system-level objects. + hr = CoSetProxyBlanket(spServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, /*EOAC_NONE*/EOAC_DEFAULT); + if (hr != S_OK) { + qCDebug(shared) << "Unable to authorize access to system objects."; + return this; + } + + // Get the vid controller + CComPtr spEnumInst = NULL; + hr = spServices->CreateInstanceEnum(CComBSTR("Win32_VideoController"), WBEM_FLAG_SHALLOW, NULL, &spEnumInst); + if (hr != WBEM_S_NO_ERROR || spEnumInst == NULL) { + qCDebug(shared) << "Unable to reach video controller."; + return this; + } + // alternative. We shouldn't need both this and the above. + IEnumWbemClassObject* pEnum; + hr = spServices->ExecQuery(CComBSTR("WQL"), CComBSTR("select * from Win32_VideoController"), WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum); + if (hr != S_OK) { + qCDebug(shared) << "Unable to query video controller"; + return this; + } + + ULONG uNumOfInstances = 0; + CComPtr spInstance = NULL; + hr = spEnumInst->Next(WBEM_INFINITE, 1, &spInstance, &uNumOfInstances); + + if (hr == S_OK && spInstance) { + // Get properties from the object + CComVariant var; + CIMTYPE type; + + hr = spInstance->Get(CComBSTR(_T("AdapterRAM")), 0, &var, 0, 0); + if (hr == S_OK) { + var.ChangeType(CIM_UINT32); // We're going to receive some integral type, but it might not be uint. + _dedicatedMemoryMB = var.uintVal / (1024 * 1024); + } else { + qCDebug(shared) << "Unable to get video AdapterRAM"; + } + + hr = spInstance->Get(CComBSTR(_T("Name")), 0, &var, 0, 0); + if (hr == S_OK) { + char sString[256]; + WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), NULL, NULL); + _name = sString; + } else { + qCDebug(shared) << "Unable to get video name"; + } + + hr = spInstance->Get(CComBSTR(_T("DriverVersion")), 0, &var, 0, 0); + if (hr == S_OK) { + char sString[256]; + WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), NULL, NULL); + _driver = sString; + } else { + qCDebug(shared) << "Unable to get video driver"; + } + + _isValid = true; + } else { + qCDebug(shared) << "Unable to enerate video adapters"; + } +#endif + return this; +} \ No newline at end of file diff --git a/libraries/shared/src/GPUIdent.h b/libraries/shared/src/GPUIdent.h new file mode 100644 index 0000000000..5c2504537f --- /dev/null +++ b/libraries/shared/src/GPUIdent.h @@ -0,0 +1,36 @@ +// +// GPUIdent.h +// libraries/shared/src +// +// Provides information about the GPU +// +// Created by Howard Stearns on 4/16/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_GPUIdent_h +#define hifi_GPUIdent_h + +class GPUIdent +{ +public: + unsigned int getMemory() { return _dedicatedMemoryMB; } + QString getName() { return _name; } + QString getDriver() { return _driver; } + bool isValid() { return _isValid; } + // E.g., GPUIdent::getInstance()->getMemory(); + static GPUIdent* getInstance() { return _instance.ensureQuery(); } +private: + uint _dedicatedMemoryMB { 0 }; + QString _name { "" }; + QString _driver { "" }; + bool _isQueried { false }; + bool _isValid { false }; + static GPUIdent _instance; + GPUIdent* ensureQuery(); +}; + +#endif // hifi_GPUIdent_h \ No newline at end of file diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 8f68e20222..64a874335b 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -26,6 +26,7 @@ #ifdef Q_OS_WIN #include "CPUIdent.h" #endif +#include "GPUIdent.h" #ifdef __APPLE__ @@ -750,6 +751,13 @@ void printSystemInformation() { qDebug().nospace().noquote() << "\t[" << (feature.supported ? "x" : " ") << "] " << feature.name.c_str(); } #endif + GPUIdent* gpu = GPUIdent::getInstance(); + if (gpu->isValid()) { + qDebug() << "GPU:"; + qDebug() << "\tcard:" << gpu->getName(); + qDebug() << "\tdriver:" << gpu->getDriver(); + qDebug() << "\tdedicated memory:" << gpu->getMemory() << "MB"; + } qDebug() << "Environment Variables"; // List of env variables to include in the log. For privacy reasons we don't send all env variables.