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 AbstractIntegerQuery
: public QueryManager::Query
{
29 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
30 bool Begin() override
;
31 bool End(base::subtle::Atomic32 submit_count
) override
;
32 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
33 void Pause() override
;
34 void Resume() override
;
35 void Destroy(bool have_context
) override
;
38 ~AbstractIntegerQuery() override
;
39 bool AreAllResultsAvailable();
41 // Service side query ids.
42 std::vector
<GLuint
> service_ids_
;
45 AbstractIntegerQuery::AbstractIntegerQuery(
46 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
47 : Query(manager
, target
, shm_id
, shm_offset
) {
48 GLuint service_id
= 0;
49 glGenQueries(1, &service_id
);
50 DCHECK_NE(0u, service_id
);
51 service_ids_
.push_back(service_id
);
54 bool AbstractIntegerQuery::Begin() {
56 // Delete all but the first one when beginning a new query.
57 if (service_ids_
.size() > 1) {
58 glDeleteQueries(service_ids_
.size() - 1, &service_ids_
[1]);
59 service_ids_
.resize(1);
61 BeginQueryHelper(target(), service_ids_
.back());
65 bool AbstractIntegerQuery::End(base::subtle::Atomic32 submit_count
) {
66 EndQueryHelper(target());
67 return AddToPendingQueue(submit_count
);
70 bool AbstractIntegerQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
75 void AbstractIntegerQuery::Pause() {
77 EndQueryHelper(target());
80 void AbstractIntegerQuery::Resume() {
83 GLuint service_id
= 0;
84 glGenQueries(1, &service_id
);
85 DCHECK_NE(0u, service_id
);
86 service_ids_
.push_back(service_id
);
87 BeginQueryHelper(target(), service_ids_
.back());
90 void AbstractIntegerQuery::Destroy(bool have_context
) {
91 if (have_context
&& !IsDeleted()) {
92 glDeleteQueries(service_ids_
.size(), &service_ids_
[0]);
98 AbstractIntegerQuery::~AbstractIntegerQuery() {
101 bool AbstractIntegerQuery::AreAllResultsAvailable() {
102 GLuint available
= 0;
104 service_ids_
.back(), GL_QUERY_RESULT_AVAILABLE_EXT
, &available
);
108 class BooleanQuery
: public AbstractIntegerQuery
{
111 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
112 bool Process(bool did_finish
) override
;
115 ~BooleanQuery() override
;
118 BooleanQuery::BooleanQuery(
119 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
120 : AbstractIntegerQuery(manager
, target
, shm_id
, shm_offset
) {
123 BooleanQuery::~BooleanQuery() {
126 bool BooleanQuery::Process(bool did_finish
) {
127 if (!AreAllResultsAvailable()) {
128 // Must return true to avoid generating an error at the command
132 for (const GLuint
& service_id
: service_ids_
) {
134 glGetQueryObjectuiv(service_id
, GL_QUERY_RESULT_EXT
, &result
);
136 return MarkAsCompleted(1);
138 return MarkAsCompleted(0);
141 class SummedIntegerQuery
: public AbstractIntegerQuery
{
144 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
145 bool Process(bool did_finish
) override
;
148 ~SummedIntegerQuery() override
;
151 SummedIntegerQuery::SummedIntegerQuery(
152 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
153 : AbstractIntegerQuery(manager
, target
, shm_id
, shm_offset
) {
156 SummedIntegerQuery::~SummedIntegerQuery() {
159 bool SummedIntegerQuery::Process(bool did_finish
) {
160 if (!AreAllResultsAvailable()) {
161 // Must return true to avoid generating an error at the command
165 GLuint summed_result
= 0;
166 for (const GLuint
& service_id
: service_ids_
) {
168 glGetQueryObjectuiv(service_id
, GL_QUERY_RESULT_EXT
, &result
);
169 summed_result
+= result
;
171 return MarkAsCompleted(summed_result
);
174 class CommandsIssuedQuery
: public QueryManager::Query
{
177 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
179 bool Begin() override
;
180 bool End(base::subtle::Atomic32 submit_count
) override
;
181 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
182 void Pause() override
;
183 void Resume() override
;
184 bool Process(bool did_finish
) override
;
185 void Destroy(bool have_context
) override
;
188 ~CommandsIssuedQuery() override
;
191 base::TimeTicks begin_time_
;
194 CommandsIssuedQuery::CommandsIssuedQuery(
195 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
196 : Query(manager
, target
, shm_id
, shm_offset
) {
199 bool CommandsIssuedQuery::Begin() {
201 begin_time_
= base::TimeTicks::Now();
205 void CommandsIssuedQuery::Pause() {
209 void CommandsIssuedQuery::Resume() {
213 bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count
) {
214 const base::TimeDelta elapsed
= base::TimeTicks::Now() - begin_time_
;
215 MarkAsPending(submit_count
);
216 return MarkAsCompleted(elapsed
.InMicroseconds());
219 bool CommandsIssuedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
224 bool CommandsIssuedQuery::Process(bool did_finish
) {
229 void CommandsIssuedQuery::Destroy(bool /* have_context */) {
235 CommandsIssuedQuery::~CommandsIssuedQuery() {
238 class CommandLatencyQuery
: public QueryManager::Query
{
241 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
243 bool Begin() override
;
244 bool End(base::subtle::Atomic32 submit_count
) override
;
245 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
246 void Pause() override
;
247 void Resume() override
;
248 bool Process(bool did_finish
) override
;
249 void Destroy(bool have_context
) override
;
252 ~CommandLatencyQuery() override
;
255 CommandLatencyQuery::CommandLatencyQuery(
256 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
257 : Query(manager
, target
, shm_id
, shm_offset
) {
260 bool CommandLatencyQuery::Begin() {
265 void CommandLatencyQuery::Pause() {
269 void CommandLatencyQuery::Resume() {
273 bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count
) {
274 base::TimeDelta now
= base::TimeTicks::Now() - base::TimeTicks();
275 MarkAsPending(submit_count
);
276 return MarkAsCompleted(now
.InMicroseconds());
279 bool CommandLatencyQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
284 bool CommandLatencyQuery::Process(bool did_finish
) {
289 void CommandLatencyQuery::Destroy(bool /* have_context */) {
295 CommandLatencyQuery::~CommandLatencyQuery() {
299 class AsyncReadPixelsCompletedQuery
300 : public QueryManager::Query
,
301 public base::SupportsWeakPtr
<AsyncReadPixelsCompletedQuery
> {
303 AsyncReadPixelsCompletedQuery(
304 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
);
306 bool Begin() override
;
307 bool End(base::subtle::Atomic32 submit_count
) override
;
308 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
309 void Pause() override
;
310 void Resume() override
;
311 bool Process(bool did_finish
) override
;
312 void Destroy(bool have_context
) override
;
316 ~AsyncReadPixelsCompletedQuery() override
;
319 bool complete_result_
;
322 AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
323 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
324 : Query(manager
, target
, shm_id
, shm_offset
),
325 complete_result_(false) {
328 bool AsyncReadPixelsCompletedQuery::Begin() {
333 void AsyncReadPixelsCompletedQuery::Pause() {
337 void AsyncReadPixelsCompletedQuery::Resume() {
341 bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count
) {
342 if (!AddToPendingQueue(submit_count
)) {
345 manager()->decoder()->WaitForReadPixels(
346 base::Bind(&AsyncReadPixelsCompletedQuery::Complete
,
349 return Process(false);
352 bool AsyncReadPixelsCompletedQuery::QueryCounter(
353 base::subtle::Atomic32 submit_count
) {
358 void AsyncReadPixelsCompletedQuery::Complete() {
359 complete_result_
= MarkAsCompleted(1);
362 bool AsyncReadPixelsCompletedQuery::Process(bool did_finish
) {
363 return !IsFinished() || complete_result_
;
366 void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
372 AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
376 class GetErrorQuery
: public QueryManager::Query
{
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
;
390 ~GetErrorQuery() override
;
395 GetErrorQuery::GetErrorQuery(
396 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
397 : Query(manager
, target
, shm_id
, shm_offset
) {
400 bool GetErrorQuery::Begin() {
405 void GetErrorQuery::Pause() {
409 void GetErrorQuery::Resume() {
413 bool GetErrorQuery::End(base::subtle::Atomic32 submit_count
) {
414 MarkAsPending(submit_count
);
415 return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
418 bool GetErrorQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
423 bool GetErrorQuery::Process(bool did_finish
) {
428 void GetErrorQuery::Destroy(bool /* have_context */) {
434 GetErrorQuery::~GetErrorQuery() {
437 class CommandsCompletedQuery
: public QueryManager::Query
{
439 CommandsCompletedQuery(QueryManager
* manager
,
444 // Overridden from QueryManager::Query:
445 bool Begin() override
;
446 bool End(base::subtle::Atomic32 submit_count
) override
;
447 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
448 void Pause() override
;
449 void Resume() override
;
450 bool Process(bool did_finish
) override
;
451 void Destroy(bool have_context
) override
;
454 ~CommandsCompletedQuery() override
;
457 scoped_ptr
<gfx::GLFence
> fence_
;
458 base::TimeTicks begin_time_
;
461 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager
* manager
,
465 : Query(manager
, target
, shm_id
, shm_offset
) {}
467 bool CommandsCompletedQuery::Begin() {
469 begin_time_
= base::TimeTicks::Now();
473 void CommandsCompletedQuery::Pause() {
477 void CommandsCompletedQuery::Resume() {
481 bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count
) {
482 fence_
.reset(gfx::GLFence::Create());
484 return AddToPendingQueue(submit_count
);
487 bool CommandsCompletedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
492 bool CommandsCompletedQuery::Process(bool did_finish
) {
493 // Note: |did_finish| guarantees that the GPU has passed the fence but
494 // we cannot assume that GLFence::HasCompleted() will return true yet as
495 // that's not guaranteed by all GLFence implementations.
496 if (!did_finish
&& fence_
&& !fence_
->HasCompleted())
499 const base::TimeDelta elapsed
= base::TimeTicks::Now() - begin_time_
;
500 return MarkAsCompleted(elapsed
.InMicroseconds());
503 void CommandsCompletedQuery::Destroy(bool have_context
) {
504 if (have_context
&& !IsDeleted()) {
510 CommandsCompletedQuery::~CommandsCompletedQuery() {}
512 class TimeElapsedQuery
: public QueryManager::Query
{
514 TimeElapsedQuery(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 ~TimeElapsedQuery() override
;
532 scoped_ptr
<gfx::GPUTimer
> gpu_timer_
;
535 TimeElapsedQuery::TimeElapsedQuery(QueryManager
* manager
,
539 : Query(manager
, target
, shm_id
, shm_offset
),
540 gpu_timer_(manager
->CreateGPUTimer(true)) {
543 bool TimeElapsedQuery::Begin() {
544 // Reset the disjoint value before the query begins if it is safe.
545 SafelyResetDisjointValue();
551 bool TimeElapsedQuery::End(base::subtle::Atomic32 submit_count
) {
553 return AddToPendingQueue(submit_count
);
556 bool TimeElapsedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
561 void TimeElapsedQuery::Pause() {
565 void TimeElapsedQuery::Resume() {
569 bool TimeElapsedQuery::Process(bool did_finish
) {
570 if (!gpu_timer_
->IsAvailable())
573 // Make sure disjoint value is up to date. This disjoint check is the only one
574 // that needs to be done to validate that this query is valid. If a disjoint
575 // occurs before the client checks the query value we will just hide the
576 // disjoint state since it did not affect this query.
577 UpdateDisjointValue();
579 const uint64_t nano_seconds
= gpu_timer_
->GetDeltaElapsed() *
580 base::Time::kNanosecondsPerMicrosecond
;
581 return MarkAsCompleted(nano_seconds
);
584 void TimeElapsedQuery::Destroy(bool have_context
) {
585 gpu_timer_
->Destroy(have_context
);
588 TimeElapsedQuery::~TimeElapsedQuery() {}
590 class TimeStampQuery
: public QueryManager::Query
{
592 TimeStampQuery(QueryManager
* manager
,
597 // Overridden from QueryManager::Query:
598 bool Begin() override
;
599 bool End(base::subtle::Atomic32 submit_count
) override
;
600 bool QueryCounter(base::subtle::Atomic32 submit_count
) override
;
601 void Pause() override
;
602 void Resume() override
;
603 bool Process(bool did_finish
) override
;
604 void Destroy(bool have_context
) override
;
607 ~TimeStampQuery() override
;
610 scoped_ptr
<gfx::GPUTimer
> gpu_timer_
;
613 TimeStampQuery::TimeStampQuery(QueryManager
* manager
,
617 : Query(manager
, target
, shm_id
, shm_offset
),
618 gpu_timer_(manager
->CreateGPUTimer(false)) {}
620 bool TimeStampQuery::Begin() {
625 bool TimeStampQuery::End(base::subtle::Atomic32 submit_count
) {
630 void TimeStampQuery::Pause() {
634 void TimeStampQuery::Resume() {
638 bool TimeStampQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
639 // Reset the disjoint value before the query begins if it is safe.
640 SafelyResetDisjointValue();
642 // After a timestamp has begun, we will want to continually detect
643 // the disjoint value every frame until the context is destroyed.
644 BeginContinualDisjointUpdate();
646 gpu_timer_
->QueryTimeStamp();
647 return AddToPendingQueue(submit_count
);
650 bool TimeStampQuery::Process(bool did_finish
) {
651 if (!gpu_timer_
->IsAvailable())
654 // Make sure disjoint value is up to date. This disjoint check is the only one
655 // that needs to be done to validate that this query is valid. If a disjoint
656 // occurs before the client checks the query value we will just hide the
657 // disjoint state since it did not affect this query.
658 UpdateDisjointValue();
662 gpu_timer_
->GetStartEndTimestamps(&start
, &end
);
663 DCHECK(start
== end
);
665 const uint64_t nano_seconds
= start
* base::Time::kNanosecondsPerMicrosecond
;
666 return MarkAsCompleted(nano_seconds
);
669 void TimeStampQuery::Destroy(bool have_context
) {
670 if (gpu_timer_
.get()) {
671 gpu_timer_
->Destroy(have_context
);
676 TimeStampQuery::~TimeStampQuery() {}
678 QueryManager::QueryManager(
679 GLES2Decoder
* decoder
,
680 FeatureInfo
* feature_info
)
682 use_arb_occlusion_query2_for_occlusion_query_boolean_(
683 feature_info
->feature_flags(
684 ).use_arb_occlusion_query2_for_occlusion_query_boolean
),
685 use_arb_occlusion_query_for_occlusion_query_boolean_(
686 feature_info
->feature_flags(
687 ).use_arb_occlusion_query_for_occlusion_query_boolean
),
688 update_disjoints_continually_(false),
689 disjoint_notify_shm_id_(-1),
690 disjoint_notify_shm_offset_(0),
691 disjoints_notified_(0),
693 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_
&&
694 use_arb_occlusion_query2_for_occlusion_query_boolean_
));
696 gfx::GLContext
* context
= decoder_
->GetGLContext();
698 gpu_timing_client_
= context
->CreateGPUTimingClient();
700 gpu_timing_client_
= new gfx::GPUTimingClient();
704 QueryManager::~QueryManager() {
705 DCHECK(queries_
.empty());
707 // If this triggers, that means something is keeping a reference to
708 // a Query belonging to this.
709 CHECK_EQ(query_count_
, 0u);
712 void QueryManager::Destroy(bool have_context
) {
713 active_queries_
.clear();
714 pending_queries_
.clear();
715 pending_transfer_queries_
.clear();
716 active_queries_
.clear();
717 while (!queries_
.empty()) {
718 Query
* query
= queries_
.begin()->second
.get();
719 query
->Destroy(have_context
);
720 queries_
.erase(queries_
.begin());
724 void QueryManager::SetDisjointSync(int32 shm_id
, uint32 shm_offset
) {
725 DCHECK(disjoint_notify_shm_id_
== -1);
726 DCHECK(shm_id
!= -1);
728 DisjointValueSync
* sync
= decoder_
->GetSharedMemoryAs
<DisjointValueSync
*>(
729 shm_id
, shm_offset
, sizeof(*sync
));
732 disjoints_notified_
= 0;
734 disjoint_notify_shm_id_
= shm_id
;
735 disjoint_notify_shm_offset_
= shm_offset
;
738 QueryManager::Query
* QueryManager::CreateQuery(
739 GLenum target
, GLuint client_id
, int32 shm_id
, uint32 shm_offset
) {
740 scoped_refptr
<Query
> query
;
742 case GL_COMMANDS_ISSUED_CHROMIUM
:
743 query
= new CommandsIssuedQuery(this, target
, shm_id
, shm_offset
);
745 case GL_LATENCY_QUERY_CHROMIUM
:
746 query
= new CommandLatencyQuery(this, target
, shm_id
, shm_offset
);
748 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
:
749 query
= new AsyncReadPixelsCompletedQuery(
750 this, target
, shm_id
, shm_offset
);
752 case GL_GET_ERROR_QUERY_CHROMIUM
:
753 query
= new GetErrorQuery(this, target
, shm_id
, shm_offset
);
755 case GL_COMMANDS_COMPLETED_CHROMIUM
:
756 query
= new CommandsCompletedQuery(this, target
, shm_id
, shm_offset
);
758 case GL_TIME_ELAPSED
:
759 query
= new TimeElapsedQuery(this, target
, shm_id
, shm_offset
);
762 query
= new TimeStampQuery(this, target
, shm_id
, shm_offset
);
764 case GL_ANY_SAMPLES_PASSED
:
765 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE
:
766 query
= new BooleanQuery(this, target
, shm_id
, shm_offset
);
768 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
:
769 query
= new SummedIntegerQuery(this, target
, shm_id
, shm_offset
);
775 std::pair
<QueryMap::iterator
, bool> result
=
776 queries_
.insert(std::make_pair(client_id
, query
));
777 DCHECK(result
.second
);
781 scoped_ptr
<gfx::GPUTimer
> QueryManager::CreateGPUTimer(bool elapsed_time
) {
782 return gpu_timing_client_
->CreateGPUTimer(elapsed_time
);
785 bool QueryManager::GPUTimingAvailable() {
786 return gpu_timing_client_
->IsAvailable();
789 void QueryManager::GenQueries(GLsizei n
, const GLuint
* queries
) {
791 for (GLsizei i
= 0; i
< n
; ++i
) {
792 generated_query_ids_
.insert(queries
[i
]);
796 bool QueryManager::IsValidQuery(GLuint id
) {
797 GeneratedQueryIds::iterator it
= generated_query_ids_
.find(id
);
798 return it
!= generated_query_ids_
.end();
801 QueryManager::Query
* QueryManager::GetQuery(GLuint client_id
) {
802 QueryMap::iterator it
= queries_
.find(client_id
);
803 return it
!= queries_
.end() ? it
->second
.get() : nullptr;
806 QueryManager::Query
* QueryManager::GetActiveQuery(GLenum target
) {
807 ActiveQueryMap::iterator it
= active_queries_
.find(target
);
808 return it
!= active_queries_
.end() ? it
->second
.get() : nullptr;
811 void QueryManager::RemoveQuery(GLuint client_id
) {
812 QueryMap::iterator it
= queries_
.find(client_id
);
813 if (it
!= queries_
.end()) {
814 Query
* query
= it
->second
.get();
816 // Remove from active query map if it is active.
817 ActiveQueryMap::iterator active_it
= active_queries_
.find(query
->target());
818 bool is_active
= (active_it
!= active_queries_
.end() &&
819 query
== active_it
->second
.get());
820 DCHECK(is_active
== query
->IsActive());
822 active_queries_
.erase(active_it
);
824 query
->Destroy(true);
825 RemovePendingQuery(query
);
826 query
->MarkAsDeleted();
829 generated_query_ids_
.erase(client_id
);
832 void QueryManager::StartTracking(QueryManager::Query
* /* query */) {
836 void QueryManager::StopTracking(QueryManager::Query
* /* query */) {
840 GLenum
QueryManager::AdjustTargetForEmulation(GLenum target
) {
842 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
:
843 case GL_ANY_SAMPLES_PASSED_EXT
:
844 if (use_arb_occlusion_query2_for_occlusion_query_boolean_
) {
845 // ARB_occlusion_query2 does not have a
846 // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
848 target
= GL_ANY_SAMPLES_PASSED_EXT
;
849 } else if (use_arb_occlusion_query_for_occlusion_query_boolean_
) {
850 // ARB_occlusion_query does not have a
851 // GL_ANY_SAMPLES_PASSED_EXT
853 target
= GL_SAMPLES_PASSED_ARB
;
862 void QueryManager::BeginQueryHelper(GLenum target
, GLuint id
) {
863 target
= AdjustTargetForEmulation(target
);
864 glBeginQuery(target
, id
);
867 void QueryManager::EndQueryHelper(GLenum target
) {
868 target
= AdjustTargetForEmulation(target
);
872 void QueryManager::UpdateDisjointValue() {
873 if (disjoint_notify_shm_id_
!= -1) {
874 if (gpu_timing_client_
->CheckAndResetTimerErrors()) {
875 disjoints_notified_
++;
877 DisjointValueSync
* sync
= decoder_
->GetSharedMemoryAs
<DisjointValueSync
*>(
878 disjoint_notify_shm_id_
, disjoint_notify_shm_offset_
, sizeof(*sync
));
880 // Shared memory does not seem to be valid, ignore the shm id/offset.
881 disjoint_notify_shm_id_
= -1;
882 disjoint_notify_shm_offset_
= 0;
884 sync
->SetDisjointCount(disjoints_notified_
);
890 void QueryManager::SafelyResetDisjointValue() {
891 // It is only safe to reset the disjoint value is there is no active
892 // elapsed timer and we are not continually updating the disjoint value.
893 if (!update_disjoints_continually_
&& !GetActiveQuery(GL_TIME_ELAPSED
)) {
894 // Reset the error state without storing the result.
895 gpu_timing_client_
->CheckAndResetTimerErrors();
899 QueryManager::Query::Query(
900 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
904 shm_offset_(shm_offset
),
906 query_state_(kQueryState_Initialize
),
909 manager_
->StartTracking(this);
912 void QueryManager::Query::RunCallbacks() {
913 for (size_t i
= 0; i
< callbacks_
.size(); i
++) {
919 void QueryManager::Query::AddCallback(base::Closure callback
) {
920 if (query_state_
== kQueryState_Pending
) {
921 callbacks_
.push_back(callback
);
927 QueryManager::Query::~Query() {
928 // The query is getting deleted, either by the client or
929 // because the context was lost. Call any outstanding
930 // callbacks to avoid leaks.
933 manager_
->StopTracking(this);
938 bool QueryManager::Query::MarkAsCompleted(uint64 result
) {
940 QuerySync
* sync
= manager_
->decoder_
->GetSharedMemoryAs
<QuerySync
*>(
941 shm_id_
, shm_offset_
, sizeof(*sync
));
946 sync
->result
= result
;
947 base::subtle::Release_Store(&sync
->process_count
, submit_count_
);
952 bool QueryManager::ProcessPendingQueries(bool did_finish
) {
953 while (!pending_queries_
.empty()) {
954 Query
* query
= pending_queries_
.front().get();
955 if (!query
->Process(did_finish
)) {
958 if (query
->IsPending()) {
961 query
->RunCallbacks();
962 pending_queries_
.pop_front();
964 // If glFinish() has been called, all of our queries should be completed.
965 DCHECK(!did_finish
|| pending_queries_
.empty());
970 bool QueryManager::HavePendingQueries() {
971 return !pending_queries_
.empty();
974 bool QueryManager::ProcessPendingTransferQueries() {
975 while (!pending_transfer_queries_
.empty()) {
976 Query
* query
= pending_transfer_queries_
.front().get();
977 if (!query
->Process(false)) {
980 if (query
->IsPending()) {
983 query
->RunCallbacks();
984 pending_transfer_queries_
.pop_front();
990 bool QueryManager::HavePendingTransferQueries() {
991 return !pending_transfer_queries_
.empty();
994 void QueryManager::ProcessFrameBeginUpdates() {
995 if (update_disjoints_continually_
)
996 UpdateDisjointValue();
999 bool QueryManager::AddPendingQuery(Query
* query
,
1000 base::subtle::Atomic32 submit_count
) {
1002 DCHECK(!query
->IsDeleted());
1003 if (!RemovePendingQuery(query
)) {
1006 query
->MarkAsPending(submit_count
);
1007 pending_queries_
.push_back(query
);
1011 bool QueryManager::AddPendingTransferQuery(
1013 base::subtle::Atomic32 submit_count
) {
1015 DCHECK(!query
->IsDeleted());
1016 if (!RemovePendingQuery(query
)) {
1019 query
->MarkAsPending(submit_count
);
1020 pending_transfer_queries_
.push_back(query
);
1024 bool QueryManager::RemovePendingQuery(Query
* query
) {
1026 if (query
->IsPending()) {
1027 // TODO(gman): Speed this up if this is a common operation. This would only
1028 // happen if you do being/end begin/end on the same query without waiting
1029 // for the first one to finish.
1030 for (QueryQueue::iterator it
= pending_queries_
.begin();
1031 it
!= pending_queries_
.end(); ++it
) {
1032 if (it
->get() == query
) {
1033 pending_queries_
.erase(it
);
1037 for (QueryQueue::iterator it
= pending_transfer_queries_
.begin();
1038 it
!= pending_transfer_queries_
.end(); ++it
) {
1039 if (it
->get() == query
) {
1040 pending_transfer_queries_
.erase(it
);
1044 if (!query
->MarkAsCompleted(0)) {
1051 bool QueryManager::BeginQuery(Query
* query
) {
1053 if (!RemovePendingQuery(query
)) {
1056 if (query
->Begin()) {
1057 active_queries_
[query
->target()] = query
;
1064 bool QueryManager::EndQuery(Query
* query
, base::subtle::Atomic32 submit_count
) {
1066 if (!RemovePendingQuery(query
)) {
1070 // Remove from active query map if it is active.
1071 ActiveQueryMap::iterator active_it
= active_queries_
.find(query
->target());
1072 DCHECK(active_it
!= active_queries_
.end());
1073 DCHECK(query
== active_it
->second
.get());
1074 active_queries_
.erase(active_it
);
1076 return query
->End(submit_count
);
1079 bool QueryManager::QueryCounter(
1080 Query
* query
, base::subtle::Atomic32 submit_count
) {
1082 return query
->QueryCounter(submit_count
);
1085 void QueryManager::PauseQueries() {
1086 for (std::pair
<const GLenum
, scoped_refptr
<Query
> >& it
: active_queries_
) {
1087 if (it
.second
->IsActive()) {
1089 DCHECK(it
.second
->IsPaused());
1094 void QueryManager::ResumeQueries() {
1095 for (std::pair
<const GLenum
, scoped_refptr
<Query
> >& it
: active_queries_
) {
1096 if (it
.second
->IsPaused()) {
1097 it
.second
->Resume();
1098 DCHECK(it
.second
->IsActive());
1103 } // namespace gles2