blob: a3283d5d4179797f3ae22555c7eff2c30198b690 [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]864b1362010-08-19 03:49:3811#include "base/file_path.h"
[email protected]dfb26432011-02-24 21:03:0312#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1513#include "base/memory/scoped_native_library.h"
[email protected]7004d7eb2011-01-21 00:27:5314#include "base/string_number_conversions.h"
[email protected]1bf14bc2010-07-09 16:10:4315#include "base/string_util.h"
[email protected]5ae0b282011-03-28 19:24:4916#include "ui/gfx/gl/gl_implementation.h"
[email protected]24edbd02011-04-14 00:11:5917#include "ui/gfx/gl/gl_surface_egl.h"
[email protected]1bf14bc2010-07-09 16:10:4318
[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]6cc8ece62011-03-14 20:05:4723namespace {
24
25// The version number stores the major and minor version in the least 16 bits;
26// for example, 2.5 is 0x00000205.
27// Returned string is in the format of "major.minor".
28std::string VersionNumberToString(uint32 version_number) {
29 int hi = (version_number >> 8) & 0xff;
30 int low = version_number & 0xff;
31 return base::IntToString(hi) + "." + base::IntToString(low);
32}
33
34} // namespace anonymous
35
[email protected]766653092011-03-01 16:45:2336// Setup API functions
37typedef HDEVINFO (WINAPI*SetupDiGetClassDevsWFunc)(
38 CONST GUID *ClassGuid,
39 PCWSTR Enumerator,
40 HWND hwndParent,
41 DWORD Flags
42);
43typedef BOOL (WINAPI*SetupDiEnumDeviceInfoFunc)(
44 HDEVINFO DeviceInfoSet,
45 DWORD MemberIndex,
46 PSP_DEVINFO_DATA DeviceInfoData
47);
48typedef BOOL (WINAPI*SetupDiGetDeviceRegistryPropertyWFunc)(
49 HDEVINFO DeviceInfoSet,
50 PSP_DEVINFO_DATA DeviceInfoData,
51 DWORD Property,
52 PDWORD PropertyRegDataType,
53 PBYTE PropertyBuffer,
54 DWORD PropertyBufferSize,
55 PDWORD RequiredSize
56);
57typedef BOOL (WINAPI*SetupDiDestroyDeviceInfoListFunc)(
58 HDEVINFO DeviceInfoSet
59);
60
[email protected]1bf14bc2010-07-09 16:10:4361namespace gpu_info_collector {
62
[email protected]4bce24e2010-09-07 20:45:0163bool CollectGraphicsInfo(GPUInfo* gpu_info) {
[email protected]7004d7eb2011-01-21 00:27:5364 DCHECK(gpu_info);
65
66 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
[email protected]6cc8ece62011-03-14 20:05:4767 gpu_info->finalized = true;
[email protected]7004d7eb2011-01-21 00:27:5368 return CollectGraphicsInfoGL(gpu_info);
69 }
70
71 // TODO(zmo): the following code only works if running on top of ANGLE.
72 // Need to handle the case when running on top of real EGL/GLES2 drivers.
[email protected]1bf14bc2010-07-09 16:10:4373
[email protected]4bce24e2010-09-07 20:45:0174 egl::Display* display = static_cast<egl::Display*>(
[email protected]24edbd02011-04-14 00:11:5975 gfx::GLSurfaceEGL::GetDisplay());
[email protected]dfb26432011-02-24 21:03:0376 if (!display) {
77 LOG(ERROR) << "gfx::BaseEGLContext::GetDisplay() failed";
[email protected]b60ca992010-09-20 18:57:0778 return false;
[email protected]dfb26432011-02-24 21:03:0379 }
[email protected]b60ca992010-09-20 18:57:0780
[email protected]4bce24e2010-09-07 20:45:0181 IDirect3DDevice9* device = display->getDevice();
[email protected]dfb26432011-02-24 21:03:0382 if (!device) {
83 LOG(ERROR) << "display->getDevice() failed";
[email protected]b60ca992010-09-20 18:57:0784 return false;
[email protected]dfb26432011-02-24 21:03:0385 }
[email protected]b60ca992010-09-20 18:57:0786
[email protected]4bce24e2010-09-07 20:45:0187 IDirect3D9* d3d = NULL;
[email protected]dfb26432011-02-24 21:03:0388 if (FAILED(device->GetDirect3D(&d3d))) {
89 LOG(ERROR) << "device->GetDirect3D(&d3d) failed";
[email protected]4bce24e2010-09-07 20:45:0190 return false;
[email protected]dfb26432011-02-24 21:03:0391 }
[email protected]1bf14bc2010-07-09 16:10:4392
[email protected]41579ae2010-11-15 22:31:2693 if (!CollectGraphicsInfoD3D(d3d, gpu_info))
94 return false;
[email protected]81f85b32010-10-08 18:03:2195
[email protected]41579ae2010-11-15 22:31:2696 // DirectX diagnostics are collected asynchronously because it takes a
[email protected]dfb26432011-02-24 21:03:0397 // couple of seconds. Do not mark gpu_info as complete until that is done.
[email protected]41579ae2010-11-15 22:31:2698 return true;
[email protected]1bf14bc2010-07-09 16:10:4399}
100
[email protected]079c4ad2011-02-19 00:05:57101bool CollectPreliminaryGraphicsInfo(GPUInfo* gpu_info) {
102 DCHECK(gpu_info);
103
[email protected]079c4ad2011-02-19 00:05:57104 bool rt = true;
105 if (!CollectVideoCardInfo(gpu_info))
106 rt = false;
107
108 return rt;
109}
110
[email protected]4bce24e2010-09-07 20:45:01111bool CollectGraphicsInfoD3D(IDirect3D9* d3d, GPUInfo* gpu_info) {
112 DCHECK(d3d);
113 DCHECK(gpu_info);
114
[email protected]766653092011-03-01 16:45:23115 bool succeed = CollectVideoCardInfo(gpu_info);
[email protected]1bf14bc2010-07-09 16:10:43116
117 // Get version information
118 D3DCAPS9 d3d_caps;
[email protected]7004d7eb2011-01-21 00:27:53119 if (d3d->GetDeviceCaps(D3DADAPTER_DEFAULT,
120 D3DDEVTYPE_HAL,
121 &d3d_caps) == D3D_OK) {
[email protected]6cc8ece62011-03-14 20:05:47122 gpu_info->pixel_shader_version =
123 VersionNumberToString(d3d_caps.PixelShaderVersion);
124 gpu_info->vertex_shader_version =
125 VersionNumberToString(d3d_caps.VertexShaderVersion);
[email protected]7004d7eb2011-01-21 00:27:53126 } else {
[email protected]dfb26432011-02-24 21:03:03127 LOG(ERROR) << "d3d->GetDeviceCaps() failed";
[email protected]7004d7eb2011-01-21 00:27:53128 succeed = false;
[email protected]1bf14bc2010-07-09 16:10:43129 }
[email protected]4bce24e2010-09-07 20:45:01130
[email protected]7004d7eb2011-01-21 00:27:53131 // Get can_lose_context
[email protected]4bce24e2010-09-07 20:45:01132 bool can_lose_context = false;
133 IDirect3D9Ex* d3dex = NULL;
134 if (SUCCEEDED(d3d->QueryInterface(__uuidof(IDirect3D9Ex),
135 reinterpret_cast<void**>(&d3dex)))) {
136 d3dex->Release();
137 } else {
138 can_lose_context = true;
139 }
[email protected]a61508e52011-03-08 17:59:42140 gpu_info->can_lose_context = can_lose_context;
[email protected]4bce24e2010-09-07 20:45:01141
[email protected]1bf14bc2010-07-09 16:10:43142 d3d->Release();
[email protected]1bf14bc2010-07-09 16:10:43143 return true;
144}
145
[email protected]7004d7eb2011-01-21 00:27:53146bool CollectVideoCardInfo(GPUInfo* gpu_info) {
147 DCHECK(gpu_info);
148
[email protected]1bf14bc2010-07-09 16:10:43149 // Taken from http://developer.nvidia.com/object/device_ids.html
150 DISPLAY_DEVICE dd;
151 dd.cb = sizeof(DISPLAY_DEVICE);
152 int i = 0;
153 std::wstring id;
154 for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
155 if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
156 id = dd.DeviceID;
157 break;
158 }
159 }
[email protected]7004d7eb2011-01-21 00:27:53160
161 if (id.length() > 20) {
162 int vendor_id = 0, device_id = 0;
163 std::wstring vendor_id_string = id.substr(8, 4);
164 std::wstring device_id_string = id.substr(17, 4);
165 base::HexStringToInt(WideToASCII(vendor_id_string), &vendor_id);
166 base::HexStringToInt(WideToASCII(device_id_string), &device_id);
[email protected]a61508e52011-03-08 17:59:42167 gpu_info->vendor_id = vendor_id;
168 gpu_info->device_id = device_id;
[email protected]93f5dcc3f2011-03-02 22:05:48169 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE.
170 return CollectDriverInfoD3D(id, gpu_info);
[email protected]1bf14bc2010-07-09 16:10:43171 }
[email protected]7004d7eb2011-01-21 00:27:53172 return false;
173}
[email protected]1bf14bc2010-07-09 16:10:43174
[email protected]766653092011-03-01 16:45:23175bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) {
176 HMODULE lib_setupapi = LoadLibraryW(L"setupapi.dll");
177 if (!lib_setupapi) {
178 LOG(ERROR) << "Open setupapi.dll failed";
179 return false;
180 }
181 SetupDiGetClassDevsWFunc fp_get_class_devs =
182 reinterpret_cast<SetupDiGetClassDevsWFunc>(
183 GetProcAddress(lib_setupapi, "SetupDiGetClassDevsW"));
184 SetupDiEnumDeviceInfoFunc fp_enum_device_info =
185 reinterpret_cast<SetupDiEnumDeviceInfoFunc>(
186 GetProcAddress(lib_setupapi, "SetupDiEnumDeviceInfo"));
187 SetupDiGetDeviceRegistryPropertyWFunc fp_get_device_registry_property =
188 reinterpret_cast<SetupDiGetDeviceRegistryPropertyWFunc>(
189 GetProcAddress(lib_setupapi, "SetupDiGetDeviceRegistryPropertyW"));
190 SetupDiDestroyDeviceInfoListFunc fp_destroy_device_info_list =
191 reinterpret_cast<SetupDiDestroyDeviceInfoListFunc>(
192 GetProcAddress(lib_setupapi, "SetupDiDestroyDeviceInfoList"));
193 if (!fp_get_class_devs || !fp_enum_device_info ||
194 !fp_get_device_registry_property || !fp_destroy_device_info_list) {
195 FreeLibrary(lib_setupapi);
196 LOG(ERROR) << "Retrieve setupapi.dll functions failed";
197 return false;
198 }
199
200 // create device info for the display device
201 HDEVINFO device_info = fp_get_class_devs(
202 NULL, device_id.c_str(), NULL,
203 DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
204 if (device_info == INVALID_HANDLE_VALUE) {
205 FreeLibrary(lib_setupapi);
206 LOG(ERROR) << "Creating device info failed";
207 return false;
208 }
209
210 DWORD index = 0;
211 bool found = false;
212 SP_DEVINFO_DATA device_info_data;
213 device_info_data.cbSize = sizeof(device_info_data);
214 while (fp_enum_device_info(device_info, index++, &device_info_data)) {
215 WCHAR value[255];
216 if (fp_get_device_registry_property(device_info,
217 &device_info_data,
218 SPDRP_DRIVER,
219 NULL,
220 reinterpret_cast<PBYTE>(value),
221 sizeof(value),
222 NULL)) {
223 HKEY key;
224 std::wstring driver_key = L"System\\CurrentControlSet\\Control\\Class\\";
225 driver_key += value;
226 LONG result = RegOpenKeyExW(
227 HKEY_LOCAL_MACHINE, driver_key.c_str(), 0, KEY_QUERY_VALUE, &key);
228 if (result == ERROR_SUCCESS) {
229 DWORD dwcb_data = sizeof(value);
230 std::string driver_version;
231 result = RegQueryValueExW(
232 key, L"DriverVersion", NULL, NULL,
233 reinterpret_cast<LPBYTE>(value), &dwcb_data);
234 if (result == ERROR_SUCCESS)
235 driver_version = WideToASCII(std::wstring(value));
236
237 std::string driver_date;
238 dwcb_data = sizeof(value);
239 result = RegQueryValueExW(
240 key, L"DriverDate", NULL, NULL,
241 reinterpret_cast<LPBYTE>(value), &dwcb_data);
242 if (result == ERROR_SUCCESS)
243 driver_date = WideToASCII(std::wstring(value));
244
[email protected]a61508e52011-03-08 17:59:42245 gpu_info->driver_version = driver_version;
246 gpu_info->driver_date = driver_date;
[email protected]766653092011-03-01 16:45:23247 found = true;
248 RegCloseKey(key);
249 break;
250 }
251 }
252 }
253 fp_destroy_device_info_list(device_info);
254 FreeLibrary(lib_setupapi);
255 return found;
256}
257
258bool CollectDriverInfoGL(GPUInfo* gpu_info) {
[email protected]7004d7eb2011-01-21 00:27:53259 DCHECK(gpu_info);
[email protected]1bf14bc2010-07-09 16:10:43260
[email protected]a61508e52011-03-08 17:59:42261 std::string gl_version_string = gpu_info->gl_version_string;
[email protected]7004d7eb2011-01-21 00:27:53262
263 // TODO(zmo): We assume the driver version is in the end of GL_VERSION
264 // string. Need to verify if it is true for majority drivers.
265
266 size_t pos = gl_version_string.find_last_not_of("0123456789.");
267 if (pos != std::string::npos && pos < gl_version_string.length() - 1) {
[email protected]a61508e52011-03-08 17:59:42268 gpu_info->driver_version = gl_version_string.substr(pos + 1);
[email protected]7004d7eb2011-01-21 00:27:53269 return true;
270 }
271 return false;
[email protected]1bf14bc2010-07-09 16:10:43272}
273
274} // namespace gpu_info_collector