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 |