compositing_iosurface_context_mac.mm revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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. 4 5#include "content/browser/renderer_host/compositing_iosurface_context_mac.h" 6 7#include <OpenGL/gl.h> 8#include <OpenGL/OpenGL.h> 9#include <vector> 10 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" 19 20namespace content { 21 22// static 23scoped_refptr<CompositingIOSurfaceContext> 24CompositingIOSurfaceContext::Get(int window_number) { 25 TRACE_EVENT0("browser", "CompositingIOSurfaceContext::Get"); 26 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_); 31 return found->second; 32 } 33 34 static bool is_vsync_disabled = 35 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync); 36 37 base::ScopedTypeRef<CGLContextObj> cgl_context_strong; 38 CGLContextObj cgl_context = NULL; 39 CGLError error = kCGLNoError; 40 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)); 48 } 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."; 57 return NULL; 58 } 59 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."; 69 return NULL; 70 } 71 cgl_context = cgl_context_strong; 72 73 // Note that VSync is ignored because CoreAnimation will automatically 74 // rate limit draws. 75 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; 80 { 81 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context); 82 shader_program_cache.reset(new CompositingIOSurfaceShaderPrograms()); 83 if (window_number == kOffscreenContextWindowNumber) { 84 prepared = true; 85 } else { 86 prepared = ( 87 shader_program_cache->UseBlitProgram() && 88 shader_program_cache->UseSolidWhiteProgram()); 89 } 90 glUseProgram(0u); 91 } 92 if (!prepared) { 93 LOG(ERROR) << "IOSurface failed to compile/link required shader programs."; 94 return NULL; 95 } 96 97 return new CompositingIOSurfaceContext( 98 window_number, 99 cgl_context_strong, 100 cgl_context, 101 is_vsync_disabled, 102 shader_program_cache.Pass()); 103} 104 105void CompositingIOSurfaceContext::PoisonContextAndSharegroup() { 106 if (poisoned_) 107 return; 108 109 for (WindowMap::iterator it = window_map()->begin(); 110 it != window_map()->end(); 111 ++it) { 112 it->second->poisoned_ = true; 113 } 114 window_map()->clear(); 115} 116 117CompositingIOSurfaceContext::CompositingIOSurfaceContext( 118 int window_number, 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()), 128 poisoned_(false) { 129 DCHECK(window_map()->find(window_number_) == window_map()->end()); 130 window_map()->insert(std::make_pair(window_number_, this)); 131 132 GpuDataManager::GetInstance()->AddObserver(this); 133} 134 135CompositingIOSurfaceContext::~CompositingIOSurfaceContext() { 136 GpuDataManager::GetInstance()->RemoveObserver(this); 137 138 { 139 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_); 140 shader_program_cache_->Reset(); 141 } 142 if (!poisoned_) { 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_); 146 } else { 147 WindowMap::const_iterator found = window_map()->find(window_number_); 148 if (found != window_map()->end()) 149 DCHECK(found->second != this); 150 } 151} 152 153void 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(); 158} 159 160// static 161CompositingIOSurfaceContext::WindowMap* 162 CompositingIOSurfaceContext::window_map() { 163 return window_map_.Pointer(); 164} 165 166// static 167base::LazyInstance<CompositingIOSurfaceContext::WindowMap> 168 CompositingIOSurfaceContext::window_map_; 169 170} // namespace content 171