PageRenderTime 70ms CodeModel.GetById 15ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llwindow/lldxhardware.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 670 lines | 357 code | 69 blank | 244 comment | 47 complexity | ec97bde63430225a6a0f2b60ffa26f6d MD5 | raw file
  1/** 
  2 * @file lldxhardware.cpp
  3 * @brief LLDXHardware implementation
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#ifdef LL_WINDOWS
 28
 29// Culled from some Microsoft sample code
 30
 31#include "linden_common.h"
 32
 33#define INITGUID
 34#include <dxdiag.h>
 35#undef INITGUID
 36
 37#include <boost/tokenizer.hpp>
 38
 39#include "lldxhardware.h"
 40#include "llerror.h"
 41
 42#include "llstring.h"
 43#include "llstl.h"
 44#include "lltimer.h"
 45
 46void (*gWriteDebug)(const char* msg) = NULL;
 47LLDXHardware gDXHardware;
 48
 49//-----------------------------------------------------------------------------
 50// Defines, and constants
 51//-----------------------------------------------------------------------------
 52#define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
 53#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
 54#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
 55
 56std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName)
 57{
 58    HRESULT hr;
 59	VARIANT var;
 60	WCHAR wszPropValue[256];
 61
 62	VariantInit( &var );
 63	hr = containerp->GetProp(wszPropName, &var );
 64	if( SUCCEEDED(hr) )
 65	{
 66		// Switch off the type.  There's 4 different types:
 67		switch( var.vt )
 68		{
 69			case VT_UI4:
 70				swprintf( wszPropValue, L"%d", var.ulVal );	/* Flawfinder: ignore */
 71				break;
 72			case VT_I4:
 73				swprintf( wszPropValue, L"%d", var.lVal );	/* Flawfinder: ignore */
 74				break;
 75			case VT_BOOL:
 76				wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" );	/* Flawfinder: ignore */
 77				break;
 78			case VT_BSTR:
 79				wcsncpy( wszPropValue, var.bstrVal, 255 );	/* Flawfinder: ignore */
 80				wszPropValue[255] = 0;
 81				break;
 82		}
 83	}
 84	// Clear the variant (this is needed to free BSTR memory)
 85	VariantClear( &var );
 86
 87	return utf16str_to_utf8str(wszPropValue);
 88}
 89
 90
 91LLVersion::LLVersion()
 92{
 93	mValid = FALSE;
 94	S32 i;
 95	for (i = 0; i < 4; i++)
 96	{
 97		mFields[i] = 0;
 98	}
 99}
100
101BOOL LLVersion::set(const std::string &version_string)
102{
103	S32 i;
104	for (i = 0; i < 4; i++)
105	{
106		mFields[i] = 0;
107	}
108	// Split the version string.
109	std::string str(version_string);
110	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
111	boost::char_separator<char> sep(".", "", boost::keep_empty_tokens);
112	tokenizer tokens(str, sep);
113
114	tokenizer::iterator iter = tokens.begin();
115	S32 count = 0;
116	for (;(iter != tokens.end()) && (count < 4);++iter)
117	{
118		mFields[count] = atoi(iter->c_str());
119		count++;
120	}
121	if (count < 4)
122	{
123		//llwarns << "Potentially bogus version string!" << version_string << llendl;
124		for (i = 0; i < 4; i++)
125		{
126			mFields[i] = 0;
127		}
128		mValid = FALSE;
129	}
130	else
131	{
132		mValid = TRUE;
133	}
134	return mValid;
135}
136
137S32 LLVersion::getField(const S32 field_num)
138{
139	if (!mValid)
140	{
141		return -1;
142	}
143	else
144	{
145		return mFields[field_num];
146	}
147}
148
149std::string LLDXDriverFile::dump()
150{
151	if (gWriteDebug)
152	{
153		gWriteDebug("Filename:");
154		gWriteDebug(mName.c_str());
155		gWriteDebug("\n");
156		gWriteDebug("Ver:");
157		gWriteDebug(mVersionString.c_str());
158		gWriteDebug("\n");
159		gWriteDebug("Date:");
160		gWriteDebug(mDateString.c_str());
161		gWriteDebug("\n");
162	}
163	llinfos << mFilepath << llendl;
164	llinfos << mName << llendl;
165	llinfos << mVersionString << llendl;
166	llinfos << mDateString << llendl;
167
168	return "";
169}
170
171LLDXDevice::~LLDXDevice()
172{
173	for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer());
174}
175
176std::string LLDXDevice::dump()
177{
178	if (gWriteDebug)
179	{
180		gWriteDebug("StartDevice\n");
181		gWriteDebug("DeviceName:");
182		gWriteDebug(mName.c_str());
183		gWriteDebug("\n");
184		gWriteDebug("PCIString:");
185		gWriteDebug(mPCIString.c_str());
186		gWriteDebug("\n");
187	}
188	llinfos << llendl;
189	llinfos << "DeviceName:" << mName << llendl;
190	llinfos << "PCIString:" << mPCIString << llendl;
191	llinfos << "Drivers" << llendl;
192	llinfos << "-------" << llendl;
193	for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
194			 end = mDriverFiles.end();
195		 iter != end; iter++)
196	{
197		LLDXDriverFile *filep = iter->second;
198		filep->dump();
199	}
200	if (gWriteDebug)
201	{
202		gWriteDebug("EndDevice\n");
203	}
204
205	return "";
206}
207
208LLDXDriverFile *LLDXDevice::findDriver(const std::string &driver)
209{
210	for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
211			 end = mDriverFiles.end();
212		 iter != end; iter++)
213	{
214		LLDXDriverFile *filep = iter->second;
215		if (!utf8str_compare_insensitive(filep->mName,driver))
216		{
217			return filep;
218		}
219	}
220
221	return NULL;
222}
223
224LLDXHardware::LLDXHardware()
225{
226	mVRAM = 0;
227	gWriteDebug = NULL;
228}
229
230void LLDXHardware::cleanup()
231{
232  // for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer());
233}
234
235/*
236std::string LLDXHardware::dumpDevices()
237{
238	if (gWriteDebug)
239	{
240		gWriteDebug("\n");
241		gWriteDebug("StartAllDevices\n");
242	}
243	for (device_map_t::iterator iter = mDevices.begin(),
244			 end = mDevices.end();
245		 iter != end; iter++)
246	{
247		LLDXDevice *devicep = iter->second;
248		devicep->dump();
249	}
250	if (gWriteDebug)
251	{
252		gWriteDebug("EndAllDevices\n\n");
253	}
254	return "";
255}
256
257LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::string &devices)
258{
259	// Iterate through different devices tokenized in devices string
260	std::string str(devices);
261	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
262	boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
263	tokenizer tokens(str, sep);
264
265	tokenizer::iterator iter = tokens.begin();
266	for (;iter != tokens.end();++iter)
267	{
268		std::string dev_str = *iter;
269		for (device_map_t::iterator iter = mDevices.begin(),
270				 end = mDevices.end();
271			 iter != end; iter++)
272		{
273			LLDXDevice *devicep = iter->second;
274			if ((devicep->mVendorID == vendor)
275				&& (devicep->mDeviceID == dev_str))
276			{
277				return devicep;
278			}
279		}
280	}
281
282	return NULL;
283}
284*/
285
286BOOL LLDXHardware::getInfo(BOOL vram_only)
287{
288	LLTimer hw_timer;
289	BOOL ok = FALSE;
290    HRESULT       hr;
291
292    CoInitialize(NULL);
293
294    IDxDiagProvider *dx_diag_providerp = NULL;
295    IDxDiagContainer *dx_diag_rootp = NULL;
296	IDxDiagContainer *devices_containerp = NULL;
297	// IDxDiagContainer *system_device_containerp= NULL;
298	IDxDiagContainer *device_containerp = NULL;
299	IDxDiagContainer *file_containerp = NULL;
300	IDxDiagContainer *driver_containerp = NULL;
301
302    // CoCreate a IDxDiagProvider*
303	LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL;
304    hr = CoCreateInstance(CLSID_DxDiagProvider,
305                          NULL,
306                          CLSCTX_INPROC_SERVER,
307                          IID_IDxDiagProvider,
308                          (LPVOID*) &dx_diag_providerp);
309
310	if (FAILED(hr))
311	{
312		LL_WARNS("AppInit") << "No DXDiag provider found!  DirectX 9 not installed!" << LL_ENDL;
313		gWriteDebug("No DXDiag provider found!  DirectX 9 not installed!\n");
314		goto LCleanup;
315	}
316    if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
317    {
318        // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
319        // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are 
320        // digital signed as logo'd by WHQL which may connect via internet to update 
321        // WHQL certificates.    
322        DXDIAG_INIT_PARAMS dx_diag_init_params;
323        ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
324
325        dx_diag_init_params.dwSize                  = sizeof(DXDIAG_INIT_PARAMS);
326        dx_diag_init_params.dwDxDiagHeaderVersion   = DXDIAG_DX9_SDK_VERSION;
327        dx_diag_init_params.bAllowWHQLChecks        = TRUE;
328        dx_diag_init_params.pReserved               = NULL;
329
330		LL_DEBUGS("AppInit") << "dx_diag_providerp->Initialize" << LL_ENDL;
331        hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
332        if(FAILED(hr))
333		{
334            goto LCleanup;
335		}
336
337		LL_DEBUGS("AppInit") << "dx_diag_providerp->GetRootContainer" << LL_ENDL;
338        hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
339        if(FAILED(hr) || !dx_diag_rootp)
340		{
341            goto LCleanup;
342		}
343
344		HRESULT hr;
345
346		// Get display driver information
347		LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer" << LL_ENDL;
348		hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
349		if(FAILED(hr) || !devices_containerp)
350		{
351            goto LCleanup;
352		}
353
354		// Get device 0
355		LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL;
356		hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
357		if(FAILED(hr) || !device_containerp)
358		{
359            goto LCleanup;
360		}
361		
362		// Get the English VRAM string
363		{
364		  std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
365
366		  // We don't need the device any more
367		  SAFE_RELEASE(device_containerp);
368
369		  // Dump the string as an int into the structure
370		  char *stopstring;
371		  mVRAM = strtol(ram_str.c_str(), &stopstring, 10); 
372		  LL_INFOS("AppInit") << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << LL_ENDL;
373		}
374
375		if (vram_only)
376		{
377			ok = TRUE;
378			goto LCleanup;
379		}
380
381
382		/* for now, we ONLY do vram_only the rest of this
383		   is commented out, to ensure no-one is tempted
384		   to use it
385		
386		// Now let's get device and driver information
387		// Get the IDxDiagContainer object called "DxDiag_SystemDevices".
388		// This call may take some time while dxdiag gathers the info.
389		DWORD num_devices = 0;
390	    WCHAR wszContainer[256];
391		LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << LL_ENDL;
392		hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp);
393		if (FAILED(hr))
394		{
395			goto LCleanup;
396		}
397
398		hr = system_device_containerp->GetNumberOfChildContainers(&num_devices);
399		if (FAILED(hr))
400		{
401			goto LCleanup;
402		}
403
404		LL_DEBUGS("AppInit") << "DX9 iterating over devices" << LL_ENDL;
405		S32 device_num = 0;
406		for (device_num = 0; device_num < (S32)num_devices; device_num++)
407		{
408			hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256);
409			if (FAILED(hr))
410			{
411				goto LCleanup;
412			}
413
414			hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp);
415			if (FAILED(hr) || device_containerp == NULL)
416			{
417				goto LCleanup;
418			}
419
420			std::string device_name = get_string(device_containerp, L"szDescription");
421
422			std::string device_id = get_string(device_containerp, L"szDeviceID");
423
424			LLDXDevice *dxdevicep = new LLDXDevice;
425			dxdevicep->mName = device_name;
426			dxdevicep->mPCIString = device_id;
427			mDevices[dxdevicep->mPCIString] = dxdevicep;
428
429			// Split the PCI string based on vendor, device, subsys, rev.
430			std::string str(device_id);
431			typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
432			boost::char_separator<char> sep("&\\", "", boost::keep_empty_tokens);
433			tokenizer tokens(str, sep);
434
435			tokenizer::iterator iter = tokens.begin();
436			S32 count = 0;
437			BOOL valid = TRUE;
438			for (;(iter != tokens.end()) && (count < 3);++iter)
439			{
440				switch (count)
441				{
442				case 0:
443					if (strcmp(iter->c_str(), "PCI"))
444					{
445						valid = FALSE;
446					}
447					break;
448				case 1:
449					dxdevicep->mVendorID = iter->c_str();
450					break;
451				case 2:
452					dxdevicep->mDeviceID = iter->c_str();
453					break;
454				default:
455					// Ignore it
456					break;
457				}
458				count++;
459			}
460
461
462
463
464			// Now, iterate through the related drivers
465			hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp);
466			if (FAILED(hr) || !driver_containerp)
467			{
468				goto LCleanup;
469			}
470
471			DWORD num_files = 0;
472			hr = driver_containerp->GetNumberOfChildContainers(&num_files);
473			if (FAILED(hr))
474			{
475				goto LCleanup;
476			}
477
478			S32 file_num = 0;
479			for (file_num = 0; file_num < (S32)num_files; file_num++ )
480			{
481
482				hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256);
483				if (FAILED(hr))
484				{
485					goto LCleanup;
486				}
487
488				hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp);
489				if (FAILED(hr) || file_containerp == NULL)
490				{
491					goto LCleanup;
492				}
493
494				std::string driver_path = get_string(file_containerp, L"szPath");
495				std::string driver_name = get_string(file_containerp, L"szName");
496				std::string driver_version = get_string(file_containerp, L"szVersion");
497				std::string driver_date = get_string(file_containerp, L"szDatestampEnglish");
498
499				LLDXDriverFile *dxdriverfilep = new LLDXDriverFile;
500				dxdriverfilep->mName = driver_name;
501				dxdriverfilep->mFilepath= driver_path;
502				dxdriverfilep->mVersionString = driver_version;
503				dxdriverfilep->mVersion.set(driver_version);
504				dxdriverfilep->mDateString = driver_date;
505
506				dxdevicep->mDriverFiles[driver_name] = dxdriverfilep;
507
508				SAFE_RELEASE(file_containerp);
509			}
510			SAFE_RELEASE(device_containerp);
511		}
512		*/
513    }
514
515    // dumpDevices();
516    ok = TRUE;
517	
518LCleanup:
519	if (!ok)
520	{
521		LL_WARNS("AppInit") << "DX9 probe failed" << LL_ENDL;
522		gWriteDebug("DX9 probe failed\n");
523	}
524
525	SAFE_RELEASE(file_containerp);
526	SAFE_RELEASE(driver_containerp);
527	SAFE_RELEASE(device_containerp);
528	SAFE_RELEASE(devices_containerp);
529    SAFE_RELEASE(dx_diag_rootp);
530    SAFE_RELEASE(dx_diag_providerp);
531    
532    CoUninitialize();
533    
534    return ok;
535    }
536
537LLSD LLDXHardware::getDisplayInfo()
538{
539	LLTimer hw_timer;
540    HRESULT       hr;
541	LLSD ret;
542    CoInitialize(NULL);
543
544    IDxDiagProvider *dx_diag_providerp = NULL;
545    IDxDiagContainer *dx_diag_rootp = NULL;
546	IDxDiagContainer *devices_containerp = NULL;
547	IDxDiagContainer *device_containerp = NULL;
548	IDxDiagContainer *file_containerp = NULL;
549	IDxDiagContainer *driver_containerp = NULL;
550
551    // CoCreate a IDxDiagProvider*
552	llinfos << "CoCreateInstance IID_IDxDiagProvider" << llendl;
553    hr = CoCreateInstance(CLSID_DxDiagProvider,
554                          NULL,
555                          CLSCTX_INPROC_SERVER,
556                          IID_IDxDiagProvider,
557                          (LPVOID*) &dx_diag_providerp);
558
559	if (FAILED(hr))
560	{
561		llwarns << "No DXDiag provider found!  DirectX 9 not installed!" << llendl;
562		gWriteDebug("No DXDiag provider found!  DirectX 9 not installed!\n");
563		goto LCleanup;
564	}
565    if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
566    {
567        // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
568        // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are 
569        // digital signed as logo'd by WHQL which may connect via internet to update 
570        // WHQL certificates.    
571        DXDIAG_INIT_PARAMS dx_diag_init_params;
572        ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
573
574        dx_diag_init_params.dwSize                  = sizeof(DXDIAG_INIT_PARAMS);
575        dx_diag_init_params.dwDxDiagHeaderVersion   = DXDIAG_DX9_SDK_VERSION;
576        dx_diag_init_params.bAllowWHQLChecks        = TRUE;
577        dx_diag_init_params.pReserved               = NULL;
578
579		llinfos << "dx_diag_providerp->Initialize" << llendl;
580        hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
581        if(FAILED(hr))
582		{
583            goto LCleanup;
584		}
585
586		llinfos << "dx_diag_providerp->GetRootContainer" << llendl;
587        hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
588        if(FAILED(hr) || !dx_diag_rootp)
589		{
590            goto LCleanup;
591		}
592
593		HRESULT hr;
594
595		// Get display driver information
596		llinfos << "dx_diag_rootp->GetChildContainer" << llendl;
597		hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
598		if(FAILED(hr) || !devices_containerp)
599		{
600            goto LCleanup;
601		}
602
603		// Get device 0
604		llinfos << "devices_containerp->GetChildContainer" << llendl;
605		hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
606		if(FAILED(hr) || !device_containerp)
607		{
608            goto LCleanup;
609		}
610		
611		// Get the English VRAM string
612		std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
613
614
615		// Dump the string as an int into the structure
616		char *stopstring;
617		ret["VRAM"] = strtol(ram_str.c_str(), &stopstring, 10);
618		std::string device_name = get_string(device_containerp, L"szDescription");
619		ret["DeviceName"] = device_name;
620		std::string device_driver=  get_string(device_containerp, L"szDriverVersion");
621		ret["DriverVersion"] = device_driver;
622        
623        // ATI has a slightly different version string
624        if(device_name.length() >= 4 && device_name.substr(0,4) == "ATI ")
625        {
626            // get the key
627            HKEY hKey;
628            const DWORD RV_SIZE = 100;
629            WCHAR release_version[RV_SIZE];
630
631            // Hard coded registry entry.  Using this since it's simpler for now.
632            // And using EnumDisplayDevices to get a registry key also requires
633            // a hard coded Query value.
634            if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\ATI Technologies\\CBT"), &hKey))
635            {
636                // get the value
637                DWORD dwType = REG_SZ;
638                DWORD dwSize = sizeof(WCHAR) * RV_SIZE;
639                if(ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("ReleaseVersion"), 
640                    NULL, &dwType, (LPBYTE)release_version, &dwSize))
641                {
642                    // print the value
643                    // windows doesn't guarantee to be null terminated
644                    release_version[RV_SIZE - 1] = NULL;
645                    ret["DriverVersion"] = utf16str_to_utf8str(release_version);
646
647                }
648                RegCloseKey(hKey);
649            }
650        }    
651    }
652
653LCleanup:
654	SAFE_RELEASE(file_containerp);
655	SAFE_RELEASE(driver_containerp);
656	SAFE_RELEASE(device_containerp);
657	SAFE_RELEASE(devices_containerp);
658    SAFE_RELEASE(dx_diag_rootp);
659    SAFE_RELEASE(dx_diag_providerp);
660    
661    CoUninitialize();
662	return ret;
663}
664
665void LLDXHardware::setWriteDebugFunc(void (*func)(const char*))
666{
667	gWriteDebug = func;
668}
669
670#endif