Skip to content

Commit

Permalink
[Impeller] Add GPUTracer for impeller metal backend (flutter#36499)
Browse files Browse the repository at this point in the history
  • Loading branch information
luckysmg authored Oct 20, 2022
1 parent fcbabce commit c8fdcf1
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 0 deletions.
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,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 Expand Up @@ -1502,6 +1504,8 @@ FILE: ../../../flutter/impeller/renderer/device_buffer_descriptor.h
FILE: ../../../flutter/impeller/renderer/device_buffer_unittests.cc
FILE: ../../../flutter/impeller/renderer/formats.cc
FILE: ../../../flutter/impeller/renderer/formats.h
FILE: ../../../flutter/impeller/renderer/gpu_tracer.cc
FILE: ../../../flutter/impeller/renderer/gpu_tracer.h
FILE: ../../../flutter/impeller/renderer/host_buffer.cc
FILE: ../../../flutter/impeller/renderer/host_buffer.h
FILE: ../../../flutter/impeller/renderer/host_buffer_unittests.cc
Expand Down
2 changes: 2 additions & 0 deletions impeller/renderer/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ impeller_component("renderer") {
"device_buffer_descriptor.h",
"formats.cc",
"formats.h",
"gpu_tracer.cc",
"gpu_tracer.h",
"host_buffer.cc",
"host_buffer.h",
"pipeline.cc",
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
5 changes: 5 additions & 0 deletions impeller/renderer/backend/metal/context_mtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "impeller/base/backend_cast.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/context.h"
Expand Down Expand Up @@ -43,6 +44,7 @@ class ContextMTL final : public Context,
std::shared_ptr<SamplerLibrary> sampler_library_;
std::shared_ptr<AllocatorMTL> resource_allocator_;
std::shared_ptr<WorkQueue> work_queue_;
std::shared_ptr<GPUTracerMTL> gpu_tracer_;
bool is_valid_ = false;

ContextMTL(id<MTLDevice> device, NSArray<id<MTLLibrary>>* shader_libraries);
Expand All @@ -68,6 +70,9 @@ class ContextMTL final : public Context,
// |Context|
std::shared_ptr<WorkQueue> GetWorkQueue() const override;

// |Context|
std::shared_ptr<GPUTracer> GetGPUTracer() const override;

// |Context|
bool SupportsOffscreenMSAA() const override;

Expand Down
10 changes: 10 additions & 0 deletions impeller/renderer/backend/metal/context_mtl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@
}
}

#if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG) || \
(FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE)
// Setup the gpu tracer.
{ gpu_tracer_ = std::shared_ptr<GPUTracerMTL>(new GPUTracerMTL(device_)); }
#endif

is_valid_ = true;
}

Expand Down Expand Up @@ -210,6 +216,10 @@
return work_queue_;
}

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

std::shared_ptr<CommandBuffer> ContextMTL::CreateCommandBufferInQueue(
id<MTLCommandQueue> queue) const {
if (!IsValid()) {
Expand Down
40 changes: 40 additions & 0 deletions impeller/renderer/backend/metal/gpu_tracer_mtl.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.

#pragma once

#include <Metal/Metal.h>

#include "flutter/fml/macros.h"
#include "impeller/base/backend_cast.h"
#include "impeller/renderer/gpu_tracer.h"

namespace impeller {

class GPUTracerMTL final : public GPUTracer,
public BackendCast<GPUTracerMTL, GPUTracer> {
public:
// |GPUTracer|
~GPUTracerMTL() override;

// |GPUTracer|
bool StartCapturingFrame(GPUTracerConfiguration configuration) override;

// |GPUTracer|
bool StopCapturingFrame() override;

private:
friend class ContextMTL;

id<MTLDevice> device_;
GPUTracerMTL(id<MTLDevice> device);

NSURL* GetUniqueGPUTraceSavedURL() const;
NSURL* GetGPUTraceSavedDictionaryURL() const;
bool CreateGPUTraceSavedDictionaryIfNeeded() const;

FML_DISALLOW_COPY_AND_ASSIGN(GPUTracerMTL);
};

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

namespace impeller {

GPUTracerMTL::GPUTracerMTL(id<MTLDevice> device) : device_(device) {}

GPUTracerMTL::~GPUTracerMTL() = default;

bool GPUTracerMTL::StartCapturingFrame(GPUTracerConfiguration configuration) {
if (!device_) {
return false;
}

MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager];
if (captureManager.isCapturing) {
return false;
}

if (@available(iOS 13.0, macOS 10.15, *)) {
MTLCaptureDescriptor* desc = [[MTLCaptureDescriptor alloc] init];
desc.captureObject = device_;

MTLCaptureDestination targetDestination =
configuration.mtl_frame_capture_save_trace_as_document
? MTLCaptureDestinationGPUTraceDocument
: MTLCaptureDestinationDeveloperTools;
if (![captureManager supportsDestination:targetDestination]) {
return false;
}
desc.destination = targetDestination;

if (configuration.mtl_frame_capture_save_trace_as_document) {
if (!CreateGPUTraceSavedDictionaryIfNeeded()) {
return false;
}
NSURL* outputURL = GetUniqueGPUTraceSavedURL();
desc.outputURL = outputURL;
}
return [captureManager startCaptureWithDescriptor:desc error:nil];
}

[captureManager startCaptureWithDevice:device_];
return captureManager.isCapturing;
}

bool GPUTracerMTL::StopCapturingFrame() {
if (!device_) {
return false;
}

MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager];
if (!captureManager.isCapturing) {
return false;
}

[captureManager stopCapture];
return !captureManager.isCapturing;
}

NSURL* GPUTracerMTL::GetUniqueGPUTraceSavedURL() const {
NSURL* savedDictionaryURL = GetGPUTraceSavedDictionaryURL();
NSString* uniqueID = [NSUUID UUID].UUIDString;
return [[savedDictionaryURL URLByAppendingPathComponent:uniqueID]
URLByAppendingPathExtension:@"gputrace"];
}

bool GPUTracerMTL::CreateGPUTraceSavedDictionaryIfNeeded() const {
NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* gpuTraceSavedDictionaryURL = GetGPUTraceSavedDictionaryURL();
if ([fileManager fileExistsAtPath:gpuTraceSavedDictionaryURL.path]) {
return true;
}

NSError* error = nil;
[fileManager createDirectoryAtURL:gpuTraceSavedDictionaryURL
withIntermediateDirectories:NO
attributes:nil
error:&error];
if (error != nil) {
FML_LOG(ERROR) << "Metal frame capture "
"CreateGPUTraceSavedDictionaryIfNeeded failed.";
return false;
}
return true;
}

NSURL* GPUTracerMTL::GetGPUTraceSavedDictionaryURL() const {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString* docPath = [paths objectAtIndex:0];
NSURL* docURL = [NSURL fileURLWithPath:docPath];
NSURL* gpuTraceDictionaryURL =
[docURL URLByAppendingPathComponent:@"MetalCaptureGPUTrace"];
return gpuTraceDictionaryURL;
}

} // namespace impeller
4 changes: 4 additions & 0 deletions impeller/renderer/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ bool Context::HasThreadingRestrictions() const {
return false;
}

std::shared_ptr<GPUTracer> Context::GetGPUTracer() const {
return nullptr;
}

} // namespace impeller
6 changes: 6 additions & 0 deletions impeller/renderer/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class SamplerLibrary;
class CommandBuffer;
class PipelineLibrary;
class Allocator;
class GPUTracer;
class WorkQueue;

class Context : public std::enable_shared_from_this<Context> {
Expand All @@ -39,6 +40,11 @@ class Context : public std::enable_shared_from_this<Context> {

virtual std::shared_ptr<WorkQueue> GetWorkQueue() const = 0;

//----------------------------------------------------------------------------
/// @return A GPU Tracer to trace gpu rendering.
///
virtual std::shared_ptr<GPUTracer> GetGPUTracer() const;

virtual bool HasThreadingRestrictions() const;

virtual bool SupportsOffscreenMSAA() const = 0;
Expand Down
21 changes: 21 additions & 0 deletions impeller/renderer/gpu_tracer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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 "gpu_tracer.h"

namespace impeller {

GPUTracer::GPUTracer() = default;

GPUTracer::~GPUTracer() = default;

bool GPUTracer::StartCapturingFrame(GPUTracerConfiguration configuration) {
return false;
}

bool GPUTracer::StopCapturingFrame() {
return false;
}

} // namespace impeller
53 changes: 53 additions & 0 deletions impeller/renderer/gpu_tracer.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.

#include "flutter/fml/macros.h"

namespace impeller {

//------------------------------------------------------------------------------
/// @brief GPU tracer configuration.
///
struct GPUTracerConfiguration {
/// This param is for metal backend.
/// When this value is true, a gpu trace file will be saved in devices when
/// metal frame capture finishes. Otherwise, the Xcode will automatically open
/// and show trace result.
///
bool mtl_frame_capture_save_trace_as_document = false;
};

//------------------------------------------------------------------------------
/// @brief A GPU tracer to trace gpu workflow during rendering.
///
class GPUTracer {
public:
virtual ~GPUTracer();

//----------------------------------------------------------------------------
/// @brief Start capturing frame. This method should only be called when
/// developing.
///
/// @param[in] configuration The configuration passed in for capture.
///
/// @return The operation successful or not.
///
virtual bool StartCapturingFrame(GPUTracerConfiguration configuration);

//----------------------------------------------------------------------------
/// @brief Stop capturing frame. This should only be called when
/// developing.
///
/// @return The operation successful or not.
///
virtual bool StopCapturingFrame();

protected:
GPUTracer();

private:
FML_DISALLOW_COPY_AND_ASSIGN(GPUTracer);
};

} // namespace impeller

0 comments on commit c8fdcf1

Please sign in to comment.