Handle account removal correctly on all platforms.
[chromium-blink-merge.git] / gpu / command_buffer / service / query_manager.cc
blob1d36c899871109a0b9038dd20169f2c57d2a9cac
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gpu/command_buffer/service/query_manager.h"
7 #include "base/atomicops.h"
8 #include "base/bind.h"
9 #include "base/logging.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/numerics/safe_math.h"
12 #include "base/synchronization/lock.h"
13 #include "base/time/time.h"
14 #include "gpu/command_buffer/common/gles2_cmd_format.h"
15 #include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
16 #include "gpu/command_buffer/service/error_state.h"
17 #include "gpu/command_buffer/service/feature_info.h"
18 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
19 #include "ui/gl/gl_fence.h"
21 namespace gpu {
22 namespace gles2 {
24 namespace {
26 class AsyncPixelTransferCompletionObserverImpl
27 : public AsyncPixelTransferCompletionObserver {
28 public:
29 AsyncPixelTransferCompletionObserverImpl(base::subtle::Atomic32 submit_count)
30 : submit_count_(submit_count), cancelled_(false) {}
32 void Cancel() {
33 base::AutoLock locked(lock_);
34 cancelled_ = true;
37 virtual void DidComplete(const AsyncMemoryParams& mem_params) OVERRIDE {
38 base::AutoLock locked(lock_);
39 if (!cancelled_) {
40 DCHECK(mem_params.buffer().get());
41 void* data = mem_params.GetDataAddress();
42 QuerySync* sync = static_cast<QuerySync*>(data);
43 base::subtle::Release_Store(&sync->process_count, submit_count_);
47 private:
48 virtual ~AsyncPixelTransferCompletionObserverImpl() {}
50 base::subtle::Atomic32 submit_count_;
52 base::Lock lock_;
53 bool cancelled_;
55 DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferCompletionObserverImpl);
58 class AsyncPixelTransfersCompletedQuery
59 : public QueryManager::Query,
60 public base::SupportsWeakPtr<AsyncPixelTransfersCompletedQuery> {
61 public:
62 AsyncPixelTransfersCompletedQuery(
63 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
65 virtual bool Begin() OVERRIDE;
66 virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
67 virtual bool Process() OVERRIDE;
68 virtual void Destroy(bool have_context) OVERRIDE;
70 protected:
71 virtual ~AsyncPixelTransfersCompletedQuery();
73 scoped_refptr<AsyncPixelTransferCompletionObserverImpl> observer_;
76 AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery(
77 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
78 : Query(manager, target, shm_id, shm_offset) {
81 bool AsyncPixelTransfersCompletedQuery::Begin() {
82 return true;
85 bool AsyncPixelTransfersCompletedQuery::End(
86 base::subtle::Atomic32 submit_count) {
87 // Get the real shared memory since it might need to be duped to prevent
88 // use-after-free of the memory.
89 scoped_refptr<Buffer> buffer =
90 manager()->decoder()->GetSharedMemoryBuffer(shm_id());
91 if (!buffer.get())
92 return false;
93 AsyncMemoryParams mem_params(buffer, shm_offset(), sizeof(QuerySync));
94 if (!mem_params.GetDataAddress())
95 return false;
97 observer_ = new AsyncPixelTransferCompletionObserverImpl(submit_count);
99 // Ask AsyncPixelTransferDelegate to run completion callback after all
100 // previous async transfers are done. No guarantee that callback is run
101 // on the current thread.
102 manager()->decoder()->GetAsyncPixelTransferManager()->AsyncNotifyCompletion(
103 mem_params, observer_.get());
105 return AddToPendingTransferQueue(submit_count);
108 bool AsyncPixelTransfersCompletedQuery::Process() {
109 QuerySync* sync = manager()->decoder()->GetSharedMemoryAs<QuerySync*>(
110 shm_id(), shm_offset(), sizeof(*sync));
111 if (!sync)
112 return false;
114 // Check if completion callback has been run. sync->process_count atomicity
115 // is guaranteed as this is already used to notify client of a completed
116 // query.
117 if (base::subtle::Acquire_Load(&sync->process_count) != submit_count())
118 return true;
120 UnmarkAsPending();
121 return true;
124 void AsyncPixelTransfersCompletedQuery::Destroy(bool /* have_context */) {
125 if (!IsDeleted()) {
126 MarkAsDeleted();
130 AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() {
131 if (observer_.get())
132 observer_->Cancel();
135 } // namespace
137 class AllSamplesPassedQuery : public QueryManager::Query {
138 public:
139 AllSamplesPassedQuery(
140 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset,
141 GLuint service_id);
142 virtual bool Begin() OVERRIDE;
143 virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
144 virtual bool Process() OVERRIDE;
145 virtual void Destroy(bool have_context) OVERRIDE;
147 protected:
148 virtual ~AllSamplesPassedQuery();
150 private:
151 // Service side query id.
152 GLuint service_id_;
155 AllSamplesPassedQuery::AllSamplesPassedQuery(
156 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset,
157 GLuint service_id)
158 : Query(manager, target, shm_id, shm_offset),
159 service_id_(service_id) {
162 bool AllSamplesPassedQuery::Begin() {
163 BeginQueryHelper(target(), service_id_);
164 return true;
167 bool AllSamplesPassedQuery::End(base::subtle::Atomic32 submit_count) {
168 EndQueryHelper(target());
169 return AddToPendingQueue(submit_count);
172 bool AllSamplesPassedQuery::Process() {
173 GLuint available = 0;
174 glGetQueryObjectuivARB(
175 service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
176 if (!available) {
177 return true;
179 GLuint result = 0;
180 glGetQueryObjectuivARB(
181 service_id_, GL_QUERY_RESULT_EXT, &result);
183 return MarkAsCompleted(result != 0);
186 void AllSamplesPassedQuery::Destroy(bool have_context) {
187 if (have_context && !IsDeleted()) {
188 glDeleteQueriesARB(1, &service_id_);
189 MarkAsDeleted();
193 AllSamplesPassedQuery::~AllSamplesPassedQuery() {
196 class CommandsIssuedQuery : public QueryManager::Query {
197 public:
198 CommandsIssuedQuery(
199 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
201 virtual bool Begin() OVERRIDE;
202 virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
203 virtual bool Process() OVERRIDE;
204 virtual void Destroy(bool have_context) OVERRIDE;
206 protected:
207 virtual ~CommandsIssuedQuery();
209 private:
210 base::TimeTicks begin_time_;
213 CommandsIssuedQuery::CommandsIssuedQuery(
214 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
215 : Query(manager, target, shm_id, shm_offset) {
218 bool CommandsIssuedQuery::Begin() {
219 begin_time_ = base::TimeTicks::HighResNow();
220 return true;
223 bool CommandsIssuedQuery::End(base::subtle::Atomic32 submit_count) {
224 base::TimeDelta elapsed = base::TimeTicks::HighResNow() - begin_time_;
225 MarkAsPending(submit_count);
226 return MarkAsCompleted(elapsed.InMicroseconds());
229 bool CommandsIssuedQuery::Process() {
230 NOTREACHED();
231 return true;
234 void CommandsIssuedQuery::Destroy(bool /* have_context */) {
235 if (!IsDeleted()) {
236 MarkAsDeleted();
240 CommandsIssuedQuery::~CommandsIssuedQuery() {
243 class CommandLatencyQuery : public QueryManager::Query {
244 public:
245 CommandLatencyQuery(
246 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
248 virtual bool Begin() OVERRIDE;
249 virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
250 virtual bool Process() OVERRIDE;
251 virtual void Destroy(bool have_context) OVERRIDE;
253 protected:
254 virtual ~CommandLatencyQuery();
257 CommandLatencyQuery::CommandLatencyQuery(
258 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
259 : Query(manager, target, shm_id, shm_offset) {
262 bool CommandLatencyQuery::Begin() {
263 return true;
266 bool CommandLatencyQuery::End(base::subtle::Atomic32 submit_count) {
267 base::TimeDelta now = base::TimeTicks::HighResNow() - base::TimeTicks();
268 MarkAsPending(submit_count);
269 return MarkAsCompleted(now.InMicroseconds());
272 bool CommandLatencyQuery::Process() {
273 NOTREACHED();
274 return true;
277 void CommandLatencyQuery::Destroy(bool /* have_context */) {
278 if (!IsDeleted()) {
279 MarkAsDeleted();
283 CommandLatencyQuery::~CommandLatencyQuery() {
287 class AsyncReadPixelsCompletedQuery
288 : public QueryManager::Query,
289 public base::SupportsWeakPtr<AsyncReadPixelsCompletedQuery> {
290 public:
291 AsyncReadPixelsCompletedQuery(
292 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
294 virtual bool Begin() OVERRIDE;
295 virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
296 virtual bool Process() OVERRIDE;
297 virtual void Destroy(bool have_context) OVERRIDE;
299 protected:
300 void Complete();
301 virtual ~AsyncReadPixelsCompletedQuery();
303 private:
304 bool completed_;
305 bool complete_result_;
308 AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
309 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
310 : Query(manager, target, shm_id, shm_offset),
311 completed_(false),
312 complete_result_(false) {
315 bool AsyncReadPixelsCompletedQuery::Begin() {
316 return true;
319 bool AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
320 if (!AddToPendingQueue(submit_count)) {
321 return false;
323 manager()->decoder()->WaitForReadPixels(
324 base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
325 AsWeakPtr()));
327 return Process();
330 void AsyncReadPixelsCompletedQuery::Complete() {
331 completed_ = true;
332 complete_result_ = MarkAsCompleted(1);
335 bool AsyncReadPixelsCompletedQuery::Process() {
336 return !completed_ || complete_result_;
339 void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
340 if (!IsDeleted()) {
341 MarkAsDeleted();
345 AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
349 class GetErrorQuery : public QueryManager::Query {
350 public:
351 GetErrorQuery(
352 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
354 virtual bool Begin() OVERRIDE;
355 virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
356 virtual bool Process() OVERRIDE;
357 virtual void Destroy(bool have_context) OVERRIDE;
359 protected:
360 virtual ~GetErrorQuery();
362 private:
365 GetErrorQuery::GetErrorQuery(
366 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
367 : Query(manager, target, shm_id, shm_offset) {
370 bool GetErrorQuery::Begin() {
371 return true;
374 bool GetErrorQuery::End(base::subtle::Atomic32 submit_count) {
375 MarkAsPending(submit_count);
376 return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
379 bool GetErrorQuery::Process() {
380 NOTREACHED();
381 return true;
384 void GetErrorQuery::Destroy(bool /* have_context */) {
385 if (!IsDeleted()) {
386 MarkAsDeleted();
390 GetErrorQuery::~GetErrorQuery() {
393 class CommandsCompletedQuery : public QueryManager::Query {
394 public:
395 CommandsCompletedQuery(QueryManager* manager,
396 GLenum target,
397 int32 shm_id,
398 uint32 shm_offset);
400 // Overridden from QueryManager::Query:
401 virtual bool Begin() OVERRIDE;
402 virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE;
403 virtual bool Process() OVERRIDE;
404 virtual void Destroy(bool have_context) OVERRIDE;
406 protected:
407 virtual ~CommandsCompletedQuery();
409 private:
410 scoped_ptr<gfx::GLFence> fence_;
413 CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager,
414 GLenum target,
415 int32 shm_id,
416 uint32 shm_offset)
417 : Query(manager, target, shm_id, shm_offset) {}
419 bool CommandsCompletedQuery::Begin() { return true; }
421 bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
422 fence_.reset(gfx::GLFence::Create());
423 DCHECK(fence_);
424 return AddToPendingQueue(submit_count);
427 bool CommandsCompletedQuery::Process() {
428 if (fence_ && !fence_->HasCompleted())
429 return true;
430 return MarkAsCompleted(0);
433 void CommandsCompletedQuery::Destroy(bool have_context) {
434 if (have_context && !IsDeleted()) {
435 fence_.reset();
436 MarkAsDeleted();
440 CommandsCompletedQuery::~CommandsCompletedQuery() {}
442 QueryManager::QueryManager(
443 GLES2Decoder* decoder,
444 FeatureInfo* feature_info)
445 : decoder_(decoder),
446 use_arb_occlusion_query2_for_occlusion_query_boolean_(
447 feature_info->feature_flags(
448 ).use_arb_occlusion_query2_for_occlusion_query_boolean),
449 use_arb_occlusion_query_for_occlusion_query_boolean_(
450 feature_info->feature_flags(
451 ).use_arb_occlusion_query_for_occlusion_query_boolean),
452 query_count_(0) {
453 DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_ &&
454 use_arb_occlusion_query2_for_occlusion_query_boolean_));
457 QueryManager::~QueryManager() {
458 DCHECK(queries_.empty());
460 // If this triggers, that means something is keeping a reference to
461 // a Query belonging to this.
462 CHECK_EQ(query_count_, 0u);
465 void QueryManager::Destroy(bool have_context) {
466 pending_queries_.clear();
467 pending_transfer_queries_.clear();
468 while (!queries_.empty()) {
469 Query* query = queries_.begin()->second.get();
470 query->Destroy(have_context);
471 queries_.erase(queries_.begin());
475 QueryManager::Query* QueryManager::CreateQuery(
476 GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) {
477 scoped_refptr<Query> query;
478 switch (target) {
479 case GL_COMMANDS_ISSUED_CHROMIUM:
480 query = new CommandsIssuedQuery(this, target, shm_id, shm_offset);
481 break;
482 case GL_LATENCY_QUERY_CHROMIUM:
483 query = new CommandLatencyQuery(this, target, shm_id, shm_offset);
484 break;
485 case GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM:
486 // Currently async pixel transfer delegates only support uploads.
487 query = new AsyncPixelTransfersCompletedQuery(
488 this, target, shm_id, shm_offset);
489 break;
490 case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM:
491 query = new AsyncReadPixelsCompletedQuery(
492 this, target, shm_id, shm_offset);
493 break;
494 case GL_GET_ERROR_QUERY_CHROMIUM:
495 query = new GetErrorQuery(this, target, shm_id, shm_offset);
496 break;
497 case GL_COMMANDS_COMPLETED_CHROMIUM:
498 query = new CommandsCompletedQuery(this, target, shm_id, shm_offset);
499 break;
500 default: {
501 GLuint service_id = 0;
502 glGenQueriesARB(1, &service_id);
503 DCHECK_NE(0u, service_id);
504 query = new AllSamplesPassedQuery(
505 this, target, shm_id, shm_offset, service_id);
506 break;
509 std::pair<QueryMap::iterator, bool> result =
510 queries_.insert(std::make_pair(client_id, query));
511 DCHECK(result.second);
512 return query.get();
515 void QueryManager::GenQueries(GLsizei n, const GLuint* queries) {
516 DCHECK_GE(n, 0);
517 for (GLsizei i = 0; i < n; ++i) {
518 generated_query_ids_.insert(queries[i]);
522 bool QueryManager::IsValidQuery(GLuint id) {
523 GeneratedQueryIds::iterator it = generated_query_ids_.find(id);
524 return it != generated_query_ids_.end();
527 QueryManager::Query* QueryManager::GetQuery(
528 GLuint client_id) {
529 QueryMap::iterator it = queries_.find(client_id);
530 return it != queries_.end() ? it->second.get() : NULL;
533 void QueryManager::RemoveQuery(GLuint client_id) {
534 QueryMap::iterator it = queries_.find(client_id);
535 if (it != queries_.end()) {
536 Query* query = it->second.get();
537 RemovePendingQuery(query);
538 query->MarkAsDeleted();
539 queries_.erase(it);
541 generated_query_ids_.erase(client_id);
544 void QueryManager::StartTracking(QueryManager::Query* /* query */) {
545 ++query_count_;
548 void QueryManager::StopTracking(QueryManager::Query* /* query */) {
549 --query_count_;
552 GLenum QueryManager::AdjustTargetForEmulation(GLenum target) {
553 switch (target) {
554 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
555 case GL_ANY_SAMPLES_PASSED_EXT:
556 if (use_arb_occlusion_query2_for_occlusion_query_boolean_) {
557 // ARB_occlusion_query2 does not have a
558 // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
559 // target.
560 target = GL_ANY_SAMPLES_PASSED_EXT;
561 } else if (use_arb_occlusion_query_for_occlusion_query_boolean_) {
562 // ARB_occlusion_query does not have a
563 // GL_ANY_SAMPLES_PASSED_EXT
564 // target.
565 target = GL_SAMPLES_PASSED_ARB;
567 break;
568 default:
569 break;
571 return target;
574 void QueryManager::BeginQueryHelper(GLenum target, GLuint id) {
575 target = AdjustTargetForEmulation(target);
576 glBeginQueryARB(target, id);
579 void QueryManager::EndQueryHelper(GLenum target) {
580 target = AdjustTargetForEmulation(target);
581 glEndQueryARB(target);
584 QueryManager::Query::Query(
585 QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
586 : manager_(manager),
587 target_(target),
588 shm_id_(shm_id),
589 shm_offset_(shm_offset),
590 submit_count_(0),
591 pending_(false),
592 deleted_(false) {
593 DCHECK(manager);
594 manager_->StartTracking(this);
597 void QueryManager::Query::RunCallbacks() {
598 for (size_t i = 0; i < callbacks_.size(); i++) {
599 callbacks_[i].Run();
601 callbacks_.clear();
604 void QueryManager::Query::AddCallback(base::Closure callback) {
605 if (pending_) {
606 callbacks_.push_back(callback);
607 } else {
608 callback.Run();
612 QueryManager::Query::~Query() {
613 // The query is getting deleted, either by the client or
614 // because the context was lost. Call any outstanding
615 // callbacks to avoid leaks.
616 RunCallbacks();
617 if (manager_) {
618 manager_->StopTracking(this);
619 manager_ = NULL;
623 bool QueryManager::Query::MarkAsCompleted(uint64 result) {
624 DCHECK(pending_);
625 QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>(
626 shm_id_, shm_offset_, sizeof(*sync));
627 if (!sync) {
628 return false;
631 pending_ = false;
632 sync->result = result;
633 base::subtle::Release_Store(&sync->process_count, submit_count_);
635 return true;
638 bool QueryManager::ProcessPendingQueries() {
639 while (!pending_queries_.empty()) {
640 Query* query = pending_queries_.front().get();
641 if (!query->Process()) {
642 return false;
644 if (query->pending()) {
645 break;
647 query->RunCallbacks();
648 pending_queries_.pop_front();
651 return true;
654 bool QueryManager::HavePendingQueries() {
655 return !pending_queries_.empty();
658 bool QueryManager::ProcessPendingTransferQueries() {
659 while (!pending_transfer_queries_.empty()) {
660 Query* query = pending_transfer_queries_.front().get();
661 if (!query->Process()) {
662 return false;
664 if (query->pending()) {
665 break;
667 query->RunCallbacks();
668 pending_transfer_queries_.pop_front();
671 return true;
674 bool QueryManager::HavePendingTransferQueries() {
675 return !pending_transfer_queries_.empty();
678 bool QueryManager::AddPendingQuery(Query* query,
679 base::subtle::Atomic32 submit_count) {
680 DCHECK(query);
681 DCHECK(!query->IsDeleted());
682 if (!RemovePendingQuery(query)) {
683 return false;
685 query->MarkAsPending(submit_count);
686 pending_queries_.push_back(query);
687 return true;
690 bool QueryManager::AddPendingTransferQuery(
691 Query* query,
692 base::subtle::Atomic32 submit_count) {
693 DCHECK(query);
694 DCHECK(!query->IsDeleted());
695 if (!RemovePendingQuery(query)) {
696 return false;
698 query->MarkAsPending(submit_count);
699 pending_transfer_queries_.push_back(query);
700 return true;
703 bool QueryManager::RemovePendingQuery(Query* query) {
704 DCHECK(query);
705 if (query->pending()) {
706 // TODO(gman): Speed this up if this is a common operation. This would only
707 // happen if you do being/end begin/end on the same query without waiting
708 // for the first one to finish.
709 for (QueryQueue::iterator it = pending_queries_.begin();
710 it != pending_queries_.end(); ++it) {
711 if (it->get() == query) {
712 pending_queries_.erase(it);
713 break;
716 for (QueryQueue::iterator it = pending_transfer_queries_.begin();
717 it != pending_transfer_queries_.end(); ++it) {
718 if (it->get() == query) {
719 pending_transfer_queries_.erase(it);
720 break;
723 if (!query->MarkAsCompleted(0)) {
724 return false;
727 return true;
730 bool QueryManager::BeginQuery(Query* query) {
731 DCHECK(query);
732 if (!RemovePendingQuery(query)) {
733 return false;
735 return query->Begin();
738 bool QueryManager::EndQuery(Query* query, base::subtle::Atomic32 submit_count) {
739 DCHECK(query);
740 if (!RemovePendingQuery(query)) {
741 return false;
743 return query->End(submit_count);
746 } // namespace gles2
747 } // namespace gpu