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 @@ -2128,6 +2128,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 @@ -4893,6 +4895,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
11 changes: 11 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,13 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
}

bool CommandBufferMTL::OnSubmitCommands(CompletionCallback callback) {
auto context = context_.lock();
if (!context) {
return false;
}
#ifdef IMPELLER_DEBUG
ContextMTL::Cast(*context).GetGPUTracer()->RecordCmdBuffer(buffer_);
#endif // IMPELLER_DEBUG
if (callback) {
[buffer_
addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
Expand Down Expand Up @@ -190,6 +197,10 @@ static bool LogMTLCommandBufferErrorIfPresent(id<MTLCommandBuffer> buffer) {
auto buffer = buffer_;
buffer_ = nil;

#ifdef IMPELLER_DEBUG
ContextMTL::Cast(*context).GetGPUTracer()->RecordCmdBuffer(buffer);
#endif // IMPELLER_DEBUG

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

Expand Down
8 changes: 8 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,10 @@ class ContextMTL final : public Context,

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

#ifdef IMPELLER_DEBUG
std::shared_ptr<GPUTracerMTL> GetGPUTracer() const;
#endif // IMPELLER_DEBUG

// |Context|
void StoreTaskForGPU(std::function<void()> task) override;

Expand All @@ -116,6 +121,9 @@ 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_;
#ifdef IMPELLER_DEBUG
std::shared_ptr<GPUTracerMTL> gpu_tracer_;
#endif // IMPELLER_DEBUG
std::deque<std::function<void()>> tasks_awaiting_gpu_;
std::unique_ptr<SyncSwitchObserver> sync_switch_observer_;
bool is_valid_ = false;
Expand Down
12 changes: 11 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 @@ -145,7 +147,9 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) {

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

#ifdef IMPELLER_DEBUG
gpu_tracer_ = std::make_shared<GPUTracerMTL>();
#endif // IMPELLER_DEBUG
is_valid_ = true;
}

Expand Down Expand Up @@ -330,6 +334,12 @@ new ContextMTL(device, command_queue,
raster_message_loop_.reset();
}

#ifdef IMPELLER_DEBUG
std::shared_ptr<GPUTracerMTL> ContextMTL::GetGPUTracer() const {
return gpu_tracer_;
}
#endif // IMPELLER_DEBUG

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

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

} // namespace impeller
56 changes: 56 additions & 0 deletions impeller/renderer/backend/metal/gpu_tracer_mtl.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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() {
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;
}
}

void GPUTracerMTL::RecordCmdBuffer(id<MTLCommandBuffer> buffer) {
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);
}
}];
}
}

} // namespace impeller
3 changes: 3 additions & 0 deletions impeller/renderer/backend/metal/surface_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@
return false;
}
}
#ifdef IMPELLER_DEBUG
ContextMTL::Cast(context.get())->GetGPUTracer()->MarkFrameEnd();
#endif // IMPELLER_DEBUG

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