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