diff options
author | Ben Murdoch <benm@google.com> | 2013-08-01 12:44:22 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2013-08-01 13:12:08 +0100 |
commit | 28390f6bb8dc6eb59bac1e0576f95a7740a9bd61 (patch) | |
tree | 02dad0e26c6660746a487ef814fffb404e16c12a /gpu | |
parent | 226ac25887216e7df5a5dbd091cae3894b3497d2 (diff) | |
download | chromium_org-28390f6bb8dc6eb59bac1e0576f95a7740a9bd61.tar.gz |
Cherry pick of https://codereview.chromium.org/19522006
Stability fixes for Chromium WebView.
Bug:9915533
Change-Id: If5730b3f0c79b1ddd56bce3a2903531632ea0bc6
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/command_buffer/client/gl_in_process_context.cc | 402 | ||||
-rw-r--r-- | gpu/command_buffer/client/gl_in_process_context.h | 4 | ||||
-rw-r--r-- | gpu/command_buffer/service/in_process_command_buffer.cc | 700 | ||||
-rw-r--r-- | gpu/command_buffer/service/in_process_command_buffer.h | 154 | ||||
-rw-r--r-- | gpu/command_buffer_service.gypi | 2 | ||||
-rw-r--r-- | gpu/command_buffer_service.target.darwin-arm.mk | 1 | ||||
-rw-r--r-- | gpu/command_buffer_service.target.darwin-mips.mk | 1 | ||||
-rw-r--r-- | gpu/command_buffer_service.target.darwin-x86.mk | 1 | ||||
-rw-r--r-- | gpu/command_buffer_service.target.linux-arm.mk | 1 | ||||
-rw-r--r-- | gpu/command_buffer_service.target.linux-mips.mk | 1 | ||||
-rw-r--r-- | gpu/command_buffer_service.target.linux-x86.mk | 1 |
11 files changed, 944 insertions, 324 deletions
diff --git a/gpu/command_buffer/client/gl_in_process_context.cc b/gpu/command_buffer/client/gl_in_process_context.cc index 2359a05887..b1b5a03a68 100644 --- a/gpu/command_buffer/client/gl_in_process_context.cc +++ b/gpu/command_buffer/client/gl_in_process_context.cc @@ -4,6 +4,7 @@ #include "gpu/command_buffer/client/gl_in_process_context.h" +#include <set> #include <utility> #include <vector> @@ -16,36 +17,24 @@ #include "base/bind.h" #include "base/bind_helpers.h" -#include "base/callback.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" -#include "base/synchronization/lock.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gpu_memory_buffer.h" #include "gpu/command_buffer/client/gpu_memory_buffer_factory.h" #include "gpu/command_buffer/client/image_factory.h" #include "gpu/command_buffer/client/transfer_buffer.h" +#include "gpu/command_buffer/common/command_buffer.h" #include "gpu/command_buffer/common/constants.h" -#include "gpu/command_buffer/common/id_allocator.h" -#include "gpu/command_buffer/service/command_buffer_service.h" -#include "gpu/command_buffer/service/context_group.h" -#include "gpu/command_buffer/service/gl_context_virtual.h" -#include "gpu/command_buffer/service/gpu_scheduler.h" -#include "gpu/command_buffer/service/image_manager.h" -#include "gpu/command_buffer/service/transfer_buffer_manager.h" +#include "gpu/command_buffer/service/in_process_command_buffer.h" #include "ui/gfx/size.h" -#include "ui/gl/gl_context.h" #include "ui/gl/gl_image.h" -#include "ui/gl/gl_share_group.h" -#include "ui/gl/gl_surface.h" namespace gpu { -using gles2::ImageManager; - namespace { const int32 kCommandBufferSize = 1024 * 1024; @@ -55,56 +44,18 @@ const size_t kStartTransferBufferSize = 4 * 1024 * 1024; const size_t kMinTransferBufferSize = 1 * 256 * 1024; const size_t kMaxTransferBufferSize = 16 * 1024 * 1024; -// In the normal command buffer implementation, all commands are passed over IPC -// to the gpu process where they are fed to the GLES2Decoder from a single -// thread. In layout tests, any thread could call this function. GLES2Decoder, -// and in particular the GL implementations behind it, are not generally -// threadsafe, so we guard entry points with a mutex. -static base::LazyInstance<base::Lock> g_decoder_lock = - LAZY_INSTANCE_INITIALIZER; - -class GLInProcessContextImpl; - -static base::LazyInstance< - std::set<GLInProcessContextImpl*> > - g_all_shared_contexts = LAZY_INSTANCE_INITIALIZER; - -static bool g_use_virtualized_gl_context = false; - static GpuMemoryBufferFactory* g_gpu_memory_buffer_factory = NULL; -// Also calls DetachFromThreadHack on all GLES2Decoders before the lock is -// released to maintain the invariant that all decoders are unbound while the -// lock is not held. This is to workaround DumpRenderTree using WGC3DIPCBI with -// shared resources on different threads. -// Remove this as part of crbug.com/234964. -class AutoLockAndDecoderDetachThread { - public: - AutoLockAndDecoderDetachThread( - base::Lock& lock, - const std::set<GLInProcessContextImpl*>& contexts); - ~AutoLockAndDecoderDetachThread(); - - private: - base::AutoLock auto_lock_; - const std::set<GLInProcessContextImpl*>& contexts_; -}; - -size_t SharedContextCount() { - AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), - g_all_shared_contexts.Get()); - return g_all_shared_contexts.Get().size(); -} - class GLInProcessContextImpl : public GLInProcessContext, public gles2::ImageFactory, public base::SupportsWeakPtr<GLInProcessContextImpl> { public: - explicit GLInProcessContextImpl(bool share_resources); + explicit GLInProcessContextImpl(); virtual ~GLInProcessContextImpl(); bool Initialize(bool is_offscreen, + bool share_resources, gfx::AcceleratedWidget window, const gfx::Size& size, const char* allowed_extensions, @@ -125,67 +76,39 @@ class GLInProcessContextImpl unsigned* image_id) OVERRIDE; virtual void DeleteGpuMemoryBuffer(unsigned image_id) OVERRIDE; - // Other methods: - gles2::GLES2Decoder* GetDecoder(); - bool GetBufferChanged(int32 transfer_buffer_id); - void PumpCommands(); - void OnResizeView(gfx::Size size, float scale_factor); - void OnContextLost(); - private: void Destroy(); - bool IsCommandBufferContextLost(); void PollQueryCallbacks(); void CallQueryCallback(size_t index); - bool MakeCurrent(); + void OnContextLost(const base::Closure& callback); + void OnSignalSyncPoint(const base::Closure& callback); - gles2::ImageManager* GetImageManager(); - - base::Closure context_lost_callback_; - scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; - scoped_ptr<CommandBuffer> command_buffer_; - scoped_ptr<GpuScheduler> gpu_scheduler_; - scoped_ptr<gles2::GLES2Decoder> decoder_; - scoped_refptr<gfx::GLContext> context_; - scoped_refptr<gfx::GLSurface> surface_; scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_; scoped_ptr<TransferBuffer> transfer_buffer_; scoped_ptr<gles2::GLES2Implementation> gles2_implementation_; - bool share_resources_; - bool context_lost_; + scoped_ptr<InProcessCommandBuffer> command_buffer_; typedef std::pair<unsigned, base::Closure> QueryCallback; std::vector<QueryCallback> query_callbacks_; - std::vector<base::Closure> signal_sync_point_callbacks_; + unsigned int share_group_id_; + bool context_lost_; DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl); }; -AutoLockAndDecoderDetachThread::AutoLockAndDecoderDetachThread( - base::Lock& lock, - const std::set<GLInProcessContextImpl*>& contexts) - : auto_lock_(lock), - contexts_(contexts) { -} - -void DetachThread(GLInProcessContextImpl* context) { - if (context->GetDecoder()) - context->GetDecoder()->DetachFromThreadHack(); -} +base::LazyInstance<base::Lock> g_all_shared_contexts_lock = + LAZY_INSTANCE_INITIALIZER; +base::LazyInstance<std::set<GLInProcessContextImpl*> > g_all_shared_contexts = + LAZY_INSTANCE_INITIALIZER; -AutoLockAndDecoderDetachThread::~AutoLockAndDecoderDetachThread() { - std::for_each(contexts_.begin(), - contexts_.end(), - &DetachThread); +size_t SharedContextCount() { + base::AutoLock lock(g_all_shared_contexts_lock.Get()); + return g_all_shared_contexts.Get().size(); } scoped_ptr<GpuMemoryBuffer> GLInProcessContextImpl::CreateGpuMemoryBuffer( int width, int height, GLenum internalformat, unsigned int* image_id) { - // We're taking the lock here because we're accessing the ContextGroup's - // shared IdManager. - AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), - g_all_shared_contexts.Get()); scoped_ptr<GpuMemoryBuffer> buffer( g_gpu_memory_buffer_factory->CreateGpuMemoryBuffer(width, height, @@ -193,111 +116,58 @@ scoped_ptr<GpuMemoryBuffer> GLInProcessContextImpl::CreateGpuMemoryBuffer( if (!buffer) return scoped_ptr<GpuMemoryBuffer>(); - scoped_refptr<gfx::GLImage> gl_image = - gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer->GetNativeBuffer(), - gfx::Size(width, height)); - *image_id = decoder_->GetContextGroup() - ->GetIdAllocator(gles2::id_namespaces::kImages)->AllocateID(); - GetImageManager()->AddImage(gl_image.get(), *image_id); + *image_id = command_buffer_->CreateImageForGpuMemoryBuffer( + buffer->GetNativeBuffer(), gfx::Size(width, height)); return buffer.Pass(); } void GLInProcessContextImpl::DeleteGpuMemoryBuffer(unsigned int image_id) { - // We're taking the lock here because we're accessing the ContextGroup's - // shared ImageManager. - AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), - g_all_shared_contexts.Get()); - GetImageManager()->RemoveImage(image_id); - decoder_->GetContextGroup()->GetIdAllocator(gles2::id_namespaces::kImages) - ->FreeID(image_id); + command_buffer_->RemoveImage(image_id); } -GLInProcessContextImpl::GLInProcessContextImpl(bool share_resources) - : share_resources_(share_resources), - context_lost_(false) { -} +GLInProcessContextImpl::GLInProcessContextImpl() + : share_group_id_(0), context_lost_(false) {} GLInProcessContextImpl::~GLInProcessContextImpl() { - Destroy(); -} - -bool GLInProcessContextImpl::MakeCurrent() { - if (decoder_->MakeCurrent()) - return true; - DLOG(ERROR) << "Context lost because MakeCurrent failed."; - command_buffer_->SetContextLostReason(decoder_->GetContextLostReason()); - command_buffer_->SetParseError(gpu::error::kLostContext); - return false; -} - -void GLInProcessContextImpl::PumpCommands() { { - AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), - g_all_shared_contexts.Get()); - if (!MakeCurrent()) - return; - gpu_scheduler_->PutChanged(); - CommandBuffer::State state = command_buffer_->GetState(); - DCHECK((!error::IsError(state.error) && !context_lost_) || - (error::IsError(state.error) && context_lost_)); + base::AutoLock lock(g_all_shared_contexts_lock.Get()); + g_all_shared_contexts.Get().erase(this); } - - if (!context_lost_ && signal_sync_point_callbacks_.size()) { - for (size_t n = 0; n < signal_sync_point_callbacks_.size(); n++) { - base::MessageLoop::current()->PostTask(FROM_HERE, - signal_sync_point_callbacks_[n]); - } - } - signal_sync_point_callbacks_.clear(); -} - -bool GLInProcessContextImpl::GetBufferChanged(int32 transfer_buffer_id) { - return gpu_scheduler_->SetGetBuffer(transfer_buffer_id); + Destroy(); } void GLInProcessContextImpl::SignalSyncPoint(unsigned sync_point, const base::Closure& callback) { DCHECK(!callback.is_null()); - signal_sync_point_callbacks_.push_back(callback); -} - -bool GLInProcessContextImpl::IsCommandBufferContextLost() { - if (context_lost_ || !command_buffer_) { - return true; - } - CommandBuffer::State state = command_buffer_->GetState(); - return error::IsError(state.error); -} - -gles2::GLES2Decoder* GLInProcessContextImpl::GetDecoder() { - return decoder_.get(); -} - -void GLInProcessContextImpl::OnResizeView(gfx::Size size, float scale_factor) { - DCHECK(!surface_->IsOffscreen()); - surface_->Resize(size); + base::Closure wrapped_callback = base::Bind( + &GLInProcessContextImpl::OnSignalSyncPoint, AsWeakPtr(), callback); + command_buffer_->SignalSyncPoint(sync_point, wrapped_callback); } gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() { return gles2_implementation_.get(); } -gles2::ImageManager* GLInProcessContextImpl::GetImageManager() { - return decoder_->GetContextGroup()->image_manager(); +void GLInProcessContextImpl::OnContextLost(const base::Closure& callback) { + context_lost_ = true; + callback.Run(); +} + +void GLInProcessContextImpl::OnSignalSyncPoint(const base::Closure& callback) { + // TODO: Should it always trigger callbacks? + if (!context_lost_) + callback.Run(); } bool GLInProcessContextImpl::Initialize( bool is_offscreen, + bool share_resources, gfx::AcceleratedWidget window, const gfx::Size& size, const char* allowed_extensions, const int32* attrib_list, gfx::GpuPreference gpu_preference, const base::Closure& context_lost_callback) { - // Use one share group for all contexts. - CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group, - (new gfx::GLShareGroup)); - DCHECK(size.width() >= 0 && size.height() >= 0); std::vector<int32> attribs; @@ -327,128 +197,50 @@ bool GLInProcessContextImpl::Initialize( } } - { - TransferBufferManager* manager = new TransferBufferManager(); - transfer_buffer_manager_.reset(manager); - manager->Initialize(); - } - - scoped_ptr<CommandBufferService> command_buffer( - new CommandBufferService(transfer_buffer_manager_.get())); - command_buffer->SetPutOffsetChangeCallback(base::Bind( - &GLInProcessContextImpl::PumpCommands, base::Unretained(this))); - command_buffer->SetGetBufferChangeCallback(base::Bind( - &GLInProcessContextImpl::GetBufferChanged, base::Unretained(this))); - command_buffer->SetParseErrorCallback(base::Bind( - &GLInProcessContextImpl::OnContextLost, base::Unretained(this))); - - command_buffer_ = command_buffer.Pass(); - if (!command_buffer_->Initialize()) { - LOG(ERROR) << "Could not initialize command buffer."; - Destroy(); - return false; - } - - GLInProcessContextImpl* context_group = NULL; - - { - AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), - g_all_shared_contexts.Get()); - if (share_resources_ && !g_all_shared_contexts.Get().empty()) { - for (std::set<GLInProcessContextImpl*>::iterator it = - g_all_shared_contexts.Get().begin(); - it != g_all_shared_contexts.Get().end(); - ++it) { - if (!(*it)->IsCommandBufferContextLost()) { - context_group = *it; - break; - } - } - if (!context_group) - share_group = new gfx::GLShareGroup; - } - - // TODO(gman): This needs to be true if this is Pepper. - bool bind_generates_resource = false; - decoder_.reset(gles2::GLES2Decoder::Create( - context_group ? context_group->decoder_->GetContextGroup() - : new gles2::ContextGroup( - NULL, NULL, NULL, NULL, bind_generates_resource))); - - gpu_scheduler_.reset(new GpuScheduler(command_buffer_.get(), - decoder_.get(), - decoder_.get())); - - decoder_->set_engine(gpu_scheduler_.get()); - - if (is_offscreen) - surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size); - else - surface_ = gfx::GLSurface::CreateViewGLSurface(window); - - if (!surface_.get()) { - LOG(ERROR) << "Could not create GLSurface."; - Destroy(); - return false; - } - - if (g_use_virtualized_gl_context) { - context_ = share_group->GetSharedContext(); - if (!context_.get()) { - context_ = gfx::GLContext::CreateGLContext( - share_group.get(), surface_.get(), gpu_preference); - share_group->SetSharedContext(context_.get()); - } - - context_ = new GLContextVirtual( - share_group.get(), context_.get(), decoder_->AsWeakPtr()); - if (context_->Initialize(surface_.get(), gpu_preference)) { - VLOG(1) << "Created virtual GL context."; - } else { - context_ = NULL; + base::Closure wrapped_callback = + base::Bind(&GLInProcessContextImpl::OnContextLost, + AsWeakPtr(), + context_lost_callback); + command_buffer_.reset(new InProcessCommandBuffer()); + + scoped_ptr<base::AutoLock> scoped_shared_context_lock; + scoped_refptr<gles2::ShareGroup> share_group; + if (share_resources) { + scoped_shared_context_lock.reset( + new base::AutoLock(g_all_shared_contexts_lock.Get())); + for (std::set<GLInProcessContextImpl*>::const_iterator it = + g_all_shared_contexts.Get().begin(); + it != g_all_shared_contexts.Get().end(); + it++) { + const GLInProcessContextImpl* context = *it; + if (!context->context_lost_) { + share_group = context->gles2_implementation_->share_group(); + DCHECK(share_group); + share_group_id_ = context->share_group_id_; + break; } - } else { - context_ = gfx::GLContext::CreateGLContext(share_group.get(), - surface_.get(), - gpu_preference); + share_group_id_ = std::max(share_group_id_, context->share_group_id_); } - - if (!context_.get()) { - LOG(ERROR) << "Could not create GLContext."; - Destroy(); - return false; - } - - if (!context_->MakeCurrent(surface_.get())) { - LOG(ERROR) << "Could not make context current."; - Destroy(); - return false; - } - - gles2::DisallowedFeatures disallowed_features; - disallowed_features.swap_buffer_complete_callback = true; - disallowed_features.gpu_memory_manager = true; - if (!decoder_->Initialize(surface_, - context_, - is_offscreen, + if (!share_group && !++share_group_id_) + ++share_group_id_; + } + if (!command_buffer_->Initialize(is_offscreen, + share_resources, + window, size, - disallowed_features, allowed_extensions, - attribs)) { - LOG(ERROR) << "Could not initialize decoder."; - Destroy(); - return false; - } - - if (!is_offscreen) { - decoder_->SetResizeCallback(base::Bind( - &GLInProcessContextImpl::OnResizeView, base::Unretained(this))); - } + attribs, + gpu_preference, + wrapped_callback, + share_group_id_)) { + LOG(INFO) << "Failed to initialize InProcessCommmandBuffer"; + return false; } // Create the GLES2 helper, which writes the command buffer protocol. gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get())); if (!gles2_helper_->Initialize(kCommandBufferSize)) { + LOG(INFO) << "Failed to initialize GLES2CmdHelper"; Destroy(); return false; } @@ -459,11 +251,16 @@ bool GLInProcessContextImpl::Initialize( // Create the object exposing the OpenGL API. gles2_implementation_.reset(new gles2::GLES2Implementation( gles2_helper_.get(), - context_group ? context_group->GetImplementation()->share_group() : NULL, + share_group, transfer_buffer_.get(), false, this)); + if (share_resources) { + g_all_shared_contexts.Get().insert(this); + scoped_shared_context_lock.reset(); + } + if (!gles2_implementation_->Initialize( kStartTransferBufferSize, kMinTransferBufferSize, @@ -471,13 +268,6 @@ bool GLInProcessContextImpl::Initialize( return false; } - if (share_resources_) { - AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), - g_all_shared_contexts.Get()); - g_all_shared_contexts.Pointer()->insert(this); - } - - context_lost_callback_ = context_lost_callback; return true; } @@ -486,8 +276,6 @@ void GLInProcessContextImpl::Destroy() { CallQueryCallback(0); } - bool context_lost = IsCommandBufferContextLost(); - if (gles2_implementation_) { // First flush the context to ensure that any pending frees of resources // are completed. Otherwise, if this context is part of a share group, @@ -502,28 +290,6 @@ void GLInProcessContextImpl::Destroy() { transfer_buffer_.reset(); gles2_helper_.reset(); command_buffer_.reset(); - - AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(), - g_all_shared_contexts.Get()); - if (decoder_) { - decoder_->Destroy(!context_lost); - } - - g_all_shared_contexts.Pointer()->erase(this); -} - -void GLInProcessContextImpl::OnContextLost() { - if (!context_lost_callback_.is_null()) - context_lost_callback_.Run(); - - context_lost_ = true; - if (share_resources_) { - for (std::set<GLInProcessContextImpl*>::iterator it = - g_all_shared_contexts.Get().begin(); - it != g_all_shared_contexts.Get().end(); - ++it) - (*it)->context_lost_ = true; - } } void GLInProcessContextImpl::CallQueryCallback(size_t index) { @@ -534,6 +300,7 @@ void GLInProcessContextImpl::CallQueryCallback(size_t index) { query_callback.second.Run(); } +// TODO(sievers): Move this to the service side void GLInProcessContextImpl::PollQueryCallbacks() { for (size_t i = 0; i < query_callbacks_.size();) { unsigned query = query_callbacks_[i].first; @@ -582,9 +349,10 @@ GLInProcessContext* GLInProcessContext::CreateContext( gfx::GpuPreference gpu_preference, const base::Closure& callback) { scoped_ptr<GLInProcessContextImpl> context( - new GLInProcessContextImpl(share_resources)); + new GLInProcessContextImpl()); if (!context->Initialize( is_offscreen, + share_resources, window, size, allowed_extensions, @@ -603,10 +371,4 @@ void GLInProcessContext::SetGpuMemoryBufferFactory( g_gpu_memory_buffer_factory = factory; } -// static -void GLInProcessContext::EnableVirtualizedContext() { - DCHECK_EQ(0u, SharedContextCount()); - g_use_virtualized_gl_context = true; -} - } // namespace gpu diff --git a/gpu/command_buffer/client/gl_in_process_context.h b/gpu/command_buffer/client/gl_in_process_context.h index 9e38b1c84b..2d0754b227 100644 --- a/gpu/command_buffer/client/gl_in_process_context.h +++ b/gpu/command_buffer/client/gl_in_process_context.h @@ -30,10 +30,6 @@ class GLES2_IMPL_EXPORT GLInProcessContext { // Must be called before any GLInProcessContext instances are created. static void SetGpuMemoryBufferFactory(GpuMemoryBufferFactory* factory); - // Must be called before any GLInProcessContext instances are created. - // Default value is false. - static void EnableVirtualizedContext(); - // GLInProcessContext configuration attributes. These are the same as used by // EGL. Attributes are matched using a closest fit algorithm. enum Attribute { diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc new file mode 100644 index 0000000000..e8219a1819 --- /dev/null +++ b/gpu/command_buffer/service/in_process_command_buffer.cc @@ -0,0 +1,700 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu/command_buffer/service/in_process_command_buffer.h" + +#include <queue> +#include <utility> + +#include <GLES2/gl2.h> +#ifndef GL_GLEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES 1 +#endif +#include <GLES2/gl2ext.h> +#include <GLES2/gl2extchromium.h> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/threading/thread.h" +#include "gpu/command_buffer/common/id_allocator.h" +#include "gpu/command_buffer/service/command_buffer_service.h" +#include "gpu/command_buffer/service/context_group.h" +#include "gpu/command_buffer/service/gl_context_virtual.h" +#include "gpu/command_buffer/service/gpu_scheduler.h" +#include "gpu/command_buffer/service/image_manager.h" +#include "gpu/command_buffer/service/transfer_buffer_manager.h" +#include "ui/gfx/size.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_image.h" +#include "ui/gl/gl_share_group.h" +#include "ui/gl/gl_surface.h" + +namespace gpu { + +namespace { + +static base::LazyInstance<std::set<InProcessCommandBuffer*> > + g_all_shared_contexts = LAZY_INSTANCE_INITIALIZER; + +static bool g_use_virtualized_gl_context = false; +static bool g_uses_explicit_scheduling = false; + +template <typename T> +static void RunTaskWithResult(base::Callback<T(void)> task, + T* result, + base::WaitableEvent* completion) { + *result = task.Run(); + completion->Signal(); +} + +class GpuInProcessThread + : public base::Thread, + public base::RefCountedThreadSafe<GpuInProcessThread> { + public: + GpuInProcessThread(); + + private: + friend class base::RefCountedThreadSafe<GpuInProcessThread>; + virtual ~GpuInProcessThread(); + + DISALLOW_COPY_AND_ASSIGN(GpuInProcessThread); +}; + +GpuInProcessThread::GpuInProcessThread() : base::Thread("GpuThread") { + Start(); +} + +GpuInProcessThread::~GpuInProcessThread() { + Stop(); +} + +// Used with explicit scheduling when there is no dedicated GPU thread. +class GpuCommandQueue { + public: + GpuCommandQueue(); + ~GpuCommandQueue(); + + void QueueTask(const base::Closure& task); + void RunTasks(); + void SetScheduleCallback(const base::Closure& callback); + + private: + base::Lock tasks_lock_; + std::queue<base::Closure> tasks_; + base::Closure schedule_callback_; + + DISALLOW_COPY_AND_ASSIGN(GpuCommandQueue); +}; + +GpuCommandQueue::GpuCommandQueue() {} + +GpuCommandQueue::~GpuCommandQueue() { + base::AutoLock lock(tasks_lock_); + DCHECK(tasks_.empty()); +} + +void GpuCommandQueue::QueueTask(const base::Closure& task) { + { + base::AutoLock lock(tasks_lock_); + tasks_.push(task); + } + + DCHECK(!schedule_callback_.is_null()); + schedule_callback_.Run(); +} + +void GpuCommandQueue::RunTasks() { + size_t num_tasks; + { + base::AutoLock lock(tasks_lock_); + num_tasks = tasks_.size(); + } + + while (num_tasks) { + base::Closure task; + { + base::AutoLock lock(tasks_lock_); + task = tasks_.front(); + tasks_.pop(); + num_tasks = tasks_.size(); + } + + task.Run(); + } +} + +void GpuCommandQueue::SetScheduleCallback(const base::Closure& callback) { + DCHECK(schedule_callback_.is_null()); + schedule_callback_ = callback; +} + +static base::LazyInstance<GpuCommandQueue> g_gpu_queue = + LAZY_INSTANCE_INITIALIZER; + +class SchedulerClientBase : public InProcessCommandBuffer::SchedulerClient { + public: + explicit SchedulerClientBase(bool need_thread); + virtual ~SchedulerClientBase(); + + static bool HasClients(); + + protected: + scoped_refptr<GpuInProcessThread> thread_; + + private: + static base::LazyInstance<std::set<SchedulerClientBase*> > all_clients_; + static base::LazyInstance<base::Lock> all_clients_lock_; +}; + +base::LazyInstance<std::set<SchedulerClientBase*> > + SchedulerClientBase::all_clients_ = LAZY_INSTANCE_INITIALIZER; +base::LazyInstance<base::Lock> SchedulerClientBase::all_clients_lock_ = + LAZY_INSTANCE_INITIALIZER; + +SchedulerClientBase::SchedulerClientBase(bool need_thread) { + base::AutoLock(all_clients_lock_.Get()); + if (need_thread) { + if (!all_clients_.Get().empty()) { + SchedulerClientBase* other = *all_clients_.Get().begin(); + thread_ = other->thread_; + DCHECK(thread_.get()); + } else { + thread_ = new GpuInProcessThread; + } + } + all_clients_.Get().insert(this); +} + +SchedulerClientBase::~SchedulerClientBase() { + base::AutoLock(all_clients_lock_.Get()); + all_clients_.Get().erase(this); +} + +bool SchedulerClientBase::HasClients() { + base::AutoLock(all_clients_lock_.Get()); + return !all_clients_.Get().empty(); +} + +// A client that talks to the GPU thread +class ThreadClient : public SchedulerClientBase { + public: + ThreadClient(); + virtual void QueueTask(const base::Closure& task) OVERRIDE; +}; + +ThreadClient::ThreadClient() : SchedulerClientBase(true) { + DCHECK(thread_.get()); +} + +void ThreadClient::QueueTask(const base::Closure& task) { + thread_->message_loop()->PostTask(FROM_HERE, task); +} + +// A client that talks to the GpuCommandQueue +class QueueClient : public SchedulerClientBase { + public: + QueueClient(); + virtual void QueueTask(const base::Closure& task) OVERRIDE; +}; + +QueueClient::QueueClient() : SchedulerClientBase(false) { + DCHECK(!thread_.get()); +} + +void QueueClient::QueueTask(const base::Closure& task) { + g_gpu_queue.Get().QueueTask(task); +} + +static scoped_ptr<InProcessCommandBuffer::SchedulerClient> +CreateSchedulerClient() { + scoped_ptr<InProcessCommandBuffer::SchedulerClient> client; + if (g_uses_explicit_scheduling) + client.reset(new QueueClient); + else + client.reset(new ThreadClient); + + return client.Pass(); +} + +class ScopedEvent { + public: + ScopedEvent(base::WaitableEvent* event) : event_(event) {} + ~ScopedEvent() { event_->Signal(); } + + private: + base::WaitableEvent* event_; +}; + +} // anonyous namespace + +InProcessCommandBuffer::InProcessCommandBuffer() + : context_lost_(false), + share_group_id_(0), + last_put_offset_(-1), + flush_event_(false, false), + queue_(CreateSchedulerClient()) {} + +InProcessCommandBuffer::~InProcessCommandBuffer() { + Destroy(); +} + +bool InProcessCommandBuffer::IsContextLost() { + if (context_lost_ || !command_buffer_) { + return true; + } + CommandBuffer::State state = GetState(); + return error::IsError(state.error); +} + +void InProcessCommandBuffer::OnResizeView(gfx::Size size, float scale_factor) { + DCHECK(!surface_->IsOffscreen()); + surface_->Resize(size); +} + +bool InProcessCommandBuffer::MakeCurrent() { + command_buffer_lock_.AssertAcquired(); + + if (!context_lost_ && decoder_->MakeCurrent()) + return true; + DLOG(ERROR) << "Context lost because MakeCurrent failed."; + command_buffer_->SetContextLostReason(decoder_->GetContextLostReason()); + command_buffer_->SetParseError(gpu::error::kLostContext); + return false; +} + +void InProcessCommandBuffer::PumpCommands() { + ScopedEvent handle_flush(&flush_event_); + command_buffer_lock_.AssertAcquired(); + + if (!MakeCurrent()) + return; + + gpu_scheduler_->PutChanged(); + CommandBuffer::State state = command_buffer_->GetState(); + DCHECK((!error::IsError(state.error) && !context_lost_) || + (error::IsError(state.error) && context_lost_)); +} + +bool InProcessCommandBuffer::GetBufferChanged(int32 transfer_buffer_id) { + command_buffer_lock_.AssertAcquired(); + command_buffer_->SetGetBuffer(transfer_buffer_id); + return true; +} + +bool InProcessCommandBuffer::Initialize( + bool is_offscreen, + bool share_resources, + gfx::AcceleratedWidget window, + const gfx::Size& size, + const char* allowed_extensions, + const std::vector<int32>& attribs, + gfx::GpuPreference gpu_preference, + const base::Closure& context_lost_callback, + unsigned int share_group_id) { + + share_resources_ = share_resources; + context_lost_callback_ = WrapCallback(context_lost_callback); + share_group_id_ = share_group_id; + + base::WaitableEvent completion(true, false); + bool result; + base::Callback<bool(void)> init_task = + base::Bind(&InProcessCommandBuffer::InitializeOnGpuThread, + base::Unretained(this), + is_offscreen, + window, + size, + allowed_extensions, + attribs, + gpu_preference); + QueueTask( + base::Bind(&RunTaskWithResult<bool>, init_task, &result, &completion)); + completion.Wait(); + return result; +} + +bool InProcessCommandBuffer::InitializeOnGpuThread( + bool is_offscreen, + gfx::AcceleratedWidget window, + const gfx::Size& size, + const char* allowed_extensions, + const std::vector<int32>& attribs, + gfx::GpuPreference gpu_preference) { + // Use one share group for all contexts. + CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group, + (new gfx::GLShareGroup)); + + DCHECK(size.width() >= 0 && size.height() >= 0); + + TransferBufferManager* manager = new TransferBufferManager(); + transfer_buffer_manager_.reset(manager); + manager->Initialize(); + + scoped_ptr<CommandBufferService> command_buffer( + new CommandBufferService(transfer_buffer_manager_.get())); + command_buffer->SetPutOffsetChangeCallback(base::Bind( + &InProcessCommandBuffer::PumpCommands, base::Unretained(this))); + command_buffer->SetParseErrorCallback(base::Bind( + &InProcessCommandBuffer::OnContextLost, base::Unretained(this))); + + if (!command_buffer->Initialize()) { + LOG(ERROR) << "Could not initialize command buffer."; + DestroyOnGpuThread(); + return false; + } + + InProcessCommandBuffer* context_group = NULL; + + if (share_resources_ && !g_all_shared_contexts.Get().empty()) { + DCHECK(share_group_id_); + for (std::set<InProcessCommandBuffer*>::iterator it = + g_all_shared_contexts.Get().begin(); + it != g_all_shared_contexts.Get().end(); + ++it) { + if ((*it)->share_group_id_ == share_group_id_) { + context_group = *it; + DCHECK(context_group->share_resources_); + context_lost_ = context_group->IsContextLost(); + break; + } + } + if (!context_group) + share_group = new gfx::GLShareGroup; + } + + bool bind_generates_resource = false; + decoder_.reset(gles2::GLES2Decoder::Create( + context_group ? context_group->decoder_->GetContextGroup() + : new gles2::ContextGroup( + NULL, NULL, NULL, NULL, bind_generates_resource))); + + gpu_scheduler_.reset( + new GpuScheduler(command_buffer.get(), decoder_.get(), decoder_.get())); + command_buffer->SetGetBufferChangeCallback(base::Bind( + &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get()))); + command_buffer_ = command_buffer.Pass(); + + decoder_->set_engine(gpu_scheduler_.get()); + + if (is_offscreen) + surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size); + else + surface_ = gfx::GLSurface::CreateViewGLSurface(window); + + if (!surface_.get()) { + LOG(ERROR) << "Could not create GLSurface."; + DestroyOnGpuThread(); + return false; + } + + if (g_use_virtualized_gl_context) { + context_ = share_group->GetSharedContext(); + if (!context_.get()) { + context_ = gfx::GLContext::CreateGLContext( + share_group.get(), surface_.get(), gpu_preference); + share_group->SetSharedContext(context_.get()); + } + + context_ = new GLContextVirtual( + share_group.get(), context_.get(), decoder_->AsWeakPtr()); + if (context_->Initialize(surface_.get(), gpu_preference)) { + VLOG(1) << "Created virtual GL context."; + } else { + context_ = NULL; + } + } else { + context_ = gfx::GLContext::CreateGLContext( + share_group.get(), surface_.get(), gpu_preference); + } + + if (!context_.get()) { + LOG(ERROR) << "Could not create GLContext."; + DestroyOnGpuThread(); + return false; + } + + if (!context_->MakeCurrent(surface_.get())) { + LOG(ERROR) << "Could not make context current."; + DestroyOnGpuThread(); + return false; + } + + gles2::DisallowedFeatures disallowed_features; + disallowed_features.swap_buffer_complete_callback = true; + disallowed_features.gpu_memory_manager = true; + if (!decoder_->Initialize(surface_, + context_, + is_offscreen, + size, + disallowed_features, + allowed_extensions, + attribs)) { + LOG(ERROR) << "Could not initialize decoder."; + DestroyOnGpuThread(); + return false; + } + + if (!is_offscreen) { + decoder_->SetResizeCallback(base::Bind( + &InProcessCommandBuffer::OnResizeView, base::Unretained(this))); + } + + if (share_resources_) { + g_all_shared_contexts.Pointer()->insert(this); + } + + return true; +} + +void InProcessCommandBuffer::Destroy() { + base::WaitableEvent completion(true, false); + bool result; + base::Callback<bool(void)> destroy_task = base::Bind( + &InProcessCommandBuffer::DestroyOnGpuThread, base::Unretained(this)); + QueueTask( + base::Bind(&RunTaskWithResult<bool>, destroy_task, &result, &completion)); + completion.Wait(); +} + +bool InProcessCommandBuffer::DestroyOnGpuThread() { + command_buffer_.reset(); + // Clean up GL resources if possible. + bool have_context = context_ && context_->MakeCurrent(surface_); + if (decoder_) { + decoder_->Destroy(have_context); + decoder_.reset(); + } + context_ = NULL; + surface_ = NULL; + + g_all_shared_contexts.Pointer()->erase(this); + return true; +} + +unsigned int InProcessCommandBuffer::CreateImageForGpuMemoryBuffer( + gfx::GpuMemoryBufferHandle buffer, + gfx::Size size) { + unsigned int image_id; + { + // TODO: ID allocation should go through CommandBuffer + base::AutoLock lock(command_buffer_lock_); + gles2::ContextGroup* group = decoder_->GetContextGroup(); + image_id = + group->GetIdAllocator(gles2::id_namespaces::kImages)->AllocateID(); + } + base::Closure image_task = + base::Bind(&InProcessCommandBuffer::CreateImageOnGpuThread, + base::Unretained(this), buffer, size, image_id); + QueueTask(image_task); + return image_id; +} + +void InProcessCommandBuffer::CreateImageOnGpuThread( + gfx::GpuMemoryBufferHandle buffer, + gfx::Size size, + unsigned int image_id) { + scoped_refptr<gfx::GLImage> gl_image = + gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer, size); + decoder_->GetContextGroup()->image_manager()->AddImage(gl_image, image_id); +} + +void InProcessCommandBuffer::RemoveImage(unsigned int image_id) { + { + // TODO: ID allocation should go through CommandBuffer + base::AutoLock lock(command_buffer_lock_); + gles2::ContextGroup* group = decoder_->GetContextGroup(); + group->GetIdAllocator(gles2::id_namespaces::kImages)->FreeID(image_id); + } + base::Closure image_manager_task = + base::Bind(&InProcessCommandBuffer::RemoveImageOnGpuThread, + base::Unretained(this), + image_id); + QueueTask(image_manager_task); +} + +void InProcessCommandBuffer::RemoveImageOnGpuThread(unsigned int image_id) { + decoder_->GetContextGroup()->image_manager()->RemoveImage(image_id); +} + +void InProcessCommandBuffer::OnContextLost() { + if (!context_lost_callback_.is_null()) + context_lost_callback_.Run(); + + context_lost_ = true; + if (share_resources_) { + for (std::set<InProcessCommandBuffer*>::iterator it = + g_all_shared_contexts.Get().begin(); + it != g_all_shared_contexts.Get().end(); + ++it) { + (*it)->context_lost_ = true; + } + } +} + +CommandBuffer::State InProcessCommandBuffer::GetStateFast() { + base::AutoLock lock(command_buffer_lock_); + return last_state_ = command_buffer_->GetState(); +} + +CommandBuffer::State InProcessCommandBuffer::GetState() { + return GetStateFast(); +} + +CommandBuffer::State InProcessCommandBuffer::GetLastState() { + return last_state_; +} + +int32 InProcessCommandBuffer::GetLastToken() { return last_state_.token; } + +void InProcessCommandBuffer::FlushOnGpuThread(int32 put_offset) { + base::AutoLock lock(command_buffer_lock_); + command_buffer_->Flush(put_offset); +} + +void InProcessCommandBuffer::Flush(int32 put_offset) { + if (last_state_.error != gpu::error::kNoError) + return; + + if (last_put_offset_ == put_offset) + return; + + last_put_offset_ = put_offset; + base::Closure task = base::Bind(&InProcessCommandBuffer::FlushOnGpuThread, + base::Unretained(this), + put_offset); + QueueTask(task); +} + +CommandBuffer::State InProcessCommandBuffer::FlushSync(int32 put_offset, + int32 last_known_get) { + if (put_offset == last_known_get || last_state_.error != gpu::error::kNoError) + return last_state_; + + Flush(put_offset); + GetStateFast(); + while (last_known_get == last_state_.get_offset && + last_state_.error == gpu::error::kNoError) { + flush_event_.Wait(); + GetStateFast(); + } + + return last_state_; +} + +void InProcessCommandBuffer::SetGetBuffer(int32 shm_id) { + if (last_state_.error != gpu::error::kNoError) + return; + + { + base::AutoLock lock(command_buffer_lock_); + command_buffer_->SetGetBuffer(shm_id); + last_put_offset_ = 0; + } + GetStateFast(); +} + +gpu::Buffer InProcessCommandBuffer::CreateTransferBuffer(size_t size, + int32* id) { + base::AutoLock lock(command_buffer_lock_); + return command_buffer_->CreateTransferBuffer(size, id); +} + +void InProcessCommandBuffer::DestroyTransferBuffer(int32 id) { + base::Closure task = base::Bind(&CommandBuffer::DestroyTransferBuffer, + base::Unretained(command_buffer_.get()), + id); + + QueueTask(task); +} + +gpu::Buffer InProcessCommandBuffer::GetTransferBuffer(int32 id) { + NOTREACHED(); + return gpu::Buffer(); +} + +uint32 InProcessCommandBuffer::InsertSyncPoint() { + NOTREACHED(); + return 0; +} +void InProcessCommandBuffer::SignalSyncPoint(unsigned sync_point, + const base::Closure& callback) { + QueueTask(WrapCallback(callback)); +} + +gpu::error::Error InProcessCommandBuffer::GetLastError() { + return last_state_.error; +} + +bool InProcessCommandBuffer::Initialize() { + NOTREACHED(); + return false; +} + +void InProcessCommandBuffer::SetGetOffset(int32 get_offset) { NOTREACHED(); } + +void InProcessCommandBuffer::SetToken(int32 token) { NOTREACHED(); } + +void InProcessCommandBuffer::SetParseError(gpu::error::Error error) { + NOTREACHED(); +} + +void InProcessCommandBuffer::SetContextLostReason( + gpu::error::ContextLostReason reason) { + NOTREACHED(); +} + +namespace { + +static void PostCallback(const scoped_refptr<base::MessageLoopProxy>& loop, + const base::Closure& callback) { + if (loop != base::MessageLoopProxy::current()) + loop->PostTask(FROM_HERE, callback); + else + callback.Run(); +} + +static void RunCallback(scoped_ptr<base::Closure> callback) { + DCHECK(callback.get()); + callback->Run(); +} + +} // anonymous namespace + +base::Closure InProcessCommandBuffer::WrapCallback( + const base::Closure& callback) { + // Make sure the callback gets deleted on the target thread by passing + // ownership. + scoped_ptr<base::Closure> scoped_callback(new base::Closure(callback)); + base::Closure callback_on_client_thread = + base::Bind(&RunCallback, base::Passed(&scoped_callback)); + base::Closure wrapped_callback = + base::Bind(&PostCallback, base::MessageLoopProxy::current(), + callback); + return wrapped_callback; +} + +// static +void InProcessCommandBuffer::EnableVirtualizedContext() { + g_use_virtualized_gl_context = true; +} + +// static +void InProcessCommandBuffer::SetScheduleCallback( + const base::Closure& callback) { + DCHECK(!g_uses_explicit_scheduling); + DCHECK(!SchedulerClientBase::HasClients()); + g_uses_explicit_scheduling = true; + g_gpu_queue.Get().SetScheduleCallback(callback); +} + +// static +void InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread() { + g_gpu_queue.Get().RunTasks(); +} + +} // namespace gpu diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h new file mode 100644 index 0000000000..88d437dace --- /dev/null +++ b/gpu/command_buffer/service/in_process_command_buffer.h @@ -0,0 +1,154 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_IN_PROCESS_COMMAND_BUFFER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_IN_PROCESS_COMMAND_BUFFER_H_ + +#include <vector> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/synchronization/lock.h" +#include "base/synchronization/waitable_event.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/gpu_export.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gl/gpu_preference.h" + +namespace gfx { +class GLContext; +class GLImage; +class GLSurface; +class Size; +} + +namespace gpu { + +namespace gles2 { +class GLES2Decoder; +} + +class GpuScheduler; +class TransferBufferManagerInterface; + +// This class provides a thread-safe interface to the global GPU service (for +// example GPU thread) when being run in single process mode. +// However, the behavior for accessing one context (i.e. one instance of this +// class) from different client threads is undefined. +class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer { + public: + InProcessCommandBuffer(); + virtual ~InProcessCommandBuffer(); + + // Used to override the GPU thread with explicit scheduling. + // (By default an internal GPU thread will be spawned to handle all GL work + // and the two functions are unused.) + // The callback will be called from different client threads. After the + // callback is issued, the client is expected to eventually call + // ProcessGpuWorkOnCurrentThread(). The latter cannot be called from different + // threads. + // The callback needs to be set before any context is created. + static void SetScheduleCallback(const base::Closure& callback); + static void ProcessGpuWorkOnCurrentThread(); + + static void EnableVirtualizedContext(); + + bool Initialize(bool is_offscreen, + bool share_resources, + gfx::AcceleratedWidget window, + const gfx::Size& size, + const char* allowed_extensions, + const std::vector<int32>& attribs, + gfx::GpuPreference gpu_preference, + const base::Closure& context_lost_callback, + unsigned int share_group_id); + void Destroy(); + void SignalSyncPoint(unsigned sync_point, + const base::Closure& callback); + unsigned int CreateImageForGpuMemoryBuffer( + gfx::GpuMemoryBufferHandle buffer, + gfx::Size size); + void RemoveImage(unsigned int image_id); + + // CommandBuffer implementation: + virtual bool Initialize() OVERRIDE; + virtual State GetState() OVERRIDE; + virtual State GetLastState() OVERRIDE; + virtual int32 GetLastToken() OVERRIDE; + virtual void Flush(int32 put_offset) OVERRIDE; + virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE; + virtual void SetGetBuffer(int32 shm_id) OVERRIDE; + virtual void SetGetOffset(int32 get_offset) OVERRIDE; + virtual gpu::Buffer CreateTransferBuffer(size_t size, int32* id) OVERRIDE; + virtual void DestroyTransferBuffer(int32 id) OVERRIDE; + virtual gpu::Buffer GetTransferBuffer(int32 id) OVERRIDE; + virtual void SetToken(int32 token) OVERRIDE; + virtual void SetParseError(gpu::error::Error error) OVERRIDE; + virtual void SetContextLostReason( + gpu::error::ContextLostReason reason) OVERRIDE; + virtual uint32 InsertSyncPoint() OVERRIDE; + virtual gpu::error::Error GetLastError() OVERRIDE; + + // The serializer interface to the GPU service (i.e. thread). + class SchedulerClient { + public: + virtual ~SchedulerClient() {} + virtual void QueueTask(const base::Closure& task) = 0; + }; + + private: + bool InitializeOnGpuThread(bool is_offscreen, + gfx::AcceleratedWidget window, + const gfx::Size& size, + const char* allowed_extensions, + const std::vector<int32>& attribs, + gfx::GpuPreference gpu_preference); + bool DestroyOnGpuThread(); + void FlushOnGpuThread(int32 put_offset); + void CreateImageOnGpuThread(gfx::GpuMemoryBufferHandle buffer, + gfx::Size size, + unsigned int image_id); + void RemoveImageOnGpuThread(unsigned int image_id); + bool MakeCurrent(); + bool IsContextLost(); + base::Closure WrapCallback(const base::Closure& callback); + State GetStateFast(); + void QueueTask(const base::Closure& task) { queue_->QueueTask(task); } + + // Callbacks: + void OnContextLost(); + void OnResizeView(gfx::Size size, float scale_factor); + bool GetBufferChanged(int32 transfer_buffer_id); + void PumpCommands(); + + // Members accessed on the gpu thread (possibly with the exception of + // creation): + bool context_lost_; + bool share_resources_; + scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; + scoped_ptr<GpuScheduler> gpu_scheduler_; + scoped_ptr<gles2::GLES2Decoder> decoder_; + scoped_refptr<gfx::GLContext> context_; + scoped_refptr<gfx::GLSurface> surface_; + base::Closure context_lost_callback_; + unsigned int share_group_id_; + + // Members accessed on the client thread: + State last_state_; + int32 last_put_offset_; + + // Accessed on both threads: + scoped_ptr<CommandBuffer> command_buffer_; + base::Lock command_buffer_lock_; + base::WaitableEvent flush_event_; + scoped_ptr<SchedulerClient> queue_; + + DISALLOW_COPY_AND_ASSIGN(InProcessCommandBuffer); +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_IN_PROCESS_COMMAND_BUFFER_H_ diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi index c47f15f86c..37d28a5b4c 100644 --- a/gpu/command_buffer_service.gypi +++ b/gpu/command_buffer_service.gypi @@ -86,6 +86,8 @@ 'command_buffer/service/id_manager.cc', 'command_buffer/service/image_manager.cc', 'command_buffer/service/image_manager.h', + 'command_buffer/service/in_process_command_buffer.cc', + 'command_buffer/service/in_process_command_buffer.h', 'command_buffer/service/logger.cc', 'command_buffer/service/logger.h', 'command_buffer/service/mailbox_manager.cc', diff --git a/gpu/command_buffer_service.target.darwin-arm.mk b/gpu/command_buffer_service.target.darwin-arm.mk index 8c6fdca212..dc7f90e20f 100644 --- a/gpu/command_buffer_service.target.darwin-arm.mk +++ b/gpu/command_buffer_service.target.darwin-arm.mk @@ -53,6 +53,7 @@ LOCAL_SRC_FILES := \ gpu/command_buffer/service/gpu_tracer.cc \ gpu/command_buffer/service/id_manager.cc \ gpu/command_buffer/service/image_manager.cc \ + gpu/command_buffer/service/in_process_command_buffer.cc \ gpu/command_buffer/service/logger.cc \ gpu/command_buffer/service/mailbox_manager.cc \ gpu/command_buffer/service/memory_program_cache.cc \ diff --git a/gpu/command_buffer_service.target.darwin-mips.mk b/gpu/command_buffer_service.target.darwin-mips.mk index f324f40bb5..8ab0fbf9a7 100644 --- a/gpu/command_buffer_service.target.darwin-mips.mk +++ b/gpu/command_buffer_service.target.darwin-mips.mk @@ -53,6 +53,7 @@ LOCAL_SRC_FILES := \ gpu/command_buffer/service/gpu_tracer.cc \ gpu/command_buffer/service/id_manager.cc \ gpu/command_buffer/service/image_manager.cc \ + gpu/command_buffer/service/in_process_command_buffer.cc \ gpu/command_buffer/service/logger.cc \ gpu/command_buffer/service/mailbox_manager.cc \ gpu/command_buffer/service/memory_program_cache.cc \ diff --git a/gpu/command_buffer_service.target.darwin-x86.mk b/gpu/command_buffer_service.target.darwin-x86.mk index 4cef07bcea..6c7b408aec 100644 --- a/gpu/command_buffer_service.target.darwin-x86.mk +++ b/gpu/command_buffer_service.target.darwin-x86.mk @@ -53,6 +53,7 @@ LOCAL_SRC_FILES := \ gpu/command_buffer/service/gpu_tracer.cc \ gpu/command_buffer/service/id_manager.cc \ gpu/command_buffer/service/image_manager.cc \ + gpu/command_buffer/service/in_process_command_buffer.cc \ gpu/command_buffer/service/logger.cc \ gpu/command_buffer/service/mailbox_manager.cc \ gpu/command_buffer/service/memory_program_cache.cc \ diff --git a/gpu/command_buffer_service.target.linux-arm.mk b/gpu/command_buffer_service.target.linux-arm.mk index 8c6fdca212..dc7f90e20f 100644 --- a/gpu/command_buffer_service.target.linux-arm.mk +++ b/gpu/command_buffer_service.target.linux-arm.mk @@ -53,6 +53,7 @@ LOCAL_SRC_FILES := \ gpu/command_buffer/service/gpu_tracer.cc \ gpu/command_buffer/service/id_manager.cc \ gpu/command_buffer/service/image_manager.cc \ + gpu/command_buffer/service/in_process_command_buffer.cc \ gpu/command_buffer/service/logger.cc \ gpu/command_buffer/service/mailbox_manager.cc \ gpu/command_buffer/service/memory_program_cache.cc \ diff --git a/gpu/command_buffer_service.target.linux-mips.mk b/gpu/command_buffer_service.target.linux-mips.mk index f324f40bb5..8ab0fbf9a7 100644 --- a/gpu/command_buffer_service.target.linux-mips.mk +++ b/gpu/command_buffer_service.target.linux-mips.mk @@ -53,6 +53,7 @@ LOCAL_SRC_FILES := \ gpu/command_buffer/service/gpu_tracer.cc \ gpu/command_buffer/service/id_manager.cc \ gpu/command_buffer/service/image_manager.cc \ + gpu/command_buffer/service/in_process_command_buffer.cc \ gpu/command_buffer/service/logger.cc \ gpu/command_buffer/service/mailbox_manager.cc \ gpu/command_buffer/service/memory_program_cache.cc \ diff --git a/gpu/command_buffer_service.target.linux-x86.mk b/gpu/command_buffer_service.target.linux-x86.mk index 4cef07bcea..6c7b408aec 100644 --- a/gpu/command_buffer_service.target.linux-x86.mk +++ b/gpu/command_buffer_service.target.linux-x86.mk @@ -53,6 +53,7 @@ LOCAL_SRC_FILES := \ gpu/command_buffer/service/gpu_tracer.cc \ gpu/command_buffer/service/id_manager.cc \ gpu/command_buffer/service/image_manager.cc \ + gpu/command_buffer/service/in_process_command_buffer.cc \ gpu/command_buffer/service/logger.cc \ gpu/command_buffer/service/mailbox_manager.cc \ gpu/command_buffer/service/memory_program_cache.cc \ |