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

Commit 8ccb9d3

Browse files
committed
[macOS] Merge FlutterMetalCompositor, superclass
Now that OpenGL support in Flutter on macOS has been removed, the only FlutterCompositor implementation is the Metal-based compositor. This patch merges it into the FlutterCompositor base class since there's no longer any reason to keep the interface separate from its implementation. This patch will be followed by similar patches for the renderer, surface manager, and external textures. Issue: flutter/flutter#108304 Issue: flutter/flutter#114445
1 parent 216702f commit 8ccb9d3

File tree

8 files changed

+194
-261
lines changed

8 files changed

+194
-261
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,6 +2596,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterChann
25962596
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm
25972597
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h
25982598
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm
2599+
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositorUnittests.mm
25992600
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject.mm
26002601
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h
26012602
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEmbedderExternalTextureUnittests.mm
@@ -2621,9 +2622,6 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuP
26212622
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin.mm
26222623
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPluginTest.mm
26232624
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin_Internal.h
2624-
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalCompositor.h
2625-
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalCompositor.mm
2626-
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalCompositorUnittests.mm
26272625
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.h
26282626
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.mm
26292627
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalRendererTest.mm

shell/platform/darwin/macos/BUILD.gn

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ source_set("flutter_framework_source") {
8282
"framework/Source/FlutterMenuPlugin.h",
8383
"framework/Source/FlutterMenuPlugin.mm",
8484
"framework/Source/FlutterMenuPlugin_Internal.h",
85-
"framework/Source/FlutterMetalCompositor.h",
86-
"framework/Source/FlutterMetalCompositor.mm",
8785
"framework/Source/FlutterMetalRenderer.h",
8886
"framework/Source/FlutterMetalRenderer.mm",
8987
"framework/Source/FlutterMouseCursorPlugin.h",
@@ -171,14 +169,14 @@ executable("flutter_desktop_darwin_unittests") {
171169
sources = [
172170
"framework/Source/AccessibilityBridgeMacTest.mm",
173171
"framework/Source/FlutterChannelKeyResponderUnittests.mm",
172+
"framework/Source/FlutterCompositorUnittests.mm",
174173
"framework/Source/FlutterEmbedderExternalTextureUnittests.mm",
175174
"framework/Source/FlutterEmbedderKeyResponderUnittests.mm",
176175
"framework/Source/FlutterEngineTest.mm",
177176
"framework/Source/FlutterEngineTestUtils.h",
178177
"framework/Source/FlutterEngineTestUtils.mm",
179178
"framework/Source/FlutterKeyboardManagerUnittests.mm",
180179
"framework/Source/FlutterMenuPluginTest.mm",
181-
"framework/Source/FlutterMetalCompositorUnittests.mm",
182180
"framework/Source/FlutterMetalRendererTest.mm",
183181
"framework/Source/FlutterMetalSurfaceManagerTest.mm",
184182
"framework/Source/FlutterPlatformNodeDelegateMacTest.mm",

shell/platform/darwin/macos/framework/Source/FlutterCompositor.h

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <list>
1010

1111
#include "flutter/fml/macros.h"
12+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
1213
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h"
1314
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h"
1415
#include "flutter/shell/platform/embedder/embedder.h"
@@ -25,52 +26,57 @@ class FlutterCompositor {
2526
// The view_provider is used to query FlutterViews from view IDs,
2627
// which are used for presenting and creating backing stores.
2728
// It must not be null, and is typically FlutterViewEngineProvider.
28-
explicit FlutterCompositor(id<FlutterViewProvider> view_provider);
29+
explicit FlutterCompositor(
30+
id<FlutterViewProvider> view_provider,
31+
FlutterPlatformViewController* platform_views_controller,
32+
id<MTLDevice> mtl_device);
2933

3034
virtual ~FlutterCompositor() = default;
3135

32-
// Creates a BackingStore and saves updates the backing_store_out
33-
// data with the new BackingStore data.
34-
// If the backing store is being requested for the first time
35-
// for a given frame, this compositor does not create a new backing
36-
// store but rather returns the backing store associated with the
37-
// FlutterView's FlutterSurfaceManager.
36+
// Creates a backing store and saves updates the backing_store_out data with
37+
// the new FlutterBackingStore data.
3838
//
39-
// Any additional state allocated for the backing store and
40-
// saved as user_data in the backing store must be collected
41-
// in the backing_store's destruction_callback field which will
42-
// be called when the embedder collects the backing store.
39+
// If the backing store is being requested for the first time for a given
40+
// frame, this compositor does not create a new backing store but rather
41+
// returns the backing store associated with the FlutterView's
42+
// FlutterSurfaceManager.
43+
//
44+
// Any additional state allocated for the backing store and saved as
45+
// user_data in the backing store must be collected in the backing_store's
46+
// destruction_callback field which will be called when the embedder collects
47+
// the backing store.
4348
virtual bool CreateBackingStore(const FlutterBackingStoreConfig* config,
44-
FlutterBackingStore* backing_store_out) = 0;
49+
FlutterBackingStore* backing_store_out);
4550

46-
// Releases the memory for any state used by the backing store.
47-
virtual bool CollectBackingStore(
48-
const FlutterBackingStore* backing_store) = 0;
51+
// Releases the memory for any resources that were allocated for the
52+
// specified backing store.
53+
virtual bool CollectBackingStore(const FlutterBackingStore* backing_store);
4954

5055
// Presents the FlutterLayers by updating the FlutterView specified by
51-
// `view_id` using the layer content.
52-
// Present sets frame_started_ to false.
56+
// `view_id` using the layer content. Sets frame_started_ to false.
5357
virtual bool Present(uint64_t view_id,
5458
const FlutterLayer** layers,
55-
size_t layers_count) = 0;
59+
size_t layers_count);
5660

61+
// Callback triggered at the end of the Present function. has_flutter_content
62+
// is true when Flutter content was rendered, otherwise false.
5763
using PresentCallback = std::function<bool(bool has_flutter_content)>;
5864

59-
// PresentCallback is called at the end of the Present function.
65+
// Registers a callback to be triggered at the end of the Present function.
66+
// If a callback was previously registered, it will be replaced.
6067
void SetPresentCallback(const PresentCallback& present_callback);
6168

62-
// Denotes the current status of the frame being composited.
63-
// Started: A new frame has begun and we have cleared the old layer tree
64-
// and are now creating backingstore(s) for the embedder to use.
69+
// The status of the frame being composited.
70+
// Started: A new frame has begun and we have cleared the old layer tree and
71+
// are now creating backingstore(s) for the embedder to use.
6572
// Presenting: the embedder has finished rendering into the provided
66-
// backingstore(s) and we are creating the layer tree for the
67-
// system compositor to present with.
68-
// Ended: The frame has been presented and we are no longer processing
69-
// it.
73+
// backingstore(s) and we are creating the layer tree for the system
74+
// compositor to present with.
75+
// Ended: The frame has been presented and we are no longer processing it.
7076
typedef enum { kStarted, kPresenting, kEnded } FrameStatus;
7177

7278
protected:
73-
// Get the view associated with the view ID.
79+
// Returns the view associated with the view ID.
7480
//
7581
// Returns nil if the ID is invalid.
7682
FlutterView* GetView(uint64_t view_id);
@@ -94,12 +100,25 @@ class FlutterCompositor {
94100
CATransform3D transform = CATransform3DIdentity);
95101

96102
private:
103+
// Presents the platform view layer represented by `layer`. `layer_index` is
104+
// used to position the layer in the z-axis. If the layer does not have a
105+
// superview, it will become subview of `default_base_view`.
106+
void PresentPlatformView(FlutterView* default_base_view,
107+
const FlutterLayer* layer,
108+
size_t layer_position);
109+
97110
// A list of the active CALayer objects for the frame that need to be removed.
98111
std::list<CALayer*> active_ca_layers_;
99112

100113
// Where the compositor can query FlutterViews. Must not be null.
101114
id<FlutterViewProvider> const view_provider_;
102115

116+
// The controller used to manage creation and deletion of platform views.
117+
const FlutterPlatformViewController* platform_view_controller_;
118+
119+
// The Metal device used to draw graphics.
120+
const id<MTLDevice> mtl_device_;
121+
103122
// Callback set by the embedder to be called when the layer tree has been
104123
// correctly set up for this frame.
105124
PresentCallback present_callback_;

shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm

Lines changed: 129 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,139 @@
33
// found in the LICENSE file.
44

55
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h"
6+
67
#include "flutter/fml/logging.h"
8+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h"
79

810
namespace flutter {
911

10-
FlutterCompositor::FlutterCompositor(id<FlutterViewProvider> view_provider)
11-
: view_provider_(view_provider) {
12-
FML_CHECK(view_provider != nullptr) << "FlutterViewProvider* cannot be nullptr";
12+
FlutterCompositor::FlutterCompositor(id<FlutterViewProvider> view_provider,
13+
FlutterPlatformViewController* platform_view_controller,
14+
id<MTLDevice> mtl_device)
15+
: view_provider_(view_provider),
16+
platform_view_controller_(platform_view_controller),
17+
mtl_device_(mtl_device) {
18+
FML_CHECK(view_provider != nullptr) << "view_provider cannot be nullptr";
19+
}
20+
21+
bool FlutterCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config,
22+
FlutterBackingStore* backing_store_out) {
23+
// TODO(dkwingsmt): This class only supports single-view for now. As more
24+
// classes are gradually converted to multi-view, it should get the view ID
25+
// from somewhere.
26+
FlutterView* view = GetView(kFlutterDefaultViewId);
27+
if (!view) {
28+
return false;
29+
}
30+
31+
CGSize size = CGSizeMake(config->size.width, config->size.height);
32+
33+
backing_store_out->metal.struct_size = sizeof(FlutterMetalBackingStore);
34+
backing_store_out->metal.texture.struct_size = sizeof(FlutterMetalTexture);
35+
36+
if (GetFrameStatus() != FrameStatus::kStarted) {
37+
StartFrame();
38+
// If the backing store is for the first layer, return the MTLTexture for the
39+
// FlutterView.
40+
FlutterMetalRenderBackingStore* backingStore =
41+
reinterpret_cast<FlutterMetalRenderBackingStore*>([view backingStoreForSize:size]);
42+
backing_store_out->metal.texture.texture =
43+
(__bridge FlutterMetalTextureHandle)backingStore.texture;
44+
} else {
45+
FlutterIOSurfaceHolder* io_surface_holder = [[FlutterIOSurfaceHolder alloc] init];
46+
[io_surface_holder recreateIOSurfaceWithSize:size];
47+
auto texture_descriptor =
48+
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
49+
width:size.width
50+
height:size.height
51+
mipmapped:NO];
52+
texture_descriptor.usage =
53+
MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget | MTLTextureUsageShaderWrite;
54+
55+
backing_store_out->metal.texture.texture = (__bridge_retained FlutterMetalTextureHandle)
56+
[mtl_device_ newTextureWithDescriptor:texture_descriptor
57+
iosurface:[io_surface_holder ioSurface]
58+
plane:0];
59+
60+
backing_store_out->metal.texture.user_data = (__bridge_retained void*)io_surface_holder;
61+
}
62+
63+
backing_store_out->type = kFlutterBackingStoreTypeMetal;
64+
backing_store_out->metal.texture.destruction_callback = [](void* user_data) {
65+
if (user_data != nullptr) {
66+
CFRelease(user_data);
67+
}
68+
};
69+
70+
return true;
71+
}
72+
73+
bool FlutterCompositor::CollectBackingStore(const FlutterBackingStore* backing_store) {
74+
// If we allocated this MTLTexture ourselves, user_data is not null, and we will need
75+
// to release it manually.
76+
if (backing_store->metal.texture.user_data != nullptr &&
77+
backing_store->metal.texture.texture != nullptr) {
78+
CFRelease(backing_store->metal.texture.texture);
79+
}
80+
return true;
81+
}
82+
83+
bool FlutterCompositor::Present(uint64_t view_id,
84+
const FlutterLayer** layers,
85+
size_t layers_count) {
86+
FlutterView* view = GetView(view_id);
87+
if (!view) {
88+
return false;
89+
}
90+
91+
SetFrameStatus(FrameStatus::kPresenting);
92+
93+
bool has_flutter_content = false;
94+
for (size_t i = 0; i < layers_count; ++i) {
95+
const auto* layer = layers[i];
96+
FlutterBackingStore* backing_store = const_cast<FlutterBackingStore*>(layer->backing_store);
97+
98+
switch (layer->type) {
99+
case kFlutterLayerContentTypeBackingStore: {
100+
if (backing_store->metal.texture.user_data) {
101+
FlutterIOSurfaceHolder* io_surface_holder =
102+
(__bridge FlutterIOSurfaceHolder*)backing_store->metal.texture.user_data;
103+
IOSurfaceRef io_surface = [io_surface_holder ioSurface];
104+
InsertCALayerForIOSurface(view, io_surface);
105+
}
106+
has_flutter_content = true;
107+
break;
108+
}
109+
case kFlutterLayerContentTypePlatformView: {
110+
PresentPlatformView(view, layer, i);
111+
break;
112+
}
113+
};
114+
}
115+
116+
return EndFrame(has_flutter_content);
117+
}
118+
119+
void FlutterCompositor::PresentPlatformView(FlutterView* default_base_view,
120+
const FlutterLayer* layer,
121+
size_t layer_position) {
122+
// TODO (https://github.com/flutter/flutter/issues/96668)
123+
// once the issue is fixed, this check will pass.
124+
FML_DCHECK([[NSThread currentThread] isMainThread])
125+
<< "Must be on the main thread to present platform views";
126+
127+
int64_t platform_view_id = layer->platform_view->identifier;
128+
NSView* platform_view = [platform_view_controller_ platformViewWithID:platform_view_id];
129+
130+
FML_DCHECK(platform_view) << "Platform view not found for id: " << platform_view_id;
131+
132+
CGFloat scale = [[NSScreen mainScreen] backingScaleFactor];
133+
platform_view.frame = CGRectMake(layer->offset.x / scale, layer->offset.y / scale,
134+
layer->size.width / scale, layer->size.height / scale);
135+
if (platform_view.superview == nil) {
136+
[default_base_view addSubview:platform_view];
137+
}
138+
platform_view.layer.zPosition = layer_position;
13139
}
14140

15141
void FlutterCompositor::SetPresentCallback(

shell/platform/darwin/macos/framework/Source/FlutterMetalCompositorUnittests.mm renamed to shell/platform/darwin/macos/framework/Source/FlutterCompositorUnittests.mm

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#import <Foundation/Foundation.h>
66
#import <OCMock/OCMock.h>
77

8-
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalCompositor.h"
8+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h"
99
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h"
1010
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewProvider.h"
1111
#import "flutter/testing/testing.h"
@@ -62,10 +62,10 @@ - (nullable FlutterView*)getView:(uint64_t)viewId {
6262
}
6363
} // namespace
6464

65-
TEST(FlutterMetalCompositorTest, TestPresent) {
66-
std::unique_ptr<flutter::FlutterMetalCompositor> macos_compositor =
67-
std::make_unique<FlutterMetalCompositor>(
68-
MockViewProvider(), /*platform_view_controller*/ nullptr, /*mtl_device*/ nullptr);
65+
TEST(FlutterCompositorTest, TestPresent) {
66+
std::unique_ptr<flutter::FlutterCompositor> macos_compositor =
67+
std::make_unique<FlutterCompositor>(MockViewProvider(), /*platform_view_controller*/ nullptr,
68+
/*mtl_device*/ nullptr);
6969

7070
bool flag = false;
7171
macos_compositor->SetPresentCallback([f = &flag](bool has_flutter_content) {
@@ -77,10 +77,10 @@ - (nullable FlutterView*)getView:(uint64_t)viewId {
7777
ASSERT_TRUE(flag);
7878
}
7979

80-
TEST(FlutterMetalCompositorTest, TestCreate) {
81-
std::unique_ptr<flutter::FlutterMetalCompositor> macos_compositor =
82-
std::make_unique<FlutterMetalCompositor>(
83-
MockViewProvider(), /*platform_view_controller*/ nullptr, /*mtl_device*/ nullptr);
80+
TEST(FlutterCompositorTest, TestCreate) {
81+
std::unique_ptr<flutter::FlutterCompositor> macos_compositor =
82+
std::make_unique<FlutterCompositor>(MockViewProvider(), /*platform_view_controller*/ nullptr,
83+
/*mtl_device*/ nullptr);
8484

8585
FlutterBackingStore backing_store;
8686
FlutterBackingStoreConfig config;
@@ -96,10 +96,10 @@ - (nullable FlutterView*)getView:(uint64_t)viewId {
9696
ASSERT_EQ(texture.height, 600ul);
9797
}
9898

99-
TEST(FlutterMetalCompositorTest, TestCompositing) {
100-
std::unique_ptr<flutter::FlutterMetalCompositor> macos_compositor =
101-
std::make_unique<FlutterMetalCompositor>(
102-
MockViewProvider(), /*platform_view_controller*/ nullptr, /*mtl_device*/ nullptr);
99+
TEST(FlutterCompositorTest, TestCompositing) {
100+
std::unique_ptr<flutter::FlutterCompositor> macos_compositor =
101+
std::make_unique<FlutterCompositor>(MockViewProvider(), /*platform_view_controller*/ nullptr,
102+
/*mtl_device*/ nullptr);
103103

104104
FlutterBackingStore backing_store;
105105
FlutterBackingStoreConfig config;

shell/platform/darwin/macos/framework/Source/FlutterEngine.mm

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
#include <iostream>
1010
#include <vector>
1111

12+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h"
1213
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
1314
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin.h"
14-
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalCompositor.h"
1515
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.h"
1616
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h"
1717
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
@@ -202,9 +202,8 @@ @implementation FlutterEngine {
202202
// Pointer to the Dart AOT snapshot and instruction data.
203203
_FlutterEngineAOTData* _aotData;
204204

205-
// _macOSCompositor is created when the engine is created and
206-
// its destruction is handled by ARC when the engine is destroyed.
207-
// This is either a FlutterGLCompositor or a FlutterMetalCompositor instance.
205+
// _macOSCompositor is created when the engine is created and its destruction is handled by ARC
206+
// when the engine is destroyed.
208207
std::unique_ptr<flutter::FlutterCompositor> _macOSCompositor;
209208

210209
FlutterViewEngineProvider* _viewProvider;
@@ -424,7 +423,7 @@ - (FlutterCompositor*)createFlutterCompositor {
424423
__weak FlutterEngine* weakSelf = self;
425424

426425
FlutterMetalRenderer* metalRenderer = reinterpret_cast<FlutterMetalRenderer*>(_renderer);
427-
_macOSCompositor = std::make_unique<flutter::FlutterMetalCompositor>(
426+
_macOSCompositor = std::make_unique<flutter::FlutterCompositor>(
428427
_viewProvider, _platformViewController, metalRenderer.device);
429428
_macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) {
430429
if (has_flutter_content) {

0 commit comments

Comments
 (0)