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/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"
26 class AllSamplesPassedQuery
: public QueryManager::Query
{
28 AllSamplesPassedQuery(
29 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
30 bool Begin() override
;
31 bool End(base::subtle::Atomic32 submit_count
) override
;
32 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
33 void Pause() override
;
34 void Resume() override
;
35 bool Process(bool did_finish
) override
;
36 void Destroy(bool have_context
) override
;
39 ~AllSamplesPassedQuery() override
;
42 // Service side query id.
43 std::vector
<GLuint
> service_ids_
;
46 AllSamplesPassedQuery::AllSamplesPassedQuery(
47 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
48 : Query(manager
, target
, shm_id
, shm_offset
) {
49 GLuint service_id
= 0;
50 glGenQueries(1, &service_id
);
51 DCHECK_NE(0u, service_id
);
52 service_ids_
.push_back(service_id
);
55 bool AllSamplesPassedQuery::Begin() {
57 // Delete all but the first one when beginning a new query.
58 if (service_ids_
.size() > 1) {
59 glDeleteQueries(service_ids_
.size() - 1, &service_ids_
[1]);
60 service_ids_
.resize(1);
62 BeginQueryHelper(target(), service_ids_
.back());
66 bool AllSamplesPassedQuery::End(base::subtle::Atomic32 submit_count
) {
67 EndQueryHelper(target());
68 return AddToPendingQueue(submit_count
);
71 bool AllSamplesPassedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
76 void AllSamplesPassedQuery::Pause() {
78 EndQueryHelper(target());
81 void AllSamplesPassedQuery::Resume() {
84 GLuint service_id
= 0;
85 glGenQueries(1, &service_id
);
86 DCHECK_NE(0u, service_id
);
87 service_ids_
.push_back(service_id
);
88 BeginQueryHelper(target(), service_ids_
.back());
91 bool AllSamplesPassedQuery::Process(bool did_finish
) {
94 service_ids_
.back(), GL_QUERY_RESULT_AVAILABLE_EXT
, &available
);
98 for (const GLuint
& service_id
: service_ids_
) {
100 glGetQueryObjectuiv(service_id
, GL_QUERY_RESULT_EXT
, &result
);
102 return MarkAsCompleted(1);
104 return MarkAsCompleted(0);
107 void AllSamplesPassedQuery::Destroy(bool have_context
) {
108 if (have_context
&& !IsDeleted()) {
109 glDeleteQueries(service_ids_
.size(), &service_ids_
[0]);
110 service_ids_
.clear();
115 AllSamplesPassedQuery::~AllSamplesPassedQuery() {
118 class CommandsIssuedQuery
: public QueryManager::Query
{
121 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
123 bool Begin() override
;
124 bool End(base::subtle::Atomic32 submit_count
) override
;
125 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
126 void Pause() override
;
127 void Resume() override
;
128 bool Process(bool did_finish
) override
;
129 void Destroy(bool have_context
) override
;
132 ~CommandsIssuedQuery() override
;
135 base::TimeTicks begin_time_
;
138 CommandsIssuedQuery::CommandsIssuedQuery(
139 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
140 : Query(manager
, target
, shm_id
, shm_offset
) {
143 bool CommandsIssuedQuery::Begin() {
145 begin_time_
= base::TimeTicks::Now();
149 void CommandsIssuedQuery::Pause() {
153 void CommandsIssuedQuery::Resume() {
157 bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count
) {
158 const base::TimeDelta elapsed
= base::TimeTicks::Now() - begin_time_
;
159 MarkAsPending(submit_count
);
160 return MarkAsCompleted(elapsed
.InMicroseconds());
163 bool CommandsIssuedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
168 bool CommandsIssuedQuery::Process(bool did_finish
) {
173 void CommandsIssuedQuery::Destroy(bool /* have_context */) {
179 CommandsIssuedQuery::~CommandsIssuedQuery() {
182 class CommandLatencyQuery
: public QueryManager::Query
{
185 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
187 bool Begin() override
;
188 bool End(base::subtle::Atomic32 submit_count
) override
;
189 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
190 void Pause() override
;
191 void Resume() override
;
192 bool Process(bool did_finish
) override
;
193 void Destroy(bool have_context
) override
;
196 ~CommandLatencyQuery() override
;
199 CommandLatencyQuery::CommandLatencyQuery(
200 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
201 : Query(manager
, target
, shm_id
, shm_offset
) {
204 bool CommandLatencyQuery::Begin() {
209 void CommandLatencyQuery::Pause() {
213 void CommandLatencyQuery::Resume() {
217 bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count
) {
218 base::TimeDelta now
= base::TimeTicks::Now() - base::TimeTicks();
219 MarkAsPending(submit_count
);
220 return MarkAsCompleted(now
.InMicroseconds());
223 bool CommandLatencyQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
228 bool CommandLatencyQuery::Process(bool did_finish
) {
233 void CommandLatencyQuery::Destroy(bool /* have_context */) {
239 CommandLatencyQuery::~CommandLatencyQuery() {
243 class AsyncReadPixelsCompletedQuery
244 : public QueryManager::Query
,
245 public base::SupportsWeakPtr
<AsyncReadPixelsCompletedQuery
> {
247 AsyncReadPixelsCompletedQuery(
248 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
250 bool Begin() override
;
251 bool End(base::subtle::Atomic32 submit_count
) override
;
252 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
253 void Pause() override
;
254 void Resume() override
;
255 bool Process(bool did_finish
) override
;
256 void Destroy(bool have_context
) override
;
260 ~AsyncReadPixelsCompletedQuery() override
;
263 bool complete_result_
;
266 AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
267 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
268 : Query(manager
, target
, shm_id
, shm_offset
),
269 complete_result_(false) {
272 bool AsyncReadPixelsCompletedQuery::Begin() {
277 void AsyncReadPixelsCompletedQuery::Pause() {
281 void AsyncReadPixelsCompletedQuery::Resume() {
285 bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count
) {
286 if (!AddToPendingQueue(submit_count
)) {
289 manager()->decoder()->WaitForReadPixels(
290 base::Bind(&AsyncReadPixelsCompletedQuery::Complete
,
293 return Process(false);
296 bool AsyncReadPixelsCompletedQuery::QueryCounter(
297 base::subtle::Atomic32 submit_count
) {
302 void AsyncReadPixelsCompletedQuery::Complete() {
303 complete_result_
= MarkAsCompleted(1);
306 bool AsyncReadPixelsCompletedQuery::Process(bool did_finish
) {
307 return !IsFinished() || complete_result_
;
310 void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
316 AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
320 class GetErrorQuery
: public QueryManager::Query
{
323 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
325 bool Begin() override
;
326 bool End(base::subtle::Atomic32 submit_count
) override
;
327 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
328 void Pause() override
;
329 void Resume() override
;
330 bool Process(bool did_finish
) override
;
331 void Destroy(bool have_context
) override
;
334 ~GetErrorQuery() override
;
339 GetErrorQuery::GetErrorQuery(
340 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
341 : Query(manager
, target
, shm_id
, shm_offset
) {
344 bool GetErrorQuery::Begin() {
349 void GetErrorQuery::Pause() {
353 void GetErrorQuery::Resume() {
357 bool GetErrorQuery::End(base::subtle::Atomic32 submit_count
) {
358 MarkAsPending(submit_count
);
359 return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
362 bool GetErrorQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
367 bool GetErrorQuery::Process(bool did_finish
) {
372 void GetErrorQuery::Destroy(bool /* have_context */) {
378 GetErrorQuery::~GetErrorQuery() {
381 class CommandsCompletedQuery
: public QueryManager::Query
{
383 CommandsCompletedQuery(QueryManager
* manager
,
388 // Overridden from QueryManager::Query:
389 bool Begin() override
;
390 bool End(base::subtle::Atomic32 submit_count
) override
;
391 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
392 void Pause() override
;
393 void Resume() override
;
394 bool Process(bool did_finish
) override
;
395 void Destroy(bool have_context
) override
;
398 ~CommandsCompletedQuery() override
;
401 scoped_ptr
<gfx::GLFence
> fence_
;
402 base::TimeTicks begin_time_
;
405 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager
* manager
,
409 : Query(manager
, target
, shm_id
, shm_offset
) {}
411 bool CommandsCompletedQuery::Begin() {
413 begin_time_
= base::TimeTicks::Now();
417 void CommandsCompletedQuery::Pause() {
421 void CommandsCompletedQuery::Resume() {
425 bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count
) {
426 fence_
.reset(gfx::GLFence::Create());
428 return AddToPendingQueue(submit_count
);
431 bool CommandsCompletedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
436 bool CommandsCompletedQuery::Process(bool did_finish
) {
437 // Note: |did_finish| guarantees that the GPU has passed the fence but
438 // we cannot assume that GLFence::HasCompleted() will return true yet as
439 // that's not guaranteed by all GLFence implementations.
440 if (!did_finish
&& fence_
&& !fence_
->HasCompleted())
443 const base::TimeDelta elapsed
= base::TimeTicks::Now() - begin_time_
;
444 return MarkAsCompleted(elapsed
.InMicroseconds());
447 void CommandsCompletedQuery::Destroy(bool have_context
) {
448 if (have_context
&& !IsDeleted()) {
454 CommandsCompletedQuery::~CommandsCompletedQuery() {}
456 class TimeElapsedQuery
: public QueryManager::Query
{
458 TimeElapsedQuery(QueryManager
* manager
,
463 // Overridden from QueryManager::Query:
464 bool Begin() override
;
465 bool End(base::subtle::Atomic32 submit_count
) override
;
466 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
467 void Pause() override
;
468 void Resume() override
;
469 bool Process(bool did_finish
) override
;
470 void Destroy(bool have_context
) override
;
473 ~TimeElapsedQuery() override
;
476 scoped_ptr
<gfx::GPUTimer
> gpu_timer_
;
479 TimeElapsedQuery::TimeElapsedQuery(QueryManager
* manager
,
483 : Query(manager
, target
, shm_id
, shm_offset
),
484 gpu_timer_(manager
->CreateGPUTimer(true)) {
487 bool TimeElapsedQuery::Begin() {
488 // Reset the disjoint value before the query begins if it is safe.
489 SafelyResetDisjointValue();
495 bool TimeElapsedQuery::End(base::subtle::Atomic32 submit_count
) {
497 return AddToPendingQueue(submit_count
);
500 bool TimeElapsedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
505 void TimeElapsedQuery::Pause() {
509 void TimeElapsedQuery::Resume() {
513 bool TimeElapsedQuery::Process(bool did_finish
) {
514 if (!gpu_timer_
->IsAvailable())
517 // Make sure disjoint value is up to date. This disjoint check is the only one
518 // that needs to be done to validate that this query is valid. If a disjoint
519 // occurs before the client checks the query value we will just hide the
520 // disjoint state since it did not affect this query.
521 UpdateDisjointValue();
523 const uint64_t nano_seconds
= gpu_timer_
->GetDeltaElapsed() *
524 base::Time::kNanosecondsPerMicrosecond
;
525 return MarkAsCompleted(nano_seconds
);
528 void TimeElapsedQuery::Destroy(bool have_context
) {
529 gpu_timer_
->Destroy(have_context
);
532 TimeElapsedQuery::~TimeElapsedQuery() {}
534 class TimeStampQuery
: public QueryManager::Query
{
536 TimeStampQuery(QueryManager
* manager
,
541 // Overridden from QueryManager::Query:
542 bool Begin() override
;
543 bool End(base::subtle::Atomic32 submit_count
) override
;
544 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
545 void Pause() override
;
546 void Resume() override
;
547 bool Process(bool did_finish
) override
;
548 void Destroy(bool have_context
) override
;
551 ~TimeStampQuery() override
;
554 scoped_ptr
<gfx::GPUTimer
> gpu_timer_
;
557 TimeStampQuery::TimeStampQuery(QueryManager
* manager
,
561 : Query(manager
, target
, shm_id
, shm_offset
),
562 gpu_timer_(manager
->CreateGPUTimer(false)) {}
564 bool TimeStampQuery::Begin() {
569 bool TimeStampQuery::End(base::subtle::Atomic32 submit_count
) {
574 void TimeStampQuery::Pause() {
578 void TimeStampQuery::Resume() {
582 bool TimeStampQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
583 // Reset the disjoint value before the query begins if it is safe.
584 SafelyResetDisjointValue();
586 // After a timestamp has begun, we will want to continually detect
587 // the disjoint value every frame until the context is destroyed.
588 BeginContinualDisjointUpdate();
590 gpu_timer_
->QueryTimeStamp();
591 return AddToPendingQueue(submit_count
);
594 bool TimeStampQuery::Process(bool did_finish
) {
595 if (!gpu_timer_
->IsAvailable())
598 // Make sure disjoint value is up to date. This disjoint check is the only one
599 // that needs to be done to validate that this query is valid. If a disjoint
600 // occurs before the client checks the query value we will just hide the
601 // disjoint state since it did not affect this query.
602 UpdateDisjointValue();
606 gpu_timer_
->GetStartEndTimestamps(&start
, &end
);
607 DCHECK(start
== end
);
609 const uint64_t nano_seconds
= start
* base::Time::kNanosecondsPerMicrosecond
;
610 return MarkAsCompleted(nano_seconds
);
613 void TimeStampQuery::Destroy(bool have_context
) {
614 if (gpu_timer_
.get()) {
615 gpu_timer_
->Destroy(have_context
);
620 TimeStampQuery::~TimeStampQuery() {}
622 QueryManager::QueryManager(
623 GLES2Decoder
* decoder
,
624 FeatureInfo
* feature_info
)
626 use_arb_occlusion_query2_for_occlusion_query_boolean_(
627 feature_info
->feature_flags(
628 ).use_arb_occlusion_query2_for_occlusion_query_boolean
),
629 use_arb_occlusion_query_for_occlusion_query_boolean_(
630 feature_info
->feature_flags(
631 ).use_arb_occlusion_query_for_occlusion_query_boolean
),
632 update_disjoints_continually_(false),
633 disjoint_notify_shm_id_(-1),
634 disjoint_notify_shm_offset_(0),
635 disjoints_notified_(0),
637 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_
&&
638 use_arb_occlusion_query2_for_occlusion_query_boolean_
));
640 gfx::GLContext
* context
= decoder_
->GetGLContext();
642 gpu_timing_client_
= context
->CreateGPUTimingClient();
644 gpu_timing_client_
= new gfx::GPUTimingClient();
648 QueryManager::~QueryManager() {
649 DCHECK(queries_
.empty());
651 // If this triggers, that means something is keeping a reference to
652 // a Query belonging to this.
653 CHECK_EQ(query_count_
, 0u);
656 void QueryManager::Destroy(bool have_context
) {
657 active_queries_
.clear();
658 pending_queries_
.clear();
659 pending_transfer_queries_
.clear();
660 active_queries_
.clear();
661 while (!queries_
.empty()) {
662 Query
* query
= queries_
.begin()->second
.get();
663 query
->Destroy(have_context
);
664 queries_
.erase(queries_
.begin());
668 void QueryManager::SetDisjointSync(int32 shm_id
, uint32 shm_offset
) {
669 DCHECK(disjoint_notify_shm_id_
== -1);
670 DCHECK(shm_id
!= -1);
672 DisjointValueSync
* sync
= decoder_
->GetSharedMemoryAs
<DisjointValueSync
*>(
673 shm_id
, shm_offset
, sizeof(*sync
));
676 disjoints_notified_
= 0;
678 disjoint_notify_shm_id_
= shm_id
;
679 disjoint_notify_shm_offset_
= shm_offset
;
682 QueryManager::Query
* QueryManager::CreateQuery(
683 GLenum target
, GLuint client_id
, int32 shm_id
, uint32 shm_offset
) {
684 scoped_refptr
<Query
> query
;
686 case GL_COMMANDS_ISSUED_CHROMIUM
:
687 query
= new CommandsIssuedQuery(this, target
, shm_id
, shm_offset
);
689 case GL_LATENCY_QUERY_CHROMIUM
:
690 query
= new CommandLatencyQuery(this, target
, shm_id
, shm_offset
);
692 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
:
693 query
= new AsyncReadPixelsCompletedQuery(
694 this, target
, shm_id
, shm_offset
);
696 case GL_GET_ERROR_QUERY_CHROMIUM
:
697 query
= new GetErrorQuery(this, target
, shm_id
, shm_offset
);
699 case GL_COMMANDS_COMPLETED_CHROMIUM
:
700 query
= new CommandsCompletedQuery(this, target
, shm_id
, shm_offset
);
702 case GL_TIME_ELAPSED
:
703 query
= new TimeElapsedQuery(this, target
, shm_id
, shm_offset
);
706 query
= new TimeStampQuery(this, target
, shm_id
, shm_offset
);
709 query
= new AllSamplesPassedQuery(this, target
, shm_id
, shm_offset
);
713 std::pair
<QueryMap::iterator
, bool> result
=
714 queries_
.insert(std::make_pair(client_id
, query
));
715 DCHECK(result
.second
);
719 scoped_ptr
<gfx::GPUTimer
> QueryManager::CreateGPUTimer(bool elapsed_time
) {
720 return gpu_timing_client_
->CreateGPUTimer(elapsed_time
);
723 bool QueryManager::GPUTimingAvailable() {
724 return gpu_timing_client_
->IsAvailable();
727 void QueryManager::GenQueries(GLsizei n
, const GLuint
* queries
) {
729 for (GLsizei i
= 0; i
< n
; ++i
) {
730 generated_query_ids_
.insert(queries
[i
]);
734 bool QueryManager::IsValidQuery(GLuint id
) {
735 GeneratedQueryIds::iterator it
= generated_query_ids_
.find(id
);
736 return it
!= generated_query_ids_
.end();
739 QueryManager::Query
* QueryManager::GetQuery(GLuint client_id
) {
740 QueryMap::iterator it
= queries_
.find(client_id
);
741 return it
!= queries_
.end() ? it
->second
.get() : nullptr;
744 QueryManager::Query
* QueryManager::GetActiveQuery(GLenum target
) {
745 ActiveQueryMap::iterator it
= active_queries_
.find(target
);
746 return it
!= active_queries_
.end() ? it
->second
.get() : nullptr;
749 void QueryManager::RemoveQuery(GLuint client_id
) {
750 QueryMap::iterator it
= queries_
.find(client_id
);
751 if (it
!= queries_
.end()) {
752 Query
* query
= it
->second
.get();
754 // Remove from active query map if it is active.
755 ActiveQueryMap::iterator active_it
= active_queries_
.find(query
->target());
756 bool is_active
= (active_it
!= active_queries_
.end() &&
757 query
== active_it
->second
.get());
758 DCHECK(is_active
== query
->IsActive());
760 active_queries_
.erase(active_it
);
762 query
->Destroy(true);
763 RemovePendingQuery(query
);
764 query
->MarkAsDeleted();
767 generated_query_ids_
.erase(client_id
);
770 void QueryManager::StartTracking(QueryManager::Query
* /* query */) {
774 void QueryManager::StopTracking(QueryManager::Query
* /* query */) {
778 GLenum
QueryManager::AdjustTargetForEmulation(GLenum target
) {
780 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
:
781 case GL_ANY_SAMPLES_PASSED_EXT
:
782 if (use_arb_occlusion_query2_for_occlusion_query_boolean_
) {
783 // ARB_occlusion_query2 does not have a
784 // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
786 target
= GL_ANY_SAMPLES_PASSED_EXT
;
787 } else if (use_arb_occlusion_query_for_occlusion_query_boolean_
) {
788 // ARB_occlusion_query does not have a
789 // GL_ANY_SAMPLES_PASSED_EXT
791 target
= GL_SAMPLES_PASSED_ARB
;
800 void QueryManager::BeginQueryHelper(GLenum target
, GLuint id
) {
801 target
= AdjustTargetForEmulation(target
);
802 glBeginQuery(target
, id
);
805 void QueryManager::EndQueryHelper(GLenum target
) {
806 target
= AdjustTargetForEmulation(target
);
810 void QueryManager::UpdateDisjointValue() {
811 if (disjoint_notify_shm_id_
!= -1) {
812 if (gpu_timing_client_
->CheckAndResetTimerErrors()) {
813 disjoints_notified_
++;
815 DisjointValueSync
* sync
= decoder_
->GetSharedMemoryAs
<DisjointValueSync
*>(
816 disjoint_notify_shm_id_
, disjoint_notify_shm_offset_
, sizeof(*sync
));
818 // Shared memory does not seem to be valid, ignore the shm id/offset.
819 disjoint_notify_shm_id_
= -1;
820 disjoint_notify_shm_offset_
= 0;
822 sync
->SetDisjointCount(disjoints_notified_
);
828 void QueryManager::SafelyResetDisjointValue() {
829 // It is only safe to reset the disjoint value is there is no active
830 // elapsed timer and we are not continually updating the disjoint value.
831 if (!update_disjoints_continually_
&& !GetActiveQuery(GL_TIME_ELAPSED
)) {
832 // Reset the error state without storing the result.
833 gpu_timing_client_
->CheckAndResetTimerErrors();
837 QueryManager::Query::Query(
838 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
842 shm_offset_(shm_offset
),
844 query_state_(kQueryState_Initialize
),
847 manager_
->StartTracking(this);
850 void QueryManager::Query::RunCallbacks() {
851 for (size_t i
= 0; i
< callbacks_
.size(); i
++) {
857 void QueryManager::Query::AddCallback(base::Closure callback
) {
858 if (query_state_
== kQueryState_Pending
) {
859 callbacks_
.push_back(callback
);
865 QueryManager::Query::~Query() {
866 // The query is getting deleted, either by the client or
867 // because the context was lost. Call any outstanding
868 // callbacks to avoid leaks.
871 manager_
->StopTracking(this);
876 bool QueryManager::Query::MarkAsCompleted(uint64 result
) {
878 QuerySync
* sync
= manager_
->decoder_
->GetSharedMemoryAs
<QuerySync
*>(
879 shm_id_
, shm_offset_
, sizeof(*sync
));
884 sync
->result
= result
;
885 base::subtle::Release_Store(&sync
->process_count
, submit_count_
);
890 bool QueryManager::ProcessPendingQueries(bool did_finish
) {
891 while (!pending_queries_
.empty()) {
892 Query
* query
= pending_queries_
.front().get();
893 if (!query
->Process(did_finish
)) {
896 if (query
->IsPending()) {
899 query
->RunCallbacks();
900 pending_queries_
.pop_front();
902 // If glFinish() has been called, all of our queries should be completed.
903 DCHECK(!did_finish
|| pending_queries_
.empty());
908 bool QueryManager::HavePendingQueries() {
909 return !pending_queries_
.empty();
912 bool QueryManager::ProcessPendingTransferQueries() {
913 while (!pending_transfer_queries_
.empty()) {
914 Query
* query
= pending_transfer_queries_
.front().get();
915 if (!query
->Process(false)) {
918 if (query
->IsPending()) {
921 query
->RunCallbacks();
922 pending_transfer_queries_
.pop_front();
928 bool QueryManager::HavePendingTransferQueries() {
929 return !pending_transfer_queries_
.empty();
932 void QueryManager::ProcessFrameBeginUpdates() {
933 if (update_disjoints_continually_
)
934 UpdateDisjointValue();
937 bool QueryManager::AddPendingQuery(Query
* query
,
938 base::subtle::Atomic32 submit_count
) {
940 DCHECK(!query
->IsDeleted());
941 if (!RemovePendingQuery(query
)) {
944 query
->MarkAsPending(submit_count
);
945 pending_queries_
.push_back(query
);
949 bool QueryManager::AddPendingTransferQuery(
951 base::subtle::Atomic32 submit_count
) {
953 DCHECK(!query
->IsDeleted());
954 if (!RemovePendingQuery(query
)) {
957 query
->MarkAsPending(submit_count
);
958 pending_transfer_queries_
.push_back(query
);
962 bool QueryManager::RemovePendingQuery(Query
* query
) {
964 if (query
->IsPending()) {
965 // TODO(gman): Speed this up if this is a common operation. This would only
966 // happen if you do being/end begin/end on the same query without waiting
967 // for the first one to finish.
968 for (QueryQueue::iterator it
= pending_queries_
.begin();
969 it
!= pending_queries_
.end(); ++it
) {
970 if (it
->get() == query
) {
971 pending_queries_
.erase(it
);
975 for (QueryQueue::iterator it
= pending_transfer_queries_
.begin();
976 it
!= pending_transfer_queries_
.end(); ++it
) {
977 if (it
->get() == query
) {
978 pending_transfer_queries_
.erase(it
);
982 if (!query
->MarkAsCompleted(0)) {
989 bool QueryManager::BeginQuery(Query
* query
) {
991 if (!RemovePendingQuery(query
)) {
994 if (query
->Begin()) {
995 active_queries_
[query
->target()] = query
;
1002 bool QueryManager::EndQuery(Query
* query
, base::subtle::Atomic32 submit_count
) {
1004 if (!RemovePendingQuery(query
)) {
1008 // Remove from active query map if it is active.
1009 ActiveQueryMap::iterator active_it
= active_queries_
.find(query
->target());
1010 DCHECK(active_it
!= active_queries_
.end());
1011 DCHECK(query
== active_it
->second
.get());
1012 active_queries_
.erase(active_it
);
1014 return query
->End(submit_count
);
1017 bool QueryManager::QueryCounter(
1018 Query
* query
, base::subtle::Atomic32 submit_count
) {
1020 return query
->QueryCounter(submit_count
);
1023 void QueryManager::PauseQueries() {
1024 for (std::pair
<const GLenum
, scoped_refptr
<Query
> >& it
: active_queries_
) {
1025 if (it
.second
->IsActive()) {
1027 DCHECK(it
.second
->IsPaused());
1032 void QueryManager::ResumeQueries() {
1033 for (std::pair
<const GLenum
, scoped_refptr
<Query
> >& it
: active_queries_
) {
1034 if (it
.second
->IsPaused()) {
1035 it
.second
->Resume();
1036 DCHECK(it
.second
->IsActive());
1041 } // namespace gles2