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 #define INITGUID
00039 #include <dxdiag.h>
00040 #undef INITGUID
00041 
00042 #include <boost/tokenizer.hpp>
00043 
00044 #include "lldxhardware.h"
00045 #include "llerror.h"
00046 
00047 #include "llstring.h"
00048 #include "llstl.h"
00049 
00050 void (*gWriteDebug)(const char* msg) = NULL;
00051 LLDXHardware gDXHardware;
00052 
00053 //-----------------------------------------------------------------------------
00054 // Defines, and constants
00055 //-----------------------------------------------------------------------------
00056 #define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
00057 #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
00058 #define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
00059 
00060 std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName)
00061 {
00062     HRESULT hr;
00063         VARIANT var;
00064         WCHAR wszPropValue[256];
00065 
00066         VariantInit( &var );
00067         hr = containerp->GetProp(wszPropName, &var );
00068         if( SUCCEEDED(hr) )
00069         {
00070                 // Switch off the type.  There's 4 different types:
00071                 switch( var.vt )
00072                 {
00073                         case VT_UI4:
00074                                 swprintf( wszPropValue, L"%d", var.ulVal );     /* Flawfinder: ignore */
00075                                 break;
00076                         case VT_I4:
00077                                 swprintf( wszPropValue, L"%d", var.lVal );      /* Flawfinder: ignore */
00078                                 break;
00079                         case VT_BOOL:
00080                                 wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" );     /* Flawfinder: ignore */
00081                                 break;
00082                         case VT_BSTR:
00083                                 wcsncpy( wszPropValue, var.bstrVal, 255 );      /* Flawfinder: ignore */
00084                                 wszPropValue[255] = 0;
00085                                 break;
00086                 }
00087         }
00088         // Clear the variant (this is needed to free BSTR memory)
00089         VariantClear( &var );
00090 
00091         return utf16str_to_utf8str(wszPropValue);
00092 }
00093 
00094 
00095 LLVersion::LLVersion()
00096 {
00097         mValid = FALSE;
00098         S32 i;
00099         for (i = 0; i < 4; i++)
00100         {
00101                 mFields[i] = 0;
00102         }
00103 }
00104 
00105 BOOL LLVersion::set(const std::string &version_string)
00106 {
00107         S32 i;
00108         for (i = 0; i < 4; i++)
00109         {
00110                 mFields[i] = 0;
00111         }
00112         // Split the version string.
00113         std::string str(version_string);
00114         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00115         boost::char_separator<char> sep(".", "", boost::keep_empty_tokens);
00116         tokenizer tokens(str, sep);
00117 
00118         tokenizer::iterator iter = tokens.begin();
00119         S32 count = 0;
00120         for (;(iter != tokens.end()) && (count < 4);++iter)
00121         {
00122                 mFields[count] = atoi(iter->c_str());
00123                 count++;
00124         }
00125         if (count < 4)
00126         {
00127                 //llwarns << "Potentially bogus version string!" << version_string << llendl;
00128                 for (i = 0; i < 4; i++)
00129                 {
00130                         mFields[i] = 0;
00131                 }
00132                 mValid = FALSE;
00133         }
00134         else
00135         {
00136                 mValid = TRUE;
00137         }
00138         return mValid;
00139 }
00140 
00141 S32 LLVersion::getField(const S32 field_num)
00142 {
00143         if (!mValid)
00144         {
00145                 return -1;
00146         }
00147         else
00148         {
00149                 return mFields[field_num];
00150         }
00151 }
00152 
00153 LLString LLDXDriverFile::dump()
00154 {
00155         if (gWriteDebug)
00156         {
00157                 gWriteDebug("Filename:");
00158                 gWriteDebug(mName.c_str());
00159                 gWriteDebug("\n");
00160                 gWriteDebug("Ver:");
00161                 gWriteDebug(mVersionString.c_str());
00162                 gWriteDebug("\n");
00163                 gWriteDebug("Date:");
00164                 gWriteDebug(mDateString.c_str());
00165                 gWriteDebug("\n");
00166         }
00167         llinfos << mFilepath << llendl;
00168         llinfos << mName << llendl;
00169         llinfos << mVersionString << llendl;
00170         llinfos << mDateString << llendl;
00171 
00172         return "";
00173 }
00174 
00175 LLDXDevice::~LLDXDevice()
00176 {
00177         for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer());
00178 }
00179 
00180 std::string LLDXDevice::dump()
00181 {
00182         if (gWriteDebug)
00183         {
00184                 gWriteDebug("StartDevice\n");
00185                 gWriteDebug("DeviceName:");
00186                 gWriteDebug(mName.c_str());
00187                 gWriteDebug("\n");
00188                 gWriteDebug("PCIString:");
00189                 gWriteDebug(mPCIString.c_str());
00190                 gWriteDebug("\n");
00191         }
00192         llinfos << llendl;
00193         llinfos << "DeviceName:" << mName << llendl;
00194         llinfos << "PCIString:" << mPCIString << llendl;
00195         llinfos << "Drivers" << llendl;
00196         llinfos << "-------" << llendl;
00197         for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
00198                          end = mDriverFiles.end();
00199                  iter != end; iter++)
00200         {
00201                 LLDXDriverFile *filep = iter->second;
00202                 filep->dump();
00203         }
00204         if (gWriteDebug)
00205         {
00206                 gWriteDebug("EndDevice\n");
00207         }
00208 
00209         return "";
00210 }
00211 
00212 LLDXDriverFile *LLDXDevice::findDriver(const std::string &driver)
00213 {
00214         for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
00215                          end = mDriverFiles.end();
00216                  iter != end; iter++)
00217         {
00218                 LLDXDriverFile *filep = iter->second;
00219                 if (!utf8str_compare_insensitive(filep->mName,driver))
00220                 {
00221                         return filep;
00222                 }
00223         }
00224 
00225         return NULL;
00226 }
00227 
00228 LLDXHardware::LLDXHardware()
00229 {
00230         mVRAM = 0;
00231         gWriteDebug = NULL;
00232 }
00233 
00234 void LLDXHardware::cleanup()
00235 {
00236   // for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer());
00237 }
00238 
00239 /*
00240 LLString LLDXHardware::dumpDevices()
00241 {
00242         if (gWriteDebug)
00243         {
00244                 gWriteDebug("\n");
00245                 gWriteDebug("StartAllDevices\n");
00246         }
00247         for (device_map_t::iterator iter = mDevices.begin(),
00248                          end = mDevices.end();
00249                  iter != end; iter++)
00250         {
00251                 LLDXDevice *devicep = iter->second;
00252                 devicep->dump();
00253         }
00254         if (gWriteDebug)
00255         {
00256                 gWriteDebug("EndAllDevices\n\n");
00257         }
00258         return "";
00259 }
00260 
00261 LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::string &devices)
00262 {
00263         // Iterate through different devices tokenized in devices string
00264         std::string str(devices);
00265         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00266         boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
00267         tokenizer tokens(str, sep);
00268 
00269         tokenizer::iterator iter = tokens.begin();
00270         for (;iter != tokens.end();++iter)
00271         {
00272                 std::string dev_str = *iter;
00273                 for (device_map_t::iterator iter = mDevices.begin(),
00274                                  end = mDevices.end();
00275                          iter != end; iter++)
00276                 {
00277                         LLDXDevice *devicep = iter->second;
00278                         if ((devicep->mVendorID == vendor)
00279                                 && (devicep->mDeviceID == dev_str))
00280                         {
00281                                 return devicep;
00282                         }
00283                 }
00284         }
00285 
00286         return NULL;
00287 }
00288 */
00289 
00290 BOOL LLDXHardware::getInfo(BOOL vram_only)
00291 {
00292         LLTimer hw_timer;
00293         BOOL ok = FALSE;
00294     HRESULT       hr;
00295 
00296     CoInitialize(NULL);
00297 
00298     IDxDiagProvider *dx_diag_providerp = NULL;
00299     IDxDiagContainer *dx_diag_rootp = NULL;
00300         IDxDiagContainer *devices_containerp = NULL;
00301         // IDxDiagContainer *system_device_containerp= NULL;
00302         IDxDiagContainer *device_containerp = NULL;
00303         IDxDiagContainer *file_containerp = NULL;
00304         IDxDiagContainer *driver_containerp = NULL;
00305 
00306     // CoCreate a IDxDiagProvider*
00307         LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL;
00308     hr = CoCreateInstance(CLSID_DxDiagProvider,
00309                           NULL,
00310                           CLSCTX_INPROC_SERVER,
00311                           IID_IDxDiagProvider,
00312                           (LPVOID*) &dx_diag_providerp);
00313 
00314         if (FAILED(hr))
00315         {
00316                 LL_WARNS("AppInit") << "No DXDiag provider found!  DirectX 9 not installed!" << LL_ENDL;
00317                 gWriteDebug("No DXDiag provider found!  DirectX 9 not installed!\n");
00318                 goto LCleanup;
00319         }
00320     if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
00321     {
00322         // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
00323         // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are 
00324         // digital signed as logo'd by WHQL which may connect via internet to update 
00325         // WHQL certificates.    
00326         DXDIAG_INIT_PARAMS dx_diag_init_params;
00327         ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
00328 
00329         dx_diag_init_params.dwSize                  = sizeof(DXDIAG_INIT_PARAMS);
00330         dx_diag_init_params.dwDxDiagHeaderVersion   = DXDIAG_DX9_SDK_VERSION;
00331         dx_diag_init_params.bAllowWHQLChecks        = TRUE;
00332         dx_diag_init_params.pReserved               = NULL;
00333 
00334                 LL_DEBUGS("AppInit") << "dx_diag_providerp->Initialize" << LL_ENDL;
00335         hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
00336         if(FAILED(hr))
00337                 {
00338             goto LCleanup;
00339                 }
00340 
00341                 LL_DEBUGS("AppInit") << "dx_diag_providerp->GetRootContainer" << LL_ENDL;
00342         hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
00343         if(FAILED(hr) || !dx_diag_rootp)
00344                 {
00345             goto LCleanup;
00346                 }
00347 
00348                 HRESULT hr;
00349 
00350                 // Get display driver information
00351                 LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer" << LL_ENDL;
00352                 hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
00353                 if(FAILED(hr) || !devices_containerp)
00354                 {
00355             goto LCleanup;
00356                 }
00357 
00358                 // Get device 0
00359                 LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL;
00360                 hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
00361                 if(FAILED(hr) || !device_containerp)
00362                 {
00363             goto LCleanup;
00364                 }
00365                 
00366                 // Get the English VRAM string
00367                 {
00368                   std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
00369 
00370                   // We don't need the device any more
00371                   SAFE_RELEASE(device_containerp);
00372 
00373                   // Dump the string as an int into the structure
00374                   char *stopstring;
00375                   mVRAM = strtol(ram_str.c_str(), &stopstring, 10); 
00376                   LL_INFOS("AppInit") << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << LL_ENDL;
00377                 }
00378 
00379                 if (vram_only)
00380                 {
00381                         ok = TRUE;
00382                         goto LCleanup;
00383                 }
00384 
00385 
00386                 /* for now, we ONLY do vram_only the rest of this
00387                    is commented out, to ensure no-one is tempted
00388                    to use it
00389                 
00390                 // Now let's get device and driver information
00391                 // Get the IDxDiagContainer object called "DxDiag_SystemDevices".
00392                 // This call may take some time while dxdiag gathers the info.
00393                 DWORD num_devices = 0;
00394             WCHAR wszContainer[256];
00395                 LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << LL_ENDL;
00396                 hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp);
00397                 if (FAILED(hr))
00398                 {
00399                         goto LCleanup;
00400                 }
00401 
00402                 hr = system_device_containerp->GetNumberOfChildContainers(&num_devices);
00403                 if (FAILED(hr))
00404                 {
00405                         goto LCleanup;
00406                 }
00407 
00408                 LL_DEBUGS("AppInit") << "DX9 iterating over devices" << LL_ENDL;
00409                 S32 device_num = 0;
00410                 for (device_num = 0; device_num < (S32)num_devices; device_num++)
00411                 {
00412                         hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256);
00413                         if (FAILED(hr))
00414                         {
00415                                 goto LCleanup;
00416                         }
00417 
00418                         hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp);
00419                         if (FAILED(hr) || device_containerp == NULL)
00420                         {
00421                                 goto LCleanup;
00422                         }
00423 
00424                         std::string device_name = get_string(device_containerp, L"szDescription");
00425 
00426                         std::string device_id = get_string(device_containerp, L"szDeviceID");
00427 
00428                         LLDXDevice *dxdevicep = new LLDXDevice;
00429                         dxdevicep->mName = device_name;
00430                         dxdevicep->mPCIString = device_id;
00431                         mDevices[dxdevicep->mPCIString] = dxdevicep;
00432 
00433                         // Split the PCI string based on vendor, device, subsys, rev.
00434                         std::string str(device_id);
00435                         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00436                         boost::char_separator<char> sep("&\\", "", boost::keep_empty_tokens);
00437                         tokenizer tokens(str, sep);
00438 
00439                         tokenizer::iterator iter = tokens.begin();
00440                         S32 count = 0;
00441                         BOOL valid = TRUE;
00442                         for (;(iter != tokens.end()) && (count < 3);++iter)
00443                         {
00444                                 switch (count)
00445                                 {
00446                                 case 0:
00447                                         if (strcmp(iter->c_str(), "PCI"))
00448                                         {
00449                                                 valid = FALSE;
00450                                         }
00451                                         break;
00452                                 case 1:
00453                                         dxdevicep->mVendorID = iter->c_str();
00454                                         break;
00455                                 case 2:
00456                                         dxdevicep->mDeviceID = iter->c_str();
00457                                         break;
00458                                 default:
00459                                         // Ignore it
00460                                         break;
00461                                 }
00462                                 count++;
00463                         }
00464 
00465 
00466 
00467 
00468                         // Now, iterate through the related drivers
00469                         hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp);
00470                         if (FAILED(hr) || !driver_containerp)
00471                         {
00472                                 goto LCleanup;
00473                         }
00474 
00475                         DWORD num_files = 0;
00476                         hr = driver_containerp->GetNumberOfChildContainers(&num_files);
00477                         if (FAILED(hr))
00478                         {
00479                                 goto LCleanup;
00480                         }
00481 
00482                         S32 file_num = 0;
00483                         for (file_num = 0; file_num < (S32)num_files; file_num++ )
00484                         {
00485 
00486                                 hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256);
00487                                 if (FAILED(hr))
00488                                 {
00489                                         goto LCleanup;
00490                                 }
00491 
00492                                 hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp);
00493                                 if (FAILED(hr) || file_containerp == NULL)
00494                                 {
00495                                         goto LCleanup;
00496                                 }
00497 
00498                                 std::string driver_path = get_string(file_containerp, L"szPath");
00499                                 std::string driver_name = get_string(file_containerp, L"szName");
00500                                 std::string driver_version = get_string(file_containerp, L"szVersion");
00501                                 std::string driver_date = get_string(file_containerp, L"szDatestampEnglish");
00502 
00503                                 LLDXDriverFile *dxdriverfilep = new LLDXDriverFile;
00504                                 dxdriverfilep->mName = driver_name;
00505                                 dxdriverfilep->mFilepath= driver_path;
00506                                 dxdriverfilep->mVersionString = driver_version;
00507                                 dxdriverfilep->mVersion.set(driver_version);
00508                                 dxdriverfilep->mDateString = driver_date;
00509 
00510                                 dxdevicep->mDriverFiles[driver_name] = dxdriverfilep;
00511 
00512                                 SAFE_RELEASE(file_containerp);
00513                         }
00514                         SAFE_RELEASE(device_containerp);
00515                 }
00516                 */
00517     }
00518 
00519     // dumpDevices();
00520     ok = TRUE;
00521         
00522 LCleanup:
00523         if (!ok)
00524         {
00525                 LL_WARNS("AppInit") << "DX9 probe failed" << LL_ENDL;
00526                 gWriteDebug("DX9 probe failed\n");
00527         }
00528 
00529         SAFE_RELEASE(file_containerp);
00530         SAFE_RELEASE(driver_containerp);
00531         SAFE_RELEASE(device_containerp);
00532         SAFE_RELEASE(devices_containerp);
00533     SAFE_RELEASE(dx_diag_rootp);
00534     SAFE_RELEASE(dx_diag_providerp);
00535     
00536     CoUninitialize();
00537     
00538     return ok;
00539     }
00540 
00541 LLSD LLDXHardware::getDisplayInfo()
00542 {
00543         LLTimer hw_timer;
00544     HRESULT       hr;
00545         LLSD ret;
00546     CoInitialize(NULL);
00547 
00548     IDxDiagProvider *dx_diag_providerp = NULL;
00549     IDxDiagContainer *dx_diag_rootp = NULL;
00550         IDxDiagContainer *devices_containerp = NULL;
00551         IDxDiagContainer *device_containerp = NULL;
00552         IDxDiagContainer *file_containerp = NULL;
00553         IDxDiagContainer *driver_containerp = NULL;
00554 
00555     // CoCreate a IDxDiagProvider*
00556         llinfos << "CoCreateInstance IID_IDxDiagProvider" << llendl;
00557     hr = CoCreateInstance(CLSID_DxDiagProvider,
00558                           NULL,
00559                           CLSCTX_INPROC_SERVER,
00560                           IID_IDxDiagProvider,
00561                           (LPVOID*) &dx_diag_providerp);
00562 
00563         if (FAILED(hr))
00564         {
00565                 llwarns << "No DXDiag provider found!  DirectX 9 not installed!" << llendl;
00566                 gWriteDebug("No DXDiag provider found!  DirectX 9 not installed!\n");
00567                 goto LCleanup;
00568         }
00569     if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
00570     {
00571         // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
00572         // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are 
00573         // digital signed as logo'd by WHQL which may connect via internet to update 
00574         // WHQL certificates.    
00575         DXDIAG_INIT_PARAMS dx_diag_init_params;
00576         ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
00577 
00578         dx_diag_init_params.dwSize                  = sizeof(DXDIAG_INIT_PARAMS);
00579         dx_diag_init_params.dwDxDiagHeaderVersion   = DXDIAG_DX9_SDK_VERSION;
00580         dx_diag_init_params.bAllowWHQLChecks        = TRUE;
00581         dx_diag_init_params.pReserved               = NULL;
00582 
00583                 llinfos << "dx_diag_providerp->Initialize" << llendl;
00584         hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
00585         if(FAILED(hr))
00586                 {
00587             goto LCleanup;
00588                 }
00589 
00590                 llinfos << "dx_diag_providerp->GetRootContainer" << llendl;
00591         hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
00592         if(FAILED(hr) || !dx_diag_rootp)
00593                 {
00594             goto LCleanup;
00595                 }
00596 
00597                 HRESULT hr;
00598 
00599                 // Get display driver information
00600                 llinfos << "dx_diag_rootp->GetChildContainer" << llendl;
00601                 hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
00602                 if(FAILED(hr) || !devices_containerp)
00603                 {
00604             goto LCleanup;
00605                 }
00606 
00607                 // Get device 0
00608                 llinfos << "devices_containerp->GetChildContainer" << llendl;
00609                 hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
00610                 if(FAILED(hr) || !device_containerp)
00611                 {
00612             goto LCleanup;
00613                 }
00614                 
00615                 // Get the English VRAM string
00616                 std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
00617 
00618 
00619                 // Dump the string as an int into the structure
00620                 char *stopstring;
00621                 ret["VRAM"] = strtol(ram_str.c_str(), &stopstring, 10);
00622                 std::string device_name = get_string(device_containerp, L"szDescription");
00623                 ret["DeviceName"] = device_name;
00624                 std::string device_driver=  get_string(device_containerp, L"szDriverVersion");
00625                 ret["DriverVersion"] = device_driver;
00626         }
00627 LCleanup:
00628         SAFE_RELEASE(file_containerp);
00629         SAFE_RELEASE(driver_containerp);
00630         SAFE_RELEASE(device_containerp);
00631         SAFE_RELEASE(devices_containerp);
00632     SAFE_RELEASE(dx_diag_rootp);
00633     SAFE_RELEASE(dx_diag_providerp);
00634     
00635     CoUninitialize();
00636         return ret;
00637 }
00638 
00639 void LLDXHardware::setWriteDebugFunc(void (*func)(const char*))
00640 {
00641         gWriteDebug = func;
00642 }
00643 
00644 #endif

Generated on Fri May 16 08:33:02 2008 for SecondLife by  doxygen 1.5.5