Roll src/third_party/skia d32087a:1052f51
[chromium-blink-merge.git] / gpu / command_buffer / service / query_manager.cc
blob6c1e2628a7159e84b5c67a0e3cc862e0f4fd320c
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 AbstractIntegerQuery : public QueryManager::Query {
27 public:
28 AbstractIntegerQuery(
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 void Destroy(bool have_context) override;
37 protected:
38 ~AbstractIntegerQuery() override;
39 bool AreAllResultsAvailable();
41 // Service side query ids.
42 std::vector<GLuint> service_ids_;
45 AbstractIntegerQuery::AbstractIntegerQuery(
46 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
47 : Query(manager, target, shm_id, shm_offset) {
48 GLuint service_id = 0;
49 glGenQueries(1, &service_id);
50 DCHECK_NE(0u, service_id);
51 service_ids_.push_back(service_id);
54 bool AbstractIntegerQuery::Begin() {
55 MarkAsActive();
56 // Delete all but the first one when beginning a new query.
57 if (service_ids_.size() > 1) {
58 glDeleteQueries(service_ids_.size() - 1, &service_ids_[1]);
59 service_ids_.resize(1);
61 BeginQueryHelper(target(), service_ids_.back());
62 return true;
65 bool AbstractIntegerQuery::End(base::subtle::Atomic32 submit_count) {
66 EndQueryHelper(target());
67 return AddToPendingQueue(submit_count);
70 bool AbstractIntegerQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
71 NOTREACHED();
72 return false;
75 void AbstractIntegerQuery::Pause() {
76 MarkAsPaused();
77 EndQueryHelper(target());
80 void AbstractIntegerQuery::Resume() {
81 MarkAsActive();
83 GLuint service_id = 0;
84 glGenQueries(1, &service_id);
85 DCHECK_NE(0u, service_id);
86 service_ids_.push_back(service_id);
87 BeginQueryHelper(target(), service_ids_.back());
90 void AbstractIntegerQuery::Destroy(bool have_context) {
91 if (have_context && !IsDeleted()) {
92 glDeleteQueries(service_ids_.size(), &service_ids_[0]);
93 service_ids_.clear();
94 MarkAsDeleted();
98 AbstractIntegerQuery::~AbstractIntegerQuery() {
101 bool AbstractIntegerQuery::AreAllResultsAvailable() {
102 GLuint available = 0;
103 glGetQueryObjectuiv(
104 service_ids_.back(), GL_QUERY_RESULT_AVAILABLE_EXT, &available);
105 return !!available;
108 class BooleanQuery : public AbstractIntegerQuery {
109 public:
110 BooleanQuery(
111 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
112 bool Process(bool did_finish) override;
114 protected:
115 ~BooleanQuery() override;
118 BooleanQuery::BooleanQuery(
119 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
120 : AbstractIntegerQuery(manager, target, shm_id, shm_offset) {
123 BooleanQuery::~BooleanQuery() {
126 bool BooleanQuery::Process(bool did_finish) {
127 if (!AreAllResultsAvailable()) {
128 // Must return true to avoid generating an error at the command
129 // buffer level.
130 return true;
132 for (const GLuint& service_id : service_ids_) {
133 GLuint result = 0;
134 glGetQueryObjectuiv(service_id, GL_QUERY_RESULT_EXT, &result);
135 if (result != 0)
136 return MarkAsCompleted(1);
138 return MarkAsCompleted(0);
141 class SummedIntegerQuery : public AbstractIntegerQuery {
142 public:
143 SummedIntegerQuery(
144 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
145 bool Process(bool did_finish) override;
147 protected:
148 ~SummedIntegerQuery() override;
151 SummedIntegerQuery::SummedIntegerQuery(
152 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
153 : AbstractIntegerQuery(manager, target, shm_id, shm_offset) {
156 SummedIntegerQuery::~SummedIntegerQuery() {
159 bool SummedIntegerQuery::Process(bool did_finish) {
160 if (!AreAllResultsAvailable()) {
161 // Must return true to avoid generating an error at the command
162 // buffer level.
163 return true;
165 GLuint summed_result = 0;
166 for (const GLuint& service_id : service_ids_) {
167 GLuint result = 0;
168 glGetQueryObjectuiv(service_id, GL_QUERY_RESULT_EXT, &result);
169 summed_result += result;
171 return MarkAsCompleted(summed_result);
174 class CommandsIssuedQuery : public QueryManager::Query {
175 public:
176 CommandsIssuedQuery(
177 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
179 bool Begin() override;
180 bool End(base::subtle::Atomic32 submit_count) override;
181 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
182 void Pause() override;
183 void Resume() override;
184 bool Process(bool did_finish) override;
185 void Destroy(bool have_context) override;
187 protected:
188 ~CommandsIssuedQuery() override;
190 private:
191 base::TimeTicks begin_time_;
194 CommandsIssuedQuery::CommandsIssuedQuery(
195 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
196 : Query(manager, target, shm_id, shm_offset) {
199 bool CommandsIssuedQuery::Begin() {
200 MarkAsActive();
201 begin_time_ = base::TimeTicks::Now();
202 return true;
205 void CommandsIssuedQuery::Pause() {
206 MarkAsPaused();
209 void CommandsIssuedQuery::Resume() {
210 MarkAsActive();
213 bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count) {
214 const base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
215 MarkAsPending(submit_count);
216 return MarkAsCompleted(elapsed.InMicroseconds());
219 bool CommandsIssuedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
220 NOTREACHED();
221 return false;
224 bool CommandsIssuedQuery::Process(bool did_finish) {
225 NOTREACHED();
226 return true;
229 void CommandsIssuedQuery::Destroy(bool /* have_context */) {
230 if (!IsDeleted()) {
231 MarkAsDeleted();
235 CommandsIssuedQuery::~CommandsIssuedQuery() {
238 class CommandLatencyQuery : public QueryManager::Query {
239 public:
240 CommandLatencyQuery(
241 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
243 bool Begin() override;
244 bool End(base::subtle::Atomic32 submit_count) override;
245 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
246 void Pause() override;
247 void Resume() override;
248 bool Process(bool did_finish) override;
249 void Destroy(bool have_context) override;
251 protected:
252 ~CommandLatencyQuery() override;
255 CommandLatencyQuery::CommandLatencyQuery(
256 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
257 : Query(manager, target, shm_id, shm_offset) {
260 bool CommandLatencyQuery::Begin() {
261 MarkAsActive();
262 return true;
265 void CommandLatencyQuery::Pause() {
266 MarkAsPaused();
269 void CommandLatencyQuery::Resume() {
270 MarkAsActive();
273 bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count) {
274 base::TimeDelta now = base::TimeTicks::Now() - base::TimeTicks();
275 MarkAsPending(submit_count);
276 return MarkAsCompleted(now.InMicroseconds());
279 bool CommandLatencyQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
280 NOTREACHED();
281 return false;
284 bool CommandLatencyQuery::Process(bool did_finish) {
285 NOTREACHED();
286 return true;
289 void CommandLatencyQuery::Destroy(bool /* have_context */) {
290 if (!IsDeleted()) {
291 MarkAsDeleted();
295 CommandLatencyQuery::~CommandLatencyQuery() {
299 class AsyncReadPixelsCompletedQuery
300 : public QueryManager::Query,
301 public base::SupportsWeakPtr<AsyncReadPixelsCompletedQuery> {
302 public:
303 AsyncReadPixelsCompletedQuery(
304 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
306 bool Begin() override;
307 bool End(base::subtle::Atomic32 submit_count) override;
308 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
309 void Pause() override;
310 void Resume() override;
311 bool Process(bool did_finish) override;
312 void Destroy(bool have_context) override;
314 protected:
315 void Complete();
316 ~AsyncReadPixelsCompletedQuery() override;
318 private:
319 bool complete_result_;
322 AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
323 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
324 : Query(manager, target, shm_id, shm_offset),
325 complete_result_(false) {
328 bool AsyncReadPixelsCompletedQuery::Begin() {
329 MarkAsActive();
330 return true;
333 void AsyncReadPixelsCompletedQuery::Pause() {
334 MarkAsPaused();
337 void AsyncReadPixelsCompletedQuery::Resume() {
338 MarkAsActive();
341 bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
342 if (!AddToPendingQueue(submit_count)) {
343 return false;
345 manager()->decoder()->WaitForReadPixels(
346 base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
347 AsWeakPtr()));
349 return Process(false);
352 bool AsyncReadPixelsCompletedQuery::QueryCounter(
353 base::subtle::Atomic32 submit_count) {
354 NOTREACHED();
355 return false;
358 void AsyncReadPixelsCompletedQuery::Complete() {
359 complete_result_ = MarkAsCompleted(1);
362 bool AsyncReadPixelsCompletedQuery::Process(bool did_finish) {
363 return !IsFinished() || complete_result_;
366 void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
367 if (!IsDeleted()) {
368 MarkAsDeleted();
372 AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
376 class GetErrorQuery : public QueryManager::Query {
377 public:
378 GetErrorQuery(
379 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
381 bool Begin() override;
382 bool End(base::subtle::Atomic32 submit_count) override;
383 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
384 void Pause() override;
385 void Resume() override;
386 bool Process(bool did_finish) override;
387 void Destroy(bool have_context) override;
389 protected:
390 ~GetErrorQuery() override;
392 private:
395 GetErrorQuery::GetErrorQuery(
396 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
397 : Query(manager, target, shm_id, shm_offset) {
400 bool GetErrorQuery::Begin() {
401 MarkAsActive();
402 return true;
405 void GetErrorQuery::Pause() {
406 MarkAsPaused();
409 void GetErrorQuery::Resume() {
410 MarkAsActive();
413 bool GetErrorQuery::End(base::subtle::Atomic32 submit_count) {
414 MarkAsPending(submit_count);
415 return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
418 bool GetErrorQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
419 NOTREACHED();
420 return false;
423 bool GetErrorQuery::Process(bool did_finish) {
424 NOTREACHED();
425 return true;
428 void GetErrorQuery::Destroy(bool /* have_context */) {
429 if (!IsDeleted()) {
430 MarkAsDeleted();
434 GetErrorQuery::~GetErrorQuery() {
437 class CommandsCompletedQuery : public QueryManager::Query {
438 public:
439 CommandsCompletedQuery(QueryManager* manager,
440 GLenum target,
441 int32 shm_id,
442 uint32 shm_offset);
444 // Overridden from QueryManager::Query:
445 bool Begin() override;
446 bool End(base::subtle::Atomic32 submit_count) override;
447 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
448 void Pause() override;
449 void Resume() override;
450 bool Process(bool did_finish) override;
451 void Destroy(bool have_context) override;
453 protected:
454 ~CommandsCompletedQuery() override;
456 private:
457 scoped_ptr<gfx::GLFence> fence_;
458 base::TimeTicks begin_time_;
461 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager,
462 GLenum target,
463 int32 shm_id,
464 uint32 shm_offset)
465 : Query(manager, target, shm_id, shm_offset) {}
467 bool CommandsCompletedQuery::Begin() {
468 MarkAsActive();
469 begin_time_ = base::TimeTicks::Now();
470 return true;
473 void CommandsCompletedQuery::Pause() {
474 MarkAsPaused();
477 void CommandsCompletedQuery::Resume() {
478 MarkAsActive();
481 bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
482 fence_.reset(gfx::GLFence::Create());
483 DCHECK(fence_);
484 return AddToPendingQueue(submit_count);
487 bool CommandsCompletedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
488 NOTREACHED();
489 return false;
492 bool CommandsCompletedQuery::Process(bool did_finish) {
493 // Note: |did_finish| guarantees that the GPU has passed the fence but
494 // we cannot assume that GLFence::HasCompleted() will return true yet as
495 // that's not guaranteed by all GLFence implementations.
496 if (!did_finish && fence_ && !fence_->HasCompleted())
497 return true;
499 const base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
500 return MarkAsCompleted(elapsed.InMicroseconds());
503 void CommandsCompletedQuery::Destroy(bool have_context) {
504 if (have_context && !IsDeleted()) {
505 fence_.reset();
506 MarkAsDeleted();
510 CommandsCompletedQuery::~CommandsCompletedQuery() {}
512 class TimeElapsedQuery : public QueryManager::Query {
513 public:
514 TimeElapsedQuery(QueryManager* manager,
515 GLenum target,
516 int32 shm_id,
517 uint32 shm_offset);
519 // Overridden from QueryManager::Query:
520 bool Begin() override;
521 bool End(base::subtle::Atomic32 submit_count) override;
522 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
523 void Pause() override;
524 void Resume() override;
525 bool Process(bool did_finish) override;
526 void Destroy(bool have_context) override;
528 protected:
529 ~TimeElapsedQuery() override;
531 private:
532 scoped_ptr<gfx::GPUTimer> gpu_timer_;
535 TimeElapsedQuery::TimeElapsedQuery(QueryManager* manager,
536 GLenum target,
537 int32 shm_id,
538 uint32 shm_offset)
539 : Query(manager, target, shm_id, shm_offset),
540 gpu_timer_(manager->CreateGPUTimer(true)) {
543 bool TimeElapsedQuery::Begin() {
544 // Reset the disjoint value before the query begins if it is safe.
545 SafelyResetDisjointValue();
546 MarkAsActive();
547 gpu_timer_->Start();
548 return true;
551 bool TimeElapsedQuery::End(base::subtle::Atomic32 submit_count) {
552 gpu_timer_->End();
553 return AddToPendingQueue(submit_count);
556 bool TimeElapsedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
557 NOTREACHED();
558 return false;
561 void TimeElapsedQuery::Pause() {
562 MarkAsPaused();
565 void TimeElapsedQuery::Resume() {
566 MarkAsActive();
569 bool TimeElapsedQuery::Process(bool did_finish) {
570 if (!gpu_timer_->IsAvailable())
571 return true;
573 // Make sure disjoint value is up to date. This disjoint check is the only one
574 // that needs to be done to validate that this query is valid. If a disjoint
575 // occurs before the client checks the query value we will just hide the
576 // disjoint state since it did not affect this query.
577 UpdateDisjointValue();
579 const uint64_t nano_seconds = gpu_timer_->GetDeltaElapsed() *
580 base::Time::kNanosecondsPerMicrosecond;
581 return MarkAsCompleted(nano_seconds);
584 void TimeElapsedQuery::Destroy(bool have_context) {
585 gpu_timer_->Destroy(have_context);
588 TimeElapsedQuery::~TimeElapsedQuery() {}
590 class TimeStampQuery : public QueryManager::Query {
591 public:
592 TimeStampQuery(QueryManager* manager,
593 GLenum target,
594 int32 shm_id,
595 uint32 shm_offset);
597 // Overridden from QueryManager::Query:
598 bool Begin() override;
599 bool End(base::subtle::Atomic32 submit_count) override;
600 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
601 void Pause() override;
602 void Resume() override;
603 bool Process(bool did_finish) override;
604 void Destroy(bool have_context) override;
606 protected:
607 ~TimeStampQuery() override;
609 private:
610 scoped_ptr<gfx::GPUTimer> gpu_timer_;
613 TimeStampQuery::TimeStampQuery(QueryManager* manager,
614 GLenum target,
615 int32 shm_id,
616 uint32 shm_offset)
617 : Query(manager, target, shm_id, shm_offset),
618 gpu_timer_(manager->CreateGPUTimer(false)) {}
620 bool TimeStampQuery::Begin() {
621 NOTREACHED();
622 return false;
625 bool TimeStampQuery::End(base::subtle::Atomic32 submit_count) {
626 NOTREACHED();
627 return false;
630 void TimeStampQuery::Pause() {
631 MarkAsPaused();
634 void TimeStampQuery::Resume() {
635 MarkAsActive();
638 bool TimeStampQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
639 // Reset the disjoint value before the query begins if it is safe.
640 SafelyResetDisjointValue();
641 MarkAsActive();
642 // After a timestamp has begun, we will want to continually detect
643 // the disjoint value every frame until the context is destroyed.
644 BeginContinualDisjointUpdate();
646 gpu_timer_->QueryTimeStamp();
647 return AddToPendingQueue(submit_count);
650 bool TimeStampQuery::Process(bool did_finish) {
651 if (!gpu_timer_->IsAvailable())
652 return true;
654 // Make sure disjoint value is up to date. This disjoint check is the only one
655 // that needs to be done to validate that this query is valid. If a disjoint
656 // occurs before the client checks the query value we will just hide the
657 // disjoint state since it did not affect this query.
658 UpdateDisjointValue();
660 int64_t start = 0;
661 int64_t end = 0;
662 gpu_timer_->GetStartEndTimestamps(&start, &end);
663 DCHECK(start == end);
665 const uint64_t nano_seconds = start * base::Time::kNanosecondsPerMicrosecond;
666 return MarkAsCompleted(nano_seconds);
669 void TimeStampQuery::Destroy(bool have_context) {
670 if (gpu_timer_.get()) {
671 gpu_timer_->Destroy(have_context);
672 gpu_timer_.reset();
676 TimeStampQuery::~TimeStampQuery() {}
678 QueryManager::QueryManager(
679 GLES2Decoder* decoder,
680 FeatureInfo* feature_info)
681 : decoder_(decoder),
682 use_arb_occlusion_query2_for_occlusion_query_boolean_(
683 feature_info->feature_flags(
684 ).use_arb_occlusion_query2_for_occlusion_query_boolean),
685 use_arb_occlusion_query_for_occlusion_query_boolean_(
686 feature_info->feature_flags(
687 ).use_arb_occlusion_query_for_occlusion_query_boolean),
688 update_disjoints_continually_(false),
689 disjoint_notify_shm_id_(-1),
690 disjoint_notify_shm_offset_(0),
691 disjoints_notified_(0),
692 query_count_(0) {
693 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_ &&
694 use_arb_occlusion_query2_for_occlusion_query_boolean_));
695 DCHECK(decoder);
696 gfx::GLContext* context = decoder_->GetGLContext();
697 if (context) {
698 gpu_timing_client_ = context->CreateGPUTimingClient();
699 } else {
700 gpu_timing_client_ = new gfx::GPUTimingClient();
704 QueryManager::~QueryManager() {
705 DCHECK(queries_.empty());
707 // If this triggers, that means something is keeping a reference to
708 // a Query belonging to this.
709 CHECK_EQ(query_count_, 0u);
712 void QueryManager::Destroy(bool have_context) {
713 active_queries_.clear();
714 pending_queries_.clear();
715 pending_transfer_queries_.clear();
716 active_queries_.clear();
717 while (!queries_.empty()) {
718 Query* query = queries_.begin()->second.get();
719 query->Destroy(have_context);
720 queries_.erase(queries_.begin());
724 void QueryManager::SetDisjointSync(int32 shm_id, uint32 shm_offset) {
725 DCHECK(disjoint_notify_shm_id_ == -1);
726 DCHECK(shm_id != -1);
728 DisjointValueSync* sync = decoder_->GetSharedMemoryAs<DisjointValueSync*>(
729 shm_id, shm_offset, sizeof(*sync));
730 DCHECK(sync);
731 sync->Reset();
732 disjoints_notified_ = 0;
734 disjoint_notify_shm_id_ = shm_id;
735 disjoint_notify_shm_offset_ = shm_offset;
738 QueryManager::Query* QueryManager::CreateQuery(
739 GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) {
740 scoped_refptr<Query> query;
741 switch (target) {
742 case GL_COMMANDS_ISSUED_CHROMIUM:
743 query = new CommandsIssuedQuery(this, target, shm_id, shm_offset);
744 break;
745 case GL_LATENCY_QUERY_CHROMIUM:
746 query = new CommandLatencyQuery(this, target, shm_id, shm_offset);
747 break;
748 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
749 query = new AsyncReadPixelsCompletedQuery(
750 this, target, shm_id, shm_offset);
751 break;
752 case GL_GET_ERROR_QUERY_CHROMIUM:
753 query = new GetErrorQuery(this, target, shm_id, shm_offset);
754 break;
755 case GL_COMMANDS_COMPLETED_CHROMIUM:
756 query = new CommandsCompletedQuery(this, target, shm_id, shm_offset);
757 break;
758 case GL_TIME_ELAPSED:
759 query = new TimeElapsedQuery(this, target, shm_id, shm_offset);
760 break;
761 case GL_TIMESTAMP:
762 query = new TimeStampQuery(this, target, shm_id, shm_offset);
763 break;
764 case GL_ANY_SAMPLES_PASSED:
765 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
766 query = new BooleanQuery(this, target, shm_id, shm_offset);
767 break;
768 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
769 query = new SummedIntegerQuery(this, target, shm_id, shm_offset);
770 break;
771 default: {
772 NOTREACHED();
775 std::pair<QueryMap::iterator, bool> result =
776 queries_.insert(std::make_pair(client_id, query));
777 DCHECK(result.second);
778 return query.get();
781 scoped_ptr<gfx::GPUTimer> QueryManager::CreateGPUTimer(bool elapsed_time) {
782 return gpu_timing_client_->CreateGPUTimer(elapsed_time);
785 bool QueryManager::GPUTimingAvailable() {
786 return gpu_timing_client_->IsAvailable();
789 void QueryManager::GenQueries(GLsizei n, const GLuint* queries) {
790 DCHECK_GE(n, 0);
791 for (GLsizei i = 0; i < n; ++i) {
792 generated_query_ids_.insert(queries[i]);
796 bool QueryManager::IsValidQuery(GLuint id) {
797 GeneratedQueryIds::iterator it = generated_query_ids_.find(id);
798 return it != generated_query_ids_.end();
801 QueryManager::Query* QueryManager::GetQuery(GLuint client_id) {
802 QueryMap::iterator it = queries_.find(client_id);
803 return it != queries_.end() ? it->second.get() : nullptr;
806 QueryManager::Query* QueryManager::GetActiveQuery(GLenum target) {
807 ActiveQueryMap::iterator it = active_queries_.find(target);
808 return it != active_queries_.end() ? it->second.get() : nullptr;
811 void QueryManager::RemoveQuery(GLuint client_id) {
812 QueryMap::iterator it = queries_.find(client_id);
813 if (it != queries_.end()) {
814 Query* query = it->second.get();
816 // Remove from active query map if it is active.
817 ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
818 bool is_active = (active_it != active_queries_.end() &&
819 query == active_it->second.get());
820 DCHECK(is_active == query->IsActive());
821 if (is_active)
822 active_queries_.erase(active_it);
824 query->Destroy(true);
825 RemovePendingQuery(query);
826 query->MarkAsDeleted();
827 queries_.erase(it);
829 generated_query_ids_.erase(client_id);
832 void QueryManager::StartTracking(QueryManager::Query* /* query */) {
833 ++query_count_;
836 void QueryManager::StopTracking(QueryManager::Query* /* query */) {
837 --query_count_;
840 GLenum QueryManager::AdjustTargetForEmulation(GLenum target) {
841 switch (target) {
842 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
843 case GL_ANY_SAMPLES_PASSED_EXT:
844 if (use_arb_occlusion_query2_for_occlusion_query_boolean_) {
845 // ARB_occlusion_query2 does not have a
846 // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
847 // target.
848 target = GL_ANY_SAMPLES_PASSED_EXT;
849 } else if (use_arb_occlusion_query_for_occlusion_query_boolean_) {
850 // ARB_occlusion_query does not have a
851 // GL_ANY_SAMPLES_PASSED_EXT
852 // target.
853 target = GL_SAMPLES_PASSED_ARB;
855 break;
856 default:
857 break;
859 return target;
862 void QueryManager::BeginQueryHelper(GLenum target, GLuint id) {
863 target = AdjustTargetForEmulation(target);
864 glBeginQuery(target, id);
867 void QueryManager::EndQueryHelper(GLenum target) {
868 target = AdjustTargetForEmulation(target);
869 glEndQuery(target);
872 void QueryManager::UpdateDisjointValue() {
873 if (disjoint_notify_shm_id_ != -1) {
874 if (gpu_timing_client_->CheckAndResetTimerErrors()) {
875 disjoints_notified_++;
877 DisjointValueSync* sync = decoder_->GetSharedMemoryAs<DisjointValueSync*>(
878 disjoint_notify_shm_id_, disjoint_notify_shm_offset_, sizeof(*sync));
879 if (!sync) {
880 // Shared memory does not seem to be valid, ignore the shm id/offset.
881 disjoint_notify_shm_id_ = -1;
882 disjoint_notify_shm_offset_ = 0;
883 } else {
884 sync->SetDisjointCount(disjoints_notified_);
890 void QueryManager::SafelyResetDisjointValue() {
891 // It is only safe to reset the disjoint value is there is no active
892 // elapsed timer and we are not continually updating the disjoint value.
893 if (!update_disjoints_continually_ && !GetActiveQuery(GL_TIME_ELAPSED)) {
894 // Reset the error state without storing the result.
895 gpu_timing_client_->CheckAndResetTimerErrors();
899 QueryManager::Query::Query(
900 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
901 : manager_(manager),
902 target_(target),
903 shm_id_(shm_id),
904 shm_offset_(shm_offset),
905 submit_count_(0),
906 query_state_(kQueryState_Initialize),
907 deleted_(false) {
908 DCHECK(manager);
909 manager_->StartTracking(this);
912 void QueryManager::Query::RunCallbacks() {
913 for (size_t i = 0; i < callbacks_.size(); i++) {
914 callbacks_[i].Run();
916 callbacks_.clear();
919 void QueryManager::Query::AddCallback(base::Closure callback) {
920 if (query_state_ == kQueryState_Pending) {
921 callbacks_.push_back(callback);
922 } else {
923 callback.Run();
927 QueryManager::Query::~Query() {
928 // The query is getting deleted, either by the client or
929 // because the context was lost. Call any outstanding
930 // callbacks to avoid leaks.
931 RunCallbacks();
932 if (manager_) {
933 manager_->StopTracking(this);
934 manager_ = NULL;
938 bool QueryManager::Query::MarkAsCompleted(uint64 result) {
939 UnmarkAsPending();
940 QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>(
941 shm_id_, shm_offset_, sizeof(*sync));
942 if (!sync) {
943 return false;
946 sync->result = result;
947 base::subtle::Release_Store(&sync->process_count, submit_count_);
949 return true;
952 bool QueryManager::ProcessPendingQueries(bool did_finish) {
953 while (!pending_queries_.empty()) {
954 Query* query = pending_queries_.front().get();
955 if (!query->Process(did_finish)) {
956 return false;
958 if (query->IsPending()) {
959 break;
961 query->RunCallbacks();
962 pending_queries_.pop_front();
964 // If glFinish() has been called, all of our queries should be completed.
965 DCHECK(!did_finish || pending_queries_.empty());
967 return true;
970 bool QueryManager::HavePendingQueries() {
971 return !pending_queries_.empty();
974 bool QueryManager::ProcessPendingTransferQueries() {
975 while (!pending_transfer_queries_.empty()) {
976 Query* query = pending_transfer_queries_.front().get();
977 if (!query->Process(false)) {
978 return false;
980 if (query->IsPending()) {
981 break;
983 query->RunCallbacks();
984 pending_transfer_queries_.pop_front();
987 return true;
990 bool QueryManager::HavePendingTransferQueries() {
991 return !pending_transfer_queries_.empty();
994 void QueryManager::ProcessFrameBeginUpdates() {
995 if (update_disjoints_continually_)
996 UpdateDisjointValue();
999 bool QueryManager::AddPendingQuery(Query* query,
1000 base::subtle::Atomic32 submit_count) {
1001 DCHECK(query);
1002 DCHECK(!query->IsDeleted());
1003 if (!RemovePendingQuery(query)) {
1004 return false;
1006 query->MarkAsPending(submit_count);
1007 pending_queries_.push_back(query);
1008 return true;
1011 bool QueryManager::AddPendingTransferQuery(
1012 Query* query,
1013 base::subtle::Atomic32 submit_count) {
1014 DCHECK(query);
1015 DCHECK(!query->IsDeleted());
1016 if (!RemovePendingQuery(query)) {
1017 return false;
1019 query->MarkAsPending(submit_count);
1020 pending_transfer_queries_.push_back(query);
1021 return true;
1024 bool QueryManager::RemovePendingQuery(Query* query) {
1025 DCHECK(query);
1026 if (query->IsPending()) {
1027 // TODO(gman): Speed this up if this is a common operation. This would only
1028 // happen if you do being/end begin/end on the same query without waiting
1029 // for the first one to finish.
1030 for (QueryQueue::iterator it = pending_queries_.begin();
1031 it != pending_queries_.end(); ++it) {
1032 if (it->get() == query) {
1033 pending_queries_.erase(it);
1034 break;
1037 for (QueryQueue::iterator it = pending_transfer_queries_.begin();
1038 it != pending_transfer_queries_.end(); ++it) {
1039 if (it->get() == query) {
1040 pending_transfer_queries_.erase(it);
1041 break;
1044 if (!query->MarkAsCompleted(0)) {
1045 return false;
1048 return true;
1051 bool QueryManager::BeginQuery(Query* query) {
1052 DCHECK(query);
1053 if (!RemovePendingQuery(query)) {
1054 return false;
1056 if (query->Begin()) {
1057 active_queries_[query->target()] = query;
1058 return true;
1061 return false;
1064 bool QueryManager::EndQuery(Query* query, base::subtle::Atomic32 submit_count) {
1065 DCHECK(query);
1066 if (!RemovePendingQuery(query)) {
1067 return false;
1070 // Remove from active query map if it is active.
1071 ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
1072 DCHECK(active_it != active_queries_.end());
1073 DCHECK(query == active_it->second.get());
1074 active_queries_.erase(active_it);
1076 return query->End(submit_count);
1079 bool QueryManager::QueryCounter(
1080 Query* query, base::subtle::Atomic32 submit_count) {
1081 DCHECK(query);
1082 return query->QueryCounter(submit_count);
1085 void QueryManager::PauseQueries() {
1086 for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
1087 if (it.second->IsActive()) {
1088 it.second->Pause();
1089 DCHECK(it.second->IsPaused());
1094 void QueryManager::ResumeQueries() {
1095 for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
1096 if (it.second->IsPaused()) {
1097 it.second->Resume();
1098 DCHECK(it.second->IsActive());
1103 } // namespace gles2
1104 } // namespace gpu