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 "ui/gl/gpu_switching_manager.h"
6
7#include "base/command_line.h"
8#include "base/logging.h"
9#include "ui/gl/gl_switches.h"
10
11#if defined(OS_MACOSX)
12#include "base/mac/mac_util.h"
13#include "ui/gl/gl_context_cgl.h"
14#endif  // OS_MACOSX
15
16namespace ui {
17
18// static
19GpuSwitchingManager* GpuSwitchingManager::GetInstance() {
20  return Singleton<GpuSwitchingManager>::get();
21}
22
23GpuSwitchingManager::GpuSwitchingManager()
24    : gpu_switching_option_(gfx::PreferIntegratedGpu),
25      gpu_switching_option_set_(false),
26      supports_dual_gpus_(false),
27      supports_dual_gpus_set_(false),
28      gpu_count_(0) {
29#if defined(OS_MACOSX)
30  discrete_pixel_format_ = NULL;
31#endif  // OS_MACOSX
32}
33
34GpuSwitchingManager::~GpuSwitchingManager() {
35#if defined(OS_MACOSX)
36  if (discrete_pixel_format_)
37    CGLReleasePixelFormat(discrete_pixel_format_);
38#endif  // OS_MACOSX
39}
40
41void GpuSwitchingManager::ForceUseOfIntegratedGpu() {
42  DCHECK(SupportsDualGpus());
43  if (gpu_switching_option_set_) {
44    DCHECK_EQ(gpu_switching_option_, gfx::PreferIntegratedGpu);
45  } else {
46    gpu_switching_option_ = gfx::PreferIntegratedGpu;
47    gpu_switching_option_set_ = true;
48  }
49}
50
51void GpuSwitchingManager::ForceUseOfDiscreteGpu() {
52  DCHECK(SupportsDualGpus());
53  if (gpu_switching_option_set_) {
54    DCHECK_EQ(gpu_switching_option_, gfx::PreferDiscreteGpu);
55  } else {
56    gpu_switching_option_ = gfx::PreferDiscreteGpu;
57    gpu_switching_option_set_ = true;
58#if defined(OS_MACOSX)
59    // Create a pixel format that lasts the lifespan of Chrome, so Chrome
60    // stays on the discrete GPU.
61    SwitchToDiscreteGpuMac();
62#endif  // OS_MACOSX
63  }
64}
65
66bool GpuSwitchingManager::SupportsDualGpus() {
67  if (!supports_dual_gpus_set_) {
68    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
69    bool flag = false;
70    if (command_line.HasSwitch(switches::kSupportsDualGpus)) {
71      // GPU process, flag is passed down from browser process.
72      std::string flag_string = command_line.GetSwitchValueASCII(
73          switches::kSupportsDualGpus);
74      if (flag_string == "true") {
75        flag = true;
76      } else if (flag_string == "false") {
77        flag = false;
78      } else {
79        NOTIMPLEMENTED();
80      }
81    } else {
82      // Browser process.
83      // We only compute this flag in the browser process.
84#if defined(OS_MACOSX)
85      flag = (gpu_count_ == 2);
86      if (flag && command_line.HasSwitch(switches::kUseGL) &&
87          command_line.GetSwitchValueASCII(switches::kUseGL) !=
88            gfx::kGLImplementationDesktopName)
89        flag = false;
90
91      if (flag && !base::mac::IsOSLionOrLater())
92        flag = false;
93#endif  // OS_MACOSX
94    }
95    supports_dual_gpus_ = flag;
96    supports_dual_gpus_set_ = true;
97  }
98  return supports_dual_gpus_;
99}
100
101void GpuSwitchingManager::SetGpuCount(size_t gpu_count) {
102  gpu_count_ = gpu_count;
103}
104
105gfx::GpuPreference GpuSwitchingManager::AdjustGpuPreference(
106    gfx::GpuPreference gpu_preference) {
107  if (!gpu_switching_option_set_)
108    return gpu_preference;
109  return gpu_switching_option_;
110}
111
112#if defined(OS_MACOSX)
113void GpuSwitchingManager::SwitchToDiscreteGpuMac() {
114  if (discrete_pixel_format_)
115    return;
116  CGLPixelFormatAttribute attribs[1];
117  attribs[0] = static_cast<CGLPixelFormatAttribute>(0);
118  GLint num_pixel_formats = 0;
119  CGLChoosePixelFormat(attribs, &discrete_pixel_format_, &num_pixel_formats);
120}
121#endif  // OS_MACOSX
122
123}  // namespace ui
124