Chromium Code Reviews| Index: ui/gl/async_pixel_transfer_delegate_idle.cc |
| 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 0000000000000000000000000000000000000000..902fcdb37c5e31198432b05eebcc97cb60d6ccf7 |
| --- /dev/null |
| +++ b/ui/gl/async_pixel_transfer_delegate_idle.cc |
| @@ -0,0 +1,331 @@ |
| +// 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 |
| + // is 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) { |
|
epenner
2013/03/14 18:23:24
id=id? Would we call it 'id_' by making it a class
reveman
2013/03/14 19:21:47
Yes, but I prefer using a struct for this simple c
epenner
2013/03/14 20:31:00
Touche! I thought it was a bug, but it's totally f
|
| +} |
| + |
| +AsyncPixelTransferDelegateIdle::Transfer::~Transfer() {} |
| + |
| +AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle() |
| + : texture_upload_count_(0) { |
| +} |
| + |
| +AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() { |
| +} |
| + |
| +AsyncPixelTransferState* |
| + AsyncPixelTransferDelegateIdle::CreateRawPixelTransferState( |
| + GLuint texture_id, |
| + const AsyncTexImage2DParams& define_params) { |
| + return static_cast<AsyncPixelTransferState*>( |
| + 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(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(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); |
| + 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, 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); |
| + 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, 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; |
| +} |
| + |
| +} // namespace gfx |