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