Fix retain cycle in FlutterMetalLayer (flutter/engine#54119)
*Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* *List which issues are fixed by this PR. You must list at least one issue.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
parent
b0dfbbd8ef
commit
f0901b70fc
@ -50,6 +50,7 @@ extern CFTimeInterval display_link_target;
|
||||
BOOL _displayLinkForcedMaxRate;
|
||||
}
|
||||
|
||||
- (void)onDisplayLink:(CADisplayLink*)link;
|
||||
- (void)presentTexture:(FlutterTexture*)texture;
|
||||
- (void)returnTexture:(FlutterTexture*)texture;
|
||||
|
||||
@ -163,6 +164,26 @@ extern CFTimeInterval display_link_target;
|
||||
|
||||
@end
|
||||
|
||||
@interface FlutterMetalLayerDisplayLinkProxy : NSObject {
|
||||
__weak FlutterMetalLayer* _layer;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FlutterMetalLayerDisplayLinkProxy
|
||||
- (instancetype)initWithLayer:(FlutterMetalLayer*)layer {
|
||||
if (self = [super init]) {
|
||||
_layer = layer;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)onDisplayLink:(CADisplayLink*)link {
|
||||
[_layer onDisplayLink:link];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FlutterMetalLayer
|
||||
|
||||
@synthesize preferredDevice = _preferredDevice;
|
||||
@ -179,7 +200,9 @@ extern CFTimeInterval display_link_target;
|
||||
self.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
_availableTextures = [[NSMutableSet alloc] init];
|
||||
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)];
|
||||
FlutterMetalLayerDisplayLinkProxy* proxy =
|
||||
[[FlutterMetalLayerDisplayLinkProxy alloc] initWithLayer:self];
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:proxy selector:@selector(onDisplayLink:)];
|
||||
[self setMaxRefreshRate:DisplayLinkManager.displayRefreshRate forceMax:NO];
|
||||
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
@ -190,6 +213,11 @@ extern CFTimeInterval display_link_target;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_displayLink invalidate];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)setMaxRefreshRate:(double)refreshRate forceMax:(BOOL)forceMax {
|
||||
// This is copied from vsync_waiter_ios.mm. The vsync waiter has display link scheduled on UI
|
||||
// thread which does not trigger actual core animation frame. As a workaround FlutterMetalLayer
|
||||
|
@ -270,4 +270,24 @@
|
||||
[self removeMetalLayer:layer];
|
||||
}
|
||||
|
||||
- (void)testDealloc {
|
||||
__weak FlutterMetalLayer* weakLayer;
|
||||
@autoreleasepool {
|
||||
FlutterMetalLayer* layer = [self addMetalLayer];
|
||||
weakLayer = layer;
|
||||
TestCompositor* compositor = [[TestCompositor alloc] initWithLayer:layer];
|
||||
|
||||
id<CAMetalDrawable> drawable = [layer nextDrawable];
|
||||
BAIL_IF_NO_DRAWABLE(drawable);
|
||||
[drawable present];
|
||||
[compositor commitTransaction];
|
||||
|
||||
[self removeMetalLayer:layer];
|
||||
// Deallocating the layer after removing is not synchronous.
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, YES);
|
||||
}
|
||||
|
||||
XCTAssertNil(weakLayer);
|
||||
}
|
||||
|
||||
@end
|
||||
|
Loading…
x
Reference in New Issue
Block a user