1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gl/gpu_switching_manager.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "ui/gl/gl_switches.h"
#if defined(OS_MACOSX)
#include <OpenGL/OpenGL.h>
#include "ui/gl/gl_context_cgl.h"
#endif // OS_MACOSX
namespace ui {
struct GpuSwitchingManager::PlatformSpecific {
#if defined(OS_MACOSX)
CGLPixelFormatObj discrete_pixel_format;
#endif // OS_MACOSX
};
// static
GpuSwitchingManager* GpuSwitchingManager::GetInstance() {
return base::Singleton<GpuSwitchingManager>::get();
}
GpuSwitchingManager::GpuSwitchingManager()
: gpu_switching_option_(gl::PreferIntegratedGpu),
gpu_switching_option_set_(false),
supports_dual_gpus_(false),
supports_dual_gpus_set_(false),
platform_specific_(new PlatformSpecific) {
#if defined(OS_MACOSX)
platform_specific_->discrete_pixel_format = nullptr;
#endif // OS_MACOSX
}
GpuSwitchingManager::~GpuSwitchingManager() {
#if defined(OS_MACOSX)
if (platform_specific_->discrete_pixel_format)
CGLReleasePixelFormat(platform_specific_->discrete_pixel_format);
#endif // OS_MACOSX
}
void GpuSwitchingManager::ForceUseOfIntegratedGpu() {
DCHECK(SupportsDualGpus());
if (gpu_switching_option_set_) {
DCHECK_EQ(gpu_switching_option_, gl::PreferIntegratedGpu);
} else {
gpu_switching_option_ = gl::PreferIntegratedGpu;
gpu_switching_option_set_ = true;
}
}
void GpuSwitchingManager::ForceUseOfDiscreteGpu() {
DCHECK(SupportsDualGpus());
if (gpu_switching_option_set_) {
DCHECK_EQ(gpu_switching_option_, gl::PreferDiscreteGpu);
} else {
gpu_switching_option_ = gl::PreferDiscreteGpu;
gpu_switching_option_set_ = true;
#if defined(OS_MACOSX)
// Create a pixel format that lasts the lifespan of Chrome, so Chrome
// stays on the discrete GPU.
SwitchToDiscreteGpuMac();
#endif // OS_MACOSX
}
}
bool GpuSwitchingManager::SupportsDualGpus() {
if (!supports_dual_gpus_set_) {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
bool flag = false;
if (command_line.HasSwitch(switches::kSupportsDualGpus)) {
// GPU process, flag is passed down from browser process.
std::string flag_string = command_line.GetSwitchValueASCII(
switches::kSupportsDualGpus);
if (flag_string == "true") {
flag = true;
} else if (flag_string == "false") {
flag = false;
} else {
NOTIMPLEMENTED();
}
} else {
// Browser process.
// We only compute this flag in the browser process.
#if defined(OS_MACOSX)
flag = (vendor_ids_.size() == 2);
if (flag && command_line.HasSwitch(switches::kUseGL) &&
command_line.GetSwitchValueASCII(switches::kUseGL) !=
gl::kGLImplementationDesktopName)
flag = false;
if (flag) {
// Only advertise that we have two GPUs to the rest of
// Chrome's code if we find an Intel GPU and some other
// vendor's GPU. Otherwise we don't understand the
// configuration and don't deal well with it (an example being
// the dual AMD GPUs in recent Mac Pros).
const uint32_t intel = 0x8086;
flag = ((vendor_ids_[0] == intel && vendor_ids_[1] != intel) ||
(vendor_ids_[0] != intel && vendor_ids_[1] == intel));
}
#endif // OS_MACOSX
}
supports_dual_gpus_ = flag;
supports_dual_gpus_set_ = true;
}
return supports_dual_gpus_;
}
void GpuSwitchingManager::SetGpuVendorIds(
const std::vector<uint32_t>& vendor_ids) {
vendor_ids_ = vendor_ids;
}
void GpuSwitchingManager::AddObserver(GpuSwitchingObserver* observer) {
observer_list_.AddObserver(observer);
}
void GpuSwitchingManager::RemoveObserver(GpuSwitchingObserver* observer) {
observer_list_.RemoveObserver(observer);
}
void GpuSwitchingManager::NotifyGpuSwitched() {
for (GpuSwitchingObserver& observer : observer_list_)
observer.OnGpuSwitched();
}
gl::GpuPreference GpuSwitchingManager::AdjustGpuPreference(
gl::GpuPreference gpu_preference) {
if (!gpu_switching_option_set_)
return gpu_preference;
return gpu_switching_option_;
}
#if defined(OS_MACOSX)
void GpuSwitchingManager::SwitchToDiscreteGpuMac() {
if (platform_specific_->discrete_pixel_format)
return;
CGLPixelFormatAttribute attribs[1];
attribs[0] = static_cast<CGLPixelFormatAttribute>(0);
GLint num_pixel_formats = 0;
CGLChoosePixelFormat(attribs, &platform_specific_->discrete_pixel_format,
&num_pixel_formats);
}
#endif // OS_MACOSX
} // namespace ui
|