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