aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llwindow/lldxhardware.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llwindow/lldxhardware.cpp')
-rw-r--r--linden/indra/llwindow/lldxhardware.cpp527
1 files changed, 527 insertions, 0 deletions
diff --git a/linden/indra/llwindow/lldxhardware.cpp b/linden/indra/llwindow/lldxhardware.cpp
new file mode 100644
index 0000000..5dd632b
--- /dev/null
+++ b/linden/indra/llwindow/lldxhardware.cpp
@@ -0,0 +1,527 @@
1/**
2 * @file lldxhardware.cpp
3 * @brief LLDXHardware implementation
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifdef LL_WINDOWS
29
30// Culled from some Microsoft sample code
31
32#include "linden_common.h"
33
34#include <assert.h>
35#include <dxdiag.h>
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
45void (*gWriteDebug)(const char* msg) = NULL;
46LLDXHardware gDXHardware;
47
48//-----------------------------------------------------------------------------
49// Defines, and constants
50//-----------------------------------------------------------------------------
51#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
52#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
53#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
54
55std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName)
56{
57 HRESULT hr;
58 VARIANT var;
59 WCHAR wszPropValue[256];
60
61 VariantInit( &var );
62 hr = containerp->GetProp(wszPropName, &var );
63 if( SUCCEEDED(hr) )
64 {
65 // Switch off the type. There's 4 different types:
66 switch( var.vt )
67 {
68 case VT_UI4:
69 swprintf( wszPropValue, L"%d", var.ulVal );
70 break;
71 case VT_I4:
72 swprintf( wszPropValue, L"%d", var.lVal );
73 break;
74 case VT_BOOL:
75 wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" );
76 break;
77 case VT_BSTR:
78 wcsncpy( wszPropValue, var.bstrVal, 255 );
79 wszPropValue[255] = 0;
80 break;
81 }
82 }
83 // Clear the variant (this is needed to free BSTR memory)
84 VariantClear( &var );
85
86 return utf16str_to_utf8str(wszPropValue);
87}
88
89
90LLVersion::LLVersion()
91{
92 mValid = FALSE;
93 S32 i;
94 for (i = 0; i < 4; i++)
95 {
96 mFields[i] = 0;
97 }
98}
99
100BOOL LLVersion::set(const std::string &version_string)
101{
102 S32 i;
103 for (i = 0; i < 4; i++)
104 {
105 mFields[i] = 0;
106 }
107 // Split the version string.
108 std::string str(version_string);
109 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
110 boost::char_separator<char> sep(".", "", boost::keep_empty_tokens);
111 tokenizer tokens(str, sep);
112
113 tokenizer::iterator iter = tokens.begin();
114 S32 count = 0;
115 for (;(iter != tokens.end()) && (count < 4);++iter)
116 {
117 mFields[count] = atoi(iter->c_str());
118 count++;
119 }
120 if (count < 4)
121 {
122 //llwarns << "Potentially bogus version string!" << version_string << llendl;
123 for (i = 0; i < 4; i++)
124 {
125 mFields[i] = 0;
126 }
127 mValid = FALSE;
128 }
129 else
130 {
131 mValid = TRUE;
132 }
133 return mValid;
134}
135
136S32 LLVersion::getField(const S32 field_num)
137{
138 if (!mValid)
139 {
140 return -1;
141 }
142 else
143 {
144 return mFields[field_num];
145 }
146}
147
148LLString LLDXDriverFile::dump()
149{
150 if (gWriteDebug)
151 {
152 gWriteDebug("Filename:");
153 gWriteDebug(mName.c_str());
154 gWriteDebug("\n");
155 gWriteDebug("Ver:");
156 gWriteDebug(mVersionString.c_str());
157 gWriteDebug("\n");
158 gWriteDebug("Date:");
159 gWriteDebug(mDateString.c_str());
160 gWriteDebug("\n");
161 }
162 llinfos << mFilepath << llendl;
163 llinfos << mName << llendl;
164 llinfos << mVersionString << llendl;
165 llinfos << mDateString << llendl;
166
167 return "";
168}
169
170LLDXDevice::~LLDXDevice()
171{
172 for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer());
173}
174
175std::string LLDXDevice::dump()
176{
177 if (gWriteDebug)
178 {
179 gWriteDebug("StartDevice\n");
180 gWriteDebug("DeviceName:");
181 gWriteDebug(mName.c_str());
182 gWriteDebug("\n");
183 gWriteDebug("PCIString:");
184 gWriteDebug(mPCIString.c_str());
185 gWriteDebug("\n");
186 }
187 llinfos << llendl;
188 llinfos << "DeviceName:" << mName << llendl;
189 llinfos << "PCIString:" << mPCIString << llendl;
190 llinfos << "Drivers" << llendl;
191 llinfos << "-------" << llendl;
192 for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
193 end = mDriverFiles.end();
194 iter != end; iter++)
195 {
196 LLDXDriverFile *filep = iter->second;
197 filep->dump();
198 }
199 if (gWriteDebug)
200 {
201 gWriteDebug("EndDevice\n");
202 }
203
204 return "";
205}
206
207LLDXDriverFile *LLDXDevice::findDriver(const std::string &driver)
208{
209 for (driver_file_map_t::iterator iter = mDriverFiles.begin(),
210 end = mDriverFiles.end();
211 iter != end; iter++)
212 {
213 LLDXDriverFile *filep = iter->second;
214 if (!utf8str_compare_insensitive(filep->mName,driver))
215 {
216 return filep;
217 }
218 }
219
220 return NULL;
221}
222
223LLDXHardware::LLDXHardware()
224{
225 mVRAM = 0;
226 gWriteDebug = NULL;
227}
228
229void LLDXHardware::cleanup()
230{
231 for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer());
232}
233
234LLString LLDXHardware::dumpDevices()
235{
236 if (gWriteDebug)
237 {
238 gWriteDebug("\n");
239 gWriteDebug("StartAllDevices\n");
240 }
241 for (device_map_t::iterator iter = mDevices.begin(),
242 end = mDevices.end();
243 iter != end; iter++)
244 {
245 LLDXDevice *devicep = iter->second;
246 devicep->dump();
247 }
248 if (gWriteDebug)
249 {
250 gWriteDebug("EndAllDevices\n\n");
251 }
252 return "";
253}
254
255LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::string &devices)
256{
257 // Iterate through different devices tokenized in devices string
258 std::string str(devices);
259 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
260 boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
261 tokenizer tokens(str, sep);
262
263 tokenizer::iterator iter = tokens.begin();
264 for (;iter != tokens.end();++iter)
265 {
266 std::string dev_str = *iter;
267 for (device_map_t::iterator iter = mDevices.begin(),
268 end = mDevices.end();
269 iter != end; iter++)
270 {
271 LLDXDevice *devicep = iter->second;
272 if ((devicep->mVendorID == vendor)
273 && (devicep->mDeviceID == dev_str))
274 {
275 return devicep;
276 }
277 }
278 }
279
280 return NULL;
281}
282
283BOOL LLDXHardware::getInfo(BOOL vram_only)
284{
285 LLTimer hw_timer;
286 BOOL ok = FALSE;
287 HRESULT hr;
288
289 CoInitialize(NULL);
290
291 IDxDiagProvider *dx_diag_providerp = NULL;
292 IDxDiagContainer *dx_diag_rootp = NULL;
293 IDxDiagContainer *devices_containerp = NULL;
294 IDxDiagContainer *system_device_containerp= NULL;
295 IDxDiagContainer *device_containerp = NULL;
296 IDxDiagContainer *file_containerp = NULL;
297 IDxDiagContainer *driver_containerp = NULL;
298
299 // CoCreate a IDxDiagProvider*
300 llinfos << "CoCreateInstance IID_IDxDiagProvider" << llendl;
301 hr = CoCreateInstance(CLSID_DxDiagProvider,
302 NULL,
303 CLSCTX_INPROC_SERVER,
304 IID_IDxDiagProvider,
305 (LPVOID*) &dx_diag_providerp);
306
307 if (FAILED(hr))
308 {
309 llwarns << "No DXDiag provider found! DirectX 9 not installed!" << llendl;
310 gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n");
311 goto LCleanup;
312 }
313 if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
314 {
315 // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize
316 // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are
317 // digital signed as logo'd by WHQL which may connect via internet to update
318 // WHQL certificates.
319 DXDIAG_INIT_PARAMS dx_diag_init_params;
320 ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
321
322 dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS);
323 dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
324 dx_diag_init_params.bAllowWHQLChecks = TRUE;
325 dx_diag_init_params.pReserved = NULL;
326
327 llinfos << "dx_diag_providerp->Initialize" << llendl;
328 hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
329 if(FAILED(hr))
330 {
331 goto LCleanup;
332 }
333
334 llinfos << "dx_diag_providerp->GetRootContainer" << llendl;
335 hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp );
336 if(FAILED(hr) || !dx_diag_rootp)
337 {
338 goto LCleanup;
339 }
340
341 HRESULT hr;
342
343 // Get display driver information
344 llinfos << "dx_diag_rootp->GetChildContainer" << llendl;
345 hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp);
346 if(FAILED(hr) || !devices_containerp)
347 {
348 goto LCleanup;
349 }
350
351 // Get device 0
352 llinfos << "devices_containerp->GetChildContainer" << llendl;
353 hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
354 if(FAILED(hr) || !device_containerp)
355 {
356 goto LCleanup;
357 }
358
359 // Get the English VRAM string
360 std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish");
361
362 // We don't need the device any more
363 SAFE_RELEASE(device_containerp);
364
365 // Dump the string as an int into the structure
366 char *stopstring;
367 mVRAM = strtol(ram_str.c_str(), &stopstring, 10);
368 llinfos << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << llendl;
369
370 if (vram_only)
371 {
372 ok = TRUE;
373 goto LCleanup;
374 }
375
376 // Now let's get device and driver information
377 // Get the IDxDiagContainer object called "DxDiag_SystemDevices".
378 // This call may take some time while dxdiag gathers the info.
379 DWORD num_devices = 0;
380 WCHAR wszContainer[256];
381 llinfos << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << llendl;
382 hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp);
383 if (FAILED(hr))
384 {
385 goto LCleanup;
386 }
387
388 hr = system_device_containerp->GetNumberOfChildContainers(&num_devices);
389 if (FAILED(hr))
390 {
391 goto LCleanup;
392 }
393
394 llinfos << "DX9 iterating over devices" << llendl;
395 S32 device_num = 0;
396 for (device_num = 0; device_num < (S32)num_devices; device_num++)
397 {
398 hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256);
399 if (FAILED(hr))
400 {
401 goto LCleanup;
402 }
403
404 hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp);
405 if (FAILED(hr) || device_containerp == NULL)
406 {
407 goto LCleanup;
408 }
409
410 std::string device_name = get_string(device_containerp, L"szDescription");
411 std::string device_id = get_string(device_containerp, L"szDeviceID");
412
413 LLDXDevice *dxdevicep = new LLDXDevice;
414 dxdevicep->mName = device_name;
415 dxdevicep->mPCIString = device_id;
416 mDevices[dxdevicep->mPCIString] = dxdevicep;
417
418 // Split the PCI string based on vendor, device, subsys, rev.
419 std::string str(device_id);
420 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
421 boost::char_separator<char> sep("&\\", "", boost::keep_empty_tokens);
422 tokenizer tokens(str, sep);
423
424 tokenizer::iterator iter = tokens.begin();
425 S32 count = 0;
426 BOOL valid = TRUE;
427 for (;(iter != tokens.end()) && (count < 3);++iter)
428 {
429 switch (count)
430 {
431 case 0:
432 if (strcmp(iter->c_str(), "PCI"))
433 {
434 valid = FALSE;
435 }
436 break;
437 case 1:
438 dxdevicep->mVendorID = iter->c_str();
439 break;
440 case 2:
441 dxdevicep->mDeviceID = iter->c_str();
442 break;
443 default:
444 // Ignore it
445 break;
446 }
447 count++;
448 }
449
450
451 // Now, iterate through the related drivers
452 hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp);
453 if (FAILED(hr) || !driver_containerp)
454 {
455 goto LCleanup;
456 }
457
458 DWORD num_files = 0;
459 hr = driver_containerp->GetNumberOfChildContainers(&num_files);
460 if (FAILED(hr))
461 {
462 goto LCleanup;
463 }
464
465 S32 file_num = 0;
466 for (file_num = 0; file_num < (S32)num_files; file_num++ )
467 {
468 hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256);
469 if (FAILED(hr))
470 {
471 goto LCleanup;
472 }
473
474 hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp);
475 if (FAILED(hr) || file_containerp == NULL)
476 {
477 goto LCleanup;
478 }
479
480 std::string driver_path = get_string(file_containerp, L"szPath");
481 std::string driver_name = get_string(file_containerp, L"szName");
482 std::string driver_version = get_string(file_containerp, L"szVersion");
483 std::string driver_date = get_string(file_containerp, L"szDatestampEnglish");
484
485 LLDXDriverFile *dxdriverfilep = new LLDXDriverFile;
486 dxdriverfilep->mName = driver_name;
487 dxdriverfilep->mFilepath= driver_path;
488 dxdriverfilep->mVersionString = driver_version;
489 dxdriverfilep->mVersion.set(driver_version);
490 dxdriverfilep->mDateString = driver_date;
491
492 dxdevicep->mDriverFiles[driver_name] = dxdriverfilep;
493
494 SAFE_RELEASE(file_containerp);
495 }
496 SAFE_RELEASE(device_containerp);
497 }
498 }
499
500 dumpDevices();
501 ok = TRUE;
502
503LCleanup:
504 if (!ok)
505 {
506 llwarns << "DX9 probe failed" << llendl;
507 gWriteDebug("DX9 probe failed\n");
508 }
509
510 SAFE_RELEASE(file_containerp);
511 SAFE_RELEASE(driver_containerp);
512 SAFE_RELEASE(device_containerp);
513 SAFE_RELEASE(devices_containerp);
514 SAFE_RELEASE(dx_diag_rootp);
515 SAFE_RELEASE(dx_diag_providerp);
516
517 CoUninitialize();
518
519 return ok;
520}
521
522void LLDXHardware::setWriteDebugFunc(void (*func)(const char*))
523{
524 gWriteDebug = func;
525}
526
527#endif