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() {
624 bool TimeElapsedQuery::End(base::subtle::Atomic32 submit_count
) {
626 return AddToPendingQueue(submit_count
);
629 bool TimeElapsedQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
634 void TimeElapsedQuery::Pause() {
638 void TimeElapsedQuery::Resume() {
642 bool TimeElapsedQuery::Process(bool did_finish
) {
643 if (!gpu_timer_
->IsAvailable())
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
{
659 TimeStampQuery(QueryManager
* manager
,
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
;
674 ~TimeStampQuery() override
;
677 scoped_ptr
<gfx::GPUTimer
> gpu_timer_
;
680 TimeStampQuery::TimeStampQuery(QueryManager
* manager
,
684 : Query(manager
, target
, shm_id
, shm_offset
),
685 gpu_timer_(manager
->CreateGPUTimer(false)) {}
687 bool TimeStampQuery::Begin() {
692 bool TimeStampQuery::End(base::subtle::Atomic32 submit_count
) {
697 void TimeStampQuery::Pause() {
701 void TimeStampQuery::Resume() {
705 bool TimeStampQuery::QueryCounter(base::subtle::Atomic32 submit_count
) {
707 gpu_timer_
->QueryTimeStamp();
708 return AddToPendingQueue(submit_count
);
711 bool TimeStampQuery::Process(bool did_finish
) {
712 if (!gpu_timer_
->IsAvailable())
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
);
731 TimeStampQuery::~TimeStampQuery() {}
733 QueryManager::QueryManager(
734 GLES2Decoder
* decoder
,
735 FeatureInfo
* feature_info
)
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
),
744 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_
&&
745 use_arb_occlusion_query2_for_occlusion_query_boolean_
));
747 gfx::GLContext
* context
= decoder_
->GetGLContext();
749 gpu_timing_client_
= context
->CreateGPUTimingClient();
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
;
777 case GL_COMMANDS_ISSUED_CHROMIUM
:
778 query
= new CommandsIssuedQuery(this, target
, shm_id
, shm_offset
);
780 case GL_LATENCY_QUERY_CHROMIUM
:
781 query
= new CommandLatencyQuery(this, target
, shm_id
, shm_offset
);
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
);
788 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
:
789 query
= new AsyncReadPixelsCompletedQuery(
790 this, target
, shm_id
, shm_offset
);
792 case GL_GET_ERROR_QUERY_CHROMIUM
:
793 query
= new GetErrorQuery(this, target
, shm_id
, shm_offset
);
795 case GL_COMMANDS_COMPLETED_CHROMIUM
:
796 query
= new CommandsCompletedQuery(this, target
, shm_id
, shm_offset
);
798 case GL_TIME_ELAPSED
:
799 query
= new TimeElapsedQuery(this, target
, shm_id
, shm_offset
);
802 query
= new TimeStampQuery(this, target
, shm_id
, shm_offset
);
805 query
= new AllSamplesPassedQuery(this, target
, shm_id
, shm_offset
);
809 std::pair
<QueryMap::iterator
, bool> result
=
810 queries_
.insert(std::make_pair(client_id
, query
));
811 DCHECK(result
.second
);
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
) {
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());
856 active_queries_
.erase(active_it
);
858 query
->Destroy(true);
859 RemovePendingQuery(query
);
860 query
->MarkAsDeleted();
863 generated_query_ids_
.erase(client_id
);
866 void QueryManager::StartTracking(QueryManager::Query
* /* query */) {
870 void QueryManager::StopTracking(QueryManager::Query
* /* query */) {
874 GLenum
QueryManager::AdjustTargetForEmulation(GLenum 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
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
887 target
= GL_SAMPLES_PASSED_ARB
;
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
);
906 QueryManager::Query::Query(
907 QueryManager
* manager
, GLenum target
, int32 shm_id
, uint32 shm_offset
)
911 shm_offset_(shm_offset
),
913 query_state_(kQueryState_Initialize
),
916 manager_
->StartTracking(this);
919 void QueryManager::Query::RunCallbacks() {
920 for (size_t i
= 0; i
< callbacks_
.size(); i
++) {
926 void QueryManager::Query::AddCallback(base::Closure callback
) {
927 if (query_state_
== kQueryState_Pending
) {
928 callbacks_
.push_back(callback
);
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.
940 manager_
->StopTracking(this);
945 bool QueryManager::Query::MarkAsCompleted(uint64 result
) {
947 QuerySync
* sync
= manager_
->decoder_
->GetSharedMemoryAs
<QuerySync
*>(
948 shm_id_
, shm_offset_
, sizeof(*sync
));
953 sync
->result
= result
;
954 base::subtle::Release_Store(&sync
->process_count
, submit_count_
);
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
)) {
965 if (query
->IsPending()) {
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());
976 DCHECK(!did_finish
|| pending_queries_
.empty());
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)) {
992 if (query
->IsPending()) {
995 query
->RunCallbacks();
996 pending_transfer_queries_
.pop_front();
1002 bool QueryManager::HavePendingTransferQueries() {
1003 return !pending_transfer_queries_
.empty();
1006 bool QueryManager::AddPendingQuery(Query
* query
,
1007 base::subtle::Atomic32 submit_count
) {
1009 DCHECK(!query
->IsDeleted());
1010 if (!RemovePendingQuery(query
)) {
1013 query
->MarkAsPending(submit_count
);
1014 pending_queries_
.push_back(query
);
1018 bool QueryManager::AddPendingTransferQuery(
1020 base::subtle::Atomic32 submit_count
) {
1022 DCHECK(!query
->IsDeleted());
1023 if (!RemovePendingQuery(query
)) {
1026 query
->MarkAsPending(submit_count
);
1027 pending_transfer_queries_
.push_back(query
);
1031 bool QueryManager::RemovePendingQuery(Query
* 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
);
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
);
1051 if (!query
->MarkAsCompleted(0)) {
1058 bool QueryManager::BeginQuery(Query
* query
) {
1060 if (!RemovePendingQuery(query
)) {
1063 if (query
->Begin()) {
1064 active_queries_
[query
->target()] = query
;
1071 bool QueryManager::EndQuery(Query
* query
, base::subtle::Atomic32 submit_count
) {
1073 if (!RemovePendingQuery(query
)) {
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
) {
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()) {
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