| // 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 <deque> |
| #include <memory> |
| #include <vector> |
| |
| #include "base/atomicops.h" |
| #include "base/containers/hash_tables.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "gpu/command_buffer/service/feature_info.h" |
| #include "gpu/gpu_export.h" |
| |
| namespace gl { |
| class GPUTimer; |
| class GPUTimingClient; |
| } |
| |
| namespace gpu { |
| |
| class GLES2Decoder; |
| |
| namespace gles2 { |
| |
| class FeatureInfo; |
| |
| // This class keeps track of the queries and their state |
| // As Queries are not shared there is one QueryManager per context. |
| class GPU_EXPORT QueryManager { |
| public: |
| class GPU_EXPORT Query : public base::RefCounted<Query> { |
| public: |
| Query(QueryManager* manager, |
| GLenum target, |
| int32_t shm_id, |
| uint32_t shm_offset); |
| |
| 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; |
| } |
| |
| int32_t shm_id() const { return shm_id_; } |
| |
| uint32_t shm_offset() const { return shm_offset_; } |
| |
| // Returns false if shared memory for sync is invalid. |
| virtual bool Begin() = 0; |
| |
| // Returns false if shared memory for sync is invalid. |
| virtual bool End(base::subtle::Atomic32 submit_count) = 0; |
| |
| // Returns false if shared memory for sync is invalid. |
| virtual bool QueryCounter(base::subtle::Atomic32 submit_count) = 0; |
| |
| // Returns false if shared memory for sync is invalid. |
| virtual bool 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; |
| |
| void AddCallback(base::Closure 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; |
| } |
| |
| // Returns false if shared memory for sync is invalid. |
| bool MarkAsCompleted(uint64_t result); |
| |
| void UnmarkAsPending() { |
| DCHECK(query_state_ == kQueryState_Pending); |
| query_state_ = kQueryState_Finished; |
| } |
| |
| // Returns false if shared memory for sync is invalid. |
| bool AddToPendingQueue(base::subtle::Atomic32 submit_count) { |
| return manager_->AddPendingQuery(this, submit_count); |
| } |
| |
| // Returns false if shared memory for sync is invalid. |
| bool AddToPendingTransferQueue(base::subtle::Atomic32 submit_count) { |
| return manager_->AddPendingTransferQuery(this, submit_count); |
| } |
| |
| void BeginQueryHelper(GLenum target, GLuint id) { |
| manager_->BeginQueryHelper(target, id); |
| } |
| |
| void EndQueryHelper(GLenum target) { |
| manager_->EndQueryHelper(target); |
| } |
| |
| void SafelyResetDisjointValue() { |
| manager_->SafelyResetDisjointValue(); |
| } |
| |
| void UpdateDisjointValue() { |
| manager_->UpdateDisjointValue(); |
| } |
| |
| void BeginContinualDisjointUpdate() { |
| manager_->update_disjoints_continually_ = true; |
| } |
| |
| 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. |
| int32_t shm_id_; |
| uint32_t shm_offset_; |
| |
| // 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::Closure> callbacks_; |
| }; |
| |
| QueryManager( |
| GLES2Decoder* decoder, |
| FeatureInfo* feature_info); |
| ~QueryManager(); |
| |
| // Must call before destruction. |
| void Destroy(bool have_context); |
| |
| // Sets up a location to be incremented whenever a disjoint is detected. |
| error::Error SetDisjointSync(int32_t shm_id, uint32_t shm_offset); |
| |
| // Creates a Query for the given query. |
| Query* CreateQuery(GLenum target, |
| GLuint client_id, |
| int32_t shm_id, |
| uint32_t shm_offset); |
| |
| // 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. |
| bool BeginQuery(Query* query); |
| |
| // Returns false if any query is pointing to invalid shared memory. |
| bool EndQuery(Query* query, base::subtle::Atomic32 submit_count); |
| |
| // Returns false if any query is pointing to invalid shared memory. |
| bool QueryCounter(Query* query, base::subtle::Atomic32 submit_count); |
| |
| void PauseQueries(); |
| void ResumeQueries(); |
| |
| // 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(). |
| bool ProcessPendingQueries(bool did_finish); |
| |
| // True if there are pending queries. |
| bool HavePendingQueries(); |
| |
| // Processes pending transfer queries. Returns false if any queries are |
| // pointing to invalid shared memory. |
| bool ProcessPendingTransferQueries(); |
| |
| // True if there are pending transfer queries. |
| bool HavePendingTransferQueries(); |
| |
| // Do any updates we need to do when the frame has begun. |
| void ProcessFrameBeginUpdates(); |
| |
| GLES2Decoder* decoder() const { |
| return decoder_; |
| } |
| |
| std::unique_ptr<gl::GPUTimer> CreateGPUTimer(bool elapsed_time); |
| bool GPUTimingAvailable(); |
| |
| void GenQueries(GLsizei n, const GLuint* queries); |
| bool IsValidQuery(GLuint id); |
| |
| private: |
| 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. |
| bool AddPendingQuery(Query* query, base::subtle::Atomic32 submit_count); |
| |
| // Adds to queue of transfer queries waiting for completion. |
| // Returns false if any query is pointing to invalid shared memory. |
| bool AddPendingTransferQuery(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. |
| bool RemovePendingQuery(Query* query); |
| |
| // Returns a target used for the underlying GL extension |
| // used to emulate a query. |
| GLenum AdjustTargetForEmulation(GLenum target); |
| |
| // Checks and notifies if a disjoint occurred. |
| void UpdateDisjointValue(); |
| |
| // Safely resets the disjoint value if no queries are active. |
| void SafelyResetDisjointValue(); |
| |
| // Used to validate shared memory and get GL errors. |
| GLES2Decoder* decoder_; |
| |
| bool use_arb_occlusion_query2_for_occlusion_query_boolean_; |
| bool use_arb_occlusion_query_for_occlusion_query_boolean_; |
| |
| // Whether we are tracking disjoint values every frame. |
| bool update_disjoints_continually_; |
| |
| // The shared memory used for disjoint notifications. |
| int32_t disjoint_notify_shm_id_; |
| uint32_t disjoint_notify_shm_offset_; |
| |
| // Current number of disjoints notified. |
| uint32_t disjoints_notified_; |
| |
| // 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. |
| typedef base::hash_map<GLuint, scoped_refptr<Query> > QueryMap; |
| QueryMap queries_; |
| |
| typedef base::hash_set<GLuint> GeneratedQueryIds; |
| GeneratedQueryIds generated_query_ids_; |
| |
| // A map of targets -> Query for current active queries. |
| typedef std::map<GLenum, scoped_refptr<Query> > ActiveQueryMap; |
| ActiveQueryMap active_queries_; |
| |
| // Queries waiting for completion. |
| typedef std::deque<scoped_refptr<Query> > QueryQueue; |
| QueryQueue pending_queries_; |
| |
| // Async pixel transfer queries waiting for completion. |
| QueryQueue pending_transfer_queries_; |
| |
| scoped_refptr<gl::GPUTimingClient> gpu_timing_client_; |
| |
| DISALLOW_COPY_AND_ASSIGN(QueryManager); |
| }; |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |
| #endif // GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_ |