[MacViews] Show comboboxes with a native NSMenu
[chromium-blink-merge.git] / gpu / command_buffer / service / query_manager.cc
bloba228ae06bac3f944d70bb7e5df0b82af96ed9b44
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/error_state.h"
16 #include "gpu/command_buffer/service/feature_info.h"
17 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
18 #include "ui/gl/gl_bindings.h"
19 #include "ui/gl/gl_context.h"
20 #include "ui/gl/gl_fence.h"
21 #include "ui/gl/gpu_timing.h"
23 namespace gpu {
24 namespace gles2 {
26 class AllSamplesPassedQuery : public QueryManager::Query {
27 public:
28 AllSamplesPassedQuery(
29 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
30 bool Begin() override;
31 bool End(base::subtle::Atomic32 submit_count) override;
32 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
33 void Pause() override;
34 void Resume() override;
35 bool Process(bool did_finish) override;
36 void Destroy(bool have_context) override;
38 protected:
39 ~AllSamplesPassedQuery() override;
41 private:
42 // Service side query id.
43 std::vector<GLuint> service_ids_;
46 AllSamplesPassedQuery::AllSamplesPassedQuery(
47 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
48 : Query(manager, target, shm_id, shm_offset) {
49 GLuint service_id = 0;
50 glGenQueries(1, &service_id);
51 DCHECK_NE(0u, service_id);
52 service_ids_.push_back(service_id);
55 bool AllSamplesPassedQuery::Begin() {
56 MarkAsActive();
57 // Delete all but the first one when beginning a new query.
58 if (service_ids_.size() > 1) {
59 glDeleteQueries(service_ids_.size() - 1, &service_ids_[1]);
60 service_ids_.resize(1);
62 BeginQueryHelper(target(), service_ids_.back());
63 return true;
66 bool AllSamplesPassedQuery::End(base::subtle::Atomic32 submit_count) {
67 EndQueryHelper(target());
68 return AddToPendingQueue(submit_count);
71 bool AllSamplesPassedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
72 NOTREACHED();
73 return false;
76 void AllSamplesPassedQuery::Pause() {
77 MarkAsPaused();
78 EndQueryHelper(target());
81 void AllSamplesPassedQuery::Resume() {
82 MarkAsActive();
84 GLuint service_id = 0;
85 glGenQueries(1, &service_id);
86 DCHECK_NE(0u, service_id);
87 service_ids_.push_back(service_id);
88 BeginQueryHelper(target(), service_ids_.back());
91 bool AllSamplesPassedQuery::Process(bool did_finish) {
92 GLuint available = 0;
93 glGetQueryObjectuiv(
94 service_ids_.back(), GL_QUERY_RESULT_AVAILABLE_EXT, &available);
95 if (!available) {
96 return true;
98 for (const GLuint& service_id : service_ids_) {
99 GLuint result = 0;
100 glGetQueryObjectuiv(service_id, GL_QUERY_RESULT_EXT, &result);
101 if (result != 0)
102 return MarkAsCompleted(1);
104 return MarkAsCompleted(0);
107 void AllSamplesPassedQuery::Destroy(bool have_context) {
108 if (have_context && !IsDeleted()) {
109 glDeleteQueries(service_ids_.size(), &service_ids_[0]);
110 service_ids_.clear();
111 MarkAsDeleted();
115 AllSamplesPassedQuery::~AllSamplesPassedQuery() {
118 class CommandsIssuedQuery : public QueryManager::Query {
119 public:
120 CommandsIssuedQuery(
121 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
123 bool Begin() override;
124 bool End(base::subtle::Atomic32 submit_count) override;
125 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
126 void Pause() override;
127 void Resume() override;
128 bool Process(bool did_finish) override;
129 void Destroy(bool have_context) override;
131 protected:
132 ~CommandsIssuedQuery() override;
134 private:
135 base::TimeTicks begin_time_;
138 CommandsIssuedQuery::CommandsIssuedQuery(
139 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
140 : Query(manager, target, shm_id, shm_offset) {
143 bool CommandsIssuedQuery::Begin() {
144 MarkAsActive();
145 begin_time_ = base::TimeTicks::Now();
146 return true;
149 void CommandsIssuedQuery::Pause() {
150 MarkAsPaused();
153 void CommandsIssuedQuery::Resume() {
154 MarkAsActive();
157 bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count) {
158 const base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
159 MarkAsPending(submit_count);
160 return MarkAsCompleted(elapsed.InMicroseconds());
163 bool CommandsIssuedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
164 NOTREACHED();
165 return false;
168 bool CommandsIssuedQuery::Process(bool did_finish) {
169 NOTREACHED();
170 return true;
173 void CommandsIssuedQuery::Destroy(bool /* have_context */) {
174 if (!IsDeleted()) {
175 MarkAsDeleted();
179 CommandsIssuedQuery::~CommandsIssuedQuery() {
182 class CommandLatencyQuery : public QueryManager::Query {
183 public:
184 CommandLatencyQuery(
185 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
187 bool Begin() override;
188 bool End(base::subtle::Atomic32 submit_count) override;
189 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
190 void Pause() override;
191 void Resume() override;
192 bool Process(bool did_finish) override;
193 void Destroy(bool have_context) override;
195 protected:
196 ~CommandLatencyQuery() override;
199 CommandLatencyQuery::CommandLatencyQuery(
200 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
201 : Query(manager, target, shm_id, shm_offset) {
204 bool CommandLatencyQuery::Begin() {
205 MarkAsActive();
206 return true;
209 void CommandLatencyQuery::Pause() {
210 MarkAsPaused();
213 void CommandLatencyQuery::Resume() {
214 MarkAsActive();
217 bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count) {
218 base::TimeDelta now = base::TimeTicks::Now() - base::TimeTicks();
219 MarkAsPending(submit_count);
220 return MarkAsCompleted(now.InMicroseconds());
223 bool CommandLatencyQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
224 NOTREACHED();
225 return false;
228 bool CommandLatencyQuery::Process(bool did_finish) {
229 NOTREACHED();
230 return true;
233 void CommandLatencyQuery::Destroy(bool /* have_context */) {
234 if (!IsDeleted()) {
235 MarkAsDeleted();
239 CommandLatencyQuery::~CommandLatencyQuery() {
243 class AsyncReadPixelsCompletedQuery
244 : public QueryManager::Query,
245 public base::SupportsWeakPtr<AsyncReadPixelsCompletedQuery> {
246 public:
247 AsyncReadPixelsCompletedQuery(
248 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
250 bool Begin() override;
251 bool End(base::subtle::Atomic32 submit_count) override;
252 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
253 void Pause() override;
254 void Resume() override;
255 bool Process(bool did_finish) override;
256 void Destroy(bool have_context) override;
258 protected:
259 void Complete();
260 ~AsyncReadPixelsCompletedQuery() override;
262 private:
263 bool complete_result_;
266 AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
267 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
268 : Query(manager, target, shm_id, shm_offset),
269 complete_result_(false) {
272 bool AsyncReadPixelsCompletedQuery::Begin() {
273 MarkAsActive();
274 return true;
277 void AsyncReadPixelsCompletedQuery::Pause() {
278 MarkAsPaused();
281 void AsyncReadPixelsCompletedQuery::Resume() {
282 MarkAsActive();
285 bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
286 if (!AddToPendingQueue(submit_count)) {
287 return false;
289 manager()->decoder()->WaitForReadPixels(
290 base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
291 AsWeakPtr()));
293 return Process(false);
296 bool AsyncReadPixelsCompletedQuery::QueryCounter(
297 base::subtle::Atomic32 submit_count) {
298 NOTREACHED();
299 return false;
302 void AsyncReadPixelsCompletedQuery::Complete() {
303 complete_result_ = MarkAsCompleted(1);
306 bool AsyncReadPixelsCompletedQuery::Process(bool did_finish) {
307 return !IsFinished() || complete_result_;
310 void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
311 if (!IsDeleted()) {
312 MarkAsDeleted();
316 AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
320 class GetErrorQuery : public QueryManager::Query {
321 public:
322 GetErrorQuery(
323 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
325 bool Begin() override;
326 bool End(base::subtle::Atomic32 submit_count) override;
327 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
328 void Pause() override;
329 void Resume() override;
330 bool Process(bool did_finish) override;
331 void Destroy(bool have_context) override;
333 protected:
334 ~GetErrorQuery() override;
336 private:
339 GetErrorQuery::GetErrorQuery(
340 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
341 : Query(manager, target, shm_id, shm_offset) {
344 bool GetErrorQuery::Begin() {
345 MarkAsActive();
346 return true;
349 void GetErrorQuery::Pause() {
350 MarkAsPaused();
353 void GetErrorQuery::Resume() {
354 MarkAsActive();
357 bool GetErrorQuery::End(base::subtle::Atomic32 submit_count) {
358 MarkAsPending(submit_count);
359 return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
362 bool GetErrorQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
363 NOTREACHED();
364 return false;
367 bool GetErrorQuery::Process(bool did_finish) {
368 NOTREACHED();
369 return true;
372 void GetErrorQuery::Destroy(bool /* have_context */) {
373 if (!IsDeleted()) {
374 MarkAsDeleted();
378 GetErrorQuery::~GetErrorQuery() {
381 class CommandsCompletedQuery : public QueryManager::Query {
382 public:
383 CommandsCompletedQuery(QueryManager* manager,
384 GLenum target,
385 int32 shm_id,
386 uint32 shm_offset);
388 // Overridden from QueryManager::Query:
389 bool Begin() override;
390 bool End(base::subtle::Atomic32 submit_count) override;
391 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
392 void Pause() override;
393 void Resume() override;
394 bool Process(bool did_finish) override;
395 void Destroy(bool have_context) override;
397 protected:
398 ~CommandsCompletedQuery() override;
400 private:
401 scoped_ptr<gfx::GLFence> fence_;
402 base::TimeTicks begin_time_;
405 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager,
406 GLenum target,
407 int32 shm_id,
408 uint32 shm_offset)
409 : Query(manager, target, shm_id, shm_offset) {}
411 bool CommandsCompletedQuery::Begin() {
412 MarkAsActive();
413 begin_time_ = base::TimeTicks::Now();
414 return true;
417 void CommandsCompletedQuery::Pause() {
418 MarkAsPaused();
421 void CommandsCompletedQuery::Resume() {
422 MarkAsActive();
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::QueryCounter(base::subtle::Atomic32 submit_count) {
432 NOTREACHED();
433 return false;
436 bool CommandsCompletedQuery::Process(bool did_finish) {
437 // Note: |did_finish| guarantees that the GPU has passed the fence but
438 // we cannot assume that GLFence::HasCompleted() will return true yet as
439 // that's not guaranteed by all GLFence implementations.
440 if (!did_finish && fence_ && !fence_->HasCompleted())
441 return true;
443 const base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
444 return MarkAsCompleted(elapsed.InMicroseconds());
447 void CommandsCompletedQuery::Destroy(bool have_context) {
448 if (have_context && !IsDeleted()) {
449 fence_.reset();
450 MarkAsDeleted();
454 CommandsCompletedQuery::~CommandsCompletedQuery() {}
456 class TimeElapsedQuery : public QueryManager::Query {
457 public:
458 TimeElapsedQuery(QueryManager* manager,
459 GLenum target,
460 int32 shm_id,
461 uint32 shm_offset);
463 // Overridden from QueryManager::Query:
464 bool Begin() override;
465 bool End(base::subtle::Atomic32 submit_count) override;
466 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
467 void Pause() override;
468 void Resume() override;
469 bool Process(bool did_finish) override;
470 void Destroy(bool have_context) override;
472 protected:
473 ~TimeElapsedQuery() override;
475 private:
476 scoped_ptr<gfx::GPUTimer> gpu_timer_;
479 TimeElapsedQuery::TimeElapsedQuery(QueryManager* manager,
480 GLenum target,
481 int32 shm_id,
482 uint32 shm_offset)
483 : Query(manager, target, shm_id, shm_offset),
484 gpu_timer_(manager->CreateGPUTimer(true)) {
487 bool TimeElapsedQuery::Begin() {
488 // Reset the disjoint value before the query begins if it is safe.
489 SafelyResetDisjointValue();
490 MarkAsActive();
491 gpu_timer_->Start();
492 return true;
495 bool TimeElapsedQuery::End(base::subtle::Atomic32 submit_count) {
496 gpu_timer_->End();
497 return AddToPendingQueue(submit_count);
500 bool TimeElapsedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
501 NOTREACHED();
502 return false;
505 void TimeElapsedQuery::Pause() {
506 MarkAsPaused();
509 void TimeElapsedQuery::Resume() {
510 MarkAsActive();
513 bool TimeElapsedQuery::Process(bool did_finish) {
514 if (!gpu_timer_->IsAvailable())
515 return true;
517 // Make sure disjoint value is up to date. This disjoint check is the only one
518 // that needs to be done to validate that this query is valid. If a disjoint
519 // occurs before the client checks the query value we will just hide the
520 // disjoint state since it did not affect this query.
521 UpdateDisjointValue();
523 const uint64_t nano_seconds = gpu_timer_->GetDeltaElapsed() *
524 base::Time::kNanosecondsPerMicrosecond;
525 return MarkAsCompleted(nano_seconds);
528 void TimeElapsedQuery::Destroy(bool have_context) {
529 gpu_timer_->Destroy(have_context);
532 TimeElapsedQuery::~TimeElapsedQuery() {}
534 class TimeStampQuery : public QueryManager::Query {
535 public:
536 TimeStampQuery(QueryManager* manager,
537 GLenum target,
538 int32 shm_id,
539 uint32 shm_offset);
541 // Overridden from QueryManager::Query:
542 bool Begin() override;
543 bool End(base::subtle::Atomic32 submit_count) override;
544 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
545 void Pause() override;
546 void Resume() override;
547 bool Process(bool did_finish) override;
548 void Destroy(bool have_context) override;
550 protected:
551 ~TimeStampQuery() override;
553 private:
554 scoped_ptr<gfx::GPUTimer> gpu_timer_;
557 TimeStampQuery::TimeStampQuery(QueryManager* manager,
558 GLenum target,
559 int32 shm_id,
560 uint32 shm_offset)
561 : Query(manager, target, shm_id, shm_offset),
562 gpu_timer_(manager->CreateGPUTimer(false)) {}
564 bool TimeStampQuery::Begin() {
565 NOTREACHED();
566 return false;
569 bool TimeStampQuery::End(base::subtle::Atomic32 submit_count) {
570 NOTREACHED();
571 return false;
574 void TimeStampQuery::Pause() {
575 MarkAsPaused();
578 void TimeStampQuery::Resume() {
579 MarkAsActive();
582 bool TimeStampQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
583 // Reset the disjoint value before the query begins if it is safe.
584 SafelyResetDisjointValue();
585 MarkAsActive();
586 // After a timestamp has begun, we will want to continually detect
587 // the disjoint value every frame until the context is destroyed.
588 BeginContinualDisjointUpdate();
590 gpu_timer_->QueryTimeStamp();
591 return AddToPendingQueue(submit_count);
594 bool TimeStampQuery::Process(bool did_finish) {
595 if (!gpu_timer_->IsAvailable())
596 return true;
598 // Make sure disjoint value is up to date. This disjoint check is the only one
599 // that needs to be done to validate that this query is valid. If a disjoint
600 // occurs before the client checks the query value we will just hide the
601 // disjoint state since it did not affect this query.
602 UpdateDisjointValue();
604 int64_t start = 0;
605 int64_t end = 0;
606 gpu_timer_->GetStartEndTimestamps(&start, &end);
607 DCHECK(start == end);
609 const uint64_t nano_seconds = start * base::Time::kNanosecondsPerMicrosecond;
610 return MarkAsCompleted(nano_seconds);
613 void TimeStampQuery::Destroy(bool have_context) {
614 if (gpu_timer_.get()) {
615 gpu_timer_->Destroy(have_context);
616 gpu_timer_.reset();
620 TimeStampQuery::~TimeStampQuery() {}
622 QueryManager::QueryManager(
623 GLES2Decoder* decoder,
624 FeatureInfo* feature_info)
625 : decoder_(decoder),
626 use_arb_occlusion_query2_for_occlusion_query_boolean_(
627 feature_info->feature_flags(
628 ).use_arb_occlusion_query2_for_occlusion_query_boolean),
629 use_arb_occlusion_query_for_occlusion_query_boolean_(
630 feature_info->feature_flags(
631 ).use_arb_occlusion_query_for_occlusion_query_boolean),
632 update_disjoints_continually_(false),
633 disjoint_notify_shm_id_(-1),
634 disjoint_notify_shm_offset_(0),
635 disjoints_notified_(0),
636 query_count_(0) {
637 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_ &&
638 use_arb_occlusion_query2_for_occlusion_query_boolean_));
639 DCHECK(decoder);
640 gfx::GLContext* context = decoder_->GetGLContext();
641 if (context) {
642 gpu_timing_client_ = context->CreateGPUTimingClient();
643 } else {
644 gpu_timing_client_ = new gfx::GPUTimingClient();
648 QueryManager::~QueryManager() {
649 DCHECK(queries_.empty());
651 // If this triggers, that means something is keeping a reference to
652 // a Query belonging to this.
653 CHECK_EQ(query_count_, 0u);
656 void QueryManager::Destroy(bool have_context) {
657 active_queries_.clear();
658 pending_queries_.clear();
659 pending_transfer_queries_.clear();
660 active_queries_.clear();
661 while (!queries_.empty()) {
662 Query* query = queries_.begin()->second.get();
663 query->Destroy(have_context);
664 queries_.erase(queries_.begin());
668 void QueryManager::SetDisjointSync(int32 shm_id, uint32 shm_offset) {
669 DCHECK(disjoint_notify_shm_id_ == -1);
670 DCHECK(shm_id != -1);
672 DisjointValueSync* sync = decoder_->GetSharedMemoryAs<DisjointValueSync*>(
673 shm_id, shm_offset, sizeof(*sync));
674 DCHECK(sync);
675 sync->Reset();
676 disjoints_notified_ = 0;
678 disjoint_notify_shm_id_ = shm_id;
679 disjoint_notify_shm_offset_ = shm_offset;
682 QueryManager::Query* QueryManager::CreateQuery(
683 GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) {
684 scoped_refptr<Query> query;
685 switch (target) {
686 case GL_COMMANDS_ISSUED_CHROMIUM:
687 query = new CommandsIssuedQuery(this, target, shm_id, shm_offset);
688 break;
689 case GL_LATENCY_QUERY_CHROMIUM:
690 query = new CommandLatencyQuery(this, target, shm_id, shm_offset);
691 break;
692 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
693 query = new AsyncReadPixelsCompletedQuery(
694 this, target, shm_id, shm_offset);
695 break;
696 case GL_GET_ERROR_QUERY_CHROMIUM:
697 query = new GetErrorQuery(this, target, shm_id, shm_offset);
698 break;
699 case GL_COMMANDS_COMPLETED_CHROMIUM:
700 query = new CommandsCompletedQuery(this, target, shm_id, shm_offset);
701 break;
702 case GL_TIME_ELAPSED:
703 query = new TimeElapsedQuery(this, target, shm_id, shm_offset);
704 break;
705 case GL_TIMESTAMP:
706 query = new TimeStampQuery(this, target, shm_id, shm_offset);
707 break;
708 default: {
709 query = new AllSamplesPassedQuery(this, target, shm_id, shm_offset);
710 break;
713 std::pair<QueryMap::iterator, bool> result =
714 queries_.insert(std::make_pair(client_id, query));
715 DCHECK(result.second);
716 return query.get();
719 scoped_ptr<gfx::GPUTimer> QueryManager::CreateGPUTimer(bool elapsed_time) {
720 return gpu_timing_client_->CreateGPUTimer(elapsed_time);
723 bool QueryManager::GPUTimingAvailable() {
724 return gpu_timing_client_->IsAvailable();
727 void QueryManager::GenQueries(GLsizei n, const GLuint* queries) {
728 DCHECK_GE(n, 0);
729 for (GLsizei i = 0; i < n; ++i) {
730 generated_query_ids_.insert(queries[i]);
734 bool QueryManager::IsValidQuery(GLuint id) {
735 GeneratedQueryIds::iterator it = generated_query_ids_.find(id);
736 return it != generated_query_ids_.end();
739 QueryManager::Query* QueryManager::GetQuery(GLuint client_id) {
740 QueryMap::iterator it = queries_.find(client_id);
741 return it != queries_.end() ? it->second.get() : nullptr;
744 QueryManager::Query* QueryManager::GetActiveQuery(GLenum target) {
745 ActiveQueryMap::iterator it = active_queries_.find(target);
746 return it != active_queries_.end() ? it->second.get() : nullptr;
749 void QueryManager::RemoveQuery(GLuint client_id) {
750 QueryMap::iterator it = queries_.find(client_id);
751 if (it != queries_.end()) {
752 Query* query = it->second.get();
754 // Remove from active query map if it is active.
755 ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
756 bool is_active = (active_it != active_queries_.end() &&
757 query == active_it->second.get());
758 DCHECK(is_active == query->IsActive());
759 if (is_active)
760 active_queries_.erase(active_it);
762 query->Destroy(true);
763 RemovePendingQuery(query);
764 query->MarkAsDeleted();
765 queries_.erase(it);
767 generated_query_ids_.erase(client_id);
770 void QueryManager::StartTracking(QueryManager::Query* /* query */) {
771 ++query_count_;
774 void QueryManager::StopTracking(QueryManager::Query* /* query */) {
775 --query_count_;
778 GLenum QueryManager::AdjustTargetForEmulation(GLenum target) {
779 switch (target) {
780 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
781 case GL_ANY_SAMPLES_PASSED_EXT:
782 if (use_arb_occlusion_query2_for_occlusion_query_boolean_) {
783 // ARB_occlusion_query2 does not have a
784 // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
785 // target.
786 target = GL_ANY_SAMPLES_PASSED_EXT;
787 } else if (use_arb_occlusion_query_for_occlusion_query_boolean_) {
788 // ARB_occlusion_query does not have a
789 // GL_ANY_SAMPLES_PASSED_EXT
790 // target.
791 target = GL_SAMPLES_PASSED_ARB;
793 break;
794 default:
795 break;
797 return target;
800 void QueryManager::BeginQueryHelper(GLenum target, GLuint id) {
801 target = AdjustTargetForEmulation(target);
802 glBeginQuery(target, id);
805 void QueryManager::EndQueryHelper(GLenum target) {
806 target = AdjustTargetForEmulation(target);
807 glEndQuery(target);
810 void QueryManager::UpdateDisjointValue() {
811 if (disjoint_notify_shm_id_ != -1) {
812 if (gpu_timing_client_->CheckAndResetTimerErrors()) {
813 disjoints_notified_++;
815 DisjointValueSync* sync = decoder_->GetSharedMemoryAs<DisjointValueSync*>(
816 disjoint_notify_shm_id_, disjoint_notify_shm_offset_, sizeof(*sync));
817 if (!sync) {
818 // Shared memory does not seem to be valid, ignore the shm id/offset.
819 disjoint_notify_shm_id_ = -1;
820 disjoint_notify_shm_offset_ = 0;
821 } else {
822 sync->SetDisjointCount(disjoints_notified_);
828 void QueryManager::SafelyResetDisjointValue() {
829 // It is only safe to reset the disjoint value is there is no active
830 // elapsed timer and we are not continually updating the disjoint value.
831 if (!update_disjoints_continually_ && !GetActiveQuery(GL_TIME_ELAPSED)) {
832 // Reset the error state without storing the result.
833 gpu_timing_client_->CheckAndResetTimerErrors();
837 QueryManager::Query::Query(
838 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
839 : manager_(manager),
840 target_(target),
841 shm_id_(shm_id),
842 shm_offset_(shm_offset),
843 submit_count_(0),
844 query_state_(kQueryState_Initialize),
845 deleted_(false) {
846 DCHECK(manager);
847 manager_->StartTracking(this);
850 void QueryManager::Query::RunCallbacks() {
851 for (size_t i = 0; i < callbacks_.size(); i++) {
852 callbacks_[i].Run();
854 callbacks_.clear();
857 void QueryManager::Query::AddCallback(base::Closure callback) {
858 if (query_state_ == kQueryState_Pending) {
859 callbacks_.push_back(callback);
860 } else {
861 callback.Run();
865 QueryManager::Query::~Query() {
866 // The query is getting deleted, either by the client or
867 // because the context was lost. Call any outstanding
868 // callbacks to avoid leaks.
869 RunCallbacks();
870 if (manager_) {
871 manager_->StopTracking(this);
872 manager_ = NULL;
876 bool QueryManager::Query::MarkAsCompleted(uint64 result) {
877 UnmarkAsPending();
878 QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>(
879 shm_id_, shm_offset_, sizeof(*sync));
880 if (!sync) {
881 return false;
884 sync->result = result;
885 base::subtle::Release_Store(&sync->process_count, submit_count_);
887 return true;
890 bool QueryManager::ProcessPendingQueries(bool did_finish) {
891 while (!pending_queries_.empty()) {
892 Query* query = pending_queries_.front().get();
893 if (!query->Process(did_finish)) {
894 return false;
896 if (query->IsPending()) {
897 break;
899 query->RunCallbacks();
900 pending_queries_.pop_front();
902 // If glFinish() has been called, all of our queries should be completed.
903 DCHECK(!did_finish || pending_queries_.empty());
905 return true;
908 bool QueryManager::HavePendingQueries() {
909 return !pending_queries_.empty();
912 bool QueryManager::ProcessPendingTransferQueries() {
913 while (!pending_transfer_queries_.empty()) {
914 Query* query = pending_transfer_queries_.front().get();
915 if (!query->Process(false)) {
916 return false;
918 if (query->IsPending()) {
919 break;
921 query->RunCallbacks();
922 pending_transfer_queries_.pop_front();
925 return true;
928 bool QueryManager::HavePendingTransferQueries() {
929 return !pending_transfer_queries_.empty();
932 void QueryManager::ProcessFrameBeginUpdates() {
933 if (update_disjoints_continually_)
934 UpdateDisjointValue();
937 bool QueryManager::AddPendingQuery(Query* query,
938 base::subtle::Atomic32 submit_count) {
939 DCHECK(query);
940 DCHECK(!query->IsDeleted());
941 if (!RemovePendingQuery(query)) {
942 return false;
944 query->MarkAsPending(submit_count);
945 pending_queries_.push_back(query);
946 return true;
949 bool QueryManager::AddPendingTransferQuery(
950 Query* query,
951 base::subtle::Atomic32 submit_count) {
952 DCHECK(query);
953 DCHECK(!query->IsDeleted());
954 if (!RemovePendingQuery(query)) {
955 return false;
957 query->MarkAsPending(submit_count);
958 pending_transfer_queries_.push_back(query);
959 return true;
962 bool QueryManager::RemovePendingQuery(Query* query) {
963 DCHECK(query);
964 if (query->IsPending()) {
965 // TODO(gman): Speed this up if this is a common operation. This would only
966 // happen if you do being/end begin/end on the same query without waiting
967 // for the first one to finish.
968 for (QueryQueue::iterator it = pending_queries_.begin();
969 it != pending_queries_.end(); ++it) {
970 if (it->get() == query) {
971 pending_queries_.erase(it);
972 break;
975 for (QueryQueue::iterator it = pending_transfer_queries_.begin();
976 it != pending_transfer_queries_.end(); ++it) {
977 if (it->get() == query) {
978 pending_transfer_queries_.erase(it);
979 break;
982 if (!query->MarkAsCompleted(0)) {
983 return false;
986 return true;
989 bool QueryManager::BeginQuery(Query* query) {
990 DCHECK(query);
991 if (!RemovePendingQuery(query)) {
992 return false;
994 if (query->Begin()) {
995 active_queries_[query->target()] = query;
996 return true;
999 return false;
1002 bool QueryManager::EndQuery(Query* query, base::subtle::Atomic32 submit_count) {
1003 DCHECK(query);
1004 if (!RemovePendingQuery(query)) {
1005 return false;
1008 // Remove from active query map if it is active.
1009 ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
1010 DCHECK(active_it != active_queries_.end());
1011 DCHECK(query == active_it->second.get());
1012 active_queries_.erase(active_it);
1014 return query->End(submit_count);
1017 bool QueryManager::QueryCounter(
1018 Query* query, base::subtle::Atomic32 submit_count) {
1019 DCHECK(query);
1020 return query->QueryCounter(submit_count);
1023 void QueryManager::PauseQueries() {
1024 for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
1025 if (it.second->IsActive()) {
1026 it.second->Pause();
1027 DCHECK(it.second->IsPaused());
1032 void QueryManager::ResumeQueries() {
1033 for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
1034 if (it.second->IsPaused()) {
1035 it.second->Resume();
1036 DCHECK(it.second->IsActive());
1041 } // namespace gles2
1042 } // namespace gpu