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/gpu/gpu_data_manager_impl.h" 15 #include "ui/base/ui_base_switches.h" 16 #include "ui/gl/gl_switches.h" 17 #include "ui/gl/gpu_switching_manager.h" 18 19 namespace content { 20 21 // static 22 scoped_refptr<CompositingIOSurfaceContext> 23 CompositingIOSurfaceContext::Get(int window_number) { 24 TRACE_EVENT0("browser", "CompositingIOSurfaceContext::Get"); 25 26 // Return the context for this window_number, if it exists. 27 WindowMap::iterator found = window_map()->find(window_number); 28 if (found != window_map()->end()) { 29 DCHECK(!found->second->poisoned_); 30 return found->second; 31 } 32 33 base::ScopedTypeRef<CGLContextObj> cgl_context_strong; 34 CGLContextObj cgl_context = NULL; 35 CGLError error = kCGLNoError; 36 37 // Create the pixel format object for the context. 38 std::vector<CGLPixelFormatAttribute> attribs; 39 attribs.push_back(kCGLPFADepthSize); 40 attribs.push_back(static_cast<CGLPixelFormatAttribute>(0)); 41 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) { 42 attribs.push_back(kCGLPFAAllowOfflineRenderers); 43 attribs.push_back(static_cast<CGLPixelFormatAttribute>(1)); 44 } 45 attribs.push_back(static_cast<CGLPixelFormatAttribute>(0)); 46 GLint number_virtual_screens = 0; 47 base::ScopedTypeRef<CGLPixelFormatObj> pixel_format; 48 error = CGLChoosePixelFormat(&attribs.front(), 49 pixel_format.InitializeInto(), 50 &number_virtual_screens); 51 if (error != kCGLNoError) { 52 LOG(ERROR) << "Failed to create pixel format object."; 53 return NULL; 54 } 55 56 // Create all contexts in the same share group so that the textures don't 57 // need to be recreated when transitioning contexts. 58 CGLContextObj share_context = NULL; 59 if (!window_map()->empty()) 60 share_context = window_map()->begin()->second->cgl_context(); 61 error = CGLCreateContext( 62 pixel_format, share_context, cgl_context_strong.InitializeInto()); 63 if (error != kCGLNoError) { 64 LOG(ERROR) << "Failed to create context object."; 65 return NULL; 66 } 67 cgl_context = cgl_context_strong; 68 69 // Note that VSync is ignored because CoreAnimation will automatically 70 // rate limit draws. 71 72 return new CompositingIOSurfaceContext( 73 window_number, 74 cgl_context_strong, 75 cgl_context); 76 } 77 78 void CompositingIOSurfaceContext::PoisonContextAndSharegroup() { 79 if (poisoned_) 80 return; 81 82 for (WindowMap::iterator it = window_map()->begin(); 83 it != window_map()->end(); 84 ++it) { 85 it->second->poisoned_ = true; 86 } 87 window_map()->clear(); 88 } 89 90 CompositingIOSurfaceContext::CompositingIOSurfaceContext( 91 int window_number, 92 base::ScopedTypeRef<CGLContextObj> cgl_context_strong, 93 CGLContextObj cgl_context) 94 : window_number_(window_number), 95 cgl_context_strong_(cgl_context_strong), 96 cgl_context_(cgl_context), 97 poisoned_(false) { 98 DCHECK(window_map()->find(window_number_) == window_map()->end()); 99 window_map()->insert(std::make_pair(window_number_, this)); 100 101 GpuDataManager::GetInstance()->AddObserver(this); 102 } 103 104 CompositingIOSurfaceContext::~CompositingIOSurfaceContext() { 105 GpuDataManager::GetInstance()->RemoveObserver(this); 106 107 if (!poisoned_) { 108 DCHECK(window_map()->find(window_number_) != window_map()->end()); 109 DCHECK(window_map()->find(window_number_)->second == this); 110 window_map()->erase(window_number_); 111 } else { 112 WindowMap::const_iterator found = window_map()->find(window_number_); 113 if (found != window_map()->end()) 114 DCHECK(found->second != this); 115 } 116 } 117 118 void CompositingIOSurfaceContext::OnGpuSwitching() { 119 // Recreate all browser-side GL contexts whenever the GPU switches. If this 120 // is not done, performance will suffer. 121 // http://crbug.com/361493 122 PoisonContextAndSharegroup(); 123 } 124 125 // static 126 CompositingIOSurfaceContext::WindowMap* 127 CompositingIOSurfaceContext::window_map() { 128 return window_map_.Pointer(); 129 } 130 131 // static 132 base::LazyInstance<CompositingIOSurfaceContext::WindowMap> 133 CompositingIOSurfaceContext::window_map_; 134 135 } // namespace content 136