Files
SingularityViewer/indra/llwindow/lldxhardware.cpp
Lirusaito 79965fade1 Alchemerge
Applies the following alchemy patches:
28fe46209ea5: Don't spam setPaused in fmod studio audio stream code
eb12ff41434a: Fix single click to walk triggering on huds
31955a7826b9: Fix double click to walk being triggered by huds and touchable objects
Fix double click to walk triggering while sitting and flying
Fix double click to walk behavior being inconsistent with single click to walk
Fix double click teleport being affected by transparent objects
Properly fixes MAINT-957

Compile stuff updates:
Adds VCRedist to package, should fix failure to launch reported by Nomade Zhao.
Updates package_description to better suit Singularity
Turns secondlife-bin in places to singularity-bin

Updates the following libraries:
Curl (7.47.0), gperftools (0.0.2), openssl (1.0.2f), SLVoice on Linux64,
2016-02-25 21:13:13 -05:00

849 lines
23 KiB
C++

/**
* @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 <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;
HRESULT hrCoInitialize = S_OK;
IWbemLocator* pIWbemLocator = nullptr;
IWbemServices* pIWbemServices = nullptr;
BSTR pNamespace = nullptr;
*pdwAdapterRam = 0;
hrCoInitialize = CoInitialize( 0 );
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;
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 ) )
{
if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 )
bFound = true;
}
VariantClear( &var );
if( pPropName ) SysFreeString( pPropName );
if( bFound )
{
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 = var.ulVal;
}
VariantClear( &var );
if( pPropName ) SysFreeString( pPropName );
break;
}
SAFE_RELEASE( pVideoControllers[iController] );
}
}
}
if( pClassName )
SysFreeString( pClassName );
SAFE_RELEASE( pEnumVideoControllers );
}
if( pNamespace )
SysFreeString( pNamespace );
SAFE_RELEASE( pIWbemServices );
}
SAFE_RELEASE( pIWbemLocator );
if( SUCCEEDED( hrCoInitialize ) )
CoUninitialize();
if( bGotMemory )
return S_OK;
else
return E_FAIL;
}
void get_wstring(IDxDiagContainer* containerp, const 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, outputSize, L"%d", var.ulVal); /* Flawfinder: ignore */
break;
case VT_I4:
swprintf(wszPropValue, outputSize, 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, const 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;
hr = CoInitialize(NULL);
if (FAILED(hr))
{
LL_WARNS() << "COM initialization failure!" << LL_ENDL;
gWriteDebug("COM initialization failure!\n");
return ok;
}
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;
// 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;
}
// 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)
{
goto LCleanup;
}
// Get device 0
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);
if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram)))
{
mVRAM = vram/(1024*1024);
}
else
{ // 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;
hr = CoInitialize(NULL);
if (FAILED(hr))
{
LL_WARNS() << "COM initialization failure!" << LL_ENDL;
gWriteDebug("COM initialization failure!\n");
return ret;
}
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;
// 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;
}
// 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)
{
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:
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