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