Roll leveldb 3f7758:803d69 (v1.17 -> v1.18)
[chromium-blink-merge.git] / gpu / command_buffer / client / query_tracker.cc
blobe215c16061bec6e160c1409e38a8d080068f4782
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 "base/atomicops.h"
12 #include "base/numerics/safe_conversions.h"
13 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
14 #include "gpu/command_buffer/client/gles2_implementation.h"
15 #include "gpu/command_buffer/client/mapped_memory.h"
16 #include "gpu/command_buffer/common/time.h"
18 namespace gpu {
19 namespace gles2 {
21 QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
22 : mapped_memory_(manager) {
23 DCHECK(manager);
26 QuerySyncManager::~QuerySyncManager() {
27 while (!buckets_.empty()) {
28 mapped_memory_->Free(buckets_.front()->syncs);
29 delete buckets_.front();
30 buckets_.pop_front();
34 bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
35 DCHECK(info);
36 if (free_queries_.empty()) {
37 int32 shm_id;
38 unsigned int shm_offset;
39 void* mem = mapped_memory_->Alloc(
40 kSyncsPerBucket * sizeof(QuerySync), &shm_id, &shm_offset);
41 if (!mem) {
42 return false;
44 QuerySync* syncs = static_cast<QuerySync*>(mem);
45 Bucket* bucket = new Bucket(syncs);
46 buckets_.push_back(bucket);
47 for (size_t ii = 0; ii < kSyncsPerBucket; ++ii) {
48 free_queries_.push_back(QueryInfo(bucket, shm_id, shm_offset, syncs));
49 ++syncs;
50 shm_offset += sizeof(*syncs);
53 *info = free_queries_.front();
54 ++(info->bucket->used_query_count);
55 info->sync->Reset();
56 free_queries_.pop_front();
57 return true;
60 void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
61 DCHECK_GT(info.bucket->used_query_count, 0u);
62 --(info.bucket->used_query_count);
63 free_queries_.push_back(info);
66 void QuerySyncManager::Shrink() {
67 std::deque<QueryInfo> new_queue;
68 while (!free_queries_.empty()) {
69 if (free_queries_.front().bucket->used_query_count)
70 new_queue.push_back(free_queries_.front());
71 free_queries_.pop_front();
73 free_queries_.swap(new_queue);
75 std::deque<Bucket*> new_buckets;
76 while (!buckets_.empty()) {
77 Bucket* bucket = buckets_.front();
78 if (bucket->used_query_count) {
79 new_buckets.push_back(bucket);
80 } else {
81 mapped_memory_->Free(bucket->syncs);
82 delete bucket;
84 buckets_.pop_front();
86 buckets_.swap(new_buckets);
89 QueryTracker::Query::Query(GLuint id, GLenum target,
90 const QuerySyncManager::QueryInfo& info)
91 : id_(id),
92 target_(target),
93 info_(info),
94 state_(kUninitialized),
95 submit_count_(0),
96 token_(0),
97 flush_count_(0),
98 client_begin_time_us_(0),
99 result_(0) {
103 void QueryTracker::Query::Begin(GLES2Implementation* gl) {
104 // init memory, inc count
105 MarkAsActive();
107 switch (target()) {
108 case GL_GET_ERROR_QUERY_CHROMIUM:
109 // To nothing on begin for error queries.
110 break;
111 case GL_LATENCY_QUERY_CHROMIUM:
112 client_begin_time_us_ = MicrosecondsSinceOriginOfTime();
113 // tell service about id, shared memory and count
114 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
115 break;
116 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
117 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
118 default:
119 // tell service about id, shared memory and count
120 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
121 break;
125 void QueryTracker::Query::End(GLES2Implementation* gl) {
126 switch (target()) {
127 case GL_GET_ERROR_QUERY_CHROMIUM: {
128 GLenum error = gl->GetClientSideGLError();
129 if (error == GL_NO_ERROR) {
130 // There was no error so start the query on the service.
131 // it will end immediately.
132 gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
133 } else {
134 // There's an error on the client, no need to bother the service. Just
135 // set the query as completed and return the error.
136 if (error != GL_NO_ERROR) {
137 state_ = kComplete;
138 result_ = error;
139 return;
144 flush_count_ = gl->helper()->flush_generation();
145 gl->helper()->EndQueryEXT(target(), submit_count());
146 MarkAsPending(gl->helper()->InsertToken());
149 bool QueryTracker::Query::CheckResultsAvailable(
150 CommandBufferHelper* helper) {
151 if (Pending()) {
152 if (base::subtle::Acquire_Load(&info_.sync->process_count) ==
153 submit_count_ ||
154 helper->IsContextLost()) {
155 switch (target()) {
156 case GL_COMMANDS_ISSUED_CHROMIUM:
157 result_ = base::saturated_cast<uint32>(info_.sync->result);
158 break;
159 case GL_LATENCY_QUERY_CHROMIUM:
160 // Disabled DCHECK because of http://crbug.com/419236.
161 //DCHECK(info_.sync->result >= client_begin_time_us_);
162 result_ = base::saturated_cast<uint32>(
163 info_.sync->result - client_begin_time_us_);
164 break;
165 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
166 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
167 default:
168 result_ = static_cast<uint32>(info_.sync->result);
169 break;
171 state_ = kComplete;
172 } else {
173 if ((helper->flush_generation() - flush_count_ - 1) >= 0x80000000) {
174 helper->Flush();
175 } else {
176 // Insert no-ops so that eventually the GPU process will see more work.
177 helper->Noop(1);
181 return state_ == kComplete;
184 uint32 QueryTracker::Query::GetResult() const {
185 DCHECK(state_ == kComplete || state_ == kUninitialized);
186 return result_;
189 QueryTracker::QueryTracker(MappedMemoryManager* manager)
190 : query_sync_manager_(manager) {
193 QueryTracker::~QueryTracker() {
194 while (!queries_.empty()) {
195 delete queries_.begin()->second;
196 queries_.erase(queries_.begin());
198 while (!removed_queries_.empty()) {
199 delete removed_queries_.front();
200 removed_queries_.pop_front();
204 QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
205 DCHECK_NE(0u, id);
206 FreeCompletedQueries();
207 QuerySyncManager::QueryInfo info;
208 if (!query_sync_manager_.Alloc(&info)) {
209 return NULL;
211 Query* query = new Query(id, target, info);
212 std::pair<QueryMap::iterator, bool> result =
213 queries_.insert(std::make_pair(id, query));
214 DCHECK(result.second);
215 return query;
218 QueryTracker::Query* QueryTracker::GetQuery(
219 GLuint client_id) {
220 QueryMap::iterator it = queries_.find(client_id);
221 return it != queries_.end() ? it->second : NULL;
224 void QueryTracker::RemoveQuery(GLuint client_id) {
225 QueryMap::iterator it = queries_.find(client_id);
226 if (it != queries_.end()) {
227 Query* query = it->second;
228 // When you delete a query you can't mark its memory as unused until it's
229 // completed.
230 // Note: If you don't do this you won't mess up the service but you will
231 // mess up yourself.
232 removed_queries_.push_back(query);
233 queries_.erase(it);
234 FreeCompletedQueries();
238 void QueryTracker::Shrink() {
239 FreeCompletedQueries();
240 query_sync_manager_.Shrink();
243 void QueryTracker::FreeCompletedQueries() {
244 QueryList::iterator it = removed_queries_.begin();
245 while (it != removed_queries_.end()) {
246 Query* query = *it;
247 if (query->Pending() &&
248 base::subtle::Acquire_Load(&query->info_.sync->process_count) !=
249 query->submit_count()) {
250 ++it;
251 continue;
254 query_sync_manager_.Free(query->info_);
255 it = removed_queries_.erase(it);
256 delete query;
260 } // namespace gles2
261 } // namespace gpu