677 lines
18 KiB
C++
677 lines
18 KiB
C++
/**
|
|
* @file lldxhardware.cpp
|
|
* @brief LLDXHardware implementation
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2001-2009, Linden Research, Inc.
|
|
*
|
|
* Second Life Viewer Source Code
|
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
* to you under the terms of the GNU General Public License, version 2.0
|
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
* online at
|
|
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge
|
|
* that you have read and understood your obligations described above,
|
|
* and agree to abide by those obligations.
|
|
*
|
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
* COMPLETENESS OR PERFORMANCE.
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#ifdef LL_WINDOWS
|
|
|
|
// Culled from some Microsoft sample code
|
|
|
|
#include "linden_common.h"
|
|
|
|
#define INITGUID
|
|
#include <dxdiag.h>
|
|
#undef INITGUID
|
|
|
|
#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; } }
|
|
|
|
std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName)
|
|
{
|
|
HRESULT hr;
|
|
VARIANT var;
|
|
WCHAR wszPropValue[256];
|
|
|
|
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, 255 ); /* Flawfinder: ignore */
|
|
wszPropValue[255] = 0;
|
|
break;
|
|
}
|
|
}
|
|
// Clear the variant (this is needed to free BSTR memory)
|
|
VariantClear( &var );
|
|
|
|
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)
|
|
{
|
|
//llwarns << "Potentially bogus version string!" << version_string << llendl;
|
|
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");
|
|
}
|
|
llinfos << mFilepath << llendl;
|
|
llinfos << mName << llendl;
|
|
llinfos << mVersionString << llendl;
|
|
llinfos << mDateString << llendl;
|
|
|
|
return "";
|
|
}
|
|
|
|
LLDXDevice::~LLDXDevice()
|
|
{
|
|
for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer());
|
|
}
|
|
|
|
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");
|
|
}
|
|
llinfos << llendl;
|
|
llinfos << "DeviceName:" << mName << llendl;
|
|
llinfos << "PCIString:" << mPCIString << llendl;
|
|
llinfos << "Drivers" << llendl;
|
|
llinfos << "-------" << llendl;
|
|
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());
|
|
}
|
|
|
|
/*
|
|
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;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
// 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;
|
|
CoInitialize(NULL);
|
|
|
|
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*
|
|
llinfos << "CoCreateInstance IID_IDxDiagProvider" << llendl;
|
|
hr = CoCreateInstance(CLSID_DxDiagProvider,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDxDiagProvider,
|
|
(LPVOID*) &dx_diag_providerp);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
llwarns << "No DXDiag provider found! DirectX 9 not installed!" << llendl;
|
|
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;
|
|
|
|
llinfos << "dx_diag_providerp->Initialize" << llendl;
|
|
hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
|
|
if(FAILED(hr))
|
|
{
|
|
goto LCleanup;
|
|
}
|
|
|
|
llinfos << "dx_diag_providerp->GetRootContainer" << llendl;
|
|
hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
|
|
if(FAILED(hr) || !dx_diag_rootp)
|
|
{
|
|
goto LCleanup;
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// Get display driver information
|
|
llinfos << "dx_diag_rootp->GetChildContainer" << llendl;
|
|
hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
|
|
if(FAILED(hr) || !devices_containerp)
|
|
{
|
|
goto LCleanup;
|
|
}
|
|
|
|
// Get device 0
|
|
llinfos << "devices_containerp->GetChildContainer" << llendl;
|
|
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
|