blob: 35ab7c0f60b4a43cf791a65a0c61402914379c3d [file] [log] [blame]
[email protected]623c0bd2011-03-12 01:00:411// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]1bf14bc2010-07-09 16:10:432// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]623c0bd2011-03-12 01:00:415#include "content/gpu/gpu_info_collector.h"
[email protected]1bf14bc2010-07-09 16:10:436
[email protected]1bf14bc2010-07-09 16:10:437#include <d3d9.h>
[email protected]766653092011-03-01 16:45:238#include <setupapi.h>
9#include <windows.h>
[email protected]1bf14bc2010-07-09 16:10:4310
[email protected]4bce24e2010-09-07 20:45:0111#include "app/gfx/gl/gl_context_egl.h"
12#include "app/gfx/gl/gl_implementation.h"
[email protected]864b1362010-08-19 03:49:3813#include "base/file_path.h"
[email protected]dfb26432011-02-24 21:03:0314#include "base/logging.h"
[email protected]1bf14bc2010-07-09 16:10:4315#include "base/scoped_native_library.h"
[email protected]7004d7eb2011-01-21 00:27:5316#include "base/string_number_conversions.h"
[email protected]1bf14bc2010-07-09 16:10:4317#include "base/string_util.h"
18
[email protected]4bce24e2010-09-07 20:45:0119// ANGLE seems to require that main.h be included before any other ANGLE header.
20#include "libEGL/main.h"
21#include "libEGL/Display.h"
22
[email protected]766653092011-03-01 16:45:2323// Setup API functions
24typedef HDEVINFO (WINAPI*SetupDiGetClassDevsWFunc)(
25 CONST GUID *ClassGuid,
26 PCWSTR Enumerator,
27 HWND hwndParent,
28 DWORD Flags
29);
30typedef BOOL (WINAPI*SetupDiEnumDeviceInfoFunc)(
31 HDEVINFO DeviceInfoSet,
32 DWORD MemberIndex,
33 PSP_DEVINFO_DATA DeviceInfoData
34);
35typedef BOOL (WINAPI*SetupDiGetDeviceRegistryPropertyWFunc)(
36 HDEVINFO DeviceInfoSet,
37 PSP_DEVINFO_DATA DeviceInfoData,
38 DWORD Property,
39 PDWORD PropertyRegDataType,
40 PBYTE PropertyBuffer,
41 DWORD PropertyBufferSize,
42 PDWORD RequiredSize
43);
44typedef BOOL (WINAPI*SetupDiDestroyDeviceInfoListFunc)(
45 HDEVINFO DeviceInfoSet
46);
47
[email protected]1bf14bc2010-07-09 16:10:4348namespace gpu_info_collector {
49
[email protected]4bce24e2010-09-07 20:45:0150bool CollectGraphicsInfo(GPUInfo* gpu_info) {
[email protected]7004d7eb2011-01-21 00:27:5351 DCHECK(gpu_info);
52
53 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
[email protected]a61508e52011-03-08 17:59:4254 gpu_info->level = GPUInfo::kComplete;
[email protected]7004d7eb2011-01-21 00:27:5355 return CollectGraphicsInfoGL(gpu_info);
56 }
57
[email protected]dfb26432011-02-24 21:03:0358 // Set to partial now in case this function returns false below.
[email protected]a61508e52011-03-08 17:59:4259 gpu_info->level = GPUInfo::kPartial;
[email protected]dfb26432011-02-24 21:03:0360
[email protected]7004d7eb2011-01-21 00:27:5361 // TODO(zmo): the following code only works if running on top of ANGLE.
62 // Need to handle the case when running on top of real EGL/GLES2 drivers.
[email protected]1bf14bc2010-07-09 16:10:4363
[email protected]4bce24e2010-09-07 20:45:0164 egl::Display* display = static_cast<egl::Display*>(
65 gfx::BaseEGLContext::GetDisplay());
[email protected]dfb26432011-02-24 21:03:0366 if (!display) {
67 LOG(ERROR) << "gfx::BaseEGLContext::GetDisplay() failed";
[email protected]b60ca992010-09-20 18:57:0768 return false;
[email protected]dfb26432011-02-24 21:03:0369 }
[email protected]b60ca992010-09-20 18:57:0770
[email protected]4bce24e2010-09-07 20:45:0171 IDirect3DDevice9* device = display->getDevice();
[email protected]dfb26432011-02-24 21:03:0372 if (!device) {
73 LOG(ERROR) << "display->getDevice() failed";
[email protected]b60ca992010-09-20 18:57:0774 return false;
[email protected]dfb26432011-02-24 21:03:0375 }
[email protected]b60ca992010-09-20 18:57:0776
[email protected]4bce24e2010-09-07 20:45:0177 IDirect3D9* d3d = NULL;
[email protected]dfb26432011-02-24 21:03:0378 if (FAILED(device->GetDirect3D(&d3d))) {
79 LOG(ERROR) << "device->GetDirect3D(&d3d) failed";
[email protected]4bce24e2010-09-07 20:45:0180 return false;
[email protected]dfb26432011-02-24 21:03:0381 }
[email protected]1bf14bc2010-07-09 16:10:4382
[email protected]41579ae2010-11-15 22:31:2683 if (!CollectGraphicsInfoD3D(d3d, gpu_info))
84 return false;
[email protected]81f85b32010-10-08 18:03:2185
[email protected]41579ae2010-11-15 22:31:2686 // DirectX diagnostics are collected asynchronously because it takes a
[email protected]dfb26432011-02-24 21:03:0387 // couple of seconds. Do not mark gpu_info as complete until that is done.
[email protected]41579ae2010-11-15 22:31:2688 return true;
[email protected]1bf14bc2010-07-09 16:10:4389}
90
[email protected]079c4ad2011-02-19 00:05:5791bool CollectPreliminaryGraphicsInfo(GPUInfo* gpu_info) {
92 DCHECK(gpu_info);
93
[email protected]a61508e52011-03-08 17:59:4294 gpu_info->level = GPUInfo::kPreliminary;
[email protected]079c4ad2011-02-19 00:05:5795
96 bool rt = true;
97 if (!CollectVideoCardInfo(gpu_info))
98 rt = false;
99
100 return rt;
101}
102
[email protected]4bce24e2010-09-07 20:45:01103bool CollectGraphicsInfoD3D(IDirect3D9* d3d, GPUInfo* gpu_info) {
104 DCHECK(d3d);
105 DCHECK(gpu_info);
106
[email protected]766653092011-03-01 16:45:23107 bool succeed = CollectVideoCardInfo(gpu_info);
[email protected]1bf14bc2010-07-09 16:10:43108
109 // Get version information
110 D3DCAPS9 d3d_caps;
[email protected]7004d7eb2011-01-21 00:27:53111 if (d3d->GetDeviceCaps(D3DADAPTER_DEFAULT,
112 D3DDEVTYPE_HAL,
113 &d3d_caps) == D3D_OK) {
[email protected]a61508e52011-03-08 17:59:42114 gpu_info->pixel_shader_version = d3d_caps.PixelShaderVersion;
115 gpu_info->vertex_shader_version = d3d_caps.VertexShaderVersion;
[email protected]7004d7eb2011-01-21 00:27:53116 } else {
[email protected]dfb26432011-02-24 21:03:03117 LOG(ERROR) << "d3d->GetDeviceCaps() failed";
[email protected]7004d7eb2011-01-21 00:27:53118 succeed = false;
[email protected]1bf14bc2010-07-09 16:10:43119 }
[email protected]4bce24e2010-09-07 20:45:01120
[email protected]7004d7eb2011-01-21 00:27:53121 // Get can_lose_context
[email protected]4bce24e2010-09-07 20:45:01122 bool can_lose_context = false;
123 IDirect3D9Ex* d3dex = NULL;
124 if (SUCCEEDED(d3d->QueryInterface(__uuidof(IDirect3D9Ex),
125 reinterpret_cast<void**>(&d3dex)))) {
126 d3dex->Release();
127 } else {
128 can_lose_context = true;
129 }
[email protected]a61508e52011-03-08 17:59:42130 gpu_info->can_lose_context = can_lose_context;
[email protected]4bce24e2010-09-07 20:45:01131
[email protected]1bf14bc2010-07-09 16:10:43132 d3d->Release();
[email protected]1bf14bc2010-07-09 16:10:43133 return true;
134}
135
[email protected]7004d7eb2011-01-21 00:27:53136bool CollectVideoCardInfo(GPUInfo* gpu_info) {
137 DCHECK(gpu_info);
138
[email protected]1bf14bc2010-07-09 16:10:43139 // Taken from http://developer.nvidia.com/object/device_ids.html
140 DISPLAY_DEVICE dd;
141 dd.cb = sizeof(DISPLAY_DEVICE);
142 int i = 0;
143 std::wstring id;
144 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
145 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
146 id = dd.DeviceID;
147 break;
148 }
149 }
[email protected]7004d7eb2011-01-21 00:27:53150
151 if (id.length() > 20) {
152 int vendor_id = 0, device_id = 0;
153 std::wstring vendor_id_string = id.substr(8, 4);
154 std::wstring device_id_string = id.substr(17, 4);
155 base::HexStringToInt(WideToASCII(vendor_id_string), &vendor_id);
156 base::HexStringToInt(WideToASCII(device_id_string), &device_id);
[email protected]a61508e52011-03-08 17:59:42157 gpu_info->vendor_id = vendor_id;
158 gpu_info->device_id = device_id;
[email protected]93f5dcc3f2011-03-02 22:05:48159 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE.
160 return CollectDriverInfoD3D(id, gpu_info);
[email protected]1bf14bc2010-07-09 16:10:43161 }
[email protected]7004d7eb2011-01-21 00:27:53162 return false;
163}
[email protected]1bf14bc2010-07-09 16:10:43164
[email protected]766653092011-03-01 16:45:23165bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) {
166 HMODULE lib_setupapi = LoadLibraryW(L"setupapi.dll");
167 if (!lib_setupapi) {
168 LOG(ERROR) << "Open setupapi.dll failed";
169 return false;
170 }
171 SetupDiGetClassDevsWFunc fp_get_class_devs =
172 reinterpret_cast<SetupDiGetClassDevsWFunc>(
173 GetProcAddress(lib_setupapi, "SetupDiGetClassDevsW"));
174 SetupDiEnumDeviceInfoFunc fp_enum_device_info =
175 reinterpret_cast<SetupDiEnumDeviceInfoFunc>(
176 GetProcAddress(lib_setupapi, "SetupDiEnumDeviceInfo"));
177 SetupDiGetDeviceRegistryPropertyWFunc fp_get_device_registry_property =
178 reinterpret_cast<SetupDiGetDeviceRegistryPropertyWFunc>(
179 GetProcAddress(lib_setupapi, "SetupDiGetDeviceRegistryPropertyW"));
180 SetupDiDestroyDeviceInfoListFunc fp_destroy_device_info_list =
181 reinterpret_cast<SetupDiDestroyDeviceInfoListFunc>(
182 GetProcAddress(lib_setupapi, "SetupDiDestroyDeviceInfoList"));
183 if (!fp_get_class_devs || !fp_enum_device_info ||
184 !fp_get_device_registry_property || !fp_destroy_device_info_list) {
185 FreeLibrary(lib_setupapi);
186 LOG(ERROR) << "Retrieve setupapi.dll functions failed";
187 return false;
188 }
189
190 // create device info for the display device
191 HDEVINFO device_info = fp_get_class_devs(
192 NULL, device_id.c_str(), NULL,
193 DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
194 if (device_info == INVALID_HANDLE_VALUE) {
195 FreeLibrary(lib_setupapi);
196 LOG(ERROR) << "Creating device info failed";
197 return false;
198 }
199
200 DWORD index = 0;
201 bool found = false;
202 SP_DEVINFO_DATA device_info_data;
203 device_info_data.cbSize = sizeof(device_info_data);
204 while (fp_enum_device_info(device_info, index++, &device_info_data)) {
205 WCHAR value[255];
206 if (fp_get_device_registry_property(device_info,
207 &device_info_data,
208 SPDRP_DRIVER,
209 NULL,
210 reinterpret_cast<PBYTE>(value),
211 sizeof(value),
212 NULL)) {
213 HKEY key;
214 std::wstring driver_key = L"System\\CurrentControlSet\\Control\\Class\\";
215 driver_key += value;
216 LONG result = RegOpenKeyExW(
217 HKEY_LOCAL_MACHINE, driver_key.c_str(), 0, KEY_QUERY_VALUE, &key);
218 if (result == ERROR_SUCCESS) {
219 DWORD dwcb_data = sizeof(value);
220 std::string driver_version;
221 result = RegQueryValueExW(
222 key, L"DriverVersion", NULL, NULL,
223 reinterpret_cast<LPBYTE>(value), &dwcb_data);
224 if (result == ERROR_SUCCESS)
225 driver_version = WideToASCII(std::wstring(value));
226
227 std::string driver_date;
228 dwcb_data = sizeof(value);
229 result = RegQueryValueExW(
230 key, L"DriverDate", NULL, NULL,
231 reinterpret_cast<LPBYTE>(value), &dwcb_data);
232 if (result == ERROR_SUCCESS)
233 driver_date = WideToASCII(std::wstring(value));
234
[email protected]a61508e52011-03-08 17:59:42235 gpu_info->driver_version = driver_version;
236 gpu_info->driver_date = driver_date;
[email protected]766653092011-03-01 16:45:23237 found = true;
238 RegCloseKey(key);
239 break;
240 }
241 }
242 }
243 fp_destroy_device_info_list(device_info);
244 FreeLibrary(lib_setupapi);
245 return found;
246}
247
248bool CollectDriverInfoGL(GPUInfo* gpu_info) {
[email protected]7004d7eb2011-01-21 00:27:53249 DCHECK(gpu_info);
[email protected]1bf14bc2010-07-09 16:10:43250
[email protected]a61508e52011-03-08 17:59:42251 std::string gl_version_string = gpu_info->gl_version_string;
[email protected]7004d7eb2011-01-21 00:27:53252
253 // TODO(zmo): We assume the driver version is in the end of GL_VERSION
254 // string. Need to verify if it is true for majority drivers.
255
256 size_t pos = gl_version_string.find_last_not_of("0123456789.");
257 if (pos != std::string::npos && pos < gl_version_string.length() - 1) {
[email protected]a61508e52011-03-08 17:59:42258 gpu_info->driver_version = gl_version_string.substr(pos + 1);
[email protected]7004d7eb2011-01-21 00:27:53259 return true;
260 }
261 return false;
[email protected]1bf14bc2010-07-09 16:10:43262}
263
264} // namespace gpu_info_collector