Fix bug in load time stats.
[chromium-blink-merge.git] / content / gpu / gpu_info_collector_mac.mm
blob4c31ed03d785521b94d8b9ed5330b854843af03e
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
3 // found in the LICENSE file.
5 #include "content/gpu/gpu_info_collector.h"
7 #include <vector>
9 #include "base/debug/trace_event.h"
10 #include "base/logging.h"
11 #include "base/mac/scoped_cftyperef.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/string_piece.h"
14 #include "base/sys_string_conversions.h"
15 #include "ui/gl/gl_bindings.h"
16 #include "ui/gl/gl_context.h"
17 #include "ui/gl/gl_implementation.h"
18 #include "ui/gl/gl_interface.h"
20 #import <Cocoa/Cocoa.h>
21 #import <Foundation/Foundation.h>
22 #import <IOKit/IOKitLib.h>
24 namespace {
26 const UInt32 kVendorIDIntel = 0x8086;
27 const UInt32 kVendorIDNVidia = 0x10de;
28 const UInt32 kVendorIDAMD = 0x1002;
30 // Return 0 if we couldn't find the property.
31 // The property values we use should not be 0, so it's OK to use 0 as failure.
32 UInt32 GetEntryProperty(io_registry_entry_t entry, CFStringRef property_name) {
33   base::mac::ScopedCFTypeRef<CFDataRef> data_ref(static_cast<CFDataRef>(
34       IORegistryEntrySearchCFProperty(entry,
35                                       kIOServicePlane,
36                                       property_name,
37                                       kCFAllocatorDefault,
38                                       kIORegistryIterateRecursively |
39                                       kIORegistryIterateParents)));
40   if (!data_ref)
41     return 0;
43   UInt32 value = 0;
44   const UInt32* value_pointer =
45       reinterpret_cast<const UInt32*>(CFDataGetBytePtr(data_ref));
46   if (value_pointer != NULL)
47     value = *value_pointer;
48   return value;
51 // Find the info of the current GPU.
52 content::GPUInfo::GPUDevice GetActiveGPU() {
53   content::GPUInfo::GPUDevice gpu;
54   io_registry_entry_t dsp_port = CGDisplayIOServicePort(kCGDirectMainDisplay);
55   gpu.vendor_id = GetEntryProperty(dsp_port, CFSTR("vendor-id"));
56   gpu.device_id = GetEntryProperty(dsp_port, CFSTR("device-id"));
57   return gpu;
60 // Scan IO registry for PCI video cards.
61 bool CollectPCIVideoCardInfo(content::GPUInfo* gpu_info) {
62   DCHECK(gpu_info);
64   // Collect all GPUs' info.
65   // match_dictionary will be consumed by IOServiceGetMatchingServices, no need
66   // to release it.
67   CFMutableDictionaryRef match_dictionary = IOServiceMatching("IOPCIDevice");
68   io_iterator_t entry_iterator;
69   std::vector<content::GPUInfo::GPUDevice> gpu_list;
70   if (IOServiceGetMatchingServices(kIOMasterPortDefault,
71                                    match_dictionary,
72                                    &entry_iterator) == kIOReturnSuccess) {
73     io_registry_entry_t entry;
74     while ((entry = IOIteratorNext(entry_iterator))) {
75       content::GPUInfo::GPUDevice gpu;
76       if (GetEntryProperty(entry, CFSTR("class-code")) != 0x30000) {
77         // 0x30000 : DISPLAY_VGA
78         continue;
79       }
80       gpu.vendor_id = GetEntryProperty(entry, CFSTR("vendor-id"));
81       gpu.device_id = GetEntryProperty(entry, CFSTR("device-id"));
82       if (gpu.vendor_id && gpu.device_id)
83         gpu_list.push_back(gpu);
84     }
85     IOObjectRelease(entry_iterator);
86   }
88   switch (gpu_list.size()) {
89     case 0:
90       return false;
91     case 1:
92       gpu_info->gpu = gpu_list[0];
93       break;
94     case 2:
95       {
96         int integrated = -1;
97         int discrete = -1;
98         if (gpu_list[0].vendor_id == kVendorIDIntel)
99           integrated = 0;
100         else if (gpu_list[1].vendor_id == kVendorIDIntel)
101           integrated = 1;
102         if (integrated >= 0) {
103           switch (gpu_list[1 - integrated].vendor_id) {
104             case kVendorIDAMD:
105               gpu_info->amd_switchable = true;
106               discrete = 1 - integrated;
107               break;
108             case kVendorIDNVidia:
109               gpu_info->optimus = true;
110               discrete = 1 - integrated;
111               break;
112             default:
113               break;
114           }
115         }
116         if (integrated >= 0 && discrete >= 0) {
117           // We always put discrete GPU as primary for blacklisting purpose.
118           gpu_info->gpu = gpu_list[discrete];
119           gpu_info->secondary_gpus.push_back(gpu_list[integrated]);
120           break;
121         }
122         // If it's not optimus or amd_switchable, we put the current GPU as
123         // primary.  Fall through to default.
124       }
125     default:
126       {
127         content::GPUInfo::GPUDevice active_gpu = GetActiveGPU();
128         size_t current = gpu_list.size();
129         if (active_gpu.vendor_id && active_gpu.device_id) {
130           for (size_t i = 0; i < gpu_list.size(); ++i) {
131             if (gpu_list[i].vendor_id == active_gpu.vendor_id &&
132                 gpu_list[i].device_id == active_gpu.device_id) {
133               current = i;
134               break;
135             }
136           }
137         }
138         if (current == gpu_list.size()) {
139           // If we fail to identify the current GPU, select any one as primary.
140           current = 0;
141         }
142         for (size_t i = 0; i < gpu_list.size(); ++i) {
143           if (i == current)
144             gpu_info->gpu = gpu_list[i];
145           else
146             gpu_info->secondary_gpus.push_back(gpu_list[i]);
147         }
148       }
149       break;
150   }
151   return (gpu_info->gpu.vendor_id && gpu_info->gpu.device_id);
154 }  // namespace anonymous
156 namespace gpu_info_collector {
158 bool CollectGraphicsInfo(content::GPUInfo* gpu_info) {
159   DCHECK(gpu_info);
161   TRACE_EVENT0("gpu", "gpu_info_collector::CollectGraphicsInfo");
163   gpu_info->can_lose_context =
164       (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2);
165   gpu_info->finalized = true;
166   return CollectGraphicsInfoGL(gpu_info);
169 bool CollectPreliminaryGraphicsInfo(content::GPUInfo* gpu_info) {
170   DCHECK(gpu_info);
172   return CollectPCIVideoCardInfo(gpu_info);
175 bool CollectVideoCardInfo(content::GPUInfo* gpu_info) {
176   return CollectPreliminaryGraphicsInfo(gpu_info);
179 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) {
180   DCHECK(gpu_info);
182   // Extract the OpenGL driver version string from the GL_VERSION string.
183   // Mac OpenGL drivers have the driver version
184   // at the end of the gl version string preceded by a dash.
185   // Use some jiggery-pokery to turn that utf8 string into a std::wstring.
186   std::string gl_version_string = gpu_info->gl_version_string;
187   size_t pos = gl_version_string.find_last_of('-');
188   if (pos == std::string::npos)
189     return false;
190   gpu_info->driver_version = gl_version_string.substr(pos + 1);
191   return true;
194 }  // namespace gpu_info_collector