| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // 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 | |
| 7 #include <d3d9.h> | |
| 8 #include <setupapi.h> | |
| 9 #include <windows.h> | |
| 10 | |
| 11 #include "app/gfx/gl/gl_context_egl.h" | |
| 12 #include "app/gfx/gl/gl_implementation.h" | |
| 13 #include "base/file_path.h" | |
| 14 #include "base/logging.h" | |
| 15 #include "base/scoped_native_library.h" | |
| 16 #include "base/string_number_conversions.h" | |
| 17 #include "base/string_util.h" | |
| 18 | |
| 19 // 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 | |
| 23 // Setup API functions | |
| 24 typedef HDEVINFO (WINAPI*SetupDiGetClassDevsWFunc)( | |
| 25 CONST GUID *ClassGuid, | |
| 26 PCWSTR Enumerator, | |
| 27 HWND hwndParent, | |
| 28 DWORD Flags | |
| 29 ); | |
| 30 typedef BOOL (WINAPI*SetupDiEnumDeviceInfoFunc)( | |
| 31 HDEVINFO DeviceInfoSet, | |
| 32 DWORD MemberIndex, | |
| 33 PSP_DEVINFO_DATA DeviceInfoData | |
| 34 ); | |
| 35 typedef 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 ); | |
| 44 typedef BOOL (WINAPI*SetupDiDestroyDeviceInfoListFunc)( | |
| 45 HDEVINFO DeviceInfoSet | |
| 46 ); | |
| 47 | |
| 48 namespace gpu_info_collector { | |
| 49 | |
| 50 bool CollectGraphicsInfo(GPUInfo* gpu_info) { | |
| 51 DCHECK(gpu_info); | |
| 52 | |
| 53 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { | |
| 54 gpu_info->level = GPUInfo::kComplete; | |
| 55 return CollectGraphicsInfoGL(gpu_info); | |
| 56 } | |
| 57 | |
| 58 // Set to partial now in case this function returns false below. | |
| 59 gpu_info->level = GPUInfo::kPartial; | |
| 60 | |
| 61 // 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. | |
| 63 | |
| 64 egl::Display* display = static_cast<egl::Display*>( | |
| 65 gfx::BaseEGLContext::GetDisplay()); | |
| 66 if (!display) { | |
| 67 LOG(ERROR) << "gfx::BaseEGLContext::GetDisplay() failed"; | |
| 68 return false; | |
| 69 } | |
| 70 | |
| 71 IDirect3DDevice9* device = display->getDevice(); | |
| 72 if (!device) { | |
| 73 LOG(ERROR) << "display->getDevice() failed"; | |
| 74 return false; | |
| 75 } | |
| 76 | |
| 77 IDirect3D9* d3d = NULL; | |
| 78 if (FAILED(device->GetDirect3D(&d3d))) { | |
| 79 LOG(ERROR) << "device->GetDirect3D(&d3d) failed"; | |
| 80 return false; | |
| 81 } | |
| 82 | |
| 83 if (!CollectGraphicsInfoD3D(d3d, gpu_info)) | |
| 84 return false; | |
| 85 | |
| 86 // DirectX diagnostics are collected asynchronously because it takes a | |
| 87 // couple of seconds. Do not mark gpu_info as complete until that is done. | |
| 88 return true; | |
| 89 } | |
| 90 | |
| 91 bool CollectPreliminaryGraphicsInfo(GPUInfo* gpu_info) { | |
| 92 DCHECK(gpu_info); | |
| 93 | |
| 94 gpu_info->level = GPUInfo::kPreliminary; | |
| 95 | |
| 96 bool rt = true; | |
| 97 if (!CollectVideoCardInfo(gpu_info)) | |
| 98 rt = false; | |
| 99 | |
| 100 return rt; | |
| 101 } | |
| 102 | |
| 103 bool CollectGraphicsInfoD3D(IDirect3D9* d3d, GPUInfo* gpu_info) { | |
| 104 DCHECK(d3d); | |
| 105 DCHECK(gpu_info); | |
| 106 | |
| 107 bool succeed = CollectVideoCardInfo(gpu_info); | |
| 108 | |
| 109 // Get version information | |
| 110 D3DCAPS9 d3d_caps; | |
| 111 if (d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, | |
| 112 D3DDEVTYPE_HAL, | |
| 113 &d3d_caps) == D3D_OK) { | |
| 114 gpu_info->pixel_shader_version = d3d_caps.PixelShaderVersion; | |
| 115 gpu_info->vertex_shader_version = d3d_caps.VertexShaderVersion; | |
| 116 } else { | |
| 117 LOG(ERROR) << "d3d->GetDeviceCaps() failed"; | |
| 118 succeed = false; | |
| 119 } | |
| 120 | |
| 121 // Get can_lose_context | |
| 122 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 } | |
| 130 gpu_info->can_lose_context = can_lose_context; | |
| 131 | |
| 132 d3d->Release(); | |
| 133 return true; | |
| 134 } | |
| 135 | |
| 136 bool CollectVideoCardInfo(GPUInfo* gpu_info) { | |
| 137 DCHECK(gpu_info); | |
| 138 | |
| 139 // 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 } | |
| 150 | |
| 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->vendor_id = vendor_id; | |
| 158 gpu_info->device_id = device_id; | |
| 159 // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE. | |
| 160 return CollectDriverInfoD3D(id, gpu_info); | |
| 161 } | |
| 162 return false; | |
| 163 } | |
| 164 | |
| 165 bool 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 | |
| 235 gpu_info->driver_version = driver_version; | |
| 236 gpu_info->driver_date = 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 | |
| 248 bool CollectDriverInfoGL(GPUInfo* gpu_info) { | |
| 249 DCHECK(gpu_info); | |
| 250 | |
| 251 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) { | |
| 258 gpu_info->driver_version = gl_version_string.substr(pos + 1); | |
| 259 return true; | |
| 260 } | |
| 261 return false; | |
| 262 } | |
| 263 | |
| 264 } // namespace gpu_info_collector | |
| OLD | NEW |