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

Commit 5bf6533

Browse files
authored
Introduce a delegate class for gpu metal rendering (#22611)
1 parent 3c51679 commit 5bf6533

18 files changed

+505
-164
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,8 @@ FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.cc
673673
FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.h
674674
FILE: ../../../flutter/shell/gpu/gpu_surface_metal.h
675675
FILE: ../../../flutter/shell/gpu/gpu_surface_metal.mm
676+
FILE: ../../../flutter/shell/gpu/gpu_surface_metal_delegate.cc
677+
FILE: ../../../flutter/shell/gpu/gpu_surface_metal_delegate.h
676678
FILE: ../../../flutter/shell/gpu/gpu_surface_software.cc
677679
FILE: ../../../flutter/shell/gpu/gpu_surface_software.h
678680
FILE: ../../../flutter/shell/gpu/gpu_surface_software_delegate.cc
@@ -932,6 +934,8 @@ FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStan
932934
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h
933935
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/flutter_codecs_unittest.mm
934936
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/flutter_standard_codec_unittest.mm
937+
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.h
938+
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.mm
935939
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Flutter.podspec
936940
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h
937941
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h

shell/common/animator.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ Animator::Animator(Delegate& delegate,
2929
last_vsync_start_time_(),
3030
last_frame_target_time_(),
3131
dart_frame_deadline_(0),
32-
#if FLUTTER_SHELL_ENABLE_METAL
32+
#if SHELL_ENABLE_METAL
3333
layer_tree_pipeline_(fml::MakeRefCounted<LayerTreePipeline>(2)),
34-
#else // FLUTTER_SHELL_ENABLE_METAL
34+
#else // SHELL_ENABLE_METAL
3535
// TODO(dnfield): We should remove this logic and set the pipeline depth
3636
// back to 2 in this case. See
3737
// https://github.com/flutter/engine/pull/9132 for discussion.
@@ -40,7 +40,7 @@ Animator::Animator(Delegate& delegate,
4040
task_runners.GetRasterTaskRunner()
4141
? 1
4242
: 2)),
43-
#endif // FLUTTER_SHELL_ENABLE_METAL
43+
#endif // SHELL_ENABLE_METAL
4444
pending_frame_semaphore_(1),
4545
frame_number_(1),
4646
paused_(false),

shell/gpu/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ source_set("gpu_surface_metal") {
5151
sources = [
5252
"gpu_surface_metal.h",
5353
"gpu_surface_metal.mm",
54+
"gpu_surface_metal_delegate.cc",
55+
"gpu_surface_metal_delegate.h",
5456
]
5557

5658
deps = gpu_common_deps

shell/gpu/gpu_surface_metal.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,31 @@
55
#ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_H_
66
#define FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_H_
77

8-
#include <Metal/Metal.h>
9-
108
#include "flutter/flow/surface.h"
119
#include "flutter/fml/macros.h"
12-
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
10+
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
1311
#include "third_party/skia/include/gpu/GrDirectContext.h"
1412
#include "third_party/skia/include/gpu/mtl/GrMtlTypes.h"
1513

16-
@class CAMetalLayer;
17-
1814
namespace flutter {
1915

2016
class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetal : public Surface {
2117
public:
22-
GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer,
23-
sk_sp<GrDirectContext> context,
24-
fml::scoped_nsprotocol<id<MTLCommandQueue>> command_queue);
18+
GPUSurfaceMetal(GPUSurfaceMetalDelegate* delegate,
19+
sk_sp<GrDirectContext> context);
2520

2621
// |Surface|
2722
~GPUSurfaceMetal();
2823

29-
private:
30-
fml::scoped_nsobject<CAMetalLayer> layer_;
31-
sk_sp<GrDirectContext> context_;
32-
fml::scoped_nsprotocol<id<MTLCommandQueue>> command_queue_;
33-
GrMTLHandle next_drawable_ = nullptr;
34-
3524
// |Surface|
3625
bool IsValid() override;
3726

27+
private:
28+
const GPUSurfaceMetalDelegate* delegate_;
29+
const MTLRenderTargetType render_target_type_;
30+
GrMTLHandle next_drawable_ = nullptr;
31+
sk_sp<GrDirectContext> context_;
32+
3833
// |Surface|
3934
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
4035

@@ -47,6 +42,12 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetal : public Surface {
4742
// |Surface|
4843
std::unique_ptr<GLContextResult> MakeRenderContextCurrent() override;
4944

45+
std::unique_ptr<SurfaceFrame> AcquireFrameFromCAMetalLayer(
46+
const SkISize& frame_info);
47+
48+
std::unique_ptr<SurfaceFrame> AcquireFrameFromMTLTexture(
49+
const SkISize& frame_info);
50+
5051
void ReleaseUnusedDrawableIfNecessary();
5152

5253
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceMetal);

shell/gpu/gpu_surface_metal.mm

Lines changed: 84 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44

55
#include "flutter/shell/gpu/gpu_surface_metal.h"
66

7-
#include <QuartzCore/CAMetalLayer.h>
7+
#import <Metal/Metal.h>
88

9+
#include "flutter/fml/make_copyable.h"
10+
#include "flutter/fml/platform/darwin/cf_utils.h"
911
#include "flutter/fml/trace_event.h"
12+
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
1013
#include "third_party/skia/include/core/SkSurface.h"
1114
#include "third_party/skia/include/gpu/GrBackendSurface.h"
1215
#include "third_party/skia/include/ports/SkCFObject.h"
@@ -15,25 +18,18 @@
1518

1619
namespace flutter {
1720

18-
GPUSurfaceMetal::GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer,
19-
sk_sp<GrDirectContext> context,
20-
fml::scoped_nsprotocol<id<MTLCommandQueue>> command_queue)
21-
: layer_(std::move(layer)),
22-
context_(std::move(context)),
23-
command_queue_(std::move(command_queue)) {
24-
layer_.get().pixelFormat = MTLPixelFormatBGRA8Unorm;
25-
// Flutter needs to read from the color attachment in cases where there are effects such as
26-
// backdrop filters.
27-
layer_.get().framebufferOnly = NO;
28-
}
21+
GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceMetalDelegate* delegate, sk_sp<GrDirectContext> context)
22+
: delegate_(delegate),
23+
render_target_type_(delegate->GetRenderTargetType()),
24+
context_(std::move(context)) {}
2925

3026
GPUSurfaceMetal::~GPUSurfaceMetal() {
3127
ReleaseUnusedDrawableIfNecessary();
3228
}
3329

3430
// |Surface|
3531
bool GPUSurfaceMetal::IsValid() {
36-
return layer_ && context_ && command_queue_;
32+
return context_ != nullptr;
3733
}
3834

3935
// |Surface|
@@ -48,60 +44,99 @@
4844
return nullptr;
4945
}
5046

51-
const auto drawable_size = CGSizeMake(frame_size.width(), frame_size.height());
47+
switch (render_target_type_) {
48+
case MTLRenderTargetType::kCAMetalLayer:
49+
return AcquireFrameFromCAMetalLayer(frame_size);
50+
case MTLRenderTargetType::kMTLTexture:
51+
return AcquireFrameFromMTLTexture(frame_size);
52+
default:
53+
FML_CHECK(false) << "Unknown MTLRenderTargetType type.";
54+
}
55+
56+
return nullptr;
57+
}
5258

53-
if (!CGSizeEqualToSize(drawable_size, layer_.get().drawableSize)) {
54-
layer_.get().drawableSize = drawable_size;
59+
std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrameFromCAMetalLayer(
60+
const SkISize& frame_info) {
61+
auto layer = delegate_->GetCAMetalLayer(frame_info);
62+
if (!layer) {
63+
FML_LOG(ERROR) << "Invalid CAMetalLayer given by the embedder.";
64+
return nullptr;
5565
}
5666

5767
ReleaseUnusedDrawableIfNecessary();
68+
sk_sp<SkSurface> surface =
69+
SkSurface::MakeFromCAMetalLayer(context_.get(), // context
70+
layer, // layer
71+
kTopLeft_GrSurfaceOrigin, // origin
72+
1, // sample count
73+
kBGRA_8888_SkColorType, // color type
74+
nullptr, // colorspace
75+
nullptr, // surface properties
76+
&next_drawable_ // drawable (transfer out)
77+
);
78+
79+
if (!surface) {
80+
FML_LOG(ERROR) << "Could not create the SkSurface from the CAMetalLayer.";
81+
return nullptr;
82+
}
83+
84+
auto submit_callback =
85+
fml::MakeCopyable([drawable = next_drawable_, delegate = delegate_](
86+
const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool {
87+
TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit");
88+
if (canvas == nullptr) {
89+
FML_DLOG(ERROR) << "Canvas not available.";
90+
return false;
91+
}
92+
93+
canvas->flush();
5894

59-
// When there are platform views in the scene, the drawable needs to be presented in the same
60-
// transaction as the one created for platform views. When the drawable are being presented from
61-
// the raster thread, there is no such transaction.
62-
layer_.get().presentsWithTransaction = [[NSThread currentThread] isMainThread];
63-
64-
auto surface = SkSurface::MakeFromCAMetalLayer(context_.get(), // context
65-
layer_.get(), // layer
66-
kTopLeft_GrSurfaceOrigin, // origin
67-
1, // sample count
68-
kBGRA_8888_SkColorType, // color type
69-
nullptr, // colorspace
70-
nullptr, // surface properties
71-
&next_drawable_ // drawable (transfer out)
72-
);
95+
if (!drawable) {
96+
FML_DLOG(ERROR) << "Unable to obtain a metal drawable.";
97+
return false;
98+
}
99+
100+
return delegate->PresentDrawable(drawable);
101+
});
102+
103+
return std::make_unique<SurfaceFrame>(std::move(surface), true, submit_callback);
104+
}
105+
106+
std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrameFromMTLTexture(
107+
const SkISize& frame_info) {
108+
GPUMTLTextureInfo texture = delegate_->GetMTLTexture(frame_info);
109+
id<MTLTexture> mtl_texture = (id<MTLTexture>)(texture.texture);
110+
111+
if (!mtl_texture) {
112+
FML_LOG(ERROR) << "Invalid MTLTexture given by the embedder.";
113+
return nullptr;
114+
}
115+
116+
GrMtlTextureInfo info;
117+
info.fTexture.reset([mtl_texture retain]);
118+
GrBackendTexture backend_texture(frame_info.width(), frame_info.height(), GrMipmapped::kNo, info);
119+
120+
sk_sp<SkSurface> surface =
121+
SkSurface::MakeFromBackendTexture(context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin,
122+
1, kBGRA_8888_SkColorType, nullptr, nullptr);
73123

74124
if (!surface) {
75125
FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture.";
76126
return nullptr;
77127
}
78128

79-
auto submit_callback = [this](const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool {
80-
TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit");
129+
auto submit_callback = [texture_id = texture.texture_id, delegate = delegate_](
130+
const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool {
131+
TRACE_EVENT0("flutter", "GPUSurfaceMetal::PresentTexture");
81132
if (canvas == nullptr) {
82133
FML_DLOG(ERROR) << "Canvas not available.";
83134
return false;
84135
}
85136

86137
canvas->flush();
87138

88-
if (next_drawable_ == nullptr) {
89-
FML_DLOG(ERROR) << "Could not acquire next Metal drawable from the SkSurface.";
90-
return false;
91-
}
92-
93-
auto command_buffer =
94-
fml::scoped_nsprotocol<id<MTLCommandBuffer>>([[command_queue_.get() commandBuffer] retain]);
95-
96-
fml::scoped_nsprotocol<id<CAMetalDrawable>> drawable(
97-
reinterpret_cast<id<CAMetalDrawable>>(next_drawable_));
98-
next_drawable_ = nullptr;
99-
100-
[command_buffer.get() commit];
101-
[command_buffer.get() waitUntilScheduled];
102-
[drawable.get() present];
103-
104-
return true;
139+
return delegate->PresentTexture(texture_id);
105140
};
106141

107142
return std::make_unique<SurfaceFrame>(std::move(surface), true, submit_callback);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
6+
7+
namespace flutter {
8+
9+
GPUSurfaceMetalDelegate::GPUSurfaceMetalDelegate(
10+
MTLRenderTargetType render_target_type)
11+
: render_target_type_(render_target_type) {}
12+
13+
GPUSurfaceMetalDelegate::~GPUSurfaceMetalDelegate() = default;
14+
15+
MTLRenderTargetType GPUSurfaceMetalDelegate::GetRenderTargetType() {
16+
return render_target_type_;
17+
}
18+
19+
} // namespace flutter

0 commit comments

Comments
 (0)