• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "gpu/command_buffer/client/query_tracker.h"
6 
7 #include <GLES2/gl2.h>
8 #include <GLES2/gl2ext.h>
9 #include <GLES2/gl2extchromium.h>
10 
11 #include "base/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"
16 
17 namespace gpu {
18 namespace gles2 {
19 
QuerySyncManager(MappedMemoryManager * manager)20 QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
21     : mapped_memory_(manager) {
22   DCHECK(manager);
23 }
24 
~QuerySyncManager()25 QuerySyncManager::~QuerySyncManager() {
26   while (!buckets_.empty()) {
27     mapped_memory_->Free(buckets_.front()->syncs);
28     delete buckets_.front();
29     buckets_.pop_front();
30   }
31 }
32 
Alloc(QuerySyncManager::QueryInfo * info)33 bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
34   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;
42     }
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);
50     }
51   }
52   *info = free_queries_.front();
53   ++(info->bucket->used_query_count);
54   info->sync->Reset();
55   free_queries_.pop_front();
56   return true;
57 }
58 
Free(const QuerySyncManager::QueryInfo & info)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);
63 }
64 
Shrink()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();
71   }
72   free_queries_.swap(new_queue);
73 
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;
82     }
83     buckets_.pop_front();
84   }
85   buckets_.swap(new_buckets);
86 }
87 
Query(GLuint id,GLenum target,const QuerySyncManager::QueryInfo & info)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       flush_count_(0),
97       client_begin_time_us_(0),
98       result_(0) {
99     }
100 
101 
Begin(GLES2Implementation * gl)102 void QueryTracker::Query::Begin(GLES2Implementation* gl) {
103   // init memory, inc count
104   MarkAsActive();
105 
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;
121   }
122 }
123 
End(GLES2Implementation * gl)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 service.
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;
139         }
140       }
141     }
142   }
143   flush_count_ = gl->helper()->flush_generation();
144   gl->helper()->EndQueryEXT(target(), submit_count());
145   MarkAsPending(gl->helper()->InsertToken());
146 }
147 
CheckResultsAvailable(CommandBufferHelper * helper)148 bool QueryTracker::Query::CheckResultsAvailable(
149     CommandBufferHelper* helper) {
150   if (Pending()) {
151     if (base::subtle::Acquire_Load(&info_.sync->process_count) ==
152             submit_count_ ||
153         helper->IsContextLost()) {
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;
169       }
170       state_ = kComplete;
171     } else {
172       if ((helper->flush_generation() - flush_count_ - 1) >= 0x80000000) {
173         helper->Flush();
174       } else {
175         // Insert no-ops so that eventually the GPU process will see more work.
176         helper->Noop(1);
177       }
178     }
179   }
180   return state_ == kComplete;
181 }
182 
GetResult() const183 uint32 QueryTracker::Query::GetResult() const {
184   DCHECK(state_ == kComplete || state_ == kUninitialized);
185   return result_;
186 }
187 
QueryTracker(MappedMemoryManager * manager)188 QueryTracker::QueryTracker(MappedMemoryManager* manager)
189     : query_sync_manager_(manager) {
190 }
191 
~QueryTracker()192 QueryTracker::~QueryTracker() {
193   while (!queries_.empty()) {
194     delete queries_.begin()->second;
195     queries_.erase(queries_.begin());
196   }
197   while (!removed_queries_.empty()) {
198     delete removed_queries_.front();
199     removed_queries_.pop_front();
200   }
201 }
202 
CreateQuery(GLuint id,GLenum target)203 QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
204   DCHECK_NE(0u, id);
205   FreeCompletedQueries();
206   QuerySyncManager::QueryInfo info;
207   if (!query_sync_manager_.Alloc(&info)) {
208     return NULL;
209   }
210   Query* query = new Query(id, target, info);
211   std::pair<QueryMap::iterator, bool> result =
212       queries_.insert(std::make_pair(id, query));
213   DCHECK(result.second);
214   return query;
215 }
216 
GetQuery(GLuint client_id)217 QueryTracker::Query* QueryTracker::GetQuery(
218     GLuint client_id) {
219   QueryMap::iterator it = queries_.find(client_id);
220   return it != queries_.end() ? it->second : NULL;
221 }
222 
RemoveQuery(GLuint client_id)223 void QueryTracker::RemoveQuery(GLuint client_id) {
224   QueryMap::iterator it = queries_.find(client_id);
225   if (it != queries_.end()) {
226     Query* query = it->second;
227     // When you delete a query you can't mark its memory as unused until it's
228     // completed.
229     // Note: If you don't do this you won't mess up the service but you will
230     // mess up yourself.
231     removed_queries_.push_back(query);
232     queries_.erase(it);
233     FreeCompletedQueries();
234   }
235 }
236 
Shrink()237 void QueryTracker::Shrink() {
238   FreeCompletedQueries();
239   query_sync_manager_.Shrink();
240 }
241 
FreeCompletedQueries()242 void QueryTracker::FreeCompletedQueries() {
243   QueryList::iterator it = removed_queries_.begin();
244   while (it != removed_queries_.end()) {
245     Query* query = *it;
246     if (query->Pending() &&
247         base::subtle::Acquire_Load(&query->info_.sync->process_count) !=
248             query->submit_count()) {
249       ++it;
250       continue;
251     }
252 
253     query_sync_manager_.Free(query->info_);
254     it = removed_queries_.erase(it);
255     delete query;
256   }
257 }
258 
259 }  // namespace gles2
260 }  // namespace gpu
261