Index: gpu/command_buffer/service/async_pixel_transfer_manager_idle.cc |
diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager_idle.cc b/gpu/command_buffer/service/async_pixel_transfer_manager_idle.cc |
index 61db3b68413dde50d864b6d0ea5ce7218fed71b4..50758276f720bce1f463e1558d872de17b3d3813 100644 |
--- a/gpu/command_buffer/service/async_pixel_transfer_manager_idle.cc |
+++ b/gpu/command_buffer/service/async_pixel_transfer_manager_idle.cc |
@@ -9,6 +9,7 @@ |
#include "base/debug/trace_event_synthetic_delay.h" |
#include "base/lazy_instance.h" |
#include "base/memory/weak_ptr.h" |
+#include "base/synchronization/waitable_event.h" |
#include "ui/gl/scoped_binders.h" |
namespace gpu { |
@@ -17,6 +18,20 @@ namespace { |
static uint64 g_next_pixel_transfer_state_id = 1; |
+static const uint64 kNotificationTask = 0; |
+static const uint64 kSuspendTask = 1; |
+ |
+uint64 NextPixelTransferStateId() { |
+ g_next_pixel_transfer_state_id++; |
+ switch (g_next_pixel_transfer_state_id) { |
+ case kNotificationTask: |
+ case kSuspendTask: |
+ return NextPixelTransferStateId(); |
+ default: |
+ return g_next_pixel_transfer_state_id; |
+ } |
+} |
+ |
void PerformNotifyCompletion( |
AsyncMemoryParams mem_params, |
scoped_refptr<AsyncPixelTransferCompletionObserver> observer) { |
@@ -36,6 +51,10 @@ class AsyncPixelTransferDelegateIdle |
AsyncPixelTransferManagerIdle::SharedState* state, |
GLuint texture_id, |
const AsyncTexImage2DParams& define_params); |
+ AsyncPixelTransferDelegateIdle( |
+ AsyncPixelTransferManagerIdle::SharedState* state, |
+ GLuint texture_id, |
+ const AsyncCompressedTexImage2DParams& define_params); |
~AsyncPixelTransferDelegateIdle() override; |
// Implement AsyncPixelTransferDelegate: |
@@ -44,6 +63,13 @@ class AsyncPixelTransferDelegateIdle |
const base::Closure& bind_callback) override; |
void AsyncTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, |
const AsyncMemoryParams& mem_params) override; |
+ void AsyncCompressedTexImage2D( |
+ const AsyncCompressedTexImage2DParams& tex_params, |
+ const AsyncMemoryParams& mem_params, |
+ const base::Closure& bind_callback) override; |
+ void AsyncCompressedTexSubImage2D( |
+ const AsyncCompressedTexSubImage2DParams& tex_params, |
+ const AsyncMemoryParams& mem_params) override; |
bool TransferIsInProgress() override; |
void WaitForTransferCompletion() override; |
@@ -53,11 +79,21 @@ class AsyncPixelTransferDelegateIdle |
const base::Closure& bind_callback); |
void PerformAsyncTexSubImage2D(AsyncTexSubImage2DParams tex_params, |
AsyncMemoryParams mem_params); |
+ void PerformAsyncCompressedTexImage2D( |
+ AsyncCompressedTexImage2DParams tex_params, |
+ AsyncMemoryParams mem_params, |
+ const base::Closure& bind_callback); |
+ void PerformAsyncCompressedTexSubImage2D( |
+ AsyncCompressedTexSubImage2DParams tex_params, |
+ AsyncMemoryParams mem_params); |
uint64 id_; |
GLuint texture_id_; |
bool transfer_in_progress_; |
- AsyncTexImage2DParams define_params_; |
+ union { |
+ AsyncTexImage2DParams define_params_; |
+ AsyncCompressedTexImage2DParams compressed_define_params_; |
+ }; |
// Safe to hold a raw pointer because SharedState is owned by the Manager |
// which owns the Delegate. |
@@ -70,12 +106,23 @@ AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle( |
AsyncPixelTransferManagerIdle::SharedState* shared_state, |
GLuint texture_id, |
const AsyncTexImage2DParams& define_params) |
- : id_(g_next_pixel_transfer_state_id++), |
+ : id_(NextPixelTransferStateId()), |
texture_id_(texture_id), |
transfer_in_progress_(false), |
define_params_(define_params), |
shared_state_(shared_state) {} |
+AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle( |
+ AsyncPixelTransferManagerIdle::SharedState* shared_state, |
+ GLuint texture_id, |
+ const AsyncCompressedTexImage2DParams& define_params) |
+ : id_(NextPixelTransferStateId()), |
+ texture_id_(texture_id), |
+ transfer_in_progress_(false), |
+ compressed_define_params_(define_params), |
+ shared_state_(shared_state) { |
+} |
+ |
AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {} |
void AsyncPixelTransferDelegateIdle::AsyncTexImage2D( |
@@ -114,6 +161,37 @@ void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D( |
transfer_in_progress_ = true; |
} |
+void AsyncPixelTransferDelegateIdle::AsyncCompressedTexImage2D( |
+ const AsyncCompressedTexImage2DParams& tex_params, |
+ const AsyncMemoryParams& mem_params, |
+ const base::Closure& bind_callback) { |
+ TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage"); |
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target); |
+ |
+ shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task( |
+ id_, this, |
+ base::Bind( |
+ &AsyncPixelTransferDelegateIdle::PerformAsyncCompressedTexImage2D, |
+ AsWeakPtr(), tex_params, mem_params, bind_callback))); |
+ |
+ transfer_in_progress_ = true; |
+} |
+ |
+void AsyncPixelTransferDelegateIdle::AsyncCompressedTexSubImage2D( |
+ const AsyncCompressedTexSubImage2DParams& tex_params, |
+ const AsyncMemoryParams& mem_params) { |
+ TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage"); |
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target); |
+ |
+ shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task( |
+ id_, this, |
+ base::Bind( |
+ &AsyncPixelTransferDelegateIdle::PerformAsyncCompressedTexSubImage2D, |
+ AsWeakPtr(), tex_params, mem_params))); |
+ |
+ transfer_in_progress_ = true; |
+} |
+ |
bool AsyncPixelTransferDelegateIdle::TransferIsInProgress() { |
return transfer_in_progress_; |
} |
@@ -223,6 +301,74 @@ void AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D( |
base::TimeTicks::HighResNow() - begin_time; |
} |
+void AsyncPixelTransferDelegateIdle::PerformAsyncCompressedTexImage2D( |
+ AsyncCompressedTexImage2DParams tex_params, |
+ AsyncMemoryParams mem_params, |
+ const base::Closure& bind_callback) { |
+ TRACE_EVENT2("gpu", "PerformAsyncCompressedTexImage2D", "width", |
+ tex_params.width, "height", tex_params.height); |
+ |
+ void* data = mem_params.GetDataAddress(); |
+ |
+ base::TimeTicks begin_time(base::TimeTicks::HighResNow()); |
+ gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id_); |
+ |
+ { |
+ TRACE_EVENT0("gpu", "glCompressedTexImage2D"); |
+ glCompressedTexImage2D(tex_params.target, tex_params.level, |
+ tex_params.internal_format, tex_params.width, |
+ tex_params.height, tex_params.border, |
+ tex_params.image_size, data); |
+ } |
+ |
+ TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage"); |
+ transfer_in_progress_ = false; |
+ shared_state_->texture_upload_count++; |
+ shared_state_->total_texture_upload_time += |
+ base::TimeTicks::HighResNow() - begin_time; |
+ |
+ // The texture is already fully bound so just call it now. |
+ bind_callback.Run(); |
+} |
+ |
+void AsyncPixelTransferDelegateIdle::PerformAsyncCompressedTexSubImage2D( |
+ AsyncCompressedTexSubImage2DParams tex_params, |
+ AsyncMemoryParams mem_params) { |
+ TRACE_EVENT2("gpu", "PerformAsyncCompressedTexSubImage2D", "width", |
+ tex_params.width, "height", tex_params.height); |
+ |
+ void* data = mem_params.GetDataAddress(); |
+ |
+ base::TimeTicks begin_time(base::TimeTicks::HighResNow()); |
+ gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id_); |
+ |
+ // If it's a full texture update, use glCompressedTexImage2D as it's faster. |
+ if (tex_params.xoffset == 0 && tex_params.yoffset == 0 && |
+ tex_params.target == compressed_define_params_.target && |
+ tex_params.level == compressed_define_params_.level && |
+ tex_params.width == compressed_define_params_.width && |
+ tex_params.height == compressed_define_params_.height) { |
+ TRACE_EVENT0("gpu", "glCompressedTexImage2D"); |
+ glCompressedTexImage2D( |
+ compressed_define_params_.target, compressed_define_params_.level, |
+ compressed_define_params_.internal_format, |
+ compressed_define_params_.width, compressed_define_params_.height, |
+ compressed_define_params_.border, tex_params.image_size, data); |
+ } else { |
+ TRACE_EVENT0("gpu", "glCompressedTexSubImage2D"); |
+ glCompressedTexSubImage2D(tex_params.target, tex_params.level, |
+ tex_params.xoffset, tex_params.yoffset, |
+ tex_params.width, tex_params.height, |
+ tex_params.format, tex_params.image_size, data); |
+ } |
+ |
+ TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage"); |
+ transfer_in_progress_ = false; |
+ shared_state_->texture_upload_count++; |
+ shared_state_->total_texture_upload_time += |
+ base::TimeTicks::HighResNow() - begin_time; |
+} |
+ |
AsyncPixelTransferManagerIdle::Task::Task( |
uint64 transfer_id, |
AsyncPixelTransferDelegate* delegate, |
@@ -242,7 +388,7 @@ AsyncPixelTransferManagerIdle::SharedState::~SharedState() {} |
void AsyncPixelTransferManagerIdle::SharedState::ProcessNotificationTasks() { |
while (!tasks.empty()) { |
// Stop when we reach a pixel transfer task. |
- if (tasks.front().transfer_id) |
+ if (tasks.front().transfer_id > kSuspendTask) |
return; |
tasks.front().task.Run(); |
@@ -269,7 +415,7 @@ void AsyncPixelTransferManagerIdle::AsyncNotifyCompletion( |
} |
shared_state_.tasks.push_back( |
- Task(0, // 0 transfer_id for notification tasks. |
+ Task(kNotificationTask, |
NULL, |
base::Bind( |
&PerformNotifyCompletion, |
@@ -289,8 +435,16 @@ void AsyncPixelTransferManagerIdle::ProcessMorePendingTransfers() { |
if (shared_state_.tasks.empty()) |
return; |
- // First task should always be a pixel transfer task. |
- DCHECK(shared_state_.tasks.front().transfer_id); |
+ // Suspend uploads until waitables have been signalled. |
+ while (!suspend_waitables_.empty()) { |
+ if (!suspend_waitables_.front()->IsSignaled()) |
+ return; |
+ else |
+ suspend_waitables_.erase(suspend_waitables_.begin()); |
+ } |
+ |
+ // First task should always be a pixel transfer task or a suspend task. |
+ DCHECK_NE(shared_state_.tasks.front().transfer_id, kNotificationTask); |
shared_state_.tasks.front().task.Run(); |
shared_state_.tasks.pop_front(); |
@@ -310,6 +464,32 @@ void AsyncPixelTransferManagerIdle::WaitAllAsyncTexImage2D() { |
task.delegate->WaitForTransferCompletion(); |
} |
+void AsyncPixelTransferManagerIdle::DoSuspendUploads( |
+ scoped_ptr<base::WaitableEvent> waitable) { |
+ suspend_waitables_.push_back(waitable.release()); |
+} |
+ |
+void AsyncPixelTransferManagerIdle::SuspendUploads( |
+ base::WaitableEvent* waitable) { |
+ shared_state_.tasks.push_back( |
+ Task(kSuspendTask, |
+ NULL, |
+ base::Bind(&AsyncPixelTransferManagerIdle::DoSuspendUploads, |
+ base::Unretained(this), |
+ base::Passed( |
+ scoped_ptr<base::WaitableEvent>(waitable))))); |
+} |
+ |
+void AsyncPixelTransferManagerIdle::SignalWhenUploadsCompleted( |
+ base::WaitableEvent* waitable) { |
+ shared_state_.tasks.push_back( |
+ Task(kNotificationTask, |
+ NULL, |
+ base::Bind(&base::WaitableEvent::Signal, |
+ // WaitableEvent owned by waiter. |
+ base::Unretained(waitable)))); |
+} |
+ |
AsyncPixelTransferDelegate* |
AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl( |
gles2::TextureRef* ref, |
@@ -319,4 +499,12 @@ AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl( |
define_params); |
} |
+AsyncPixelTransferDelegate* |
+AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl( |
+ gles2::TextureRef* ref, |
+ const AsyncCompressedTexImage2DParams& define_params) { |
+ return new AsyncPixelTransferDelegateIdle(&shared_state_, ref->service_id(), |
+ define_params); |
+} |
+ |
} // namespace gpu |