| // 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_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 <list> |
| #include <memory> |
| #include <unordered_map> |
| |
| #include "base/atomicops.h" |
| #include "base/containers/circular_deque.h" |
| #include "base/containers/flat_map.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/macros.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(); |
| |
| QuerySync* 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(bucket->syncs + index) {} |
| QueryInfo() = default; |
| |
| uint32_t index() const { return sync - bucket->syncs; } |
| |
| Bucket* bucket = nullptr; |
| QuerySync* sync = nullptr; |
| int32_t submit_count = 0; |
| }; |
| |
| explicit QuerySyncManager(MappedMemoryManager* manager); |
| ~QuerySyncManager(); |
| |
| bool Alloc(QueryInfo* info); |
| void Free(const QueryInfo& sync); |
| void Shrink(CommandBufferHelper* helper); |
| |
| private: |
| FRIEND_TEST_ALL_PREFIXES(QuerySyncManagerTest, Shrink); |
| |
| MappedMemoryManager* mapped_memory_; |
| base::circular_deque<std::unique_ptr<Bucket>> buckets_; |
| |
| DISALLOW_COPY_AND_ASSIGN(QuerySyncManager); |
| }; |
| |
| 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_; |
| |
| base::Optional<base::OnceClosure> on_completed_callback_; |
| }; |
| |
| explicit QueryTracker(MappedMemoryManager* manager); |
| ~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. |
| MappedMemoryManager* mapped_memory_; |
| int32_t disjoint_count_sync_shm_id_; |
| uint32_t disjoint_count_sync_shm_offset_; |
| DisjointValueSync* disjoint_count_sync_; |
| uint32_t local_disjoint_count_; |
| |
| DISALLOW_COPY_AND_ASSIGN(QueryTracker); |
| }; |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |
| #endif // GPU_COMMAND_BUFFER_CLIENT_QUERY_TRACKER_H_ |