diff options
Diffstat (limited to 'linden/indra/llwindow/lldxhardware.cpp')
-rw-r--r-- | linden/indra/llwindow/lldxhardware.cpp | 527 |
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 | |||
45 | void (*gWriteDebug)(const char* msg) = NULL; | ||
46 | LLDXHardware 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 | |||
55 | std::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 | |||
90 | LLVersion::LLVersion() | ||
91 | { | ||
92 | mValid = FALSE; | ||
93 | S32 i; | ||
94 | for (i = 0; i < 4; i++) | ||
95 | { | ||
96 | mFields[i] = 0; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | BOOL 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 | |||
136 | S32 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 | |||
148 | LLString 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 | |||
170 | LLDXDevice::~LLDXDevice() | ||
171 | { | ||
172 | for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer()); | ||
173 | } | ||
174 | |||
175 | std::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 | |||
207 | LLDXDriverFile *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 | |||
223 | LLDXHardware::LLDXHardware() | ||
224 | { | ||
225 | mVRAM = 0; | ||
226 | gWriteDebug = NULL; | ||
227 | } | ||
228 | |||
229 | void LLDXHardware::cleanup() | ||
230 | { | ||
231 | for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer()); | ||
232 | } | ||
233 | |||
234 | LLString 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 | |||
255 | LLDXDevice *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 | |||
283 | BOOL 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 | |||
503 | LCleanup: | ||
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 | |||
522 | void LLDXHardware::setWriteDebugFunc(void (*func)(const char*)) | ||
523 | { | ||
524 | gWriteDebug = func; | ||
525 | } | ||
526 | |||
527 | #endif | ||