| 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..9c721e58092d2b3edb8a1624b6eba64271e6fb11
|
| --- /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
|
|
|