Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[iOS] Switch to FlutterMetalLayer by default. #54086

Merged
merged 3 commits into from
Jul 24, 2024
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
39 changes: 36 additions & 3 deletions impeller/renderer/backend/metal/context_mtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,36 @@

namespace impeller {

/// @brief Creates and manages a Metal capture scope that supports frame capture
/// when using the FlutterMetalLayer backed drawable.
class ImpellerMetalCaptureManager {
public:
/// @brief Construct a new capture manager from the provided Metal device.
explicit ImpellerMetalCaptureManager(id<MTLDevice> device);

~ImpellerMetalCaptureManager() = default;

/// Whether or not the Impeller capture scope is active.
///
/// This is distinct from whether or not there is a session recording the
/// capture. That can be checked with `[[MTLCaptureManager
/// sharedCaptureManager] isCapturing].`
bool CaptureScopeActive() const;

/// @brief Begin a new capture scope, no-op if the scope has already started.
void StartCapture();

/// @brief End the current capture scope.
void FinishCapture();

private:
id<MTLCaptureScope> current_capture_scope_;
bool scope_active_ = false;

ImpellerMetalCaptureManager(const ImpellerMetalCaptureManager&) = default;
ImpellerMetalCaptureManager(ImpellerMetalCaptureManager&&) = delete;
};

class ContextMTL final : public Context,
public BackendCast<ContextMTL, Context>,
public std::enable_shared_from_this<ContextMTL> {
Expand Down Expand Up @@ -101,6 +131,8 @@ class ContextMTL final : public Context,

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

const std::shared_ptr<ImpellerMetalCaptureManager> GetCaptureManager() const;
#endif // IMPELLER_DEBUG

// |Context|
Expand All @@ -125,12 +157,13 @@ class ContextMTL final : public Context,
std::shared_ptr<AllocatorMTL> resource_allocator_;
std::shared_ptr<const Capabilities> device_capabilities_;
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_;
std::shared_ptr<CommandQueue> command_queue_ip_;
#ifdef IMPELLER_DEBUG
std::shared_ptr<GPUTracerMTL> gpu_tracer_;
std::shared_ptr<ImpellerMetalCaptureManager> capture_manager_;
#endif // IMPELLER_DEBUG
bool is_valid_ = false;

ContextMTL(id<MTLDevice> device,
Expand Down
33 changes: 33 additions & 0 deletions impeller/renderer/backend/metal/context_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

#include "impeller/renderer/backend/metal/context_mtl.h"
#include <Metal/Metal.h>

#include <memory>

Expand Down Expand Up @@ -134,6 +135,7 @@ static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) {
command_queue_ip_ = std::make_shared<CommandQueue>();
#ifdef IMPELLER_DEBUG
gpu_tracer_ = std::make_shared<GPUTracerMTL>();
capture_manager_ = std::make_shared<ImpellerMetalCaptureManager>(device_);
#endif // IMPELLER_DEBUG
is_valid_ = true;
}
Expand Down Expand Up @@ -404,4 +406,35 @@ new ContextMTL(device, command_queue,
return command_queue_ip_;
}

#ifdef IMPELLER_DEBUG
const std::shared_ptr<ImpellerMetalCaptureManager>
ContextMTL::GetCaptureManager() const {
return capture_manager_;
}
#endif // IMPELLER_DEBUG

ImpellerMetalCaptureManager::ImpellerMetalCaptureManager(id<MTLDevice> device) {
current_capture_scope_ = [[MTLCaptureManager sharedCaptureManager]
newCaptureScopeWithDevice:device];
[current_capture_scope_ setLabel:@"Impeller Frame"];
}

bool ImpellerMetalCaptureManager::CaptureScopeActive() const {
return scope_active_;
}

void ImpellerMetalCaptureManager::StartCapture() {
if (scope_active_) {
return;
}
scope_active_ = true;
[current_capture_scope_ beginScope];
}

void ImpellerMetalCaptureManager::FinishCapture() {
FML_DCHECK(scope_active_);
[current_capture_scope_ endScope];
scope_active_ = false;
}

} // namespace impeller
5 changes: 5 additions & 0 deletions impeller/renderer/backend/metal/surface_mtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class SurfaceMTL final : public Surface {
// |Surface|
bool Present() const override;

void SetFrameBoundary(bool frame_boundary) {
frame_boundary_ = frame_boundary;
}

private:
std::weak_ptr<Context> context_;
std::shared_ptr<Texture> resolve_texture_;
Expand All @@ -69,6 +73,7 @@ class SurfaceMTL final : public Surface {
std::shared_ptr<Texture> destination_texture_;
bool requires_blit_ = false;
std::optional<IRect> clip_rect_;
bool frame_boundary_ = false;

static bool ShouldPerformPartialRepaint(std::optional<IRect> damage_rect);

Expand Down
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 @@ -231,6 +231,9 @@ - (void)flutterPrepareForPresent:(nonnull id<MTLCommandBuffer>)commandBuffer;

#ifdef IMPELLER_DEBUG
context->GetResourceAllocator()->DebugTraceMemoryStatistics();
if (frame_boundary_) {
ContextMTL::Cast(context.get())->GetCaptureManager()->FinishCapture();
}
#endif // IMPELLER_DEBUG

if (requires_blit_) {
Expand Down
9 changes: 9 additions & 0 deletions shell/gpu/gpu_surface_metal_impeller.mm
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@
last_texture_.reset([drawable.texture retain]);
}

#ifdef IMPELLER_DEBUG
impeller::ContextMTL::Cast(*impeller_renderer_->GetContext()).GetCaptureManager()->StartCapture();
#endif // IMPELLER_DEBUG

id<MTLTexture> last_texture = static_cast<id<MTLTexture>>(last_texture_);
SurfaceFrame::SubmitCallback submit_callback =
fml::MakeCopyable([damage = damage_,
Expand Down Expand Up @@ -186,6 +190,7 @@
display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
auto picture = impeller_dispatcher.EndRecordingAsPicture();
const bool reset_host_buffer = surface_frame.submit_info().frame_boundary;
surface->SetFrameBoundary(surface_frame.submit_info().frame_boundary);

return renderer->Render(
std::move(surface),
Expand Down Expand Up @@ -233,6 +238,10 @@
last_texture_.reset([mtl_texture retain]);
}

#ifdef IMPELLER_DEBUG
impeller::ContextMTL::Cast(*impeller_renderer_->GetContext()).GetCaptureManager()->StartCapture();
#endif // IMPELLER_DEBUG

SurfaceFrame::SubmitCallback submit_callback =
fml::MakeCopyable([disable_partial_repaint = disable_partial_repaint_, //
damage = damage_,
Expand Down
32 changes: 31 additions & 1 deletion shell/gpu/gpu_surface_metal_impeller_unittests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override

auto context = CreateImpellerContext();
std::unique_ptr<Surface> surface =
std::make_unique<GPUSurfaceMetalImpeller>(delegate.get(), CreateImpellerContext());
std::make_unique<GPUSurfaceMetalImpeller>(delegate.get(), context);

ASSERT_TRUE(surface->IsValid());

Expand All @@ -124,5 +124,35 @@ GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override
EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u);
}

#ifdef IMPELLER_DEBUG
TEST(GPUSurfaceMetalImpeller, CreatesImpellerCaptureScope) {
auto delegate = std::make_shared<TestGPUSurfaceMetalDelegate>();
delegate->SetDevice();

auto context = CreateImpellerContext();

EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive());

std::unique_ptr<Surface> surface =
std::make_unique<GPUSurfaceMetalImpeller>(delegate.get(), context);
auto frame_1 = surface->AcquireFrame(SkISize::Make(100, 100));
frame_1->set_submit_info({.frame_boundary = false});

EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive());

std::unique_ptr<Surface> surface_2 =
std::make_unique<GPUSurfaceMetalImpeller>(delegate.get(), context);
auto frame_2 = surface->AcquireFrame(SkISize::Make(100, 100));
frame_2->set_submit_info({.frame_boundary = true});

EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive());

ASSERT_TRUE(frame_1->Submit());
EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive());
ASSERT_TRUE(frame_2->Submit());
EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive());
}
#endif // IMPELLER_DEBUG

} // namespace testing
} // namespace flutter
Original file line number Diff line number Diff line change
Expand Up @@ -424,15 +424,14 @@ - (void)returnTexture:(FlutterTexture*)texture {
}

+ (BOOL)enabled {
static BOOL enabled = NO;
static BOOL enabled = YES;
static BOOL didCheckInfoPlist = NO;
if (!didCheckInfoPlist) {
didCheckInfoPlist = YES;
NSNumber* use_flutter_metal_layer =
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTUseFlutterMetalLayer"];
if (use_flutter_metal_layer != nil && [use_flutter_metal_layer boolValue]) {
enabled = YES;
FML_LOG(WARNING) << "Using FlutterMetalLayer. This is an experimental feature.";
if (use_flutter_metal_layer != nil && ![use_flutter_metal_layer boolValue]) {
enabled = NO;
}
}
return enabled;
Expand Down