Skip to content

Commit 2bf66b9

Browse files
authored
macOS: Do not swap surface if nothing was painted (flutter#28136)
1 parent db59354 commit 2bf66b9

10 files changed

+39
-17
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class FlutterCompositor {
4646
// Present sets frame_started_ to false.
4747
virtual bool Present(const FlutterLayer** layers, size_t layers_count) = 0;
4848

49-
using PresentCallback = std::function<bool()>;
49+
using PresentCallback = std::function<bool(bool has_flutter_content)>;
5050

5151
// PresentCallback is called at the end of the Present function.
5252
void SetPresentCallback(const PresentCallback& present_callback);
@@ -73,7 +73,7 @@ class FlutterCompositor {
7373

7474
// Calls the present callback and ensures the frame status is updated
7575
// to frame ended, returning whether the present was successful or not.
76-
bool EndFrame();
76+
bool EndFrame(bool has_flutter_content);
7777

7878
// Creates a CALayer object which is backed by the supplied IOSurface, and
7979
// adds it to the root CALayer for this FlutterViewController's view.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
SetFrameStatus(FrameStatus::kStarted);
3030
}
3131

32-
bool FlutterCompositor::EndFrame() {
33-
bool status = present_callback_();
32+
bool FlutterCompositor::EndFrame(bool has_flutter_content) {
33+
bool status = present_callback_(has_flutter_content);
3434
SetFrameStatus(FrameStatus::kEnded);
3535
return status;
3636
}

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -340,21 +340,29 @@ - (FlutterCompositor*)createFlutterCompositor {
340340
FlutterMetalRenderer* metalRenderer = reinterpret_cast<FlutterMetalRenderer*>(_renderer);
341341
_macOSCompositor =
342342
std::make_unique<flutter::FlutterMetalCompositor>(_viewController, metalRenderer.device);
343-
_macOSCompositor->SetPresentCallback([weakSelf]() {
344-
FlutterMetalRenderer* metalRenderer =
345-
reinterpret_cast<FlutterMetalRenderer*>(weakSelf.renderer);
346-
return [metalRenderer present:0 /*=textureID*/];
343+
_macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) {
344+
if (has_flutter_content) {
345+
FlutterMetalRenderer* metalRenderer =
346+
reinterpret_cast<FlutterMetalRenderer*>(weakSelf.renderer);
347+
return [metalRenderer present:0 /*=textureID*/] == YES;
348+
} else {
349+
return true;
350+
}
347351
});
348352
} else {
349353
FlutterOpenGLRenderer* openGLRenderer = reinterpret_cast<FlutterOpenGLRenderer*>(_renderer);
350354
[openGLRenderer.openGLContext makeCurrentContext];
351355
_macOSCompositor = std::make_unique<flutter::FlutterGLCompositor>(_viewController,
352356
openGLRenderer.openGLContext);
353357

354-
_macOSCompositor->SetPresentCallback([weakSelf]() {
355-
FlutterOpenGLRenderer* openGLRenderer =
356-
reinterpret_cast<FlutterOpenGLRenderer*>(weakSelf.renderer);
357-
return [openGLRenderer glPresent];
358+
_macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) {
359+
if (has_flutter_content) {
360+
FlutterOpenGLRenderer* openGLRenderer =
361+
reinterpret_cast<FlutterOpenGLRenderer*>(weakSelf.renderer);
362+
return [openGLRenderer glPresent] == YES;
363+
} else {
364+
return true;
365+
}
358366
});
359367
}
360368

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ @interface FlutterEngine (Test)
355355
// Latch to ensure the entire layer tree has been generated and presented.
356356
fml::AutoResetWaitableEvent latch;
357357
auto compositor = engine.macOSCompositor;
358-
compositor->SetPresentCallback([&]() {
358+
compositor->SetPresentCallback([&](bool has_flutter_content) {
359359
latch.Signal();
360360
return true;
361361
});

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@
7777
bool FlutterGLCompositor::Present(const FlutterLayer** layers, size_t layers_count) {
7878
SetFrameStatus(FrameStatus::kPresenting);
7979

80+
bool has_flutter_content = false;
81+
8082
for (size_t i = 0; i < layers_count; ++i) {
8183
const auto* layer = layers[i];
8284
FlutterBackingStore* backing_store = const_cast<FlutterBackingStore*>(layer->backing_store);
@@ -93,6 +95,7 @@
9395
// and needs to be flipped vertically
9496
InsertCALayerForIOSurface(io_surface, CATransform3DMakeScale(1, -1, 1));
9597
}
98+
has_flutter_content = true;
9699
break;
97100
}
98101
case kFlutterLayerContentTypePlatformView:
@@ -102,7 +105,7 @@
102105
};
103106
}
104107

105-
return EndFrame();
108+
return EndFrame(has_flutter_content);
106109
}
107110

108111
} // namespace flutter

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
std::make_unique<FlutterGLCompositor>(mockViewController, nullptr);
1818

1919
bool flag = false;
20-
macos_compositor->SetPresentCallback([f = &flag]() {
20+
macos_compositor->SetPresentCallback([f = &flag](bool has_flutter_content) {
2121
*f = true;
2222
return true;
2323
});

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
bool FlutterMetalCompositor::Present(const FlutterLayer** layers, size_t layers_count) {
7777
SetFrameStatus(FrameStatus::kPresenting);
7878

79+
bool has_flutter_content = false;
80+
7981
for (size_t i = 0; i < layers_count; ++i) {
8082
const auto* layer = layers[i];
8183
FlutterBackingStore* backing_store = const_cast<FlutterBackingStore*>(layer->backing_store);
@@ -88,6 +90,7 @@
8890
IOSurfaceRef io_surface = [io_surface_holder ioSurface];
8991
InsertCALayerForIOSurface(io_surface);
9092
}
93+
has_flutter_content = true;
9194
break;
9295
}
9396
case kFlutterLayerContentTypePlatformView:
@@ -97,7 +100,7 @@
97100
};
98101
}
99102

100-
return EndFrame();
103+
return EndFrame(has_flutter_content);
101104
}
102105

103106
} // namespace flutter

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
std::make_unique<FlutterMetalCompositor>(mockViewController, nullptr);
1818

1919
bool flag = false;
20-
macos_compositor->SetPresentCallback([f = &flag]() {
20+
macos_compositor->SetPresentCallback([f = &flag](bool has_flutter_content) {
2121
*f = true;
2222
return true;
2323
});

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ - (instancetype)init {
5353
FlutterMetalSurfaceManager* surfaceManager = CreateSurfaceManager();
5454
CGSize size = CGSizeMake(100, 50);
5555
[surfaceManager ensureSurfaceSize:size];
56+
[surfaceManager renderBuffer]; // make sure we have back buffer
5657
[surfaceManager swapBuffers];
5758
id<MTLTexture> texture =
5859
(reinterpret_cast<FlutterMetalRenderBackingStore*>([surfaceManager renderBuffer])).texture;

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ - (void)ensureSurfaceSize:(CGSize)size {
5858
}
5959

6060
- (void)swapBuffers {
61+
#ifndef NDEBUG
62+
// swapBuffers should not be called unless a frame was drawn
63+
@synchronized(self) {
64+
assert(_frameInProgress);
65+
}
66+
#endif
67+
6168
_contentLayer.frame = _containingLayer.bounds;
6269
_contentLayer.transform = _contentTransform;
6370
IOSurfaceRef contentIOSurface = [_ioSurfaces[kFlutterSurfaceManagerBackBuffer] ioSurface];

0 commit comments

Comments
 (0)