diff options
author | backer@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-26 17:39:48 +0000 |
---|---|---|
committer | backer@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-26 17:39:48 +0000 |
commit | 3c5fa3a461a83be263b34bf6f5cbe927ad3a6af3 (patch) | |
tree | 77042aa9ea59984a1278cb2bdb69bab0db1ce665 /gpu | |
parent | d4e51191a0dd6ce335beef503c5cbcce3a902205 (diff) | |
download | chromium_src-3c5fa3a461a83be263b34bf6f5cbe927ad3a6af3.zip chromium_src-3c5fa3a461a83be263b34bf6f5cbe927ad3a6af3.tar.gz chromium_src-3c5fa3a461a83be263b34bf6f5cbe927ad3a6af3.tar.bz2 |
GPU: Fast track waited uploads.
Rather than bump thread priority when waiting (which is not yet supported on
CrOS), execute the upload out-of-order on the higher priority main thread.
BUG=252143
Review URL: https://chromiumcodereview.appspot.com/17198006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@208718 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc | 242 |
1 files changed, 148 insertions, 94 deletions
diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc b/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc index 2e13e7f..5a19311 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc +++ b/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc @@ -16,6 +16,7 @@ #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" +#include "base/threading/thread_checker.h" #include "gpu/command_buffer/service/async_pixel_transfer_delegate.h" #include "gpu/command_buffer/service/safe_shared_memory_pool.h" #include "ui/gl/gl_bindings.h" @@ -138,6 +139,72 @@ SafeSharedMemoryPool* safe_shared_memory_pool() { return g_transfer_thread.Pointer()->safe_shared_memory_pool(); } +class PendingTask : public base::RefCountedThreadSafe<PendingTask> { + public: + explicit PendingTask(const base::Closure& task) + : task_(task), task_pending_(true, false) {} + + bool TryRun() { + // This is meant to be called on the main thread where the texture + // is already bound. + DCHECK(checker_.CalledOnValidThread()); + if (task_lock_.Try()) { + // Only run once. + if (!task_.is_null()) + task_.Run(); + task_.Reset(); + + task_lock_.Release(); + task_pending_.Signal(); + return true; + } + return false; + } + + void BindAndRun(GLuint texture_id) { + // This is meant to be called on the upload thread where we don't have to + // restore the previous texture binding. + DCHECK(!checker_.CalledOnValidThread()); + base::AutoLock locked(task_lock_); + if (!task_.is_null()) { + glBindTexture(GL_TEXTURE_2D, texture_id); + task_.Run(); + task_.Reset(); + glBindTexture(GL_TEXTURE_2D, 0); + // Flush for synchronization between threads. + glFlush(); + task_pending_.Signal(); + } + } + + void Cancel() { + base::AutoLock locked(task_lock_); + task_.Reset(); + task_pending_.Signal(); + } + + bool TaskIsInProgress() { + return !task_pending_.IsSignaled(); + } + + void WaitForTask() { + task_pending_.Wait(); + } + + private: + friend class base::RefCountedThreadSafe<PendingTask>; + + virtual ~PendingTask() {} + + base::ThreadChecker checker_; + + base::Lock task_lock_; + base::Closure task_; + base::WaitableEvent task_pending_; + + DISALLOW_COPY_AND_ASSIGN(PendingTask); +}; + // Class which holds async pixel transfers state. // The texture_id is accessed by either thread, but everything // else accessed only on the main thread. @@ -146,13 +213,10 @@ class TransferStateInternal public: TransferStateInternal(GLuint texture_id, const AsyncTexImage2DParams& define_params) - : texture_id_(texture_id), - transfer_completion_(true, true) { - define_params_ = define_params; - } + : texture_id_(texture_id), define_params_(define_params) {} bool TransferIsInProgress() { - return !transfer_completion_.IsSignaled(); + return pending_upload_task_ && pending_upload_task_->TaskIsInProgress(); } void BindTransfer() { @@ -165,25 +229,71 @@ class TransferStateInternal bind_callback_.Run(); } - void MarkAsTransferIsInProgress() { - transfer_completion_.Reset(); + void WaitForTransferCompletion() { + TRACE_EVENT0("gpu", "WaitForTransferCompletion"); + DCHECK(pending_upload_task_); + if (!pending_upload_task_->TryRun()) { + pending_upload_task_->WaitForTask(); + } + pending_upload_task_ = NULL; } - void MarkAsCompleted() { - TRACE_EVENT0("gpu", "MarkAsCompleted"); - glFlush(); - transfer_completion_.Signal(); + void CancelUpload() { + TRACE_EVENT0("gpu", "CancelUpload"); + if (pending_upload_task_) + pending_upload_task_->Cancel(); + pending_upload_task_ = NULL; } - void WaitForTransferCompletion() { - TRACE_EVENT0("gpu", "WaitForTransferCompletion"); - // TODO(backer): Deschedule the channel rather than blocking the main GPU - // thread (crbug.com/240265). - transfer_completion_.Wait(); + void ScheduleAsyncTexImage2D( + const AsyncTexImage2DParams tex_params, + const AsyncMemoryParams mem_params, + scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats, + const base::Closure& bind_callback) { + pending_upload_task_ = new PendingTask(base::Bind( + &TransferStateInternal::PerformAsyncTexImage2D, + this, + tex_params, + mem_params, + // Duplicate the shared memory so there is no way we can get + // a use-after-free of the raw pixels. + base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), + mem_params.shared_memory, + mem_params.shm_size)), + texture_upload_stats)); + transfer_message_loop_proxy()->PostTask( + FROM_HERE, + base::Bind( + &PendingTask::BindAndRun, pending_upload_task_, texture_id_)); + + // Save the late bind callback, so we can notify the client when it is + // bound. + bind_callback_ = bind_callback; } - void SetBindCallback(base::Closure bind_callback) { - bind_callback_ = bind_callback; + void ScheduleAsyncTexSubImage2D( + AsyncTexSubImage2DParams tex_params, + AsyncMemoryParams mem_params, + scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) { + pending_upload_task_ = new PendingTask(base::Bind( + &TransferStateInternal::PerformAsyncTexSubImage2D, + this, + tex_params, + mem_params, + base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), + mem_params.shared_memory, + mem_params.shm_size)), + texture_upload_stats)); + transfer_message_loop_proxy()->PostTask( + FROM_HERE, + base::Bind( + &PendingTask::BindAndRun, pending_upload_task_, texture_id_)); + } + + private: + friend class base::RefCountedThreadSafe<TransferStateInternal>; + + virtual ~TransferStateInternal() { } void PerformAsyncTexImage2D( @@ -191,10 +301,6 @@ class TransferStateInternal AsyncMemoryParams mem_params, ScopedSafeSharedMemory* safe_shared_memory, scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) { - base::AutoLock locked(upload_lock_); - if (cancel_upload_flag_.IsSet()) - return; - TRACE_EVENT2("gpu", "PerformAsyncTexImage", "width", @@ -212,7 +318,6 @@ class TransferStateInternal { TRACE_EVENT0("gpu", "glTexImage2D"); - glBindTexture(GL_TEXTURE_2D, texture_id_); glTexImage2D(GL_TEXTURE_2D, tex_params.level, tex_params.internal_format, @@ -222,11 +327,8 @@ class TransferStateInternal tex_params.format, tex_params.type, data); - glBindTexture(GL_TEXTURE_2D, 0); } - MarkAsCompleted(); - if (texture_upload_stats.get()) { texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() - begin_time); @@ -238,10 +340,6 @@ class TransferStateInternal AsyncMemoryParams mem_params, ScopedSafeSharedMemory* safe_shared_memory, scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) { - base::AutoLock locked(upload_lock_); - if (cancel_upload_flag_.IsSet()) - return; - TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D", "width", @@ -259,7 +357,6 @@ class TransferStateInternal { TRACE_EVENT0("gpu", "glTexSubImage2D"); - glBindTexture(GL_TEXTURE_2D, texture_id_); glTexSubImage2D(GL_TEXTURE_2D, tex_params.level, tex_params.xoffset, @@ -269,38 +366,21 @@ class TransferStateInternal tex_params.format, tex_params.type, data); - glBindTexture(GL_TEXTURE_2D, 0); } - MarkAsCompleted(); - if (texture_upload_stats.get()) { texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() - begin_time); } } - base::CancellationFlag* cancel_upload_flag() { return &cancel_upload_flag_; } - base::Lock* upload_lock() { return &upload_lock_; } - - private: - friend class base::RefCountedThreadSafe<TransferStateInternal>; - - virtual ~TransferStateInternal() { - } - - // Used to cancel pending uploads. - base::CancellationFlag cancel_upload_flag_; - base::Lock upload_lock_; + scoped_refptr<PendingTask> pending_upload_task_; GLuint texture_id_; // Definition params for texture that needs binding. AsyncTexImage2DParams define_params_; - // Indicates that an async transfer is in progress. - base::WaitableEvent transfer_completion_; - // Callback to invoke when AsyncTexImage2D is complete // and the client can safely use the texture. This occurs // during BindCompletedAsyncTransfers(). @@ -350,8 +430,7 @@ AsyncPixelTransferDelegateShareGroup::AsyncPixelTransferDelegateShareGroup( AsyncPixelTransferDelegateShareGroup::~AsyncPixelTransferDelegateShareGroup() { TRACE_EVENT0("gpu", " ~AsyncPixelTransferDelegateShareGroup"); - base::AutoLock locked(*state_->upload_lock()); - state_->cancel_upload_flag()->Set(); + state_->CancelUpload(); } bool AsyncPixelTransferDelegateShareGroup::TransferIsInProgress() { @@ -360,16 +439,21 @@ bool AsyncPixelTransferDelegateShareGroup::TransferIsInProgress() { void AsyncPixelTransferDelegateShareGroup::WaitForTransferCompletion() { if (state_->TransferIsInProgress()) { -#if defined(OS_ANDROID) || defined(OS_LINUX) - g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Display); -#endif - state_->WaitForTransferCompletion(); DCHECK(!state_->TransferIsInProgress()); + } -#if defined(OS_ANDROID) || defined(OS_LINUX) - g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Background); -#endif + // Fast track the BindTransfer, if applicable. + for (AsyncPixelTransferManagerShareGroup::SharedState::TransferQueue::iterator + iter = shared_state_->pending_allocations.begin(); + iter != shared_state_->pending_allocations.end(); + ++iter) { + if (iter->get() != this) + continue; + + shared_state_->pending_allocations.erase(iter); + BindTransfer(); + break; } } @@ -384,27 +468,11 @@ void AsyncPixelTransferDelegateShareGroup::AsyncTexImage2D( DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target); DCHECK_EQ(tex_params.level, 0); - // Mark the transfer in progress and save the late bind - // callback, so we can notify the client when it is bound. shared_state_->pending_allocations.push_back(AsWeakPtr()); - state_->SetBindCallback(bind_callback); - - // Mark the transfer in progress. - state_->MarkAsTransferIsInProgress(); - - // Duplicate the shared memory so there is no way we can get - // a use-after-free of the raw pixels. - transfer_message_loop_proxy()->PostTask( - FROM_HERE, - base::Bind( - &TransferStateInternal::PerformAsyncTexImage2D, - state_, - tex_params, - mem_params, - base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), - mem_params.shared_memory, - mem_params.shm_size)), - shared_state_->texture_upload_stats)); + state_->ScheduleAsyncTexImage2D(tex_params, + mem_params, + shared_state_->texture_upload_stats, + bind_callback); } void AsyncPixelTransferDelegateShareGroup::AsyncTexSubImage2D( @@ -420,22 +488,8 @@ void AsyncPixelTransferDelegateShareGroup::AsyncTexSubImage2D( DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target); DCHECK_EQ(tex_params.level, 0); - // Mark the transfer in progress. - state_->MarkAsTransferIsInProgress(); - - // Duplicate the shared memory so there are no way we can get - // a use-after-free of the raw pixels. - transfer_message_loop_proxy()->PostTask( - FROM_HERE, - base::Bind( - &TransferStateInternal::PerformAsyncTexSubImage2D, - state_, - tex_params, - mem_params, - base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), - mem_params.shared_memory, - mem_params.shm_size)), - shared_state_->texture_upload_stats)); + state_->ScheduleAsyncTexSubImage2D( + tex_params, mem_params, shared_state_->texture_upload_stats); } AsyncPixelTransferManagerShareGroup::SharedState::SharedState() |