Added grv@ and dvh@ as owners of developer private API.
[chromium-blink-merge.git] / gpu / command_buffer / client / query_tracker.cc
blob285560590b34a403ba5e2abb763d8c9d340ffc8d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gpu/command_buffer/client/query_tracker.h"
7 #include <GLES2/gl2.h>
8 #include <GLES2/gl2ext.h>
9 #include <GLES2/gl2extchromium.h>
11 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
12 #include "gpu/command_buffer/client/gles2_implementation.h"
13 #include "gpu/command_buffer/client/mapped_memory.h"
14 #include "gpu/command_buffer/common/time.h"
16 namespace gpu {
17 namespace gles2 {
19 QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
20 : mapped_memory_(manager) {
21 DCHECK(manager);
24 QuerySyncManager::~QuerySyncManager() {
25 while (!buckets_.empty()) {
26 mapped_memory_->Free(buckets_.front()->syncs);
27 delete buckets_.front();
28 buckets_.pop_front();
32 bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
33 DCHECK(info);
34 if (free_queries_.empty()) {
35 int32 shm_id;
36 unsigned int shm_offset;
37 void* mem = mapped_memory_->Alloc(
38 kSyncsPerBucket * sizeof(QuerySync), &shm_id, &shm_offset);
39 if (!mem) {
40 return false;
42 QuerySync* syncs = static_cast<QuerySync*>(mem);
43 Bucket* bucket = new Bucket(syncs);
44 buckets_.push_back(bucket);
45 for (size_t ii = 0; ii < kSyncsPerBucket; ++ii) {
46 free_queries_.push_back(QueryInfo(bucket, shm_id, shm_offset, syncs));
47 ++syncs;
48 shm_offset += sizeof(*syncs);
51 *info = free_queries_.front();
52 ++(info->bucket->used_query_count);
53 info->sync->Reset();
54 free_queries_.pop_front();
55 return true;
58 void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
59 DCHECK_GT(info.bucket->used_query_count, 0u);
60 --(info.bucket->used_query_count);
61 free_queries_.push_back(info);
64 void QuerySyncManager::Shrink() {
65 std::deque<QueryInfo> new_queue;
66 while (!free_queries_.empty()) {
67 if (free_queries_.front().bucket->used_query_count)
68 new_queue.push_back(free_queries_.front());
69 free_queries_.pop_front();
71 free_queries_.swap(new_queue);
73 std::deque<Bucket*> new_buckets;
74 while (!buckets_.empty()) {
75 Bucket* bucket = buckets_.front();
76 if (bucket->used_query_count) {
77 new_buckets.push_back(bucket);
78 } else {
79 mapped_memory_->Free(bucket->syncs);
80 delete bucket;
82 buckets_.pop_front();
84 buckets_.swap(new_buckets);
87 QueryTracker::Query::Query(GLuint id, GLenum target,
88 const QuerySyncManager::QueryInfo& info)
89 : id_(id),
90 target_(target),
91 info_(info),
92 state_(kUninitialized),
93 submit_count_(0),
94 token_(0),
95 flushed_(false),
96 client_begin_time_us_(0),
97 result_(0) {
101 void QueryTracker::Query::Begin(GLES2Implementation* gl) {
102 // init memory, inc count
103 MarkAsActive();
105 switch (target()) {
106 case GL_GET_ERROR_QUERY_CHROMIUM:
107 // To nothing on begin for error queries.
108 break;
109 case GL_LATENCY_QUERY_CHROMIUM:
110 client_begin_time_us_ = MicrosecondsSinceOriginOfTime();
111 // tell service about id, shared memory and count
112 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
113 break;
114 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
115 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
116 default:
117 // tell service about id, shared memory and count
118 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
119 break;
123 void QueryTracker::Query::End(GLES2Implementation* gl) {
124 switch (target()) {
125 case GL_GET_ERROR_QUERY_CHROMIUM: {
126 GLenum error = gl->GetClientSideGLError();
127 if (error == GL_NO_ERROR) {
128 // There was no error so start the query on the serivce.
129 // it will end immediately.
130 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
131 } else {
132 // There's an error on the client, no need to bother the service. just
133 // set the query as completed and return the error.
134 if (error != GL_NO_ERROR) {
135 state_ = kComplete;
136 result_ = error;
137 return;
142 gl->helper()->EndQueryEXT(target(), submit_count());
143 MarkAsPending(gl->helper()->InsertToken());
146 bool QueryTracker::Query::CheckResultsAvailable(
147 CommandBufferHelper* helper) {
148 if (Pending()) {
149 if (info_.sync->process_count == submit_count_ ||
150 helper->IsContextLost()) {
151 // Need a MemoryBarrier here so that sync->result read after
152 // sync->process_count.
153 base::subtle::MemoryBarrier();
154 switch (target()) {
155 case GL_COMMANDS_ISSUED_CHROMIUM:
156 result_ = std::min(info_.sync->result,
157 static_cast<uint64>(0xFFFFFFFFL));
158 break;
159 case GL_LATENCY_QUERY_CHROMIUM:
160 DCHECK(info_.sync->result >= client_begin_time_us_);
161 result_ = std::min(info_.sync->result - client_begin_time_us_,
162 static_cast<uint64>(0xFFFFFFFFL));
163 break;
164 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
165 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
166 default:
167 result_ = info_.sync->result;
168 break;
170 state_ = kComplete;
171 } else {
172 if (!flushed_) {
173 // TODO(gman): We could reduce the number of flushes by having a
174 // flush count, recording that count at the time we insert the
175 // EndQuery command and then only flushing here if we've have not
176 // passed that count yet.
177 flushed_ = true;
178 helper->Flush();
179 } else {
180 // Insert no-ops so that eventually the GPU process will see more work.
181 helper->Noop(1);
185 return state_ == kComplete;
188 uint32 QueryTracker::Query::GetResult() const {
189 DCHECK(state_ == kComplete || state_ == kUninitialized);
190 return result_;
193 QueryTracker::QueryTracker(MappedMemoryManager* manager)
194 : query_sync_manager_(manager) {
197 QueryTracker::~QueryTracker() {
198 while (!queries_.empty()) {
199 delete queries_.begin()->second;
200 queries_.erase(queries_.begin());
202 while (!removed_queries_.empty()) {
203 delete removed_queries_.front();
204 removed_queries_.pop_front();
208 QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
209 DCHECK_NE(0u, id);
210 FreeCompletedQueries();
211 QuerySyncManager::QueryInfo info;
212 if (!query_sync_manager_.Alloc(&info)) {
213 return NULL;
215 Query* query = new Query(id, target, info);
216 std::pair<QueryMap::iterator, bool> result =
217 queries_.insert(std::make_pair(id, query));
218 DCHECK(result.second);
219 return query;
222 QueryTracker::Query* QueryTracker::GetQuery(
223 GLuint client_id) {
224 QueryMap::iterator it = queries_.find(client_id);
225 return it != queries_.end() ? it->second : NULL;
228 void QueryTracker::RemoveQuery(GLuint client_id) {
229 QueryMap::iterator it = queries_.find(client_id);
230 if (it != queries_.end()) {
231 Query* query = it->second;
232 // When you delete a query you can't mark its memory as unused until it's
233 // completed.
234 // Note: If you don't do this you won't mess up the service but you will
235 // mess up yourself.
236 removed_queries_.push_back(query);
237 queries_.erase(it);
238 FreeCompletedQueries();
242 void QueryTracker::Shrink() {
243 FreeCompletedQueries();
244 query_sync_manager_.Shrink();
247 void QueryTracker::FreeCompletedQueries() {
248 QueryList::iterator it = removed_queries_.begin();
249 while (it != removed_queries_.end()) {
250 Query* query = *it;
251 if (query->Pending() &&
252 query->info_.sync->process_count != query->submit_count()) {
253 ++it;
254 continue;
257 query_sync_manager_.Free(query->info_);
258 it = removed_queries_.erase(it);
259 delete query;
263 } // namespace gles2
264 } // namespace gpu