Chromium Code Reviews| Index: ui/gl/async_pixel_transfer_delegate_stub.cc |
| diff --git a/ui/gl/async_pixel_transfer_delegate_stub.cc b/ui/gl/async_pixel_transfer_delegate_stub.cc |
| index 093cb116b28e3a3247861c0be2d3b9e27e1c83e3..8294460667465efadcbe1a0bc81b1af320d33e20 100644 |
| --- a/ui/gl/async_pixel_transfer_delegate_stub.cc |
| +++ b/ui/gl/async_pixel_transfer_delegate_stub.cc |
| @@ -4,29 +4,43 @@ |
| #include "ui/gl/async_pixel_transfer_delegate_stub.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_size, |
| - uint32 shm_data_offset, |
| - uint32 shm_data_size) { |
| +void* GetAddress(SharedMemory* shared_memory, uint32 shm_data_offset) { |
| // Memory bounds have already been validated, so there |
| // is just DCHECKS here. |
| DCHECK(shared_memory); |
| DCHECK(shared_memory->memory()); |
| - DCHECK_LE(shm_data_offset + shm_data_size, shm_size); |
| return static_cast<int8*>(shared_memory->memory()) + shm_data_offset; |
| } |
| -} // namespace |
| -namespace gfx { |
| +base::LazyInstance<SafeSharedMemoryPool> g_safe_shared_memory_pool = |
| + LAZY_INSTANCE_INITIALIZER; |
| + |
| +SafeSharedMemoryPool* safe_shared_memory_pool() { |
| + return g_safe_shared_memory_pool.Pointer(); |
| +} |
| + |
| +} // namespace |
| #if !defined(OS_ANDROID) |
| scoped_ptr<AsyncPixelTransferDelegate> |
| @@ -42,26 +56,74 @@ scoped_ptr<AsyncPixelTransferDelegate> |
| new AsyncPixelTransferDelegateStub())); |
| } |
| -AsyncTransferStateStub::AsyncTransferStateStub(GLuint texture_id) { |
| - static const AsyncTexImage2DParams zero_params = {0, 0, 0, 0, 0, 0, 0, 0}; |
| - late_bind_define_params_ = zero_params; |
| - needs_late_bind_ = false; |
| -} |
| +// Class which holds async pixel transfers state. |
| +class TransferStateInternalStub |
| + : public base::RefCounted<TransferStateInternalStub> { |
| + public: |
| + explicit TransferStateInternalStub(GLuint texture_id) |
| + : texture_id_(texture_id), |
| + needs_late_bind_(false), |
| + transfer_in_progress_(false) { |
| + static const AsyncTexImage2DParams zero_params = {0, 0, 0, 0, 0, 0, 0, 0}; |
| + late_bind_define_params_ = zero_params; |
| + } |
| -AsyncTransferStateStub::~AsyncTransferStateStub() { |
| -} |
| + // Implement AsyncPixelTransferState: |
| + bool TransferIsInProgress() { |
| + return transfer_in_progress_; |
| + } |
| -bool AsyncTransferStateStub::TransferIsInProgress() { |
| - return false; |
| -} |
| + void BindTransfer(AsyncTexImage2DParams* bound_params) { |
| + DCHECK(bound_params); |
| + DCHECK(needs_late_bind_); |
| + *bound_params = late_bind_define_params_; |
| + needs_late_bind_ = false; |
| + } |
| + |
| + protected: |
| + friend class base::RefCounted<TransferStateInternalStub>; |
| + friend class AsyncPixelTransferDelegateStub; |
| + |
| + virtual ~TransferStateInternalStub() {} |
| -void AsyncTransferStateStub::BindTransfer(AsyncTexImage2DParams* out_params) { |
| - DCHECK(out_params); |
| - DCHECK(needs_late_bind_); |
| - *out_params = late_bind_define_params_; |
| - needs_late_bind_ = false; |
| + GLuint texture_id_; |
| + |
| + // Indicates there is a new EGLImage and the 'real' |
|
Sami
2013/03/07 16:57:19
No EGLImages here :)
reveman
2013/03/07 20:21:04
Done.
|
| + // texture needs to be bound to it as an EGLImage target. |
| + bool needs_late_bind_; |
| + |
| + // Definition params for texture that needs binding. |
| + AsyncTexImage2DParams late_bind_define_params_; |
| + |
| + // Indicates that an async transfer is in progress. |
| + bool transfer_in_progress_; |
| +}; |
| + |
| +// This just wraps an internal ref-counted state object. |
| +class AsyncTransferStateStub : public AsyncPixelTransferState { |
| + public: |
| + explicit AsyncTransferStateStub(GLuint texture_id) |
| + : internal_(new TransferStateInternalStub(texture_id)) { |
| + } |
| + virtual ~AsyncTransferStateStub() {} |
| + virtual bool TransferIsInProgress() { |
| + return internal_->TransferIsInProgress(); |
|
Sami
2013/03/07 16:57:19
Nit: indent by 2.
reveman
2013/03/07 20:21:04
Done.
|
| + } |
| + virtual void BindTransfer(AsyncTexImage2DParams* bound_params) { |
| + internal_->BindTransfer(bound_params); |
|
Sami
2013/03/07 16:57:19
Ditto.
reveman
2013/03/07 20:21:04
Done.
|
| + } |
| + scoped_refptr<TransferStateInternalStub> internal_; |
| +}; |
| + |
| +AsyncPixelTransferDelegateStub::Transfer::Transfer( |
| + TransferStateInternalStub* state, |
| + const base::Closure& task) |
| + : state(state), |
| + task(task) { |
| } |
| +AsyncPixelTransferDelegateStub::Transfer::~Transfer() {} |
| + |
| AsyncPixelTransferDelegateStub::AsyncPixelTransferDelegateStub() |
| : texture_upload_count_(0) { |
| } |
| @@ -79,69 +141,102 @@ AsyncPixelTransferState* |
| void AsyncPixelTransferDelegateStub::AsyncNotifyCompletion( |
| const AsyncMemoryParams& mem_params, |
| const CompletionCallback& callback) { |
| - callback.Run(mem_params); |
| + if (transfers_.empty()) { |
| + callback.Run(mem_params); |
| + return; |
| + } |
| + |
| + transfers_.back().notifications.push( |
| + base::Bind( |
| + &AsyncPixelTransferDelegateStub::PerformNotifyCompletion, |
| + AsWeakPtr(), |
| + mem_params, |
| + base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), |
| + mem_params.shared_memory, |
| + mem_params.shm_size)), |
| + callback)); |
| } |
| void AsyncPixelTransferDelegateStub::AsyncTexImage2D( |
| AsyncPixelTransferState* transfer_state, |
| const AsyncTexImage2DParams& tex_params, |
| const AsyncMemoryParams& mem_params) { |
| - // Save the define params to return later during deferred |
| - // binding of the transfer texture. |
| - DCHECK(transfer_state); |
| - AsyncTransferStateStub* state = |
| - static_cast<AsyncTransferStateStub*>(transfer_state); |
| - // We don't actually need a late bind since this stub does |
| - // everything synchronously, but this tries to be similar |
| - // as an async implementation. |
| + scoped_refptr<TransferStateInternalStub> state = |
| + static_cast<AsyncTransferStateStub*>(transfer_state)->internal_.get(); |
| + DCHECK(mem_params.shared_memory); |
| + DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size, |
| + mem_params.shm_size); |
| + DCHECK(state); |
| + DCHECK(state->texture_id_); |
| + DCHECK(!state->needs_late_bind_); |
| + |
| + // Mark the transfer in progress and save define params for lazy binding. |
| state->needs_late_bind_ = true; |
| state->late_bind_define_params_ = tex_params; |
| - void* data = GetAddress(mem_params.shared_memory, |
| - mem_params.shm_size, |
| - mem_params.shm_data_offset, |
| - mem_params.shm_data_size); |
| - 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); |
| + |
| + transfers_.push_back( |
| + Transfer( |
| + state.get(), |
| + base::Bind( |
| + &AsyncPixelTransferDelegateStub::PerformAsyncTexImage2D, |
| + AsWeakPtr(), |
| + state, |
| + tex_params, |
| + mem_params, |
| + base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), |
| + mem_params.shared_memory, |
| + mem_params.shm_size))))); |
| + |
| + state->transfer_in_progress_ = true; |
| } |
| void AsyncPixelTransferDelegateStub::AsyncTexSubImage2D( |
| AsyncPixelTransferState* transfer_state, |
| const AsyncTexSubImage2DParams& tex_params, |
| const AsyncMemoryParams& mem_params) { |
| - void* data = GetAddress(mem_params.shared_memory, |
| - mem_params.shm_size, |
| - mem_params.shm_data_offset, |
| - mem_params.shm_data_size); |
| - DCHECK(transfer_state); |
| - AsyncTransferStateStub* state = |
| - static_cast<AsyncTransferStateStub*>(transfer_state); |
| + scoped_refptr<TransferStateInternalStub> state = |
| + static_cast<AsyncTransferStateStub*>(transfer_state)->internal_.get(); |
| + DCHECK(mem_params.shared_memory); |
| + DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size, |
| + mem_params.shm_size); |
| + DCHECK(state); |
| + DCHECK(state->texture_id_); |
| DCHECK(!state->needs_late_bind_); |
| - base::TimeTicks begin_time(base::TimeTicks::HighResNow()); |
| - 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; |
| + |
| + transfers_.push_back( |
| + Transfer( |
| + state.get(), |
| + base::Bind( |
| + &AsyncPixelTransferDelegateStub::PerformAsyncTexSubImage2D, |
| + AsWeakPtr(), |
| + state, |
| + tex_params, |
| + mem_params, |
| + base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), |
| + mem_params.shared_memory, |
| + mem_params.shm_size))))); |
| + |
| + state->transfer_in_progress_ = true; |
| } |
| void AsyncPixelTransferDelegateStub::WaitForTransferCompletion( |
| - AsyncPixelTransferState* state) { |
| - // Already done. |
| + AsyncPixelTransferState* transfer_state) { |
| + scoped_refptr<TransferStateInternalStub> state = |
| + static_cast<AsyncTransferStateStub*>(transfer_state)->internal_.get(); |
| + |
| + for (std::list<Transfer>::iterator iter = transfers_.begin(); |
| + iter != transfers_.end(); ++iter) { |
| + if (iter->state.get() != state) |
| + continue; |
| + |
| + iter->task.Run(); |
|
Sami
2013/03/07 16:57:19
Neat!
Is it worth wrapping this bit into PerformT
reveman
2013/03/07 20:21:04
Done. Added ProcessTransfer.
|
| + while (!iter->notifications.empty()) { |
| + iter->notifications.front().Run(); |
| + iter->notifications.pop(); |
| + } |
| + transfers_.erase(iter); |
| + break; |
| + } |
| } |
| uint32 AsyncPixelTransferDelegateStub::GetTextureUploadCount() { |
| @@ -152,5 +247,101 @@ base::TimeDelta AsyncPixelTransferDelegateStub::GetTotalTextureUploadTime() { |
| return total_texture_upload_time_; |
| } |
| +void AsyncPixelTransferDelegateStub::ProcessPendingTransfers() { |
| + if (transfers_.empty()) |
| + return; |
| + |
| + transfers_.front().task.Run(); |
| + while (!transfers_.front().notifications.empty()) { |
| + transfers_.front().notifications.front().Run(); |
| + transfers_.front().notifications.pop(); |
| + } |
| + transfers_.pop_front(); |
| +} |
| + |
| +bool AsyncPixelTransferDelegateStub::HasPendingTransfers() { |
| + return !transfers_.empty(); |
| +} |
| + |
| +void AsyncPixelTransferDelegateStub::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 AsyncPixelTransferDelegateStub::PerformAsyncTexImage2D( |
| + scoped_refptr<TransferStateInternalStub> state, |
| + AsyncTexImage2DParams tex_params, |
| + AsyncMemoryParams mem_params, |
| + ScopedSafeSharedMemory* safe_shared_memory) { |
| + TRACE_EVENT2("gpu", "PerformAsyncTexImage2D", |
| + "width", tex_params.width, |
| + "height", tex_params.height); |
| + DCHECK_EQ(0, tex_params.level); |
| + |
| + void* data = GetAddress(safe_shared_memory->shared_memory(), |
| + mem_params.shm_data_offset); |
| + |
| + glActiveTexture(GL_TEXTURE0); |
| + glBindTexture(GL_TEXTURE_2D, state->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); |
| + } |
| + |
| + state->transfer_in_progress_ = false; |
| +} |
| + |
| +void AsyncPixelTransferDelegateStub::PerformAsyncTexSubImage2D( |
| + scoped_refptr<TransferStateInternalStub> state, |
| + AsyncTexSubImage2DParams tex_params, |
| + AsyncMemoryParams mem_params, |
| + ScopedSafeSharedMemory* safe_shared_memory) { |
| + TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D", |
| + "width", tex_params.width, |
| + "height", tex_params.height); |
| + DCHECK_EQ(0, tex_params.level); |
| + |
| + void* data = GetAddress(safe_shared_memory->shared_memory(), |
| + mem_params.shm_data_offset); |
| + |
| + base::TimeTicks begin_time(base::TimeTicks::HighResNow()); |
| + glActiveTexture(GL_TEXTURE0); |
| + glBindTexture(GL_TEXTURE_2D, state->texture_id_); |
| + |
| + { |
| + TRACE_EVENT0("gpu", "glTexSubImage2D"); |
| + glTexSubImage2D( |
| + GL_TEXTURE_2D, |
| + 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; |
| + |
| + state->transfer_in_progress_ = false; |
| +} |
| + |
| } // namespace gfx |