[content shell] hook up testRunner.dumpEditingCallbacks
[chromium-blink-merge.git] / content / gpu / gpu_info_collector_mac.mm
blob66c362d74176b39f8c34c9229d15c95f6bc345ea
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/mac_util.h"
12 #include "base/mac/scoped_cftyperef.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/string_number_conversions.h"
15 #include "base/string_piece.h"
16 #include "base/string_util.h"
17 #include "base/sys_string_conversions.h"
18 #include "ui/gl/gl_bindings.h"
19 #include "ui/gl/gl_context.h"
20 #include "ui/gl/gl_implementation.h"
21 #include "ui/gl/gl_interface.h"
23 #import <Cocoa/Cocoa.h>
24 #import <Foundation/Foundation.h>
25 #import <IOKit/IOKitLib.h>
27 namespace {
29 const UInt32 kVendorIDIntel = 0x8086;
30 const UInt32 kVendorIDNVidia = 0x10de;
31 const UInt32 kVendorIDAMD = 0x1002;
33 // Return 0 if we couldn't find the property.
34 // The property values we use should not be 0, so it's OK to use 0 as failure.
35 UInt32 GetEntryProperty(io_registry_entry_t entry, CFStringRef property_name) {
36   base::mac::ScopedCFTypeRef<CFDataRef> data_ref(static_cast<CFDataRef>(
37       IORegistryEntrySearchCFProperty(entry,
38                                       kIOServicePlane,
39                                       property_name,
40                                       kCFAllocatorDefault,
41                                       kIORegistryIterateRecursively |
42                                       kIORegistryIterateParents)));
43   if (!data_ref)
44     return 0;
46   UInt32 value = 0;
47   const UInt32* value_pointer =
48       reinterpret_cast<const UInt32*>(CFDataGetBytePtr(data_ref));
49   if (value_pointer != NULL)
50     value = *value_pointer;
51   return value;
54 // Find the info of the current GPU.
55 content::GPUInfo::GPUDevice GetActiveGPU() {
56   content::GPUInfo::GPUDevice gpu;
57   io_registry_entry_t dsp_port = CGDisplayIOServicePort(kCGDirectMainDisplay);
58   gpu.vendor_id = GetEntryProperty(dsp_port, CFSTR("vendor-id"));
59   gpu.device_id = GetEntryProperty(dsp_port, CFSTR("device-id"));
60   return gpu;
63 // Scan IO registry for PCI video cards.
64 bool CollectPCIVideoCardInfo(content::GPUInfo* gpu_info) {
65   DCHECK(gpu_info);
67   // Collect all GPUs' info.
68   // match_dictionary will be consumed by IOServiceGetMatchingServices, no need
69   // to release it.
70   CFMutableDictionaryRef match_dictionary = IOServiceMatching("IOPCIDevice");
71   io_iterator_t entry_iterator;
72   std::vector<content::GPUInfo::GPUDevice> gpu_list;
73   if (IOServiceGetMatchingServices(kIOMasterPortDefault,
74                                    match_dictionary,
75                                    &entry_iterator) == kIOReturnSuccess) {
76     io_registry_entry_t entry;
77     while ((entry = IOIteratorNext(entry_iterator))) {
78       content::GPUInfo::GPUDevice gpu;
79       if (GetEntryProperty(entry, CFSTR("class-code")) != 0x30000) {
80         // 0x30000 : DISPLAY_VGA
81         continue;
82       }
83       gpu.vendor_id = GetEntryProperty(entry, CFSTR("vendor-id"));
84       gpu.device_id = GetEntryProperty(entry, CFSTR("device-id"));
85       if (gpu.vendor_id && gpu.device_id)
86         gpu_list.push_back(gpu);
87     }
88     IOObjectRelease(entry_iterator);
89   }
91   switch (gpu_list.size()) {
92     case 0:
93       return false;
94     case 1:
95       gpu_info->gpu = gpu_list[0];
96       break;
97     case 2:
98       {
99         int integrated = -1;
100         int discrete = -1;
101         if (gpu_list[0].vendor_id == kVendorIDIntel)
102           integrated = 0;
103         else if (gpu_list[1].vendor_id == kVendorIDIntel)
104           integrated = 1;
105         if (integrated >= 0) {
106           switch (gpu_list[1 - integrated].vendor_id) {
107             case kVendorIDAMD:
108               gpu_info->amd_switchable = true;
109               discrete = 1 - integrated;
110               break;
111             case kVendorIDNVidia:
112               gpu_info->optimus = true;
113               discrete = 1 - integrated;
114               break;
115             default:
116               break;
117           }
118         }
119         if (integrated >= 0 && discrete >= 0) {
120           // We always put discrete GPU as primary for blacklisting purpose.
121           gpu_info->gpu = gpu_list[discrete];
122           gpu_info->secondary_gpus.push_back(gpu_list[integrated]);
123           break;
124         }
125         // If it's not optimus or amd_switchable, we put the current GPU as
126         // primary.  Fall through to default.
127       }
128     default:
129       {
130         content::GPUInfo::GPUDevice active_gpu = GetActiveGPU();
131         size_t current = gpu_list.size();
132         if (active_gpu.vendor_id && active_gpu.device_id) {
133           for (size_t i = 0; i < gpu_list.size(); ++i) {
134             if (gpu_list[i].vendor_id == active_gpu.vendor_id &&
135                 gpu_list[i].device_id == active_gpu.device_id) {
136               current = i;
137               break;
138             }
139           }
140         }
141         if (current == gpu_list.size()) {
142           // If we fail to identify the current GPU, select any one as primary.
143           current = 0;
144         }
145         for (size_t i = 0; i < gpu_list.size(); ++i) {
146           if (i == current)
147             gpu_info->gpu = gpu_list[i];
148           else
149             gpu_info->secondary_gpus.push_back(gpu_list[i]);
150         }
151       }
152       break;
153   }
154   return (gpu_info->gpu.vendor_id && gpu_info->gpu.device_id);
157 }  // namespace anonymous
159 namespace gpu_info_collector {
161 bool CollectContextGraphicsInfo(content::GPUInfo* gpu_info) {
162   DCHECK(gpu_info);
164   TRACE_EVENT0("gpu", "gpu_info_collector::CollectGraphicsInfo");
166   gpu_info->can_lose_context =
167       (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2);
168   gpu_info->finalized = true;
169   return CollectGraphicsInfoGL(gpu_info);
172 bool CollectBasicGraphicsInfo(content::GPUInfo* gpu_info) {
173   DCHECK(gpu_info);
175   std::string model_name;
176   int32 model_major = 0, model_minor = 0;
177   base::mac::ParseModelIdentifier(base::mac::GetModelIdentifier(),
178                                   &model_name, &model_major, &model_minor);
179   ReplaceChars(model_name, " ", "_", &gpu_info->machine_model);
180   gpu_info->machine_model += " " + base::IntToString(model_major) +
181                              "." + base::IntToString(model_minor);
183   return CollectPCIVideoCardInfo(gpu_info);
186 bool CollectDriverInfoGL(content::GPUInfo* gpu_info) {
187   DCHECK(gpu_info);
189   // Extract the OpenGL driver version string from the GL_VERSION string.
190   // Mac OpenGL drivers have the driver version
191   // at the end of the gl version string preceded by a dash.
192   // Use some jiggery-pokery to turn that utf8 string into a std::wstring.
193   std::string gl_version_string = gpu_info->gl_version_string;
194   size_t pos = gl_version_string.find_last_of('-');
195   if (pos == std::string::npos)
196     return false;
197   gpu_info->driver_version = gl_version_string.substr(pos + 1);
198   return true;
201 void MergeGPUInfo(content::GPUInfo* basic_gpu_info,
202                   const content::GPUInfo& context_gpu_info) {
203   MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
206 }  // namespace gpu_info_collector