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