diff options
author | reveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-12 06:34:18 +0000 |
---|---|---|
committer | reveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-12 06:34:18 +0000 |
commit | 95272e9f7bfb6ae6cde046117acc137eb84dbba2 (patch) | |
tree | 5c35aa8e022bc9229a067ecf9545dc05b87efd00 /gpu | |
parent | afc42102b92753ec892f7ca1fd26f02382add425 (diff) | |
download | chromium_src-95272e9f7bfb6ae6cde046117acc137eb84dbba2.zip chromium_src-95272e9f7bfb6ae6cde046117acc137eb84dbba2.tar.gz chromium_src-95272e9f7bfb6ae6cde046117acc137eb84dbba2.tar.bz2 |
cc: Mark async texture uploads as completed from the upload thread.
This reduces the latency between when an upload completes and when the
client is notified.
BUG=173802
Review URL: https://chromiumcodereview.appspot.com/12213073
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@181883 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h | 5 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 5 | ||||
-rw-r--r-- | gpu/command_buffer/service/query_manager.cc | 104 | ||||
-rw-r--r-- | gpu/command_buffer/service/query_manager.h | 32 |
4 files changed, 119 insertions, 27 deletions
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h index 4f44f7a..b716e70 100644 --- a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h +++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h @@ -32,8 +32,9 @@ class MockAsyncPixelTransferDelegate : public gfx::AsyncPixelTransferDelegate { // Implement AsyncPixelTransferDelegate. MOCK_METHOD1(CreateRawPixelTransferState, gfx::AsyncPixelTransferState*(GLuint service_id)); - MOCK_METHOD1(AsyncNotifyCompletion, - void(const base::Closure& task)); + MOCK_METHOD2(AsyncNotifyCompletion, + void(const AsyncMemoryParams& mem_params, + const CompletionCallback& callback)); MOCK_METHOD3(AsyncTexImage2D, void(gfx::AsyncPixelTransferState*, const AsyncTexImage2DParams& tex_params, diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 3b441a2..0ac835b 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -2719,6 +2719,9 @@ bool GLES2DecoderImpl::MakeCurrent() { return false; } + if (query_manager_.get()) + query_manager_->ProcessPendingTransferQueries(); + // TODO(epenner): Is there a better place to do this? Transfers // can complete any time we yield the main thread. So we *must* // process transfers after any such yield, before resuming. @@ -9116,6 +9119,8 @@ error::Error GLES2DecoderImpl::HandleEndQueryEXT( return error::kOutOfBounds; } + query_manager_->ProcessPendingTransferQueries(); + state_.current_query = NULL; return error::kNoError; } diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc index 51055e2..cc4de7a 100644 --- a/gpu/command_buffer/service/query_manager.cc +++ b/gpu/command_buffer/service/query_manager.cc @@ -3,13 +3,15 @@ // found in the LICENSE file. #include "gpu/command_buffer/service/query_manager.h" + #include "base/atomicops.h" #include "base/bind.h" #include "base/logging.h" +#include "base/shared_memory.h" #include "base/time.h" #include "gpu/command_buffer/common/gles2_cmd_format.h" -#include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/feature_info.h" +#include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "ui/gl/async_pixel_transfer_delegate.h" namespace gpu { @@ -176,10 +178,20 @@ class AsyncPixelTransfersCompletedQuery virtual bool Process() OVERRIDE; virtual void Destroy(bool have_context) OVERRIDE; - void MarkAsCompletedCallback() { MarkAsCompleted(1); } - protected: virtual ~AsyncPixelTransfersCompletedQuery(); + + static void MarkAsCompletedThreadSafe( + uint32 submit_count, const gfx::AsyncMemoryParams& mem_params) { + DCHECK(mem_params.shared_memory); + DCHECK(mem_params.shared_memory->memory()); + void *data = static_cast<int8*>(mem_params.shared_memory->memory()) + + mem_params.shm_data_offset; + QuerySync* sync = static_cast<QuerySync*>(data); + + // No need for a MemoryBarrier here as sync->result is not written. + sync->process_count = submit_count; + } }; AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery( @@ -192,28 +204,41 @@ bool AsyncPixelTransfersCompletedQuery::Begin() { } bool AsyncPixelTransfersCompletedQuery::End(uint32 submit_count) { - MarkAsPending(submit_count); - - // This will call MarkAsCompleted(1) as a reply to a task on - // the async upload thread, such that it occurs after all previous - // async transfers have completed. + gfx::AsyncMemoryParams mem_params; + // Get the real shared memory since it might need to be duped to prevent + // use-after-free of the memory. + Buffer buffer = manager()->decoder()->GetSharedMemoryBuffer(shm_id()); + if (!buffer.shared_memory) + return false; + mem_params.shared_memory = buffer.shared_memory; + mem_params.shm_size = buffer.size; + mem_params.shm_data_offset = shm_offset(); + mem_params.shm_data_size = sizeof(QuerySync); + + // Ask AsyncPixelTransferDelegate to run completion callback after all + // previous async transfers are done. No guarantee that callback is run + // on the current thread. manager()->decoder()->GetAsyncPixelTransferDelegate()->AsyncNotifyCompletion( - base::Bind( - &AsyncPixelTransfersCompletedQuery::MarkAsCompletedCallback, - AsWeakPtr())); - - // TODO(epenner): The async task occurs outside the normal - // flow, via a callback on this thread. Is there anything - // missing or wrong with that? + mem_params, + base::Bind(AsyncPixelTransfersCompletedQuery::MarkAsCompletedThreadSafe, + submit_count)); - // TODO(epenner): Could we possibly trigger the completion on - // the upload thread by writing to the query shared memory - // directly? - return true; + return AddToPendingTransferQueue(submit_count); } bool AsyncPixelTransfersCompletedQuery::Process() { - NOTREACHED(); + QuerySync* sync = manager()->decoder()->GetSharedMemoryAs<QuerySync*>( + shm_id(), shm_offset(), sizeof(*sync)); + if (!sync) + return false; + + // Check if completion callback has been run. sync->process_count atomicity + // is guaranteed as this is already used to notify client of a completed + // query. + if (sync->process_count != submit_count()) + return true; + + UnmarkAsPending(); return true; } @@ -435,7 +460,7 @@ bool QueryManager::ProcessPendingQueries() { return false; } if (query->pending()) { - return true; + break; } pending_queries_.pop_front(); } @@ -447,6 +472,25 @@ bool QueryManager::HavePendingQueries() { return !pending_queries_.empty(); } +bool QueryManager::ProcessPendingTransferQueries() { + while (!pending_transfer_queries_.empty()) { + Query* query = pending_transfer_queries_.front().get(); + if (!query->Process()) { + return false; + } + if (query->pending()) { + break; + } + pending_transfer_queries_.pop_front(); + } + + return true; +} + +bool QueryManager::HavePendingTransferQueries() { + return !pending_transfer_queries_.empty(); +} + bool QueryManager::AddPendingQuery(Query* query, uint32 submit_count) { DCHECK(query); DCHECK(!query->IsDeleted()); @@ -458,6 +502,17 @@ bool QueryManager::AddPendingQuery(Query* query, uint32 submit_count) { return true; } +bool QueryManager::AddPendingTransferQuery(Query* query, uint32 submit_count) { + DCHECK(query); + DCHECK(!query->IsDeleted()); + if (!RemovePendingQuery(query)) { + return false; + } + query->MarkAsPending(submit_count); + pending_transfer_queries_.push_back(query); + return true; +} + bool QueryManager::RemovePendingQuery(Query* query) { DCHECK(query); if (query->pending()) { @@ -471,6 +526,13 @@ bool QueryManager::RemovePendingQuery(Query* query) { break; } } + for (QueryQueue::iterator it = pending_transfer_queries_.begin(); + it != pending_transfer_queries_.end(); ++it) { + if (it->get() == query) { + pending_transfer_queries_.erase(it); + break; + } + } if (!query->MarkAsCompleted(0)) { return false; } diff --git a/gpu/command_buffer/service/query_manager.h b/gpu/command_buffer/service/query_manager.h index 322c03d..bf083aa 100644 --- a/gpu/command_buffer/service/query_manager.h +++ b/gpu/command_buffer/service/query_manager.h @@ -89,11 +89,21 @@ class GPU_EXPORT QueryManager { submit_count_ = submit_count; } + void UnmarkAsPending() { + DCHECK(pending_); + pending_ = false; + } + // Returns false if shared memory for sync is invalid. bool AddToPendingQueue(uint32 submit_count) { return manager_->AddPendingQuery(this, submit_count); } + // Returns false if shared memory for sync is invalid. + bool AddToPendingTransferQueue(uint32 submit_count) { + return manager_->AddPendingTransferQuery(this, submit_count); + } + void BeginQueryHelper(GLenum target, GLuint id) { manager_->BeginQueryHelper(target, id); } @@ -102,15 +112,15 @@ class GPU_EXPORT QueryManager { manager_->EndQueryHelper(target); } + uint32 submit_count() const { + return submit_count_; + } + private: friend class QueryManager; friend class QueryManagerTest; friend class base::RefCounted<Query>; - uint32 submit_count() const { - return submit_count_; - } - // The manager that owns this Query. QueryManager* manager_; @@ -162,6 +172,13 @@ class GPU_EXPORT QueryManager { // True if there are pending queries. bool HavePendingQueries(); + // Processes pending transfer queries. Returns false if any queries are + // pointing to invalid shared memory. + bool ProcessPendingTransferQueries(); + + // True if there are pending transfer queries. + bool HavePendingTransferQueries(); + GLES2Decoder* decoder() const { return decoder_; } @@ -179,6 +196,10 @@ class GPU_EXPORT QueryManager { // Returns false if any query is pointing to invalid shared memory. bool AddPendingQuery(Query* query, uint32 submit_count); + // Adds to queue of transfer queries waiting for completion. + // Returns false if any query is pointing to invalid shared memory. + bool AddPendingTransferQuery(Query* query, uint32 submit_count); + // Removes a query from the queue of pending queries. // Returns false if any query is pointing to invalid shared memory. bool RemovePendingQuery(Query* query); @@ -205,6 +226,9 @@ class GPU_EXPORT QueryManager { typedef std::deque<Query::Ref> QueryQueue; QueryQueue pending_queries_; + // Async pixel transfer queries waiting for completion. + QueryQueue pending_transfer_queries_; + DISALLOW_COPY_AND_ASSIGN(QueryManager); }; |