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

Commit eb6eabc

Browse files
authored
Reland "Introduce a delegate class for gpu metal rendering (#22611)" (#22777)
This reverts commit 0d71d27.
1 parent 14cb066 commit eb6eabc

18 files changed

+498
-158
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
@@ -933,6 +935,8 @@ FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStan
933935
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h
934936
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/flutter_codecs_unittest.mm
935937
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/flutter_standard_codec_unittest.mm
938+
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.h
939+
FILE: ../../../flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.mm
936940
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Flutter.podspec
937941
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h
938942
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: 77 additions & 43 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,31 +44,40 @@
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();
58-
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-
);
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+
);
7378

7479
if (!surface) {
75-
FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture.";
80+
FML_LOG(ERROR) << "Could not create the SkSurface from the CAMetalLayer.";
7681
return nullptr;
7782
}
7883

@@ -85,23 +90,52 @@
8590

8691
canvas->flush();
8792

88-
if (next_drawable_ == nullptr) {
89-
FML_DLOG(ERROR) << "Could not acquire next Metal drawable from the SkSurface.";
93+
GrMTLHandle drawable = next_drawable_;
94+
if (!drawable) {
95+
FML_DLOG(ERROR) << "Unable to obtain a metal drawable.";
9096
return false;
9197
}
9298

93-
auto command_buffer =
94-
fml::scoped_nsprotocol<id<MTLCommandBuffer>>([[command_queue_.get() commandBuffer] retain]);
99+
return delegate_->PresentDrawable(drawable);
100+
};
101+
102+
return std::make_unique<SurfaceFrame>(std::move(surface), true, submit_callback);
103+
}
95104

96-
fml::scoped_nsprotocol<id<CAMetalDrawable>> drawable(
97-
reinterpret_cast<id<CAMetalDrawable>>(next_drawable_));
98-
next_drawable_ = nullptr;
105+
std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrameFromMTLTexture(
106+
const SkISize& frame_info) {
107+
GPUMTLTextureInfo texture = delegate_->GetMTLTexture(frame_info);
108+
id<MTLTexture> mtl_texture = (id<MTLTexture>)(texture.texture);
109+
110+
if (!mtl_texture) {
111+
FML_LOG(ERROR) << "Invalid MTLTexture given by the embedder.";
112+
return nullptr;
113+
}
99114

100-
[command_buffer.get() commit];
101-
[command_buffer.get() waitUntilScheduled];
102-
[drawable.get() present];
115+
GrMtlTextureInfo info;
116+
info.fTexture.reset([mtl_texture retain]);
117+
GrBackendTexture backend_texture(frame_info.width(), frame_info.height(), GrMipmapped::kNo, info);
118+
119+
sk_sp<SkSurface> surface =
120+
SkSurface::MakeFromBackendTexture(context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin,
121+
1, kBGRA_8888_SkColorType, nullptr, nullptr);
122+
123+
if (!surface) {
124+
FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture.";
125+
return nullptr;
126+
}
127+
128+
auto submit_callback = [texture_id = texture.texture_id, delegate = delegate_](
129+
const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool {
130+
TRACE_EVENT0("flutter", "GPUSurfaceMetal::PresentTexture");
131+
if (canvas == nullptr) {
132+
FML_DLOG(ERROR) << "Canvas not available.";
133+
return false;
134+
}
135+
136+
canvas->flush();
103137

104-
return true;
138+
return delegate->PresentTexture(texture_id);
105139
};
106140

107141
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
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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+
#ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_DELEGATE_H_
6+
#define FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_DELEGATE_H_
7+
8+
#include <stdint.h>
9+
10+
#include "flutter/fml/macros.h"
11+
#include "third_party/skia/include/core/SkSize.h"
12+
#include "third_party/skia/include/core/SkSurface.h"
13+
#include "third_party/skia/include/gpu/mtl/GrMtlTypes.h"
14+
15+
namespace flutter {
16+
17+
// expected to be id<MTLDevice>
18+
typedef void* GPUMTLDeviceHandle;
19+
20+
// expected to be id<MTLCommandQueues>
21+
typedef void* GPUMTLCommandQueueHandle;
22+
23+
// expected to be CAMetalLayer*
24+
typedef void* GPUCAMetalLayerHandle;
25+
26+
// expected to be id<MTLTexture>
27+
typedef void* GPUMTLTextureHandle;
28+
29+
struct GPUMTLTextureInfo {
30+
intptr_t texture_id;
31+
GPUMTLTextureHandle texture;
32+
};
33+
34+
enum class MTLRenderTargetType { kMTLTexture, kCAMetalLayer };
35+
36+
//------------------------------------------------------------------------------
37+
/// @brief Interface implemented by all platform surfaces that can present
38+
/// a metal backing store to the "screen". The GPU surface
39+
/// abstraction (which abstracts the client rendering API) uses this
40+
/// delegation pattern to tell the platform surface (which abstracts
41+
/// how backing stores fulfilled by the selected client rendering
42+
/// API end up on the "screen" on a particular platform) when the
43+
/// rasterizer needs to allocate and present the software backing
44+
/// store.
45+
///
46+
/// @see |IOSurfaceMetal| and |EmbedderSurfaceMetal|.
47+
///
48+
class GPUSurfaceMetalDelegate {
49+
public:
50+
//------------------------------------------------------------------------------
51+
/// @brief Construct a new GPUSurfaceMetalDelegate object with the specified
52+
/// render_target type.
53+
///
54+
/// @see |MTLRenderTargetType|
55+
///
56+
explicit GPUSurfaceMetalDelegate(MTLRenderTargetType render_target);
57+
58+
virtual ~GPUSurfaceMetalDelegate();
59+
60+
//------------------------------------------------------------------------------
61+
/// @brief Returns the handle to the CAMetalLayer to render to. This is only
62+
/// called when the specifed render target type is `kCAMetalLayer`.
63+
///
64+
virtual GPUCAMetalLayerHandle GetCAMetalLayer(
65+
const SkISize& frame_info) const = 0;
66+
67+
//------------------------------------------------------------------------------
68+
/// @brief Presents the drawable to the "screen". The drawable is obtained
69+
/// from the CAMetalLayer that given by `GetCAMetalLayer` call. This is only
70+
/// called when the specified render target type in `kCAMetalLayer`.
71+
///
72+
/// @see |GPUSurfaceMetalDelegate::GetCAMetalLayer|
73+
///
74+
virtual bool PresentDrawable(GrMTLHandle drawable) const = 0;
75+
76+
//------------------------------------------------------------------------------
77+
/// @brief Returns the handle to the MTLTexture to render to. This is only
78+
/// called when the specefied render target type is `kMTLTexture`.
79+
///
80+
virtual GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_info) const = 0;
81+
82+
//------------------------------------------------------------------------------
83+
/// @brief Presents the texture with `texture_id` to the "screen".
84+
/// `texture_id` corresponds to a texture that has been obtained by an earlier
85+
/// call to `GetMTLTexture`. This is only called when the specefied render
86+
/// target type is `kMTLTexture`.
87+
///
88+
/// @see |GPUSurfaceMetalDelegate::GetMTLTexture|
89+
///
90+
virtual bool PresentTexture(intptr_t texture_id) const = 0;
91+
92+
MTLRenderTargetType GetRenderTargetType();
93+
94+
private:
95+
const MTLRenderTargetType render_target_type_;
96+
};
97+
98+
} // namespace flutter
99+
100+
#endif // FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_DELEGATE_H_

0 commit comments

Comments
 (0)