| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "gpu/command_buffer/client/gl_in_process_context.h" | 5 #include "gpu/command_buffer/client/gl_in_process_context.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include <GLES2/gl2.h> | 10 #include <GLES2/gl2.h> |
| 11 #ifndef GL_GLEXT_PROTOTYPES | 11 #ifndef GL_GLEXT_PROTOTYPES |
| 12 #define GL_GLEXT_PROTOTYPES 1 | 12 #define GL_GLEXT_PROTOTYPES 1 |
| 13 #endif | 13 #endif |
| 14 #include <GLES2/gl2ext.h> | 14 #include <GLES2/gl2ext.h> |
| 15 #include <GLES2/gl2extchromium.h> | 15 #include <GLES2/gl2extchromium.h> |
| 16 | 16 |
| 17 #include "base/bind.h" | 17 #include "base/bind.h" |
| 18 #include "base/bind_helpers.h" | 18 #include "base/bind_helpers.h" |
| 19 #include "base/callback.h" | |
| 20 #include "base/lazy_instance.h" | 19 #include "base/lazy_instance.h" |
| 21 #include "base/logging.h" | 20 #include "base/logging.h" |
| 22 #include "base/memory/scoped_ptr.h" | 21 #include "base/memory/scoped_ptr.h" |
| 23 #include "base/memory/weak_ptr.h" | 22 #include "base/memory/weak_ptr.h" |
| 24 #include "base/message_loop/message_loop.h" | 23 #include "base/message_loop/message_loop.h" |
| 25 #include "base/synchronization/lock.h" | |
| 26 #include "gpu/command_buffer/client/gles2_implementation.h" | 24 #include "gpu/command_buffer/client/gles2_implementation.h" |
| 27 #include "gpu/command_buffer/client/gpu_memory_buffer.h" | 25 #include "gpu/command_buffer/client/gpu_memory_buffer.h" |
| 28 #include "gpu/command_buffer/client/image_factory.h" | 26 #include "gpu/command_buffer/client/image_factory.h" |
| 29 #include "gpu/command_buffer/client/transfer_buffer.h" | 27 #include "gpu/command_buffer/client/transfer_buffer.h" |
| 28 #include "gpu/command_buffer/common/command_buffer.h" |
| 30 #include "gpu/command_buffer/common/constants.h" | 29 #include "gpu/command_buffer/common/constants.h" |
| 31 #include "gpu/command_buffer/common/id_allocator.h" | 30 #include "gpu/command_buffer/service/in_process_command_buffer.h" |
| 32 #include "gpu/command_buffer/service/command_buffer_service.h" | |
| 33 #include "gpu/command_buffer/service/context_group.h" | |
| 34 #include "gpu/command_buffer/service/gl_context_virtual.h" | |
| 35 #include "gpu/command_buffer/service/gpu_scheduler.h" | |
| 36 #include "gpu/command_buffer/service/image_manager.h" | |
| 37 #include "gpu/command_buffer/service/transfer_buffer_manager.h" | |
| 38 #include "ui/gfx/size.h" | 31 #include "ui/gfx/size.h" |
| 39 #include "ui/gl/gl_context.h" | |
| 40 #include "ui/gl/gl_image.h" | 32 #include "ui/gl/gl_image.h" |
| 41 #include "ui/gl/gl_share_group.h" | |
| 42 #include "ui/gl/gl_surface.h" | |
| 43 | 33 |
| 44 namespace gpu { | 34 namespace gpu { |
| 45 | 35 |
| 46 using gles2::ImageManager; | |
| 47 | |
| 48 namespace { | 36 namespace { |
| 49 | 37 |
| 50 const int32 kCommandBufferSize = 1024 * 1024; | 38 const int32 kCommandBufferSize = 1024 * 1024; |
| 51 // TODO(kbr): make the transfer buffer size configurable via context | 39 // TODO(kbr): make the transfer buffer size configurable via context |
| 52 // creation attributes. | 40 // creation attributes. |
| 53 const size_t kStartTransferBufferSize = 4 * 1024 * 1024; | 41 const size_t kStartTransferBufferSize = 4 * 1024 * 1024; |
| 54 const size_t kMinTransferBufferSize = 1 * 256 * 1024; | 42 const size_t kMinTransferBufferSize = 1 * 256 * 1024; |
| 55 const size_t kMaxTransferBufferSize = 16 * 1024 * 1024; | 43 const size_t kMaxTransferBufferSize = 16 * 1024 * 1024; |
| 56 | 44 |
| 57 // In the normal command buffer implementation, all commands are passed over IPC | |
| 58 // to the gpu process where they are fed to the GLES2Decoder from a single | |
| 59 // thread. In layout tests, any thread could call this function. GLES2Decoder, | |
| 60 // and in particular the GL implementations behind it, are not generally | |
| 61 // threadsafe, so we guard entry points with a mutex. | |
| 62 static base::LazyInstance<base::Lock> g_decoder_lock = | |
| 63 LAZY_INSTANCE_INITIALIZER; | |
| 64 | |
| 65 class GLInProcessContextImpl; | |
| 66 | |
| 67 static base::LazyInstance< | |
| 68 std::set<GLInProcessContextImpl*> > | |
| 69 g_all_shared_contexts = LAZY_INSTANCE_INITIALIZER; | |
| 70 | |
| 71 static bool g_use_virtualized_gl_context = false; | |
| 72 | |
| 73 static GLInProcessContext::GpuMemoryBufferCreator* g_gpu_memory_buffer_creator = | 45 static GLInProcessContext::GpuMemoryBufferCreator* g_gpu_memory_buffer_creator = |
| 74 NULL; | 46 NULL; |
| 75 | 47 |
| 76 // Also calls DetachFromThreadHack on all GLES2Decoders before the lock is | |
| 77 // released to maintain the invariant that all decoders are unbound while the | |
| 78 // lock is not held. This is to workaround DumpRenderTree using WGC3DIPCBI with | |
| 79 // shared resources on different threads. | |
| 80 // Remove this as part of crbug.com/234964. | |
| 81 class AutoLockAndDecoderDetachThread { | |
| 82 public: | |
| 83 AutoLockAndDecoderDetachThread( | |
| 84 base::Lock& lock, | |
| 85 const std::set<GLInProcessContextImpl*>& contexts); | |
| 86 ~AutoLockAndDecoderDetachThread(); | |
| 87 | |
| 88 private: | |
| 89 base::AutoLock auto_lock_; | |
| 90 const std::set<GLInProcessContextImpl*>& contexts_; | |
| 91 }; | |
| 92 | |
| 93 class GLInProcessContextImpl | 48 class GLInProcessContextImpl |
| 94 : public GLInProcessContext, | 49 : public GLInProcessContext, |
| 95 public gles2::ImageFactory, | 50 public gles2::ImageFactory, |
| 96 public base::SupportsWeakPtr<GLInProcessContextImpl> { | 51 public base::SupportsWeakPtr<GLInProcessContextImpl> { |
| 97 public: | 52 public: |
| 98 explicit GLInProcessContextImpl(bool share_resources); | 53 explicit GLInProcessContextImpl(); |
| 99 virtual ~GLInProcessContextImpl(); | 54 virtual ~GLInProcessContextImpl(); |
| 100 | 55 |
| 101 bool Initialize(bool is_offscreen, | 56 bool Initialize(bool is_offscreen, |
| 57 bool share_resources, |
| 102 gfx::AcceleratedWidget window, | 58 gfx::AcceleratedWidget window, |
| 103 const gfx::Size& size, | 59 const gfx::Size& size, |
| 104 const char* allowed_extensions, | 60 const char* allowed_extensions, |
| 105 const int32* attrib_list, | 61 const int32* attrib_list, |
| 106 gfx::GpuPreference gpu_preference, | 62 gfx::GpuPreference gpu_preference, |
| 107 const base::Closure& context_lost_callback); | 63 const base::Closure& context_lost_callback); |
| 108 | 64 |
| 109 // GLInProcessContext implementation: | 65 // GLInProcessContext implementation: |
| 110 virtual void SignalSyncPoint(unsigned sync_point, | 66 virtual void SignalSyncPoint(unsigned sync_point, |
| 111 const base::Closure& callback) OVERRIDE; | 67 const base::Closure& callback) OVERRIDE; |
| 112 virtual void SignalQuery(unsigned query, const base::Closure& callback) | 68 virtual void SignalQuery(unsigned query, const base::Closure& callback) |
| 113 OVERRIDE; | 69 OVERRIDE; |
| 114 virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE; | 70 virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE; |
| 115 | 71 |
| 116 // ImageFactory implementation: | 72 // ImageFactory implementation: |
| 117 virtual scoped_ptr<GpuMemoryBuffer> CreateGpuMemoryBuffer( | 73 virtual scoped_ptr<GpuMemoryBuffer> CreateGpuMemoryBuffer( |
| 118 int width, int height, GLenum internalformat, | 74 int width, int height, GLenum internalformat, |
| 119 unsigned* image_id) OVERRIDE; | 75 unsigned* image_id) OVERRIDE; |
| 120 virtual void DeleteGpuMemoryBuffer(unsigned image_id) OVERRIDE; | 76 virtual void DeleteGpuMemoryBuffer(unsigned image_id) OVERRIDE; |
| 121 | 77 |
| 122 // Other methods: | |
| 123 gles2::GLES2Decoder* GetDecoder(); | |
| 124 bool GetBufferChanged(int32 transfer_buffer_id); | |
| 125 void PumpCommands(); | |
| 126 void OnResizeView(gfx::Size size, float scale_factor); | |
| 127 void OnContextLost(); | |
| 128 | |
| 129 private: | 78 private: |
| 130 void Destroy(); | 79 void Destroy(); |
| 131 bool IsCommandBufferContextLost(); | |
| 132 void PollQueryCallbacks(); | 80 void PollQueryCallbacks(); |
| 133 void CallQueryCallback(size_t index); | 81 void CallQueryCallback(size_t index); |
| 134 bool MakeCurrent(); | |
| 135 | 82 |
| 136 gles2::ImageManager* GetImageManager(); | |
| 137 | |
| 138 base::Closure context_lost_callback_; | |
| 139 scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; | |
| 140 scoped_ptr<CommandBuffer> command_buffer_; | |
| 141 scoped_ptr<GpuScheduler> gpu_scheduler_; | |
| 142 scoped_ptr<gles2::GLES2Decoder> decoder_; | |
| 143 scoped_refptr<gfx::GLContext> context_; | |
| 144 scoped_refptr<gfx::GLSurface> surface_; | |
| 145 scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_; | 83 scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_; |
| 146 scoped_ptr<TransferBuffer> transfer_buffer_; | 84 scoped_ptr<TransferBuffer> transfer_buffer_; |
| 147 scoped_ptr<gles2::GLES2Implementation> gles2_implementation_; | 85 scoped_ptr<gles2::GLES2Implementation> gles2_implementation_; |
| 148 bool share_resources_; | 86 scoped_ptr<InProcessCommandBuffer> command_buffer_; |
| 149 bool context_lost_; | |
| 150 | 87 |
| 151 typedef std::pair<unsigned, base::Closure> QueryCallback; | 88 typedef std::pair<unsigned, base::Closure> QueryCallback; |
| 152 std::vector<QueryCallback> query_callbacks_; | 89 std::vector<QueryCallback> query_callbacks_; |
| 153 | 90 |
| 154 std::vector<base::Closure> signal_sync_point_callbacks_; | |
| 155 | |
| 156 DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl); | 91 DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl); |
| 157 }; | 92 }; |
| 158 | 93 |
| 159 AutoLockAndDecoderDetachThread::AutoLockAndDecoderDetachThread( | |
| 160 base::Lock& lock, | |
| 161 const std::set<GLInProcessContextImpl*>& contexts) | |
| 162 : auto_lock_(lock), | |
| 163 contexts_(contexts) { | |
| 164 } | |
| 165 | |
| 166 void DetachThread(GLInProcessContextImpl* context) { | |
| 167 if (context->GetDecoder()) | |
| 168 context->GetDecoder()->DetachFromThreadHack(); | |
| 169 } | |
| 170 | |
| 171 AutoLockAndDecoderDetachThread::~AutoLockAndDecoderDetachThread() { | |
| 172 std::for_each(contexts_.begin(), | |
| 173 contexts_.end(), | |
| 174 &DetachThread); | |
| 175 } | |
| 176 | |
| 177 scoped_ptr<GpuMemoryBuffer> GLInProcessContextImpl::CreateGpuMemoryBuffer( | 94 scoped_ptr<GpuMemoryBuffer> GLInProcessContextImpl::CreateGpuMemoryBuffer( |
| 178 int width, int height, GLenum internalformat, unsigned int* image_id) { | 95 int width, int height, GLenum internalformat, unsigned int* image_id) { |
| 179 // We're taking the lock here because we're accessing the ContextGroup's | |
| 180 // shared IdManager. | |
| 181 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), | |
| 182 g_all_shared_contexts.Get()); | |
| 183 // For Android WebView we assume the |internalformat| will always be | 96 // For Android WebView we assume the |internalformat| will always be |
| 184 // GL_RGBA8_OES. | 97 // GL_RGBA8_OES. |
| 185 DCHECK_EQ(static_cast<GLenum>(GL_RGBA8_OES), internalformat); | 98 DCHECK_EQ(static_cast<GLenum>(GL_RGBA8_OES), internalformat); |
| 186 scoped_ptr<GpuMemoryBuffer> buffer = | 99 scoped_ptr<GpuMemoryBuffer> buffer = |
| 187 g_gpu_memory_buffer_creator(width, height); | 100 g_gpu_memory_buffer_creator(width, height); |
| 188 | 101 |
| 189 if (buffer.get() == NULL) | 102 if (buffer.get() == NULL) |
| 190 return buffer.Pass(); | 103 return buffer.Pass(); |
| 191 | 104 |
| 192 scoped_refptr<gfx::GLImage> gl_image = | 105 *image_id = command_buffer_->CreateImageForGpuMemoryBuffer( |
| 193 gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer->GetNativeBuffer(), | 106 buffer->GetNativeBuffer(), gfx::Size(width, height)); |
| 194 gfx::Size(width, height)); | |
| 195 *image_id = decoder_->GetContextGroup() | |
| 196 ->GetIdAllocator(gles2::id_namespaces::kImages)->AllocateID(); | |
| 197 GetImageManager()->AddImage(gl_image.get(), *image_id); | |
| 198 return buffer.Pass(); | 107 return buffer.Pass(); |
| 199 } | 108 } |
| 200 | 109 |
| 201 void GLInProcessContextImpl::DeleteGpuMemoryBuffer(unsigned int image_id) { | 110 void GLInProcessContextImpl::DeleteGpuMemoryBuffer(unsigned int image_id) { |
| 202 // We're taking the lock here because we're accessing the ContextGroup's | 111 command_buffer_->RemoveImage(image_id); |
| 203 // shared ImageManager. | |
| 204 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), | |
| 205 g_all_shared_contexts.Get()); | |
| 206 GetImageManager()->RemoveImage(image_id); | |
| 207 decoder_->GetContextGroup()->GetIdAllocator(gles2::id_namespaces::kImages) | |
| 208 ->FreeID(image_id); | |
| 209 } | 112 } |
| 210 | 113 |
| 211 GLInProcessContextImpl::GLInProcessContextImpl(bool share_resources) | 114 GLInProcessContextImpl::GLInProcessContextImpl() {} |
| 212 : share_resources_(share_resources), | |
| 213 context_lost_(false) { | |
| 214 } | |
| 215 | 115 |
| 216 GLInProcessContextImpl::~GLInProcessContextImpl() { | 116 GLInProcessContextImpl::~GLInProcessContextImpl() { |
| 217 Destroy(); | 117 Destroy(); |
| 218 } | 118 } |
| 219 | 119 |
| 220 bool GLInProcessContextImpl::MakeCurrent() { | |
| 221 if (decoder_->MakeCurrent()) | |
| 222 return true; | |
| 223 DLOG(ERROR) << "Context lost because MakeCurrent failed."; | |
| 224 command_buffer_->SetContextLostReason(decoder_->GetContextLostReason()); | |
| 225 command_buffer_->SetParseError(gpu::error::kLostContext); | |
| 226 return false; | |
| 227 } | |
| 228 | |
| 229 void GLInProcessContextImpl::PumpCommands() { | |
| 230 { | |
| 231 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), | |
| 232 g_all_shared_contexts.Get()); | |
| 233 if (!MakeCurrent()) | |
| 234 return; | |
| 235 gpu_scheduler_->PutChanged(); | |
| 236 CommandBuffer::State state = command_buffer_->GetState(); | |
| 237 DCHECK((!error::IsError(state.error) && !context_lost_) || | |
| 238 (error::IsError(state.error) && context_lost_)); | |
| 239 } | |
| 240 | |
| 241 if (!context_lost_ && signal_sync_point_callbacks_.size()) { | |
| 242 for (size_t n = 0; n < signal_sync_point_callbacks_.size(); n++) { | |
| 243 base::MessageLoop::current()->PostTask(FROM_HERE, | |
| 244 signal_sync_point_callbacks_[n]); | |
| 245 } | |
| 246 } | |
| 247 signal_sync_point_callbacks_.clear(); | |
| 248 } | |
| 249 | |
| 250 bool GLInProcessContextImpl::GetBufferChanged(int32 transfer_buffer_id) { | |
| 251 return gpu_scheduler_->SetGetBuffer(transfer_buffer_id); | |
| 252 } | |
| 253 | |
| 254 void GLInProcessContextImpl::SignalSyncPoint(unsigned sync_point, | 120 void GLInProcessContextImpl::SignalSyncPoint(unsigned sync_point, |
| 255 const base::Closure& callback) { | 121 const base::Closure& callback) { |
| 256 DCHECK(!callback.is_null()); | 122 DCHECK(!callback.is_null()); |
| 257 signal_sync_point_callbacks_.push_back(callback); | 123 command_buffer_->SignalSyncPoint(sync_point, callback); |
| 258 } | |
| 259 | |
| 260 bool GLInProcessContextImpl::IsCommandBufferContextLost() { | |
| 261 if (context_lost_ || !command_buffer_) { | |
| 262 return true; | |
| 263 } | |
| 264 CommandBuffer::State state = command_buffer_->GetState(); | |
| 265 return error::IsError(state.error); | |
| 266 } | |
| 267 | |
| 268 gles2::GLES2Decoder* GLInProcessContextImpl::GetDecoder() { | |
| 269 return decoder_.get(); | |
| 270 } | |
| 271 | |
| 272 void GLInProcessContextImpl::OnResizeView(gfx::Size size, float scale_factor) { | |
| 273 DCHECK(!surface_->IsOffscreen()); | |
| 274 surface_->Resize(size); | |
| 275 } | 124 } |
| 276 | 125 |
| 277 gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() { | 126 gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() { |
| 278 return gles2_implementation_.get(); | 127 return gles2_implementation_.get(); |
| 279 } | 128 } |
| 280 | 129 |
| 281 gles2::ImageManager* GLInProcessContextImpl::GetImageManager() { | |
| 282 return decoder_->GetContextGroup()->image_manager(); | |
| 283 } | |
| 284 | |
| 285 bool GLInProcessContextImpl::Initialize( | 130 bool GLInProcessContextImpl::Initialize( |
| 286 bool is_offscreen, | 131 bool is_offscreen, |
| 132 bool share_resources, |
| 287 gfx::AcceleratedWidget window, | 133 gfx::AcceleratedWidget window, |
| 288 const gfx::Size& size, | 134 const gfx::Size& size, |
| 289 const char* allowed_extensions, | 135 const char* allowed_extensions, |
| 290 const int32* attrib_list, | 136 const int32* attrib_list, |
| 291 gfx::GpuPreference gpu_preference, | 137 gfx::GpuPreference gpu_preference, |
| 292 const base::Closure& context_lost_callback) { | 138 const base::Closure& context_lost_callback) { |
| 293 // Use one share group for all contexts. | |
| 294 CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group, | |
| 295 (new gfx::GLShareGroup)); | |
| 296 | |
| 297 DCHECK(size.width() >= 0 && size.height() >= 0); | 139 DCHECK(size.width() >= 0 && size.height() >= 0); |
| 298 | 140 |
| 299 std::vector<int32> attribs; | 141 std::vector<int32> attribs; |
| 300 while (attrib_list) { | 142 while (attrib_list) { |
| 301 int32 attrib = *attrib_list++; | 143 int32 attrib = *attrib_list++; |
| 302 switch (attrib) { | 144 switch (attrib) { |
| 303 // Known attributes | 145 // Known attributes |
| 304 case ALPHA_SIZE: | 146 case ALPHA_SIZE: |
| 305 case BLUE_SIZE: | 147 case BLUE_SIZE: |
| 306 case GREEN_SIZE: | 148 case GREEN_SIZE: |
| 307 case RED_SIZE: | 149 case RED_SIZE: |
| 308 case DEPTH_SIZE: | 150 case DEPTH_SIZE: |
| 309 case STENCIL_SIZE: | 151 case STENCIL_SIZE: |
| 310 case SAMPLES: | 152 case SAMPLES: |
| 311 case SAMPLE_BUFFERS: | 153 case SAMPLE_BUFFERS: |
| 312 attribs.push_back(attrib); | 154 attribs.push_back(attrib); |
| 313 attribs.push_back(*attrib_list++); | 155 attribs.push_back(*attrib_list++); |
| 314 break; | 156 break; |
| 315 case NONE: | 157 case NONE: |
| 316 attribs.push_back(attrib); | 158 attribs.push_back(attrib); |
| 317 attrib_list = NULL; | 159 attrib_list = NULL; |
| 318 break; | 160 break; |
| 319 default: | 161 default: |
| 320 attribs.push_back(NONE); | 162 attribs.push_back(NONE); |
| 321 attrib_list = NULL; | 163 attrib_list = NULL; |
| 322 break; | 164 break; |
| 323 } | 165 } |
| 324 } | 166 } |
| 325 | 167 |
| 326 { | 168 command_buffer_.reset(new InProcessCommandBuffer()); |
| 327 TransferBufferManager* manager = new TransferBufferManager(); | 169 scoped_refptr<gles2::ShareGroup> share_group; |
| 328 transfer_buffer_manager_.reset(manager); | 170 if (!command_buffer_->Initialize(is_offscreen, |
| 329 manager->Initialize(); | 171 share_resources, |
| 330 } | 172 window, |
| 331 | 173 size, |
| 332 scoped_ptr<CommandBufferService> command_buffer( | 174 allowed_extensions, |
| 333 new CommandBufferService(transfer_buffer_manager_.get())); | 175 attribs, |
| 334 command_buffer->SetPutOffsetChangeCallback(base::Bind( | 176 gpu_preference, |
| 335 &GLInProcessContextImpl::PumpCommands, base::Unretained(this))); | 177 context_lost_callback, |
| 336 command_buffer->SetGetBufferChangeCallback(base::Bind( | 178 &share_group)) { |
| 337 &GLInProcessContextImpl::GetBufferChanged, base::Unretained(this))); | 179 LOG(INFO) << "Failed to initialize InProcessCommmandBuffer"; |
| 338 command_buffer->SetParseErrorCallback(base::Bind( | |
| 339 &GLInProcessContextImpl::OnContextLost, base::Unretained(this))); | |
| 340 | |
| 341 command_buffer_ = command_buffer.Pass(); | |
| 342 if (!command_buffer_->Initialize()) { | |
| 343 LOG(ERROR) << "Could not initialize command buffer."; | |
| 344 Destroy(); | |
| 345 return false; | 180 return false; |
| 346 } | 181 } |
| 347 | 182 DCHECK(share_resources == !!share_group.get()); |
| 348 GLInProcessContextImpl* context_group = NULL; | |
| 349 | |
| 350 { | |
| 351 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), | |
| 352 g_all_shared_contexts.Get()); | |
| 353 if (share_resources_ && !g_all_shared_contexts.Get().empty()) { | |
| 354 for (std::set<GLInProcessContextImpl*>::iterator it = | |
| 355 g_all_shared_contexts.Get().begin(); | |
| 356 it != g_all_shared_contexts.Get().end(); | |
| 357 ++it) { | |
| 358 if (!(*it)->IsCommandBufferContextLost()) { | |
| 359 context_group = *it; | |
| 360 break; | |
| 361 } | |
| 362 } | |
| 363 if (!context_group) | |
| 364 share_group = new gfx::GLShareGroup; | |
| 365 } | |
| 366 | |
| 367 // TODO(gman): This needs to be true if this is Pepper. | |
| 368 bool bind_generates_resource = false; | |
| 369 decoder_.reset(gles2::GLES2Decoder::Create( | |
| 370 context_group ? context_group->decoder_->GetContextGroup() | |
| 371 : new gles2::ContextGroup( | |
| 372 NULL, NULL, NULL, NULL, bind_generates_resource))); | |
| 373 | |
| 374 gpu_scheduler_.reset(new GpuScheduler(command_buffer_.get(), | |
| 375 decoder_.get(), | |
| 376 decoder_.get())); | |
| 377 | |
| 378 decoder_->set_engine(gpu_scheduler_.get()); | |
| 379 | |
| 380 if (is_offscreen) | |
| 381 surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size); | |
| 382 else | |
| 383 surface_ = gfx::GLSurface::CreateViewGLSurface(window); | |
| 384 | |
| 385 if (!surface_.get()) { | |
| 386 LOG(ERROR) << "Could not create GLSurface."; | |
| 387 Destroy(); | |
| 388 return false; | |
| 389 } | |
| 390 | |
| 391 if (g_use_virtualized_gl_context) { | |
| 392 context_ = share_group->GetSharedContext(); | |
| 393 if (!context_.get()) { | |
| 394 context_ = gfx::GLContext::CreateGLContext( | |
| 395 share_group.get(), surface_.get(), gpu_preference); | |
| 396 share_group->SetSharedContext(context_.get()); | |
| 397 } | |
| 398 | |
| 399 context_ = new GLContextVirtual( | |
| 400 share_group.get(), context_.get(), decoder_->AsWeakPtr()); | |
| 401 if (context_->Initialize(surface_.get(), gpu_preference)) { | |
| 402 VLOG(1) << "Created virtual GL context."; | |
| 403 } else { | |
| 404 context_ = NULL; | |
| 405 } | |
| 406 } else { | |
| 407 context_ = gfx::GLContext::CreateGLContext(share_group.get(), | |
| 408 surface_.get(), | |
| 409 gpu_preference); | |
| 410 } | |
| 411 | |
| 412 if (!context_.get()) { | |
| 413 LOG(ERROR) << "Could not create GLContext."; | |
| 414 Destroy(); | |
| 415 return false; | |
| 416 } | |
| 417 | |
| 418 if (!context_->MakeCurrent(surface_.get())) { | |
| 419 LOG(ERROR) << "Could not make context current."; | |
| 420 Destroy(); | |
| 421 return false; | |
| 422 } | |
| 423 | |
| 424 gles2::DisallowedFeatures disallowed_features; | |
| 425 disallowed_features.swap_buffer_complete_callback = true; | |
| 426 disallowed_features.gpu_memory_manager = true; | |
| 427 if (!decoder_->Initialize(surface_, | |
| 428 context_, | |
| 429 is_offscreen, | |
| 430 size, | |
| 431 disallowed_features, | |
| 432 allowed_extensions, | |
| 433 attribs)) { | |
| 434 LOG(ERROR) << "Could not initialize decoder."; | |
| 435 Destroy(); | |
| 436 return false; | |
| 437 } | |
| 438 | |
| 439 if (!is_offscreen) { | |
| 440 decoder_->SetResizeCallback(base::Bind( | |
| 441 &GLInProcessContextImpl::OnResizeView, base::Unretained(this))); | |
| 442 } | |
| 443 } | |
| 444 | 183 |
| 445 // Create the GLES2 helper, which writes the command buffer protocol. | 184 // Create the GLES2 helper, which writes the command buffer protocol. |
| 446 gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get())); | 185 gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get())); |
| 447 if (!gles2_helper_->Initialize(kCommandBufferSize)) { | 186 if (!gles2_helper_->Initialize(kCommandBufferSize)) { |
| 187 LOG(INFO) << "Failed to initialize GLES2CmdHelper"; |
| 448 Destroy(); | 188 Destroy(); |
| 449 return false; | 189 return false; |
| 450 } | 190 } |
| 451 | 191 |
| 452 // Create a transfer buffer. | 192 // Create a transfer buffer. |
| 453 transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get())); | 193 transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get())); |
| 454 | 194 |
| 455 // Create the object exposing the OpenGL API. | 195 // Create the object exposing the OpenGL API. |
| 456 gles2_implementation_.reset(new gles2::GLES2Implementation( | 196 gles2_implementation_.reset(new gles2::GLES2Implementation( |
| 457 gles2_helper_.get(), | 197 gles2_helper_.get(), |
| 458 context_group ? context_group->GetImplementation()->share_group() : NULL, | 198 share_group, |
| 459 transfer_buffer_.get(), | 199 transfer_buffer_.get(), |
| 460 true, | 200 true, |
| 461 false, | 201 false, |
| 462 this)); | 202 this)); |
| 463 | 203 |
| 464 if (!gles2_implementation_->Initialize( | 204 if (!gles2_implementation_->Initialize( |
| 465 kStartTransferBufferSize, | 205 kStartTransferBufferSize, |
| 466 kMinTransferBufferSize, | 206 kMinTransferBufferSize, |
| 467 kMaxTransferBufferSize)) { | 207 kMaxTransferBufferSize)) { |
| 468 return false; | 208 return false; |
| 469 } | 209 } |
| 470 | 210 |
| 471 if (share_resources_) { | |
| 472 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), | |
| 473 g_all_shared_contexts.Get()); | |
| 474 g_all_shared_contexts.Pointer()->insert(this); | |
| 475 } | |
| 476 | |
| 477 context_lost_callback_ = context_lost_callback; | |
| 478 return true; | 211 return true; |
| 479 } | 212 } |
| 480 | 213 |
| 481 void GLInProcessContextImpl::Destroy() { | 214 void GLInProcessContextImpl::Destroy() { |
| 482 while (!query_callbacks_.empty()) { | 215 while (!query_callbacks_.empty()) { |
| 483 CallQueryCallback(0); | 216 CallQueryCallback(0); |
| 484 } | 217 } |
| 485 | 218 |
| 486 bool context_lost = IsCommandBufferContextLost(); | |
| 487 | |
| 488 if (gles2_implementation_) { | 219 if (gles2_implementation_) { |
| 489 // First flush the context to ensure that any pending frees of resources | 220 // First flush the context to ensure that any pending frees of resources |
| 490 // are completed. Otherwise, if this context is part of a share group, | 221 // are completed. Otherwise, if this context is part of a share group, |
| 491 // those resources might leak. Also, any remaining side effects of commands | 222 // those resources might leak. Also, any remaining side effects of commands |
| 492 // issued on this context might not be visible to other contexts in the | 223 // issued on this context might not be visible to other contexts in the |
| 493 // share group. | 224 // share group. |
| 494 gles2_implementation_->Flush(); | 225 gles2_implementation_->Flush(); |
| 495 | 226 |
| 496 gles2_implementation_.reset(); | 227 gles2_implementation_.reset(); |
| 497 } | 228 } |
| 498 | 229 |
| 499 transfer_buffer_.reset(); | 230 transfer_buffer_.reset(); |
| 500 gles2_helper_.reset(); | 231 gles2_helper_.reset(); |
| 501 command_buffer_.reset(); | 232 command_buffer_.reset(); |
| 502 | |
| 503 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), | |
| 504 g_all_shared_contexts.Get()); | |
| 505 if (decoder_) { | |
| 506 decoder_->Destroy(!context_lost); | |
| 507 } | |
| 508 | |
| 509 g_all_shared_contexts.Pointer()->erase(this); | |
| 510 } | |
| 511 | |
| 512 void GLInProcessContextImpl::OnContextLost() { | |
| 513 if (!context_lost_callback_.is_null()) | |
| 514 context_lost_callback_.Run(); | |
| 515 | |
| 516 context_lost_ = true; | |
| 517 if (share_resources_) { | |
| 518 for (std::set<GLInProcessContextImpl*>::iterator it = | |
| 519 g_all_shared_contexts.Get().begin(); | |
| 520 it != g_all_shared_contexts.Get().end(); | |
| 521 ++it) | |
| 522 (*it)->context_lost_ = true; | |
| 523 } | |
| 524 } | 233 } |
| 525 | 234 |
| 526 void GLInProcessContextImpl::CallQueryCallback(size_t index) { | 235 void GLInProcessContextImpl::CallQueryCallback(size_t index) { |
| 527 DCHECK_LT(index, query_callbacks_.size()); | 236 DCHECK_LT(index, query_callbacks_.size()); |
| 528 QueryCallback query_callback = query_callbacks_[index]; | 237 QueryCallback query_callback = query_callbacks_[index]; |
| 529 query_callbacks_[index] = query_callbacks_.back(); | 238 query_callbacks_[index] = query_callbacks_.back(); |
| 530 query_callbacks_.pop_back(); | 239 query_callbacks_.pop_back(); |
| 531 query_callback.second.Run(); | 240 query_callback.second.Run(); |
| 532 } | 241 } |
| 533 | 242 |
| 243 // TODO(sievers): Move this to the service side |
| 534 void GLInProcessContextImpl::PollQueryCallbacks() { | 244 void GLInProcessContextImpl::PollQueryCallbacks() { |
| 535 for (size_t i = 0; i < query_callbacks_.size();) { | 245 for (size_t i = 0; i < query_callbacks_.size();) { |
| 536 unsigned query = query_callbacks_[i].first; | 246 unsigned query = query_callbacks_[i].first; |
| 537 GLuint param = 0; | 247 GLuint param = 0; |
| 538 gles2::GLES2Implementation* gl = GetImplementation(); | 248 gles2::GLES2Implementation* gl = GetImplementation(); |
| 539 if (gl->IsQueryEXT(query)) { | 249 if (gl->IsQueryEXT(query)) { |
| 540 gl->GetQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, ¶m); | 250 gl->GetQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, ¶m); |
| 541 } else { | 251 } else { |
| 542 param = 1; | 252 param = 1; |
| 543 } | 253 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 572 GLInProcessContext* GLInProcessContext::CreateContext( | 282 GLInProcessContext* GLInProcessContext::CreateContext( |
| 573 bool is_offscreen, | 283 bool is_offscreen, |
| 574 gfx::AcceleratedWidget window, | 284 gfx::AcceleratedWidget window, |
| 575 const gfx::Size& size, | 285 const gfx::Size& size, |
| 576 bool share_resources, | 286 bool share_resources, |
| 577 const char* allowed_extensions, | 287 const char* allowed_extensions, |
| 578 const int32* attrib_list, | 288 const int32* attrib_list, |
| 579 gfx::GpuPreference gpu_preference, | 289 gfx::GpuPreference gpu_preference, |
| 580 const base::Closure& callback) { | 290 const base::Closure& callback) { |
| 581 scoped_ptr<GLInProcessContextImpl> context( | 291 scoped_ptr<GLInProcessContextImpl> context( |
| 582 new GLInProcessContextImpl(share_resources)); | 292 new GLInProcessContextImpl()); |
| 583 if (!context->Initialize( | 293 if (!context->Initialize( |
| 584 is_offscreen, | 294 is_offscreen, |
| 295 share_resources, |
| 585 window, | 296 window, |
| 586 size, | 297 size, |
| 587 allowed_extensions, | 298 allowed_extensions, |
| 588 attrib_list, | 299 attrib_list, |
| 589 gpu_preference, | 300 gpu_preference, |
| 590 callback)) | 301 callback)) |
| 591 return NULL; | 302 return NULL; |
| 592 | 303 |
| 593 return context.release(); | 304 return context.release(); |
| 594 } | 305 } |
| 595 | 306 |
| 596 // static | 307 // static |
| 597 void GLInProcessContext::SetGpuMemoryBufferCreator( | 308 void GLInProcessContext::SetGpuMemoryBufferCreator( |
| 598 GpuMemoryBufferCreator* creator) { | 309 GpuMemoryBufferCreator* creator) { |
| 599 g_gpu_memory_buffer_creator = creator; | 310 g_gpu_memory_buffer_creator = creator; |
| 600 } | 311 } |
| 601 | 312 |
| 602 // static | |
| 603 void GLInProcessContext::EnableVirtualizedContext() { | |
| 604 #if !defined(NDEBUG) | |
| 605 { | |
| 606 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), | |
| 607 g_all_shared_contexts.Get()); | |
| 608 DCHECK(g_all_shared_contexts.Get().empty()); | |
| 609 } | |
| 610 #endif // !defined(NDEBUG) | |
| 611 g_use_virtualized_gl_context = true; | |
| 612 } | |
| 613 | |
| 614 } // namespace gpu | 313 } // namespace gpu |
| OLD | NEW |