Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / gpu / command_buffer / client / query_tracker.cc
bloba258f93643742d300a9eb06c1250066fd0b66151
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 <limits.h>
13 #include "base/atomicops.h"
14 #include "base/numerics/safe_conversions.h"
15 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
16 #include "gpu/command_buffer/client/gles2_implementation.h"
17 #include "gpu/command_buffer/client/mapped_memory.h"
18 #include "gpu/command_buffer/common/time.h"
20 namespace gpu {
21 namespace gles2 {
23 QuerySyncManager::Bucket::Bucket(QuerySync* sync_mem,
24 int32 shm_id,
25 unsigned int shm_offset)
26 : syncs(sync_mem),
27 shm_id(shm_id),
28 base_shm_offset(shm_offset) {
31 QuerySyncManager::Bucket::~Bucket() = default;
33 QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
34 : mapped_memory_(manager) {
35 DCHECK(manager);
38 QuerySyncManager::~QuerySyncManager() {
39 while (!buckets_.empty()) {
40 mapped_memory_->Free(buckets_.front()->syncs);
41 delete buckets_.front();
42 buckets_.pop_front();
46 bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
47 DCHECK(info);
48 Bucket* bucket = nullptr;
49 for (Bucket* bucket_candidate : buckets_) {
50 // In C++11 STL this could be replaced with
51 // if (!bucket_candidate->in_use_queries.all()) { ... }
52 if (bucket_candidate->in_use_queries.count() != kSyncsPerBucket) {
53 bucket = bucket_candidate;
54 break;
57 if (!bucket) {
58 int32 shm_id;
59 unsigned int shm_offset;
60 void* mem = mapped_memory_->Alloc(
61 kSyncsPerBucket * sizeof(QuerySync), &shm_id, &shm_offset);
62 if (!mem) {
63 return false;
65 QuerySync* syncs = static_cast<QuerySync*>(mem);
66 bucket = new Bucket(syncs, shm_id, shm_offset);
67 buckets_.push_back(bucket);
70 unsigned short index_in_bucket = 0;
71 for (size_t i = 0; i < kSyncsPerBucket; i++) {
72 if (!bucket->in_use_queries[i]) {
73 index_in_bucket = i;
74 break;
78 uint32 shm_offset =
79 bucket->base_shm_offset + index_in_bucket * sizeof(QuerySync);
80 QuerySync* sync = bucket->syncs + index_in_bucket;
81 *info = QueryInfo(bucket, bucket->shm_id, shm_offset, sync);
82 info->sync->Reset();
83 bucket->in_use_queries[index_in_bucket] = true;
84 return true;
87 void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
88 DCHECK_NE(info.bucket->in_use_queries.count(), 0u);
89 unsigned short index_in_bucket = info.sync - info.bucket->syncs;
90 DCHECK(info.bucket->in_use_queries[index_in_bucket]);
91 info.bucket->in_use_queries[index_in_bucket] = false;
94 void QuerySyncManager::Shrink() {
95 std::deque<Bucket*> new_buckets;
96 while (!buckets_.empty()) {
97 Bucket* bucket = buckets_.front();
98 if (bucket->in_use_queries.any()) {
99 new_buckets.push_back(bucket);
100 } else {
101 mapped_memory_->Free(bucket->syncs);
102 delete bucket;
104 buckets_.pop_front();
106 buckets_.swap(new_buckets);
109 QueryTracker::Query::Query(GLuint id, GLenum target,
110 const QuerySyncManager::QueryInfo& info)
111 : id_(id),
112 target_(target),
113 info_(info),
114 state_(kUninitialized),
115 submit_count_(0),
116 token_(0),
117 flush_count_(0),
118 client_begin_time_us_(0),
119 result_(0) {
123 void QueryTracker::Query::Begin(GLES2Implementation* gl) {
124 // init memory, inc count
125 MarkAsActive();
127 switch (target()) {
128 case GL_GET_ERROR_QUERY_CHROMIUM:
129 // To nothing on begin for error queries.
130 break;
131 case GL_LATENCY_QUERY_CHROMIUM:
132 client_begin_time_us_ = MicrosecondsSinceOriginOfTime();
133 // tell service about id, shared memory and count
134 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
135 break;
136 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
137 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
138 default:
139 // tell service about id, shared memory and count
140 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
141 break;
145 void QueryTracker::Query::End(GLES2Implementation* gl) {
146 switch (target()) {
147 case GL_GET_ERROR_QUERY_CHROMIUM: {
148 GLenum error = gl->GetClientSideGLError();
149 if (error == GL_NO_ERROR) {
150 // There was no error so start the query on the service.
151 // it will end immediately.
152 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
153 } else {
154 // There's an error on the client, no need to bother the service. Just
155 // set the query as completed and return the error.
156 if (error != GL_NO_ERROR) {
157 state_ = kComplete;
158 result_ = error;
159 return;
164 flush_count_ = gl->helper()->flush_generation();
165 gl->helper()->EndQueryEXT(target(), submit_count());
166 MarkAsPending(gl->helper()->InsertToken());
169 void QueryTracker::Query::QueryCounter(GLES2Implementation* gl) {
170 MarkAsActive();
171 flush_count_ = gl->helper()->flush_generation();
172 gl->helper()->QueryCounterEXT(target(), id(), shm_id(), shm_offset(),
173 submit_count());
174 MarkAsPending(gl->helper()->InsertToken());
177 bool QueryTracker::Query::CheckResultsAvailable(
178 CommandBufferHelper* helper) {
179 if (Pending()) {
180 if (base::subtle::Acquire_Load(&info_.sync->process_count) ==
181 submit_count_ ||
182 helper->IsContextLost()) {
183 switch (target()) {
184 case GL_COMMANDS_ISSUED_CHROMIUM:
185 result_ = info_.sync->result;
186 break;
187 case GL_LATENCY_QUERY_CHROMIUM:
188 // Disabled DCHECK because of http://crbug.com/419236.
189 //DCHECK(info_.sync->result >= client_begin_time_us_);
190 result_ = info_.sync->result - client_begin_time_us_;
191 break;
192 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
193 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
194 default:
195 result_ = info_.sync->result;
196 break;
198 state_ = kComplete;
199 } else {
200 if ((helper->flush_generation() - flush_count_ - 1) >= 0x80000000) {
201 helper->Flush();
202 } else {
203 // Insert no-ops so that eventually the GPU process will see more work.
204 helper->Noop(1);
208 return state_ == kComplete;
211 uint64 QueryTracker::Query::GetResult() const {
212 DCHECK(state_ == kComplete || state_ == kUninitialized);
213 return result_;
216 QueryTracker::QueryTracker(MappedMemoryManager* manager)
217 : query_sync_manager_(manager),
218 mapped_memory_(manager),
219 disjoint_count_sync_shm_id_(-1),
220 disjoint_count_sync_shm_offset_(0),
221 disjoint_count_sync_(nullptr),
222 local_disjoint_count_(0) {
225 QueryTracker::~QueryTracker() {
226 while (!queries_.empty()) {
227 delete queries_.begin()->second;
228 queries_.erase(queries_.begin());
230 while (!removed_queries_.empty()) {
231 delete removed_queries_.front();
232 removed_queries_.pop_front();
234 if (disjoint_count_sync_) {
235 mapped_memory_->Free(disjoint_count_sync_);
236 disjoint_count_sync_ = nullptr;
240 QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
241 DCHECK_NE(0u, id);
242 FreeCompletedQueries();
243 QuerySyncManager::QueryInfo info;
244 if (!query_sync_manager_.Alloc(&info)) {
245 return nullptr;
247 Query* query = new Query(id, target, info);
248 std::pair<QueryIdMap::iterator, bool> result =
249 queries_.insert(std::make_pair(id, query));
250 DCHECK(result.second);
251 return query;
254 QueryTracker::Query* QueryTracker::GetQuery(GLuint client_id) {
255 QueryIdMap::iterator it = queries_.find(client_id);
256 return it != queries_.end() ? it->second : nullptr;
259 QueryTracker::Query* QueryTracker::GetCurrentQuery(GLenum target) {
260 QueryTargetMap::iterator it = current_queries_.find(target);
261 return it != current_queries_.end() ? it->second : nullptr;
264 void QueryTracker::RemoveQuery(GLuint client_id) {
265 QueryIdMap::iterator it = queries_.find(client_id);
266 if (it != queries_.end()) {
267 Query* query = it->second;
269 // Erase from current targets map if it is the current target.
270 const GLenum target = query->target();
271 QueryTargetMap::iterator target_it = current_queries_.find(target);
272 if (target_it != current_queries_.end() && target_it->second == query) {
273 current_queries_.erase(target_it);
276 // When you delete a query you can't mark its memory as unused until it's
277 // completed.
278 // Note: If you don't do this you won't mess up the service but you will
279 // mess up yourself.
280 removed_queries_.push_back(query);
281 queries_.erase(it);
282 FreeCompletedQueries();
286 void QueryTracker::Shrink() {
287 FreeCompletedQueries();
288 query_sync_manager_.Shrink();
291 void QueryTracker::FreeCompletedQueries() {
292 QueryList::iterator it = removed_queries_.begin();
293 while (it != removed_queries_.end()) {
294 Query* query = *it;
295 if (query->Pending() &&
296 base::subtle::Acquire_Load(&query->info_.sync->process_count) !=
297 query->submit_count()) {
298 ++it;
299 continue;
302 query_sync_manager_.Free(query->info_);
303 it = removed_queries_.erase(it);
304 delete query;
308 bool QueryTracker::BeginQuery(GLuint id, GLenum target,
309 GLES2Implementation* gl) {
310 QueryTracker::Query* query = GetQuery(id);
311 if (!query) {
312 query = CreateQuery(id, target);
313 if (!query) {
314 gl->SetGLError(GL_OUT_OF_MEMORY,
315 "glBeginQueryEXT",
316 "transfer buffer allocation failed");
317 return false;
319 } else if (query->target() != target) {
320 gl->SetGLError(GL_INVALID_OPERATION,
321 "glBeginQueryEXT",
322 "target does not match");
323 return false;
326 current_queries_[query->target()] = query;
327 query->Begin(gl);
328 return true;
331 bool QueryTracker::EndQuery(GLenum target, GLES2Implementation* gl) {
332 QueryTargetMap::iterator target_it = current_queries_.find(target);
333 if (target_it == current_queries_.end()) {
334 gl->SetGLError(GL_INVALID_OPERATION,
335 "glEndQueryEXT", "no active query");
336 return false;
339 target_it->second->End(gl);
340 current_queries_.erase(target_it);
341 return true;
344 bool QueryTracker::QueryCounter(GLuint id, GLenum target,
345 GLES2Implementation* gl) {
346 QueryTracker::Query* query = GetQuery(id);
347 if (!query) {
348 query = CreateQuery(id, target);
349 if (!query) {
350 gl->SetGLError(GL_OUT_OF_MEMORY,
351 "glQueryCounterEXT",
352 "transfer buffer allocation failed");
353 return false;
355 } else if (query->target() != target) {
356 gl->SetGLError(GL_INVALID_OPERATION,
357 "glQueryCounterEXT",
358 "target does not match");
359 return false;
362 query->QueryCounter(gl);
363 return true;
366 bool QueryTracker::SetDisjointSync(GLES2Implementation* gl) {
367 if (!disjoint_count_sync_) {
368 // Allocate memory for disjoint value sync.
369 int32_t shm_id = -1;
370 uint32_t shm_offset;
371 void* mem = mapped_memory_->Alloc(sizeof(*disjoint_count_sync_),
372 &shm_id,
373 &shm_offset);
374 if (mem) {
375 disjoint_count_sync_shm_id_ = shm_id;
376 disjoint_count_sync_shm_offset_ = shm_offset;
377 disjoint_count_sync_ = static_cast<DisjointValueSync*>(mem);
378 disjoint_count_sync_->Reset();
379 gl->helper()->SetDisjointValueSyncCHROMIUM(shm_id, shm_offset);
382 return disjoint_count_sync_ != nullptr;
385 bool QueryTracker::CheckAndResetDisjoint() {
386 if (disjoint_count_sync_) {
387 const uint32_t disjoint_count = disjoint_count_sync_->GetDisjointCount();
388 if (local_disjoint_count_ != disjoint_count) {
389 local_disjoint_count_ = disjoint_count;
390 return true;
393 return false;
396 } // namespace gles2
397 } // namespace gpu