| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h" | 5 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h" |
| 6 | 6 |
| 7 #include <OpenGL/gl.h> | 7 #include <OpenGL/gl.h> |
| 8 #include <OpenGL/OpenGL.h> | 8 #include <OpenGL/OpenGL.h> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/debug/trace_event.h" | 12 #include "base/debug/trace_event.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "content/browser/renderer_host/compositing_iosurface_shader_programs_ma
c.h" | 14 #include "content/browser/renderer_host/compositing_iosurface_shader_programs_ma
c.h" |
| 15 #include "content/public/common/content_switches.h" | 15 #include "content/public/common/content_switches.h" |
| 16 #include "ui/gl/gl_switches.h" | 16 #include "ui/gl/gl_switches.h" |
| 17 #include "ui/gl/gpu_switching_manager.h" | 17 #include "ui/gl/gpu_switching_manager.h" |
| 18 | 18 |
| 19 namespace { | |
| 20 | |
| 21 template<typename T, void Release(T)> | |
| 22 class ScopedCGLTypeRef { | |
| 23 public: | |
| 24 ScopedCGLTypeRef() : object_(NULL) {} | |
| 25 | |
| 26 ~ScopedCGLTypeRef() { | |
| 27 if (object_) | |
| 28 Release(object_); | |
| 29 object_ = NULL; | |
| 30 } | |
| 31 | |
| 32 // Only to be used for pass-by-pointer initialization. The object must have | |
| 33 // been reset to NULL prior to calling. | |
| 34 T* operator&() { | |
| 35 DCHECK(object_ == NULL); | |
| 36 return &object_; | |
| 37 } | |
| 38 | |
| 39 operator T() const { | |
| 40 return object_; | |
| 41 } | |
| 42 | |
| 43 T release() WARN_UNUSED_RESULT { | |
| 44 T object = object_; | |
| 45 object_ = NULL; | |
| 46 return object; | |
| 47 } | |
| 48 | |
| 49 private: | |
| 50 T object_; | |
| 51 DISALLOW_COPY_AND_ASSIGN(ScopedCGLTypeRef); | |
| 52 }; | |
| 53 | |
| 54 } | |
| 55 | |
| 56 namespace content { | 19 namespace content { |
| 57 | 20 |
| 58 CoreAnimationStatus GetCoreAnimationStatus() { | 21 CoreAnimationStatus GetCoreAnimationStatus() { |
| 59 static CoreAnimationStatus status = | 22 static CoreAnimationStatus status = |
| 60 CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseCoreAnimation) ? | 23 CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseCoreAnimation) ? |
| 61 CORE_ANIMATION_ENABLED : CORE_ANIMATION_DISABLED; | 24 CORE_ANIMATION_ENABLED : CORE_ANIMATION_DISABLED; |
| 62 return status; | 25 return status; |
| 63 } | 26 } |
| 64 | 27 |
| 65 // static | 28 // static |
| 66 scoped_refptr<CompositingIOSurfaceContext> | 29 scoped_refptr<CompositingIOSurfaceContext> |
| 67 CompositingIOSurfaceContext::Get(int window_number) { | 30 CompositingIOSurfaceContext::Get(int window_number) { |
| 68 TRACE_EVENT0("browser", "CompositingIOSurfaceContext::Get"); | 31 TRACE_EVENT0("browser", "CompositingIOSurfaceContext::Get"); |
| 69 | 32 |
| 70 // Return the context for this window_number, if it exists. | 33 // Return the context for this window_number, if it exists. |
| 71 WindowMap::iterator found = window_map()->find(window_number); | 34 WindowMap::iterator found = window_map()->find(window_number); |
| 72 if (found != window_map()->end()) { | 35 if (found != window_map()->end()) { |
| 73 DCHECK(found->second->can_be_shared_); | 36 DCHECK(found->second->can_be_shared_); |
| 74 return found->second; | 37 return found->second; |
| 75 } | 38 } |
| 76 | 39 |
| 77 bool is_vsync_disabled = | 40 bool is_vsync_disabled = |
| 78 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync); | 41 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync); |
| 79 | 42 |
| 80 base::scoped_nsobject<NSOpenGLContext> nsgl_context; | 43 base::scoped_nsobject<NSOpenGLContext> nsgl_context; |
| 81 ScopedCGLTypeRef<CGLContextObj, CGLReleaseContext> cgl_context_strong; | 44 gfx::ScopedCGLContextObjRef cgl_context_strong; |
| 82 CGLContextObj cgl_context = NULL; | 45 CGLContextObj cgl_context = NULL; |
| 83 if (GetCoreAnimationStatus() == CORE_ANIMATION_DISABLED) { | 46 if (GetCoreAnimationStatus() == CORE_ANIMATION_DISABLED) { |
| 84 std::vector<NSOpenGLPixelFormatAttribute> attributes; | 47 std::vector<NSOpenGLPixelFormatAttribute> attributes; |
| 85 attributes.push_back(NSOpenGLPFADoubleBuffer); | 48 attributes.push_back(NSOpenGLPFADoubleBuffer); |
| 86 // We don't need a depth buffer - try setting its size to 0... | 49 // We don't need a depth buffer - try setting its size to 0... |
| 87 attributes.push_back(NSOpenGLPFADepthSize); attributes.push_back(0); | 50 attributes.push_back(NSOpenGLPFADepthSize); attributes.push_back(0); |
| 88 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) | 51 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) |
| 89 attributes.push_back(NSOpenGLPFAAllowOfflineRenderers); | 52 attributes.push_back(NSOpenGLPFAAllowOfflineRenderers); |
| 90 attributes.push_back(0); | 53 attributes.push_back(0); |
| 91 | 54 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 // Create the pixel format object for the context. | 90 // Create the pixel format object for the context. |
| 128 std::vector<CGLPixelFormatAttribute> attribs; | 91 std::vector<CGLPixelFormatAttribute> attribs; |
| 129 attribs.push_back(kCGLPFADepthSize); | 92 attribs.push_back(kCGLPFADepthSize); |
| 130 attribs.push_back(static_cast<CGLPixelFormatAttribute>(0)); | 93 attribs.push_back(static_cast<CGLPixelFormatAttribute>(0)); |
| 131 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) { | 94 if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) { |
| 132 attribs.push_back(kCGLPFAAllowOfflineRenderers); | 95 attribs.push_back(kCGLPFAAllowOfflineRenderers); |
| 133 attribs.push_back(static_cast<CGLPixelFormatAttribute>(1)); | 96 attribs.push_back(static_cast<CGLPixelFormatAttribute>(1)); |
| 134 } | 97 } |
| 135 attribs.push_back(static_cast<CGLPixelFormatAttribute>(0)); | 98 attribs.push_back(static_cast<CGLPixelFormatAttribute>(0)); |
| 136 GLint number_virtual_screens = 0; | 99 GLint number_virtual_screens = 0; |
| 137 ScopedCGLTypeRef<CGLPixelFormatObj, CGLReleasePixelFormat> pixel_format; | 100 gfx::ScopedCGLPixelFormatObjRef pixel_format; |
| 138 error = CGLChoosePixelFormat( | 101 error = CGLChoosePixelFormat( |
| 139 &attribs.front(), &pixel_format, &number_virtual_screens); | 102 &attribs.front(), &pixel_format, &number_virtual_screens); |
| 140 if (error != kCGLNoError) { | 103 if (error != kCGLNoError) { |
| 141 LOG(ERROR) << "Failed to create pixel format object."; | 104 LOG(ERROR) << "Failed to create pixel format object."; |
| 142 return NULL; | 105 return NULL; |
| 143 } | 106 } |
| 144 | 107 |
| 145 // Create all contexts in the same share group so that the textures don't | 108 // Create all contexts in the same share group so that the textures don't |
| 146 // need to be recreated when transitioning contexts. | 109 // need to be recreated when transitioning contexts. |
| 147 CGLContextObj share_context = NULL; | 110 CGLContextObj share_context = NULL; |
| 148 if (!window_map()->empty()) | 111 if (!window_map()->empty()) |
| 149 share_context = window_map()->begin()->second->cgl_context(); | 112 share_context = window_map()->begin()->second->cgl_context(); |
| 150 error = CGLCreateContext( | 113 error = CGLCreateContext( |
| 151 pixel_format, share_context, &cgl_context_strong); | 114 pixel_format, share_context, &cgl_context_strong); |
| 152 if (error != kCGLNoError) { | 115 if (error != kCGLNoError) { |
| 153 LOG(ERROR) << "Failed to create context object."; | 116 LOG(ERROR) << "Failed to create context object."; |
| 154 return NULL; | 117 return NULL; |
| 155 } | 118 } |
| 156 cgl_context = cgl_context_strong; | 119 cgl_context = cgl_context_strong; |
| 157 | 120 |
| 158 // Note that VSync is ignored because CoreAnimation will automatically | 121 // Note that VSync is ignored because CoreAnimation will automatically |
| 159 // rate limit draws. | 122 // rate limit draws. |
| 160 } | 123 } |
| 161 | 124 |
| 162 // Prepare the shader program cache. Precompile the shader programs | 125 // Prepare the shader program cache. Precompile the shader programs |
| 163 // needed to draw the IO Surface for non-offscreen contexts. | 126 // needed to draw the IO Surface for non-offscreen contexts. |
| 164 CGLSetCurrentContext(cgl_context); | |
| 165 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache( | |
| 166 new CompositingIOSurfaceShaderPrograms()); | |
| 167 bool prepared = false; | 127 bool prepared = false; |
| 168 if (window_number == kOffscreenContextWindowNumber) { | 128 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache; |
| 169 prepared = true; | 129 { |
| 170 } else { | 130 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context); |
| 171 prepared = ( | 131 shader_program_cache.reset(new CompositingIOSurfaceShaderPrograms()); |
| 172 shader_program_cache->UseBlitProgram() && | 132 if (window_number == kOffscreenContextWindowNumber) { |
| 173 shader_program_cache->UseSolidWhiteProgram()); | 133 prepared = true; |
| 134 } else { |
| 135 prepared = ( |
| 136 shader_program_cache->UseBlitProgram() && |
| 137 shader_program_cache->UseSolidWhiteProgram()); |
| 138 } |
| 139 glUseProgram(0u); |
| 174 } | 140 } |
| 175 glUseProgram(0u); | |
| 176 CGLSetCurrentContext(0); | |
| 177 if (!prepared) { | 141 if (!prepared) { |
| 178 LOG(ERROR) << "IOSurface failed to compile/link required shader programs."; | 142 LOG(ERROR) << "IOSurface failed to compile/link required shader programs."; |
| 179 return NULL; | 143 return NULL; |
| 180 } | 144 } |
| 181 | 145 |
| 182 scoped_refptr<DisplayLinkMac> display_link = DisplayLinkMac::Create(); | 146 scoped_refptr<DisplayLinkMac> display_link = DisplayLinkMac::Create(); |
| 183 if (!display_link) { | 147 if (!display_link) { |
| 184 LOG(ERROR) << "Failed to create display link for GL context."; | 148 LOG(ERROR) << "Failed to create display link for GL context."; |
| 185 return NULL; | 149 return NULL; |
| 186 } | 150 } |
| 187 | 151 |
| 188 return new CompositingIOSurfaceContext( | 152 return new CompositingIOSurfaceContext( |
| 189 window_number, | 153 window_number, |
| 190 nsgl_context.release(), | 154 nsgl_context.release(), |
| 191 cgl_context_strong.release(), | 155 cgl_context_strong, |
| 192 cgl_context, | 156 cgl_context, |
| 193 is_vsync_disabled, | 157 is_vsync_disabled, |
| 194 display_link, | 158 display_link, |
| 195 shader_program_cache.Pass()); | 159 shader_program_cache.Pass()); |
| 196 } | 160 } |
| 197 | 161 |
| 198 // static | 162 // static |
| 199 void CompositingIOSurfaceContext::MarkExistingContextsAsNotShareable() { | 163 void CompositingIOSurfaceContext::MarkExistingContextsAsNotShareable() { |
| 200 for (WindowMap::iterator it = window_map()->begin(); | 164 for (WindowMap::iterator it = window_map()->begin(); |
| 201 it != window_map()->end(); | 165 it != window_map()->end(); |
| 202 ++it) { | 166 ++it) { |
| 203 it->second->can_be_shared_ = false; | 167 it->second->can_be_shared_ = false; |
| 204 } | 168 } |
| 205 window_map()->clear(); | 169 window_map()->clear(); |
| 206 } | 170 } |
| 207 | 171 |
| 208 CompositingIOSurfaceContext::CompositingIOSurfaceContext( | 172 CompositingIOSurfaceContext::CompositingIOSurfaceContext( |
| 209 int window_number, | 173 int window_number, |
| 210 NSOpenGLContext* nsgl_context, | 174 NSOpenGLContext* nsgl_context, |
| 211 CGLContextObj cgl_context_strong, | 175 gfx::ScopedCGLContextObjRef cgl_context_strong, |
| 212 CGLContextObj cgl_context, | 176 CGLContextObj cgl_context, |
| 213 bool is_vsync_disabled, | 177 bool is_vsync_disabled, |
| 214 scoped_refptr<DisplayLinkMac> display_link, | 178 scoped_refptr<DisplayLinkMac> display_link, |
| 215 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache) | 179 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache) |
| 216 : window_number_(window_number), | 180 : window_number_(window_number), |
| 217 nsgl_context_(nsgl_context), | 181 nsgl_context_(nsgl_context), |
| 218 cgl_context_strong_(cgl_context_strong), | 182 cgl_context_strong_(cgl_context_strong), |
| 219 cgl_context_(cgl_context), | 183 cgl_context_(cgl_context), |
| 220 is_vsync_disabled_(is_vsync_disabled), | 184 is_vsync_disabled_(is_vsync_disabled), |
| 221 shader_program_cache_(shader_program_cache.Pass()), | 185 shader_program_cache_(shader_program_cache.Pass()), |
| 222 can_be_shared_(true), | 186 can_be_shared_(true), |
| 223 initialized_is_intel_(false), | 187 initialized_is_intel_(false), |
| 224 is_intel_(false), | 188 is_intel_(false), |
| 225 screen_(0), | 189 screen_(0), |
| 226 display_link_(display_link) { | 190 display_link_(display_link) { |
| 227 DCHECK(window_map()->find(window_number_) == window_map()->end()); | 191 DCHECK(window_map()->find(window_number_) == window_map()->end()); |
| 228 window_map()->insert(std::make_pair(window_number_, this)); | 192 window_map()->insert(std::make_pair(window_number_, this)); |
| 229 } | 193 } |
| 230 | 194 |
| 231 CompositingIOSurfaceContext::~CompositingIOSurfaceContext() { | 195 CompositingIOSurfaceContext::~CompositingIOSurfaceContext() { |
| 232 CGLSetCurrentContext(cgl_context_); | 196 { |
| 233 shader_program_cache_->Reset(); | 197 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_); |
| 234 CGLSetCurrentContext(0); | 198 shader_program_cache_->Reset(); |
| 199 } |
| 235 if (can_be_shared_) { | 200 if (can_be_shared_) { |
| 236 DCHECK(window_map()->find(window_number_) != window_map()->end()); | 201 DCHECK(window_map()->find(window_number_) != window_map()->end()); |
| 237 DCHECK(window_map()->find(window_number_)->second == this); | 202 DCHECK(window_map()->find(window_number_)->second == this); |
| 238 window_map()->erase(window_number_); | 203 window_map()->erase(window_number_); |
| 239 } else { | 204 } else { |
| 240 WindowMap::const_iterator found = window_map()->find(window_number_); | 205 WindowMap::const_iterator found = window_map()->find(window_number_); |
| 241 if (found != window_map()->end()) | 206 if (found != window_map()->end()) |
| 242 DCHECK(found->second != this); | 207 DCHECK(found->second != this); |
| 243 } | 208 } |
| 244 if (cgl_context_strong_) | |
| 245 CGLReleaseContext(cgl_context_strong_); | |
| 246 } | 209 } |
| 247 | 210 |
| 248 NSOpenGLContext* CompositingIOSurfaceContext::nsgl_context() const { | 211 NSOpenGLContext* CompositingIOSurfaceContext::nsgl_context() const { |
| 249 // This should not be called from any CoreAnimation paths. | 212 // This should not be called from any CoreAnimation paths. |
| 250 CHECK(GetCoreAnimationStatus() == CORE_ANIMATION_DISABLED); | 213 CHECK(GetCoreAnimationStatus() == CORE_ANIMATION_DISABLED); |
| 251 return nsgl_context_; | 214 return nsgl_context_; |
| 252 } | 215 } |
| 253 | 216 |
| 254 bool CompositingIOSurfaceContext::IsVendorIntel() { | 217 bool CompositingIOSurfaceContext::IsVendorIntel() { |
| 255 GLint screen; | 218 GLint screen; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 269 CompositingIOSurfaceContext::WindowMap* | 232 CompositingIOSurfaceContext::WindowMap* |
| 270 CompositingIOSurfaceContext::window_map() { | 233 CompositingIOSurfaceContext::window_map() { |
| 271 return window_map_.Pointer(); | 234 return window_map_.Pointer(); |
| 272 } | 235 } |
| 273 | 236 |
| 274 // static | 237 // static |
| 275 base::LazyInstance<CompositingIOSurfaceContext::WindowMap> | 238 base::LazyInstance<CompositingIOSurfaceContext::WindowMap> |
| 276 CompositingIOSurfaceContext::window_map_; | 239 CompositingIOSurfaceContext::window_map_; |
| 277 | 240 |
| 278 } // namespace content | 241 } // namespace content |
| OLD | NEW |