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: 29 AsyncPixelTransferCompletionObserverImpl(base::subtle::Atomic32 submit_count) 30 : submit_count_(submit_count), cancelled_(false) {} 31 32 void Cancel() { 33 base::AutoLock locked(lock_); 34 cancelled_ = true; 35 } 36 37 virtual void DidComplete(const AsyncMemoryParams& mem_params) OVERRIDE { 38 base::AutoLock locked(lock_); 39 if (!cancelled_) { 40 DCHECK(mem_params.buffer()); 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: 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 76 AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery( 77 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) 78 : Query(manager, target, shm_id, shm_offset) { 79 } 80 81 bool AsyncPixelTransfersCompletedQuery::Begin() { 82 return true; 83 } 84 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) 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() 103 ->AsyncNotifyCompletion(mem_params, observer_); 104 105 return AddToPendingTransferQueue(submit_count); 106 } 107 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 124 void AsyncPixelTransfersCompletedQuery::Destroy(bool /* have_context */) { 125 if (!IsDeleted()) { 126 MarkAsDeleted(); 127 } 128 } 129 130 AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() { 131 if (observer_) 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 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 162 bool AllSamplesPassedQuery::Begin() { 163 BeginQueryHelper(target(), service_id_); 164 return true; 165 } 166 167 bool AllSamplesPassedQuery::End(base::subtle::Atomic32 submit_count) { 168 EndQueryHelper(target()); 169 return AddToPendingQueue(submit_count); 170 } 171 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 186 void AllSamplesPassedQuery::Destroy(bool have_context) { 187 if (have_context && !IsDeleted()) { 188 glDeleteQueriesARB(1, &service_id_); 189 MarkAsDeleted(); 190 } 191 } 192 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 213 CommandsIssuedQuery::CommandsIssuedQuery( 214 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) 215 : Query(manager, target, shm_id, shm_offset) { 216 } 217 218 bool CommandsIssuedQuery::Begin() { 219 begin_time_ = base::TimeTicks::HighResNow(); 220 return true; 221 } 222 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 229 bool CommandsIssuedQuery::Process() { 230 NOTREACHED(); 231 return true; 232 } 233 234 void CommandsIssuedQuery::Destroy(bool /* have_context */) { 235 if (!IsDeleted()) { 236 MarkAsDeleted(); 237 } 238 } 239 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 257 CommandLatencyQuery::CommandLatencyQuery( 258 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) 259 : Query(manager, target, shm_id, shm_offset) { 260 } 261 262 bool CommandLatencyQuery::Begin() { 263 return true; 264 } 265 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 272 bool CommandLatencyQuery::Process() { 273 NOTREACHED(); 274 return true; 275 } 276 277 void CommandLatencyQuery::Destroy(bool /* have_context */) { 278 if (!IsDeleted()) { 279 MarkAsDeleted(); 280 } 281 } 282 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 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 315 bool AsyncReadPixelsCompletedQuery::Begin() { 316 return true; 317 } 318 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 330 void AsyncReadPixelsCompletedQuery::Complete() { 331 completed_ = true; 332 complete_result_ = MarkAsCompleted(1); 333 } 334 335 bool AsyncReadPixelsCompletedQuery::Process() { 336 return !completed_ || complete_result_; 337 } 338 339 void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) { 340 if (!IsDeleted()) { 341 MarkAsDeleted(); 342 } 343 } 344 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 365 GetErrorQuery::GetErrorQuery( 366 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) 367 : Query(manager, target, shm_id, shm_offset) { 368 } 369 370 bool GetErrorQuery::Begin() { 371 return true; 372 } 373 374 bool GetErrorQuery::End(base::subtle::Atomic32 submit_count) { 375 MarkAsPending(submit_count); 376 return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError()); 377 } 378 379 bool GetErrorQuery::Process() { 380 NOTREACHED(); 381 return true; 382 } 383 384 void GetErrorQuery::Destroy(bool /* have_context */) { 385 if (!IsDeleted()) { 386 MarkAsDeleted(); 387 } 388 } 389 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 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 419 bool CommandsCompletedQuery::Begin() { return true; } 420 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 427 bool CommandsCompletedQuery::Process() { 428 if (fence_ && !fence_->HasCompleted()) 429 return true; 430 return MarkAsCompleted(0); 431 } 432 433 void CommandsCompletedQuery::Destroy(bool have_context) { 434 if (have_context && !IsDeleted()) { 435 fence_.reset(); 436 MarkAsDeleted(); 437 } 438 } 439 440 CommandsCompletedQuery::~CommandsCompletedQuery() {} 441 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 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 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 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 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 522 bool QueryManager::IsValidQuery(GLuint id) { 523 GeneratedQueryIds::iterator it = generated_query_ids_.find(id); 524 return it != generated_query_ids_.end(); 525 } 526 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 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 544 void QueryManager::StartTracking(QueryManager::Query* /* query */) { 545 ++query_count_; 546 } 547 548 void QueryManager::StopTracking(QueryManager::Query* /* query */) { 549 --query_count_; 550 } 551 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 574 void QueryManager::BeginQueryHelper(GLenum target, GLuint id) { 575 target = AdjustTargetForEmulation(target); 576 glBeginQueryARB(target, id); 577 } 578 579 void QueryManager::EndQueryHelper(GLenum target) { 580 target = AdjustTargetForEmulation(target); 581 glEndQueryARB(target); 582 } 583 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 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 604 void QueryManager::Query::AddCallback(base::Closure callback) { 605 if (pending_) { 606 callbacks_.push_back(callback); 607 } else { 608 callback.Run(); 609 } 610 } 611 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 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 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 654 bool QueryManager::HavePendingQueries() { 655 return !pending_queries_.empty(); 656 } 657 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 674 bool QueryManager::HavePendingTransferQueries() { 675 return !pending_transfer_queries_.empty(); 676 } 677 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 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 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 730 bool QueryManager::BeginQuery(Query* query) { 731 DCHECK(query); 732 if (!RemovePendingQuery(query)) { 733 return false; 734 } 735 return query->Begin(); 736 } 737 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