diff options
author | reveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-16 09:25:05 +0000 |
---|---|---|
committer | reveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-16 09:25:05 +0000 |
commit | 2b1767cf508a22ca32767ce3ed0a25c9506d855d (patch) | |
tree | 72bac0c2afa5fb9771a2101c1e067ca0bbbc5481 /ui | |
parent | 909dd1e9ee6a590fc988fc3d5a856e9892707e18 (diff) | |
download | chromium_src-2b1767cf508a22ca32767ce3ed0a25c9506d855d.zip chromium_src-2b1767cf508a22ca32767ce3ed0a25c9506d855d.tar.gz chromium_src-2b1767cf508a22ca32767ce3ed0a25c9506d855d.tar.bz2 |
gpu: Implement idle async pixel transfers.
This makes the fallback pixel transfer implementation perform
texture uploads when command buffer is idle.
BUG=161337
R=epenner@chromium.org
Review URL: https://chromiumcodereview.appspot.com/12040049
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188558 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/gl/async_pixel_transfer_delegate.h | 10 | ||||
-rw-r--r-- | ui/gl/async_pixel_transfer_delegate_android.cc | 25 | ||||
-rw-r--r-- | ui/gl/async_pixel_transfer_delegate_idle.cc | 328 | ||||
-rw-r--r-- | ui/gl/async_pixel_transfer_delegate_idle.h | 96 | ||||
-rw-r--r-- | ui/gl/async_pixel_transfer_delegate_stub.cc | 20 | ||||
-rw-r--r-- | ui/gl/async_pixel_transfer_delegate_stub.h | 2 | ||||
-rw-r--r-- | ui/gl/gl.gyp | 2 |
7 files changed, 465 insertions, 18 deletions
diff --git a/ui/gl/async_pixel_transfer_delegate.h b/ui/gl/async_pixel_transfer_delegate.h index 44bcbcb..3f9f434 100644 --- a/ui/gl/async_pixel_transfer_delegate.h +++ b/ui/gl/async_pixel_transfer_delegate.h @@ -112,6 +112,16 @@ class GL_EXPORT AsyncPixelTransferDelegate { virtual uint32 GetTextureUploadCount() = 0; virtual base::TimeDelta GetTotalTextureUploadTime() = 0; + // ProcessMorePendingTransfers() will be called at a good time + // to process a small amount of pending transfer work while + // NeedsProcessMorePendingTransfers() returns true. Implementations + // that can't dispatch work to separate threads should use + // this to avoid blocking the caller thread inappropriately. + // ProcessMorePendingTransfers() returns true iff a texture was + // bound to texture-unit zero. + virtual bool ProcessMorePendingTransfers() = 0; + virtual bool NeedsProcessMorePendingTransfers() = 0; + protected: AsyncPixelTransferDelegate() {} // For testing, as returning scoped_ptr wouldn't work with MOCK_METHOD. diff --git a/ui/gl/async_pixel_transfer_delegate_android.cc b/ui/gl/async_pixel_transfer_delegate_android.cc index 6a34639..31f90bc 100644 --- a/ui/gl/async_pixel_transfer_delegate_android.cc +++ b/ui/gl/async_pixel_transfer_delegate_android.cc @@ -113,7 +113,7 @@ void DoFullTexSubImage2D(const AsyncTexImage2DParams& tex_params, void* data) { // Gets the address of the data from shared memory. void* GetAddress(SharedMemory* shared_memory, uint32 shm_data_offset) { // Memory bounds have already been validated, so there - // is just DCHECKS here. + // are just DCHECKS here. CHECK(shared_memory); CHECK(shared_memory->memory()); return static_cast<int8*>(shared_memory->memory()) + shm_data_offset; @@ -212,7 +212,6 @@ class TransferStateInternal // We can only change the active texture and unit 0, // as that is all that will be restored. - glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture_id_); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_); bind_callback_.Run(); @@ -384,6 +383,8 @@ class AsyncPixelTransferDelegateAndroid AsyncPixelTransferState* state) OVERRIDE; virtual uint32 GetTextureUploadCount() OVERRIDE; virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE; + virtual bool ProcessMorePendingTransfers() OVERRIDE; + virtual bool NeedsProcessMorePendingTransfers() OVERRIDE; private: // implement AsyncPixelTransferDelegate: @@ -483,12 +484,11 @@ AsyncPixelTransferState* // we just using image_preservedd=TRUE on Qualcomm as a work-around. bool use_image_preserved = is_qualcomm_ || is_imagination_; - return static_cast<AsyncPixelTransferState*>( - new AsyncTransferStateAndroid(texture_id, - define_params, - wait_for_uploads, - wait_for_creation, - use_image_preserved)); + return new AsyncTransferStateAndroid(texture_id, + define_params, + wait_for_uploads, + wait_for_creation, + use_image_preserved); } bool AsyncPixelTransferDelegateAndroid::BindCompletedAsyncTransfers() { @@ -658,6 +658,15 @@ base::TimeDelta AsyncPixelTransferDelegateAndroid::GetTotalTextureUploadTime() { return total_texture_upload_time; } +bool AsyncPixelTransferDelegateAndroid::ProcessMorePendingTransfers() { + return false; +} + +bool AsyncPixelTransferDelegateAndroid::NeedsProcessMorePendingTransfers() { + return false; +} + + namespace { void SetGlParametersForEglImageTexture() { // These params are needed for EGLImage creation to succeed on several diff --git a/ui/gl/async_pixel_transfer_delegate_idle.cc b/ui/gl/async_pixel_transfer_delegate_idle.cc new file mode 100644 index 0000000..9c721e5 --- /dev/null +++ b/ui/gl/async_pixel_transfer_delegate_idle.cc @@ -0,0 +1,328 @@ +// Copyright (c) 2013 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 "ui/gl/async_pixel_transfer_delegate_idle.h" + +#include "base/bind.h" +#include "base/debug/trace_event.h" +#include "base/lazy_instance.h" +#include "base/message_loop.h" +#include "base/process_util.h" +#include "base/shared_memory.h" +#include "build/build_config.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_surface.h" +#include "ui/gl/safe_shared_memory_pool.h" +#include "ui/gl/scoped_make_current.h" + +using base::SharedMemory; +using base::SharedMemoryHandle; + +namespace gfx { + +namespace { + +// Gets the address of the data from shared memory. +void* GetAddress(SharedMemory* shared_memory, uint32 shm_data_offset) { + // Memory bounds have already been validated, so there + // are just DCHECKS here. + DCHECK(shared_memory); + DCHECK(shared_memory->memory()); + return static_cast<int8*>(shared_memory->memory()) + shm_data_offset; +} + +base::LazyInstance<SafeSharedMemoryPool> g_safe_shared_memory_pool = + LAZY_INSTANCE_INITIALIZER; + +SafeSharedMemoryPool* safe_shared_memory_pool() { + return g_safe_shared_memory_pool.Pointer(); +} + +static uint64 g_next_pixel_transfer_state_id = 1; + +} // namespace + +#if !defined(OS_ANDROID) +scoped_ptr<AsyncPixelTransferDelegate> + AsyncPixelTransferDelegate::Create(gfx::GLContext* context) { + return AsyncPixelTransferDelegateIdle::Create(context); +} +#endif + +scoped_ptr<AsyncPixelTransferDelegate> + AsyncPixelTransferDelegateIdle::Create(gfx::GLContext* context) { + return make_scoped_ptr( + static_cast<AsyncPixelTransferDelegate*>( + new AsyncPixelTransferDelegateIdle())); +} + +class AsyncPixelTransferStateIdle : public AsyncPixelTransferState { + public: + typedef base::Callback<void(GLuint)> TransferCallback; + + explicit AsyncPixelTransferStateIdle(GLuint texture_id) + : id_(g_next_pixel_transfer_state_id++), + texture_id_(texture_id), + transfer_in_progress_(false) { + } + virtual ~AsyncPixelTransferStateIdle() {} + + // Overridden from gfx::AsyncPixelTransferState: + virtual bool TransferIsInProgress() OVERRIDE { + return transfer_in_progress_; + } + + uint64 id() const { return id_; } + + void set_transfer_in_progress(bool transfer_in_progress) { + transfer_in_progress_ = transfer_in_progress; + } + + void PerformTransfer(const TransferCallback& callback) { + DCHECK(texture_id_); + DCHECK(transfer_in_progress_); + callback.Run(texture_id_); + transfer_in_progress_ = false; + } + + private: + uint64 id_; + GLuint texture_id_; + bool transfer_in_progress_; +}; + +AsyncPixelTransferDelegateIdle::Transfer::Transfer( + uint64 id, const base::Closure& task) + : id(id), + task(task) { +} + +AsyncPixelTransferDelegateIdle::Transfer::~Transfer() {} + +AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle() + : texture_upload_count_(0) { +} + +AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() { +} + +AsyncPixelTransferState* + AsyncPixelTransferDelegateIdle::CreateRawPixelTransferState( + GLuint texture_id, + const AsyncTexImage2DParams& define_params) { + return new AsyncPixelTransferStateIdle(texture_id); +} + +bool AsyncPixelTransferDelegateIdle::BindCompletedAsyncTransfers() { + // Everything is already bound. + return false; +} + +void AsyncPixelTransferDelegateIdle::AsyncNotifyCompletion( + const AsyncMemoryParams& mem_params, + const CompletionCallback& callback) { + if (transfers_.empty()) { + callback.Run(mem_params); + return; + } + + transfers_.back().notifications.push( + base::Bind( + &AsyncPixelTransferDelegateIdle::PerformNotifyCompletion, + AsWeakPtr(), + mem_params, + base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), + mem_params.shared_memory, + mem_params.shm_size)), + callback)); +} + +void AsyncPixelTransferDelegateIdle::AsyncTexImage2D( + AsyncPixelTransferState* transfer_state, + const AsyncTexImage2DParams& tex_params, + const AsyncMemoryParams& mem_params, + const base::Closure& bind_callback) { + AsyncPixelTransferStateIdle* state = + static_cast<AsyncPixelTransferStateIdle*>(transfer_state); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target); + DCHECK(mem_params.shared_memory); + DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size, + mem_params.shm_size); + DCHECK(state); + + transfers_.push_back( + Transfer( + state->id(), + base::Bind( + &AsyncPixelTransferStateIdle::PerformTransfer, + base::AsWeakPtr(state), + base::Bind( + &AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D, + AsWeakPtr(), + tex_params, + mem_params, + bind_callback, + base::Owned(new ScopedSafeSharedMemory( + safe_shared_memory_pool(), + mem_params.shared_memory, + mem_params.shm_size)))))); + + state->set_transfer_in_progress(true); +} + +void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D( + AsyncPixelTransferState* transfer_state, + const AsyncTexSubImage2DParams& tex_params, + const AsyncMemoryParams& mem_params) { + AsyncPixelTransferStateIdle* state = + static_cast<AsyncPixelTransferStateIdle*>(transfer_state); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target); + DCHECK(mem_params.shared_memory); + DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size, + mem_params.shm_size); + DCHECK(state); + + transfers_.push_back( + Transfer( + state->id(), + base::Bind( + &AsyncPixelTransferStateIdle::PerformTransfer, + base::AsWeakPtr(state), + base::Bind( + &AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D, + AsWeakPtr(), + tex_params, + mem_params, + base::Owned(new ScopedSafeSharedMemory( + safe_shared_memory_pool(), + mem_params.shared_memory, + mem_params.shm_size)))))); + + state->set_transfer_in_progress(true); +} + +void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion( + AsyncPixelTransferState* transfer_state) { + AsyncPixelTransferStateIdle* state = + static_cast<AsyncPixelTransferStateIdle*>(transfer_state); + DCHECK(state); + + for (std::list<Transfer>::iterator iter = transfers_.begin(); + iter != transfers_.end(); ++iter) { + if (iter->id != state->id()) + continue; + + ProcessTransfer(*iter); + transfers_.erase(iter); + break; + } +} + +uint32 AsyncPixelTransferDelegateIdle::GetTextureUploadCount() { + return texture_upload_count_; +} + +base::TimeDelta AsyncPixelTransferDelegateIdle::GetTotalTextureUploadTime() { + return total_texture_upload_time_; +} + +bool AsyncPixelTransferDelegateIdle::ProcessMorePendingTransfers() { + if (transfers_.empty()) + return false; + + ProcessTransfer(transfers_.front()); + transfers_.pop_front(); + return true; +} + +bool AsyncPixelTransferDelegateIdle::NeedsProcessMorePendingTransfers() { + return !transfers_.empty(); +} + +void AsyncPixelTransferDelegateIdle::ProcessTransfer(Transfer& transfer) { + transfer.task.Run(); + while (!transfer.notifications.empty()) { + transfer.notifications.front().Run(); + transfer.notifications.pop(); + } +} + +void AsyncPixelTransferDelegateIdle::PerformNotifyCompletion( + AsyncMemoryParams mem_params, + ScopedSafeSharedMemory* safe_shared_memory, + const CompletionCallback& callback) { + TRACE_EVENT0("gpu", "PerformNotifyCompletion"); + gfx::AsyncMemoryParams safe_mem_params = mem_params; + safe_mem_params.shared_memory = safe_shared_memory->shared_memory(); + callback.Run(safe_mem_params); +} + +void AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D( + AsyncTexImage2DParams tex_params, + AsyncMemoryParams mem_params, + const base::Closure& bind_callback, + ScopedSafeSharedMemory* safe_shared_memory, + GLuint texture_id) { + TRACE_EVENT2("gpu", "PerformAsyncTexImage2D", + "width", tex_params.width, + "height", tex_params.height); + + void* data = GetAddress(safe_shared_memory->shared_memory(), + mem_params.shm_data_offset); + + glBindTexture(tex_params.target, texture_id); + + { + TRACE_EVENT0("gpu", "glTexImage2D"); + glTexImage2D( + tex_params.target, + tex_params.level, + tex_params.internal_format, + tex_params.width, + tex_params.height, + tex_params.border, + tex_params.format, + tex_params.type, + data); + } + + // The texture is already fully bound so just call it now. + bind_callback.Run(); +} + +void AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D( + AsyncTexSubImage2DParams tex_params, + AsyncMemoryParams mem_params, + ScopedSafeSharedMemory* safe_shared_memory, + GLuint texture_id) { + TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D", + "width", tex_params.width, + "height", tex_params.height); + + void* data = GetAddress(safe_shared_memory->shared_memory(), + mem_params.shm_data_offset); + + base::TimeTicks begin_time(base::TimeTicks::HighResNow()); + glBindTexture(tex_params.target, texture_id); + + { + TRACE_EVENT0("gpu", "glTexSubImage2D"); + glTexSubImage2D( + tex_params.target, + tex_params.level, + tex_params.xoffset, + tex_params.yoffset, + tex_params.width, + tex_params.height, + tex_params.format, + tex_params.type, + data); + } + + texture_upload_count_++; + total_texture_upload_time_ += base::TimeTicks::HighResNow() - begin_time; +} + +} // namespace gfx diff --git a/ui/gl/async_pixel_transfer_delegate_idle.h b/ui/gl/async_pixel_transfer_delegate_idle.h new file mode 100644 index 0000000..101c526 --- /dev/null +++ b/ui/gl/async_pixel_transfer_delegate_idle.h @@ -0,0 +1,96 @@ +// Copyright (c) 2013 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 UI_GL_ASYNC_TASK_DELEGATE_IDLE_H_ +#define UI_GL_ASYNC_TASK_DELEGATE_IDLE_H_ + +#include <list> +#include <queue> + +#include "base/callback.h" +#include "ui/gl/async_pixel_transfer_delegate.h" + +namespace gfx { +class GLSurface; +class TransferStateInternalIdle; +class ScopedSafeSharedMemory; + +// Class which handles async pixel transfers in a platform +// independent way. +class AsyncPixelTransferDelegateIdle : public AsyncPixelTransferDelegate, + public base::SupportsWeakPtr<AsyncPixelTransferDelegateIdle> { + public: + static scoped_ptr<AsyncPixelTransferDelegate> + Create(gfx::GLContext* context); + + AsyncPixelTransferDelegateIdle(); + virtual ~AsyncPixelTransferDelegateIdle(); + + // implement AsyncPixelTransferDelegate: + virtual bool BindCompletedAsyncTransfers() OVERRIDE; + virtual void AsyncNotifyCompletion( + const AsyncMemoryParams& mem_params, + const CompletionCallback& callback) OVERRIDE; + virtual void AsyncTexImage2D( + AsyncPixelTransferState* transfer_state, + const AsyncTexImage2DParams& tex_params, + const AsyncMemoryParams& mem_params, + const base::Closure& bind_callback) OVERRIDE; + virtual void AsyncTexSubImage2D( + AsyncPixelTransferState* transfer_state, + const AsyncTexSubImage2DParams& tex_params, + const AsyncMemoryParams& mem_params) OVERRIDE; + virtual void WaitForTransferCompletion( + AsyncPixelTransferState* transfer_state) OVERRIDE; + virtual uint32 GetTextureUploadCount() OVERRIDE; + virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE; + virtual bool ProcessMorePendingTransfers() OVERRIDE; + virtual bool NeedsProcessMorePendingTransfers() OVERRIDE; + + private: + struct Transfer { + Transfer(uint64 id, const base::Closure& task); + ~Transfer(); + + uint64 id; + base::Closure task; + std::queue<base::Closure> notifications; + }; + + void ProcessTransfer(Transfer& transfer); + + // implement AsyncPixelTransferDelegate: + virtual AsyncPixelTransferState* + CreateRawPixelTransferState( + GLuint texture_id, + const AsyncTexImage2DParams& define_params) OVERRIDE; + + void PerformNotifyCompletion( + AsyncMemoryParams mem_params, + ScopedSafeSharedMemory* safe_shared_memory, + const CompletionCallback& callback); + void PerformAsyncTexImage2D( + AsyncTexImage2DParams tex_params, + AsyncMemoryParams mem_params, + const base::Closure& bind_callback, + ScopedSafeSharedMemory* safe_shared_memory, + GLuint texture_id); + void PerformAsyncTexSubImage2D( + AsyncTexSubImage2DParams tex_params, + AsyncMemoryParams mem_params, + ScopedSafeSharedMemory* safe_shared_memory, + GLuint texture_id); + + int texture_upload_count_; + base::TimeDelta total_texture_upload_time_; + + std::list<Transfer> transfers_; + + DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateIdle); +}; + +} // namespace gfx + +#endif // UI_GL_ASYNC_TASK_DELEGATE_IDLE_H_ + diff --git a/ui/gl/async_pixel_transfer_delegate_stub.cc b/ui/gl/async_pixel_transfer_delegate_stub.cc index 2ec16bb..e3835a2 100644 --- a/ui/gl/async_pixel_transfer_delegate_stub.cc +++ b/ui/gl/async_pixel_transfer_delegate_stub.cc @@ -18,7 +18,7 @@ void* GetAddress(SharedMemory* shared_memory, uint32 shm_data_offset, uint32 shm_data_size) { // Memory bounds have already been validated, so there - // is just DCHECKS here. + // are just DCHECKS here. DCHECK(shared_memory); DCHECK(shared_memory->memory()); DCHECK_LE(shm_data_offset + shm_data_size, shm_size); @@ -28,13 +28,6 @@ void* GetAddress(SharedMemory* shared_memory, namespace gfx { -#if !defined(OS_ANDROID) -scoped_ptr<AsyncPixelTransferDelegate> - AsyncPixelTransferDelegate::Create(gfx::GLContext* context) { - return AsyncPixelTransferDelegateStub::Create(context); -} -#endif - scoped_ptr<AsyncPixelTransferDelegate> AsyncPixelTransferDelegateStub::Create(gfx::GLContext* context) { return make_scoped_ptr( @@ -63,8 +56,7 @@ AsyncPixelTransferState* AsyncPixelTransferDelegateStub::CreateRawPixelTransferState( GLuint texture_id, const AsyncTexImage2DParams& define_params) { - return static_cast<AsyncPixelTransferState*>( - new AsyncTransferStateStub(texture_id)); + return new AsyncTransferStateStub(texture_id); } bool AsyncPixelTransferDelegateStub::BindCompletedAsyncTransfers() { @@ -141,5 +133,13 @@ base::TimeDelta AsyncPixelTransferDelegateStub::GetTotalTextureUploadTime() { return total_texture_upload_time_; } +bool AsyncPixelTransferDelegateStub::ProcessMorePendingTransfers() { + return false; +} + +bool AsyncPixelTransferDelegateStub::NeedsProcessMorePendingTransfers() { + return false; +} + } // namespace gfx diff --git a/ui/gl/async_pixel_transfer_delegate_stub.h b/ui/gl/async_pixel_transfer_delegate_stub.h index ae90342..40548b1 100644 --- a/ui/gl/async_pixel_transfer_delegate_stub.h +++ b/ui/gl/async_pixel_transfer_delegate_stub.h @@ -50,6 +50,8 @@ class AsyncPixelTransferDelegateStub : public AsyncPixelTransferDelegate { AsyncPixelTransferState* state) OVERRIDE; virtual uint32 GetTextureUploadCount() OVERRIDE; virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE; + virtual bool ProcessMorePendingTransfers() OVERRIDE; + virtual bool NeedsProcessMorePendingTransfers() OVERRIDE; private: // implement AsyncPixelTransferDelegate: virtual AsyncPixelTransferState* diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp index 81279bfb..53b3136 100644 --- a/ui/gl/gl.gyp +++ b/ui/gl/gl.gyp @@ -41,6 +41,8 @@ ], 'sources': [ 'async_pixel_transfer_delegate.h', + 'async_pixel_transfer_delegate_idle.cc', + 'async_pixel_transfer_delegate_idle.h', 'async_pixel_transfer_delegate_stub.cc', 'async_pixel_transfer_delegate_stub.h', 'gl_bindings.h', |