11 #include "fml/logging.h"
12 #include "fml/trace_event.h"
15 #include "vulkan/vulkan.hpp"
22 : device_holder_(device_holder) {
23 timestamp_period_ = device_holder_->GetPhysicalDevice()
25 .limits.timestampPeriod;
26 if (timestamp_period_ <= 0) {
41 FML_DCHECK(!in_frame_);
43 raster_thread_id_ = std::this_thread::get_id();
51 Lock lock(trace_state_mutex_);
52 current_state_ = (current_state_ + 1) % kTraceStatesSize;
54 auto& state = trace_states_[current_state_];
60 FML_DCHECK(state.pending_buffers == 0u);
62 state.pending_buffers = 0;
63 state.current_index = 0;
68 return std::make_unique<GPUProbe>(weak_from_this());
71 void GPUTracerVK::RecordCmdBufferStart(
const vk::CommandBuffer& buffer,
73 if (!enabled_ || std::this_thread::get_id() != raster_thread_id_ ||
77 Lock lock(trace_state_mutex_);
78 auto& state = trace_states_[current_state_];
81 if (state.pending_buffers == 0) {
82 vk::QueryPoolCreateInfo info;
84 info.queryType = vk::QueryType::eTimestamp;
87 device_holder_->GetDevice().createQueryPoolUnique(info);
88 if (status != vk::Result::eSuccess) {
92 trace_states_[current_state_].query_pool = std::move(pool);
93 buffer.resetQueryPool(trace_states_[current_state_].query_pool.get(), 0,
104 buffer.writeTimestamp(vk::PipelineStageFlagBits::eTopOfPipe,
105 trace_states_[current_state_].query_pool.get(),
106 state.current_index);
107 state.current_index += 1;
108 if (!probe.index_.has_value()) {
109 state.pending_buffers += 1;
110 probe.index_ = current_state_;
114 void GPUTracerVK::RecordCmdBufferEnd(
const vk::CommandBuffer& buffer,
116 if (!enabled_ || std::this_thread::get_id() != raster_thread_id_ ||
120 Lock lock(trace_state_mutex_);
121 GPUTraceState& state = trace_states_[current_state_];
127 buffer.writeTimestamp(vk::PipelineStageFlagBits::eBottomOfPipe,
128 state.query_pool.get(), state.current_index);
130 state.current_index += 1;
131 if (!probe.index_.has_value()) {
132 state.pending_buffers += 1;
133 probe.index_ = current_state_;
137 void GPUTracerVK::OnFenceComplete(
size_t frame_index) {
141 Lock lock(trace_state_mutex_);
142 GPUTraceState& state = trace_states_[frame_index];
144 FML_DCHECK(state.pending_buffers > 0);
145 state.pending_buffers -= 1;
147 if (state.pending_buffers == 0) {
148 auto buffer_count = state.current_index;
149 std::vector<uint64_t> bits(buffer_count);
151 auto result = device_holder_->GetDevice().getQueryPoolResults(
152 state.query_pool.get(), 0, state.current_index,
153 buffer_count *
sizeof(uint64_t), bits.data(),
sizeof(uint64_t),
154 vk::QueryResultFlagBits::e64);
163 if (result != vk::Result::eSuccess) {
167 uint64_t smallest_timestamp = std::numeric_limits<uint64_t>::max();
168 uint64_t largest_timestamp = 0;
169 for (
auto i = 0u; i < bits.size(); i++) {
170 smallest_timestamp = std::min(smallest_timestamp, bits[i]);
171 largest_timestamp = std::max(largest_timestamp, bits[i]);
174 (((largest_timestamp - smallest_timestamp) * timestamp_period_) /
176 FML_TRACE_COUNTER(
"flutter",
"GPUTracer",
177 reinterpret_cast<int64_t
>(
this),
178 "FrameTimeMS", gpu_ms);
186 if (!index_.has_value()) {
189 auto tracer = tracer_.lock();
193 tracer->OnFenceComplete(index_.value());
197 auto tracer = tracer_.lock();
201 tracer->RecordCmdBufferStart(buffer, *
this);
205 auto tracer = tracer_.lock();
209 tracer->RecordCmdBufferEnd(buffer, *
this);