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 all 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 @@ -2185,6 +2185,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 @@ -4946,6 +4948,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
134 changes: 134 additions & 0 deletions impeller/renderer/backend/vulkan/gpu_tracer_vk.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// 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::eBottomOfPipe,
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",
reinterpret_cast<int64_t>(this), // Trace Counter ID
"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 @@ -376,6 +379,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 @@ -451,6 +457,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