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 7 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 @@ -2127,6 +2127,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/metal/device_buffer_mtl.h + .
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/formats_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/formats_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/gpu_tracer_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/gpu_tracer_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/pipeline_library_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/pipeline_library_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/pipeline_mtl.h + ../../../flutter/LICENSE
Expand Down Expand Up @@ -4887,6 +4889,8 @@ FILE: ../../../flutter/impeller/renderer/backend/metal/device_buffer_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/device_buffer_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/formats_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/formats_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/gpu_tracer_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/gpu_tracer_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/pipeline_library_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/pipeline_library_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/pipeline_mtl.h
Expand Down
2 changes: 2 additions & 0 deletions impeller/renderer/backend/metal/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ impeller_component("metal") {
"device_buffer_mtl.mm",
"formats_mtl.h",
"formats_mtl.mm",
"gpu_tracer_mtl.h",
"gpu_tracer_mtl.mm",
"pipeline_library_mtl.h",
"pipeline_library_mtl.mm",
"pipeline_mtl.h",
Expand Down
8 changes: 8 additions & 0 deletions impeller/renderer/backend/metal/command_buffer_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
}

bool CommandBufferMTL::OnSubmitCommands(CompletionCallback callback) {
auto context = context_.lock();
if (!context) {
return false;
}
ContextMTL::Cast(*context).GetGPUTracer()->RecordCmdBuffer(buffer_);

if (callback) {
[buffer_
addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
Expand Down Expand Up @@ -190,6 +196,8 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
auto buffer = buffer_;
buffer_ = nil;

ContextMTL::Cast(*context).GetGPUTracer()->RecordCmdBuffer(buffer);

auto worker_task_runner = ContextMTL::Cast(*context).GetWorkerTaskRunner();
auto mtl_render_pass = static_cast<RenderPassMTL*>(render_pass.get());

Expand Down
4 changes: 4 additions & 0 deletions impeller/renderer/backend/metal/context_mtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "impeller/core/sampler.h"
#include "impeller/renderer/backend/metal/allocator_mtl.h"
#include "impeller/renderer/backend/metal/command_buffer_mtl.h"
#include "impeller/renderer/backend/metal/gpu_tracer_mtl.h"
#include "impeller/renderer/backend/metal/pipeline_library_mtl.h"
#include "impeller/renderer/backend/metal/shader_library_mtl.h"
#include "impeller/renderer/capabilities.h"
Expand Down Expand Up @@ -93,6 +94,8 @@ class ContextMTL final : public Context,

std::shared_ptr<const fml::SyncSwitch> GetIsGpuDisabledSyncSwitch() const;

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

private:
id<MTLDevice> device_ = nullptr;
id<MTLCommandQueue> command_queue_ = nullptr;
Expand All @@ -103,6 +106,7 @@ class ContextMTL final : public Context,
std::shared_ptr<const Capabilities> device_capabilities_;
std::shared_ptr<fml::ConcurrentMessageLoop> raster_message_loop_;
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch_;
std::shared_ptr<GPUTracerMTL> gpu_tracer_;
bool is_valid_ = false;

ContextMTL(
Expand Down
8 changes: 7 additions & 1 deletion impeller/renderer/backend/metal/context_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
#include "impeller/renderer/backend/metal/context_mtl.h"

#include <Foundation/Foundation.h>
#include <memory>

#include "flutter/fml/concurrent_message_loop.h"
#include "flutter/fml/file.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/synchronization/sync_switch.h"
#include "impeller/core/sampler_descriptor.h"
#include "impeller/renderer/backend/metal/gpu_tracer_mtl.h"
#include "impeller/renderer/backend/metal/sampler_library_mtl.h"
#include "impeller/renderer/capabilities.h"

Expand Down Expand Up @@ -142,7 +144,7 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) {

device_capabilities_ =
InferMetalCapabilities(device_, PixelFormat::kB8G8R8A8UNormInt);

gpu_tracer_ = std::make_shared<GPUTracerMTL>();
is_valid_ = true;
}

Expand Down Expand Up @@ -325,6 +327,10 @@ new ContextMTL(device, command_queue,
raster_message_loop_.reset();
}

std::shared_ptr<GPUTracerMTL> ContextMTL::GetGPUTracer() const {
return gpu_tracer_;
}

const std::shared_ptr<fml::ConcurrentTaskRunner>
ContextMTL::GetWorkerTaskRunner() const {
return raster_message_loop_->GetTaskRunner();
Expand Down
53 changes: 53 additions & 0 deletions impeller/renderer/backend/metal/gpu_tracer_mtl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// 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.

#pragma once

#include <Metal/Metal.h>

#include <memory>
#include <optional>
#include "impeller/base/thread.h"
#include "impeller/base/thread_safety.h"
#include "impeller/geometry/scalar.h"

namespace impeller {

class ContextMTL;

/// @brief Approximate the GPU frame time by computing a difference between the
/// smallest
/// GPUStartTime and largest GPUEndTime for all cmd buffers submitted in
/// a frame workload.
class GPUTracerMTL : public std::enable_shared_from_this<GPUTracerMTL> {
public:
GPUTracerMTL() = default;

~GPUTracerMTL() = default;

/// @brief Record that the current frame has ended. Any additional cmd buffers
/// will be
/// attributed to the "next" frame.
void MarkFrameEnd();

/// @brief Record the current cmd buffer GPU execution timestamps into an
/// aggregate
/// frame workload metric.
void RecordCmdBuffer(id<MTLCommandBuffer> buffer);

private:
struct GPUTraceState {
Scalar smallest_timestamp = std::numeric_limits<float>::max();
Scalar largest_timestamp = 0;
size_t pending_buffers = 0;
};

[[maybe_unused]] mutable Mutex trace_state_mutex_;
[[maybe_unused]] GPUTraceState trace_states_[16] IPLR_GUARDED_BY(
trace_state_mutex_);
[[maybe_unused]] size_t current_state_ IPLR_GUARDED_BY(trace_state_mutex_) =
0u;
};

} // namespace impeller
60 changes: 60 additions & 0 deletions impeller/renderer/backend/metal/gpu_tracer_mtl.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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 <Metal/Metal.h>
#include "fml/trace_event.h"
#include "impeller/renderer/backend/metal/context_mtl.h"
#include "impeller/renderer/backend/metal/formats_mtl.h"

#include <memory>

#include "impeller/renderer/backend/metal/gpu_tracer_mtl.h"

namespace impeller {

void GPUTracerMTL::MarkFrameEnd() {
#ifdef IMPELLER_DEBUG
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit - rather than guarding each method, just don't even allocate this outside of debug?

if (@available(ios 10.3, tvos 10.2, macos 10.15, macCatalyst 13.0, *)) {
Lock lock(trace_state_mutex_);
current_state_ = (current_state_ + 1) % 16;
}
#endif // IMPELLER_DEBUG
}

void GPUTracerMTL::RecordCmdBuffer(id<MTLCommandBuffer> buffer) {
#ifdef IMPELLER_DEBUG
if (@available(ios 10.3, tvos 10.2, macos 10.15, macCatalyst 13.0, *)) {
Lock lock(trace_state_mutex_);
auto current_state = current_state_;
trace_states_[current_state].pending_buffers += 1;

auto weak_self = weak_from_this();
[buffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this has some issues with GPUTracerMTL being deleted (or retained), but I'm not quite sure how to solve that with object-c / c++ interop.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed, thanks @gaaclarke !

auto self = weak_self.lock();
if (!self) {
return;
}
Lock lock(self->trace_state_mutex_);
auto& state = self->trace_states_[current_state];
state.pending_buffers--;
state.smallest_timestamp = std::min(
state.smallest_timestamp, static_cast<Scalar>(buffer.GPUStartTime));
state.largest_timestamp = std::max(
state.largest_timestamp, static_cast<Scalar>(buffer.GPUEndTime));

if (state.pending_buffers == 0) {
auto gpu_ms =
(state.largest_timestamp - state.smallest_timestamp) * 1000;
state.smallest_timestamp = std::numeric_limits<float>::max();
state.largest_timestamp = 0;
FML_TRACE_COUNTER("flutter", "GPUTracer",
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like it should be a constant somewhere so that MTL and VK use the same one always

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Where would you want this? I can put it in core?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Im gonna punt on this - the trace event will probably change a few times

reinterpret_cast<int64_t>(this), // Trace Counter ID
"FrameTimeMS", gpu_ms);
}
}];
}
#endif // IMPELLER_DEBUG
}

} // namespace impeller
1 change: 1 addition & 0 deletions impeller/renderer/backend/metal/surface_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@
return false;
}
}
ContextMTL::Cast(context.get())->GetGPUTracer()->MarkFrameEnd();

if (drawable_) {
id<MTLCommandBuffer> command_buffer =
Expand Down