blob: a383f0c7d45b124e634584fae732db9c76b454a1 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "base/atomicops.h"
#include "base/callback_forward.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "gpu/command_buffer/common/buffer.h"
#include "gpu/command_buffer/common/common_cmd_format.h"
#include "gpu/command_buffer/common/gl2_types.h"
#include "gpu/gpu_gles2_export.h"
namespace gpu {
// This class keeps track of the queries and their state
// As Queries are not shared there is one QueryManager per context.
class GPU_GLES2_EXPORT QueryManager {
class GPU_GLES2_EXPORT Query : public base::RefCounted<Query> {
Query(QueryManager* manager,
GLenum target,
scoped_refptr<gpu::Buffer> buffer,
QuerySync* sync);
GLenum target() const {
return target_;
bool IsDeleted() const {
return deleted_;
bool IsValid() const {
return target() && !IsDeleted();
bool IsActive() const {
return query_state_ == kQueryState_Active;
bool IsPaused() const {
return query_state_ == kQueryState_Paused;
bool IsPending() const {
return query_state_ == kQueryState_Pending;
bool IsFinished() const {
return query_state_ == kQueryState_Finished;
const QuerySync* sync() const { return sync_; }
virtual void Begin() = 0;
virtual void End(base::subtle::Atomic32 submit_count) = 0;
virtual void QueryCounter(base::subtle::Atomic32 submit_count) = 0;
virtual void Process(bool did_finish) = 0;
// Pauses active query to be resumed later.
virtual void Pause() = 0;
// Resume from a paused active query.
virtual void Resume() = 0;
virtual void Destroy(bool have_context) = 0;
virtual void BeginProcessingCommands() {}
virtual void EndProcessingCommands() {}
void AddCallback(base::OnceClosure callback);
virtual ~Query();
QueryManager* manager() const {
return manager_;
void MarkAsDeleted() {
deleted_ = true;
void MarkAsActive() {
DCHECK(query_state_ == kQueryState_Initialize ||
query_state_ == kQueryState_Paused ||
query_state_ == kQueryState_Finished);
query_state_ = kQueryState_Active;
void MarkAsPaused() {
DCHECK(query_state_ == kQueryState_Active);
query_state_ = kQueryState_Paused;
void MarkAsPending(base::subtle::Atomic32 submit_count) {
DCHECK(query_state_ == kQueryState_Active);
query_state_ = kQueryState_Pending;
submit_count_ = submit_count;
void MarkAsCompleted(uint64_t result);
void UnmarkAsPending() {
DCHECK(query_state_ == kQueryState_Pending);
query_state_ = kQueryState_Finished;
void AddToPendingQueue(base::subtle::Atomic32 submit_count) {
manager_->AddPendingQuery(this, submit_count);
void BeginQueryHelper(GLenum target, GLuint id) {
manager_->BeginQueryHelper(target, id);
void EndQueryHelper(GLenum target) {
base::subtle::Atomic32 submit_count() const { return submit_count_; }
friend class QueryManager;
friend class QueryManagerTest;
friend class base::RefCounted<Query>;
void RunCallbacks();
// The manager that owns this Query.
QueryManager* manager_;
// The type of query.
GLenum target_;
// The shared memory used with this Query. We keep a reference to the Buffer
// to ensure it doesn't get released until we wrote results. sync_ points to
// memory inside buffer_.
scoped_refptr<gpu::Buffer> buffer_;
QuerySync* sync_;
// Count to set process count do when completed.
base::subtle::Atomic32 submit_count_;
// Current state of the query.
enum QueryState {
kQueryState_Initialize, // Has not been queried yet.
kQueryState_Active, // Query began but has not ended.
kQueryState_Paused, // Query was active but is now paused.
kQueryState_Pending, // Query ended, waiting for result.
kQueryState_Finished, // Query received result.
} query_state_;
// True if deleted.
bool deleted_;
// List of callbacks to run when result is available.
std::vector<base::OnceClosure> callbacks_;
virtual ~QueryManager();
// Must call before destruction.
void Destroy(bool have_context);
// Creates a Query for the given query.
virtual Query* CreateQuery(GLenum target,
GLuint client_id,
scoped_refptr<gpu::Buffer> buffer,
QuerySync* sync);
// Gets the query info for the given query.
Query* GetQuery(GLuint client_id);
// Gets the currently active query for a target.
Query* GetActiveQuery(GLenum target);
// Removes a query info for the given query.
void RemoveQuery(GLuint client_id);
// Returns false if any query is pointing to invalid shared memory.
void BeginQuery(Query* query);
// Returns false if any query is pointing to invalid shared memory.
void EndQuery(Query* query, base::subtle::Atomic32 submit_count);
// Returns false if any query is pointing to invalid shared memory.
void QueryCounter(Query* query, base::subtle::Atomic32 submit_count);
void PauseQueries();
void ResumeQueries();
void BeginProcessingCommands();
void EndProcessingCommands();
// Processes pending queries. Returns false if any queries are pointing
// to invalid shared memory. |did_finish| is true if this is called as
// a result of calling glFinish().
void ProcessPendingQueries(bool did_finish);
// True if there are pending queries.
bool HavePendingQueries();
void GenQueries(GLsizei n, const GLuint* queries);
bool IsValidQuery(GLuint id);
void StartTracking(Query* query);
void StopTracking(Query* query);
// Wrappers for BeginQueryARB and EndQueryARB to hide differences between
// ARB_occlusion_query2 and EXT_occlusion_query_boolean.
void BeginQueryHelper(GLenum target, GLuint id);
void EndQueryHelper(GLenum target);
// Adds to queue of queries waiting for completion.
// Returns false if any query is pointing to invalid shared memory.
void AddPendingQuery(Query* query, base::subtle::Atomic32 submit_count);
// Removes a query from the queue of pending queries.
// Returns false if any query is pointing to invalid shared memory.
void RemovePendingQuery(Query* query);
// Returns a target used for the underlying GL extension
// used to emulate a query.
virtual GLenum AdjustTargetForEmulation(GLenum target);
// Counts the number of Queries allocated with 'this' as their manager.
// Allows checking no Query will outlive this.
unsigned query_count_;
// Info for each query in the system.
using QueryMap = std::unordered_map<GLuint, scoped_refptr<Query>>;
QueryMap queries_;
using GeneratedQueryIds = std::unordered_set<GLuint>;
GeneratedQueryIds generated_query_ids_;
// A map of targets -> Query for current active queries.
using ActiveQueryMap = std::map<GLenum, scoped_refptr<Query>>;
ActiveQueryMap active_queries_;
// Queries waiting for completion.
using QueryQueue = base::circular_deque<scoped_refptr<Query>>;
QueryQueue pending_queries_;
} // namespace gpu