diff options
author | reveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-16 22:37:32 +0000 |
---|---|---|
committer | reveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-16 22:37:32 +0000 |
commit | fe8d73c066f9fd5506509fbc95d53f33872e13ab (patch) | |
tree | 516643eab1296a4906b733f58db42ca7033b27ac /gpu/command_buffer/service/query_manager.cc | |
parent | aee50e84293e34ee609fad03cc21ed29cce9c27e (diff) | |
download | chromium_src-fe8d73c066f9fd5506509fbc95d53f33872e13ab.zip chromium_src-fe8d73c066f9fd5506509fbc95d53f33872e13ab.tar.gz chromium_src-fe8d73c066f9fd5506509fbc95d53f33872e13ab.tar.bz2 |
Re-land: 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
NOTRY=True
Review URL: https://chromiumcodereview.appspot.com/12213073
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@183010 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu/command_buffer/service/query_manager.cc')
-rw-r--r-- | gpu/command_buffer/service/query_manager.cc | 104 |
1 files changed, 83 insertions, 21 deletions
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; } |