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"
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"
28 class AsyncPixelTransferCompletionObserverImpl
29 : public AsyncPixelTransferCompletionObserver
{
31 AsyncPixelTransferCompletionObserverImpl(base::subtle::Atomic32 submit_count
)
32 : submit_count_(submit_count
), cancelled_(false) {}
35 base::AutoLock
locked(lock_
);
39 void DidComplete(const AsyncMemoryParams
& mem_params
) override
{
40 base::AutoLock
locked(lock_
);
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_
);
50 ~AsyncPixelTransferCompletionObserverImpl() override
{}
52 base::subtle::Atomic32 submit_count_
;
57 DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferCompletionObserverImpl
);
60 class AsyncPixelTransfersCompletedQuery
61 : public QueryManager::Query
,
62 public base::SupportsWeakPtr
<AsyncPixelTransfersCompletedQuery
> {
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
;
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() {
91 void AsyncPixelTransfersCompletedQuery::Pause() {
95 void AsyncPixelTransfersCompletedQuery::Resume() {
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());
107 AsyncMemoryParams
mem_params(buffer
, shm_offset(), sizeof(QuerySync
));
108 if (!mem_params
.GetDataAddress())
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
) {
128 bool AsyncPixelTransfersCompletedQuery::Process(bool did_finish
) {
129 QuerySync
* sync
= manager()->decoder()->GetSharedMemoryAs
<QuerySync
*>(
130 shm_id(), shm_offset(), sizeof(*sync
));
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
137 if (base::subtle::Acquire_Load(&sync
->process_count
) != submit_count())
144 void AsyncPixelTransfersCompletedQuery::Destroy(bool /* have_context */) {
150 AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() {
157 class AllSamplesPassedQuery
: public QueryManager::Query
{
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
;
170 ~AllSamplesPassedQuery() override
;
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() {
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());
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
) {
207 void AllSamplesPassedQuery::Pause() {
209 EndQueryHelper(target());
212 void AllSamplesPassedQuery::Resume() {
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;
225 service_ids_
.back(), GL_QUERY_RESULT_AVAILABLE_EXT
, &available
);
229 for (const GLuint
& service_id
: service_ids_
) {
231 glGetQueryObjectuiv(service_id
, GL_QUERY_RESULT_EXT
, &result
);
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();
246 AllSamplesPassedQuery::~AllSamplesPassedQuery() {
249 class CommandsIssuedQuery
: public QueryManager::Query
{
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
;
263 ~CommandsIssuedQuery() override
;
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() {
276 begin_time_
= base::TimeTicks::Now();
280 void CommandsIssuedQuery::Pause() {
284 void CommandsIssuedQuery::Resume() {
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
) {
299 bool CommandsIssuedQuery::Process(bool did_finish
) {
304 void CommandsIssuedQuery::Destroy(bool /* have_context */) {
310 CommandsIssuedQuery::~CommandsIssuedQuery() {
313 class CommandLatencyQuery
: public QueryManager::Query
{
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
;
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() {
340 void CommandLatencyQuery::Pause() {
344 void CommandLatencyQuery::Resume() {
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
) {
359 bool CommandLatencyQuery::Process(bool did_finish
) {
364 void CommandLatencyQuery::Destroy(bool /* have_context */) {
370 CommandLatencyQuery::~CommandLatencyQuery() {
374 class AsyncReadPixelsCompletedQuery
375 : public QueryManager::Query
,
376 public base::SupportsWeakPtr
<AsyncReadPixelsCompletedQuery
> {
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
;
391 ~AsyncReadPixelsCompletedQuery() override
;
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() {
408 void AsyncReadPixelsCompletedQuery::Pause() {
412 void AsyncReadPixelsCompletedQuery::Resume() {
416 bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count
) {
417 if (!AddToPendingQueue(submit_count
)) {
420 manager()->decoder()->WaitForReadPixels(
421 base::Bind(&AsyncReadPixelsCompletedQuery::Complete
,
424 return Process(false);
427 bool AsyncReadPixelsCompletedQuery::QueryCounter(
428 base::subtle::Atomic32 submit_count
) {
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 */) {
447 AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
451 class GetErrorQuery
: public QueryManager::Query
{
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
;
465 ~GetErrorQuery() override
;
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() {
480 void GetErrorQuery::Pause() {
484 void GetErrorQuery::Resume() {
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
) {
498 bool GetErrorQuery::Process(bool did_finish
) {
503 void GetErrorQuery::Destroy(bool /* have_context */) {
509 GetErrorQuery::~GetErrorQuery() {
512 class CommandsCompletedQuery
: public QueryManager::Query
{
514 CommandsCompletedQuery(QueryManager
* manager
,
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
;
529 ~CommandsCompletedQuery() override
;
532 scoped_ptr
<gfx::GLFence
> fence_
;
533 base::TimeTicks begin_time_
;
536 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager
* manager
,
540 : Query(manager
, target
, shm_id
, shm_offset
) {}
542 bool CommandsCompletedQuery::Begin() {
544 begin_time_
= base::TimeTicks::Now();
548 void CommandsCompletedQuery::Pause() {
552 void CommandsCompletedQuery::Resume() {
556 bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count
) {
557 fence_
.reset(gfx::GLFence::Create());
559 return AddToPendingQueue(submit_count
);
562 bool CommandsCompletedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
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())
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()) {
585 CommandsCompletedQuery::~CommandsCompletedQuery() {}
587 class TimeElapsedQuery
: public QueryManager::Query
{
589 TimeElapsedQuery(QueryManager
* manager
,
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
;
604 ~TimeElapsedQuery() override
;
607 scoped_ptr
<gfx::GPUTimer
> gpu_timer_
;
610 TimeElapsedQuery::TimeElapsedQuery(QueryManager
* manager
,
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();
626 bool TimeElapsedQuery::End(base::subtle::Atomic32 submit_count
) {
628 return AddToPendingQueue(submit_count
);
631 bool TimeElapsedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
636 void TimeElapsedQuery::Pause() {
640 void TimeElapsedQuery::Resume() {
644 bool TimeElapsedQuery::Process(bool did_finish
) {
645 if (!gpu_timer_
->IsAvailable())
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
{
667 TimeStampQuery(QueryManager
* manager
,
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
;
682 ~TimeStampQuery() override
;
685 scoped_ptr
<gfx::GPUTimer
> gpu_timer_
;
688 TimeStampQuery::TimeStampQuery(QueryManager
* manager
,
692 : Query(manager
, target
, shm_id
, shm_offset
),
693 gpu_timer_(manager
->CreateGPUTimer(false)) {}
695 bool TimeStampQuery::Begin() {
700 bool TimeStampQuery::End(base::subtle::Atomic32 submit_count
) {
705 void TimeStampQuery::Pause() {
709 void TimeStampQuery::Resume() {
713 bool TimeStampQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
714 // Reset the disjoint value before the query begins if it is safe.
715 SafelyResetDisjointValue();
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())
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();
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
);
751 TimeStampQuery::~TimeStampQuery() {}
753 QueryManager::QueryManager(
754 GLES2Decoder
* decoder
,
755 FeatureInfo
* feature_info
)
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),
768 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_
&&
769 use_arb_occlusion_query2_for_occlusion_query_boolean_
));
771 gfx::GLContext
* context
= decoder_
->GetGLContext();
773 gpu_timing_client_
= context
->CreateGPUTimingClient();
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
));
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
;
817 case GL_COMMANDS_ISSUED_CHROMIUM
:
818 query
= new CommandsIssuedQuery(this, target
, shm_id
, shm_offset
);
820 case GL_LATENCY_QUERY_CHROMIUM
:
821 query
= new CommandLatencyQuery(this, target
, shm_id
, shm_offset
);
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
);
828 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
:
829 query
= new AsyncReadPixelsCompletedQuery(
830 this, target
, shm_id
, shm_offset
);
832 case GL_GET_ERROR_QUERY_CHROMIUM
:
833 query
= new GetErrorQuery(this, target
, shm_id
, shm_offset
);
835 case GL_COMMANDS_COMPLETED_CHROMIUM
:
836 query
= new CommandsCompletedQuery(this, target
, shm_id
, shm_offset
);
838 case GL_TIME_ELAPSED
:
839 query
= new TimeElapsedQuery(this, target
, shm_id
, shm_offset
);
842 query
= new TimeStampQuery(this, target
, shm_id
, shm_offset
);
845 query
= new AllSamplesPassedQuery(this, target
, shm_id
, shm_offset
);
849 std::pair
<QueryMap::iterator
, bool> result
=
850 queries_
.insert(std::make_pair(client_id
, query
));
851 DCHECK(result
.second
);
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
) {
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());
896 active_queries_
.erase(active_it
);
898 query
->Destroy(true);
899 RemovePendingQuery(query
);
900 query
->MarkAsDeleted();
903 generated_query_ids_
.erase(client_id
);
906 void QueryManager::StartTracking(QueryManager::Query
* /* query */) {
910 void QueryManager::StopTracking(QueryManager::Query
* /* query */) {
914 GLenum
QueryManager::AdjustTargetForEmulation(GLenum 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
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
927 target
= GL_SAMPLES_PASSED_ARB
;
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
);
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
));
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;
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
)
978 shm_offset_(shm_offset
),
980 query_state_(kQueryState_Initialize
),
983 manager_
->StartTracking(this);
986 void QueryManager::Query::RunCallbacks() {
987 for (size_t i
= 0; i
< callbacks_
.size(); i
++) {
993 void QueryManager::Query::AddCallback(base::Closure callback
) {
994 if (query_state_
== kQueryState_Pending
) {
995 callbacks_
.push_back(callback
);
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.
1007 manager_
->StopTracking(this);
1012 bool QueryManager::Query::MarkAsCompleted(uint64 result
) {
1014 QuerySync
* sync
= manager_
->decoder_
->GetSharedMemoryAs
<QuerySync
*>(
1015 shm_id_
, shm_offset_
, sizeof(*sync
));
1020 sync
->result
= result
;
1021 base::subtle::Release_Store(&sync
->process_count
, submit_count_
);
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
)) {
1032 if (query
->IsPending()) {
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());
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)) {
1054 if (query
->IsPending()) {
1057 query
->RunCallbacks();
1058 pending_transfer_queries_
.pop_front();
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
) {
1076 DCHECK(!query
->IsDeleted());
1077 if (!RemovePendingQuery(query
)) {
1080 query
->MarkAsPending(submit_count
);
1081 pending_queries_
.push_back(query
);
1085 bool QueryManager::AddPendingTransferQuery(
1087 base::subtle::Atomic32 submit_count
) {
1089 DCHECK(!query
->IsDeleted());
1090 if (!RemovePendingQuery(query
)) {
1093 query
->MarkAsPending(submit_count
);
1094 pending_transfer_queries_
.push_back(query
);
1098 bool QueryManager::RemovePendingQuery(Query
* 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
);
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
);
1118 if (!query
->MarkAsCompleted(0)) {
1125 bool QueryManager::BeginQuery(Query
* query
) {
1127 if (!RemovePendingQuery(query
)) {
1130 if (query
->Begin()) {
1131 active_queries_
[query
->target()] = query
;
1138 bool QueryManager::EndQuery(Query
* query
, base::subtle::Atomic32 submit_count
) {
1140 if (!RemovePendingQuery(query
)) {
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
) {
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()) {
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