summaryrefslogtreecommitdiff
path: root/indra/llwindow/lldxhardware.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llwindow/lldxhardware.cpp')
-rw-r--r--indra/llwindow/lldxhardware.cpp2238
1 files changed, 1119 insertions, 1119 deletions
diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp
index f972e8f628..5d0e15d9f4 100644
--- a/indra/llwindow/lldxhardware.cpp
+++ b/indra/llwindow/lldxhardware.cpp
@@ -1,1119 +1,1119 @@
-/**
- * @file lldxhardware.cpp
- * @brief LLDXHardware implementation
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifdef LL_WINDOWS
-
-// Culled from some Microsoft sample code
-
-#include "linden_common.h"
-
-#define INITGUID
-#include <dxdiag.h>
-#undef INITGUID
-
-#include <wbemidl.h>
-#include <comdef.h>
-
-#include <boost/tokenizer.hpp>
-
-#include "lldxhardware.h"
-
-#include "llerror.h"
-
-#include "llstring.h"
-#include "llstl.h"
-#include "lltimer.h"
-
-void (*gWriteDebug)(const char* msg) = NULL;
-LLDXHardware gDXHardware;
-
-//-----------------------------------------------------------------------------
-// Defines, and constants
-//-----------------------------------------------------------------------------
-#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
-#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
-#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
-
-typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc,
- OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel,
- RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities );
-
-HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam)
-{
- HRESULT hr;
- bool bGotMemory = false;
- IWbemLocator* pIWbemLocator = nullptr;
- IWbemServices* pIWbemServices = nullptr;
- BSTR pNamespace = nullptr;
-
- *pdwAdapterRam = 0;
- CoInitializeEx(0, COINIT_APARTMENTTHREADED);
-
- hr = CoCreateInstance( CLSID_WbemLocator,
- nullptr,
- CLSCTX_INPROC_SERVER,
- IID_IWbemLocator,
- ( LPVOID* )&pIWbemLocator );
-#ifdef PRINTF_DEBUGGING
- if( FAILED( hr ) ) wprintf( L"WMI: CoCreateInstance failed: 0x%0.8x\n", hr );
-#endif
-
- if( SUCCEEDED( hr ) && pIWbemLocator )
- {
- // Using the locator, connect to WMI in the given namespace.
- pNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );
-
- hr = pIWbemLocator->ConnectServer( pNamespace, nullptr, nullptr, 0L,
- 0L, nullptr, nullptr, &pIWbemServices );
-#ifdef PRINTF_DEBUGGING
- if( FAILED( hr ) ) wprintf( L"WMI: pIWbemLocator->ConnectServer failed: 0x%0.8x\n", hr );
-#endif
- if( SUCCEEDED( hr ) && pIWbemServices != 0 )
- {
- HINSTANCE hinstOle32 = nullptr;
-
- hinstOle32 = LoadLibraryW( L"ole32.dll" );
- if( hinstOle32 )
- {
- PfnCoSetProxyBlanket pfnCoSetProxyBlanket = nullptr;
-
- pfnCoSetProxyBlanket = ( PfnCoSetProxyBlanket )GetProcAddress( hinstOle32, "CoSetProxyBlanket" );
- if( pfnCoSetProxyBlanket != 0 )
- {
- // Switch security level to IMPERSONATE.
- pfnCoSetProxyBlanket( pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
- RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, 0 );
- }
-
- FreeLibrary( hinstOle32 );
- }
-
- IEnumWbemClassObject* pEnumVideoControllers = nullptr;
- BSTR pClassName = nullptr;
-
- pClassName = SysAllocString( L"Win32_VideoController" );
-
- hr = pIWbemServices->CreateInstanceEnum( pClassName, 0,
- nullptr, &pEnumVideoControllers );
-#ifdef PRINTF_DEBUGGING
- if( FAILED( hr ) ) wprintf( L"WMI: pIWbemServices->CreateInstanceEnum failed: 0x%0.8x\n", hr );
-#endif
-
- if( SUCCEEDED( hr ) && pEnumVideoControllers )
- {
- IWbemClassObject* pVideoControllers[10] = {0};
- DWORD uReturned = 0;
- BSTR pPropName = nullptr;
-
- // Get the first one in the list
- pEnumVideoControllers->Reset();
- hr = pEnumVideoControllers->Next( 5000, // timeout in 5 seconds
- 10, // return the first 10
- pVideoControllers,
- &uReturned );
-#ifdef PRINTF_DEBUGGING
- if( FAILED( hr ) ) wprintf( L"WMI: pEnumVideoControllers->Next failed: 0x%0.8x\n", hr );
- if( uReturned == 0 ) wprintf( L"WMI: pEnumVideoControllers uReturned == 0\n" );
-#endif
-
- VARIANT var;
- if( SUCCEEDED( hr ) )
- {
- bool bFound = false;
- for( UINT iController = 0; iController < uReturned; iController++ )
- {
- if ( !pVideoControllers[iController] )
- continue;
-
- // if strInputDeviceID is set find this specific device and return memory or specific device
- // if strInputDeviceID is not set return the best device
- if (strInputDeviceID)
- {
- pPropName = SysAllocString( L"PNPDeviceID" );
- hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr );
-#ifdef PRINTF_DEBUGGING
- if( FAILED( hr ) )
- wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr );
-#endif
- if( SUCCEEDED( hr ) && strInputDeviceID)
- {
- if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 )
- bFound = true;
- }
- VariantClear( &var );
- if( pPropName ) SysFreeString( pPropName );
- }
-
- if( bFound || !strInputDeviceID )
- {
- pPropName = SysAllocString( L"AdapterRAM" );
- hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr );
-#ifdef PRINTF_DEBUGGING
- if( FAILED( hr ) )
- wprintf( L"WMI: pVideoControllers[iController]->Get AdapterRAM failed: 0x%0.8x\n",
- hr );
-#endif
- if( SUCCEEDED( hr ) )
- {
- bGotMemory = true;
- *pdwAdapterRam = llmax(var.ulVal, *pdwAdapterRam);
- }
- VariantClear( &var );
- if( pPropName ) SysFreeString( pPropName );
- }
-
- SAFE_RELEASE( pVideoControllers[iController] );
-
- if (bFound)
- {
- break;
- }
- }
- }
- }
-
- if( pClassName )
- SysFreeString( pClassName );
- SAFE_RELEASE( pEnumVideoControllers );
- }
-
- if( pNamespace )
- SysFreeString( pNamespace );
- SAFE_RELEASE( pIWbemServices );
- }
-
- SAFE_RELEASE( pIWbemLocator );
-
- CoUninitialize();
-
- if( bGotMemory )
- return S_OK;
- else
- return E_FAIL;
-}
-
-//static
-S32 LLDXHardware::getMBVideoMemoryViaWMI()
-{
- DWORD vram = 0;
- if (SUCCEEDED(GetVideoMemoryViaWMI(NULL, &vram)))
- {
- return vram / (1024 * 1024);;
- }
- return 0;
-}
-
-//Getting the version of graphics controller driver via WMI
-std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor)
-{
- std::string mDriverVersion;
- HRESULT hres;
- CoInitializeEx(0, COINIT_APARTMENTTHREADED);
- IWbemLocator *pLoc = NULL;
-
- hres = CoCreateInstance(
- CLSID_WbemLocator,
- 0,
- CLSCTX_INPROC_SERVER,
- IID_IWbemLocator, (LPVOID *)&pLoc);
-
- if (FAILED(hres))
- {
- LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << hres << LL_ENDL;
- return std::string(); // Program has failed.
- }
-
- IWbemServices *pSvc = NULL;
-
- // Connect to the root\cimv2 namespace with
- // the current user and obtain pointer pSvc
- // to make IWbemServices calls.
- hres = pLoc->ConnectServer(
- _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
- NULL, // User name. NULL = current user
- NULL, // User password. NULL = current
- 0, // Locale. NULL indicates current
- NULL, // Security flags.
- 0, // Authority (e.g. Kerberos)
- 0, // Context object
- &pSvc // pointer to IWbemServices proxy
- );
-
- if (FAILED(hres))
- {
- LL_WARNS("AppInit") << "Could not connect. Error code = 0x" << hres << LL_ENDL;
- pLoc->Release();
- CoUninitialize();
- return std::string(); // Program has failed.
- }
-
- LL_DEBUGS("AppInit") << "Connected to ROOT\\CIMV2 WMI namespace" << LL_ENDL;
-
- // Set security levels on the proxy -------------------------
- hres = CoSetProxyBlanket(
- pSvc, // Indicates the proxy to set
- RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
- RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
- NULL, // Server principal name
- RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
- RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
- NULL, // client identity
- EOAC_NONE // proxy capabilities
- );
-
- if (FAILED(hres))
- {
- LL_WARNS("AppInit") << "Could not set proxy blanket. Error code = 0x" << hres << LL_ENDL;
- pSvc->Release();
- pLoc->Release();
- CoUninitialize();
- return std::string(); // Program has failed.
- }
- IEnumWbemClassObject* pEnumerator = NULL;
-
- // Get the data from the query
- ULONG uReturn = 0;
- hres = pSvc->ExecQuery(
- bstr_t("WQL"),
- bstr_t("SELECT * FROM Win32_VideoController"), //Consider using Availability to filter out disabled controllers
- WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
- NULL,
- &pEnumerator);
-
- if (FAILED(hres))
- {
- LL_WARNS("AppInit") << "Query for operating system name failed." << " Error code = 0x" << hres << LL_ENDL;
- pSvc->Release();
- pLoc->Release();
- CoUninitialize();
- return std::string(); // Program has failed.
- }
-
- while (pEnumerator)
- {
- IWbemClassObject *pclsObj = NULL;
- HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
- &pclsObj, &uReturn);
-
- if (0 == uReturn)
- {
- break; // If quantity less then 1.
- }
-
- if (vendor != GPU_ANY)
- {
- VARIANT vtCaptionProp;
- // Might be preferable to check "AdapterCompatibility" here instead of caption.
- hr = pclsObj->Get(L"Caption", 0, &vtCaptionProp, 0, 0);
-
- if (FAILED(hr))
- {
- LL_WARNS("AppInit") << "Query for Caption property failed." << " Error code = 0x" << hr << LL_ENDL;
- pSvc->Release();
- pLoc->Release();
- CoUninitialize();
- return std::string(); // Program has failed.
- }
-
- // use characters in the returned driver version
- BSTR caption(vtCaptionProp.bstrVal);
-
- //convert BSTR to std::string
- std::wstring ws(caption, SysStringLen(caption));
- std::string caption_str(ws.begin(), ws.end());
- LLStringUtil::toLower(caption_str);
-
- bool found = false;
- switch (vendor)
- {
- case GPU_INTEL:
- found = caption_str.find("intel") != std::string::npos;
- break;
- case GPU_NVIDIA:
- found = caption_str.find("nvidia") != std::string::npos;
- break;
- case GPU_AMD:
- found = caption_str.find("amd") != std::string::npos
- || caption_str.find("ati ") != std::string::npos
- || caption_str.find("radeon") != std::string::npos;
- break;
- default:
- break;
- }
-
- if (found)
- {
- VariantClear(&vtCaptionProp);
- }
- else
- {
- VariantClear(&vtCaptionProp);
- pclsObj->Release();
- continue;
- }
- }
-
- VARIANT vtVersionProp;
-
- // Get the value of the DriverVersion property
- hr = pclsObj->Get(L"DriverVersion", 0, &vtVersionProp, 0, 0);
-
- if (FAILED(hr))
- {
- LL_WARNS("AppInit") << "Query for DriverVersion property failed." << " Error code = 0x" << hr << LL_ENDL;
- pSvc->Release();
- pLoc->Release();
- CoUninitialize();
- return std::string(); // Program has failed.
- }
-
- // use characters in the returned driver version
- BSTR driverVersion(vtVersionProp.bstrVal);
-
- //convert BSTR to std::string
- std::wstring ws(driverVersion, SysStringLen(driverVersion));
- std::string str(ws.begin(), ws.end());
- LL_INFOS("AppInit") << " DriverVersion : " << str << LL_ENDL;
-
- if (mDriverVersion.empty())
- {
- mDriverVersion = str;
- }
- else if (mDriverVersion != str)
- {
- if (vendor == GPU_ANY)
- {
- // Expected from systems with gpus from different vendors
- LL_INFOS("DriverVersion") << "Multiple video drivers detected. Version of second driver: " << str << LL_ENDL;
- }
- else
- {
- // Not Expected!
- LL_WARNS("DriverVersion") << "Multiple video drivers detected from same vendor. Version of second driver : " << str << LL_ENDL;
- }
- }
-
- VariantClear(&vtVersionProp);
- pclsObj->Release();
- }
-
- // Cleanup
- // ========
- if (pSvc)
- {
- pSvc->Release();
- }
- if (pLoc)
- {
- pLoc->Release();
- }
- if (pEnumerator)
- {
- pEnumerator->Release();
- }
-
- // supposed to always call CoUninitialize even if init returned false
- CoUninitialize();
-
- return mDriverVersion;
-}
-
-void get_wstring(IDxDiagContainer* containerp, WCHAR* wszPropName, WCHAR* wszPropValue, int outputSize)
-{
- HRESULT hr;
- VARIANT var;
-
- VariantInit( &var );
- hr = containerp->GetProp(wszPropName, &var );
- if( SUCCEEDED(hr) )
- {
- // Switch off the type. There's 4 different types:
- switch( var.vt )
- {
- case VT_UI4:
- swprintf( wszPropValue, L"%d", var.ulVal ); /* Flawfinder: ignore */
- break;
- case VT_I4:
- swprintf( wszPropValue, L"%d", var.lVal ); /* Flawfinder: ignore */
- break;
- case VT_BOOL:
- wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" ); /* Flawfinder: ignore */
- break;
- case VT_BSTR:
- wcsncpy( wszPropValue, var.bstrVal, outputSize-1 ); /* Flawfinder: ignore */
- wszPropValue[outputSize-1] = 0;
- break;
- }
- }
- // Clear the variant (this is needed to free BSTR memory)
- VariantClear( &var );
-}
-
-std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName)
-{
- WCHAR wszPropValue[256];
- get_wstring(containerp, wszPropName, wszPropValue, 256);
-
- return utf16str_to_utf8str(wszPropValue);
-}
-
-
-LLVersion::LLVersion()
-{
- mValid = FALSE;
- S32 i;
- for (i = 0; i < 4; i++)
- {
- mFields[i] = 0;
- }
-}
-
-BOOL LLVersion::set(const std::string &version_string)
-{
- S32 i;
- for (i = 0; i < 4; i++)
- {
- mFields[i] = 0;
- }
- // Split the version string.
- std::string str(version_string);
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep(".", "", boost::keep_empty_tokens);
- tokenizer tokens(str, sep);
-
- tokenizer::iterator iter = tokens.begin();
- S32 count = 0;
- for (;(iter != tokens.end()) && (count < 4);++iter)
- {
- mFields[count] = atoi(iter->c_str());
- count++;
- }
- if (count < 4)
- {
- //LL_WARNS() << "Potentially bogus version string!" << version_string << LL_ENDL;
- for (i = 0; i < 4; i++)
- {
- mFields[i] = 0;
- }
- mValid = FALSE;
- }
- else
- {
- mValid = TRUE;
- }
- return mValid;
-}
-
-S32 LLVersion::getField(const S32 field_num)
-{
- if (!mValid)
- {
- return -1;
- }
- else
- {
- return mFields[field_num];
- }
-}
-
-std::string LLDXDriverFile::dump()
-{
- if (gWriteDebug)
- {
- gWriteDebug("Filename:");
- gWriteDebug(mName.c_str());
- gWriteDebug("\n");
- gWriteDebug("Ver:");
- gWriteDebug(mVersionString.c_str());
- gWriteDebug("\n");
- gWriteDebug("Date:");
- gWriteDebug(mDateString.c_str());
- gWriteDebug("\n");
- }
- LL_INFOS() << mFilepath << LL_ENDL;
- LL_INFOS() << mName << LL_ENDL;
- LL_INFOS() << mVersionString << LL_ENDL;
- LL_INFOS() << mDateString << LL_ENDL;
-
- return "";
-}
-
-LLDXDevice::~LLDXDevice()
-{
- for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer());
- mDriverFiles.clear();
-}
-
-std::string LLDXDevice::dump()
-{
- if (gWriteDebug)
- {
- gWriteDebug("StartDevice\n");
- gWriteDebug("DeviceName:");
- gWriteDebug(mName.c_str());
- gWriteDebug("\n");
- gWriteDebug("PCIString:");
- gWriteDebug(mPCIString.c_str());
- gWriteDebug("\n");
- }
- LL_INFOS() << LL_ENDL;
- LL_INFOS() << "DeviceName:" << mName << LL_ENDL;
- LL_INFOS() << "PCIString:" << mPCIString << LL_ENDL;
- LL_INFOS() << "Drivers" << LL_ENDL;
- LL_INFOS() << "-------" << LL_ENDL;
- for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
- end = mDriverFiles.end();
- iter != end; iter++)
- {
- LLDXDriverFile *filep = iter->second;
- filep->dump();
- }
- if (gWriteDebug)
- {
- gWriteDebug("EndDevice\n");
- }
-
- return "";
-}
-
-LLDXDriverFile *LLDXDevice::findDriver(const std::string &driver)
-{
- for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
- end = mDriverFiles.end();
- iter != end; iter++)
- {
- LLDXDriverFile *filep = iter->second;
- if (!utf8str_compare_insensitive(filep->mName,driver))
- {
- return filep;
- }
- }
-
- return NULL;
-}
-
-LLDXHardware::LLDXHardware()
-{
- mVRAM = 0;
- gWriteDebug = NULL;
-}
-
-void LLDXHardware::cleanup()
-{
- // for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer());
- // mDevices.clear();
-}
-
-/*
-std::string LLDXHardware::dumpDevices()
-{
- if (gWriteDebug)
- {
- gWriteDebug("\n");
- gWriteDebug("StartAllDevices\n");
- }
- for (device_map_t::iterator iter = mDevices.begin(),
- end = mDevices.end();
- iter != end; iter++)
- {
- LLDXDevice *devicep = iter->second;
- devicep->dump();
- }
- if (gWriteDebug)
- {
- gWriteDebug("EndAllDevices\n\n");
- }
- return "";
-}
-
-LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::string &devices)
-{
- // Iterate through different devices tokenized in devices string
- std::string str(devices);
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
- tokenizer tokens(str, sep);
-
- tokenizer::iterator iter = tokens.begin();
- for (;iter != tokens.end();++iter)
- {
- std::string dev_str = *iter;
- for (device_map_t::iterator iter = mDevices.begin(),
- end = mDevices.end();
- iter != end; iter++)
- {
- LLDXDevice *devicep = iter->second;
- if ((devicep->mVendorID == vendor)
- && (devicep->mDeviceID == dev_str))
- {
- return devicep;
- }
- }
- }
-
- return NULL;
-}
-*/
-
-BOOL LLDXHardware::getInfo(BOOL vram_only)
-{
- LLTimer hw_timer;
- BOOL ok = FALSE;
- HRESULT hr;
-
- // CLSID_DxDiagProvider does not work with Multithreaded?
- CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
-
- IDxDiagProvider *dx_diag_providerp = NULL;
- IDxDiagContainer *dx_diag_rootp = NULL;
- IDxDiagContainer *devices_containerp = NULL;
- // IDxDiagContainer *system_device_containerp= NULL;
- IDxDiagContainer *device_containerp = NULL;
- IDxDiagContainer *file_containerp = NULL;
- IDxDiagContainer *driver_containerp = NULL;
- DWORD dw_device_count;
-
- mVRAM = 0;
-
- // CoCreate a IDxDiagProvider*
- LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL;
- hr = CoCreateInstance(CLSID_DxDiagProvider,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_IDxDiagProvider,
- (LPVOID*) &dx_diag_providerp);
-
- if (FAILED(hr))
- {
- LL_WARNS("AppInit") << "No DXDiag provider found! DirectX 9 not installed!" << LL_ENDL;
- gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n");
- goto LCleanup;
- }
- if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
- {
- // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
- // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are
- // digital signed as logo'd by WHQL which may connect via internet to update
- // WHQL certificates.
- DXDIAG_INIT_PARAMS dx_diag_init_params;
- ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
-
- dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS);
- dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
- dx_diag_init_params.bAllowWHQLChecks = TRUE;
- dx_diag_init_params.pReserved = NULL;
-
- LL_DEBUGS("AppInit") << "dx_diag_providerp->Initialize" << LL_ENDL;
- hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
- if(FAILED(hr))
- {
- goto LCleanup;
- }
-
- LL_DEBUGS("AppInit") << "dx_diag_providerp->GetRootContainer" << LL_ENDL;
- hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
- if(FAILED(hr) || !dx_diag_rootp)
- {
- goto LCleanup;
- }
-
- HRESULT hr;
-
- // Get display driver information
- LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer" << LL_ENDL;
- hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
- if(FAILED(hr) || !devices_containerp)
- {
- // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp
- devices_containerp = NULL;
- goto LCleanup;
- }
-
- // make sure there is something inside
- hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count);
- if (FAILED(hr) || dw_device_count == 0)
- {
- goto LCleanup;
- }
-
- // Get device 0
- // By default 0 device is the primary one, howhever in case of various hybrid graphics
- // like itegrated AMD and PCI AMD GPUs system might switch.
- LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL;
- hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
- if(FAILED(hr) || !device_containerp)
- {
- goto LCleanup;
- }
-
- DWORD vram = 0;
-
- WCHAR deviceID[512];
-
- get_wstring(device_containerp, L"szDeviceID", deviceID, 512);
- // Example: searches id like 1F06 in pnp string (aka VEN_10DE&DEV_1F06)
- // doesn't seem to work on some systems since format is unrecognizable
- // but in such case keyDeviceID works
- if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram)))
- {
- mVRAM = vram/(1024*1024);
- }
- else
- {
- get_wstring(device_containerp, L"szKeyDeviceID", deviceID, 512);
- LL_WARNS() << "szDeviceID" << deviceID << LL_ENDL;
- // '+9' to avoid ENUM\\PCI\\ prefix
- // Returns string like Enum\\PCI\\VEN_10DE&DEV_1F06&SUBSYS...
- // and since GetVideoMemoryViaWMI searches by PNPDeviceID it is sufficient
- if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID + 9, &vram)))
- {
- mVRAM = vram / (1024 * 1024);
- }
- }
-
- if (mVRAM == 0)
- { // Get the English VRAM string
- std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
-
- // We don't need the device any more
- SAFE_RELEASE(device_containerp);
-
- // Dump the string as an int into the structure
- char *stopstring;
- mVRAM = strtol(ram_str.c_str(), &stopstring, 10);
- LL_INFOS("AppInit") << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << LL_ENDL;
- }
-
- if (vram_only)
- {
- ok = TRUE;
- goto LCleanup;
- }
-
-
- /* for now, we ONLY do vram_only the rest of this
- is commented out, to ensure no-one is tempted
- to use it
-
- // Now let's get device and driver information
- // Get the IDxDiagContainer object called "DxDiag_SystemDevices".
- // This call may take some time while dxdiag gathers the info.
- DWORD num_devices = 0;
- WCHAR wszContainer[256];
- LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << LL_ENDL;
- hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp);
- if (FAILED(hr))
- {
- goto LCleanup;
- }
-
- hr = system_device_containerp->GetNumberOfChildContainers(&num_devices);
- if (FAILED(hr))
- {
- goto LCleanup;
- }
-
- LL_DEBUGS("AppInit") << "DX9 iterating over devices" << LL_ENDL;
- S32 device_num = 0;
- for (device_num = 0; device_num < (S32)num_devices; device_num++)
- {
- hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256);
- if (FAILED(hr))
- {
- goto LCleanup;
- }
-
- hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp);
- if (FAILED(hr) || device_containerp == NULL)
- {
- goto LCleanup;
- }
-
- std::string device_name = get_string(device_containerp, L"szDescription");
-
- std::string device_id = get_string(device_containerp, L"szDeviceID");
-
- LLDXDevice *dxdevicep = new LLDXDevice;
- dxdevicep->mName = device_name;
- dxdevicep->mPCIString = device_id;
- mDevices[dxdevicep->mPCIString] = dxdevicep;
-
- // Split the PCI string based on vendor, device, subsys, rev.
- std::string str(device_id);
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("&\\", "", boost::keep_empty_tokens);
- tokenizer tokens(str, sep);
-
- tokenizer::iterator iter = tokens.begin();
- S32 count = 0;
- BOOL valid = TRUE;
- for (;(iter != tokens.end()) && (count < 3);++iter)
- {
- switch (count)
- {
- case 0:
- if (strcmp(iter->c_str(), "PCI"))
- {
- valid = FALSE;
- }
- break;
- case 1:
- dxdevicep->mVendorID = iter->c_str();
- break;
- case 2:
- dxdevicep->mDeviceID = iter->c_str();
- break;
- default:
- // Ignore it
- break;
- }
- count++;
- }
-
-
-
-
- // Now, iterate through the related drivers
- hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp);
- if (FAILED(hr) || !driver_containerp)
- {
- goto LCleanup;
- }
-
- DWORD num_files = 0;
- hr = driver_containerp->GetNumberOfChildContainers(&num_files);
- if (FAILED(hr))
- {
- goto LCleanup;
- }
-
- S32 file_num = 0;
- for (file_num = 0; file_num < (S32)num_files; file_num++ )
- {
-
- hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256);
- if (FAILED(hr))
- {
- goto LCleanup;
- }
-
- hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp);
- if (FAILED(hr) || file_containerp == NULL)
- {
- goto LCleanup;
- }
-
- std::string driver_path = get_string(file_containerp, L"szPath");
- std::string driver_name = get_string(file_containerp, L"szName");
- std::string driver_version = get_string(file_containerp, L"szVersion");
- std::string driver_date = get_string(file_containerp, L"szDatestampEnglish");
-
- LLDXDriverFile *dxdriverfilep = new LLDXDriverFile;
- dxdriverfilep->mName = driver_name;
- dxdriverfilep->mFilepath= driver_path;
- dxdriverfilep->mVersionString = driver_version;
- dxdriverfilep->mVersion.set(driver_version);
- dxdriverfilep->mDateString = driver_date;
-
- dxdevicep->mDriverFiles[driver_name] = dxdriverfilep;
-
- SAFE_RELEASE(file_containerp);
- }
- SAFE_RELEASE(device_containerp);
- }
- */
- }
-
- // dumpDevices();
- ok = TRUE;
-
-LCleanup:
- if (!ok)
- {
- LL_WARNS("AppInit") << "DX9 probe failed" << LL_ENDL;
- gWriteDebug("DX9 probe failed\n");
- }
-
- SAFE_RELEASE(file_containerp);
- SAFE_RELEASE(driver_containerp);
- SAFE_RELEASE(device_containerp);
- SAFE_RELEASE(devices_containerp);
- SAFE_RELEASE(dx_diag_rootp);
- SAFE_RELEASE(dx_diag_providerp);
-
- CoUninitialize();
-
- return ok;
- }
-
-LLSD LLDXHardware::getDisplayInfo()
-{
- LLTimer hw_timer;
- HRESULT hr;
- LLSD ret;
- CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
-
- IDxDiagProvider *dx_diag_providerp = NULL;
- IDxDiagContainer *dx_diag_rootp = NULL;
- IDxDiagContainer *devices_containerp = NULL;
- IDxDiagContainer *device_containerp = NULL;
- IDxDiagContainer *file_containerp = NULL;
- IDxDiagContainer *driver_containerp = NULL;
- DWORD dw_device_count;
-
- // CoCreate a IDxDiagProvider*
- LL_INFOS() << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL;
- hr = CoCreateInstance(CLSID_DxDiagProvider,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_IDxDiagProvider,
- (LPVOID*) &dx_diag_providerp);
-
- if (FAILED(hr))
- {
- LL_WARNS() << "No DXDiag provider found! DirectX 9 not installed!" << LL_ENDL;
- gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n");
- goto LCleanup;
- }
- if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
- {
- // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
- // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are
- // digital signed as logo'd by WHQL which may connect via internet to update
- // WHQL certificates.
- DXDIAG_INIT_PARAMS dx_diag_init_params;
- ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
-
- dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS);
- dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
- dx_diag_init_params.bAllowWHQLChecks = TRUE;
- dx_diag_init_params.pReserved = NULL;
-
- LL_INFOS() << "dx_diag_providerp->Initialize" << LL_ENDL;
- hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
- if(FAILED(hr))
- {
- goto LCleanup;
- }
-
- LL_INFOS() << "dx_diag_providerp->GetRootContainer" << LL_ENDL;
- hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
- if(FAILED(hr) || !dx_diag_rootp)
- {
- goto LCleanup;
- }
-
- HRESULT hr;
-
- // Get display driver information
- LL_INFOS() << "dx_diag_rootp->GetChildContainer" << LL_ENDL;
- hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
- if(FAILED(hr) || !devices_containerp)
- {
- // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp
- devices_containerp = NULL;
- goto LCleanup;
- }
-
- // make sure there is something inside
- hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count);
- if (FAILED(hr) || dw_device_count == 0)
- {
- goto LCleanup;
- }
-
- // Get device 0
- LL_INFOS() << "devices_containerp->GetChildContainer" << LL_ENDL;
- hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
- if(FAILED(hr) || !device_containerp)
- {
- goto LCleanup;
- }
-
- // Get the English VRAM string
- std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
-
-
- // Dump the string as an int into the structure
- char *stopstring;
- ret["VRAM"] = strtol(ram_str.c_str(), &stopstring, 10);
- std::string device_name = get_string(device_containerp, L"szDescription");
- ret["DeviceName"] = device_name;
- std::string device_driver= get_string(device_containerp, L"szDriverVersion");
- ret["DriverVersion"] = device_driver;
-
- // ATI has a slightly different version string
- if(device_name.length() >= 4 && device_name.substr(0,4) == "ATI ")
- {
- // get the key
- HKEY hKey;
- const DWORD RV_SIZE = 100;
- WCHAR release_version[RV_SIZE];
-
- // Hard coded registry entry. Using this since it's simpler for now.
- // And using EnumDisplayDevices to get a registry key also requires
- // a hard coded Query value.
- if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\ATI Technologies\\CBT"), &hKey))
- {
- // get the value
- DWORD dwType = REG_SZ;
- DWORD dwSize = sizeof(WCHAR) * RV_SIZE;
- if(ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("ReleaseVersion"),
- NULL, &dwType, (LPBYTE)release_version, &dwSize))
- {
- // print the value
- // windows doesn't guarantee to be null terminated
- release_version[RV_SIZE - 1] = NULL;
- ret["DriverVersion"] = utf16str_to_utf8str(release_version);
-
- }
- RegCloseKey(hKey);
- }
- }
- }
-
-LCleanup:
- if (!ret.isMap() || (ret.size() == 0))
- {
- LL_INFOS() << "Failed to get data, cleaning up" << LL_ENDL;
- }
- SAFE_RELEASE(file_containerp);
- SAFE_RELEASE(driver_containerp);
- SAFE_RELEASE(device_containerp);
- SAFE_RELEASE(devices_containerp);
- SAFE_RELEASE(dx_diag_rootp);
- SAFE_RELEASE(dx_diag_providerp);
-
- CoUninitialize();
- return ret;
-}
-
-void LLDXHardware::setWriteDebugFunc(void (*func)(const char*))
-{
- gWriteDebug = func;
-}
-
-#endif
+/**
+ * @file lldxhardware.cpp
+ * @brief LLDXHardware implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifdef LL_WINDOWS
+
+// Culled from some Microsoft sample code
+
+#include "linden_common.h"
+
+#define INITGUID
+#include <dxdiag.h>
+#undef INITGUID
+
+#include <wbemidl.h>
+#include <comdef.h>
+
+#include <boost/tokenizer.hpp>
+
+#include "lldxhardware.h"
+
+#include "llerror.h"
+
+#include "llstring.h"
+#include "llstl.h"
+#include "lltimer.h"
+
+void (*gWriteDebug)(const char* msg) = NULL;
+LLDXHardware gDXHardware;
+
+//-----------------------------------------------------------------------------
+// Defines, and constants
+//-----------------------------------------------------------------------------
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc,
+ OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel,
+ RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities );
+
+HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam)
+{
+ HRESULT hr;
+ bool bGotMemory = false;
+ IWbemLocator* pIWbemLocator = nullptr;
+ IWbemServices* pIWbemServices = nullptr;
+ BSTR pNamespace = nullptr;
+
+ *pdwAdapterRam = 0;
+ CoInitializeEx(0, COINIT_APARTMENTTHREADED);
+
+ hr = CoCreateInstance( CLSID_WbemLocator,
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator,
+ ( LPVOID* )&pIWbemLocator );
+#ifdef PRINTF_DEBUGGING
+ if( FAILED( hr ) ) wprintf( L"WMI: CoCreateInstance failed: 0x%0.8x\n", hr );
+#endif
+
+ if( SUCCEEDED( hr ) && pIWbemLocator )
+ {
+ // Using the locator, connect to WMI in the given namespace.
+ pNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );
+
+ hr = pIWbemLocator->ConnectServer( pNamespace, nullptr, nullptr, 0L,
+ 0L, nullptr, nullptr, &pIWbemServices );
+#ifdef PRINTF_DEBUGGING
+ if( FAILED( hr ) ) wprintf( L"WMI: pIWbemLocator->ConnectServer failed: 0x%0.8x\n", hr );
+#endif
+ if( SUCCEEDED( hr ) && pIWbemServices != 0 )
+ {
+ HINSTANCE hinstOle32 = nullptr;
+
+ hinstOle32 = LoadLibraryW( L"ole32.dll" );
+ if( hinstOle32 )
+ {
+ PfnCoSetProxyBlanket pfnCoSetProxyBlanket = nullptr;
+
+ pfnCoSetProxyBlanket = ( PfnCoSetProxyBlanket )GetProcAddress( hinstOle32, "CoSetProxyBlanket" );
+ if( pfnCoSetProxyBlanket != 0 )
+ {
+ // Switch security level to IMPERSONATE.
+ pfnCoSetProxyBlanket( pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
+ RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, 0 );
+ }
+
+ FreeLibrary( hinstOle32 );
+ }
+
+ IEnumWbemClassObject* pEnumVideoControllers = nullptr;
+ BSTR pClassName = nullptr;
+
+ pClassName = SysAllocString( L"Win32_VideoController" );
+
+ hr = pIWbemServices->CreateInstanceEnum( pClassName, 0,
+ nullptr, &pEnumVideoControllers );
+#ifdef PRINTF_DEBUGGING
+ if( FAILED( hr ) ) wprintf( L"WMI: pIWbemServices->CreateInstanceEnum failed: 0x%0.8x\n", hr );
+#endif
+
+ if( SUCCEEDED( hr ) && pEnumVideoControllers )
+ {
+ IWbemClassObject* pVideoControllers[10] = {0};
+ DWORD uReturned = 0;
+ BSTR pPropName = nullptr;
+
+ // Get the first one in the list
+ pEnumVideoControllers->Reset();
+ hr = pEnumVideoControllers->Next( 5000, // timeout in 5 seconds
+ 10, // return the first 10
+ pVideoControllers,
+ &uReturned );
+#ifdef PRINTF_DEBUGGING
+ if( FAILED( hr ) ) wprintf( L"WMI: pEnumVideoControllers->Next failed: 0x%0.8x\n", hr );
+ if( uReturned == 0 ) wprintf( L"WMI: pEnumVideoControllers uReturned == 0\n" );
+#endif
+
+ VARIANT var;
+ if( SUCCEEDED( hr ) )
+ {
+ bool bFound = false;
+ for( UINT iController = 0; iController < uReturned; iController++ )
+ {
+ if ( !pVideoControllers[iController] )
+ continue;
+
+ // if strInputDeviceID is set find this specific device and return memory or specific device
+ // if strInputDeviceID is not set return the best device
+ if (strInputDeviceID)
+ {
+ pPropName = SysAllocString( L"PNPDeviceID" );
+ hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr );
+#ifdef PRINTF_DEBUGGING
+ if( FAILED( hr ) )
+ wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr );
+#endif
+ if( SUCCEEDED( hr ) && strInputDeviceID)
+ {
+ if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 )
+ bFound = true;
+ }
+ VariantClear( &var );
+ if( pPropName ) SysFreeString( pPropName );
+ }
+
+ if( bFound || !strInputDeviceID )
+ {
+ pPropName = SysAllocString( L"AdapterRAM" );
+ hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr );
+#ifdef PRINTF_DEBUGGING
+ if( FAILED( hr ) )
+ wprintf( L"WMI: pVideoControllers[iController]->Get AdapterRAM failed: 0x%0.8x\n",
+ hr );
+#endif
+ if( SUCCEEDED( hr ) )
+ {
+ bGotMemory = true;
+ *pdwAdapterRam = llmax(var.ulVal, *pdwAdapterRam);
+ }
+ VariantClear( &var );
+ if( pPropName ) SysFreeString( pPropName );
+ }
+
+ SAFE_RELEASE( pVideoControllers[iController] );
+
+ if (bFound)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ if( pClassName )
+ SysFreeString( pClassName );
+ SAFE_RELEASE( pEnumVideoControllers );
+ }
+
+ if( pNamespace )
+ SysFreeString( pNamespace );
+ SAFE_RELEASE( pIWbemServices );
+ }
+
+ SAFE_RELEASE( pIWbemLocator );
+
+ CoUninitialize();
+
+ if( bGotMemory )
+ return S_OK;
+ else
+ return E_FAIL;
+}
+
+//static
+S32 LLDXHardware::getMBVideoMemoryViaWMI()
+{
+ DWORD vram = 0;
+ if (SUCCEEDED(GetVideoMemoryViaWMI(NULL, &vram)))
+ {
+ return vram / (1024 * 1024);;
+ }
+ return 0;
+}
+
+//Getting the version of graphics controller driver via WMI
+std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor)
+{
+ std::string mDriverVersion;
+ HRESULT hres;
+ CoInitializeEx(0, COINIT_APARTMENTTHREADED);
+ IWbemLocator *pLoc = NULL;
+
+ hres = CoCreateInstance(
+ CLSID_WbemLocator,
+ 0,
+ CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator, (LPVOID *)&pLoc);
+
+ if (FAILED(hres))
+ {
+ LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << hres << LL_ENDL;
+ return std::string(); // Program has failed.
+ }
+
+ IWbemServices *pSvc = NULL;
+
+ // Connect to the root\cimv2 namespace with
+ // the current user and obtain pointer pSvc
+ // to make IWbemServices calls.
+ hres = pLoc->ConnectServer(
+ _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
+ NULL, // User name. NULL = current user
+ NULL, // User password. NULL = current
+ 0, // Locale. NULL indicates current
+ NULL, // Security flags.
+ 0, // Authority (e.g. Kerberos)
+ 0, // Context object
+ &pSvc // pointer to IWbemServices proxy
+ );
+
+ if (FAILED(hres))
+ {
+ LL_WARNS("AppInit") << "Could not connect. Error code = 0x" << hres << LL_ENDL;
+ pLoc->Release();
+ CoUninitialize();
+ return std::string(); // Program has failed.
+ }
+
+ LL_DEBUGS("AppInit") << "Connected to ROOT\\CIMV2 WMI namespace" << LL_ENDL;
+
+ // Set security levels on the proxy -------------------------
+ hres = CoSetProxyBlanket(
+ pSvc, // Indicates the proxy to set
+ RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
+ RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
+ NULL, // Server principal name
+ RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
+ RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
+ NULL, // client identity
+ EOAC_NONE // proxy capabilities
+ );
+
+ if (FAILED(hres))
+ {
+ LL_WARNS("AppInit") << "Could not set proxy blanket. Error code = 0x" << hres << LL_ENDL;
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return std::string(); // Program has failed.
+ }
+ IEnumWbemClassObject* pEnumerator = NULL;
+
+ // Get the data from the query
+ ULONG uReturn = 0;
+ hres = pSvc->ExecQuery(
+ bstr_t("WQL"),
+ bstr_t("SELECT * FROM Win32_VideoController"), //Consider using Availability to filter out disabled controllers
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL,
+ &pEnumerator);
+
+ if (FAILED(hres))
+ {
+ LL_WARNS("AppInit") << "Query for operating system name failed." << " Error code = 0x" << hres << LL_ENDL;
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return std::string(); // Program has failed.
+ }
+
+ while (pEnumerator)
+ {
+ IWbemClassObject *pclsObj = NULL;
+ HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
+ &pclsObj, &uReturn);
+
+ if (0 == uReturn)
+ {
+ break; // If quantity less then 1.
+ }
+
+ if (vendor != GPU_ANY)
+ {
+ VARIANT vtCaptionProp;
+ // Might be preferable to check "AdapterCompatibility" here instead of caption.
+ hr = pclsObj->Get(L"Caption", 0, &vtCaptionProp, 0, 0);
+
+ if (FAILED(hr))
+ {
+ LL_WARNS("AppInit") << "Query for Caption property failed." << " Error code = 0x" << hr << LL_ENDL;
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return std::string(); // Program has failed.
+ }
+
+ // use characters in the returned driver version
+ BSTR caption(vtCaptionProp.bstrVal);
+
+ //convert BSTR to std::string
+ std::wstring ws(caption, SysStringLen(caption));
+ std::string caption_str(ws.begin(), ws.end());
+ LLStringUtil::toLower(caption_str);
+
+ bool found = false;
+ switch (vendor)
+ {
+ case GPU_INTEL:
+ found = caption_str.find("intel") != std::string::npos;
+ break;
+ case GPU_NVIDIA:
+ found = caption_str.find("nvidia") != std::string::npos;
+ break;
+ case GPU_AMD:
+ found = caption_str.find("amd") != std::string::npos
+ || caption_str.find("ati ") != std::string::npos
+ || caption_str.find("radeon") != std::string::npos;
+ break;
+ default:
+ break;
+ }
+
+ if (found)
+ {
+ VariantClear(&vtCaptionProp);
+ }
+ else
+ {
+ VariantClear(&vtCaptionProp);
+ pclsObj->Release();
+ continue;
+ }
+ }
+
+ VARIANT vtVersionProp;
+
+ // Get the value of the DriverVersion property
+ hr = pclsObj->Get(L"DriverVersion", 0, &vtVersionProp, 0, 0);
+
+ if (FAILED(hr))
+ {
+ LL_WARNS("AppInit") << "Query for DriverVersion property failed." << " Error code = 0x" << hr << LL_ENDL;
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return std::string(); // Program has failed.
+ }
+
+ // use characters in the returned driver version
+ BSTR driverVersion(vtVersionProp.bstrVal);
+
+ //convert BSTR to std::string
+ std::wstring ws(driverVersion, SysStringLen(driverVersion));
+ std::string str(ws.begin(), ws.end());
+ LL_INFOS("AppInit") << " DriverVersion : " << str << LL_ENDL;
+
+ if (mDriverVersion.empty())
+ {
+ mDriverVersion = str;
+ }
+ else if (mDriverVersion != str)
+ {
+ if (vendor == GPU_ANY)
+ {
+ // Expected from systems with gpus from different vendors
+ LL_INFOS("DriverVersion") << "Multiple video drivers detected. Version of second driver: " << str << LL_ENDL;
+ }
+ else
+ {
+ // Not Expected!
+ LL_WARNS("DriverVersion") << "Multiple video drivers detected from same vendor. Version of second driver : " << str << LL_ENDL;
+ }
+ }
+
+ VariantClear(&vtVersionProp);
+ pclsObj->Release();
+ }
+
+ // Cleanup
+ // ========
+ if (pSvc)
+ {
+ pSvc->Release();
+ }
+ if (pLoc)
+ {
+ pLoc->Release();
+ }
+ if (pEnumerator)
+ {
+ pEnumerator->Release();
+ }
+
+ // supposed to always call CoUninitialize even if init returned false
+ CoUninitialize();
+
+ return mDriverVersion;
+}
+
+void get_wstring(IDxDiagContainer* containerp, WCHAR* wszPropName, WCHAR* wszPropValue, int outputSize)
+{
+ HRESULT hr;
+ VARIANT var;
+
+ VariantInit( &var );
+ hr = containerp->GetProp(wszPropName, &var );
+ if( SUCCEEDED(hr) )
+ {
+ // Switch off the type. There's 4 different types:
+ switch( var.vt )
+ {
+ case VT_UI4:
+ swprintf( wszPropValue, L"%d", var.ulVal ); /* Flawfinder: ignore */
+ break;
+ case VT_I4:
+ swprintf( wszPropValue, L"%d", var.lVal ); /* Flawfinder: ignore */
+ break;
+ case VT_BOOL:
+ wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" ); /* Flawfinder: ignore */
+ break;
+ case VT_BSTR:
+ wcsncpy( wszPropValue, var.bstrVal, outputSize-1 ); /* Flawfinder: ignore */
+ wszPropValue[outputSize-1] = 0;
+ break;
+ }
+ }
+ // Clear the variant (this is needed to free BSTR memory)
+ VariantClear( &var );
+}
+
+std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName)
+{
+ WCHAR wszPropValue[256];
+ get_wstring(containerp, wszPropName, wszPropValue, 256);
+
+ return utf16str_to_utf8str(wszPropValue);
+}
+
+
+LLVersion::LLVersion()
+{
+ mValid = false;
+ S32 i;
+ for (i = 0; i < 4; i++)
+ {
+ mFields[i] = 0;
+ }
+}
+
+bool LLVersion::set(const std::string &version_string)
+{
+ S32 i;
+ for (i = 0; i < 4; i++)
+ {
+ mFields[i] = 0;
+ }
+ // Split the version string.
+ std::string str(version_string);
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep(".", "", boost::keep_empty_tokens);
+ tokenizer tokens(str, sep);
+
+ tokenizer::iterator iter = tokens.begin();
+ S32 count = 0;
+ for (;(iter != tokens.end()) && (count < 4);++iter)
+ {
+ mFields[count] = atoi(iter->c_str());
+ count++;
+ }
+ if (count < 4)
+ {
+ //LL_WARNS() << "Potentially bogus version string!" << version_string << LL_ENDL;
+ for (i = 0; i < 4; i++)
+ {
+ mFields[i] = 0;
+ }
+ mValid = false;
+ }
+ else
+ {
+ mValid = true;
+ }
+ return mValid;
+}
+
+S32 LLVersion::getField(const S32 field_num)
+{
+ if (!mValid)
+ {
+ return -1;
+ }
+ else
+ {
+ return mFields[field_num];
+ }
+}
+
+std::string LLDXDriverFile::dump()
+{
+ if (gWriteDebug)
+ {
+ gWriteDebug("Filename:");
+ gWriteDebug(mName.c_str());
+ gWriteDebug("\n");
+ gWriteDebug("Ver:");
+ gWriteDebug(mVersionString.c_str());
+ gWriteDebug("\n");
+ gWriteDebug("Date:");
+ gWriteDebug(mDateString.c_str());
+ gWriteDebug("\n");
+ }
+ LL_INFOS() << mFilepath << LL_ENDL;
+ LL_INFOS() << mName << LL_ENDL;
+ LL_INFOS() << mVersionString << LL_ENDL;
+ LL_INFOS() << mDateString << LL_ENDL;
+
+ return "";
+}
+
+LLDXDevice::~LLDXDevice()
+{
+ for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer());
+ mDriverFiles.clear();
+}
+
+std::string LLDXDevice::dump()
+{
+ if (gWriteDebug)
+ {
+ gWriteDebug("StartDevice\n");
+ gWriteDebug("DeviceName:");
+ gWriteDebug(mName.c_str());
+ gWriteDebug("\n");
+ gWriteDebug("PCIString:");
+ gWriteDebug(mPCIString.c_str());
+ gWriteDebug("\n");
+ }
+ LL_INFOS() << LL_ENDL;
+ LL_INFOS() << "DeviceName:" << mName << LL_ENDL;
+ LL_INFOS() << "PCIString:" << mPCIString << LL_ENDL;
+ LL_INFOS() << "Drivers" << LL_ENDL;
+ LL_INFOS() << "-------" << LL_ENDL;
+ for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
+ end = mDriverFiles.end();
+ iter != end; iter++)
+ {
+ LLDXDriverFile *filep = iter->second;
+ filep->dump();
+ }
+ if (gWriteDebug)
+ {
+ gWriteDebug("EndDevice\n");
+ }
+
+ return "";
+}
+
+LLDXDriverFile *LLDXDevice::findDriver(const std::string &driver)
+{
+ for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
+ end = mDriverFiles.end();
+ iter != end; iter++)
+ {
+ LLDXDriverFile *filep = iter->second;
+ if (!utf8str_compare_insensitive(filep->mName,driver))
+ {
+ return filep;
+ }
+ }
+
+ return NULL;
+}
+
+LLDXHardware::LLDXHardware()
+{
+ mVRAM = 0;
+ gWriteDebug = NULL;
+}
+
+void LLDXHardware::cleanup()
+{
+ // for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer());
+ // mDevices.clear();
+}
+
+/*
+std::string LLDXHardware::dumpDevices()
+{
+ if (gWriteDebug)
+ {
+ gWriteDebug("\n");
+ gWriteDebug("StartAllDevices\n");
+ }
+ for (device_map_t::iterator iter = mDevices.begin(),
+ end = mDevices.end();
+ iter != end; iter++)
+ {
+ LLDXDevice *devicep = iter->second;
+ devicep->dump();
+ }
+ if (gWriteDebug)
+ {
+ gWriteDebug("EndAllDevices\n\n");
+ }
+ return "";
+}
+
+LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::string &devices)
+{
+ // Iterate through different devices tokenized in devices string
+ std::string str(devices);
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
+ tokenizer tokens(str, sep);
+
+ tokenizer::iterator iter = tokens.begin();
+ for (;iter != tokens.end();++iter)
+ {
+ std::string dev_str = *iter;
+ for (device_map_t::iterator iter = mDevices.begin(),
+ end = mDevices.end();
+ iter != end; iter++)
+ {
+ LLDXDevice *devicep = iter->second;
+ if ((devicep->mVendorID == vendor)
+ && (devicep->mDeviceID == dev_str))
+ {
+ return devicep;
+ }
+ }
+ }
+
+ return NULL;
+}
+*/
+
+bool LLDXHardware::getInfo(bool vram_only)
+{
+ LLTimer hw_timer;
+ bool ok = false;
+ HRESULT hr;
+
+ // CLSID_DxDiagProvider does not work with Multithreaded?
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ IDxDiagProvider *dx_diag_providerp = NULL;
+ IDxDiagContainer *dx_diag_rootp = NULL;
+ IDxDiagContainer *devices_containerp = NULL;
+ // IDxDiagContainer *system_device_containerp= NULL;
+ IDxDiagContainer *device_containerp = NULL;
+ IDxDiagContainer *file_containerp = NULL;
+ IDxDiagContainer *driver_containerp = NULL;
+ DWORD dw_device_count;
+
+ mVRAM = 0;
+
+ // CoCreate a IDxDiagProvider*
+ LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL;
+ hr = CoCreateInstance(CLSID_DxDiagProvider,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IDxDiagProvider,
+ (LPVOID*) &dx_diag_providerp);
+
+ if (FAILED(hr))
+ {
+ LL_WARNS("AppInit") << "No DXDiag provider found! DirectX 9 not installed!" << LL_ENDL;
+ gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n");
+ goto LCleanup;
+ }
+ if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
+ {
+ // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
+ // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are
+ // digital signed as logo'd by WHQL which may connect via internet to update
+ // WHQL certificates.
+ DXDIAG_INIT_PARAMS dx_diag_init_params;
+ ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
+
+ dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS);
+ dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
+ dx_diag_init_params.bAllowWHQLChecks = TRUE;
+ dx_diag_init_params.pReserved = NULL;
+
+ LL_DEBUGS("AppInit") << "dx_diag_providerp->Initialize" << LL_ENDL;
+ hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
+ if(FAILED(hr))
+ {
+ goto LCleanup;
+ }
+
+ LL_DEBUGS("AppInit") << "dx_diag_providerp->GetRootContainer" << LL_ENDL;
+ hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
+ if(FAILED(hr) || !dx_diag_rootp)
+ {
+ goto LCleanup;
+ }
+
+ HRESULT hr;
+
+ // Get display driver information
+ LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer" << LL_ENDL;
+ hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
+ if(FAILED(hr) || !devices_containerp)
+ {
+ // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp
+ devices_containerp = NULL;
+ goto LCleanup;
+ }
+
+ // make sure there is something inside
+ hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count);
+ if (FAILED(hr) || dw_device_count == 0)
+ {
+ goto LCleanup;
+ }
+
+ // Get device 0
+ // By default 0 device is the primary one, howhever in case of various hybrid graphics
+ // like itegrated AMD and PCI AMD GPUs system might switch.
+ LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL;
+ hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
+ if(FAILED(hr) || !device_containerp)
+ {
+ goto LCleanup;
+ }
+
+ DWORD vram = 0;
+
+ WCHAR deviceID[512];
+
+ get_wstring(device_containerp, L"szDeviceID", deviceID, 512);
+ // Example: searches id like 1F06 in pnp string (aka VEN_10DE&DEV_1F06)
+ // doesn't seem to work on some systems since format is unrecognizable
+ // but in such case keyDeviceID works
+ if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram)))
+ {
+ mVRAM = vram/(1024*1024);
+ }
+ else
+ {
+ get_wstring(device_containerp, L"szKeyDeviceID", deviceID, 512);
+ LL_WARNS() << "szDeviceID" << deviceID << LL_ENDL;
+ // '+9' to avoid ENUM\\PCI\\ prefix
+ // Returns string like Enum\\PCI\\VEN_10DE&DEV_1F06&SUBSYS...
+ // and since GetVideoMemoryViaWMI searches by PNPDeviceID it is sufficient
+ if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID + 9, &vram)))
+ {
+ mVRAM = vram / (1024 * 1024);
+ }
+ }
+
+ if (mVRAM == 0)
+ { // Get the English VRAM string
+ std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
+
+ // We don't need the device any more
+ SAFE_RELEASE(device_containerp);
+
+ // Dump the string as an int into the structure
+ char *stopstring;
+ mVRAM = strtol(ram_str.c_str(), &stopstring, 10);
+ LL_INFOS("AppInit") << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << LL_ENDL;
+ }
+
+ if (vram_only)
+ {
+ ok = true;
+ goto LCleanup;
+ }
+
+
+ /* for now, we ONLY do vram_only the rest of this
+ is commented out, to ensure no-one is tempted
+ to use it
+
+ // Now let's get device and driver information
+ // Get the IDxDiagContainer object called "DxDiag_SystemDevices".
+ // This call may take some time while dxdiag gathers the info.
+ DWORD num_devices = 0;
+ WCHAR wszContainer[256];
+ LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << LL_ENDL;
+ hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp);
+ if (FAILED(hr))
+ {
+ goto LCleanup;
+ }
+
+ hr = system_device_containerp->GetNumberOfChildContainers(&num_devices);
+ if (FAILED(hr))
+ {
+ goto LCleanup;
+ }
+
+ LL_DEBUGS("AppInit") << "DX9 iterating over devices" << LL_ENDL;
+ S32 device_num = 0;
+ for (device_num = 0; device_num < (S32)num_devices; device_num++)
+ {
+ hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256);
+ if (FAILED(hr))
+ {
+ goto LCleanup;
+ }
+
+ hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp);
+ if (FAILED(hr) || device_containerp == NULL)
+ {
+ goto LCleanup;
+ }
+
+ std::string device_name = get_string(device_containerp, L"szDescription");
+
+ std::string device_id = get_string(device_containerp, L"szDeviceID");
+
+ LLDXDevice *dxdevicep = new LLDXDevice;
+ dxdevicep->mName = device_name;
+ dxdevicep->mPCIString = device_id;
+ mDevices[dxdevicep->mPCIString] = dxdevicep;
+
+ // Split the PCI string based on vendor, device, subsys, rev.
+ std::string str(device_id);
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("&\\", "", boost::keep_empty_tokens);
+ tokenizer tokens(str, sep);
+
+ tokenizer::iterator iter = tokens.begin();
+ S32 count = 0;
+ bool valid = true;
+ for (;(iter != tokens.end()) && (count < 3);++iter)
+ {
+ switch (count)
+ {
+ case 0:
+ if (strcmp(iter->c_str(), "PCI"))
+ {
+ valid = false;
+ }
+ break;
+ case 1:
+ dxdevicep->mVendorID = iter->c_str();
+ break;
+ case 2:
+ dxdevicep->mDeviceID = iter->c_str();
+ break;
+ default:
+ // Ignore it
+ break;
+ }
+ count++;
+ }
+
+
+
+
+ // Now, iterate through the related drivers
+ hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp);
+ if (FAILED(hr) || !driver_containerp)
+ {
+ goto LCleanup;
+ }
+
+ DWORD num_files = 0;
+ hr = driver_containerp->GetNumberOfChildContainers(&num_files);
+ if (FAILED(hr))
+ {
+ goto LCleanup;
+ }
+
+ S32 file_num = 0;
+ for (file_num = 0; file_num < (S32)num_files; file_num++ )
+ {
+
+ hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256);
+ if (FAILED(hr))
+ {
+ goto LCleanup;
+ }
+
+ hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp);
+ if (FAILED(hr) || file_containerp == NULL)
+ {
+ goto LCleanup;
+ }
+
+ std::string driver_path = get_string(file_containerp, L"szPath");
+ std::string driver_name = get_string(file_containerp, L"szName");
+ std::string driver_version = get_string(file_containerp, L"szVersion");
+ std::string driver_date = get_string(file_containerp, L"szDatestampEnglish");
+
+ LLDXDriverFile *dxdriverfilep = new LLDXDriverFile;
+ dxdriverfilep->mName = driver_name;
+ dxdriverfilep->mFilepath= driver_path;
+ dxdriverfilep->mVersionString = driver_version;
+ dxdriverfilep->mVersion.set(driver_version);
+ dxdriverfilep->mDateString = driver_date;
+
+ dxdevicep->mDriverFiles[driver_name] = dxdriverfilep;
+
+ SAFE_RELEASE(file_containerp);
+ }
+ SAFE_RELEASE(device_containerp);
+ }
+ */
+ }
+
+ // dumpDevices();
+ ok = true;
+
+LCleanup:
+ if (!ok)
+ {
+ LL_WARNS("AppInit") << "DX9 probe failed" << LL_ENDL;
+ gWriteDebug("DX9 probe failed\n");
+ }
+
+ SAFE_RELEASE(file_containerp);
+ SAFE_RELEASE(driver_containerp);
+ SAFE_RELEASE(device_containerp);
+ SAFE_RELEASE(devices_containerp);
+ SAFE_RELEASE(dx_diag_rootp);
+ SAFE_RELEASE(dx_diag_providerp);
+
+ CoUninitialize();
+
+ return ok;
+ }
+
+LLSD LLDXHardware::getDisplayInfo()
+{
+ LLTimer hw_timer;
+ HRESULT hr;
+ LLSD ret;
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ IDxDiagProvider *dx_diag_providerp = NULL;
+ IDxDiagContainer *dx_diag_rootp = NULL;
+ IDxDiagContainer *devices_containerp = NULL;
+ IDxDiagContainer *device_containerp = NULL;
+ IDxDiagContainer *file_containerp = NULL;
+ IDxDiagContainer *driver_containerp = NULL;
+ DWORD dw_device_count;
+
+ // CoCreate a IDxDiagProvider*
+ LL_INFOS() << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL;
+ hr = CoCreateInstance(CLSID_DxDiagProvider,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IDxDiagProvider,
+ (LPVOID*) &dx_diag_providerp);
+
+ if (FAILED(hr))
+ {
+ LL_WARNS() << "No DXDiag provider found! DirectX 9 not installed!" << LL_ENDL;
+ gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n");
+ goto LCleanup;
+ }
+ if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
+ {
+ // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
+ // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are
+ // digital signed as logo'd by WHQL which may connect via internet to update
+ // WHQL certificates.
+ DXDIAG_INIT_PARAMS dx_diag_init_params;
+ ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
+
+ dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS);
+ dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
+ dx_diag_init_params.bAllowWHQLChecks = TRUE;
+ dx_diag_init_params.pReserved = NULL;
+
+ LL_INFOS() << "dx_diag_providerp->Initialize" << LL_ENDL;
+ hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
+ if(FAILED(hr))
+ {
+ goto LCleanup;
+ }
+
+ LL_INFOS() << "dx_diag_providerp->GetRootContainer" << LL_ENDL;
+ hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
+ if(FAILED(hr) || !dx_diag_rootp)
+ {
+ goto LCleanup;
+ }
+
+ HRESULT hr;
+
+ // Get display driver information
+ LL_INFOS() << "dx_diag_rootp->GetChildContainer" << LL_ENDL;
+ hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
+ if(FAILED(hr) || !devices_containerp)
+ {
+ // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp
+ devices_containerp = NULL;
+ goto LCleanup;
+ }
+
+ // make sure there is something inside
+ hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count);
+ if (FAILED(hr) || dw_device_count == 0)
+ {
+ goto LCleanup;
+ }
+
+ // Get device 0
+ LL_INFOS() << "devices_containerp->GetChildContainer" << LL_ENDL;
+ hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
+ if(FAILED(hr) || !device_containerp)
+ {
+ goto LCleanup;
+ }
+
+ // Get the English VRAM string
+ std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
+
+
+ // Dump the string as an int into the structure
+ char *stopstring;
+ ret["VRAM"] = strtol(ram_str.c_str(), &stopstring, 10);
+ std::string device_name = get_string(device_containerp, L"szDescription");
+ ret["DeviceName"] = device_name;
+ std::string device_driver= get_string(device_containerp, L"szDriverVersion");
+ ret["DriverVersion"] = device_driver;
+
+ // ATI has a slightly different version string
+ if(device_name.length() >= 4 && device_name.substr(0,4) == "ATI ")
+ {
+ // get the key
+ HKEY hKey;
+ const DWORD RV_SIZE = 100;
+ WCHAR release_version[RV_SIZE];
+
+ // Hard coded registry entry. Using this since it's simpler for now.
+ // And using EnumDisplayDevices to get a registry key also requires
+ // a hard coded Query value.
+ if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\ATI Technologies\\CBT"), &hKey))
+ {
+ // get the value
+ DWORD dwType = REG_SZ;
+ DWORD dwSize = sizeof(WCHAR) * RV_SIZE;
+ if(ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("ReleaseVersion"),
+ NULL, &dwType, (LPBYTE)release_version, &dwSize))
+ {
+ // print the value
+ // windows doesn't guarantee to be null terminated
+ release_version[RV_SIZE - 1] = NULL;
+ ret["DriverVersion"] = utf16str_to_utf8str(release_version);
+
+ }
+ RegCloseKey(hKey);
+ }
+ }
+ }
+
+LCleanup:
+ if (!ret.isMap() || (ret.size() == 0))
+ {
+ LL_INFOS() << "Failed to get data, cleaning up" << LL_ENDL;
+ }
+ SAFE_RELEASE(file_containerp);
+ SAFE_RELEASE(driver_containerp);
+ SAFE_RELEASE(device_containerp);
+ SAFE_RELEASE(devices_containerp);
+ SAFE_RELEASE(dx_diag_rootp);
+ SAFE_RELEASE(dx_diag_providerp);
+
+ CoUninitialize();
+ return ret;
+}
+
+void LLDXHardware::setWriteDebugFunc(void (*func)(const char*))
+{
+ gWriteDebug = func;
+}
+
+#endif