lldxhardware.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /**
  2. * @file lldxhardware.cpp
  3. * @brief LLDXHardware implementation
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #ifdef LL_WINDOWS
  33. // Culled from some Microsoft sample code
  34. #include "linden_common.h"
  35. #include <combaseapi.h> // For IID_PPV_ARGS()
  36. #define INITGUID
  37. #include <dxdiag.h>
  38. #undef INITGUID
  39. #include <dxgi.h>
  40. #include <stdlib.h> // For getenv()
  41. #include <wbemidl.h>
  42. #include "lldxhardware.h"
  43. void (*gWriteDebug)(const char* msg) = NULL;
  44. LLDXHardware gDXHardware;
  45. #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } }
  46. static void get_wstring(IDxDiagContainer* containerp, WCHAR* prop_name,
  47. WCHAR* prop_value, int output_size)
  48. {
  49. VARIANT var;
  50. VariantInit(&var);
  51. HRESULT hr = containerp->GetProp(prop_name, &var);
  52. if (SUCCEEDED(hr))
  53. {
  54. // Switch off the type. There's 4 different types:
  55. switch (var.vt)
  56. {
  57. case VT_UI4:
  58. swprintf(prop_value, L"%d", var.ulVal);
  59. break;
  60. case VT_I4:
  61. swprintf(prop_value, L"%d", var.lVal);
  62. break;
  63. case VT_BOOL:
  64. wcscpy(prop_value, var.boolVal ? L"true" : L"false");
  65. break;
  66. case VT_BSTR:
  67. wcsncpy(prop_value, var.bstrVal, output_size - 1);
  68. prop_value[output_size - 1] = 0;
  69. break;
  70. }
  71. }
  72. // Clear the variant (this is needed to free BSTR memory)
  73. VariantClear(&var);
  74. }
  75. static std::string get_string(IDxDiagContainer* containerp, WCHAR* prop_name)
  76. {
  77. WCHAR prop_value[256];
  78. get_wstring(containerp, prop_name, prop_value, 256);
  79. return ll_convert_wide_to_string(prop_value);
  80. }
  81. //static
  82. S32 LLDXHardware::getMBVideoMemoryViaDXGI()
  83. {
  84. // Let the user override the detection in case it fails on their system.
  85. // They can specify the amount of VRAM in megabytes, via the LL_VRAM_MB
  86. // environment variable. HB
  87. char* vram_override = getenv("LL_VRAM_MB");
  88. if (vram_override)
  89. {
  90. S32 vram = atoi(vram_override);
  91. if (vram > 0)
  92. {
  93. llinfos << "Amount of VRAM overridden via the LL_VRAM_MB environment variable; detection step skipped. VRAM amount: "
  94. << vram << "MB" << llendl;
  95. return vram;
  96. }
  97. }
  98. SIZE_T vram = 0;
  99. if (SUCCEEDED(CoInitialize(0)))
  100. {
  101. IDXGIFactory1* factoryp = NULL;
  102. HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&factoryp));
  103. if (SUCCEEDED(hr))
  104. {
  105. IDXGIAdapter1* adapterp = NULL;
  106. IDXGIAdapter1* tmp_adapterp = NULL;
  107. DXGI_ADAPTER_DESC1 desc;
  108. UINT idx = 0;
  109. while (factoryp->EnumAdapters1(idx++, &tmp_adapterp) !=
  110. DXGI_ERROR_NOT_FOUND)
  111. {
  112. if (!tmp_adapterp) // Should not happen.
  113. {
  114. break;
  115. }
  116. hr = tmp_adapterp->GetDesc1(&desc);
  117. if (SUCCEEDED(hr) && desc.Flags == 0)
  118. {
  119. tmp_adapterp->QueryInterface(IID_PPV_ARGS(&adapterp));
  120. if (adapterp)
  121. {
  122. adapterp->GetDesc1(&desc);
  123. if (desc.DedicatedVideoMemory > vram)
  124. {
  125. vram = desc.DedicatedVideoMemory;
  126. }
  127. SAFE_RELEASE(adapterp);
  128. }
  129. }
  130. SAFE_RELEASE(tmp_adapterp);
  131. }
  132. SAFE_RELEASE(factoryp);
  133. }
  134. CoUninitialize();
  135. }
  136. return vram / (1024 * 1024);
  137. }
  138. LLSD LLDXHardware::getDisplayInfo()
  139. {
  140. if (mInfo.size())
  141. {
  142. return mInfo;
  143. }
  144. HRESULT hr = CoInitialize(NULL);
  145. if (FAILED(hr))
  146. {
  147. llwarns << "COM library initialization failed !" << llendl;
  148. gWriteDebug("COM library initialization failed !\n");
  149. return mInfo;
  150. }
  151. IDxDiagProvider* dx_diag_providerp = NULL;
  152. IDxDiagContainer* dx_diag_rootp = NULL;
  153. IDxDiagContainer* devices_containerp = NULL;
  154. IDxDiagContainer* device_containerp = NULL;
  155. IDxDiagContainer* file_containerp = NULL;
  156. IDxDiagContainer* driver_containerp = NULL;
  157. // CoCreate a IDxDiagProvider*
  158. llinfos << "CoCreateInstance IID_IDxDiagProvider" << llendl;
  159. hr = CoCreateInstance(CLSID_DxDiagProvider, NULL, CLSCTX_INPROC_SERVER,
  160. IID_IDxDiagProvider, (LPVOID*)&dx_diag_providerp);
  161. if (FAILED(hr))
  162. {
  163. llwarns << "No DXDiag provider found ! DirectX not installed !"
  164. << llendl;
  165. gWriteDebug("No DXDiag provider found ! DirectX not installed !\n");
  166. goto exit_cleanup;
  167. }
  168. if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed
  169. {
  170. // Fill out a DXDIAG_INIT_PARAMS struct and pass it to
  171. // IDxDiagContainer::Initialize(). Passing in TRUE for bAllowWHQLChecks
  172. // allows dxdiag to check if drivers are digital signed as logo'd by
  173. // WHQL which may connect via internet to update WHQL certificates.
  174. DXDIAG_INIT_PARAMS dx_diag_init_params;
  175. ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS));
  176. dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS);
  177. dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
  178. dx_diag_init_params.bAllowWHQLChecks = TRUE;
  179. dx_diag_init_params.pReserved = NULL;
  180. LL_DEBUGS("AppInit") << "dx_diag_providerp->Initialize" << LL_ENDL;
  181. hr = dx_diag_providerp->Initialize(&dx_diag_init_params);
  182. if (FAILED(hr))
  183. {
  184. goto exit_cleanup;
  185. }
  186. LL_DEBUGS("AppInit") << "dx_diag_providerp->GetRootContainer"
  187. << LL_ENDL;
  188. hr = dx_diag_providerp->GetRootContainer(&dx_diag_rootp);
  189. if (FAILED(hr) || !dx_diag_rootp)
  190. {
  191. goto exit_cleanup;
  192. }
  193. HRESULT hr;
  194. // Get display driver information
  195. LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer" << LL_ENDL;
  196. hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices",
  197. &devices_containerp);
  198. if (FAILED(hr) || !devices_containerp)
  199. {
  200. // Do not release 'dirty' devices_containerp at this stage, only
  201. // dx_diag_rootp
  202. devices_containerp = NULL;
  203. goto exit_cleanup;
  204. }
  205. DWORD dw_device_count;
  206. // Make sure there is something inside
  207. hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count);
  208. if (FAILED(hr) || dw_device_count == 0)
  209. {
  210. goto exit_cleanup;
  211. }
  212. // Get device 0
  213. LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer"
  214. << LL_ENDL;
  215. hr = devices_containerp->GetChildContainer(L"0", &device_containerp);
  216. if (FAILED(hr) || !device_containerp)
  217. {
  218. goto exit_cleanup;
  219. }
  220. // Get the English VRAM string
  221. std::string ram_str = get_string(device_containerp,
  222. L"szDisplayMemoryEnglish");
  223. // Dump the string as an int into the structure
  224. char* stopstring;
  225. mInfo["VRAM"] = S32(strtol(ram_str.c_str(),
  226. &stopstring, 10) / (1024 * 1024));
  227. std::string device_name = get_string(device_containerp,
  228. L"szDescription");
  229. mInfo["DeviceName"] = device_name;
  230. std::string device_driver= get_string(device_containerp,
  231. L"szDriverVersion");
  232. mInfo["DriverVersion"] = device_driver;
  233. // ATI has a slightly different version string
  234. if (device_name.length() >= 4 && device_name.substr(0, 4) == "ATI ")
  235. {
  236. // Get the key
  237. HKEY hKey;
  238. const DWORD RV_SIZE = 100;
  239. WCHAR release_version[RV_SIZE];
  240. // Hard coded registry entry. Using this since it is simpler for
  241. // now. And using EnumDisplayDevices to get a registry key also
  242. // requires a hard coded Query value.
  243. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE,
  244. TEXT("SOFTWARE\\ATI Technologies\\CBT"),
  245. &hKey))
  246. {
  247. // Get the value
  248. DWORD dwType = REG_SZ;
  249. DWORD dwSize = sizeof(WCHAR) * RV_SIZE;
  250. if (ERROR_SUCCESS == RegQueryValueEx(hKey,
  251. TEXT("ReleaseVersion"),
  252. NULL, &dwType,
  253. (LPBYTE)release_version,
  254. &dwSize))
  255. {
  256. // Print the value; Windows does not guarantee to be nul
  257. // terminated
  258. release_version[RV_SIZE - 1] = 0;
  259. mInfo["DriverVersion"] =
  260. ll_convert_wide_to_string(release_version);
  261. }
  262. RegCloseKey(hKey);
  263. }
  264. }
  265. }
  266. exit_cleanup:
  267. if (!mInfo.size())
  268. {
  269. llinfos << "Failed to get data, cleaning up..." << llendl;
  270. }
  271. SAFE_RELEASE(file_containerp);
  272. SAFE_RELEASE(driver_containerp);
  273. SAFE_RELEASE(device_containerp);
  274. SAFE_RELEASE(devices_containerp);
  275. SAFE_RELEASE(dx_diag_rootp);
  276. SAFE_RELEASE(dx_diag_providerp);
  277. CoUninitialize();
  278. return mInfo;
  279. }
  280. #endif