|  | // 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_ |