cc: Use worker context for one-copy tile initialization.
[chromium-blink-merge.git] / gpu / command_buffer / service / query_manager.cc
bloba269f35323d58a9b2cfc8bed147941d9378135b4
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_context.h"
20 #include "ui/gl/gl_fence.h"
21 #include "ui/gl/gpu_timing.h"
23 namespace gpu {
24 namespace gles2 {
26 namespace {
28 class AsyncPixelTransferCompletionObserverImpl
29 : public AsyncPixelTransferCompletionObserver {
30 public:
31 AsyncPixelTransferCompletionObserverImpl(base::subtle::Atomic32 submit_count)
32 : submit_count_(submit_count), cancelled_(false) {}
34 void Cancel() {
35 base::AutoLock locked(lock_);
36 cancelled_ = true;
39 void DidComplete(const AsyncMemoryParams& mem_params) override {
40 base::AutoLock locked(lock_);
41 if (!cancelled_) {
42 DCHECK(mem_params.buffer().get());
43 void* data = mem_params.GetDataAddress();
44 QuerySync* sync = static_cast<QuerySync*>(data);
45 base::subtle::Release_Store(&sync->process_count, submit_count_);
49 private:
50 ~AsyncPixelTransferCompletionObserverImpl() override {}
52 base::subtle::Atomic32 submit_count_;
54 base::Lock lock_;
55 bool cancelled_;
57 DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferCompletionObserverImpl);
60 class AsyncPixelTransfersCompletedQuery
61 : public QueryManager::Query,
62 public base::SupportsWeakPtr<AsyncPixelTransfersCompletedQuery> {
63 public:
64 AsyncPixelTransfersCompletedQuery(
65 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
67 bool Begin() override;
68 bool End(base::subtle::Atomic32 submit_count) override;
69 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
70 void Pause() override;
71 void Resume() override;
72 bool Process(bool did_finish) override;
73 void Destroy(bool have_context) override;
75 protected:
76 ~AsyncPixelTransfersCompletedQuery() override;
78 scoped_refptr<AsyncPixelTransferCompletionObserverImpl> observer_;
81 AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery(
82 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
83 : Query(manager, target, shm_id, shm_offset) {
86 bool AsyncPixelTransfersCompletedQuery::Begin() {
87 MarkAsActive();
88 return true;
91 void AsyncPixelTransfersCompletedQuery::Pause() {
92 MarkAsPaused();
95 void AsyncPixelTransfersCompletedQuery::Resume() {
96 MarkAsActive();
99 bool AsyncPixelTransfersCompletedQuery::End(
100 base::subtle::Atomic32 submit_count) {
101 // Get the real shared memory since it might need to be duped to prevent
102 // use-after-free of the memory.
103 scoped_refptr<Buffer> buffer =
104 manager()->decoder()->GetSharedMemoryBuffer(shm_id());
105 if (!buffer.get())
106 return false;
107 AsyncMemoryParams mem_params(buffer, shm_offset(), sizeof(QuerySync));
108 if (!mem_params.GetDataAddress())
109 return false;
111 observer_ = new AsyncPixelTransferCompletionObserverImpl(submit_count);
113 // Ask AsyncPixelTransferDelegate to run completion callback after all
114 // previous async transfers are done. No guarantee that callback is run
115 // on the current thread.
116 manager()->decoder()->GetAsyncPixelTransferManager()->AsyncNotifyCompletion(
117 mem_params, observer_.get());
119 return AddToPendingTransferQueue(submit_count);
122 bool AsyncPixelTransfersCompletedQuery::QueryCounter(
123 base::subtle::Atomic32 submit_count) {
124 NOTREACHED();
125 return false;
128 bool AsyncPixelTransfersCompletedQuery::Process(bool did_finish) {
129 QuerySync* sync = manager()->decoder()->GetSharedMemoryAs<QuerySync*>(
130 shm_id(), shm_offset(), sizeof(*sync));
131 if (!sync)
132 return false;
134 // Check if completion callback has been run. sync->process_count atomicity
135 // is guaranteed as this is already used to notify client of a completed
136 // query.
137 if (base::subtle::Acquire_Load(&sync->process_count) != submit_count())
138 return true;
140 UnmarkAsPending();
141 return true;
144 void AsyncPixelTransfersCompletedQuery::Destroy(bool /* have_context */) {
145 if (!IsDeleted()) {
146 MarkAsDeleted();
150 AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() {
151 if (observer_.get())
152 observer_->Cancel();
155 } // namespace
157 class AllSamplesPassedQuery : public QueryManager::Query {
158 public:
159 AllSamplesPassedQuery(
160 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
161 bool Begin() override;
162 bool End(base::subtle::Atomic32 submit_count) override;
163 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
164 void Pause() override;
165 void Resume() override;
166 bool Process(bool did_finish) override;
167 void Destroy(bool have_context) override;
169 protected:
170 ~AllSamplesPassedQuery() override;
172 private:
173 // Service side query id.
174 std::vector<GLuint> service_ids_;
177 AllSamplesPassedQuery::AllSamplesPassedQuery(
178 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
179 : Query(manager, target, shm_id, shm_offset) {
180 GLuint service_id = 0;
181 glGenQueries(1, &service_id);
182 DCHECK_NE(0u, service_id);
183 service_ids_.push_back(service_id);
186 bool AllSamplesPassedQuery::Begin() {
187 MarkAsActive();
188 // Delete all but the first one when beginning a new query.
189 if (service_ids_.size() > 1) {
190 glDeleteQueries(service_ids_.size() - 1, &service_ids_[1]);
191 service_ids_.resize(1);
193 BeginQueryHelper(target(), service_ids_.back());
194 return true;
197 bool AllSamplesPassedQuery::End(base::subtle::Atomic32 submit_count) {
198 EndQueryHelper(target());
199 return AddToPendingQueue(submit_count);
202 bool AllSamplesPassedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
203 NOTREACHED();
204 return false;
207 void AllSamplesPassedQuery::Pause() {
208 MarkAsPaused();
209 EndQueryHelper(target());
212 void AllSamplesPassedQuery::Resume() {
213 MarkAsActive();
215 GLuint service_id = 0;
216 glGenQueries(1, &service_id);
217 DCHECK_NE(0u, service_id);
218 service_ids_.push_back(service_id);
219 BeginQueryHelper(target(), service_ids_.back());
222 bool AllSamplesPassedQuery::Process(bool did_finish) {
223 GLuint available = 0;
224 glGetQueryObjectuiv(
225 service_ids_.back(), GL_QUERY_RESULT_AVAILABLE_EXT, &available);
226 if (!available) {
227 return true;
229 for (const GLuint& service_id : service_ids_) {
230 GLuint result = 0;
231 glGetQueryObjectuiv(service_id, GL_QUERY_RESULT_EXT, &result);
232 if (result != 0)
233 return MarkAsCompleted(1);
235 return MarkAsCompleted(0);
238 void AllSamplesPassedQuery::Destroy(bool have_context) {
239 if (have_context && !IsDeleted()) {
240 glDeleteQueries(service_ids_.size(), &service_ids_[0]);
241 service_ids_.clear();
242 MarkAsDeleted();
246 AllSamplesPassedQuery::~AllSamplesPassedQuery() {
249 class CommandsIssuedQuery : public QueryManager::Query {
250 public:
251 CommandsIssuedQuery(
252 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
254 bool Begin() override;
255 bool End(base::subtle::Atomic32 submit_count) override;
256 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
257 void Pause() override;
258 void Resume() override;
259 bool Process(bool did_finish) override;
260 void Destroy(bool have_context) override;
262 protected:
263 ~CommandsIssuedQuery() override;
265 private:
266 base::TimeTicks begin_time_;
269 CommandsIssuedQuery::CommandsIssuedQuery(
270 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
271 : Query(manager, target, shm_id, shm_offset) {
274 bool CommandsIssuedQuery::Begin() {
275 MarkAsActive();
276 begin_time_ = base::TimeTicks::Now();
277 return true;
280 void CommandsIssuedQuery::Pause() {
281 MarkAsPaused();
284 void CommandsIssuedQuery::Resume() {
285 MarkAsActive();
288 bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count) {
289 const base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
290 MarkAsPending(submit_count);
291 return MarkAsCompleted(elapsed.InMicroseconds());
294 bool CommandsIssuedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
295 NOTREACHED();
296 return false;
299 bool CommandsIssuedQuery::Process(bool did_finish) {
300 NOTREACHED();
301 return true;
304 void CommandsIssuedQuery::Destroy(bool /* have_context */) {
305 if (!IsDeleted()) {
306 MarkAsDeleted();
310 CommandsIssuedQuery::~CommandsIssuedQuery() {
313 class CommandLatencyQuery : public QueryManager::Query {
314 public:
315 CommandLatencyQuery(
316 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
318 bool Begin() override;
319 bool End(base::subtle::Atomic32 submit_count) override;
320 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
321 void Pause() override;
322 void Resume() override;
323 bool Process(bool did_finish) override;
324 void Destroy(bool have_context) override;
326 protected:
327 ~CommandLatencyQuery() override;
330 CommandLatencyQuery::CommandLatencyQuery(
331 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
332 : Query(manager, target, shm_id, shm_offset) {
335 bool CommandLatencyQuery::Begin() {
336 MarkAsActive();
337 return true;
340 void CommandLatencyQuery::Pause() {
341 MarkAsPaused();
344 void CommandLatencyQuery::Resume() {
345 MarkAsActive();
348 bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count) {
349 base::TimeDelta now = base::TimeTicks::Now() - base::TimeTicks();
350 MarkAsPending(submit_count);
351 return MarkAsCompleted(now.InMicroseconds());
354 bool CommandLatencyQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
355 NOTREACHED();
356 return false;
359 bool CommandLatencyQuery::Process(bool did_finish) {
360 NOTREACHED();
361 return true;
364 void CommandLatencyQuery::Destroy(bool /* have_context */) {
365 if (!IsDeleted()) {
366 MarkAsDeleted();
370 CommandLatencyQuery::~CommandLatencyQuery() {
374 class AsyncReadPixelsCompletedQuery
375 : public QueryManager::Query,
376 public base::SupportsWeakPtr<AsyncReadPixelsCompletedQuery> {
377 public:
378 AsyncReadPixelsCompletedQuery(
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 void Complete();
391 ~AsyncReadPixelsCompletedQuery() override;
393 private:
394 bool complete_result_;
397 AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
398 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
399 : Query(manager, target, shm_id, shm_offset),
400 complete_result_(false) {
403 bool AsyncReadPixelsCompletedQuery::Begin() {
404 MarkAsActive();
405 return true;
408 void AsyncReadPixelsCompletedQuery::Pause() {
409 MarkAsPaused();
412 void AsyncReadPixelsCompletedQuery::Resume() {
413 MarkAsActive();
416 bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
417 if (!AddToPendingQueue(submit_count)) {
418 return false;
420 manager()->decoder()->WaitForReadPixels(
421 base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
422 AsWeakPtr()));
424 return Process(false);
427 bool AsyncReadPixelsCompletedQuery::QueryCounter(
428 base::subtle::Atomic32 submit_count) {
429 NOTREACHED();
430 return false;
433 void AsyncReadPixelsCompletedQuery::Complete() {
434 complete_result_ = MarkAsCompleted(1);
437 bool AsyncReadPixelsCompletedQuery::Process(bool did_finish) {
438 return !IsFinished() || complete_result_;
441 void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
442 if (!IsDeleted()) {
443 MarkAsDeleted();
447 AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
451 class GetErrorQuery : public QueryManager::Query {
452 public:
453 GetErrorQuery(
454 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
456 bool Begin() override;
457 bool End(base::subtle::Atomic32 submit_count) override;
458 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
459 void Pause() override;
460 void Resume() override;
461 bool Process(bool did_finish) override;
462 void Destroy(bool have_context) override;
464 protected:
465 ~GetErrorQuery() override;
467 private:
470 GetErrorQuery::GetErrorQuery(
471 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
472 : Query(manager, target, shm_id, shm_offset) {
475 bool GetErrorQuery::Begin() {
476 MarkAsActive();
477 return true;
480 void GetErrorQuery::Pause() {
481 MarkAsPaused();
484 void GetErrorQuery::Resume() {
485 MarkAsActive();
488 bool GetErrorQuery::End(base::subtle::Atomic32 submit_count) {
489 MarkAsPending(submit_count);
490 return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
493 bool GetErrorQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
494 NOTREACHED();
495 return false;
498 bool GetErrorQuery::Process(bool did_finish) {
499 NOTREACHED();
500 return true;
503 void GetErrorQuery::Destroy(bool /* have_context */) {
504 if (!IsDeleted()) {
505 MarkAsDeleted();
509 GetErrorQuery::~GetErrorQuery() {
512 class CommandsCompletedQuery : public QueryManager::Query {
513 public:
514 CommandsCompletedQuery(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 ~CommandsCompletedQuery() override;
531 private:
532 scoped_ptr<gfx::GLFence> fence_;
533 base::TimeTicks begin_time_;
536 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager,
537 GLenum target,
538 int32 shm_id,
539 uint32 shm_offset)
540 : Query(manager, target, shm_id, shm_offset) {}
542 bool CommandsCompletedQuery::Begin() {
543 MarkAsActive();
544 begin_time_ = base::TimeTicks::Now();
545 return true;
548 void CommandsCompletedQuery::Pause() {
549 MarkAsPaused();
552 void CommandsCompletedQuery::Resume() {
553 MarkAsActive();
556 bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
557 fence_.reset(gfx::GLFence::Create());
558 DCHECK(fence_);
559 return AddToPendingQueue(submit_count);
562 bool CommandsCompletedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
563 NOTREACHED();
564 return false;
567 bool CommandsCompletedQuery::Process(bool did_finish) {
568 // Note: |did_finish| guarantees that the GPU has passed the fence but
569 // we cannot assume that GLFence::HasCompleted() will return true yet as
570 // that's not guaranteed by all GLFence implementations.
571 if (!did_finish && fence_ && !fence_->HasCompleted())
572 return true;
574 const base::TimeDelta elapsed = base::TimeTicks::Now() - begin_time_;
575 return MarkAsCompleted(elapsed.InMicroseconds());
578 void CommandsCompletedQuery::Destroy(bool have_context) {
579 if (have_context && !IsDeleted()) {
580 fence_.reset();
581 MarkAsDeleted();
585 CommandsCompletedQuery::~CommandsCompletedQuery() {}
587 class TimeElapsedQuery : public QueryManager::Query {
588 public:
589 TimeElapsedQuery(QueryManager* manager,
590 GLenum target,
591 int32 shm_id,
592 uint32 shm_offset);
594 // Overridden from QueryManager::Query:
595 bool Begin() override;
596 bool End(base::subtle::Atomic32 submit_count) override;
597 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
598 void Pause() override;
599 void Resume() override;
600 bool Process(bool did_finish) override;
601 void Destroy(bool have_context) override;
603 protected:
604 ~TimeElapsedQuery() override;
606 private:
607 scoped_ptr<gfx::GPUTimer> gpu_timer_;
610 TimeElapsedQuery::TimeElapsedQuery(QueryManager* manager,
611 GLenum target,
612 int32 shm_id,
613 uint32 shm_offset)
614 : Query(manager, target, shm_id, shm_offset),
615 gpu_timer_(manager->CreateGPUTimer(true)) {
618 bool TimeElapsedQuery::Begin() {
619 // Reset the disjoint value before the query begins if it is safe.
620 SafelyResetDisjointValue();
621 MarkAsActive();
622 gpu_timer_->Start();
623 return true;
626 bool TimeElapsedQuery::End(base::subtle::Atomic32 submit_count) {
627 gpu_timer_->End();
628 return AddToPendingQueue(submit_count);
631 bool TimeElapsedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
632 NOTREACHED();
633 return false;
636 void TimeElapsedQuery::Pause() {
637 MarkAsPaused();
640 void TimeElapsedQuery::Resume() {
641 MarkAsActive();
644 bool TimeElapsedQuery::Process(bool did_finish) {
645 if (!gpu_timer_->IsAvailable())
646 return true;
648 // Make sure disjoint value is up to date. This disjoint check is the only one
649 // that needs to be done to validate that this query is valid. If a disjoint
650 // occurs before the client checks the query value we will just hide the
651 // disjoint state since it did not affect this query.
652 UpdateDisjointValue();
654 const uint64_t nano_seconds = gpu_timer_->GetDeltaElapsed() *
655 base::Time::kNanosecondsPerMicrosecond;
656 return MarkAsCompleted(nano_seconds);
659 void TimeElapsedQuery::Destroy(bool have_context) {
660 gpu_timer_->Destroy(have_context);
663 TimeElapsedQuery::~TimeElapsedQuery() {}
665 class TimeStampQuery : public QueryManager::Query {
666 public:
667 TimeStampQuery(QueryManager* manager,
668 GLenum target,
669 int32 shm_id,
670 uint32 shm_offset);
672 // Overridden from QueryManager::Query:
673 bool Begin() override;
674 bool End(base::subtle::Atomic32 submit_count) override;
675 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
676 void Pause() override;
677 void Resume() override;
678 bool Process(bool did_finish) override;
679 void Destroy(bool have_context) override;
681 protected:
682 ~TimeStampQuery() override;
684 private:
685 scoped_ptr<gfx::GPUTimer> gpu_timer_;
688 TimeStampQuery::TimeStampQuery(QueryManager* manager,
689 GLenum target,
690 int32 shm_id,
691 uint32 shm_offset)
692 : Query(manager, target, shm_id, shm_offset),
693 gpu_timer_(manager->CreateGPUTimer(false)) {}
695 bool TimeStampQuery::Begin() {
696 NOTREACHED();
697 return false;
700 bool TimeStampQuery::End(base::subtle::Atomic32 submit_count) {
701 NOTREACHED();
702 return false;
705 void TimeStampQuery::Pause() {
706 MarkAsPaused();
709 void TimeStampQuery::Resume() {
710 MarkAsActive();
713 bool TimeStampQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
714 // Reset the disjoint value before the query begins if it is safe.
715 SafelyResetDisjointValue();
716 MarkAsActive();
717 // After a timestamp has begun, we will want to continually detect
718 // the disjoint value every frame until the context is destroyed.
719 BeginContinualDisjointUpdate();
721 gpu_timer_->QueryTimeStamp();
722 return AddToPendingQueue(submit_count);
725 bool TimeStampQuery::Process(bool did_finish) {
726 if (!gpu_timer_->IsAvailable())
727 return true;
729 // Make sure disjoint value is up to date. This disjoint check is the only one
730 // that needs to be done to validate that this query is valid. If a disjoint
731 // occurs before the client checks the query value we will just hide the
732 // disjoint state since it did not affect this query.
733 UpdateDisjointValue();
735 int64_t start = 0;
736 int64_t end = 0;
737 gpu_timer_->GetStartEndTimestamps(&start, &end);
738 DCHECK(start == end);
740 const uint64_t nano_seconds = start * base::Time::kNanosecondsPerMicrosecond;
741 return MarkAsCompleted(nano_seconds);
744 void TimeStampQuery::Destroy(bool have_context) {
745 if (gpu_timer_.get()) {
746 gpu_timer_->Destroy(have_context);
747 gpu_timer_.reset();
751 TimeStampQuery::~TimeStampQuery() {}
753 QueryManager::QueryManager(
754 GLES2Decoder* decoder,
755 FeatureInfo* feature_info)
756 : decoder_(decoder),
757 use_arb_occlusion_query2_for_occlusion_query_boolean_(
758 feature_info->feature_flags(
759 ).use_arb_occlusion_query2_for_occlusion_query_boolean),
760 use_arb_occlusion_query_for_occlusion_query_boolean_(
761 feature_info->feature_flags(
762 ).use_arb_occlusion_query_for_occlusion_query_boolean),
763 update_disjoints_continually_(false),
764 disjoint_notify_shm_id_(-1),
765 disjoint_notify_shm_offset_(0),
766 disjoints_notified_(0),
767 query_count_(0) {
768 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_ &&
769 use_arb_occlusion_query2_for_occlusion_query_boolean_));
770 DCHECK(decoder);
771 gfx::GLContext* context = decoder_->GetGLContext();
772 if (context) {
773 gpu_timing_client_ = context->CreateGPUTimingClient();
774 } else {
775 gpu_timing_client_ = new gfx::GPUTimingClient();
779 QueryManager::~QueryManager() {
780 DCHECK(queries_.empty());
782 // If this triggers, that means something is keeping a reference to
783 // a Query belonging to this.
784 CHECK_EQ(query_count_, 0u);
787 void QueryManager::Destroy(bool have_context) {
788 active_queries_.clear();
789 pending_queries_.clear();
790 pending_transfer_queries_.clear();
791 active_queries_.clear();
792 while (!queries_.empty()) {
793 Query* query = queries_.begin()->second.get();
794 query->Destroy(have_context);
795 queries_.erase(queries_.begin());
799 void QueryManager::SetDisjointSync(int32 shm_id, uint32 shm_offset) {
800 DCHECK(disjoint_notify_shm_id_ == -1);
801 DCHECK(shm_id != -1);
803 DisjointValueSync* sync = decoder_->GetSharedMemoryAs<DisjointValueSync*>(
804 shm_id, shm_offset, sizeof(*sync));
805 DCHECK(sync);
806 sync->Reset();
807 disjoints_notified_ = 0;
809 disjoint_notify_shm_id_ = shm_id;
810 disjoint_notify_shm_offset_ = shm_offset;
813 QueryManager::Query* QueryManager::CreateQuery(
814 GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) {
815 scoped_refptr<Query> query;
816 switch (target) {
817 case GL_COMMANDS_ISSUED_CHROMIUM:
818 query = new CommandsIssuedQuery(this, target, shm_id, shm_offset);
819 break;
820 case GL_LATENCY_QUERY_CHROMIUM:
821 query = new CommandLatencyQuery(this, target, shm_id, shm_offset);
822 break;
823 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
824 // Currently async pixel transfer delegates only support uploads.
825 query = new AsyncPixelTransfersCompletedQuery(
826 this, target, shm_id, shm_offset);
827 break;
828 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
829 query = new AsyncReadPixelsCompletedQuery(
830 this, target, shm_id, shm_offset);
831 break;
832 case GL_GET_ERROR_QUERY_CHROMIUM:
833 query = new GetErrorQuery(this, target, shm_id, shm_offset);
834 break;
835 case GL_COMMANDS_COMPLETED_CHROMIUM:
836 query = new CommandsCompletedQuery(this, target, shm_id, shm_offset);
837 break;
838 case GL_TIME_ELAPSED:
839 query = new TimeElapsedQuery(this, target, shm_id, shm_offset);
840 break;
841 case GL_TIMESTAMP:
842 query = new TimeStampQuery(this, target, shm_id, shm_offset);
843 break;
844 default: {
845 query = new AllSamplesPassedQuery(this, target, shm_id, shm_offset);
846 break;
849 std::pair<QueryMap::iterator, bool> result =
850 queries_.insert(std::make_pair(client_id, query));
851 DCHECK(result.second);
852 return query.get();
855 scoped_ptr<gfx::GPUTimer> QueryManager::CreateGPUTimer(bool elapsed_time) {
856 return gpu_timing_client_->CreateGPUTimer(elapsed_time);
859 bool QueryManager::GPUTimingAvailable() {
860 return gpu_timing_client_->IsAvailable();
863 void QueryManager::GenQueries(GLsizei n, const GLuint* queries) {
864 DCHECK_GE(n, 0);
865 for (GLsizei i = 0; i < n; ++i) {
866 generated_query_ids_.insert(queries[i]);
870 bool QueryManager::IsValidQuery(GLuint id) {
871 GeneratedQueryIds::iterator it = generated_query_ids_.find(id);
872 return it != generated_query_ids_.end();
875 QueryManager::Query* QueryManager::GetQuery(GLuint client_id) {
876 QueryMap::iterator it = queries_.find(client_id);
877 return it != queries_.end() ? it->second.get() : nullptr;
880 QueryManager::Query* QueryManager::GetActiveQuery(GLenum target) {
881 ActiveQueryMap::iterator it = active_queries_.find(target);
882 return it != active_queries_.end() ? it->second.get() : nullptr;
885 void QueryManager::RemoveQuery(GLuint client_id) {
886 QueryMap::iterator it = queries_.find(client_id);
887 if (it != queries_.end()) {
888 Query* query = it->second.get();
890 // Remove from active query map if it is active.
891 ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
892 bool is_active = (active_it != active_queries_.end() &&
893 query == active_it->second.get());
894 DCHECK(is_active == query->IsActive());
895 if (is_active)
896 active_queries_.erase(active_it);
898 query->Destroy(true);
899 RemovePendingQuery(query);
900 query->MarkAsDeleted();
901 queries_.erase(it);
903 generated_query_ids_.erase(client_id);
906 void QueryManager::StartTracking(QueryManager::Query* /* query */) {
907 ++query_count_;
910 void QueryManager::StopTracking(QueryManager::Query* /* query */) {
911 --query_count_;
914 GLenum QueryManager::AdjustTargetForEmulation(GLenum target) {
915 switch (target) {
916 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
917 case GL_ANY_SAMPLES_PASSED_EXT:
918 if (use_arb_occlusion_query2_for_occlusion_query_boolean_) {
919 // ARB_occlusion_query2 does not have a
920 // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
921 // target.
922 target = GL_ANY_SAMPLES_PASSED_EXT;
923 } else if (use_arb_occlusion_query_for_occlusion_query_boolean_) {
924 // ARB_occlusion_query does not have a
925 // GL_ANY_SAMPLES_PASSED_EXT
926 // target.
927 target = GL_SAMPLES_PASSED_ARB;
929 break;
930 default:
931 break;
933 return target;
936 void QueryManager::BeginQueryHelper(GLenum target, GLuint id) {
937 target = AdjustTargetForEmulation(target);
938 glBeginQuery(target, id);
941 void QueryManager::EndQueryHelper(GLenum target) {
942 target = AdjustTargetForEmulation(target);
943 glEndQuery(target);
946 void QueryManager::UpdateDisjointValue() {
947 if (disjoint_notify_shm_id_ != -1) {
948 if (gpu_timing_client_->CheckAndResetTimerErrors()) {
949 disjoints_notified_++;
951 DisjointValueSync* sync = decoder_->GetSharedMemoryAs<DisjointValueSync*>(
952 disjoint_notify_shm_id_, disjoint_notify_shm_offset_, sizeof(*sync));
953 if (!sync) {
954 // Shared memory does not seem to be valid, ignore the shm id/offset.
955 disjoint_notify_shm_id_ = -1;
956 disjoint_notify_shm_offset_ = 0;
957 } else {
958 sync->SetDisjointCount(disjoints_notified_);
964 void QueryManager::SafelyResetDisjointValue() {
965 // It is only safe to reset the disjoint value is there is no active
966 // elapsed timer and we are not continually updating the disjoint value.
967 if (!update_disjoints_continually_ && !GetActiveQuery(GL_TIME_ELAPSED)) {
968 // Reset the error state without storing the result.
969 gpu_timing_client_->CheckAndResetTimerErrors();
973 QueryManager::Query::Query(
974 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
975 : manager_(manager),
976 target_(target),
977 shm_id_(shm_id),
978 shm_offset_(shm_offset),
979 submit_count_(0),
980 query_state_(kQueryState_Initialize),
981 deleted_(false) {
982 DCHECK(manager);
983 manager_->StartTracking(this);
986 void QueryManager::Query::RunCallbacks() {
987 for (size_t i = 0; i < callbacks_.size(); i++) {
988 callbacks_[i].Run();
990 callbacks_.clear();
993 void QueryManager::Query::AddCallback(base::Closure callback) {
994 if (query_state_ == kQueryState_Pending) {
995 callbacks_.push_back(callback);
996 } else {
997 callback.Run();
1001 QueryManager::Query::~Query() {
1002 // The query is getting deleted, either by the client or
1003 // because the context was lost. Call any outstanding
1004 // callbacks to avoid leaks.
1005 RunCallbacks();
1006 if (manager_) {
1007 manager_->StopTracking(this);
1008 manager_ = NULL;
1012 bool QueryManager::Query::MarkAsCompleted(uint64 result) {
1013 UnmarkAsPending();
1014 QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>(
1015 shm_id_, shm_offset_, sizeof(*sync));
1016 if (!sync) {
1017 return false;
1020 sync->result = result;
1021 base::subtle::Release_Store(&sync->process_count, submit_count_);
1023 return true;
1026 bool QueryManager::ProcessPendingQueries(bool did_finish) {
1027 while (!pending_queries_.empty()) {
1028 Query* query = pending_queries_.front().get();
1029 if (!query->Process(did_finish)) {
1030 return false;
1032 if (query->IsPending()) {
1033 break;
1035 query->RunCallbacks();
1036 pending_queries_.pop_front();
1038 // If glFinish() has been called, all of our queries should be completed.
1039 DCHECK(!did_finish || pending_queries_.empty());
1041 return true;
1044 bool QueryManager::HavePendingQueries() {
1045 return !pending_queries_.empty();
1048 bool QueryManager::ProcessPendingTransferQueries() {
1049 while (!pending_transfer_queries_.empty()) {
1050 Query* query = pending_transfer_queries_.front().get();
1051 if (!query->Process(false)) {
1052 return false;
1054 if (query->IsPending()) {
1055 break;
1057 query->RunCallbacks();
1058 pending_transfer_queries_.pop_front();
1061 return true;
1064 bool QueryManager::HavePendingTransferQueries() {
1065 return !pending_transfer_queries_.empty();
1068 void QueryManager::ProcessFrameBeginUpdates() {
1069 if (update_disjoints_continually_)
1070 UpdateDisjointValue();
1073 bool QueryManager::AddPendingQuery(Query* query,
1074 base::subtle::Atomic32 submit_count) {
1075 DCHECK(query);
1076 DCHECK(!query->IsDeleted());
1077 if (!RemovePendingQuery(query)) {
1078 return false;
1080 query->MarkAsPending(submit_count);
1081 pending_queries_.push_back(query);
1082 return true;
1085 bool QueryManager::AddPendingTransferQuery(
1086 Query* query,
1087 base::subtle::Atomic32 submit_count) {
1088 DCHECK(query);
1089 DCHECK(!query->IsDeleted());
1090 if (!RemovePendingQuery(query)) {
1091 return false;
1093 query->MarkAsPending(submit_count);
1094 pending_transfer_queries_.push_back(query);
1095 return true;
1098 bool QueryManager::RemovePendingQuery(Query* query) {
1099 DCHECK(query);
1100 if (query->IsPending()) {
1101 // TODO(gman): Speed this up if this is a common operation. This would only
1102 // happen if you do being/end begin/end on the same query without waiting
1103 // for the first one to finish.
1104 for (QueryQueue::iterator it = pending_queries_.begin();
1105 it != pending_queries_.end(); ++it) {
1106 if (it->get() == query) {
1107 pending_queries_.erase(it);
1108 break;
1111 for (QueryQueue::iterator it = pending_transfer_queries_.begin();
1112 it != pending_transfer_queries_.end(); ++it) {
1113 if (it->get() == query) {
1114 pending_transfer_queries_.erase(it);
1115 break;
1118 if (!query->MarkAsCompleted(0)) {
1119 return false;
1122 return true;
1125 bool QueryManager::BeginQuery(Query* query) {
1126 DCHECK(query);
1127 if (!RemovePendingQuery(query)) {
1128 return false;
1130 if (query->Begin()) {
1131 active_queries_[query->target()] = query;
1132 return true;
1135 return false;
1138 bool QueryManager::EndQuery(Query* query, base::subtle::Atomic32 submit_count) {
1139 DCHECK(query);
1140 if (!RemovePendingQuery(query)) {
1141 return false;
1144 // Remove from active query map if it is active.
1145 ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
1146 DCHECK(active_it != active_queries_.end());
1147 DCHECK(query == active_it->second.get());
1148 active_queries_.erase(active_it);
1150 return query->End(submit_count);
1153 bool QueryManager::QueryCounter(
1154 Query* query, base::subtle::Atomic32 submit_count) {
1155 DCHECK(query);
1156 return query->QueryCounter(submit_count);
1159 void QueryManager::PauseQueries() {
1160 for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
1161 if (it.second->IsActive()) {
1162 it.second->Pause();
1163 DCHECK(it.second->IsPaused());
1168 void QueryManager::ResumeQueries() {
1169 for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
1170 if (it.second->IsPaused()) {
1171 it.second->Resume();
1172 DCHECK(it.second->IsActive());
1177 } // namespace gles2
1178 } // namespace gpu