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 "webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" | 5 #include "webkit/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" |
6 | 6 |
7 #include <GLES2/gl2.h> | 7 #include <GLES2/gl2.h> |
8 #ifndef GL_GLEXT_PROTOTYPES | 8 #ifndef GL_GLEXT_PROTOTYPES |
9 #define GL_GLEXT_PROTOTYPES 1 | 9 #define GL_GLEXT_PROTOTYPES 1 |
10 #endif | 10 #endif |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 using gpu::gles2::GLES2CmdHelper; | 44 using gpu::gles2::GLES2CmdHelper; |
45 using gpu::gles2::GLES2Implementation; | 45 using gpu::gles2::GLES2Implementation; |
46 using gpu::GpuScheduler; | 46 using gpu::GpuScheduler; |
47 using gpu::TransferBuffer; | 47 using gpu::TransferBuffer; |
48 using gpu::TransferBufferManager; | 48 using gpu::TransferBufferManager; |
49 using gpu::TransferBufferManagerInterface; | 49 using gpu::TransferBufferManagerInterface; |
50 | 50 |
51 namespace webkit { | 51 namespace webkit { |
52 namespace gpu { | 52 namespace gpu { |
53 | 53 |
54 class GLInProcessContext : public base::SupportsWeakPtr<GLInProcessContext> { | 54 class GLInProcessContext { |
55 public: | 55 public: |
56 // These are the same error codes as used by EGL. | 56 // These are the same error codes as used by EGL. |
57 enum Error { | 57 enum Error { |
58 SUCCESS = 0x3000, | 58 SUCCESS = 0x3000, |
59 NOT_INITIALIZED = 0x3001, | 59 NOT_INITIALIZED = 0x3001, |
60 BAD_ATTRIBUTE = 0x3004, | 60 BAD_ATTRIBUTE = 0x3004, |
61 BAD_GLContext = 0x3006, | 61 BAD_GLContext = 0x3006, |
62 CONTEXT_LOST = 0x300E | 62 CONTEXT_LOST = 0x300E |
63 }; | 63 }; |
64 | 64 |
(...skipping 26 matching lines...) Expand all Loading... |
91 | 91 |
92 // Create a GLInProcessContext that renders to an offscreen frame buffer. If | 92 // Create a GLInProcessContext that renders to an offscreen frame buffer. If |
93 // parent is not NULL, that GLInProcessContext can access a copy of the | 93 // parent is not NULL, that GLInProcessContext can access a copy of the |
94 // created GLInProcessContext's frame buffer that is updated every time | 94 // created GLInProcessContext's frame buffer that is updated every time |
95 // SwapBuffers is called. It is not as general as shared GLInProcessContexts | 95 // SwapBuffers is called. It is not as general as shared GLInProcessContexts |
96 // in other implementations of OpenGL. If parent is not NULL, it must be used | 96 // in other implementations of OpenGL. If parent is not NULL, it must be used |
97 // on the same thread as the parent. A child GLInProcessContext may not | 97 // on the same thread as the parent. A child GLInProcessContext may not |
98 // outlive its parent. attrib_list must be NULL or a NONE-terminated list of | 98 // outlive its parent. attrib_list must be NULL or a NONE-terminated list of |
99 // attribute/value pairs. | 99 // attribute/value pairs. |
100 static GLInProcessContext* CreateOffscreenContext( | 100 static GLInProcessContext* CreateOffscreenContext( |
101 GLInProcessContext* parent, | |
102 const gfx::Size& size, | 101 const gfx::Size& size, |
103 GLInProcessContext* context_group, | 102 bool share_resources, |
104 const char* allowed_extensions, | 103 const char* allowed_extensions, |
105 const int32* attrib_list, | 104 const int32* attrib_list, |
106 gfx::GpuPreference gpu_preference); | 105 gfx::GpuPreference gpu_preference); |
107 | 106 |
108 // For an offscreen frame buffer GLInProcessContext, return the texture ID | 107 // For an offscreen frame buffer GLInProcessContext, return the texture ID |
109 // with respect to the parent GLInProcessContext. Returns zero if | 108 // with respect to the parent GLInProcessContext. Returns zero if |
110 // GLInProcessContext does not have a parent. | 109 // GLInProcessContext does not have a parent. |
111 uint32 GetParentTextureId(); | 110 uint32 GetParentTextureId(); |
112 | 111 |
113 // Create a new texture in the parent's GLInProcessContext. Returns zero if | 112 // Create a new texture in the parent's GLInProcessContext. Returns zero if |
(...skipping 23 matching lines...) Expand all Loading... |
137 | 136 |
138 // Return the current error. | 137 // Return the current error. |
139 Error GetError(); | 138 Error GetError(); |
140 | 139 |
141 // Return true if GPU process reported GLInProcessContext lost or there was a | 140 // Return true if GPU process reported GLInProcessContext lost or there was a |
142 // problem communicating with the GPU process. | 141 // problem communicating with the GPU process. |
143 bool IsCommandBufferContextLost(); | 142 bool IsCommandBufferContextLost(); |
144 | 143 |
145 CommandBufferService* GetCommandBufferService(); | 144 CommandBufferService* GetCommandBufferService(); |
146 | 145 |
| 146 ::gpu::gles2::GLES2Decoder* GetDecoder(); |
| 147 |
147 private: | 148 private: |
148 explicit GLInProcessContext(GLInProcessContext* parent); | 149 explicit GLInProcessContext(bool share_resources); |
149 | 150 |
150 bool Initialize(const gfx::Size& size, | 151 bool Initialize(const gfx::Size& size, |
151 GLInProcessContext* context_group, | |
152 const char* allowed_extensions, | 152 const char* allowed_extensions, |
153 const int32* attrib_list, | 153 const int32* attrib_list, |
154 gfx::GpuPreference gpu_preference); | 154 gfx::GpuPreference gpu_preference); |
155 void Destroy(); | 155 void Destroy(); |
156 | 156 |
157 void OnContextLost(); | 157 void OnContextLost(); |
158 | 158 |
159 base::WeakPtr<GLInProcessContext> parent_; | |
160 base::Closure context_lost_callback_; | 159 base::Closure context_lost_callback_; |
161 uint32 parent_texture_id_; | |
162 scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; | 160 scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; |
163 scoped_ptr<CommandBufferService> command_buffer_; | 161 scoped_ptr<CommandBufferService> command_buffer_; |
164 scoped_ptr< ::gpu::GpuScheduler> gpu_scheduler_; | 162 scoped_ptr< ::gpu::GpuScheduler> gpu_scheduler_; |
165 scoped_ptr< ::gpu::gles2::GLES2Decoder> decoder_; | 163 scoped_ptr< ::gpu::gles2::GLES2Decoder> decoder_; |
166 scoped_refptr<gfx::GLContext> context_; | 164 scoped_refptr<gfx::GLContext> context_; |
167 scoped_refptr<gfx::GLSurface> surface_; | 165 scoped_refptr<gfx::GLSurface> surface_; |
168 scoped_ptr<GLES2CmdHelper> gles2_helper_; | 166 scoped_ptr<GLES2CmdHelper> gles2_helper_; |
169 scoped_ptr<TransferBuffer> transfer_buffer_; | 167 scoped_ptr<TransferBuffer> transfer_buffer_; |
170 scoped_ptr<GLES2Implementation> gles2_implementation_; | 168 scoped_ptr<GLES2Implementation> gles2_implementation_; |
171 Error last_error_; | 169 Error last_error_; |
| 170 bool share_resources_; |
172 bool context_lost_; | 171 bool context_lost_; |
173 | 172 |
174 DISALLOW_COPY_AND_ASSIGN(GLInProcessContext); | 173 DISALLOW_COPY_AND_ASSIGN(GLInProcessContext); |
175 }; | 174 }; |
176 | 175 |
177 namespace { | 176 namespace { |
178 | 177 |
179 const int32 kCommandBufferSize = 1024 * 1024; | 178 const int32 kCommandBufferSize = 1024 * 1024; |
180 // TODO(kbr): make the transfer buffer size configurable via context | 179 // TODO(kbr): make the transfer buffer size configurable via context |
181 // creation attributes. | 180 // creation attributes. |
182 const size_t kStartTransferBufferSize = 4 * 1024 * 1024; | 181 const size_t kStartTransferBufferSize = 4 * 1024 * 1024; |
183 const size_t kMinTransferBufferSize = 1 * 256 * 1024; | 182 const size_t kMinTransferBufferSize = 1 * 256 * 1024; |
184 const size_t kMaxTransferBufferSize = 16 * 1024 * 1024; | 183 const size_t kMaxTransferBufferSize = 16 * 1024 * 1024; |
185 | 184 |
186 static base::LazyInstance< | |
187 std::set<WebGraphicsContext3DInProcessCommandBufferImpl*> > | |
188 g_all_shared_contexts = LAZY_INSTANCE_INITIALIZER; | |
189 static base::LazyInstance<base::Lock>::Leaky | |
190 g_all_shared_contexts_lock = LAZY_INSTANCE_INITIALIZER; | |
191 | |
192 // Singleton used to initialize and terminate the gles2 library. | 185 // Singleton used to initialize and terminate the gles2 library. |
193 class GLES2Initializer { | 186 class GLES2Initializer { |
194 public: | 187 public: |
195 GLES2Initializer() { | 188 GLES2Initializer() { |
196 gles2::Initialize(); | 189 gles2::Initialize(); |
197 } | 190 } |
198 | 191 |
199 ~GLES2Initializer() { | 192 ~GLES2Initializer() { |
200 gles2::Terminate(); | 193 gles2::Terminate(); |
201 } | 194 } |
202 | 195 |
203 private: | 196 private: |
204 DISALLOW_COPY_AND_ASSIGN(GLES2Initializer); | 197 DISALLOW_COPY_AND_ASSIGN(GLES2Initializer); |
205 }; | 198 }; |
206 | 199 |
207 //////////////////////////////////////////////////////////////////////////////// | 200 //////////////////////////////////////////////////////////////////////////////// |
208 | 201 |
209 static base::LazyInstance<GLES2Initializer> g_gles2_initializer = | 202 static base::LazyInstance<GLES2Initializer> g_gles2_initializer = |
210 LAZY_INSTANCE_INITIALIZER; | 203 LAZY_INSTANCE_INITIALIZER; |
211 | 204 |
212 } // namespace anonymous | 205 } // namespace anonymous |
213 | 206 |
214 GLInProcessContext::~GLInProcessContext() { | 207 GLInProcessContext::~GLInProcessContext() { |
215 Destroy(); | 208 Destroy(); |
216 } | 209 } |
217 | 210 |
218 GLInProcessContext* GLInProcessContext::CreateOffscreenContext( | 211 GLInProcessContext* GLInProcessContext::CreateOffscreenContext( |
219 GLInProcessContext* parent, | |
220 const gfx::Size& size, | 212 const gfx::Size& size, |
221 GLInProcessContext* context_group, | 213 bool share_resources, |
222 const char* allowed_extensions, | 214 const char* allowed_extensions, |
223 const int32* attrib_list, | 215 const int32* attrib_list, |
224 gfx::GpuPreference gpu_preference) { | 216 gfx::GpuPreference gpu_preference) { |
225 scoped_ptr<GLInProcessContext> context(new GLInProcessContext(parent)); | 217 scoped_ptr<GLInProcessContext> context( |
| 218 new GLInProcessContext(share_resources)); |
226 if (!context->Initialize( | 219 if (!context->Initialize( |
227 size, | 220 size, |
228 context_group, | |
229 allowed_extensions, | 221 allowed_extensions, |
230 attrib_list, | 222 attrib_list, |
231 gpu_preference)) | 223 gpu_preference)) |
232 return NULL; | 224 return NULL; |
233 | 225 |
234 return context.release(); | 226 return context.release(); |
235 } | 227 } |
236 | 228 |
237 // In the normal command buffer implementation, all commands are passed over IPC | 229 // In the normal command buffer implementation, all commands are passed over IPC |
238 // to the gpu process where they are fed to the GLES2Decoder from a single | 230 // to the gpu process where they are fed to the GLES2Decoder from a single |
239 // thread. In layout tests, any thread could call this function. GLES2Decoder, | 231 // thread. In layout tests, any thread could call this function. GLES2Decoder, |
240 // and in particular the GL implementations behind it, are not generally | 232 // and in particular the GL implementations behind it, are not generally |
241 // threadsafe, so we guard entry points with a mutex. | 233 // threadsafe, so we guard entry points with a mutex. |
242 static base::LazyInstance<base::Lock> g_decoder_lock = | 234 static base::LazyInstance<base::Lock> g_decoder_lock = |
243 LAZY_INSTANCE_INITIALIZER; | 235 LAZY_INSTANCE_INITIALIZER; |
244 | 236 |
| 237 static base::LazyInstance< |
| 238 std::set<GLInProcessContext*> > |
| 239 g_all_shared_contexts = LAZY_INSTANCE_INITIALIZER; |
| 240 |
| 241 namespace { |
| 242 |
| 243 // Also calls DetachFromThread on all GLES2Decoders before the lock is released |
| 244 // to maintain the invariant that all decoders are unbounded while the lock is |
| 245 // not held. This is to workaround DumpRenderTree uses WGC3DIPCBI with shared |
| 246 // resources on different threads. |
| 247 class AutoLockAndDecoderDetachThread { |
| 248 public: |
| 249 AutoLockAndDecoderDetachThread(base::Lock& lock, |
| 250 const std::set<GLInProcessContext*>& contexts); |
| 251 ~AutoLockAndDecoderDetachThread(); |
| 252 |
| 253 private: |
| 254 base::AutoLock auto_lock_; |
| 255 const std::set<GLInProcessContext*>& contexts_; |
| 256 }; |
| 257 |
| 258 AutoLockAndDecoderDetachThread::AutoLockAndDecoderDetachThread( |
| 259 base::Lock& lock, |
| 260 const std::set<GLInProcessContext*>& contexts) |
| 261 : auto_lock_(lock), |
| 262 contexts_(contexts) { |
| 263 } |
| 264 |
| 265 void DetachThread(GLInProcessContext* context) { |
| 266 if (context->GetDecoder()) |
| 267 context->GetDecoder()->DetachFromThread(); |
| 268 } |
| 269 |
| 270 AutoLockAndDecoderDetachThread::~AutoLockAndDecoderDetachThread() { |
| 271 std::for_each(contexts_.begin(), |
| 272 contexts_.end(), |
| 273 &DetachThread); |
| 274 } |
| 275 |
| 276 } // namespace |
| 277 |
245 void GLInProcessContext::PumpCommands() { | 278 void GLInProcessContext::PumpCommands() { |
246 if (!context_lost_) { | 279 if (!context_lost_) { |
247 base::AutoLock lock(g_decoder_lock.Get()); | 280 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), |
| 281 g_all_shared_contexts.Get()); |
248 decoder_->MakeCurrent(); | 282 decoder_->MakeCurrent(); |
249 gpu_scheduler_->PutChanged(); | 283 gpu_scheduler_->PutChanged(); |
250 ::gpu::CommandBuffer::State state = command_buffer_->GetState(); | 284 ::gpu::CommandBuffer::State state = command_buffer_->GetState(); |
251 if (::gpu::error::IsError(state.error)) { | 285 if (::gpu::error::IsError(state.error)) { |
252 context_lost_ = true; | 286 context_lost_ = true; |
253 } | 287 } |
254 } | 288 } |
255 } | 289 } |
256 | 290 |
257 bool GLInProcessContext::GetBufferChanged(int32 transfer_buffer_id) { | 291 bool GLInProcessContext::GetBufferChanged(int32 transfer_buffer_id) { |
258 return gpu_scheduler_->SetGetBuffer(transfer_buffer_id); | 292 return gpu_scheduler_->SetGetBuffer(transfer_buffer_id); |
259 } | 293 } |
260 | 294 |
261 uint32 GLInProcessContext::GetParentTextureId() { | 295 uint32 GLInProcessContext::GetParentTextureId() { |
262 return parent_texture_id_; | 296 return 0; |
263 } | 297 } |
264 | 298 |
265 uint32 GLInProcessContext::CreateParentTexture(const gfx::Size& size) { | 299 uint32 GLInProcessContext::CreateParentTexture(const gfx::Size& size) { |
266 uint32 texture = 0; | 300 uint32 texture = 0; |
267 gles2_implementation_->GenTextures(1, &texture); | 301 gles2_implementation_->GenTextures(1, &texture); |
268 gles2_implementation_->Flush(); | 302 gles2_implementation_->Flush(); |
269 return texture; | 303 return texture; |
270 } | 304 } |
271 | 305 |
272 void GLInProcessContext::DeleteParentTexture(uint32 texture) { | 306 void GLInProcessContext::DeleteParentTexture(uint32 texture) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 return true; | 359 return true; |
326 } | 360 } |
327 CommandBuffer::State state = command_buffer_->GetState(); | 361 CommandBuffer::State state = command_buffer_->GetState(); |
328 return ::gpu::error::IsError(state.error); | 362 return ::gpu::error::IsError(state.error); |
329 } | 363 } |
330 | 364 |
331 CommandBufferService* GLInProcessContext::GetCommandBufferService() { | 365 CommandBufferService* GLInProcessContext::GetCommandBufferService() { |
332 return command_buffer_.get(); | 366 return command_buffer_.get(); |
333 } | 367 } |
334 | 368 |
| 369 ::gpu::gles2::GLES2Decoder* GLInProcessContext::GetDecoder() { |
| 370 return decoder_.get(); |
| 371 } |
| 372 |
335 // TODO(gman): Remove This | 373 // TODO(gman): Remove This |
336 void GLInProcessContext::DisableShaderTranslation() { | 374 void GLInProcessContext::DisableShaderTranslation() { |
337 NOTREACHED(); | 375 NOTREACHED(); |
338 } | 376 } |
339 | 377 |
340 GLES2Implementation* GLInProcessContext::GetImplementation() { | 378 GLES2Implementation* GLInProcessContext::GetImplementation() { |
341 return gles2_implementation_.get(); | 379 return gles2_implementation_.get(); |
342 } | 380 } |
343 | 381 |
344 GLInProcessContext::GLInProcessContext(GLInProcessContext* parent) | 382 GLInProcessContext::GLInProcessContext(bool share_resources) |
345 : parent_(parent ? | 383 : last_error_(SUCCESS), |
346 parent->AsWeakPtr() : base::WeakPtr<GLInProcessContext>()), | 384 share_resources_(share_resources), |
347 parent_texture_id_(0), | |
348 last_error_(SUCCESS), | |
349 context_lost_(false) { | 385 context_lost_(false) { |
350 } | 386 } |
351 | 387 |
352 bool GLInProcessContext::Initialize(const gfx::Size& size, | 388 bool GLInProcessContext::Initialize(const gfx::Size& size, |
353 GLInProcessContext* context_group, | |
354 const char* allowed_extensions, | 389 const char* allowed_extensions, |
355 const int32* attrib_list, | 390 const int32* attrib_list, |
356 gfx::GpuPreference gpu_preference) { | 391 gfx::GpuPreference gpu_preference) { |
357 // Use one share group for all contexts. | 392 // Use one share group for all contexts. |
358 CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group, | 393 CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group, |
359 (new gfx::GLShareGroup)); | 394 (new gfx::GLShareGroup)); |
360 | 395 |
361 DCHECK(size.width() >= 0 && size.height() >= 0); | 396 DCHECK(size.width() >= 0 && size.height() >= 0); |
362 | 397 |
363 // Ensure the gles2 library is initialized first in a thread safe way. | 398 // Ensure the gles2 library is initialized first in a thread safe way. |
364 g_gles2_initializer.Get(); | 399 g_gles2_initializer.Get(); |
365 | 400 |
366 // Allocate a frame buffer ID with respect to the parent. | |
367 if (parent_.get()) { | |
368 // Flush any remaining commands in the parent context to make sure the | |
369 // texture id accounting stays consistent. | |
370 int32 token = parent_->gles2_helper_->InsertToken(); | |
371 parent_->gles2_helper_->WaitForToken(token); | |
372 parent_texture_id_ = parent_->gles2_implementation_->MakeTextureId(); | |
373 } | |
374 | |
375 std::vector<int32> attribs; | 401 std::vector<int32> attribs; |
376 while (attrib_list) { | 402 while (attrib_list) { |
377 int32 attrib = *attrib_list++; | 403 int32 attrib = *attrib_list++; |
378 switch (attrib) { | 404 switch (attrib) { |
379 // Known attributes | 405 // Known attributes |
380 case ALPHA_SIZE: | 406 case ALPHA_SIZE: |
381 case BLUE_SIZE: | 407 case BLUE_SIZE: |
382 case GREEN_SIZE: | 408 case GREEN_SIZE: |
383 case RED_SIZE: | 409 case RED_SIZE: |
384 case DEPTH_SIZE: | 410 case DEPTH_SIZE: |
(...skipping 22 matching lines...) Expand all Loading... |
407 } | 433 } |
408 | 434 |
409 command_buffer_.reset( | 435 command_buffer_.reset( |
410 new CommandBufferService(transfer_buffer_manager_.get())); | 436 new CommandBufferService(transfer_buffer_manager_.get())); |
411 if (!command_buffer_->Initialize()) { | 437 if (!command_buffer_->Initialize()) { |
412 LOG(ERROR) << "Could not initialize command buffer."; | 438 LOG(ERROR) << "Could not initialize command buffer."; |
413 Destroy(); | 439 Destroy(); |
414 return false; | 440 return false; |
415 } | 441 } |
416 | 442 |
417 // TODO(gman): This needs to be true if this is Pepper. | 443 GLInProcessContext* context_group = NULL; |
418 bool bind_generates_resource = false; | |
419 decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group ? | |
420 context_group->decoder_->GetContextGroup() : | |
421 new ::gpu::gles2::ContextGroup( | |
422 NULL, NULL, NULL, bind_generates_resource))); | |
423 | 444 |
424 gpu_scheduler_.reset(new GpuScheduler(command_buffer_.get(), | 445 { |
425 decoder_.get(), | 446 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), |
426 decoder_.get())); | 447 g_all_shared_contexts.Get()); |
| 448 if (share_resources_ && !g_all_shared_contexts.Get().empty()) |
| 449 context_group = *g_all_shared_contexts.Get().begin(); |
427 | 450 |
428 decoder_->set_engine(gpu_scheduler_.get()); | 451 // TODO(gman): This needs to be true if this is Pepper. |
| 452 bool bind_generates_resource = false; |
| 453 decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group ? |
| 454 context_group->decoder_->GetContextGroup() : |
| 455 new ::gpu::gles2::ContextGroup( |
| 456 NULL, NULL, NULL, bind_generates_resource))); |
429 | 457 |
430 surface_ = gfx::GLSurface::CreateOffscreenGLSurface(false, gfx::Size(1, 1)); | 458 gpu_scheduler_.reset(new GpuScheduler(command_buffer_.get(), |
| 459 decoder_.get(), |
| 460 decoder_.get())); |
431 | 461 |
432 if (!surface_.get()) { | 462 decoder_->set_engine(gpu_scheduler_.get()); |
433 LOG(ERROR) << "Could not create GLSurface."; | |
434 Destroy(); | |
435 return false; | |
436 } | |
437 | 463 |
438 context_ = gfx::GLContext::CreateGLContext(share_group.get(), | 464 surface_ = gfx::GLSurface::CreateOffscreenGLSurface(false, gfx::Size(1, 1)); |
439 surface_.get(), | |
440 gpu_preference); | |
441 if (!context_.get()) { | |
442 LOG(ERROR) << "Could not create GLContext."; | |
443 Destroy(); | |
444 return false; | |
445 } | |
446 | 465 |
447 if (!context_->MakeCurrent(surface_.get())) { | 466 if (!surface_.get()) { |
448 LOG(ERROR) << "Could not make context current."; | 467 LOG(ERROR) << "Could not create GLSurface."; |
449 Destroy(); | 468 Destroy(); |
450 return false; | 469 return false; |
451 } | 470 } |
452 | 471 |
453 ::gpu::gles2::DisallowedFeatures disallowed_features; | 472 context_ = gfx::GLContext::CreateGLContext(share_group.get(), |
454 disallowed_features.swap_buffer_complete_callback = true; | 473 surface_.get(), |
455 disallowed_features.gpu_memory_manager = true; | 474 gpu_preference); |
456 if (!decoder_->Initialize(surface_, | 475 if (!context_.get()) { |
457 context_, | 476 LOG(ERROR) << "Could not create GLContext."; |
458 true, | 477 Destroy(); |
459 size, | 478 return false; |
460 disallowed_features, | 479 } |
461 allowed_extensions, | |
462 attribs)) { | |
463 LOG(ERROR) << "Could not initialize decoder."; | |
464 Destroy(); | |
465 return false; | |
466 } | |
467 | 480 |
468 if (!decoder_->SetParent( | 481 if (!context_->MakeCurrent(surface_.get())) { |
469 parent_.get() ? parent_->decoder_.get() : NULL, | 482 LOG(ERROR) << "Could not make context current."; |
470 parent_texture_id_)) { | 483 Destroy(); |
471 LOG(ERROR) << "Could not set parent."; | 484 return false; |
472 Destroy(); | 485 } |
473 return false; | 486 |
| 487 ::gpu::gles2::DisallowedFeatures disallowed_features; |
| 488 disallowed_features.swap_buffer_complete_callback = true; |
| 489 disallowed_features.gpu_memory_manager = true; |
| 490 if (!decoder_->Initialize(surface_, |
| 491 context_, |
| 492 true, |
| 493 size, |
| 494 disallowed_features, |
| 495 allowed_extensions, |
| 496 attribs)) { |
| 497 LOG(ERROR) << "Could not initialize decoder."; |
| 498 Destroy(); |
| 499 return false; |
| 500 } |
474 } | 501 } |
475 | 502 |
476 command_buffer_->SetPutOffsetChangeCallback( | 503 command_buffer_->SetPutOffsetChangeCallback( |
477 base::Bind(&GLInProcessContext::PumpCommands, base::Unretained(this))); | 504 base::Bind(&GLInProcessContext::PumpCommands, base::Unretained(this))); |
478 command_buffer_->SetGetBufferChangeCallback( | 505 command_buffer_->SetGetBufferChangeCallback( |
479 base::Bind( | 506 base::Bind( |
480 &GLInProcessContext::GetBufferChanged, base::Unretained(this))); | 507 &GLInProcessContext::GetBufferChanged, base::Unretained(this))); |
481 command_buffer_->SetParseErrorCallback( | 508 command_buffer_->SetParseErrorCallback( |
482 base::Bind(&GLInProcessContext::OnContextLost, base::Unretained(this))); | 509 base::Bind(&GLInProcessContext::OnContextLost, base::Unretained(this))); |
483 | 510 |
(...skipping 15 matching lines...) Expand all Loading... |
499 true, | 526 true, |
500 false)); | 527 false)); |
501 | 528 |
502 if (!gles2_implementation_->Initialize( | 529 if (!gles2_implementation_->Initialize( |
503 kStartTransferBufferSize, | 530 kStartTransferBufferSize, |
504 kMinTransferBufferSize, | 531 kMinTransferBufferSize, |
505 kMaxTransferBufferSize)) { | 532 kMaxTransferBufferSize)) { |
506 return false; | 533 return false; |
507 } | 534 } |
508 | 535 |
| 536 if (share_resources_) { |
| 537 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), |
| 538 g_all_shared_contexts.Get()); |
| 539 g_all_shared_contexts.Pointer()->insert(this); |
| 540 } |
| 541 |
509 return true; | 542 return true; |
510 } | 543 } |
511 | 544 |
512 void GLInProcessContext::Destroy() { | 545 void GLInProcessContext::Destroy() { |
513 bool context_lost = IsCommandBufferContextLost(); | 546 bool context_lost = IsCommandBufferContextLost(); |
514 | 547 |
515 if (parent_.get() && parent_texture_id_ != 0) { | |
516 parent_->gles2_implementation_->FreeTextureId(parent_texture_id_); | |
517 parent_texture_id_ = 0; | |
518 } | |
519 | |
520 if (gles2_implementation_.get()) { | 548 if (gles2_implementation_.get()) { |
521 // First flush the context to ensure that any pending frees of resources | 549 // First flush the context to ensure that any pending frees of resources |
522 // are completed. Otherwise, if this context is part of a share group, | 550 // are completed. Otherwise, if this context is part of a share group, |
523 // those resources might leak. Also, any remaining side effects of commands | 551 // those resources might leak. Also, any remaining side effects of commands |
524 // issued on this context might not be visible to other contexts in the | 552 // issued on this context might not be visible to other contexts in the |
525 // share group. | 553 // share group. |
526 gles2_implementation_->Flush(); | 554 gles2_implementation_->Flush(); |
527 | 555 |
528 gles2_implementation_.reset(); | 556 gles2_implementation_.reset(); |
529 } | 557 } |
530 | 558 |
531 transfer_buffer_.reset(); | 559 transfer_buffer_.reset(); |
532 gles2_helper_.reset(); | 560 gles2_helper_.reset(); |
533 command_buffer_.reset(); | 561 command_buffer_.reset(); |
534 | 562 |
| 563 AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), |
| 564 g_all_shared_contexts.Get()); |
535 if (decoder_.get()) { | 565 if (decoder_.get()) { |
536 decoder_->Destroy(!context_lost); | 566 decoder_->Destroy(!context_lost); |
537 } | 567 } |
| 568 |
| 569 g_all_shared_contexts.Pointer()->erase(this); |
538 } | 570 } |
539 | 571 |
540 void GLInProcessContext::OnContextLost() { | 572 void GLInProcessContext::OnContextLost() { |
541 if (!context_lost_callback_.is_null()) | 573 if (!context_lost_callback_.is_null()) |
542 context_lost_callback_.Run(); | 574 context_lost_callback_.Run(); |
543 } | 575 } |
544 | 576 |
545 WebGraphicsContext3DInProcessCommandBufferImpl:: | 577 WebGraphicsContext3DInProcessCommandBufferImpl:: |
546 WebGraphicsContext3DInProcessCommandBufferImpl() | 578 WebGraphicsContext3DInProcessCommandBufferImpl( |
547 : context_(NULL), | 579 const WebKit::WebGraphicsContext3D::Attributes& attributes) |
| 580 : initialized_(false), |
| 581 initialize_failed_(false), |
| 582 context_(NULL), |
548 gl_(NULL), | 583 gl_(NULL), |
549 context_lost_callback_(NULL), | 584 context_lost_callback_(NULL), |
550 context_lost_reason_(GL_NO_ERROR), | 585 context_lost_reason_(GL_NO_ERROR), |
| 586 attributes_(attributes), |
551 cached_width_(0), | 587 cached_width_(0), |
552 cached_height_(0), | 588 cached_height_(0), |
553 bound_fbo_(0) { | 589 bound_fbo_(0) { |
554 } | 590 } |
555 | 591 |
556 WebGraphicsContext3DInProcessCommandBufferImpl:: | 592 WebGraphicsContext3DInProcessCommandBufferImpl:: |
557 ~WebGraphicsContext3DInProcessCommandBufferImpl() { | 593 ~WebGraphicsContext3DInProcessCommandBufferImpl() { |
558 base::AutoLock a(g_all_shared_contexts_lock.Get()); | |
559 g_all_shared_contexts.Pointer()->erase(this); | |
560 } | 594 } |
561 | 595 |
562 bool WebGraphicsContext3DInProcessCommandBufferImpl::Initialize( | 596 bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() { |
563 WebGraphicsContext3D::Attributes attributes, | 597 if (initialized_) |
564 WebKit::WebGraphicsContext3D* view_context) { | 598 return true; |
| 599 |
| 600 if (initialize_failed_) |
| 601 return false; |
| 602 |
565 // Convert WebGL context creation attributes into GLInProcessContext / EGL | 603 // Convert WebGL context creation attributes into GLInProcessContext / EGL |
566 // size requests. | 604 // size requests. |
567 const int alpha_size = attributes.alpha ? 8 : 0; | 605 const int alpha_size = attributes_.alpha ? 8 : 0; |
568 const int depth_size = attributes.depth ? 24 : 0; | 606 const int depth_size = attributes_.depth ? 24 : 0; |
569 const int stencil_size = attributes.stencil ? 8 : 0; | 607 const int stencil_size = attributes_.stencil ? 8 : 0; |
570 const int samples = attributes.antialias ? 4 : 0; | 608 const int samples = attributes_.antialias ? 4 : 0; |
571 const int sample_buffers = attributes.antialias ? 1 : 0; | 609 const int sample_buffers = attributes_.antialias ? 1 : 0; |
572 const int32 attribs[] = { | 610 const int32 attribs[] = { |
573 GLInProcessContext::ALPHA_SIZE, alpha_size, | 611 GLInProcessContext::ALPHA_SIZE, alpha_size, |
574 GLInProcessContext::DEPTH_SIZE, depth_size, | 612 GLInProcessContext::DEPTH_SIZE, depth_size, |
575 GLInProcessContext::STENCIL_SIZE, stencil_size, | 613 GLInProcessContext::STENCIL_SIZE, stencil_size, |
576 GLInProcessContext::SAMPLES, samples, | 614 GLInProcessContext::SAMPLES, samples, |
577 GLInProcessContext::SAMPLE_BUFFERS, sample_buffers, | 615 GLInProcessContext::SAMPLE_BUFFERS, sample_buffers, |
578 GLInProcessContext::NONE, | 616 GLInProcessContext::NONE, |
579 }; | 617 }; |
580 | 618 |
581 const char* preferred_extensions = "*"; | 619 const char* preferred_extensions = "*"; |
582 | 620 |
583 // TODO(kbr): More work will be needed in this implementation to | 621 // TODO(kbr): More work will be needed in this implementation to |
584 // properly support GPU switching. Like in the out-of-process | 622 // properly support GPU switching. Like in the out-of-process |
585 // command buffer implementation, all previously created contexts | 623 // command buffer implementation, all previously created contexts |
586 // will need to be lost either when the first context requesting the | 624 // will need to be lost either when the first context requesting the |
587 // discrete GPU is created, or the last one is destroyed. | 625 // discrete GPU is created, or the last one is destroyed. |
588 gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; | 626 gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; |
589 | 627 |
590 GLInProcessContext* parent_context = NULL; | |
591 if (view_context) { | |
592 WebGraphicsContext3DInProcessCommandBufferImpl* context_impl = | |
593 static_cast<WebGraphicsContext3DInProcessCommandBufferImpl*>( | |
594 view_context); | |
595 parent_context = context_impl->context_; | |
596 } | |
597 | |
598 WebGraphicsContext3DInProcessCommandBufferImpl* context_group = NULL; | |
599 base::AutoLock lock(g_all_shared_contexts_lock.Get()); | |
600 if (attributes.shareResources) | |
601 context_group = g_all_shared_contexts.Pointer()->empty() ? | |
602 NULL : *g_all_shared_contexts.Pointer()->begin(); | |
603 | |
604 context_ = GLInProcessContext::CreateOffscreenContext( | 628 context_ = GLInProcessContext::CreateOffscreenContext( |
605 parent_context, | |
606 gfx::Size(1, 1), | 629 gfx::Size(1, 1), |
607 context_group ? context_group->context_ : NULL, | 630 attributes_.shareResources, |
608 preferred_extensions, | 631 preferred_extensions, |
609 attribs, | 632 attribs, |
610 gpu_preference); | 633 gpu_preference); |
611 | 634 |
612 if (!context_) | 635 if (!context_) { |
| 636 initialize_failed_ = true; |
613 return false; | 637 return false; |
| 638 } |
614 | 639 |
615 gl_ = context_->GetImplementation(); | 640 gl_ = context_->GetImplementation(); |
616 | 641 |
617 if (gl_ && attributes.noExtensions) | 642 if (gl_ && attributes_.noExtensions) |
618 gl_->EnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation"); | 643 gl_->EnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation"); |
619 | 644 |
620 context_->SetContextLostCallback( | 645 context_->SetContextLostCallback( |
621 base::Bind( | 646 base::Bind( |
622 &WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost, | 647 &WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost, |
623 base::Unretained(this))); | 648 base::Unretained(this))); |
624 | 649 |
625 // Set attributes_ from created offscreen context. | 650 // Set attributes_ from created offscreen context. |
626 { | 651 { |
627 attributes_ = attributes; | |
628 GLint alpha_bits = 0; | 652 GLint alpha_bits = 0; |
629 getIntegerv(GL_ALPHA_BITS, &alpha_bits); | 653 getIntegerv(GL_ALPHA_BITS, &alpha_bits); |
630 attributes_.alpha = alpha_bits > 0; | 654 attributes_.alpha = alpha_bits > 0; |
631 GLint depth_bits = 0; | 655 GLint depth_bits = 0; |
632 getIntegerv(GL_DEPTH_BITS, &depth_bits); | 656 getIntegerv(GL_DEPTH_BITS, &depth_bits); |
633 attributes_.depth = depth_bits > 0; | 657 attributes_.depth = depth_bits > 0; |
634 GLint stencil_bits = 0; | 658 GLint stencil_bits = 0; |
635 getIntegerv(GL_STENCIL_BITS, &stencil_bits); | 659 getIntegerv(GL_STENCIL_BITS, &stencil_bits); |
636 attributes_.stencil = stencil_bits > 0; | 660 attributes_.stencil = stencil_bits > 0; |
637 GLint sample_buffers = 0; | 661 GLint sample_buffers = 0; |
638 getIntegerv(GL_SAMPLE_BUFFERS, &sample_buffers); | 662 getIntegerv(GL_SAMPLE_BUFFERS, &sample_buffers); |
639 attributes_.antialias = sample_buffers > 0; | 663 attributes_.antialias = sample_buffers > 0; |
640 } | 664 } |
641 makeContextCurrent(); | |
642 | 665 |
643 if (attributes.shareResources) | 666 initialized_ = true; |
644 g_all_shared_contexts.Pointer()->insert(this); | |
645 | |
646 return true; | 667 return true; |
647 } | 668 } |
648 | 669 |
649 bool WebGraphicsContext3DInProcessCommandBufferImpl::makeContextCurrent() { | 670 bool WebGraphicsContext3DInProcessCommandBufferImpl::makeContextCurrent() { |
| 671 if (!MaybeInitializeGL()) |
| 672 return false; |
| 673 |
650 return GLInProcessContext::MakeCurrent(context_); | 674 return GLInProcessContext::MakeCurrent(context_); |
651 } | 675 } |
652 | 676 |
653 void WebGraphicsContext3DInProcessCommandBufferImpl::ClearContext() { | 677 void WebGraphicsContext3DInProcessCommandBufferImpl::ClearContext() { |
654 // NOTE: Comment in the line below to check for code that is not calling | 678 // NOTE: Comment in the line below to check for code that is not calling |
655 // eglMakeCurrent where appropriate. The issue is code using | 679 // eglMakeCurrent where appropriate. The issue is code using |
656 // WebGraphicsContext3D does not need to call makeContextCurrent. Code using | 680 // WebGraphicsContext3D does not need to call makeContextCurrent. Code using |
657 // direct OpenGL bindings needs to call the appropriate form of | 681 // direct OpenGL bindings needs to call the appropriate form of |
658 // eglMakeCurrent. If it doesn't it will be issuing commands on the wrong | 682 // eglMakeCurrent. If it doesn't it will be issuing commands on the wrong |
659 // context. Uncommenting the line below clears the current context so that | 683 // context. Uncommenting the line below clears the current context so that |
(...skipping 1032 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1692 | 1716 |
1693 DELEGATE_TO_GL_9(asyncTexSubImage2DCHROMIUM, AsyncTexSubImage2DCHROMIUM, | 1717 DELEGATE_TO_GL_9(asyncTexSubImage2DCHROMIUM, AsyncTexSubImage2DCHROMIUM, |
1694 WGC3Denum, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dsizei, WGC3Dsizei, | 1718 WGC3Denum, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dsizei, WGC3Dsizei, |
1695 WGC3Denum, WGC3Denum, const void*) | 1719 WGC3Denum, WGC3Denum, const void*) |
1696 | 1720 |
1697 DELEGATE_TO_GL_1(waitAsyncTexImage2DCHROMIUM, WaitAsyncTexImage2DCHROMIUM, | 1721 DELEGATE_TO_GL_1(waitAsyncTexImage2DCHROMIUM, WaitAsyncTexImage2DCHROMIUM, |
1698 WGC3Denum) | 1722 WGC3Denum) |
1699 | 1723 |
1700 } // namespace gpu | 1724 } // namespace gpu |
1701 } // namespace webkit | 1725 } // namespace webkit |
OLD | NEW |