| // Copyright 2012 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef GPU_COMMAND_BUFFER_CLIENT_QUERY_TRACKER_H_ | 
 | #define GPU_COMMAND_BUFFER_CLIENT_QUERY_TRACKER_H_ | 
 |  | 
 | #include <GLES2/gl2.h> | 
 | #include <limits.h> | 
 | #include <stddef.h> | 
 | #include <stdint.h> | 
 |  | 
 | #include <bitset> | 
 | #include <memory> | 
 | #include <optional> | 
 | #include <unordered_map> | 
 |  | 
 | #include "base/atomicops.h" | 
 | #include "base/containers/circular_deque.h" | 
 | #include "base/containers/flat_map.h" | 
 | #include "base/functional/callback.h" | 
 | #include "base/gtest_prod_util.h" | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "gles2_impl_export.h" | 
 | #include "gpu/command_buffer/common/gles2_cmd_format.h" | 
 |  | 
 | namespace gpu { | 
 |  | 
 | class CommandBufferHelper; | 
 | class MappedMemoryManager; | 
 |  | 
 | namespace gles2 { | 
 |  | 
 | // Manages buckets of QuerySync instances in mapped memory. | 
 | class GLES2_IMPL_EXPORT QuerySyncManager { | 
 |  public: | 
 |   static const uint32_t kSyncsPerBucket = 256; | 
 |  | 
 |   struct GLES2_IMPL_EXPORT Bucket { | 
 |     Bucket(QuerySync* sync_mem, int32_t shm_id, uint32_t shm_offset); | 
 |     ~Bucket(); | 
 |  | 
 |     void FreePendingSyncs(); | 
 |  | 
 |     raw_ptr<QuerySync, AllowPtrArithmetic> syncs; | 
 |     int32_t shm_id; | 
 |     uint32_t base_shm_offset; | 
 |     std::bitset<kSyncsPerBucket> in_use_query_syncs; | 
 |  | 
 |     struct PendingSync { | 
 |       uint32_t index; | 
 |       int32_t submit_count; | 
 |     }; | 
 |     std::vector<PendingSync> pending_syncs; | 
 |   }; | 
 |  | 
 |   struct QueryInfo { | 
 |     QueryInfo(Bucket* bucket, uint32_t index) | 
 |         : bucket(bucket), sync(UNSAFE_TODO(bucket->syncs + index)) {} | 
 |     QueryInfo() = default; | 
 |  | 
 |     uint32_t index() const { return sync - bucket->syncs.get(); } | 
 |  | 
 |     raw_ptr<Bucket, DanglingUntriaged> bucket = nullptr; | 
 |     // AllowPtrArithmetic because it is assigned an AllowPtrArithmetic pointer. | 
 |     raw_ptr<QuerySync, DanglingUntriaged | AllowPtrArithmetic> sync = nullptr; | 
 |     int32_t submit_count = 0; | 
 |   }; | 
 |  | 
 |   explicit QuerySyncManager(MappedMemoryManager* manager); | 
 |  | 
 |   QuerySyncManager(const QuerySyncManager&) = delete; | 
 |   QuerySyncManager& operator=(const QuerySyncManager&) = delete; | 
 |  | 
 |   ~QuerySyncManager(); | 
 |  | 
 |   bool Alloc(QueryInfo* info); | 
 |   void Free(const QueryInfo& sync); | 
 |   void Shrink(CommandBufferHelper* helper); | 
 |  | 
 |  private: | 
 |   FRIEND_TEST_ALL_PREFIXES(QuerySyncManagerTest, Shrink); | 
 |  | 
 |   raw_ptr<MappedMemoryManager> mapped_memory_; | 
 |   base::circular_deque<std::unique_ptr<Bucket>> buckets_; | 
 | }; | 
 |  | 
 | class GLES2_IMPL_EXPORT QueryTrackerClient { | 
 |  public: | 
 |   // Issue commands directly to the command buffer. | 
 |   virtual void IssueBeginQuery(GLenum target, | 
 |                                GLuint id, | 
 |                                uint32_t sync_data_shm_id, | 
 |                                uint32_t sync_data_shm_offset) = 0; | 
 |   virtual void IssueEndQuery(GLenum target, GLuint submit_count) = 0; | 
 |   virtual void IssueQueryCounter(GLuint id, | 
 |                                  GLenum target, | 
 |                                  uint32_t sync_data_shm_id, | 
 |                                  uint32_t sync_data_shm_offset, | 
 |                                  GLuint submit_count) = 0; | 
 |   virtual void IssueSetDisjointValueSync(uint32_t sync_data_shm_id, | 
 |                                          uint32_t sync_data_shm_offset) = 0; | 
 |  | 
 |   // Check for client side errors. | 
 |   virtual GLenum GetClientSideGLError() = 0; | 
 |  | 
 |   // Set client side error. | 
 |   virtual void SetGLError(GLenum error, | 
 |                           const char* function_name, | 
 |                           const char* msg) = 0; | 
 |  | 
 |   virtual CommandBufferHelper* cmd_buffer_helper() = 0; | 
 | }; | 
 |  | 
 | // Tracks queries for client side of command buffer. | 
 | class GLES2_IMPL_EXPORT QueryTracker { | 
 |  public: | 
 |   class GLES2_IMPL_EXPORT Query { | 
 |    public: | 
 |     enum State { | 
 |       kUninitialized,  // never used | 
 |       kActive,         // between begin - end | 
 |       kPending,        // not yet complete | 
 |       kComplete        // completed | 
 |     }; | 
 |  | 
 |     Query(GLuint id, GLenum target, const QuerySyncManager::QueryInfo& info); | 
 |     ~Query(); | 
 |  | 
 |     GLenum target() const { | 
 |       return target_; | 
 |     } | 
 |  | 
 |     GLuint id() const { | 
 |       return id_; | 
 |     } | 
 |  | 
 |     int32_t shm_id() const { return info_.bucket->shm_id; } | 
 |  | 
 |     uint32_t shm_offset() const { | 
 |       return info_.bucket->base_shm_offset + sizeof(QuerySync) * info_.index(); | 
 |     } | 
 |  | 
 |     void MarkAsActive() { | 
 |       state_ = kActive; | 
 |     } | 
 |  | 
 |     int32_t NextSubmitCount() const { | 
 |       int32_t submit_count = info_.submit_count + 1; | 
 |       if (submit_count == INT_MAX) | 
 |         submit_count = 1; | 
 |       return submit_count; | 
 |     } | 
 |  | 
 |     void MarkAsPending(int32_t token, int32_t submit_count) { | 
 |       info_.submit_count = submit_count; | 
 |       token_ = token; | 
 |       state_ = kPending; | 
 |     } | 
 |  | 
 |     base::subtle::Atomic32 submit_count() const { return info_.submit_count; } | 
 |  | 
 |     int32_t token() const { return token_; } | 
 |  | 
 |     bool NeverUsed() const { | 
 |       return state_ == kUninitialized; | 
 |     } | 
 |  | 
 |     bool Active() const { | 
 |       return state_ == kActive; | 
 |     } | 
 |  | 
 |     bool Pending() const { | 
 |       return state_ == kPending; | 
 |     } | 
 |  | 
 |     // Checks whether the result of this query is available. | 
 |     // If the result is pending and |flush_if_pending| is true, this will ensure | 
 |     // that at least the commands up till the EndQuery for this query are | 
 |     // flushed. | 
 |     bool CheckResultsAvailable(CommandBufferHelper* helper, | 
 |                                bool flush_if_pending); | 
 |  | 
 |     uint64_t GetResult() const; | 
 |  | 
 |     void SetCompletedCallback(base::OnceClosure callback); | 
 |  | 
 |    private: | 
 |     friend class QueryTracker; | 
 |     friend class QueryTrackerTest; | 
 |  | 
 |     void Begin(QueryTrackerClient* client); | 
 |     void End(QueryTrackerClient* client); | 
 |     void QueryCounter(QueryTrackerClient* client); | 
 |  | 
 |     GLuint id_; | 
 |     GLenum target_; | 
 |     QuerySyncManager::QueryInfo info_; | 
 |     State state_; | 
 |     int32_t token_; | 
 |     uint32_t flush_count_; | 
 |     uint64_t client_begin_time_us_;  // Only used for latency query target. | 
 |     uint64_t result_; | 
 |  | 
 |     std::optional<base::OnceClosure> on_completed_callback_; | 
 |   }; | 
 |  | 
 |   explicit QueryTracker(MappedMemoryManager* manager); | 
 |  | 
 |   QueryTracker(const QueryTracker&) = delete; | 
 |   QueryTracker& operator=(const QueryTracker&) = delete; | 
 |  | 
 |   ~QueryTracker(); | 
 |  | 
 |   Query* CreateQuery(GLuint id, GLenum target); | 
 |   Query* GetQuery(GLuint id); | 
 |   Query* GetCurrentQuery(GLenum target); | 
 |   void RemoveQuery(GLuint id); | 
 |   void Shrink(CommandBufferHelper* helper); | 
 |  | 
 |   bool BeginQuery(GLuint id, GLenum target, QueryTrackerClient* client); | 
 |   bool EndQuery(GLenum target, QueryTrackerClient* client); | 
 |   bool QueryCounter(GLuint id, GLenum target, QueryTrackerClient* client); | 
 |   bool SetDisjointSync(QueryTrackerClient* client); | 
 |   bool CheckAndResetDisjoint(); | 
 |  | 
 |   int32_t DisjointCountSyncShmID() const { | 
 |     return disjoint_count_sync_shm_id_; | 
 |   } | 
 |  | 
 |   uint32_t DisjointCountSyncShmOffset() const { | 
 |     return disjoint_count_sync_shm_offset_; | 
 |   } | 
 |  | 
 |  private: | 
 |   typedef std::unordered_map<GLuint, std::unique_ptr<Query>> QueryIdMap; | 
 |   typedef base::flat_map<GLenum, Query*> QueryTargetMap; | 
 |  | 
 |   QueryIdMap queries_; | 
 |   QueryTargetMap current_queries_; | 
 |   QuerySyncManager query_sync_manager_; | 
 |  | 
 |   // The shared memory used for synchronizing timer disjoint values. | 
 |   raw_ptr<MappedMemoryManager> mapped_memory_; | 
 |   int32_t disjoint_count_sync_shm_id_; | 
 |   uint32_t disjoint_count_sync_shm_offset_; | 
 |   raw_ptr<DisjointValueSync> disjoint_count_sync_; | 
 |   uint32_t local_disjoint_count_; | 
 | }; | 
 |  | 
 | }  // namespace gles2 | 
 | }  // namespace gpu | 
 |  | 
 | #endif  // GPU_COMMAND_BUFFER_CLIENT_QUERY_TRACKER_H_ |