• Home
  • 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/service/query_manager.h"
6 
7 #include "base/atomicops.h"
8 #include "base/bind.h"
9 #include "base/logging.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/numerics/safe_math.h"
12 #include "base/synchronization/lock.h"
13 #include "base/time/time.h"
14 #include "gpu/command_buffer/common/gles2_cmd_format.h"
15 #include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
16 #include "gpu/command_buffer/service/error_state.h"
17 #include "gpu/command_buffer/service/feature_info.h"
18 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
19 #include "ui/gl/gl_fence.h"
20 
21 namespace gpu {
22 namespace gles2 {
23 
24 namespace {
25 
26 class AsyncPixelTransferCompletionObserverImpl
27     : public AsyncPixelTransferCompletionObserver {
28  public:
AsyncPixelTransferCompletionObserverImpl(base::subtle::Atomic32 submit_count)29   AsyncPixelTransferCompletionObserverImpl(base::subtle::Atomic32 submit_count)
30       : submit_count_(submit_count), cancelled_(false) {}
31 
Cancel()32   void Cancel() {
33     base::AutoLock locked(lock_);
34     cancelled_ = true;
35   }
36 
DidComplete(const AsyncMemoryParams & mem_params)37   virtual void DidComplete(const AsyncMemoryParams& mem_params) OVERRIDE {
38     base::AutoLock locked(lock_);
39     if (!cancelled_) {
40       DCHECK(mem_params.buffer().get());
41       void* data = mem_params.GetDataAddress();
42       QuerySync* sync = static_cast<QuerySync*>(data);
43       base::subtle::Release_Store(&sync->process_count, submit_count_);
44     }
45   }
46 
47  private:
~AsyncPixelTransferCompletionObserverImpl()48   virtual ~AsyncPixelTransferCompletionObserverImpl() {}
49 
50   base::subtle::Atomic32 submit_count_;
51 
52   base::Lock lock_;
53   bool cancelled_;
54 
55   DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferCompletionObserverImpl);
56 };
57 
58 class AsyncPixelTransfersCompletedQuery
59     : public QueryManager::Query,
60       public base::SupportsWeakPtr<AsyncPixelTransfersCompletedQuery> {
61  public:
62   AsyncPixelTransfersCompletedQuery(
63       QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
64 
65   virtual bool Begin() OVERRIDE;
66   virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
67   virtual bool Process() OVERRIDE;
68   virtual void Destroy(bool have_context) OVERRIDE;
69 
70  protected:
71   virtual ~AsyncPixelTransfersCompletedQuery();
72 
73   scoped_refptr<AsyncPixelTransferCompletionObserverImpl> observer_;
74 };
75 
AsyncPixelTransfersCompletedQuery(QueryManager * manager,GLenum target,int32 shm_id,uint32 shm_offset)76 AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery(
77     QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
78     : Query(manager, target, shm_id, shm_offset) {
79 }
80 
Begin()81 bool AsyncPixelTransfersCompletedQuery::Begin() {
82   return true;
83 }
84 
End(base::subtle::Atomic32 submit_count)85 bool AsyncPixelTransfersCompletedQuery::End(
86     base::subtle::Atomic32 submit_count) {
87   // Get the real shared memory since it might need to be duped to prevent
88   // use-after-free of the memory.
89   scoped_refptr<Buffer> buffer =
90       manager()->decoder()->GetSharedMemoryBuffer(shm_id());
91   if (!buffer.get())
92     return false;
93   AsyncMemoryParams mem_params(buffer, shm_offset(), sizeof(QuerySync));
94   if (!mem_params.GetDataAddress())
95     return false;
96 
97   observer_ = new AsyncPixelTransferCompletionObserverImpl(submit_count);
98 
99   // Ask AsyncPixelTransferDelegate to run completion callback after all
100   // previous async transfers are done. No guarantee that callback is run
101   // on the current thread.
102   manager()->decoder()->GetAsyncPixelTransferManager()->AsyncNotifyCompletion(
103       mem_params, observer_.get());
104 
105   return AddToPendingTransferQueue(submit_count);
106 }
107 
Process()108 bool AsyncPixelTransfersCompletedQuery::Process() {
109   QuerySync* sync = manager()->decoder()->GetSharedMemoryAs<QuerySync*>(
110       shm_id(), shm_offset(), sizeof(*sync));
111   if (!sync)
112     return false;
113 
114   // Check if completion callback has been run. sync->process_count atomicity
115   // is guaranteed as this is already used to notify client of a completed
116   // query.
117   if (base::subtle::Acquire_Load(&sync->process_count) != submit_count())
118     return true;
119 
120   UnmarkAsPending();
121   return true;
122 }
123 
Destroy(bool)124 void AsyncPixelTransfersCompletedQuery::Destroy(bool /* have_context */) {
125   if (!IsDeleted()) {
126     MarkAsDeleted();
127   }
128 }
129 
~AsyncPixelTransfersCompletedQuery()130 AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() {
131   if (observer_.get())
132     observer_->Cancel();
133 }
134 
135 }  // namespace
136 
137 class AllSamplesPassedQuery : public QueryManager::Query {
138  public:
139   AllSamplesPassedQuery(
140       QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset,
141       GLuint service_id);
142   virtual bool Begin() OVERRIDE;
143   virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
144   virtual bool Process() OVERRIDE;
145   virtual void Destroy(bool have_context) OVERRIDE;
146 
147  protected:
148   virtual ~AllSamplesPassedQuery();
149 
150  private:
151   // Service side query id.
152   GLuint service_id_;
153 };
154 
AllSamplesPassedQuery(QueryManager * manager,GLenum target,int32 shm_id,uint32 shm_offset,GLuint service_id)155 AllSamplesPassedQuery::AllSamplesPassedQuery(
156     QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset,
157     GLuint service_id)
158     : Query(manager, target, shm_id, shm_offset),
159       service_id_(service_id) {
160 }
161 
Begin()162 bool AllSamplesPassedQuery::Begin() {
163   BeginQueryHelper(target(), service_id_);
164   return true;
165 }
166 
End(base::subtle::Atomic32 submit_count)167 bool AllSamplesPassedQuery::End(base::subtle::Atomic32 submit_count) {
168   EndQueryHelper(target());
169   return AddToPendingQueue(submit_count);
170 }
171 
Process()172 bool AllSamplesPassedQuery::Process() {
173   GLuint available = 0;
174   glGetQueryObjectuivARB(
175       service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
176   if (!available) {
177     return true;
178   }
179   GLuint result = 0;
180   glGetQueryObjectuivARB(
181       service_id_, GL_QUERY_RESULT_EXT, &result);
182 
183   return MarkAsCompleted(result != 0);
184 }
185 
Destroy(bool have_context)186 void AllSamplesPassedQuery::Destroy(bool have_context) {
187   if (have_context && !IsDeleted()) {
188     glDeleteQueriesARB(1, &service_id_);
189     MarkAsDeleted();
190   }
191 }
192 
~AllSamplesPassedQuery()193 AllSamplesPassedQuery::~AllSamplesPassedQuery() {
194 }
195 
196 class CommandsIssuedQuery : public QueryManager::Query {
197  public:
198   CommandsIssuedQuery(
199       QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
200 
201   virtual bool Begin() OVERRIDE;
202   virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
203   virtual bool Process() OVERRIDE;
204   virtual void Destroy(bool have_context) OVERRIDE;
205 
206  protected:
207   virtual ~CommandsIssuedQuery();
208 
209  private:
210   base::TimeTicks begin_time_;
211 };
212 
CommandsIssuedQuery(QueryManager * manager,GLenum target,int32 shm_id,uint32 shm_offset)213 CommandsIssuedQuery::CommandsIssuedQuery(
214       QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
215     : Query(manager, target, shm_id, shm_offset) {
216 }
217 
Begin()218 bool CommandsIssuedQuery::Begin() {
219   begin_time_ = base::TimeTicks::HighResNow();
220   return true;
221 }
222 
End(base::subtle::Atomic32 submit_count)223 bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count) {
224   base::TimeDelta elapsed = base::TimeTicks::HighResNow() - begin_time_;
225   MarkAsPending(submit_count);
226   return MarkAsCompleted(elapsed.InMicroseconds());
227 }
228 
Process()229 bool CommandsIssuedQuery::Process() {
230   NOTREACHED();
231   return true;
232 }
233 
Destroy(bool)234 void CommandsIssuedQuery::Destroy(bool /* have_context */) {
235   if (!IsDeleted()) {
236     MarkAsDeleted();
237   }
238 }
239 
~CommandsIssuedQuery()240 CommandsIssuedQuery::~CommandsIssuedQuery() {
241 }
242 
243 class CommandLatencyQuery : public QueryManager::Query {
244  public:
245   CommandLatencyQuery(
246       QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
247 
248   virtual bool Begin() OVERRIDE;
249   virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
250   virtual bool Process() OVERRIDE;
251   virtual void Destroy(bool have_context) OVERRIDE;
252 
253  protected:
254   virtual ~CommandLatencyQuery();
255 };
256 
CommandLatencyQuery(QueryManager * manager,GLenum target,int32 shm_id,uint32 shm_offset)257 CommandLatencyQuery::CommandLatencyQuery(
258       QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
259     : Query(manager, target, shm_id, shm_offset) {
260 }
261 
Begin()262 bool CommandLatencyQuery::Begin() {
263     return true;
264 }
265 
End(base::subtle::Atomic32 submit_count)266 bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count) {
267     base::TimeDelta now = base::TimeTicks::HighResNow() - base::TimeTicks();
268     MarkAsPending(submit_count);
269     return MarkAsCompleted(now.InMicroseconds());
270 }
271 
Process()272 bool CommandLatencyQuery::Process() {
273   NOTREACHED();
274   return true;
275 }
276 
Destroy(bool)277 void CommandLatencyQuery::Destroy(bool /* have_context */) {
278   if (!IsDeleted()) {
279     MarkAsDeleted();
280   }
281 }
282 
~CommandLatencyQuery()283 CommandLatencyQuery::~CommandLatencyQuery() {
284 }
285 
286 
287 class AsyncReadPixelsCompletedQuery
288     : public QueryManager::Query,
289       public base::SupportsWeakPtr<AsyncReadPixelsCompletedQuery> {
290  public:
291   AsyncReadPixelsCompletedQuery(
292       QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
293 
294   virtual bool Begin() OVERRIDE;
295   virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
296   virtual bool Process() OVERRIDE;
297   virtual void Destroy(bool have_context) OVERRIDE;
298 
299  protected:
300   void Complete();
301   virtual ~AsyncReadPixelsCompletedQuery();
302 
303  private:
304   bool completed_;
305   bool complete_result_;
306 };
307 
AsyncReadPixelsCompletedQuery(QueryManager * manager,GLenum target,int32 shm_id,uint32 shm_offset)308 AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
309     QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
310     : Query(manager, target, shm_id, shm_offset),
311       completed_(false),
312       complete_result_(false) {
313 }
314 
Begin()315 bool AsyncReadPixelsCompletedQuery::Begin() {
316   return true;
317 }
318 
End(base::subtle::Atomic32 submit_count)319 bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
320   if (!AddToPendingQueue(submit_count)) {
321     return false;
322   }
323   manager()->decoder()->WaitForReadPixels(
324       base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
325                  AsWeakPtr()));
326 
327   return Process();
328 }
329 
Complete()330 void AsyncReadPixelsCompletedQuery::Complete() {
331   completed_ = true;
332   complete_result_ = MarkAsCompleted(1);
333 }
334 
Process()335 bool AsyncReadPixelsCompletedQuery::Process() {
336   return !completed_ || complete_result_;
337 }
338 
Destroy(bool)339 void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
340   if (!IsDeleted()) {
341     MarkAsDeleted();
342   }
343 }
344 
~AsyncReadPixelsCompletedQuery()345 AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
346 }
347 
348 
349 class GetErrorQuery : public QueryManager::Query {
350  public:
351   GetErrorQuery(
352       QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
353 
354   virtual bool Begin() OVERRIDE;
355   virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
356   virtual bool Process() OVERRIDE;
357   virtual void Destroy(bool have_context) OVERRIDE;
358 
359  protected:
360   virtual ~GetErrorQuery();
361 
362  private:
363 };
364 
GetErrorQuery(QueryManager * manager,GLenum target,int32 shm_id,uint32 shm_offset)365 GetErrorQuery::GetErrorQuery(
366       QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
367     : Query(manager, target, shm_id, shm_offset) {
368 }
369 
Begin()370 bool GetErrorQuery::Begin() {
371   return true;
372 }
373 
End(base::subtle::Atomic32 submit_count)374 bool GetErrorQuery::End(base::subtle::Atomic32 submit_count) {
375   MarkAsPending(submit_count);
376   return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
377 }
378 
Process()379 bool GetErrorQuery::Process() {
380   NOTREACHED();
381   return true;
382 }
383 
Destroy(bool)384 void GetErrorQuery::Destroy(bool /* have_context */) {
385   if (!IsDeleted()) {
386     MarkAsDeleted();
387   }
388 }
389 
~GetErrorQuery()390 GetErrorQuery::~GetErrorQuery() {
391 }
392 
393 class CommandsCompletedQuery : public QueryManager::Query {
394  public:
395   CommandsCompletedQuery(QueryManager* manager,
396                          GLenum target,
397                          int32 shm_id,
398                          uint32 shm_offset);
399 
400   // Overridden from QueryManager::Query:
401   virtual bool Begin() OVERRIDE;
402   virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
403   virtual bool Process() OVERRIDE;
404   virtual void Destroy(bool have_context) OVERRIDE;
405 
406  protected:
407   virtual ~CommandsCompletedQuery();
408 
409  private:
410   scoped_ptr<gfx::GLFence> fence_;
411 };
412 
CommandsCompletedQuery(QueryManager * manager,GLenum target,int32 shm_id,uint32 shm_offset)413 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager,
414                                                GLenum target,
415                                                int32 shm_id,
416                                                uint32 shm_offset)
417     : Query(manager, target, shm_id, shm_offset) {}
418 
Begin()419 bool CommandsCompletedQuery::Begin() { return true; }
420 
End(base::subtle::Atomic32 submit_count)421 bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
422   fence_.reset(gfx::GLFence::Create());
423   DCHECK(fence_);
424   return AddToPendingQueue(submit_count);
425 }
426 
Process()427 bool CommandsCompletedQuery::Process() {
428   if (fence_ && !fence_->HasCompleted())
429     return true;
430   return MarkAsCompleted(0);
431 }
432 
Destroy(bool have_context)433 void CommandsCompletedQuery::Destroy(bool have_context) {
434   if (have_context && !IsDeleted()) {
435     fence_.reset();
436     MarkAsDeleted();
437   }
438 }
439 
~CommandsCompletedQuery()440 CommandsCompletedQuery::~CommandsCompletedQuery() {}
441 
QueryManager(GLES2Decoder * decoder,FeatureInfo * feature_info)442 QueryManager::QueryManager(
443     GLES2Decoder* decoder,
444     FeatureInfo* feature_info)
445     : decoder_(decoder),
446       use_arb_occlusion_query2_for_occlusion_query_boolean_(
447           feature_info->feature_flags(
448             ).use_arb_occlusion_query2_for_occlusion_query_boolean),
449       use_arb_occlusion_query_for_occlusion_query_boolean_(
450           feature_info->feature_flags(
451             ).use_arb_occlusion_query_for_occlusion_query_boolean),
452       query_count_(0) {
453   DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_ &&
454            use_arb_occlusion_query2_for_occlusion_query_boolean_));
455 }
456 
~QueryManager()457 QueryManager::~QueryManager() {
458   DCHECK(queries_.empty());
459 
460   // If this triggers, that means something is keeping a reference to
461   // a Query belonging to this.
462   CHECK_EQ(query_count_, 0u);
463 }
464 
Destroy(bool have_context)465 void QueryManager::Destroy(bool have_context) {
466   pending_queries_.clear();
467   pending_transfer_queries_.clear();
468   while (!queries_.empty()) {
469     Query* query = queries_.begin()->second.get();
470     query->Destroy(have_context);
471     queries_.erase(queries_.begin());
472   }
473 }
474 
CreateQuery(GLenum target,GLuint client_id,int32 shm_id,uint32 shm_offset)475 QueryManager::Query* QueryManager::CreateQuery(
476     GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) {
477   scoped_refptr<Query> query;
478   switch (target) {
479     case GL_COMMANDS_ISSUED_CHROMIUM:
480       query = new CommandsIssuedQuery(this, target, shm_id, shm_offset);
481       break;
482     case GL_LATENCY_QUERY_CHROMIUM:
483       query = new CommandLatencyQuery(this, target, shm_id, shm_offset);
484       break;
485     case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
486       // Currently async pixel transfer delegates only support uploads.
487       query = new AsyncPixelTransfersCompletedQuery(
488           this, target, shm_id, shm_offset);
489       break;
490     case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
491       query = new AsyncReadPixelsCompletedQuery(
492           this, target, shm_id, shm_offset);
493       break;
494     case GL_GET_ERROR_QUERY_CHROMIUM:
495       query = new GetErrorQuery(this, target, shm_id, shm_offset);
496       break;
497     case GL_COMMANDS_COMPLETED_CHROMIUM:
498       query = new CommandsCompletedQuery(this, target, shm_id, shm_offset);
499       break;
500     default: {
501       GLuint service_id = 0;
502       glGenQueriesARB(1, &service_id);
503       DCHECK_NE(0u, service_id);
504       query = new AllSamplesPassedQuery(
505           this, target, shm_id, shm_offset, service_id);
506       break;
507     }
508   }
509   std::pair<QueryMap::iterator, bool> result =
510       queries_.insert(std::make_pair(client_id, query));
511   DCHECK(result.second);
512   return query.get();
513 }
514 
GenQueries(GLsizei n,const GLuint * queries)515 void QueryManager::GenQueries(GLsizei n, const GLuint* queries) {
516   DCHECK_GE(n, 0);
517   for (GLsizei i = 0; i < n; ++i) {
518     generated_query_ids_.insert(queries[i]);
519   }
520 }
521 
IsValidQuery(GLuint id)522 bool QueryManager::IsValidQuery(GLuint id) {
523   GeneratedQueryIds::iterator it = generated_query_ids_.find(id);
524   return it != generated_query_ids_.end();
525 }
526 
GetQuery(GLuint client_id)527 QueryManager::Query* QueryManager::GetQuery(
528     GLuint client_id) {
529   QueryMap::iterator it = queries_.find(client_id);
530   return it != queries_.end() ? it->second.get() : NULL;
531 }
532 
RemoveQuery(GLuint client_id)533 void QueryManager::RemoveQuery(GLuint client_id) {
534   QueryMap::iterator it = queries_.find(client_id);
535   if (it != queries_.end()) {
536     Query* query = it->second.get();
537     RemovePendingQuery(query);
538     query->MarkAsDeleted();
539     queries_.erase(it);
540   }
541   generated_query_ids_.erase(client_id);
542 }
543 
StartTracking(QueryManager::Query *)544 void QueryManager::StartTracking(QueryManager::Query* /* query */) {
545   ++query_count_;
546 }
547 
StopTracking(QueryManager::Query *)548 void QueryManager::StopTracking(QueryManager::Query* /* query */) {
549   --query_count_;
550 }
551 
AdjustTargetForEmulation(GLenum target)552 GLenum QueryManager::AdjustTargetForEmulation(GLenum target) {
553   switch (target) {
554     case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
555     case GL_ANY_SAMPLES_PASSED_EXT:
556       if (use_arb_occlusion_query2_for_occlusion_query_boolean_) {
557         // ARB_occlusion_query2 does not have a
558         // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
559         // target.
560         target = GL_ANY_SAMPLES_PASSED_EXT;
561       } else if (use_arb_occlusion_query_for_occlusion_query_boolean_) {
562         // ARB_occlusion_query does not have a
563         // GL_ANY_SAMPLES_PASSED_EXT
564         // target.
565         target = GL_SAMPLES_PASSED_ARB;
566       }
567       break;
568     default:
569       break;
570   }
571   return target;
572 }
573 
BeginQueryHelper(GLenum target,GLuint id)574 void QueryManager::BeginQueryHelper(GLenum target, GLuint id) {
575   target = AdjustTargetForEmulation(target);
576   glBeginQueryARB(target, id);
577 }
578 
EndQueryHelper(GLenum target)579 void QueryManager::EndQueryHelper(GLenum target) {
580   target = AdjustTargetForEmulation(target);
581   glEndQueryARB(target);
582 }
583 
Query(QueryManager * manager,GLenum target,int32 shm_id,uint32 shm_offset)584 QueryManager::Query::Query(
585      QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
586     : manager_(manager),
587       target_(target),
588       shm_id_(shm_id),
589       shm_offset_(shm_offset),
590       submit_count_(0),
591       pending_(false),
592       deleted_(false) {
593   DCHECK(manager);
594   manager_->StartTracking(this);
595 }
596 
RunCallbacks()597 void QueryManager::Query::RunCallbacks() {
598   for (size_t i = 0; i < callbacks_.size(); i++) {
599     callbacks_[i].Run();
600   }
601   callbacks_.clear();
602 }
603 
AddCallback(base::Closure callback)604 void QueryManager::Query::AddCallback(base::Closure callback) {
605   if (pending_) {
606     callbacks_.push_back(callback);
607   } else {
608     callback.Run();
609   }
610 }
611 
~Query()612 QueryManager::Query::~Query() {
613   // The query is getting deleted, either by the client or
614   // because the context was lost. Call any outstanding
615   // callbacks to avoid leaks.
616   RunCallbacks();
617   if (manager_) {
618     manager_->StopTracking(this);
619     manager_ = NULL;
620   }
621 }
622 
MarkAsCompleted(uint64 result)623 bool QueryManager::Query::MarkAsCompleted(uint64 result) {
624   DCHECK(pending_);
625   QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>(
626       shm_id_, shm_offset_, sizeof(*sync));
627   if (!sync) {
628     return false;
629   }
630 
631   pending_ = false;
632   sync->result = result;
633   base::subtle::Release_Store(&sync->process_count, submit_count_);
634 
635   return true;
636 }
637 
ProcessPendingQueries()638 bool QueryManager::ProcessPendingQueries() {
639   while (!pending_queries_.empty()) {
640     Query* query = pending_queries_.front().get();
641     if (!query->Process()) {
642       return false;
643     }
644     if (query->pending()) {
645       break;
646     }
647     query->RunCallbacks();
648     pending_queries_.pop_front();
649   }
650 
651   return true;
652 }
653 
HavePendingQueries()654 bool QueryManager::HavePendingQueries() {
655   return !pending_queries_.empty();
656 }
657 
ProcessPendingTransferQueries()658 bool QueryManager::ProcessPendingTransferQueries() {
659   while (!pending_transfer_queries_.empty()) {
660     Query* query = pending_transfer_queries_.front().get();
661     if (!query->Process()) {
662       return false;
663     }
664     if (query->pending()) {
665       break;
666     }
667     query->RunCallbacks();
668     pending_transfer_queries_.pop_front();
669   }
670 
671   return true;
672 }
673 
HavePendingTransferQueries()674 bool QueryManager::HavePendingTransferQueries() {
675   return !pending_transfer_queries_.empty();
676 }
677 
AddPendingQuery(Query * query,base::subtle::Atomic32 submit_count)678 bool QueryManager::AddPendingQuery(Query* query,
679                                    base::subtle::Atomic32 submit_count) {
680   DCHECK(query);
681   DCHECK(!query->IsDeleted());
682   if (!RemovePendingQuery(query)) {
683     return false;
684   }
685   query->MarkAsPending(submit_count);
686   pending_queries_.push_back(query);
687   return true;
688 }
689 
AddPendingTransferQuery(Query * query,base::subtle::Atomic32 submit_count)690 bool QueryManager::AddPendingTransferQuery(
691     Query* query,
692     base::subtle::Atomic32 submit_count) {
693   DCHECK(query);
694   DCHECK(!query->IsDeleted());
695   if (!RemovePendingQuery(query)) {
696     return false;
697   }
698   query->MarkAsPending(submit_count);
699   pending_transfer_queries_.push_back(query);
700   return true;
701 }
702 
RemovePendingQuery(Query * query)703 bool QueryManager::RemovePendingQuery(Query* query) {
704   DCHECK(query);
705   if (query->pending()) {
706     // TODO(gman): Speed this up if this is a common operation. This would only
707     // happen if you do being/end begin/end on the same query without waiting
708     // for the first one to finish.
709     for (QueryQueue::iterator it = pending_queries_.begin();
710          it != pending_queries_.end(); ++it) {
711       if (it->get() == query) {
712         pending_queries_.erase(it);
713         break;
714       }
715     }
716     for (QueryQueue::iterator it = pending_transfer_queries_.begin();
717          it != pending_transfer_queries_.end(); ++it) {
718       if (it->get() == query) {
719         pending_transfer_queries_.erase(it);
720         break;
721       }
722     }
723     if (!query->MarkAsCompleted(0)) {
724       return false;
725     }
726   }
727   return true;
728 }
729 
BeginQuery(Query * query)730 bool QueryManager::BeginQuery(Query* query) {
731   DCHECK(query);
732   if (!RemovePendingQuery(query)) {
733     return false;
734   }
735   return query->Begin();
736 }
737 
EndQuery(Query * query,base::subtle::Atomic32 submit_count)738 bool QueryManager::EndQuery(Query* query, base::subtle::Atomic32 submit_count) {
739   DCHECK(query);
740   if (!RemovePendingQuery(query)) {
741     return false;
742   }
743   return query->End(submit_count);
744 }
745 
746 }  // namespace gles2
747 }  // namespace gpu
748