[macOS] Merge FlutterSurfaceManager and impls (flutter/engine#37701)

Previously, FlutterSurfaceManager was a protocol with two concrete
implementations: FlutterGLSurfaceManager and FlutterMetalSurfaceManager.
Most of the implementation was in a shared superclass,
FlutterIOSurfaceManager, which called into the OpenGL or Metal-specific
subclass when backend-specific operations (such as allocating textures)
was required. It did so via a delegate pattern, wherein the subclasses
both implemented the FlutterIOSurfaceManagerDelegate protocol that
exposed the backend-specific functionality.

Now that only the Metal implementation remains, the delegate code can be
inlined into the calling functions, and the class hierarchy can be
squashed into a single concrete implementation class,
FlutterSurfaceManager, similar to how it was originally implemented in
https://github.com/flutter/engine/pull/21525 before we had two backends.

Issue: https://github.com/flutter/flutter/issues/108304
Issue: https://github.com/flutter/flutter/issues/114445
This commit is contained in:
Chris Bracken
2022-11-17 11:46:27 -08:00
committed by GitHub
parent 2252b6f362
commit 0b728cbf70
6 changed files with 65 additions and 134 deletions

View File

@@ -2642,7 +2642,6 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuP
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPluginTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin_Internal.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalSurfaceManagerTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMac.h
@@ -2660,6 +2659,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResiz
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManagerTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm

View File

@@ -174,10 +174,10 @@ executable("flutter_desktop_darwin_unittests") {
"framework/Source/FlutterEngineTestUtils.mm",
"framework/Source/FlutterKeyboardManagerUnittests.mm",
"framework/Source/FlutterMenuPluginTest.mm",
"framework/Source/FlutterMetalSurfaceManagerTest.mm",
"framework/Source/FlutterPlatformNodeDelegateMacTest.mm",
"framework/Source/FlutterPlatformViewControllerTest.mm",
"framework/Source/FlutterRendererTest.mm",
"framework/Source/FlutterSurfaceManagerTest.mm",
"framework/Source/FlutterTextInputPluginTest.mm",
"framework/Source/FlutterTextInputSemanticsObjectTest.mm",
"framework/Source/FlutterViewControllerTest.mm",

View File

@@ -11,7 +11,7 @@
@implementation FlutterMetalResizableBackingStoreProvider {
id<MTLDevice> _device;
id<MTLCommandQueue> _commandQueue;
id<FlutterSurfaceManager> _surfaceManager;
FlutterSurfaceManager* _surfaceManager;
}
- (instancetype)initWithDevice:(id<MTLDevice>)device
@@ -21,9 +21,9 @@
if (self) {
_device = device;
_commandQueue = commandQueue;
_surfaceManager = [[FlutterMetalSurfaceManager alloc] initWithDevice:device
commandQueue:commandQueue
layer:layer];
_surfaceManager = [[FlutterSurfaceManager alloc] initWithDevice:device
commandQueue:commandQueue
layer:layer];
}
return self;
}

View File

@@ -9,13 +9,25 @@
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h"
/**
* Manages the render surfaces and their corresponding backing stores.
* Manages render surfaces and corresponding backing stores used by the engine.
*
* The backing store when rendering with on Metal is a Metal texture. There are two IOSurfaces
* created during initialization, FlutterSurfaceManager manages the lifecycle of these.
*/
@protocol FlutterSurfaceManager
@interface FlutterSurfaceManager : NSObject
/**
* Updates the backing store size of the managed IOSurfaces to `size`. If the surfaces are already
* of the same size, this is a no-op.
* Initializes and returns a surface manager that renders to a child layer (referred to as the
* content layer) of the containing layer and applies the transform to the contents of the content
* layer.
*/
- (nullable instancetype)initWithDevice:(nonnull id<MTLDevice>)device
commandQueue:(nonnull id<MTLCommandQueue>)commandQueue
layer:(nonnull CALayer*)containingLayer;
/**
* Updates the backing store size of the managed IOSurfaces the specified size. If the surfaces are
* already of this size, this is a no-op.
*/
- (void)ensureSurfaceSize:(CGSize)size;
@@ -30,67 +42,3 @@
- (nonnull FlutterRenderBackingStore*)renderBuffer;
@end
/**
* Methods for managing the IOSurfaces held by FlutterIOSurfaceManager.
*/
@protocol FlutterIOSurfaceManagerDelegate
/**
* Tells the delegate that the front and back IOSurfaces are swapped.
*/
- (void)onSwapBuffers;
/**
* Tells the delegate that the IOSurfaces have been resized. `bufferIndex` is to indicate the front
* vs back buffer. `size` is the new size of the IOSurface.
*/
- (void)onUpdateSurface:(nonnull FlutterIOSurfaceHolder*)surface
bufferIndex:(size_t)index
size:(CGSize)size;
/**
* Tells the delegate that IOSurface with given index has been released. Delegate should free
* all resources associated with the surface
*/
- (void)onSurfaceReleased:(size_t)index;
@end
/**
* Manages IOSurfaces for the FlutterEngine to render to.
*
* The backing store when rendering with on Metal its a Metal texture. There are two IOSurfaces
* created during initialization, FlutterSurfaceManager manages the lifecycle of these.
*/
@interface FlutterIOSurfaceManager : NSObject <FlutterSurfaceManager>
/**
* The object that acts as the delegate for the FlutterIOSurfaceManager. See:
* FlutterIOSurfaceManagerDelegate.
*/
@property(nullable, nonatomic, weak) id<FlutterIOSurfaceManagerDelegate> delegate;
/**
* Initializes and returns an IOSurface manager that renders to a child layer (referred to as the
* content layer) of the containing layer and applies the transform to the contents of the content
* layer.
*/
- (nullable instancetype)initWithLayer:(nonnull CALayer*)containingLayer
contentTransform:(CATransform3D)transform;
@end
/**
* FlutterSurfaceManager implementation where the IOSurfaces managed are backed by a Metal textures.
*/
@interface FlutterMetalSurfaceManager : FlutterIOSurfaceManager <FlutterIOSurfaceManagerDelegate>
/**
* Creates two IOSurfaces backed by Metal textures.
*/
- (nullable instancetype)initWithDevice:(nonnull id<MTLDevice>)device
commandQueue:(nonnull id<MTLCommandQueue>)commandQueue
layer:(nonnull CALayer*)containingLayer;
@end

View File

@@ -19,7 +19,21 @@ enum {
// BackBuffer will be released after kIdleDelay if there is no activity.
static const double kIdleDelay = 1.0;
@implementation FlutterIOSurfaceManager {
@interface FlutterSurfaceManager ()
/**
* Cancels any previously-scheduled onIdle requests.
*/
- (void)cancelIdle;
/**
* Creates a backing textures for the specified surface with the specified size.
*/
- (id<MTLTexture>)createTextureForSurface:(FlutterIOSurfaceHolder*)surface size:(CGSize)size;
@end
@implementation FlutterSurfaceManager {
CALayer* _containingLayer; // provided (parent layer)
CALayer* _contentLayer;
CATransform3D _contentTransform;
@@ -27,18 +41,27 @@ static const double kIdleDelay = 1.0;
CGSize _surfaceSize;
FlutterIOSurfaceHolder* _ioSurfaces[kFlutterSurfaceManagerBufferCount];
BOOL _frameInProgress;
id<MTLDevice> _device;
id<MTLCommandQueue> _commandQueue;
id<MTLTexture> _textures[kFlutterSurfaceManagerBufferCount];
}
- (instancetype)initWithLayer:(CALayer*)containingLayer contentTransform:(CATransform3D)transform {
- (nullable instancetype)initWithDevice:(nonnull id<MTLDevice>)device
commandQueue:(nonnull id<MTLCommandQueue>)commandQueue
layer:(nonnull CALayer*)containingLayer {
self = [super init];
if (self) {
_containingLayer = containingLayer;
_contentTransform = transform;
_contentTransform = CATransform3DIdentity;
_contentLayer = [[CALayer alloc] init];
[_containingLayer addSublayer:_contentLayer];
_ioSurfaces[0] = [[FlutterIOSurfaceHolder alloc] init];
_ioSurfaces[1] = [[FlutterIOSurfaceHolder alloc] init];
_device = device;
_commandQueue = commandQueue;
}
return self;
}
@@ -51,7 +74,7 @@ static const double kIdleDelay = 1.0;
for (int i = 0; i < kFlutterSurfaceManagerBufferCount; ++i) {
if (_ioSurfaces[i] != nil) {
[_ioSurfaces[i] recreateIOSurfaceWithSize:size];
[_delegate onUpdateSurface:_ioSurfaces[i] bufferIndex:i size:size];
_textures[i] = [self createTextureForSurface:_ioSurfaces[i] size:size];
}
}
}
@@ -71,7 +94,8 @@ static const double kIdleDelay = 1.0;
std::swap(_ioSurfaces[kFlutterSurfaceManagerBackBuffer],
_ioSurfaces[kFlutterSurfaceManagerFrontBuffer]);
[_delegate onSwapBuffers];
std::swap(_textures[kFlutterSurfaceManagerBackBuffer],
_textures[kFlutterSurfaceManagerFrontBuffer]);
// performSelector:withObject:afterDelay needs to be performed on RunLoop thread
[self performSelectorOnMainThread:@selector(reschedule) withObject:nil waitUntilDone:NO];
@@ -92,7 +116,7 @@ static const double kIdleDelay = 1.0;
// Release the back buffer and notify delegate. The buffer will be restored
// on demand in ensureBackBuffer
_ioSurfaces[kFlutterSurfaceManagerBackBuffer] = nil;
[self.delegate onSurfaceReleased:kFlutterSurfaceManagerBackBuffer];
_textures[kFlutterSurfaceManagerBackBuffer] = nil;
}
}
}
@@ -104,9 +128,9 @@ static const double kIdleDelay = 1.0;
// Restore previously released backbuffer
_ioSurfaces[kFlutterSurfaceManagerBackBuffer] = [[FlutterIOSurfaceHolder alloc] init];
[_ioSurfaces[kFlutterSurfaceManagerBackBuffer] recreateIOSurfaceWithSize:_surfaceSize];
[_delegate onUpdateSurface:_ioSurfaces[kFlutterSurfaceManagerBackBuffer]
bufferIndex:kFlutterSurfaceManagerBackBuffer
size:_surfaceSize];
_textures[kFlutterSurfaceManagerBackBuffer] =
[self createTextureForSurface:_ioSurfaces[kFlutterSurfaceManagerBackBuffer]
size:_surfaceSize];
}
};
[self performSelectorOnMainThread:@selector(cancelIdle) withObject:nil waitUntilDone:NO];
@@ -117,47 +141,12 @@ static const double kIdleDelay = 1.0;
}
- (nonnull FlutterRenderBackingStore*)renderBuffer {
@throw([NSException exceptionWithName:@"Sub-classes FlutterIOSurfaceManager of"
" must override renderBuffer."
reason:nil
userInfo:nil]);
}
@end
@implementation FlutterMetalSurfaceManager {
id<MTLDevice> _device;
id<MTLCommandQueue> _commandQueue;
id<MTLTexture> _textures[kFlutterSurfaceManagerBufferCount];
}
- (nullable instancetype)initWithDevice:(nonnull id<MTLDevice>)device
commandQueue:(nonnull id<MTLCommandQueue>)commandQueue
layer:(nonnull CALayer*)containingLayer {
self = [super initWithLayer:containingLayer contentTransform:CATransform3DIdentity];
if (self) {
super.delegate = self;
_device = device;
_commandQueue = commandQueue;
}
return self;
}
- (FlutterRenderBackingStore*)renderBuffer {
[self ensureBackBuffer];
id<MTLTexture> texture = _textures[kFlutterSurfaceManagerBackBuffer];
return [[FlutterMetalRenderBackingStore alloc] initWithTexture:texture];
}
- (void)onSwapBuffers {
std::swap(_textures[kFlutterSurfaceManagerBackBuffer],
_textures[kFlutterSurfaceManagerFrontBuffer]);
}
- (void)onUpdateSurface:(FlutterIOSurfaceHolder*)surface
bufferIndex:(size_t)index
size:(CGSize)size {
- (id<MTLTexture>)createTextureForSurface:(FlutterIOSurfaceHolder*)surface size:(CGSize)size {
MTLTextureDescriptor* textureDescriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:size.width
@@ -166,13 +155,7 @@ static const double kIdleDelay = 1.0;
textureDescriptor.usage =
MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget | MTLTextureUsageShaderWrite;
// plane = 0 for BGRA.
_textures[index] = [_device newTextureWithDescriptor:textureDescriptor
iosurface:[surface ioSurface]
plane:0];
}
- (void)onSurfaceReleased:(size_t)index {
_textures[index] = nil;
return [_device newTextureWithDescriptor:textureDescriptor iosurface:[surface ioSurface] plane:0];
}
@end

View File

@@ -29,18 +29,18 @@
namespace flutter::testing {
static FlutterMetalSurfaceManager* CreateSurfaceManager() {
static FlutterSurfaceManager* CreateSurfaceManager() {
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
id<MTLCommandQueue> commandQueue = [device newCommandQueue];
TestMetalView* metalView = [[TestMetalView alloc] init];
CALayer* layer = reinterpret_cast<CALayer*>(metalView.layer);
return [[FlutterMetalSurfaceManager alloc] initWithDevice:device
commandQueue:commandQueue
layer:layer];
return [[FlutterSurfaceManager alloc] initWithDevice:device
commandQueue:commandQueue
layer:layer];
}
TEST(FlutterMetalSurfaceManager, EnsureSizeUpdatesSize) {
FlutterMetalSurfaceManager* surfaceManager = CreateSurfaceManager();
TEST(FlutterSurfaceManager, EnsureSizeUpdatesSize) {
FlutterSurfaceManager* surfaceManager = CreateSurfaceManager();
CGSize size = CGSizeMake(100, 50);
[surfaceManager ensureSurfaceSize:size];
id<MTLTexture> texture =
@@ -49,8 +49,8 @@ TEST(FlutterMetalSurfaceManager, EnsureSizeUpdatesSize) {
ASSERT_TRUE(CGSizeEqualToSize(size, textureSize));
}
TEST(FlutterMetalSurfaceManager, EnsureSizeUpdatesSizeForBackBuffer) {
FlutterMetalSurfaceManager* surfaceManager = CreateSurfaceManager();
TEST(FlutterSurfaceManager, EnsureSizeUpdatesSizeForBackBuffer) {
FlutterSurfaceManager* surfaceManager = CreateSurfaceManager();
CGSize size = CGSizeMake(100, 50);
[surfaceManager ensureSurfaceSize:size];
[surfaceManager renderBuffer]; // make sure we have back buffer