Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(423)

Side by Side Diff: content/gpu/gpu_info_collector_linux.cc

Issue 10389051: Change GPUInfo to handle multiple GPUs. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <dlfcn.h> 7 #include <dlfcn.h>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 if (end == std::string::npos) 157 if (end == std::string::npos)
158 return line.substr(begin); 158 return line.substr(begin);
159 else 159 else
160 return line.substr(begin, end - begin); 160 return line.substr(begin, end - begin);
161 } 161 }
162 } 162 }
163 } 163 }
164 return ""; 164 return "";
165 } 165 }
166 166
167 const uint32 kVendorIDIntel = 0x8086;
168 const uint32 kVendorIDNVidia = 0x10de;
169 const uint32 kVendorIDAMD = 0x1002;
170
167 } // namespace anonymous 171 } // namespace anonymous
168 172
169 namespace gpu_info_collector { 173 namespace gpu_info_collector {
170 174
171 bool CollectGraphicsInfo(content::GPUInfo* gpu_info) { 175 bool CollectGraphicsInfo(content::GPUInfo* gpu_info) {
172 DCHECK(gpu_info); 176 DCHECK(gpu_info);
173 177
174 if (CommandLine::ForCurrentProcess()->HasSwitch( 178 if (CommandLine::ForCurrentProcess()->HasSwitch(
175 switches::kGpuNoContextLost)) { 179 switches::kGpuNoContextLost)) {
176 gpu_info->can_lose_context = false; 180 gpu_info->can_lose_context = false;
177 } else { 181 } else {
178 // TODO(zmo): need to consider the case where we are running on top 182 // TODO(zmo): need to consider the case where we are running on top
179 // of desktop GL and GL_ARB_robustness extension is available. 183 // of desktop GL and GL_ARB_robustness extension is available.
180 gpu_info->can_lose_context = 184 gpu_info->can_lose_context =
181 (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2); 185 (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2);
182 } 186 }
183 187
184 gpu_info->finalized = true; 188 gpu_info->finalized = true;
185 bool rt = CollectGraphicsInfoGL(gpu_info); 189 bool rt = CollectGraphicsInfoGL(gpu_info);
186 190
187 return rt; 191 return rt;
188 } 192 }
189 193
190 bool CollectPreliminaryGraphicsInfo(content::GPUInfo* gpu_info) { 194 bool CollectPreliminaryGraphicsInfo(content::GPUInfo* gpu_info) {
191 DCHECK(gpu_info); 195 DCHECK(gpu_info);
192 196
193 bool rt = CollectVideoCardInfo(gpu_info); 197 bool rt = CollectVideoCardInfo(gpu_info);
194 198
195 if (gpu_info->vendor_id == 0x1002) { // ATI 199 if (gpu_info->gpu.vendor_id == kVendorIDAMD) {
196 std::string ati_driver_version = CollectDriverVersionATI(); 200 std::string ati_driver_version = CollectDriverVersionATI();
197 if (!ati_driver_version.empty()) { 201 if (!ati_driver_version.empty()) {
198 gpu_info->driver_vendor = "ATI / AMD"; 202 gpu_info->driver_vendor = "ATI / AMD";
199 gpu_info->driver_version = ati_driver_version; 203 gpu_info->driver_version = ati_driver_version;
200 } 204 }
201 } 205 }
202 206
207 // Disable all GPU features for Optimus on Linux.
208 if (gpu_info->optimus) {
209 gpu_info->gpu_accessible = false;
210 gpu_info->finalized = true;
211 }
212
203 return rt; 213 return rt;
204 } 214 }
205 215
206 bool CollectVideoCardInfo(content::GPUInfo* gpu_info) { 216 bool CollectVideoCardInfo(content::GPUInfo* gpu_info) {
207 DCHECK(gpu_info); 217 DCHECK(gpu_info);
208 218
209 if (IsPciSupported() == false) { 219 if (IsPciSupported() == false) {
210 VLOG(1) << "PCI bus scanning is not supported"; 220 VLOG(1) << "PCI bus scanning is not supported";
211 return false; 221 return false;
212 } 222 }
213 223
214 // TODO(zmo): be more flexible about library name. 224 // TODO(zmo): be more flexible about library name.
215 PciInterface* interface = InitializeLibPci("libpci.so.3"); 225 PciInterface* interface = InitializeLibPci("libpci.so.3");
216 if (interface == NULL) 226 if (interface == NULL)
217 interface = InitializeLibPci("libpci.so"); 227 interface = InitializeLibPci("libpci.so");
218 if (interface == NULL) { 228 if (interface == NULL) {
219 VLOG(1) << "Failed to locate libpci"; 229 VLOG(1) << "Failed to locate libpci";
220 return false; 230 return false;
221 } 231 }
222 232
223 PciAccess* access = (interface->pci_alloc)(); 233 PciAccess* access = (interface->pci_alloc)();
224 DCHECK(access != NULL); 234 DCHECK(access != NULL);
225 (interface->pci_init)(access); 235 (interface->pci_init)(access);
226 (interface->pci_scan_bus)(access); 236 (interface->pci_scan_bus)(access);
227 std::vector<PciDevice*> gpu_list; 237 bool primary_gpu_identified = false;
228 PciDevice* gpu_active = NULL;
229 for (PciDevice* device = access->device_list; 238 for (PciDevice* device = access->device_list;
230 device != NULL; device = device->next) { 239 device != NULL; device = device->next) {
231 (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields. 240 (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields.
232 // TODO(zmo): there might be other classes that qualify as display devices. 241 // TODO(zmo): there might be other classes that qualify as display devices.
233 if (device->device_class == 0x0300) { // Device class is DISPLAY_VGA. 242 if (device->device_class != 0x0300) // Device class is DISPLAY_VGA.
234 if (gpu_info->vendor_id == 0 || gpu_info->vendor_id == device->vendor_id) 243 continue;
235 gpu_list.push_back(device); 244
236 } 245 content::GPUInfo::GPUDevice gpu;
237 } 246 gpu.vendor_id = device->vendor_id;
238 if (gpu_list.size() == 1) { 247 gpu.device_id = device->device_id;
239 gpu_active = gpu_list[0]; 248
240 } else {
241 // If more than one graphics card are identified, find the one that matches
242 // gl VENDOR and RENDERER info.
243 std::string gl_vendor_string = gpu_info->gl_vendor;
244 std::string gl_renderer_string = gpu_info->gl_renderer;
245 const int buffer_size = 255; 249 const int buffer_size = 255;
246 scoped_array<char> buffer(new char[buffer_size]); 250 scoped_array<char> buffer(new char[buffer_size]);
247 std::vector<PciDevice*> candidates; 251 // The current implementation of pci_lookup_name returns the same pointer
248 for (size_t i = 0; i < gpu_list.size(); ++i) { 252 // as the passed in upon success, and a different one (NULL or a pointer
249 PciDevice* gpu = gpu_list[i]; 253 // to an error message) upon failure.
250 // The current implementation of pci_lookup_name returns the same pointer 254 if ((interface->pci_lookup_name)(access,
251 // as the passed in upon success, and a different one (NULL or a pointer 255 buffer.get(),
252 // to an error message) upon failure. 256 buffer_size,
253 if ((interface->pci_lookup_name)(access, 257 1,
254 buffer.get(), 258 device->vendor_id) == buffer.get()) {
255 buffer_size, 259 gpu.vendor_string = buffer.get();
256 1, 260 }
257 gpu->vendor_id) != buffer.get()) 261 if ((interface->pci_lookup_name)(access,
258 continue; 262 buffer.get(),
259 std::string vendor_string = buffer.get(); 263 buffer_size,
260 const bool kCaseSensitive = false; 264 2,
261 if (!StartsWithASCII(gl_vendor_string, vendor_string, kCaseSensitive)) 265 device->vendor_id,
262 continue; 266 device->device_id) == buffer.get()) {
263 if ((interface->pci_lookup_name)(access,
264 buffer.get(),
265 buffer_size,
266 2,
267 gpu->vendor_id,
268 gpu->device_id) != buffer.get())
269 continue;
270 std::string device_string = buffer.get(); 267 std::string device_string = buffer.get();
271 size_t begin = device_string.find_first_of('['); 268 size_t begin = device_string.find_first_of('[');
272 size_t end = device_string.find_last_of(']'); 269 size_t end = device_string.find_last_of(']');
273 if (begin != std::string::npos && end != std::string::npos && 270 if (begin != std::string::npos && end != std::string::npos &&
274 begin < end) { 271 begin < end) {
275 device_string = device_string.substr(begin + 1, end - begin - 1); 272 device_string = device_string.substr(begin + 1, end - begin - 1);
276 } 273 }
277 if (StartsWithASCII(gl_renderer_string, device_string, kCaseSensitive)) { 274 gpu.device_string = device_string;
278 gpu_active = gpu; 275 }
279 break; 276
277 if (!primary_gpu_identified) {
278 primary_gpu_identified = true;
279 gpu_info->gpu = gpu;
280 } else {
281 // TODO(zmo): if there are multiple GPUs, we assume the non Intel
282 // one is primary. Revisit this logic because we actually don't know
283 // which GPU we are using at this point.
284 if (gpu_info->gpu.vendor_id == kVendorIDIntel &&
285 gpu.vendor_id != kVendorIDIntel) {
286 gpu_info->secondary_gpus.push_back(gpu_info->gpu);
287 gpu_info->gpu = gpu;
288 } else {
289 gpu_info->secondary_gpus.push_back(gpu);
280 } 290 }
281 // If a device's vendor matches gl VENDOR string, we want to consider the
282 // possibility that libpci may not return the exact same name as gl
283 // RENDERER string.
284 candidates.push_back(gpu);
285 } 291 }
286 if (gpu_active == NULL && candidates.size() == 1)
287 gpu_active = candidates[0];
288 } 292 }
289 if (gpu_active != NULL) { 293
290 gpu_info->vendor_id = gpu_active->vendor_id; 294 // Detect Optimus or AMD Switchable GPU.
291 gpu_info->device_id = gpu_active->device_id; 295 if (gpu_info->secondary_gpus.size() == 1 &&
296 gpu_info->secondary_gpus[0].vendor_id == kVendorIDIntel) {
297 if (gpu_info->gpu.vendor_id == kVendorIDNVidia)
298 gpu_info->optimus = true;
299 if (gpu_info->gpu.vendor_id == kVendorIDAMD)
300 gpu_info->amd_switchable = true;
292 } 301 }
302
293 (interface->pci_cleanup)(access); 303 (interface->pci_cleanup)(access);
294 FinalizeLibPci(&interface); 304 FinalizeLibPci(&interface);
295 return (gpu_active != NULL); 305 return (primary_gpu_identified);
296 } 306 }
297 307
298 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) { 308 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) {
299 DCHECK(gpu_info); 309 DCHECK(gpu_info);
300 310
301 std::string gl_version_string = gpu_info->gl_version_string; 311 std::string gl_version_string = gpu_info->gl_version_string;
302 if (StartsWithASCII(gl_version_string, "OpenGL ES", true)) 312 if (StartsWithASCII(gl_version_string, "OpenGL ES", true))
303 gl_version_string = gl_version_string.substr(10); 313 gl_version_string = gl_version_string.substr(10);
304 std::vector<std::string> pieces; 314 std::vector<std::string> pieces;
305 base::SplitStringAlongWhitespace(gl_version_string, &pieces); 315 base::SplitStringAlongWhitespace(gl_version_string, &pieces);
306 // In linux, the gl version string might be in the format of 316 // In linux, the gl version string might be in the format of
307 // GLVersion DriverVendor DriverVersion 317 // GLVersion DriverVendor DriverVersion
308 if (pieces.size() < 3) 318 if (pieces.size() < 3)
309 return false; 319 return false;
310 320
311 std::string driver_version = pieces[2]; 321 std::string driver_version = pieces[2];
312 size_t pos = driver_version.find_first_not_of("0123456789."); 322 size_t pos = driver_version.find_first_not_of("0123456789.");
313 if (pos == 0) 323 if (pos == 0)
314 return false; 324 return false;
315 if (pos != std::string::npos) 325 if (pos != std::string::npos)
316 driver_version = driver_version.substr(0, pos); 326 driver_version = driver_version.substr(0, pos);
317 327
318 gpu_info->driver_vendor = pieces[1]; 328 gpu_info->driver_vendor = pieces[1];
319 gpu_info->driver_version = driver_version; 329 gpu_info->driver_version = driver_version;
320 return true; 330 return true;
321 } 331 }
322 332
323 } // namespace gpu_info_collector 333 } // namespace gpu_info_collector
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698