| // 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. |
| |
| #ifndef GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_ |
| #define GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_ |
| |
| #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 { |
| public: |
| class GPU_GLES2_EXPORT Query : public base::RefCounted<Query> { |
| public: |
| 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); |
| |
| protected: |
| 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) { |
| manager_->EndQueryHelper(target); |
| } |
| |
| base::subtle::Atomic32 submit_count() const { return submit_count_; } |
| |
| private: |
| 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_; |
| }; |
| |
| QueryManager(); |
| 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); |
| |
| protected: |
| 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_; |
| |
| DISALLOW_COPY_AND_ASSIGN(QueryManager); |
| }; |
| |
| } // namespace gpu |
| |
| #endif // GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_ |