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;
|
BOOL _displayLinkForcedMaxRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)onDisplayLink:(CADisplayLink*)link;
|
||||||
- (void)presentTexture:(FlutterTexture*)texture;
|
- (void)presentTexture:(FlutterTexture*)texture;
|
||||||
- (void)returnTexture:(FlutterTexture*)texture;
|
- (void)returnTexture:(FlutterTexture*)texture;
|
||||||
|
|
||||||
@ -163,6 +164,26 @@ extern CFTimeInterval display_link_target;
|
|||||||
|
|
||||||
@end
|
@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
|
@implementation FlutterMetalLayer
|
||||||
|
|
||||||
@synthesize preferredDevice = _preferredDevice;
|
@synthesize preferredDevice = _preferredDevice;
|
||||||
@ -179,7 +200,9 @@ extern CFTimeInterval display_link_target;
|
|||||||
self.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
self.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||||
_availableTextures = [[NSMutableSet alloc] init];
|
_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];
|
[self setMaxRefreshRate:DisplayLinkManager.displayRefreshRate forceMax:NO];
|
||||||
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
@ -190,6 +213,11 @@ extern CFTimeInterval display_link_target;
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[_displayLink invalidate];
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setMaxRefreshRate:(double)refreshRate forceMax:(BOOL)forceMax {
|
- (void)setMaxRefreshRate:(double)refreshRate forceMax:(BOOL)forceMax {
|
||||||
// This is copied from vsync_waiter_ios.mm. The vsync waiter has display link scheduled on UI
|
// 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
|
// thread which does not trigger actual core animation frame. As a workaround FlutterMetalLayer
|
||||||
|
@ -270,4 +270,24 @@
|
|||||||
[self removeMetalLayer:layer];
|
[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
|
@end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user