1 // Copyright (c) 2012 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 "gpu/command_buffer/client/gl_in_process_context.h" 6 7 #include <set> 8 #include <utility> 9 #include <vector> 10 11 #include <GLES2/gl2.h> 12 #ifndef GL_GLEXT_PROTOTYPES 13 #define GL_GLEXT_PROTOTYPES 1 14 #endif 15 #include <GLES2/gl2ext.h> 16 #include <GLES2/gl2extchromium.h> 17 18 #include "base/bind.h" 19 #include "base/bind_helpers.h" 20 #include "base/lazy_instance.h" 21 #include "base/logging.h" 22 #include "base/memory/scoped_ptr.h" 23 #include "base/memory/weak_ptr.h" 24 #include "base/message_loop/message_loop.h" 25 #include "gpu/command_buffer/client/gles2_implementation.h" 26 #include "gpu/command_buffer/client/transfer_buffer.h" 27 #include "gpu/command_buffer/common/command_buffer.h" 28 #include "gpu/command_buffer/common/constants.h" 29 #include "ui/gfx/size.h" 30 #include "ui/gl/gl_image.h" 31 32 #if defined(OS_ANDROID) 33 #include "ui/gl/android/surface_texture.h" 34 #endif 35 36 namespace gpu { 37 38 namespace { 39 40 const int32 kDefaultCommandBufferSize = 1024 * 1024; 41 const unsigned int kDefaultStartTransferBufferSize = 4 * 1024 * 1024; 42 const unsigned int kDefaultMinTransferBufferSize = 1 * 256 * 1024; 43 const unsigned int kDefaultMaxTransferBufferSize = 16 * 1024 * 1024; 44 45 class GLInProcessContextImpl 46 : public GLInProcessContext, 47 public base::SupportsWeakPtr<GLInProcessContextImpl> { 48 public: 49 explicit GLInProcessContextImpl( 50 const GLInProcessContextSharedMemoryLimits& mem_limits); 51 virtual ~GLInProcessContextImpl(); 52 53 bool Initialize( 54 scoped_refptr<gfx::GLSurface> surface, 55 bool is_offscreen, 56 bool use_global_share_group, 57 GLInProcessContext* share_context, 58 gfx::AcceleratedWidget window, 59 const gfx::Size& size, 60 const gpu::gles2::ContextCreationAttribHelper& attribs, 61 gfx::GpuPreference gpu_preference, 62 const scoped_refptr<InProcessCommandBuffer::Service>& service); 63 64 // GLInProcessContext implementation: 65 virtual void SetContextLostCallback(const base::Closure& callback) OVERRIDE; 66 virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE; 67 virtual size_t GetMappedMemoryLimit() OVERRIDE; 68 69 #if defined(OS_ANDROID) 70 virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture( 71 uint32 stream_id) OVERRIDE; 72 #endif 73 74 private: 75 void Destroy(); 76 void OnContextLost(); 77 void OnSignalSyncPoint(const base::Closure& callback); 78 79 scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_; 80 scoped_ptr<TransferBuffer> transfer_buffer_; 81 scoped_ptr<gles2::GLES2Implementation> gles2_implementation_; 82 scoped_ptr<InProcessCommandBuffer> command_buffer_; 83 84 const GLInProcessContextSharedMemoryLimits mem_limits_; 85 bool context_lost_; 86 base::Closure context_lost_callback_; 87 88 DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl); 89 }; 90 91 base::LazyInstance<base::Lock> g_all_shared_contexts_lock = 92 LAZY_INSTANCE_INITIALIZER; 93 base::LazyInstance<std::set<GLInProcessContextImpl*> > g_all_shared_contexts = 94 LAZY_INSTANCE_INITIALIZER; 95 96 GLInProcessContextImpl::GLInProcessContextImpl( 97 const GLInProcessContextSharedMemoryLimits& mem_limits) 98 : mem_limits_(mem_limits), context_lost_(false) { 99 } 100 101 GLInProcessContextImpl::~GLInProcessContextImpl() { 102 { 103 base::AutoLock lock(g_all_shared_contexts_lock.Get()); 104 g_all_shared_contexts.Get().erase(this); 105 } 106 Destroy(); 107 } 108 109 gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() { 110 return gles2_implementation_.get(); 111 } 112 113 size_t GLInProcessContextImpl::GetMappedMemoryLimit() { 114 return mem_limits_.mapped_memory_reclaim_limit; 115 } 116 117 void GLInProcessContextImpl::SetContextLostCallback( 118 const base::Closure& callback) { 119 context_lost_callback_ = callback; 120 } 121 122 void GLInProcessContextImpl::OnContextLost() { 123 context_lost_ = true; 124 if (!context_lost_callback_.is_null()) { 125 context_lost_callback_.Run(); 126 } 127 } 128 129 bool GLInProcessContextImpl::Initialize( 130 scoped_refptr<gfx::GLSurface> surface, 131 bool is_offscreen, 132 bool use_global_share_group, 133 GLInProcessContext* share_context, 134 gfx::AcceleratedWidget window, 135 const gfx::Size& size, 136 const gles2::ContextCreationAttribHelper& attribs, 137 gfx::GpuPreference gpu_preference, 138 const scoped_refptr<InProcessCommandBuffer::Service>& service) { 139 DCHECK(!use_global_share_group || !share_context); 140 DCHECK(size.width() >= 0 && size.height() >= 0); 141 142 std::vector<int32> attrib_vector; 143 attribs.Serialize(&attrib_vector); 144 145 base::Closure wrapped_callback = 146 base::Bind(&GLInProcessContextImpl::OnContextLost, AsWeakPtr()); 147 command_buffer_.reset(new InProcessCommandBuffer(service)); 148 149 scoped_ptr<base::AutoLock> scoped_shared_context_lock; 150 scoped_refptr<gles2::ShareGroup> share_group; 151 InProcessCommandBuffer* share_command_buffer = NULL; 152 if (use_global_share_group) { 153 scoped_shared_context_lock.reset( 154 new base::AutoLock(g_all_shared_contexts_lock.Get())); 155 for (std::set<GLInProcessContextImpl*>::const_iterator it = 156 g_all_shared_contexts.Get().begin(); 157 it != g_all_shared_contexts.Get().end(); 158 it++) { 159 const GLInProcessContextImpl* context = *it; 160 if (!context->context_lost_) { 161 share_group = context->gles2_implementation_->share_group(); 162 share_command_buffer = context->command_buffer_.get(); 163 DCHECK(share_group.get()); 164 DCHECK(share_command_buffer); 165 break; 166 } 167 } 168 } else if (share_context) { 169 GLInProcessContextImpl* impl = 170 static_cast<GLInProcessContextImpl*>(share_context); 171 share_group = impl->gles2_implementation_->share_group(); 172 share_command_buffer = impl->command_buffer_.get(); 173 DCHECK(share_group.get()); 174 DCHECK(share_command_buffer); 175 } 176 177 if (!command_buffer_->Initialize(surface, 178 is_offscreen, 179 window, 180 size, 181 attrib_vector, 182 gpu_preference, 183 wrapped_callback, 184 share_command_buffer)) { 185 LOG(ERROR) << "Failed to initialize InProcessCommmandBuffer"; 186 return false; 187 } 188 189 // Create the GLES2 helper, which writes the command buffer protocol. 190 gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get())); 191 if (!gles2_helper_->Initialize(mem_limits_.command_buffer_size)) { 192 LOG(ERROR) << "Failed to initialize GLES2CmdHelper"; 193 Destroy(); 194 return false; 195 } 196 197 // Create a transfer buffer. 198 transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get())); 199 200 // Check for consistency. 201 DCHECK(!attribs.bind_generates_resource); 202 bool bind_generates_resource = false; 203 204 // Create the object exposing the OpenGL API. 205 gles2_implementation_.reset( 206 new gles2::GLES2Implementation(gles2_helper_.get(), 207 share_group.get(), 208 transfer_buffer_.get(), 209 bind_generates_resource, 210 attribs.lose_context_when_out_of_memory, 211 command_buffer_.get())); 212 213 if (use_global_share_group) { 214 g_all_shared_contexts.Get().insert(this); 215 scoped_shared_context_lock.reset(); 216 } 217 218 if (!gles2_implementation_->Initialize( 219 mem_limits_.start_transfer_buffer_size, 220 mem_limits_.min_transfer_buffer_size, 221 mem_limits_.max_transfer_buffer_size, 222 mem_limits_.mapped_memory_reclaim_limit)) { 223 return false; 224 } 225 226 return true; 227 } 228 229 void GLInProcessContextImpl::Destroy() { 230 if (gles2_implementation_) { 231 // First flush the context to ensure that any pending frees of resources 232 // are completed. Otherwise, if this context is part of a share group, 233 // those resources might leak. Also, any remaining side effects of commands 234 // issued on this context might not be visible to other contexts in the 235 // share group. 236 gles2_implementation_->Flush(); 237 238 gles2_implementation_.reset(); 239 } 240 241 transfer_buffer_.reset(); 242 gles2_helper_.reset(); 243 command_buffer_.reset(); 244 } 245 246 #if defined(OS_ANDROID) 247 scoped_refptr<gfx::SurfaceTexture> 248 GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id) { 249 return command_buffer_->GetSurfaceTexture(stream_id); 250 } 251 #endif 252 253 } // anonymous namespace 254 255 GLInProcessContextSharedMemoryLimits::GLInProcessContextSharedMemoryLimits() 256 : command_buffer_size(kDefaultCommandBufferSize), 257 start_transfer_buffer_size(kDefaultStartTransferBufferSize), 258 min_transfer_buffer_size(kDefaultMinTransferBufferSize), 259 max_transfer_buffer_size(kDefaultMaxTransferBufferSize), 260 mapped_memory_reclaim_limit(gles2::GLES2Implementation::kNoLimit) { 261 } 262 263 // static 264 GLInProcessContext* GLInProcessContext::Create( 265 scoped_refptr<gpu::InProcessCommandBuffer::Service> service, 266 scoped_refptr<gfx::GLSurface> surface, 267 bool is_offscreen, 268 gfx::AcceleratedWidget window, 269 const gfx::Size& size, 270 GLInProcessContext* share_context, 271 bool use_global_share_group, 272 const ::gpu::gles2::ContextCreationAttribHelper& attribs, 273 gfx::GpuPreference gpu_preference, 274 const GLInProcessContextSharedMemoryLimits& memory_limits) { 275 DCHECK(!use_global_share_group || !share_context); 276 if (surface.get()) { 277 DCHECK_EQ(surface->IsOffscreen(), is_offscreen); 278 DCHECK(surface->GetSize() == size); 279 DCHECK_EQ(gfx::kNullAcceleratedWidget, window); 280 } 281 282 scoped_ptr<GLInProcessContextImpl> context( 283 new GLInProcessContextImpl(memory_limits)); 284 if (!context->Initialize(surface, 285 is_offscreen, 286 use_global_share_group, 287 share_context, 288 window, 289 size, 290 attribs, 291 gpu_preference, 292 service)) 293 return NULL; 294 295 return context.release(); 296 } 297 298 } // namespace gpu 299