blob: 6f5fa19f89f44c8a4d3f22cb82ba13bc8a635beb [file] [log] [blame]
[email protected]864b1362010-08-19 03:49:381// Copyright (c) 2010 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
5#include "chrome/gpu/gpu_info_collector.h"
6
[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]f3f79b102011-01-27 00:19:3754 gpu_info->SetLevel(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.
59 gpu_info->SetLevel(GPUInfo::kPartial);
60
[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
94 gpu_info->SetLevel(GPUInfo::kPartial);
95
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) {
114 gpu_info->SetShaderVersion(d3d_caps.PixelShaderVersion,
115 d3d_caps.VertexShaderVersion);
116 } 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]7004d7eb2011-01-21 00:27:53130 gpu_info->SetCanLoseContext(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);
157 gpu_info->SetVideoCardInfo(vendor_id, device_id);
[email protected]766653092011-03-01 16:45:23158 // TODO(zmo): need a better way to identify if ANGLE is used.
159 if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2)
160 return CollectDriverInfoD3D(id, gpu_info);
[email protected]7004d7eb2011-01-21 00:27:53161 return true;
[email protected]1bf14bc2010-07-09 16:10:43162 }
[email protected]7004d7eb2011-01-21 00:27:53163 return false;
164}
[email protected]1bf14bc2010-07-09 16:10:43165
[email protected]766653092011-03-01 16:45:23166bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) {
167 HMODULE lib_setupapi = LoadLibraryW(L"setupapi.dll");
168 if (!lib_setupapi) {
169 LOG(ERROR) << "Open setupapi.dll failed";
170 return false;
171 }
172 SetupDiGetClassDevsWFunc fp_get_class_devs =
173 reinterpret_cast<SetupDiGetClassDevsWFunc>(
174 GetProcAddress(lib_setupapi, "SetupDiGetClassDevsW"));
175 SetupDiEnumDeviceInfoFunc fp_enum_device_info =
176 reinterpret_cast<SetupDiEnumDeviceInfoFunc>(
177 GetProcAddress(lib_setupapi, "SetupDiEnumDeviceInfo"));
178 SetupDiGetDeviceRegistryPropertyWFunc fp_get_device_registry_property =
179 reinterpret_cast<SetupDiGetDeviceRegistryPropertyWFunc>(
180 GetProcAddress(lib_setupapi, "SetupDiGetDeviceRegistryPropertyW"));
181 SetupDiDestroyDeviceInfoListFunc fp_destroy_device_info_list =
182 reinterpret_cast<SetupDiDestroyDeviceInfoListFunc>(
183 GetProcAddress(lib_setupapi, "SetupDiDestroyDeviceInfoList"));
184 if (!fp_get_class_devs || !fp_enum_device_info ||
185 !fp_get_device_registry_property || !fp_destroy_device_info_list) {
186 FreeLibrary(lib_setupapi);
187 LOG(ERROR) << "Retrieve setupapi.dll functions failed";
188 return false;
189 }
190
191 // create device info for the display device
192 HDEVINFO device_info = fp_get_class_devs(
193 NULL, device_id.c_str(), NULL,
194 DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
195 if (device_info == INVALID_HANDLE_VALUE) {
196 FreeLibrary(lib_setupapi);
197 LOG(ERROR) << "Creating device info failed";
198 return false;
199 }
200
201 DWORD index = 0;
202 bool found = false;
203 SP_DEVINFO_DATA device_info_data;
204 device_info_data.cbSize = sizeof(device_info_data);
205 while (fp_enum_device_info(device_info, index++, &device_info_data)) {
206 WCHAR value[255];
207 if (fp_get_device_registry_property(device_info,
208 &device_info_data,
209 SPDRP_DRIVER,
210 NULL,
211 reinterpret_cast<PBYTE>(value),
212 sizeof(value),
213 NULL)) {
214 HKEY key;
215 std::wstring driver_key = L"System\\CurrentControlSet\\Control\\Class\\";
216 driver_key += value;
217 LONG result = RegOpenKeyExW(
218 HKEY_LOCAL_MACHINE, driver_key.c_str(), 0, KEY_QUERY_VALUE, &key);
219 if (result == ERROR_SUCCESS) {
220 DWORD dwcb_data = sizeof(value);
221 std::string driver_version;
222 result = RegQueryValueExW(
223 key, L"DriverVersion", NULL, NULL,
224 reinterpret_cast<LPBYTE>(value), &dwcb_data);
225 if (result == ERROR_SUCCESS)
226 driver_version = WideToASCII(std::wstring(value));
227
228 std::string driver_date;
229 dwcb_data = sizeof(value);
230 result = RegQueryValueExW(
231 key, L"DriverDate", NULL, NULL,
232 reinterpret_cast<LPBYTE>(value), &dwcb_data);
233 if (result == ERROR_SUCCESS)
234 driver_date = WideToASCII(std::wstring(value));
235
236 gpu_info->SetDriverInfo("", driver_version, driver_date);
237 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]7004d7eb2011-01-21 00:27:53251 std::string gl_version_string = gpu_info->gl_version_string();
252
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]766653092011-03-01 16:45:23258 gpu_info->SetDriverInfo("", 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