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