cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / gpu / command_buffer / client / query_tracker.cc
blob307b615c6fdfb22f260fb13bc2ed1fba7b480182
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/atomicops.h"
12 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
13 #include "gpu/command_buffer/client/gles2_implementation.h"
14 #include "gpu/command_buffer/client/mapped_memory.h"
15 #include "gpu/command_buffer/common/time.h"
17 namespace gpu {
18 namespace gles2 {
20 QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
21 : mapped_memory_(manager) {
22 GPU_DCHECK(manager);
25 QuerySyncManager::~QuerySyncManager() {
26 while (!buckets_.empty()) {
27 mapped_memory_->Free(buckets_.front()->syncs);
28 delete buckets_.front();
29 buckets_.pop_front();
33 bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
34 GPU_DCHECK(info);
35 if (free_queries_.empty()) {
36 int32 shm_id;
37 unsigned int shm_offset;
38 void* mem = mapped_memory_->Alloc(
39 kSyncsPerBucket * sizeof(QuerySync), &shm_id, &shm_offset);
40 if (!mem) {
41 return false;
43 QuerySync* syncs = static_cast<QuerySync*>(mem);
44 Bucket* bucket = new Bucket(syncs);
45 buckets_.push_back(bucket);
46 for (size_t ii = 0; ii < kSyncsPerBucket; ++ii) {
47 free_queries_.push_back(QueryInfo(bucket, shm_id, shm_offset, syncs));
48 ++syncs;
49 shm_offset += sizeof(*syncs);
52 *info = free_queries_.front();
53 ++(info->bucket->used_query_count);
54 info->sync->Reset();
55 free_queries_.pop_front();
56 return true;
59 void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
60 DCHECK_GT(info.bucket->used_query_count, 0u);
61 --(info.bucket->used_query_count);
62 free_queries_.push_back(info);
65 void QuerySyncManager::Shrink() {
66 std::deque<QueryInfo> new_queue;
67 while (!free_queries_.empty()) {
68 if (free_queries_.front().bucket->used_query_count)
69 new_queue.push_back(free_queries_.front());
70 free_queries_.pop_front();
72 free_queries_.swap(new_queue);
74 std::deque<Bucket*> new_buckets;
75 while (!buckets_.empty()) {
76 Bucket* bucket = buckets_.front();
77 if (bucket->used_query_count) {
78 new_buckets.push_back(bucket);
79 } else {
80 mapped_memory_->Free(bucket->syncs);
81 delete bucket;
83 buckets_.pop_front();
85 buckets_.swap(new_buckets);
88 QueryTracker::Query::Query(GLuint id, GLenum target,
89 const QuerySyncManager::QueryInfo& info)
90 : id_(id),
91 target_(target),
92 info_(info),
93 state_(kUninitialized),
94 submit_count_(0),
95 token_(0),
96 flushed_(false),
97 client_begin_time_us_(0),
98 result_(0) {
102 void QueryTracker::Query::Begin(GLES2Implementation* gl) {
103 // init memory, inc count
104 MarkAsActive();
106 switch (target()) {
107 case GL_GET_ERROR_QUERY_CHROMIUM:
108 // To nothing on begin for error queries.
109 break;
110 case GL_LATENCY_QUERY_CHROMIUM:
111 client_begin_time_us_ = MicrosecondsSinceOriginOfTime();
112 // tell service about id, shared memory and count
113 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
114 break;
115 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
116 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
117 default:
118 // tell service about id, shared memory and count
119 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
120 break;
124 void QueryTracker::Query::End(GLES2Implementation* gl) {
125 switch (target()) {
126 case GL_GET_ERROR_QUERY_CHROMIUM: {
127 GLenum error = gl->GetClientSideGLError();
128 if (error == GL_NO_ERROR) {
129 // There was no error so start the query on the serivce.
130 // it will end immediately.
131 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
132 } else {
133 // There's an error on the client, no need to bother the service. just
134 // set the query as completed and return the error.
135 if (error != GL_NO_ERROR) {
136 state_ = kComplete;
137 result_ = error;
138 return;
143 gl->helper()->EndQueryEXT(target(), submit_count());
144 MarkAsPending(gl->helper()->InsertToken());
147 bool QueryTracker::Query::CheckResultsAvailable(
148 CommandBufferHelper* helper) {
149 if (Pending()) {
150 if (info_.sync->process_count == submit_count_ ||
151 helper->IsContextLost()) {
152 // Need a MemoryBarrier here so that sync->result read after
153 // sync->process_count.
154 gpu::MemoryBarrier();
155 switch (target()) {
156 case GL_COMMANDS_ISSUED_CHROMIUM:
157 result_ = std::min(info_.sync->result,
158 static_cast<uint64>(0xFFFFFFFFL));
159 break;
160 case GL_LATENCY_QUERY_CHROMIUM:
161 GPU_DCHECK(info_.sync->result >= client_begin_time_us_);
162 result_ = std::min(info_.sync->result - client_begin_time_us_,
163 static_cast<uint64>(0xFFFFFFFFL));
164 break;
165 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
166 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
167 default:
168 result_ = info_.sync->result;
169 break;
171 state_ = kComplete;
172 } else {
173 if (!flushed_) {
174 // TODO(gman): We could reduce the number of flushes by having a
175 // flush count, recording that count at the time we insert the
176 // EndQuery command and then only flushing here if we've have not
177 // passed that count yet.
178 flushed_ = true;
179 helper->Flush();
180 } else {
181 // Insert no-ops so that eventually the GPU process will see more work.
182 helper->Noop(1);
186 return state_ == kComplete;
189 uint32 QueryTracker::Query::GetResult() const {
190 GPU_DCHECK(state_ == kComplete || state_ == kUninitialized);
191 return result_;
194 QueryTracker::QueryTracker(MappedMemoryManager* manager)
195 : query_sync_manager_(manager) {
198 QueryTracker::~QueryTracker() {
199 while (!queries_.empty()) {
200 delete queries_.begin()->second;
201 queries_.erase(queries_.begin());
203 while (!removed_queries_.empty()) {
204 delete removed_queries_.front();
205 removed_queries_.pop_front();
209 QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
210 GPU_DCHECK_NE(0u, id);
211 FreeCompletedQueries();
212 QuerySyncManager::QueryInfo info;
213 if (!query_sync_manager_.Alloc(&info)) {
214 return NULL;
216 Query* query = new Query(id, target, info);
217 std::pair<QueryMap::iterator, bool> result =
218 queries_.insert(std::make_pair(id, query));
219 GPU_DCHECK(result.second);
220 return query;
223 QueryTracker::Query* QueryTracker::GetQuery(
224 GLuint client_id) {
225 QueryMap::iterator it = queries_.find(client_id);
226 return it != queries_.end() ? it->second : NULL;
229 void QueryTracker::RemoveQuery(GLuint client_id) {
230 QueryMap::iterator it = queries_.find(client_id);
231 if (it != queries_.end()) {
232 Query* query = it->second;
233 // When you delete a query you can't mark its memory as unused until it's
234 // completed.
235 // Note: If you don't do this you won't mess up the service but you will
236 // mess up yourself.
237 removed_queries_.push_back(query);
238 queries_.erase(it);
239 FreeCompletedQueries();
243 void QueryTracker::Shrink() {
244 FreeCompletedQueries();
245 query_sync_manager_.Shrink();
248 void QueryTracker::FreeCompletedQueries() {
249 QueryList::iterator it = removed_queries_.begin();
250 while (it != removed_queries_.end()) {
251 Query* query = *it;
252 if (query->Pending() &&
253 query->info_.sync->process_count != query->submit_count()) {
254 ++it;
255 continue;
258 query_sync_manager_.Free(query->info_);
259 it = removed_queries_.erase(it);
260 delete query;
264 } // namespace gles2
265 } // namespace gpu