19#include "vulkan/vulkan.hpp"
26 bool enable_gpu_tracing)
27 : context_(
std::move(context)) {
28 if (!enable_gpu_tracing) {
31 timestamp_period_ = context_.lock()
35 .limits.timestampPeriod;
36 if (timestamp_period_ <= 0) {
50 Lock lock(trace_state_mutex_);
54 for (
auto i = 0u; i < kTraceStatesSize; i++) {
55 vk::QueryPoolCreateInfo
info;
57 info.queryType = vk::QueryType::eTimestamp;
60 if (status != vk::Result::eSuccess) {
64 trace_states_[i].query_pool = std::move(
pool);
65 buffer_vk.
GetEncoder()->GetCommandBuffer().resetQueryPool(
66 trace_states_[i].query_pool.get(), 0,
kPoolSize);
84 raster_thread_id_ = std::this_thread::get_id();
94 Lock lock(trace_state_mutex_);
95 current_state_ = (current_state_ + 1) % kTraceStatesSize;
97 auto&
state = trace_states_[current_state_];
104 state.pending_buffers = 0;
105 state.current_index = 0;
109 return std::make_unique<GPUProbe>(weak_from_this());
112void GPUTracerVK::RecordCmdBufferStart(
const vk::CommandBuffer&
buffer,
114 if (!enabled_ || std::this_thread::get_id() != raster_thread_id_ ||
118 Lock lock(trace_state_mutex_);
119 auto&
state = trace_states_[current_state_];
122 if (!states_to_reset_.empty()) {
123 for (
auto i = 0u; i < states_to_reset_.size(); i++) {
124 buffer.resetQueryPool(trace_states_[states_to_reset_[i]].query_pool.get(),
127 states_to_reset_.clear();
137 buffer.writeTimestamp(vk::PipelineStageFlagBits::eTopOfPipe,
138 trace_states_[current_state_].query_pool.get(),
139 state.current_index);
140 state.current_index += 1;
141 probe.index_ = current_state_;
142 state.pending_buffers += 1;
145void GPUTracerVK::RecordCmdBufferEnd(
const vk::CommandBuffer&
buffer,
147 if (!enabled_ || std::this_thread::get_id() != raster_thread_id_ ||
148 !in_frame_ || !probe.index_.has_value()) {
151 Lock lock(trace_state_mutex_);
152 GPUTraceState&
state = trace_states_[current_state_];
158 buffer.writeTimestamp(vk::PipelineStageFlagBits::eBottomOfPipe,
161 state.current_index += 1;
164void GPUTracerVK::OnFenceComplete(
size_t frame_index) {
170 size_t query_count = 0;
173 Lock lock(trace_state_mutex_);
174 GPUTraceState&
state = trace_states_[frame_index];
177 state.pending_buffers -= 1;
178 pending =
state.pending_buffers;
179 query_count =
state.current_index;
184 std::vector<uint64_t>
bits(query_count);
185 std::shared_ptr<ContextVK> context = context_.lock();
190 auto result = context->GetDevice().getQueryPoolResults(
191 pool, 0, query_count, query_count *
sizeof(uint64_t),
bits.data(),
192 sizeof(uint64_t), vk::QueryResultFlagBits::e64);
201 if (
result == vk::Result::eSuccess) {
202 uint64_t smallest_timestamp = std::numeric_limits<uint64_t>::max();
203 uint64_t largest_timestamp = 0;
204 for (
auto i = 0u; i <
bits.size(); i++) {
205 smallest_timestamp = std::min(smallest_timestamp, bits[i]);
206 largest_timestamp = std::max(largest_timestamp, bits[i]);
209 (((largest_timestamp - smallest_timestamp) * timestamp_period_) /
212 reinterpret_cast<int64_t
>(
this),
213 "FrameTimeMS", gpu_ms);
217 Lock lock(trace_state_mutex_);
218 states_to_reset_.push_back(frame_index);
226 if (!index_.has_value()) {
229 auto tracer = tracer_.lock();
233 tracer->OnFenceComplete(index_.value());
237 auto tracer = tracer_.lock();
241 tracer->RecordCmdBufferStart(
buffer, *
this);
245 auto tracer = tracer_.lock();
249 tracer->RecordCmdBufferEnd(
buffer, *
this);
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static CommandBufferVK & Cast(CommandBuffer &base)
const std::shared_ptr< CommandEncoderVK > & GetEncoder()
const vk::Device & GetDevice() const
std::shared_ptr< CommandBuffer > CreateCommandBuffer() const override
Create a new command buffer. Command buffers can be used to encode graphics, blit,...
std::shared_ptr< CommandQueue > GetCommandQueue() const override
Return the graphics queue for submitting command buffers.
void RecordCmdBufferStart(const vk::CommandBuffer &buffer)
Record a timestamp query into the provided cmd buffer to record start time.
GPUProbe(const std::weak_ptr< GPUTracerVK > &tracer)
void RecordCmdBufferEnd(const vk::CommandBuffer &buffer)
Record a timestamp query into the provided cmd buffer to record end time.
void MarkFrameStart()
Signal the start of a frame workload.
void MarkFrameEnd()
Signal the end of a frame workload.
std::unique_ptr< GPUProbe > CreateGPUProbe()
Create a GPUProbe to trace the execution of a command buffer on the GPU.
void InitializeQueryPool(const ContextVK &context)
Initialize the set of query pools.
GPUTracerVK(std::weak_ptr< ContextVK > context, bool enable_gpu_tracing)
static const uint8_t buffer[]
#define FML_DCHECK(condition)
static constexpr uint32_t kPoolSize
#define FML_TRACE_COUNTER(category_group, name, counter_id, arg1,...)