summaryrefslogtreecommitdiffstats
path: root/gpu/command_buffer/service/query_manager.cc
diff options
context:
space:
mode:
authorreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-16 22:37:32 +0000
committerreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-16 22:37:32 +0000
commitfe8d73c066f9fd5506509fbc95d53f33872e13ab (patch)
tree516643eab1296a4906b733f58db42ca7033b27ac /gpu/command_buffer/service/query_manager.cc
parentaee50e84293e34ee609fad03cc21ed29cce9c27e (diff)
downloadchromium_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.cc104
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;
}