00001
00032 #ifdef LL_WINDOWS
00033
00034
00035
00036 #include "linden_common.h"
00037
00038 #include <dxdiag.h>
00039
00040 #include <boost/tokenizer.hpp>
00041
00042 #include "lldxhardware.h"
00043 #include "llerror.h"
00044
00045 #include "llstring.h"
00046 #include "llstl.h"
00047
00048 void (*gWriteDebug)(const char* msg) = NULL;
00049 LLDXHardware gDXHardware;
00050
00051
00052
00053
00054 #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
00055 #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
00056 #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
00057
00058 std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName)
00059 {
00060 HRESULT hr;
00061 VARIANT var;
00062 WCHAR wszPropValue[256];
00063
00064 VariantInit( &var );
00065 hr = containerp->GetProp(wszPropName, &var );
00066 if( SUCCEEDED(hr) )
00067 {
00068
00069 switch( var.vt )
00070 {
00071 case VT_UI4:
00072 swprintf( wszPropValue, L"%d", var.ulVal );
00073 break;
00074 case VT_I4:
00075 swprintf( wszPropValue, L"%d", var.lVal );
00076 break;
00077 case VT_BOOL:
00078 wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" );
00079 break;
00080 case VT_BSTR:
00081 wcsncpy( wszPropValue, var.bstrVal, 255 );
00082 wszPropValue[255] = 0;
00083 break;
00084 }
00085 }
00086
00087 VariantClear( &var );
00088
00089 return utf16str_to_utf8str(wszPropValue);
00090 }
00091
00092
00093 LLVersion::LLVersion()
00094 {
00095 mValid = FALSE;
00096 S32 i;
00097 for (i = 0; i < 4; i++)
00098 {
00099 mFields[i] = 0;
00100 }
00101 }
00102
00103 BOOL LLVersion::set(const std::string &version_string)
00104 {
00105 S32 i;
00106 for (i = 0; i < 4; i++)
00107 {
00108 mFields[i] = 0;
00109 }
00110
00111 std::string str(version_string);
00112 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00113 boost::char_separator<char> sep(".", "", boost::keep_empty_tokens);
00114 tokenizer tokens(str, sep);
00115
00116 tokenizer::iterator iter = tokens.begin();
00117 S32 count = 0;
00118 for (;(iter != tokens.end()) && (count < 4);++iter)
00119 {
00120 mFields[count] = atoi(iter->c_str());
00121 count++;
00122 }
00123 if (count < 4)
00124 {
00125
00126 for (i = 0; i < 4; i++)
00127 {
00128 mFields[i] = 0;
00129 }
00130 mValid = FALSE;
00131 }
00132 else
00133 {
00134 mValid = TRUE;
00135 }
00136 return mValid;
00137 }
00138
00139 S32 LLVersion::getField(const S32 field_num)
00140 {
00141 if (!mValid)
00142 {
00143 return -1;
00144 }
00145 else
00146 {
00147 return mFields[field_num];
00148 }
00149 }
00150
00151 LLString LLDXDriverFile::dump()
00152 {
00153 if (gWriteDebug)
00154 {
00155 gWriteDebug("Filename:");
00156 gWriteDebug(mName.c_str());
00157 gWriteDebug("\n");
00158 gWriteDebug("Ver:");
00159 gWriteDebug(mVersionString.c_str());
00160 gWriteDebug("\n");
00161 gWriteDebug("Date:");
00162 gWriteDebug(mDateString.c_str());
00163 gWriteDebug("\n");
00164 }
00165 llinfos << mFilepath << llendl;
00166 llinfos << mName << llendl;
00167 llinfos << mVersionString << llendl;
00168 llinfos << mDateString << llendl;
00169
00170 return "";
00171 }
00172
00173 LLDXDevice::~LLDXDevice()
00174 {
00175 for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer());
00176 }
00177
00178 std::string LLDXDevice::dump()
00179 {
00180 if (gWriteDebug)
00181 {
00182 gWriteDebug("StartDevice\n");
00183 gWriteDebug("DeviceName:");
00184 gWriteDebug(mName.c_str());
00185 gWriteDebug("\n");
00186 gWriteDebug("PCIString:");
00187 gWriteDebug(mPCIString.c_str());
00188 gWriteDebug("\n");
00189 }
00190 llinfos << llendl;
00191 llinfos << "DeviceName:" << mName << llendl;
00192 llinfos << "PCIString:" << mPCIString << llendl;
00193 llinfos << "Drivers" << llendl;
00194 llinfos << "-------" << llendl;
00195 for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
00196 end = mDriverFiles.end();
00197 iter != end; iter++)
00198 {
00199 LLDXDriverFile *filep = iter->second;
00200 filep->dump();
00201 }
00202 if (gWriteDebug)
00203 {
00204 gWriteDebug("EndDevice\n");
00205 }
00206
00207 return "";
00208 }
00209
00210 LLDXDriverFile *LLDXDevice::findDriver(const std::string &driver)
00211 {
00212 for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
00213 end = mDriverFiles.end();
00214 iter != end; iter++)
00215 {
00216 LLDXDriverFile *filep = iter->second;
00217 if (!utf8str_compare_insensitive(filep->mName,driver))
00218 {
00219 return filep;
00220 }
00221 }
00222
00223 return NULL;
00224 }
00225
00226 LLDXHardware::LLDXHardware()
00227 {
00228 mVRAM = 0;
00229 gWriteDebug = NULL;
00230 }
00231
00232 void LLDXHardware::cleanup()
00233 {
00234 for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer());
00235 }
00236
00237 LLString LLDXHardware::dumpDevices()
00238 {
00239 if (gWriteDebug)
00240 {
00241 gWriteDebug("\n");
00242 gWriteDebug("StartAllDevices\n");
00243 }
00244 for (device_map_t::iterator iter = mDevices.begin(),
00245 end = mDevices.end();
00246 iter != end; iter++)
00247 {
00248 LLDXDevice *devicep = iter->second;
00249 devicep->dump();
00250 }
00251 if (gWriteDebug)
00252 {
00253 gWriteDebug("EndAllDevices\n\n");
00254 }
00255 return "";
00256 }
00257
00258 LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::string &devices)
00259 {
00260
00261 std::string str(devices);
00262 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00263 boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
00264 tokenizer tokens(str, sep);
00265
00266 tokenizer::iterator iter = tokens.begin();
00267 for (;iter != tokens.end();++iter)
00268 {
00269 std::string dev_str = *iter;
00270 for (device_map_t::iterator iter = mDevices.begin(),
00271 end = mDevices.end();
00272 iter != end; iter++)
00273 {
00274 LLDXDevice *devicep = iter->second;
00275 if ((devicep->mVendorID == vendor)
00276 && (devicep->mDeviceID == dev_str))
00277 {
00278 return devicep;
00279 }
00280 }
00281 }
00282
00283 return NULL;
00284 }
00285
00286 BOOL LLDXHardware::getInfo(BOOL vram_only)
00287 {
00288 LLTimer hw_timer;
00289 BOOL ok = FALSE;
00290 HRESULT hr;
00291
00292 CoInitialize(NULL);
00293
00294 IDxDiagProvider *dx_diag_providerp = NULL;
00295 IDxDiagContainer *dx_diag_rootp = NULL;
00296 IDxDiagContainer *devices_containerp = NULL;
00297 IDxDiagContainer *system_device_containerp= NULL;
00298 IDxDiagContainer *device_containerp = NULL;
00299 IDxDiagContainer *file_containerp = NULL;
00300 IDxDiagContainer *driver_containerp = NULL;
00301
00302
00303 llinfos << "CoCreateInstance IID_IDxDiagProvider" << llendl;
00304 hr = CoCreateInstance(CLSID_DxDiagProvider,
00305 NULL,
00306 CLSCTX_INPROC_SERVER,
00307 IID_IDxDiagProvider,
00308 (LPVOID*) &dx_diag_providerp);
00309
00310 if (FAILED(hr))
00311 {
00312 llwarns << "No DXDiag provider found! DirectX 9 not installed!" << llendl;
00313 gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n");
00314 goto LCleanup;
00315 }
00316 if (SUCCEEDED(hr))
00317 {
00318
00319
00320
00321
00322 DXDIAG_INIT_PARAMS dx_diag_init_params;
00323 ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
00324
00325 dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS);
00326 dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
00327 dx_diag_init_params.bAllowWHQLChecks = TRUE;
00328 dx_diag_init_params.pReserved = NULL;
00329
00330 llinfos << "dx_diag_providerp->Initialize" << llendl;
00331 hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
00332 if(FAILED(hr))
00333 {
00334 goto LCleanup;
00335 }
00336
00337 llinfos << "dx_diag_providerp->GetRootContainer" << llendl;
00338 hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
00339 if(FAILED(hr) || !dx_diag_rootp)
00340 {
00341 goto LCleanup;
00342 }
00343
00344 HRESULT hr;
00345
00346
00347 llinfos << "dx_diag_rootp->GetChildContainer" << llendl;
00348 hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
00349 if(FAILED(hr) || !devices_containerp)
00350 {
00351 goto LCleanup;
00352 }
00353
00354
00355 llinfos << "devices_containerp->GetChildContainer" << llendl;
00356 hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
00357 if(FAILED(hr) || !device_containerp)
00358 {
00359 goto LCleanup;
00360 }
00361
00362
00363 std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
00364
00365
00366 SAFE_RELEASE(device_containerp);
00367
00368
00369 char *stopstring;
00370 mVRAM = strtol(ram_str.c_str(), &stopstring, 10);
00371 llinfos << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << llendl;
00372
00373 if (vram_only)
00374 {
00375 ok = TRUE;
00376 goto LCleanup;
00377 }
00378
00379
00380
00381
00382 DWORD num_devices = 0;
00383 WCHAR wszContainer[256];
00384 llinfos << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << llendl;
00385 hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp);
00386 if (FAILED(hr))
00387 {
00388 goto LCleanup;
00389 }
00390
00391 hr = system_device_containerp->GetNumberOfChildContainers(&num_devices);
00392 if (FAILED(hr))
00393 {
00394 goto LCleanup;
00395 }
00396
00397 llinfos << "DX9 iterating over devices" << llendl;
00398 S32 device_num = 0;
00399 for (device_num = 0; device_num < (S32)num_devices; device_num++)
00400 {
00401 hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256);
00402 if (FAILED(hr))
00403 {
00404 goto LCleanup;
00405 }
00406
00407 hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp);
00408 if (FAILED(hr) || device_containerp == NULL)
00409 {
00410 goto LCleanup;
00411 }
00412
00413 std::string device_name = get_string(device_containerp, L"szDescription");
00414 std::string device_id = get_string(device_containerp, L"szDeviceID");
00415
00416 LLDXDevice *dxdevicep = new LLDXDevice;
00417 dxdevicep->mName = device_name;
00418 dxdevicep->mPCIString = device_id;
00419 mDevices[dxdevicep->mPCIString] = dxdevicep;
00420
00421
00422 std::string str(device_id);
00423 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00424 boost::char_separator<char> sep("&\\", "", boost::keep_empty_tokens);
00425 tokenizer tokens(str, sep);
00426
00427 tokenizer::iterator iter = tokens.begin();
00428 S32 count = 0;
00429 BOOL valid = TRUE;
00430 for (;(iter != tokens.end()) && (count < 3);++iter)
00431 {
00432 switch (count)
00433 {
00434 case 0:
00435 if (strcmp(iter->c_str(), "PCI"))
00436 {
00437 valid = FALSE;
00438 }
00439 break;
00440 case 1:
00441 dxdevicep->mVendorID = iter->c_str();
00442 break;
00443 case 2:
00444 dxdevicep->mDeviceID = iter->c_str();
00445 break;
00446 default:
00447
00448 break;
00449 }
00450 count++;
00451 }
00452
00453
00454
00455 hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp);
00456 if (FAILED(hr) || !driver_containerp)
00457 {
00458 goto LCleanup;
00459 }
00460
00461 DWORD num_files = 0;
00462 hr = driver_containerp->GetNumberOfChildContainers(&num_files);
00463 if (FAILED(hr))
00464 {
00465 goto LCleanup;
00466 }
00467
00468 S32 file_num = 0;
00469 for (file_num = 0; file_num < (S32)num_files; file_num++ )
00470 {
00471 hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256);
00472 if (FAILED(hr))
00473 {
00474 goto LCleanup;
00475 }
00476
00477 hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp);
00478 if (FAILED(hr) || file_containerp == NULL)
00479 {
00480 goto LCleanup;
00481 }
00482
00483 std::string driver_path = get_string(file_containerp, L"szPath");
00484 std::string driver_name = get_string(file_containerp, L"szName");
00485 std::string driver_version = get_string(file_containerp, L"szVersion");
00486 std::string driver_date = get_string(file_containerp, L"szDatestampEnglish");
00487
00488 LLDXDriverFile *dxdriverfilep = new LLDXDriverFile;
00489 dxdriverfilep->mName = driver_name;
00490 dxdriverfilep->mFilepath= driver_path;
00491 dxdriverfilep->mVersionString = driver_version;
00492 dxdriverfilep->mVersion.set(driver_version);
00493 dxdriverfilep->mDateString = driver_date;
00494
00495 dxdevicep->mDriverFiles[driver_name] = dxdriverfilep;
00496
00497 SAFE_RELEASE(file_containerp);
00498 }
00499 SAFE_RELEASE(device_containerp);
00500 }
00501 }
00502
00503 dumpDevices();
00504 ok = TRUE;
00505
00506 LCleanup:
00507 if (!ok)
00508 {
00509 llwarns << "DX9 probe failed" << llendl;
00510 gWriteDebug("DX9 probe failed\n");
00511 }
00512
00513 SAFE_RELEASE(file_containerp);
00514 SAFE_RELEASE(driver_containerp);
00515 SAFE_RELEASE(device_containerp);
00516 SAFE_RELEASE(devices_containerp);
00517 SAFE_RELEASE(dx_diag_rootp);
00518 SAFE_RELEASE(dx_diag_providerp);
00519
00520 CoUninitialize();
00521
00522 return ok;
00523 }
00524
00525 void LLDXHardware::setWriteDebugFunc(void (*func)(const char*))
00526 {
00527 gWriteDebug = func;
00528 }
00529
00530 #endif