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