lldxhardware.cpp

Go to the documentation of this file.
00001 
00032 #ifdef LL_WINDOWS
00033 
00034 // Culled from some Microsoft sample code
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 // Defines, and constants
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                 // Switch off the type.  There's 4 different types:
00069                 switch( var.vt )
00070                 {
00071                         case VT_UI4:
00072                                 swprintf( wszPropValue, L"%d", var.ulVal );     /* Flawfinder: ignore */
00073                                 break;
00074                         case VT_I4:
00075                                 swprintf( wszPropValue, L"%d", var.lVal );      /* Flawfinder: ignore */
00076                                 break;
00077                         case VT_BOOL:
00078                                 wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" );     /* Flawfinder: ignore */
00079                                 break;
00080                         case VT_BSTR:
00081                                 wcsncpy( wszPropValue, var.bstrVal, 255 );      /* Flawfinder: ignore */
00082                                 wszPropValue[255] = 0;
00083                                 break;
00084                 }
00085         }
00086         // Clear the variant (this is needed to free BSTR memory)
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         // Split the version string.
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                 //llwarns << "Potentially bogus version string!" << version_string << llendl;
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         // Iterate through different devices tokenized in devices string
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     // CoCreate a IDxDiagProvider*
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)) // if FAILED(hr) then dx9 is not installed
00317     {
00318         // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
00319         // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are 
00320         // digital signed as logo'd by WHQL which may connect via internet to update 
00321         // WHQL certificates.    
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                 // Get display driver information
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                 // Get device 0
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                 // Get the English VRAM string
00363                 std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
00364 
00365                 // We don't need the device any more
00366                 SAFE_RELEASE(device_containerp);
00367 
00368                 // Dump the string as an int into the structure
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                 // Now let's get device and driver information
00380                 // Get the IDxDiagContainer object called "DxDiag_SystemDevices".
00381                 // This call may take some time while dxdiag gathers the info.
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                         // Split the PCI string based on vendor, device, subsys, rev.
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                                         // Ignore it
00448                                         break;
00449                                 }
00450                                 count++;
00451                         }
00452 
00453 
00454                         // Now, iterate through the related drivers
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

Generated on Thu Jul 1 06:08:28 2010 for Second Life Viewer by  doxygen 1.4.7