| // 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 |