Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / gpu / command_buffer / service / query_manager.cc
blob6700f78ced8fcb270f9d9f0502ccf8efefd97e05
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 MarkAsActive();
620 gpu_timer_->Start();
621 return true;
624 bool TimeElapsedQuery::End(base::subtle::Atomic32 submit_count) {
625 gpu_timer_->End();
626 return AddToPendingQueue(submit_count);
629 bool TimeElapsedQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
630 NOTREACHED();
631 return false;
634 void TimeElapsedQuery::Pause() {
635 MarkAsPaused();
638 void TimeElapsedQuery::Resume() {
639 MarkAsActive();
642 bool TimeElapsedQuery::Process(bool did_finish) {
643 if (!gpu_timer_->IsAvailable())
644 return true;
646 const uint64_t nano_seconds = gpu_timer_->GetDeltaElapsed() *
647 base::Time::kNanosecondsPerMicrosecond;
648 return MarkAsCompleted(nano_seconds);
651 void TimeElapsedQuery::Destroy(bool have_context) {
652 gpu_timer_->Destroy(have_context);
655 TimeElapsedQuery::~TimeElapsedQuery() {}
657 class TimeStampQuery : public QueryManager::Query {
658 public:
659 TimeStampQuery(QueryManager* manager,
660 GLenum target,
661 int32 shm_id,
662 uint32 shm_offset);
664 // Overridden from QueryManager::Query:
665 bool Begin() override;
666 bool End(base::subtle::Atomic32 submit_count) override;
667 bool QueryCounter(base::subtle::Atomic32 submit_count) override;
668 void Pause() override;
669 void Resume() override;
670 bool Process(bool did_finish) override;
671 void Destroy(bool have_context) override;
673 protected:
674 ~TimeStampQuery() override;
676 private:
677 scoped_ptr<gfx::GPUTimer> gpu_timer_;
680 TimeStampQuery::TimeStampQuery(QueryManager* manager,
681 GLenum target,
682 int32 shm_id,
683 uint32 shm_offset)
684 : Query(manager, target, shm_id, shm_offset),
685 gpu_timer_(manager->CreateGPUTimer(false)) {}
687 bool TimeStampQuery::Begin() {
688 NOTREACHED();
689 return false;
692 bool TimeStampQuery::End(base::subtle::Atomic32 submit_count) {
693 NOTREACHED();
694 return false;
697 void TimeStampQuery::Pause() {
698 MarkAsPaused();
701 void TimeStampQuery::Resume() {
702 MarkAsActive();
705 bool TimeStampQuery::QueryCounter(base::subtle::Atomic32 submit_count) {
706 MarkAsActive();
707 gpu_timer_->QueryTimeStamp();
708 return AddToPendingQueue(submit_count);
711 bool TimeStampQuery::Process(bool did_finish) {
712 if (!gpu_timer_->IsAvailable())
713 return true;
715 int64_t start = 0;
716 int64_t end = 0;
717 gpu_timer_->GetStartEndTimestamps(&start, &end);
718 DCHECK(start == end);
720 const uint64_t nano_seconds = start * base::Time::kNanosecondsPerMicrosecond;
721 return MarkAsCompleted(nano_seconds);
724 void TimeStampQuery::Destroy(bool have_context) {
725 if (gpu_timer_.get()) {
726 gpu_timer_->Destroy(have_context);
727 gpu_timer_.reset();
731 TimeStampQuery::~TimeStampQuery() {}
733 QueryManager::QueryManager(
734 GLES2Decoder* decoder,
735 FeatureInfo* feature_info)
736 : decoder_(decoder),
737 use_arb_occlusion_query2_for_occlusion_query_boolean_(
738 feature_info->feature_flags(
739 ).use_arb_occlusion_query2_for_occlusion_query_boolean),
740 use_arb_occlusion_query_for_occlusion_query_boolean_(
741 feature_info->feature_flags(
742 ).use_arb_occlusion_query_for_occlusion_query_boolean),
743 query_count_(0) {
744 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_ &&
745 use_arb_occlusion_query2_for_occlusion_query_boolean_));
746 DCHECK(decoder);
747 gfx::GLContext* context = decoder_->GetGLContext();
748 if (context) {
749 gpu_timing_client_ = context->CreateGPUTimingClient();
750 } else {
751 gpu_timing_client_ = new gfx::GPUTimingClient();
755 QueryManager::~QueryManager() {
756 DCHECK(queries_.empty());
758 // If this triggers, that means something is keeping a reference to
759 // a Query belonging to this.
760 CHECK_EQ(query_count_, 0u);
763 void QueryManager::Destroy(bool have_context) {
764 pending_queries_.clear();
765 pending_transfer_queries_.clear();
766 while (!queries_.empty()) {
767 Query* query = queries_.begin()->second.get();
768 query->Destroy(have_context);
769 queries_.erase(queries_.begin());
773 QueryManager::Query* QueryManager::CreateQuery(
774 GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) {
775 scoped_refptr<Query> query;
776 switch (target) {
777 case GL_COMMANDS_ISSUED_CHROMIUM:
778 query = new CommandsIssuedQuery(this, target, shm_id, shm_offset);
779 break;
780 case GL_LATENCY_QUERY_CHROMIUM:
781 query = new CommandLatencyQuery(this, target, shm_id, shm_offset);
782 break;
783 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
784 // Currently async pixel transfer delegates only support uploads.
785 query = new AsyncPixelTransfersCompletedQuery(
786 this, target, shm_id, shm_offset);
787 break;
788 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
789 query = new AsyncReadPixelsCompletedQuery(
790 this, target, shm_id, shm_offset);
791 break;
792 case GL_GET_ERROR_QUERY_CHROMIUM:
793 query = new GetErrorQuery(this, target, shm_id, shm_offset);
794 break;
795 case GL_COMMANDS_COMPLETED_CHROMIUM:
796 query = new CommandsCompletedQuery(this, target, shm_id, shm_offset);
797 break;
798 case GL_TIME_ELAPSED:
799 query = new TimeElapsedQuery(this, target, shm_id, shm_offset);
800 break;
801 case GL_TIMESTAMP:
802 query = new TimeStampQuery(this, target, shm_id, shm_offset);
803 break;
804 default: {
805 query = new AllSamplesPassedQuery(this, target, shm_id, shm_offset);
806 break;
809 std::pair<QueryMap::iterator, bool> result =
810 queries_.insert(std::make_pair(client_id, query));
811 DCHECK(result.second);
812 return query.get();
815 scoped_ptr<gfx::GPUTimer> QueryManager::CreateGPUTimer(bool elapsed_time) {
816 return gpu_timing_client_->CreateGPUTimer(elapsed_time);
819 bool QueryManager::GPUTimingAvailable() {
820 return gpu_timing_client_->IsAvailable();
823 void QueryManager::GenQueries(GLsizei n, const GLuint* queries) {
824 DCHECK_GE(n, 0);
825 for (GLsizei i = 0; i < n; ++i) {
826 generated_query_ids_.insert(queries[i]);
830 bool QueryManager::IsValidQuery(GLuint id) {
831 GeneratedQueryIds::iterator it = generated_query_ids_.find(id);
832 return it != generated_query_ids_.end();
835 QueryManager::Query* QueryManager::GetQuery(GLuint client_id) {
836 QueryMap::iterator it = queries_.find(client_id);
837 return it != queries_.end() ? it->second.get() : nullptr;
840 QueryManager::Query* QueryManager::GetActiveQuery(GLenum target) {
841 ActiveQueryMap::iterator it = active_queries_.find(target);
842 return it != active_queries_.end() ? it->second.get() : nullptr;
845 void QueryManager::RemoveQuery(GLuint client_id) {
846 QueryMap::iterator it = queries_.find(client_id);
847 if (it != queries_.end()) {
848 Query* query = it->second.get();
850 // Remove from active query map if it is active.
851 ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
852 bool is_active = (active_it != active_queries_.end() &&
853 query == active_it->second.get());
854 DCHECK(is_active == query->IsActive());
855 if (is_active)
856 active_queries_.erase(active_it);
858 query->Destroy(true);
859 RemovePendingQuery(query);
860 query->MarkAsDeleted();
861 queries_.erase(it);
863 generated_query_ids_.erase(client_id);
866 void QueryManager::StartTracking(QueryManager::Query* /* query */) {
867 ++query_count_;
870 void QueryManager::StopTracking(QueryManager::Query* /* query */) {
871 --query_count_;
874 GLenum QueryManager::AdjustTargetForEmulation(GLenum target) {
875 switch (target) {
876 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
877 case GL_ANY_SAMPLES_PASSED_EXT:
878 if (use_arb_occlusion_query2_for_occlusion_query_boolean_) {
879 // ARB_occlusion_query2 does not have a
880 // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
881 // target.
882 target = GL_ANY_SAMPLES_PASSED_EXT;
883 } else if (use_arb_occlusion_query_for_occlusion_query_boolean_) {
884 // ARB_occlusion_query does not have a
885 // GL_ANY_SAMPLES_PASSED_EXT
886 // target.
887 target = GL_SAMPLES_PASSED_ARB;
889 break;
890 default:
891 break;
893 return target;
896 void QueryManager::BeginQueryHelper(GLenum target, GLuint id) {
897 target = AdjustTargetForEmulation(target);
898 glBeginQuery(target, id);
901 void QueryManager::EndQueryHelper(GLenum target) {
902 target = AdjustTargetForEmulation(target);
903 glEndQuery(target);
906 QueryManager::Query::Query(
907 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
908 : manager_(manager),
909 target_(target),
910 shm_id_(shm_id),
911 shm_offset_(shm_offset),
912 submit_count_(0),
913 query_state_(kQueryState_Initialize),
914 deleted_(false) {
915 DCHECK(manager);
916 manager_->StartTracking(this);
919 void QueryManager::Query::RunCallbacks() {
920 for (size_t i = 0; i < callbacks_.size(); i++) {
921 callbacks_[i].Run();
923 callbacks_.clear();
926 void QueryManager::Query::AddCallback(base::Closure callback) {
927 if (query_state_ == kQueryState_Pending) {
928 callbacks_.push_back(callback);
929 } else {
930 callback.Run();
934 QueryManager::Query::~Query() {
935 // The query is getting deleted, either by the client or
936 // because the context was lost. Call any outstanding
937 // callbacks to avoid leaks.
938 RunCallbacks();
939 if (manager_) {
940 manager_->StopTracking(this);
941 manager_ = NULL;
945 bool QueryManager::Query::MarkAsCompleted(uint64 result) {
946 UnmarkAsPending();
947 QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>(
948 shm_id_, shm_offset_, sizeof(*sync));
949 if (!sync) {
950 return false;
953 sync->result = result;
954 base::subtle::Release_Store(&sync->process_count, submit_count_);
956 return true;
959 bool QueryManager::ProcessPendingQueries(bool did_finish) {
960 while (!pending_queries_.empty()) {
961 Query* query = pending_queries_.front().get();
962 if (!query->Process(did_finish)) {
963 return false;
965 if (query->IsPending()) {
966 break;
968 query->RunCallbacks();
969 pending_queries_.pop_front();
971 // If glFinish() has been called, all of our queries should be completed.
972 #if defined(OS_MACOSX)
973 // TODO(dyen): Remove once we know what is failing.
974 CHECK(!did_finish || pending_queries_.empty());
975 #else
976 DCHECK(!did_finish || pending_queries_.empty());
977 #endif
979 return true;
982 bool QueryManager::HavePendingQueries() {
983 return !pending_queries_.empty();
986 bool QueryManager::ProcessPendingTransferQueries() {
987 while (!pending_transfer_queries_.empty()) {
988 Query* query = pending_transfer_queries_.front().get();
989 if (!query->Process(false)) {
990 return false;
992 if (query->IsPending()) {
993 break;
995 query->RunCallbacks();
996 pending_transfer_queries_.pop_front();
999 return true;
1002 bool QueryManager::HavePendingTransferQueries() {
1003 return !pending_transfer_queries_.empty();
1006 bool QueryManager::AddPendingQuery(Query* query,
1007 base::subtle::Atomic32 submit_count) {
1008 DCHECK(query);
1009 DCHECK(!query->IsDeleted());
1010 if (!RemovePendingQuery(query)) {
1011 return false;
1013 query->MarkAsPending(submit_count);
1014 pending_queries_.push_back(query);
1015 return true;
1018 bool QueryManager::AddPendingTransferQuery(
1019 Query* query,
1020 base::subtle::Atomic32 submit_count) {
1021 DCHECK(query);
1022 DCHECK(!query->IsDeleted());
1023 if (!RemovePendingQuery(query)) {
1024 return false;
1026 query->MarkAsPending(submit_count);
1027 pending_transfer_queries_.push_back(query);
1028 return true;
1031 bool QueryManager::RemovePendingQuery(Query* query) {
1032 DCHECK(query);
1033 if (query->IsPending()) {
1034 // TODO(gman): Speed this up if this is a common operation. This would only
1035 // happen if you do being/end begin/end on the same query without waiting
1036 // for the first one to finish.
1037 for (QueryQueue::iterator it = pending_queries_.begin();
1038 it != pending_queries_.end(); ++it) {
1039 if (it->get() == query) {
1040 pending_queries_.erase(it);
1041 break;
1044 for (QueryQueue::iterator it = pending_transfer_queries_.begin();
1045 it != pending_transfer_queries_.end(); ++it) {
1046 if (it->get() == query) {
1047 pending_transfer_queries_.erase(it);
1048 break;
1051 if (!query->MarkAsCompleted(0)) {
1052 return false;
1055 return true;
1058 bool QueryManager::BeginQuery(Query* query) {
1059 DCHECK(query);
1060 if (!RemovePendingQuery(query)) {
1061 return false;
1063 if (query->Begin()) {
1064 active_queries_[query->target()] = query;
1065 return true;
1068 return false;
1071 bool QueryManager::EndQuery(Query* query, base::subtle::Atomic32 submit_count) {
1072 DCHECK(query);
1073 if (!RemovePendingQuery(query)) {
1074 return false;
1077 // Remove from active query map if it is active.
1078 ActiveQueryMap::iterator active_it = active_queries_.find(query->target());
1079 DCHECK(active_it != active_queries_.end());
1080 DCHECK(query == active_it->second.get());
1081 active_queries_.erase(active_it);
1083 return query->End(submit_count);
1086 bool QueryManager::QueryCounter(
1087 Query* query, base::subtle::Atomic32 submit_count) {
1088 DCHECK(query);
1089 return query->QueryCounter(submit_count);
1092 void QueryManager::PauseQueries() {
1093 for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
1094 if (it.second->IsActive()) {
1095 it.second->Pause();
1096 DCHECK(it.second->IsPaused());
1101 void QueryManager::ResumeQueries() {
1102 for (std::pair<const GLenum, scoped_refptr<Query> >& it : active_queries_) {
1103 if (it.second->IsPaused()) {
1104 it.second->Resume();
1105 DCHECK(it.second->IsActive());
1110 } // namespace gles2
1111 } // namespace gpu