blob: 5fdb3cce66963dc373547b88b1cec4883d9b6fb8 [file] [log] [blame]
// 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_EACH_OBSERVER(GpuSwitchingObserver, observer_list_, 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