1 // Copyright (c) 2013 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.
5 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
8 #include <OpenGL/OpenGL.h>
11 #include "base/command_line.h"
12 #include "base/debug/trace_event.h"
13 #include "base/logging.h"
14 #include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
15 #include "content/browser/gpu/gpu_data_manager_impl.h"
16 #include "ui/base/ui_base_switches.h"
17 #include "ui/gl/gl_switches.h"
18 #include "ui/gl/gpu_switching_manager.h"
23 scoped_refptr<CompositingIOSurfaceContext>
24 CompositingIOSurfaceContext::Get(int window_number) {
25 TRACE_EVENT0("browser", "CompositingIOSurfaceContext::Get");
27 // Return the context for this window_number, if it exists.
28 WindowMap::iterator found = window_map()->find(window_number);
29 if (found != window_map()->end()) {
30 DCHECK(!found->second->poisoned_);
34 static bool is_vsync_disabled =
35 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync);
37 base::ScopedTypeRef<CGLContextObj> cgl_context_strong;
38 CGLContextObj cgl_context = NULL;
39 CGLError error = kCGLNoError;
41 // Create the pixel format object for the context.
42 std::vector<CGLPixelFormatAttribute> attribs;
43 attribs.push_back(kCGLPFADepthSize);
44 attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
45 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
46 attribs.push_back(kCGLPFAAllowOfflineRenderers);
47 attribs.push_back(static_cast<CGLPixelFormatAttribute>(1));
49 attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
50 GLint number_virtual_screens = 0;
51 base::ScopedTypeRef<CGLPixelFormatObj> pixel_format;
52 error = CGLChoosePixelFormat(&attribs.front(),
53 pixel_format.InitializeInto(),
54 &number_virtual_screens);
55 if (error != kCGLNoError) {
56 LOG(ERROR) << "Failed to create pixel format object.";
60 // Create all contexts in the same share group so that the textures don't
61 // need to be recreated when transitioning contexts.
62 CGLContextObj share_context = NULL;
63 if (!window_map()->empty())
64 share_context = window_map()->begin()->second->cgl_context();
65 error = CGLCreateContext(
66 pixel_format, share_context, cgl_context_strong.InitializeInto());
67 if (error != kCGLNoError) {
68 LOG(ERROR) << "Failed to create context object.";
71 cgl_context = cgl_context_strong;
73 // Note that VSync is ignored because CoreAnimation will automatically
76 // Prepare the shader program cache. Precompile the shader programs
77 // needed to draw the IO Surface for non-offscreen contexts.
78 bool prepared = false;
79 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache;
81 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context);
82 shader_program_cache.reset(new CompositingIOSurfaceShaderPrograms());
83 if (window_number == kOffscreenContextWindowNumber) {
87 shader_program_cache->UseBlitProgram() &&
88 shader_program_cache->UseSolidWhiteProgram());
93 LOG(ERROR) << "IOSurface failed to compile/link required shader programs.";
97 return new CompositingIOSurfaceContext(
102 shader_program_cache.Pass());
105 void CompositingIOSurfaceContext::PoisonContextAndSharegroup() {
109 for (WindowMap::iterator it = window_map()->begin();
110 it != window_map()->end();
112 it->second->poisoned_ = true;
114 window_map()->clear();
117 CompositingIOSurfaceContext::CompositingIOSurfaceContext(
119 base::ScopedTypeRef<CGLContextObj> cgl_context_strong,
120 CGLContextObj cgl_context,
121 bool is_vsync_disabled,
122 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache)
123 : window_number_(window_number),
124 cgl_context_strong_(cgl_context_strong),
125 cgl_context_(cgl_context),
126 is_vsync_disabled_(is_vsync_disabled),
127 shader_program_cache_(shader_program_cache.Pass()),
129 DCHECK(window_map()->find(window_number_) == window_map()->end());
130 window_map()->insert(std::make_pair(window_number_, this));
132 GpuDataManager::GetInstance()->AddObserver(this);
135 CompositingIOSurfaceContext::~CompositingIOSurfaceContext() {
136 GpuDataManager::GetInstance()->RemoveObserver(this);
139 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_);
140 shader_program_cache_->Reset();
143 DCHECK(window_map()->find(window_number_) != window_map()->end());
144 DCHECK(window_map()->find(window_number_)->second == this);
145 window_map()->erase(window_number_);
147 WindowMap::const_iterator found = window_map()->find(window_number_);
148 if (found != window_map()->end())
149 DCHECK(found->second != this);
153 void CompositingIOSurfaceContext::OnGpuSwitching() {
154 // Recreate all browser-side GL contexts whenever the GPU switches. If this
155 // is not done, performance will suffer.
156 // http://crbug.com/361493
157 PoisonContextAndSharegroup();
161 CompositingIOSurfaceContext::WindowMap*
162 CompositingIOSurfaceContext::window_map() {
163 return window_map_.Pointer();
167 base::LazyInstance<CompositingIOSurfaceContext::WindowMap>
168 CompositingIOSurfaceContext::window_map_;
170 } // namespace content