Don't add an aura tooltip to bubble close buttons on Windows.
[chromium-blink-merge.git] / gpu / command_buffer / service / query_manager.cc
blobc74a65000c30408a5ca0695560d864e24d0d5d1c
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.
5 #include "gpu/command_buffer/service/query_manager.h"
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"
21 namespace gpu {
22 namespace gles2 {
24 namespace {
26 class AsyncPixelTransferCompletionObserverImpl
27 : public AsyncPixelTransferCompletionObserver {
28 public:
29 AsyncPixelTransferCompletionObserverImpl(base::subtle::Atomic32 submit_count)
30 : submit_count_(submit_count), cancelled_(false) {}
32 void Cancel() {
33 base::AutoLock locked(lock_);
34 cancelled_ = true;
37 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_);
47 private:
48 ~AsyncPixelTransferCompletionObserverImpl() override {}
50 base::subtle::Atomic32 submit_count_;
52 base::Lock lock_;
53 bool cancelled_;
55 DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferCompletionObserverImpl);
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);
65 bool Begin() override;
66 bool End(base::subtle::Atomic32 submit_count) override;
67 bool Process(bool did_finish) override;
68 void Destroy(bool have_context) override;
70 protected:
71 ~AsyncPixelTransfersCompletedQuery() override;
73 scoped_refptr<AsyncPixelTransferCompletionObserverImpl> observer_;
76 AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery(
77 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
78 : Query(manager, target, shm_id, shm_offset) {
81 bool AsyncPixelTransfersCompletedQuery::Begin() {
82 return true;
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;
97 observer_ = new AsyncPixelTransferCompletionObserverImpl(submit_count);
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());
105 return AddToPendingTransferQueue(submit_count);
108 bool AsyncPixelTransfersCompletedQuery::Process(bool did_finish) {
109 QuerySync* sync = manager()->decoder()->GetSharedMemoryAs<QuerySync*>(
110 shm_id(), shm_offset(), sizeof(*sync));
111 if (!sync)
112 return false;
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;
120 UnmarkAsPending();
121 return true;
124 void AsyncPixelTransfersCompletedQuery::Destroy(bool /* have_context */) {
125 if (!IsDeleted()) {
126 MarkAsDeleted();
130 AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() {
131 if (observer_.get())
132 observer_->Cancel();
135 } // namespace
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 bool Begin() override;
143 bool End(base::subtle::Atomic32 submit_count) override;
144 bool Process(bool did_finish) override;
145 void Destroy(bool have_context) override;
147 protected:
148 ~AllSamplesPassedQuery() override;
150 private:
151 // Service side query id.
152 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) {
162 bool AllSamplesPassedQuery::Begin() {
163 BeginQueryHelper(target(), service_id_);
164 return true;
167 bool AllSamplesPassedQuery::End(base::subtle::Atomic32 submit_count) {
168 EndQueryHelper(target());
169 return AddToPendingQueue(submit_count);
172 bool AllSamplesPassedQuery::Process(bool did_finish) {
173 GLuint available = 0;
174 glGetQueryObjectuiv(
175 service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
176 if (!available) {
177 return true;
179 GLuint result = 0;
180 glGetQueryObjectuiv(
181 service_id_, GL_QUERY_RESULT_EXT, &result);
183 return MarkAsCompleted(result != 0);
186 void AllSamplesPassedQuery::Destroy(bool have_context) {
187 if (have_context && !IsDeleted()) {
188 glDeleteQueries(1, &service_id_);
189 MarkAsDeleted();
193 AllSamplesPassedQuery::~AllSamplesPassedQuery() {
196 class CommandsIssuedQuery : public QueryManager::Query {
197 public:
198 CommandsIssuedQuery(
199 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
201 bool Begin() override;
202 bool End(base::subtle::Atomic32 submit_count) override;
203 bool Process(bool did_finish) override;
204 void Destroy(bool have_context) override;
206 protected:
207 ~CommandsIssuedQuery() override;
209 private:
210 base::TimeTicks begin_time_;
213 CommandsIssuedQuery::CommandsIssuedQuery(
214 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
215 : Query(manager, target, shm_id, shm_offset) {
218 bool CommandsIssuedQuery::Begin() {
219 begin_time_ = base::TimeTicks::Now();
220 return true;
223 bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count) {
224 base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
225 MarkAsPending(submit_count);
226 return MarkAsCompleted(elapsed.InMicroseconds());
229 bool CommandsIssuedQuery::Process(bool did_finish) {
230 NOTREACHED();
231 return true;
234 void CommandsIssuedQuery::Destroy(bool /* have_context */) {
235 if (!IsDeleted()) {
236 MarkAsDeleted();
240 CommandsIssuedQuery::~CommandsIssuedQuery() {
243 class CommandLatencyQuery : public QueryManager::Query {
244 public:
245 CommandLatencyQuery(
246 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
248 bool Begin() override;
249 bool End(base::subtle::Atomic32 submit_count) override;
250 bool Process(bool did_finish) override;
251 void Destroy(bool have_context) override;
253 protected:
254 ~CommandLatencyQuery() override;
257 CommandLatencyQuery::CommandLatencyQuery(
258 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
259 : Query(manager, target, shm_id, shm_offset) {
262 bool CommandLatencyQuery::Begin() {
263 return true;
266 bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count) {
267 base::TimeDelta now = base::TimeTicks::Now() - base::TimeTicks();
268 MarkAsPending(submit_count);
269 return MarkAsCompleted(now.InMicroseconds());
272 bool CommandLatencyQuery::Process(bool did_finish) {
273 NOTREACHED();
274 return true;
277 void CommandLatencyQuery::Destroy(bool /* have_context */) {
278 if (!IsDeleted()) {
279 MarkAsDeleted();
283 CommandLatencyQuery::~CommandLatencyQuery() {
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);
294 bool Begin() override;
295 bool End(base::subtle::Atomic32 submit_count) override;
296 bool Process(bool did_finish) override;
297 void Destroy(bool have_context) override;
299 protected:
300 void Complete();
301 ~AsyncReadPixelsCompletedQuery() override;
303 private:
304 bool completed_;
305 bool complete_result_;
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) {
315 bool AsyncReadPixelsCompletedQuery::Begin() {
316 return true;
319 bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
320 if (!AddToPendingQueue(submit_count)) {
321 return false;
323 manager()->decoder()->WaitForReadPixels(
324 base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
325 AsWeakPtr()));
327 return Process(false);
330 void AsyncReadPixelsCompletedQuery::Complete() {
331 completed_ = true;
332 complete_result_ = MarkAsCompleted(1);
335 bool AsyncReadPixelsCompletedQuery::Process(bool did_finish) {
336 return !completed_ || complete_result_;
339 void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
340 if (!IsDeleted()) {
341 MarkAsDeleted();
345 AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
349 class GetErrorQuery : public QueryManager::Query {
350 public:
351 GetErrorQuery(
352 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
354 bool Begin() override;
355 bool End(base::subtle::Atomic32 submit_count) override;
356 bool Process(bool did_finish) override;
357 void Destroy(bool have_context) override;
359 protected:
360 ~GetErrorQuery() override;
362 private:
365 GetErrorQuery::GetErrorQuery(
366 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
367 : Query(manager, target, shm_id, shm_offset) {
370 bool GetErrorQuery::Begin() {
371 return true;
374 bool GetErrorQuery::End(base::subtle::Atomic32 submit_count) {
375 MarkAsPending(submit_count);
376 return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
379 bool GetErrorQuery::Process(bool did_finish) {
380 NOTREACHED();
381 return true;
384 void GetErrorQuery::Destroy(bool /* have_context */) {
385 if (!IsDeleted()) {
386 MarkAsDeleted();
390 GetErrorQuery::~GetErrorQuery() {
393 class CommandsCompletedQuery : public QueryManager::Query {
394 public:
395 CommandsCompletedQuery(QueryManager* manager,
396 GLenum target,
397 int32 shm_id,
398 uint32 shm_offset);
400 // Overridden from QueryManager::Query:
401 bool Begin() override;
402 bool End(base::subtle::Atomic32 submit_count) override;
403 bool Process(bool did_finish) override;
404 void Destroy(bool have_context) override;
406 protected:
407 ~CommandsCompletedQuery() override;
409 private:
410 scoped_ptr<gfx::GLFence> fence_;
411 base::TimeTicks begin_time_;
414 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager,
415 GLenum target,
416 int32 shm_id,
417 uint32 shm_offset)
418 : Query(manager, target, shm_id, shm_offset) {}
420 bool CommandsCompletedQuery::Begin() {
421 begin_time_ = base::TimeTicks::Now();
422 return true;
425 bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
426 fence_.reset(gfx::GLFence::Create());
427 DCHECK(fence_);
428 return AddToPendingQueue(submit_count);
431 bool CommandsCompletedQuery::Process(bool did_finish) {
432 // Note: |did_finish| guarantees that the GPU has passed the fence but
433 // we cannot assume that GLFence::HasCompleted() will return true yet as
434 // that's not guaranteed by all GLFence implementations.
435 if (!did_finish && fence_ && !fence_->HasCompleted())
436 return true;
438 base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
439 return MarkAsCompleted(elapsed.InMicroseconds());
442 void CommandsCompletedQuery::Destroy(bool have_context) {
443 if (have_context && !IsDeleted()) {
444 fence_.reset();
445 MarkAsDeleted();
449 CommandsCompletedQuery::~CommandsCompletedQuery() {}
451 QueryManager::QueryManager(
452 GLES2Decoder* decoder,
453 FeatureInfo* feature_info)
454 : decoder_(decoder),
455 use_arb_occlusion_query2_for_occlusion_query_boolean_(
456 feature_info->feature_flags(
457 ).use_arb_occlusion_query2_for_occlusion_query_boolean),
458 use_arb_occlusion_query_for_occlusion_query_boolean_(
459 feature_info->feature_flags(
460 ).use_arb_occlusion_query_for_occlusion_query_boolean),
461 query_count_(0) {
462 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_ &&
463 use_arb_occlusion_query2_for_occlusion_query_boolean_));
466 QueryManager::~QueryManager() {
467 DCHECK(queries_.empty());
469 // If this triggers, that means something is keeping a reference to
470 // a Query belonging to this.
471 CHECK_EQ(query_count_, 0u);
474 void QueryManager::Destroy(bool have_context) {
475 pending_queries_.clear();
476 pending_transfer_queries_.clear();
477 while (!queries_.empty()) {
478 Query* query = queries_.begin()->second.get();
479 query->Destroy(have_context);
480 queries_.erase(queries_.begin());
484 QueryManager::Query* QueryManager::CreateQuery(
485 GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) {
486 scoped_refptr<Query> query;
487 switch (target) {
488 case GL_COMMANDS_ISSUED_CHROMIUM:
489 query = new CommandsIssuedQuery(this, target, shm_id, shm_offset);
490 break;
491 case GL_LATENCY_QUERY_CHROMIUM:
492 query = new CommandLatencyQuery(this, target, shm_id, shm_offset);
493 break;
494 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
495 // Currently async pixel transfer delegates only support uploads.
496 query = new AsyncPixelTransfersCompletedQuery(
497 this, target, shm_id, shm_offset);
498 break;
499 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
500 query = new AsyncReadPixelsCompletedQuery(
501 this, target, shm_id, shm_offset);
502 break;
503 case GL_GET_ERROR_QUERY_CHROMIUM:
504 query = new GetErrorQuery(this, target, shm_id, shm_offset);
505 break;
506 case GL_COMMANDS_COMPLETED_CHROMIUM:
507 query = new CommandsCompletedQuery(this, target, shm_id, shm_offset);
508 break;
509 default: {
510 GLuint service_id = 0;
511 glGenQueries(1, &service_id);
512 DCHECK_NE(0u, service_id);
513 query = new AllSamplesPassedQuery(
514 this, target, shm_id, shm_offset, service_id);
515 break;
518 std::pair<QueryMap::iterator, bool> result =
519 queries_.insert(std::make_pair(client_id, query));
520 DCHECK(result.second);
521 return query.get();
524 void QueryManager::GenQueries(GLsizei n, const GLuint* queries) {
525 DCHECK_GE(n, 0);
526 for (GLsizei i = 0; i < n; ++i) {
527 generated_query_ids_.insert(queries[i]);
531 bool QueryManager::IsValidQuery(GLuint id) {
532 GeneratedQueryIds::iterator it = generated_query_ids_.find(id);
533 return it != generated_query_ids_.end();
536 QueryManager::Query* QueryManager::GetQuery(
537 GLuint client_id) {
538 QueryMap::iterator it = queries_.find(client_id);
539 return it != queries_.end() ? it->second.get() : NULL;
542 void QueryManager::RemoveQuery(GLuint client_id) {
543 QueryMap::iterator it = queries_.find(client_id);
544 if (it != queries_.end()) {
545 Query* query = it->second.get();
546 RemovePendingQuery(query);
547 query->MarkAsDeleted();
548 queries_.erase(it);
550 generated_query_ids_.erase(client_id);
553 void QueryManager::StartTracking(QueryManager::Query* /* query */) {
554 ++query_count_;
557 void QueryManager::StopTracking(QueryManager::Query* /* query */) {
558 --query_count_;
561 GLenum QueryManager::AdjustTargetForEmulation(GLenum target) {
562 switch (target) {
563 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
564 case GL_ANY_SAMPLES_PASSED_EXT:
565 if (use_arb_occlusion_query2_for_occlusion_query_boolean_) {
566 // ARB_occlusion_query2 does not have a
567 // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
568 // target.
569 target = GL_ANY_SAMPLES_PASSED_EXT;
570 } else if (use_arb_occlusion_query_for_occlusion_query_boolean_) {
571 // ARB_occlusion_query does not have a
572 // GL_ANY_SAMPLES_PASSED_EXT
573 // target.
574 target = GL_SAMPLES_PASSED_ARB;
576 break;
577 default:
578 break;
580 return target;
583 void QueryManager::BeginQueryHelper(GLenum target, GLuint id) {
584 target = AdjustTargetForEmulation(target);
585 glBeginQuery(target, id);
588 void QueryManager::EndQueryHelper(GLenum target) {
589 target = AdjustTargetForEmulation(target);
590 glEndQuery(target);
593 QueryManager::Query::Query(
594 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
595 : manager_(manager),
596 target_(target),
597 shm_id_(shm_id),
598 shm_offset_(shm_offset),
599 submit_count_(0),
600 pending_(false),
601 deleted_(false) {
602 DCHECK(manager);
603 manager_->StartTracking(this);
606 void QueryManager::Query::RunCallbacks() {
607 for (size_t i = 0; i < callbacks_.size(); i++) {
608 callbacks_[i].Run();
610 callbacks_.clear();
613 void QueryManager::Query::AddCallback(base::Closure callback) {
614 if (pending_) {
615 callbacks_.push_back(callback);
616 } else {
617 callback.Run();
621 QueryManager::Query::~Query() {
622 // The query is getting deleted, either by the client or
623 // because the context was lost. Call any outstanding
624 // callbacks to avoid leaks.
625 RunCallbacks();
626 if (manager_) {
627 manager_->StopTracking(this);
628 manager_ = NULL;
632 bool QueryManager::Query::MarkAsCompleted(uint64 result) {
633 DCHECK(pending_);
634 QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>(
635 shm_id_, shm_offset_, sizeof(*sync));
636 if (!sync) {
637 return false;
640 pending_ = false;
641 sync->result = result;
642 base::subtle::Release_Store(&sync->process_count, submit_count_);
644 return true;
647 bool QueryManager::ProcessPendingQueries(bool did_finish) {
648 while (!pending_queries_.empty()) {
649 Query* query = pending_queries_.front().get();
650 if (!query->Process(did_finish)) {
651 return false;
653 if (query->pending()) {
654 break;
656 query->RunCallbacks();
657 pending_queries_.pop_front();
660 return true;
663 bool QueryManager::HavePendingQueries() {
664 return !pending_queries_.empty();
667 bool QueryManager::ProcessPendingTransferQueries() {
668 while (!pending_transfer_queries_.empty()) {
669 Query* query = pending_transfer_queries_.front().get();
670 if (!query->Process(false)) {
671 return false;
673 if (query->pending()) {
674 break;
676 query->RunCallbacks();
677 pending_transfer_queries_.pop_front();
680 return true;
683 bool QueryManager::HavePendingTransferQueries() {
684 return !pending_transfer_queries_.empty();
687 bool QueryManager::AddPendingQuery(Query* query,
688 base::subtle::Atomic32 submit_count) {
689 DCHECK(query);
690 DCHECK(!query->IsDeleted());
691 if (!RemovePendingQuery(query)) {
692 return false;
694 query->MarkAsPending(submit_count);
695 pending_queries_.push_back(query);
696 return true;
699 bool QueryManager::AddPendingTransferQuery(
700 Query* query,
701 base::subtle::Atomic32 submit_count) {
702 DCHECK(query);
703 DCHECK(!query->IsDeleted());
704 if (!RemovePendingQuery(query)) {
705 return false;
707 query->MarkAsPending(submit_count);
708 pending_transfer_queries_.push_back(query);
709 return true;
712 bool QueryManager::RemovePendingQuery(Query* query) {
713 DCHECK(query);
714 if (query->pending()) {
715 // TODO(gman): Speed this up if this is a common operation. This would only
716 // happen if you do being/end begin/end on the same query without waiting
717 // for the first one to finish.
718 for (QueryQueue::iterator it = pending_queries_.begin();
719 it != pending_queries_.end(); ++it) {
720 if (it->get() == query) {
721 pending_queries_.erase(it);
722 break;
725 for (QueryQueue::iterator it = pending_transfer_queries_.begin();
726 it != pending_transfer_queries_.end(); ++it) {
727 if (it->get() == query) {
728 pending_transfer_queries_.erase(it);
729 break;
732 if (!query->MarkAsCompleted(0)) {
733 return false;
736 return true;
739 bool QueryManager::BeginQuery(Query* query) {
740 DCHECK(query);
741 if (!RemovePendingQuery(query)) {
742 return false;
744 return query->Begin();
747 bool QueryManager::EndQuery(Query* query, base::subtle::Atomic32 submit_count) {
748 DCHECK(query);
749 if (!RemovePendingQuery(query)) {
750 return false;
752 return query->End(submit_count);
755 } // namespace gles2
756 } // namespace gpu