Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -2184,6 +2184,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc + .
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/gpu_tracer_vk.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_cache_vk.cc + ../../../flutter/LICENSE
Expand Down Expand Up @@ -4945,6 +4947,8 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/gpu_tracer_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/limits_vk.h
FILE: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.cc
FILE: ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache.h
Expand Down
2 changes: 2 additions & 0 deletions impeller/renderer/backend/vulkan/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ impeller_component("vulkan") {
"fence_waiter_vk.h",
"formats_vk.cc",
"formats_vk.h",
"gpu_tracer_vk.cc",
"gpu_tracer_vk.h",
"limits_vk.h",
"pass_bindings_cache.cc",
"pass_bindings_cache.h",
Expand Down
3 changes: 3 additions & 0 deletions impeller/renderer/backend/vulkan/command_buffer_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ const std::shared_ptr<CommandEncoderVK>& CommandBufferVK::GetEncoder() {
}

bool CommandBufferVK::OnSubmitCommands(CompletionCallback callback) {
if (!encoder_) {
encoder_ = encoder_factory_->Create();
}
if (!callback) {
return encoder_->Submit();
}
Expand Down
9 changes: 9 additions & 0 deletions impeller/renderer/backend/vulkan/context_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
#include "impeller/renderer/backend/vulkan/debug_report_vk.h"
#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h"
#include "impeller/renderer/backend/vulkan/gpu_tracer_vk.h"
#include "impeller/renderer/backend/vulkan/resource_manager_vk.h"
#include "impeller/renderer/backend/vulkan/surface_context_vk.h"
#include "impeller/renderer/capabilities.h"
Expand Down Expand Up @@ -430,6 +431,10 @@ void ContextVK::Setup(Settings settings) {
device_name_ = std::string(physical_device_properties.deviceName);
is_valid_ = true;

// Create the GPU Tracer later because it depends on state from
// the ContextVK.
gpu_tracer_ = std::make_shared<GPUTracerVK>(weak_from_this());

//----------------------------------------------------------------------------
/// Label all the relevant objects. This happens after setup so that the
/// debug messengers have had a chance to be set up.
Expand Down Expand Up @@ -532,4 +537,8 @@ ContextVK::CreateGraphicsCommandEncoderFactory() const {
return std::make_unique<CommandEncoderFactoryVK>(weak_from_this());
}

std::shared_ptr<GPUTracerVK> ContextVK::GetGPUTracer() const {
return gpu_tracer_;
}

} // namespace impeller
7 changes: 7 additions & 0 deletions impeller/renderer/backend/vulkan/context_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class DebugReportVK;
class FenceWaiterVK;
class ResourceManagerVK;
class SurfaceContextVK;
class GPUTracerVK;

class ContextVK final : public Context,
public BackendCast<ContextVK, Context>,
Expand Down Expand Up @@ -144,6 +145,10 @@ class ContextVK final : public Context,

std::shared_ptr<CommandPoolRecyclerVK> GetCommandPoolRecycler() const;

std::shared_ptr<GPUTracerVK> GetGPUTracer() const;

void RecordFrameEndTime() const;

private:
struct DeviceHolderImpl : public DeviceHolder {
// |DeviceHolder|
Expand Down Expand Up @@ -171,6 +176,8 @@ class ContextVK final : public Context,
std::shared_ptr<CommandPoolRecyclerVK> command_pool_recycler_;
std::string device_name_;
std::shared_ptr<fml::ConcurrentMessageLoop> raster_message_loop_;
std::shared_ptr<GPUTracerVK> gpu_tracer_;

bool sync_presentation_ = false;
const uint64_t hash_;

Expand Down
133 changes: 133 additions & 0 deletions impeller/renderer/backend/vulkan/gpu_tracer_vk.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "impeller/renderer/backend/vulkan/gpu_tracer_vk.h"

#include <utility>
#include "fml/trace_event.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
#include "impeller/renderer/backend/vulkan/context_vk.h"
#include "impeller/renderer/command_buffer.h"

namespace impeller {

static constexpr uint32_t kPoolSize = 128u;

GPUTracerVK::GPUTracerVK(const std::weak_ptr<ContextVK>& context)
: context_(context) {
auto strong_context = context_.lock();
if (!strong_context) {
return;
}
timestamp_period_ = strong_context->GetPhysicalDevice()
.getProperties()
.limits.timestampPeriod;
if (timestamp_period_ <= 0) {
// The device does not support timestamp queries.
return;
}
vk::QueryPoolCreateInfo info;
info.queryCount = kPoolSize;
info.queryType = vk::QueryType::eTimestamp;

auto [status, pool] = strong_context->GetDevice().createQueryPoolUnique(info);
if (status != vk::Result::eSuccess) {
VALIDATION_LOG << "Failed to create query pool.";
return;
}
query_pool_ = std::move(pool);
// Disable tracing in release mode.
#ifdef IMPELLER_DEBUG
valid_ = true;
#endif
}

void GPUTracerVK::RecordStartFrameTime() {
if (!valid_) {
return;
}
auto strong_context = context_.lock();
if (!strong_context) {
return;
}
auto buffer = strong_context->CreateCommandBuffer();
auto vk_trace_cmd_buffer =
CommandBufferVK::Cast(*buffer).GetEncoder()->GetCommandBuffer();
// The two commands below are executed in order, such that writeTimeStamp is
// guaranteed to occur after resetQueryPool has finished. The validation
// layer seem particularly strict, and efforts to reset the entire pool
// were met with validation errors (though seemingly correct measurements).
// To work around this, the tracer only resets the query that will be
// used next.
vk_trace_cmd_buffer.resetQueryPool(query_pool_.get(), current_index_, 1);
vk_trace_cmd_buffer.writeTimestamp(vk::PipelineStageFlagBits::eTopOfPipe,
query_pool_.get(), current_index_);

if (!buffer->SubmitCommands()) {
VALIDATION_LOG << "GPUTracerVK: Failed to record start time.";
}

// The logic in RecordEndFrameTime requires us to have recorded a pair of
// tracing events. If this method failed for any reason we need to be sure we
// don't attempt to record and read back a second value, or we will get values
// that span multiple frames.
started_frame_ = true;
}

void GPUTracerVK::RecordEndFrameTime() {
if (!valid_ || !started_frame_) {
return;
}
auto strong_context = context_.lock();
if (!strong_context) {
return;
}

started_frame_ = false;
auto last_query = current_index_;
current_index_ += 1;

auto buffer = strong_context->CreateCommandBuffer();
auto vk_trace_cmd_buffer =
CommandBufferVK::Cast(*buffer).GetEncoder()->GetCommandBuffer();
vk_trace_cmd_buffer.resetQueryPool(query_pool_.get(), current_index_, 1);
vk_trace_cmd_buffer.writeTimestamp(vk::PipelineStageFlagBits::eBottomOfPipe,
query_pool_.get(), current_index_);

// On completion of the second time stamp recording, we read back this value
// and the previous value. The difference is approximately the frame time.
const auto device_holder = strong_context->GetDeviceHolder();
if (!buffer->SubmitCommands([&, last_query,
device_holder](CommandBuffer::Status status) {
auto strong_context = context_.lock();
if (!strong_context) {
return;
}
uint64_t bits[2] = {0, 0};
auto result = device_holder->GetDevice().getQueryPoolResults(
query_pool_.get(), last_query, 2, sizeof(bits), &bits,
sizeof(int64_t), vk::QueryResultFlagBits::e64);

if (result == vk::Result::eSuccess) {
// This value should probably be available in some form besides a
// timeline event but that is a job for a future Jonah.
auto gpu_ms = (((bits[1] - bits[0]) * timestamp_period_) / 1000000);
FML_TRACE_COUNTER("flutter", "GPUTracer",
1234, // Trace Counter ID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably just be reinterpret_cast<int64_t>(this), or at least a named constant somewhere.

"FrameTimeMS", gpu_ms);
}
})) {
if (!buffer->SubmitCommands()) {
VALIDATION_LOG << "GPUTracerVK failed to record frame end time.";
}
}

if (current_index_ == kPoolSize - 1) {
current_index_ = 0u;
}
}

} // namespace impeller
40 changes: 40 additions & 0 deletions impeller/renderer/backend/vulkan/gpu_tracer_vk.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>

#include "impeller/renderer/backend/vulkan/context_vk.h"

namespace impeller {

/// @brief A class that uses timestamp queries to record the approximate GPU
/// execution time.
class GPUTracerVK {
public:
explicit GPUTracerVK(const std::weak_ptr<ContextVK>& context);

~GPUTracerVK() = default;

/// @brief Record the approximate start time of the GPU workload for the
/// current frame.
void RecordStartFrameTime();

/// @brief Record the approximate end time of the GPU workload for the current
/// frame.
void RecordEndFrameTime();

private:
void ResetQueryPool(size_t pool);

const std::weak_ptr<ContextVK> context_;
vk::UniqueQueryPool query_pool_ = {};

size_t current_index_ = 0u;
// The number of nanoseconds for each timestamp unit.
float timestamp_period_ = 1;
bool started_frame_ = false;
bool valid_ = false;
};

} // namespace impeller
9 changes: 9 additions & 0 deletions impeller/renderer/backend/vulkan/swapchain_impl_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@

#include "impeller/renderer/backend/vulkan/swapchain_impl_vk.h"

#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
#include "impeller/renderer/backend/vulkan/context_vk.h"
#include "impeller/renderer/backend/vulkan/formats_vk.h"
#include "impeller/renderer/backend/vulkan/gpu_tracer_vk.h"
#include "impeller/renderer/backend/vulkan/surface_vk.h"
#include "impeller/renderer/backend/vulkan/swapchain_image_vk.h"
#include "impeller/renderer/context.h"
#include "vulkan/vulkan_structs.hpp"

namespace impeller {
Expand Down Expand Up @@ -375,6 +378,9 @@ SwapchainImplVK::AcquireResult SwapchainImplVK::AcquireNextDrawable() {
nullptr // fence
);

/// Record the approximate start of the GPU workload.
context.GetGPUTracer()->RecordStartFrameTime();

switch (acq_result) {
case vk::Result::eSuccess:
// Keep going.
Expand Down Expand Up @@ -450,6 +456,9 @@ bool SwapchainImplVK::Present(const std::shared_ptr<SwapchainImageVK>& image,
}
}

/// Record the approximate end of the GPU workload.
context.GetGPUTracer()->RecordEndFrameTime();

//----------------------------------------------------------------------------
/// Signal that the presentation semaphore is ready.
///
Expand Down