OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/gpu/gpu_info_collector.h" | 5 #include "content/gpu/gpu_info_collector.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <d3d9.h> | 8 #include <d3d9.h> |
9 #include <setupapi.h> | 9 #include <setupapi.h> |
10 | 10 |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 #if !defined(GOOGLE_CHROME_BUILD) | 164 #if !defined(GOOGLE_CHROME_BUILD) |
165 AMDVideoCardType GetAMDVideocardType() { | 165 AMDVideoCardType GetAMDVideocardType() { |
166 return UNKNOWN; | 166 return UNKNOWN; |
167 } | 167 } |
168 #else | 168 #else |
169 // This function has a real implementation for official builds that can | 169 // This function has a real implementation for official builds that can |
170 // be found in src/third_party/amd. | 170 // be found in src/third_party/amd. |
171 AMDVideoCardType GetAMDVideocardType(); | 171 AMDVideoCardType GetAMDVideocardType(); |
172 #endif | 172 #endif |
173 | 173 |
174 bool CollectGraphicsInfo(content::GPUInfo* gpu_info) { | 174 bool CollectDriverInfoD3D(const std::wstring& device_id, |
| 175 content::GPUInfo* gpu_info) { |
| 176 TRACE_EVENT0("gpu", "CollectDriverInfoD3D"); |
| 177 |
| 178 // create device info for the display device |
| 179 HDEVINFO device_info = SetupDiGetClassDevsW( |
| 180 NULL, device_id.c_str(), NULL, |
| 181 DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES); |
| 182 if (device_info == INVALID_HANDLE_VALUE) { |
| 183 LOG(ERROR) << "Creating device info failed"; |
| 184 return false; |
| 185 } |
| 186 |
| 187 DWORD index = 0; |
| 188 bool found = false; |
| 189 SP_DEVINFO_DATA device_info_data; |
| 190 device_info_data.cbSize = sizeof(device_info_data); |
| 191 while (SetupDiEnumDeviceInfo(device_info, index++, &device_info_data)) { |
| 192 WCHAR value[255]; |
| 193 if (SetupDiGetDeviceRegistryPropertyW(device_info, |
| 194 &device_info_data, |
| 195 SPDRP_DRIVER, |
| 196 NULL, |
| 197 reinterpret_cast<PBYTE>(value), |
| 198 sizeof(value), |
| 199 NULL)) { |
| 200 HKEY key; |
| 201 std::wstring driver_key = L"System\\CurrentControlSet\\Control\\Class\\"; |
| 202 driver_key += value; |
| 203 LONG result = RegOpenKeyExW( |
| 204 HKEY_LOCAL_MACHINE, driver_key.c_str(), 0, KEY_QUERY_VALUE, &key); |
| 205 if (result == ERROR_SUCCESS) { |
| 206 DWORD dwcb_data = sizeof(value); |
| 207 std::string driver_version; |
| 208 result = RegQueryValueExW( |
| 209 key, L"DriverVersion", NULL, NULL, |
| 210 reinterpret_cast<LPBYTE>(value), &dwcb_data); |
| 211 if (result == ERROR_SUCCESS) |
| 212 driver_version = WideToASCII(std::wstring(value)); |
| 213 |
| 214 std::string driver_date; |
| 215 dwcb_data = sizeof(value); |
| 216 result = RegQueryValueExW( |
| 217 key, L"DriverDate", NULL, NULL, |
| 218 reinterpret_cast<LPBYTE>(value), &dwcb_data); |
| 219 if (result == ERROR_SUCCESS) |
| 220 driver_date = WideToASCII(std::wstring(value)); |
| 221 |
| 222 std::string driver_vendor; |
| 223 dwcb_data = sizeof(value); |
| 224 result = RegQueryValueExW( |
| 225 key, L"ProviderName", NULL, NULL, |
| 226 reinterpret_cast<LPBYTE>(value), &dwcb_data); |
| 227 if (result == ERROR_SUCCESS) { |
| 228 driver_vendor = WideToASCII(std::wstring(value)); |
| 229 if (driver_vendor == "Advanced Micro Devices, Inc." || |
| 230 driver_vendor == "ATI Technologies Inc.") { |
| 231 // We are conservative and assume that in the absence of a clear |
| 232 // signal the videocard is assumed to be switchable. Additionally, |
| 233 // some switchable systems with Intel GPUs aren't correctly |
| 234 // detected, so always count them. |
| 235 AMDVideoCardType amd_card_type = GetAMDVideocardType(); |
| 236 gpu_info->amd_switchable = (gpu_info->gpu.vendor_id == 0x8086) || |
| 237 (amd_card_type != STANDALONE); |
| 238 } |
| 239 } |
| 240 |
| 241 gpu_info->driver_vendor = driver_vendor; |
| 242 gpu_info->driver_version = driver_version; |
| 243 gpu_info->driver_date = driver_date; |
| 244 found = true; |
| 245 RegCloseKey(key); |
| 246 break; |
| 247 } |
| 248 } |
| 249 } |
| 250 SetupDiDestroyDeviceInfoList(device_info); |
| 251 return found; |
| 252 } |
| 253 |
| 254 bool CollectContextGraphicsInfo(content::GPUInfo* gpu_info) { |
175 TRACE_EVENT0("gpu", "CollectGraphicsInfo"); | 255 TRACE_EVENT0("gpu", "CollectGraphicsInfo"); |
176 | 256 |
177 DCHECK(gpu_info); | 257 DCHECK(gpu_info); |
178 *gpu_info = content::GPUInfo(); | |
179 | |
180 gpu_info->performance_stats = RetrieveGpuPerformanceStats(); | |
181 | 258 |
182 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) { | 259 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) { |
183 std::string requested_implementation_name = | 260 std::string requested_implementation_name = |
184 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL); | 261 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL); |
185 if (requested_implementation_name == "swiftshader") { | 262 if (requested_implementation_name == "swiftshader") { |
186 gpu_info->software_rendering = true; | 263 gpu_info->software_rendering = true; |
187 return false; | 264 return false; |
188 } | 265 } |
189 } | 266 } |
190 | 267 |
(...skipping 17 matching lines...) Expand all Loading... |
208 LOG(ERROR) << "display->getDevice() failed"; | 285 LOG(ERROR) << "display->getDevice() failed"; |
209 return false; | 286 return false; |
210 } | 287 } |
211 | 288 |
212 base::win::ScopedComPtr<IDirect3D9> d3d; | 289 base::win::ScopedComPtr<IDirect3D9> d3d; |
213 if (FAILED(device->GetDirect3D(d3d.Receive()))) { | 290 if (FAILED(device->GetDirect3D(d3d.Receive()))) { |
214 LOG(ERROR) << "device->GetDirect3D(&d3d) failed"; | 291 LOG(ERROR) << "device->GetDirect3D(&d3d) failed"; |
215 return false; | 292 return false; |
216 } | 293 } |
217 | 294 |
218 if (!CollectGraphicsInfoD3D(d3d, gpu_info)) | 295 // Get can_lose_context |
219 return false; | 296 base::win::ScopedComPtr<IDirect3D9Ex> d3dex; |
220 | 297 if (SUCCEEDED(d3dex.QueryFrom(d3d))) |
221 // DirectX diagnostics are collected asynchronously because it takes a | 298 gpu_info->can_lose_context = false; |
222 // couple of seconds. Do not mark gpu_info as complete until that is done. | 299 else |
223 return true; | 300 gpu_info->can_lose_context = true; |
224 } | |
225 | |
226 bool CollectPreliminaryGraphicsInfo(content::GPUInfo* gpu_info) { | |
227 TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo"); | |
228 | |
229 DCHECK(gpu_info); | |
230 | |
231 bool rt = true; | |
232 if (!CollectVideoCardInfo(gpu_info)) | |
233 rt = false; | |
234 | |
235 gpu_info->performance_stats = RetrieveGpuPerformanceStatsWithHistograms(); | |
236 | |
237 return rt; | |
238 } | |
239 | |
240 bool CollectGraphicsInfoD3D(IDirect3D9* d3d, content::GPUInfo* gpu_info) { | |
241 TRACE_EVENT0("gpu", "CollectGraphicsInfoD3D"); | |
242 | |
243 DCHECK(d3d); | |
244 DCHECK(gpu_info); | |
245 | |
246 bool succeed = CollectVideoCardInfo(gpu_info); | |
247 | 301 |
248 // Get version information | 302 // Get version information |
249 D3DCAPS9 d3d_caps; | 303 D3DCAPS9 d3d_caps; |
250 if (d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, | 304 if (d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, |
251 D3DDEVTYPE_HAL, | 305 D3DDEVTYPE_HAL, |
252 &d3d_caps) == D3D_OK) { | 306 &d3d_caps) == D3D_OK) { |
253 gpu_info->pixel_shader_version = | 307 gpu_info->pixel_shader_version = |
254 VersionNumberToString(d3d_caps.PixelShaderVersion); | 308 VersionNumberToString(d3d_caps.PixelShaderVersion); |
255 gpu_info->vertex_shader_version = | 309 gpu_info->vertex_shader_version = |
256 VersionNumberToString(d3d_caps.VertexShaderVersion); | 310 VersionNumberToString(d3d_caps.VertexShaderVersion); |
257 } else { | 311 } else { |
258 LOG(ERROR) << "d3d->GetDeviceCaps() failed"; | 312 LOG(ERROR) << "d3d->GetDeviceCaps() failed"; |
259 succeed = false; | 313 return false; |
260 } | 314 } |
261 | 315 |
262 // Get can_lose_context | 316 // DirectX diagnostics are collected asynchronously because it takes a |
263 base::win::ScopedComPtr<IDirect3D9Ex> d3dex; | 317 // couple of seconds. Do not mark gpu_info as complete until that is done. |
264 if (SUCCEEDED(d3dex.QueryFrom(d3d))) | |
265 gpu_info->can_lose_context = false; | |
266 else | |
267 gpu_info->can_lose_context = true; | |
268 | |
269 return true; | 318 return true; |
270 } | 319 } |
271 | 320 |
272 bool CollectVideoCardInfo(content::GPUInfo* gpu_info) { | 321 bool CollectBasicGraphicsInfo(content::GPUInfo* gpu_info) { |
273 TRACE_EVENT0("gpu", "CollectVideoCardInfo"); | 322 TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo"); |
274 | 323 |
275 DCHECK(gpu_info); | 324 DCHECK(gpu_info); |
276 | 325 |
| 326 gpu_info->performance_stats = RetrieveGpuPerformanceStatsWithHistograms(); |
| 327 |
277 // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled. | 328 // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled. |
278 HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll"); | 329 HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll"); |
279 gpu_info->optimus = nvd3d9wrap != NULL; | 330 gpu_info->optimus = nvd3d9wrap != NULL; |
280 | 331 |
281 // Taken from http://developer.nvidia.com/object/device_ids.html | 332 // Taken from http://developer.nvidia.com/object/device_ids.html |
282 DISPLAY_DEVICE dd; | 333 DISPLAY_DEVICE dd; |
283 dd.cb = sizeof(DISPLAY_DEVICE); | 334 dd.cb = sizeof(DISPLAY_DEVICE); |
284 int i = 0; | 335 int i = 0; |
285 std::wstring id; | 336 std::wstring id; |
286 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) { | 337 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) { |
(...skipping 10 matching lines...) Expand all Loading... |
297 base::HexStringToInt(WideToASCII(vendor_id_string), &vendor_id); | 348 base::HexStringToInt(WideToASCII(vendor_id_string), &vendor_id); |
298 base::HexStringToInt(WideToASCII(device_id_string), &device_id); | 349 base::HexStringToInt(WideToASCII(device_id_string), &device_id); |
299 gpu_info->gpu.vendor_id = vendor_id; | 350 gpu_info->gpu.vendor_id = vendor_id; |
300 gpu_info->gpu.device_id = device_id; | 351 gpu_info->gpu.device_id = device_id; |
301 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE. | 352 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE. |
302 return CollectDriverInfoD3D(id, gpu_info); | 353 return CollectDriverInfoD3D(id, gpu_info); |
303 } | 354 } |
304 return false; | 355 return false; |
305 } | 356 } |
306 | 357 |
307 bool CollectDriverInfoD3D(const std::wstring& device_id, | |
308 content::GPUInfo* gpu_info) { | |
309 TRACE_EVENT0("gpu", "CollectDriverInfoD3D"); | |
310 | |
311 // create device info for the display device | |
312 HDEVINFO device_info = SetupDiGetClassDevsW( | |
313 NULL, device_id.c_str(), NULL, | |
314 DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES); | |
315 if (device_info == INVALID_HANDLE_VALUE) { | |
316 LOG(ERROR) << "Creating device info failed"; | |
317 return false; | |
318 } | |
319 | |
320 DWORD index = 0; | |
321 bool found = false; | |
322 SP_DEVINFO_DATA device_info_data; | |
323 device_info_data.cbSize = sizeof(device_info_data); | |
324 while (SetupDiEnumDeviceInfo(device_info, index++, &device_info_data)) { | |
325 WCHAR value[255]; | |
326 if (SetupDiGetDeviceRegistryPropertyW(device_info, | |
327 &device_info_data, | |
328 SPDRP_DRIVER, | |
329 NULL, | |
330 reinterpret_cast<PBYTE>(value), | |
331 sizeof(value), | |
332 NULL)) { | |
333 HKEY key; | |
334 std::wstring driver_key = L"System\\CurrentControlSet\\Control\\Class\\"; | |
335 driver_key += value; | |
336 LONG result = RegOpenKeyExW( | |
337 HKEY_LOCAL_MACHINE, driver_key.c_str(), 0, KEY_QUERY_VALUE, &key); | |
338 if (result == ERROR_SUCCESS) { | |
339 DWORD dwcb_data = sizeof(value); | |
340 std::string driver_version; | |
341 result = RegQueryValueExW( | |
342 key, L"DriverVersion", NULL, NULL, | |
343 reinterpret_cast<LPBYTE>(value), &dwcb_data); | |
344 if (result == ERROR_SUCCESS) | |
345 driver_version = WideToASCII(std::wstring(value)); | |
346 | |
347 std::string driver_date; | |
348 dwcb_data = sizeof(value); | |
349 result = RegQueryValueExW( | |
350 key, L"DriverDate", NULL, NULL, | |
351 reinterpret_cast<LPBYTE>(value), &dwcb_data); | |
352 if (result == ERROR_SUCCESS) | |
353 driver_date = WideToASCII(std::wstring(value)); | |
354 | |
355 std::string driver_vendor; | |
356 dwcb_data = sizeof(value); | |
357 result = RegQueryValueExW( | |
358 key, L"ProviderName", NULL, NULL, | |
359 reinterpret_cast<LPBYTE>(value), &dwcb_data); | |
360 if (result == ERROR_SUCCESS) { | |
361 driver_vendor = WideToASCII(std::wstring(value)); | |
362 if (driver_vendor == "Advanced Micro Devices, Inc." || | |
363 driver_vendor == "ATI Technologies Inc.") { | |
364 // We are conservative and assume that in the absence of a clear | |
365 // signal the videocard is assumed to be switchable. Additionally, | |
366 // some switchable systems with Intel GPUs aren't correctly | |
367 // detected, so always count them. | |
368 AMDVideoCardType amd_card_type = GetAMDVideocardType(); | |
369 gpu_info->amd_switchable = (gpu_info->gpu.vendor_id == 0x8086) || | |
370 (amd_card_type != STANDALONE); | |
371 } | |
372 } | |
373 | |
374 gpu_info->driver_vendor = driver_vendor; | |
375 gpu_info->driver_version = driver_version; | |
376 gpu_info->driver_date = driver_date; | |
377 found = true; | |
378 RegCloseKey(key); | |
379 break; | |
380 } | |
381 } | |
382 } | |
383 SetupDiDestroyDeviceInfoList(device_info); | |
384 return found; | |
385 } | |
386 | |
387 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) { | 358 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) { |
388 TRACE_EVENT0("gpu", "CollectDriverInfoGL"); | 359 TRACE_EVENT0("gpu", "CollectDriverInfoGL"); |
389 | 360 |
390 DCHECK(gpu_info); | 361 DCHECK(gpu_info); |
391 | 362 |
392 std::string gl_version_string = gpu_info->gl_version_string; | 363 std::string gl_version_string = gpu_info->gl_version_string; |
393 | 364 |
394 // TODO(zmo): We assume the driver version is in the end of GL_VERSION | 365 // TODO(zmo): We assume the driver version is in the end of GL_VERSION |
395 // string. Need to verify if it is true for majority drivers. | 366 // string. Need to verify if it is true for majority drivers. |
396 | 367 |
397 size_t pos = gl_version_string.find_last_not_of("0123456789."); | 368 size_t pos = gl_version_string.find_last_not_of("0123456789."); |
398 if (pos != std::string::npos && pos < gl_version_string.length() - 1) { | 369 if (pos != std::string::npos && pos < gl_version_string.length() - 1) { |
399 gpu_info->driver_version = gl_version_string.substr(pos + 1); | 370 gpu_info->driver_version = gl_version_string.substr(pos + 1); |
400 return true; | 371 return true; |
401 } | 372 } |
402 return false; | 373 return false; |
403 } | 374 } |
404 | 375 |
| 376 void MergeGPUInfo(content::GPUInfo* basic_gpu_info, |
| 377 const content::GPUInfo& context_gpu_info) { |
| 378 DCHECK(basic_gpu_info); |
| 379 |
| 380 if (context_gpu_info.software_rendering) { |
| 381 basic_gpu_info->software_rendering = true; |
| 382 return; |
| 383 } |
| 384 |
| 385 if (!context_gpu_info.gl_vendor.empty()) { |
| 386 MergeGPUInfoGL(basic_gpu_info, context_gpu_info); |
| 387 return; |
| 388 } |
| 389 |
| 390 basic_gpu_info->pixel_shader_version = |
| 391 context_gpu_info.pixel_shader_version; |
| 392 basic_gpu_info->vertex_shader_version = |
| 393 context_gpu_info.vertex_shader_version; |
| 394 |
| 395 basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics; |
| 396 |
| 397 basic_gpu_info->can_lose_context = context_gpu_info.can_lose_context; |
| 398 basic_gpu_info->sandboxed = context_gpu_info.sandboxed; |
| 399 basic_gpu_info->gpu_accessible = context_gpu_info.gpu_accessible; |
| 400 basic_gpu_info->finalized = context_gpu_info.finalized; |
| 401 basic_gpu_info->initialization_time = context_gpu_info.initialization_time; |
| 402 } |
| 403 |
405 } // namespace gpu_info_collector | 404 } // namespace gpu_info_collector |
OLD | NEW |