1 // Copyright (c) 2017 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_switching.h"
6 
7 #if defined(OS_MACOSX)
8 #include <OpenGL/OpenGL.h>
9 #endif
10 
11 #include <algorithm>
12 #include <vector>
13 
14 #include "base/command_line.h"
15 #include "base/logging.h"
16 #include "gpu/config/gpu_driver_bug_workaround_type.h"
17 #include "gpu/config/gpu_info.h"
18 #include "ui/gl/gl_context.h"
19 #include "ui/gl/gl_switches.h"
20 #include "ui/gl/gpu_preference.h"
21 
22 namespace gpu {
23 
24 namespace {
25 
26 #if defined(OS_MACOSX)
27 typedef CGLPixelFormatObj PlatformPixelFormatObj;
28 #else
29 typedef void* PlatformPixelFormatObj;
30 #endif  // OS_MACOSX
31 
32 PlatformPixelFormatObj g_discrete_pixel_format_obj = nullptr;
33 
ContainsWorkaround(const std::vector<int32_t> & workarounds,int32_t workaround)34 bool ContainsWorkaround(const std::vector<int32_t>& workarounds,
35                         int32_t workaround) {
36   return (std::find(workarounds.begin(), workarounds.end(), workaround) !=
37           workarounds.end());
38 }
39 
ForceDiscreteGPU()40 void ForceDiscreteGPU() {
41   if (g_discrete_pixel_format_obj)
42     return;
43 #if defined(OS_MACOSX)
44   CGLPixelFormatAttribute attribs[1];
45   attribs[0] = static_cast<CGLPixelFormatAttribute>(0);
46   GLint num_pixel_formats = 0;
47   CGLChoosePixelFormat(attribs, &g_discrete_pixel_format_obj,
48                        &num_pixel_formats);
49 #endif  // OS_MACOSX
50 }
51 
52 }  // namespace anonymous
53 
SwitchableGPUsSupported(const GPUInfo & gpu_info,const base::CommandLine & command_line)54 bool SwitchableGPUsSupported(const GPUInfo& gpu_info,
55                              const base::CommandLine& command_line) {
56 #if defined(OS_MACOSX)
57   if (command_line.HasSwitch(switches::kUseGL) &&
58       command_line.GetSwitchValueASCII(switches::kUseGL) !=
59           gl::kGLImplementationDesktopName &&
60       command_line.GetSwitchValueASCII(switches::kUseGL) !=
61           gl::kGLImplementationCoreProfileName) {
62     return false;
63   }
64   if (gpu_info.secondary_gpus.size() != 1) {
65     return false;
66   }
67   // Only advertise that we have two GPUs to the rest of
68   // Chrome's code if we find an Intel GPU and some other
69   // vendor's GPU. Otherwise we don't understand the
70   // configuration and don't deal well with it (an example being
71   // the dual AMD GPUs in recent Mac Pros).
72   const uint32_t kVendorIntel = 0x8086;
73   return ((gpu_info.gpu.vendor_id == kVendorIntel &&
74            gpu_info.secondary_gpus[0].vendor_id != kVendorIntel) ||
75           (gpu_info.gpu.vendor_id != kVendorIntel &&
76            gpu_info.secondary_gpus[0].vendor_id == kVendorIntel));
77 #else
78   return false;
79 #endif  // OS_MACOSX
80 }
81 
InitializeSwitchableGPUs(const std::vector<int32_t> & driver_bug_workarounds)82 void InitializeSwitchableGPUs(
83     const std::vector<int32_t>& driver_bug_workarounds) {
84   gl::GLContext::SetSwitchableGPUsSupported();
85   if (ContainsWorkaround(driver_bug_workarounds, FORCE_HIGH_PERFORMANCE_GPU)) {
86     gl::GLContext::SetForcedGpuPreference(gl::GpuPreference::kHighPerformance);
87     ForceDiscreteGPU();
88   } else if (ContainsWorkaround(driver_bug_workarounds, FORCE_LOW_POWER_GPU)) {
89     gl::GLContext::SetForcedGpuPreference(gl::GpuPreference::kLowPower);
90   }
91 }
92 
StopForceDiscreteGPU()93 void StopForceDiscreteGPU() {
94 #if defined(OS_MACOSX)
95   if (g_discrete_pixel_format_obj) {
96     CGLReleasePixelFormat(g_discrete_pixel_format_obj);
97     g_discrete_pixel_format_obj = nullptr;
98   }
99 #endif  // OS_MACOSX
100 }
101 
102 }  // namespace gpu
103