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

Commit 54b669a

Browse files
committed
Purge back buffer cache when inactive
1 parent ecf1780 commit 54b669a

File tree

2 files changed

+100
-17
lines changed

2 files changed

+100
-17
lines changed

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

Lines changed: 79 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,64 @@
88
#import <Metal/Metal.h>
99
#include <algorithm>
1010

11+
// Cached back buffers will be released after kIdleDelay if there is no activity.
12+
static const double kIdleDelay = 1.0;
13+
14+
@interface FlutterBackBufferCache () {
15+
NSMutableArray<FlutterSurface*>* _surfaces;
16+
}
17+
18+
@end
19+
20+
@implementation FlutterBackBufferCache
21+
22+
- (instancetype)init {
23+
if (self = [super init]) {
24+
self->_surfaces = [[NSMutableArray alloc] init];
25+
}
26+
return self;
27+
}
28+
29+
- (nullable FlutterSurface*)getSurfaceForSize:(CGSize)size {
30+
@synchronized(self) {
31+
for (FlutterSurface* surface in _surfaces) {
32+
if (CGSizeEqualToSize(surface.size, size)) {
33+
FlutterSurface* res = surface;
34+
[_surfaces removeObject:surface];
35+
return res;
36+
}
37+
}
38+
return nil;
39+
}
40+
}
41+
42+
- (void)replaceWith:(nonnull NSArray<FlutterSurface*>*)surfaces {
43+
@synchronized(self) {
44+
[_surfaces removeAllObjects];
45+
[_surfaces addObjectsFromArray:surfaces];
46+
}
47+
48+
// performSelector:withObject:afterDelay needs to be performed on RunLoop thread
49+
[self performSelectorOnMainThread:@selector(reschedule) withObject:nil waitUntilDone:NO];
50+
}
51+
52+
- (void)onIdle {
53+
@synchronized(self) {
54+
[_surfaces removeAllObjects];
55+
}
56+
}
57+
58+
- (void)reschedule {
59+
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onIdle) object:nil];
60+
[self performSelector:@selector(onIdle) withObject:nil afterDelay:kIdleDelay];
61+
}
62+
63+
- (void)dealloc {
64+
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onIdle) object:nil];
65+
}
66+
67+
@end
68+
1169
@implementation FlutterSurfacePresentInfo
1270
@end
1371

@@ -17,9 +75,9 @@ @interface FlutterSurfaceManager () {
1775
CALayer* _containingLayer;
1876
__weak id<FlutterSurfaceManagerDelegate> _delegate;
1977

20-
// Available (cached) back buffer surfaces. These will be removed during
78+
// Available (cached) back buffer surfaces. These will be cleared during
2179
// present and replaced by current frong surfaces.
22-
NSMutableArray<FlutterSurface*>* _backBufferSurfaces;
80+
FlutterBackBufferCache* _backBufferCache;
2381

2482
// Surfaces that currently obtained through backBufferForSize waiting to be
2583
// presented. This is used to keep the surface alive because the non compositor
@@ -46,14 +104,30 @@ - (instancetype)initWithDevice:(id<MTLDevice>)device
46104
_containingLayer = containingLayer;
47105
_delegate = delegate;
48106

49-
_backBufferSurfaces = [NSMutableArray array];
107+
_backBufferCache = [[FlutterBackBufferCache alloc] init];
50108
_borrowedSurfaces = [NSMutableArray array];
51109
_frontSurfaces = [NSMutableArray array];
52110
_layers = [NSMutableArray array];
53111
}
54112
return self;
55113
}
56114

115+
- (FlutterBackBufferCache*)backBufferCache {
116+
return _backBufferCache;
117+
}
118+
119+
- (NSArray*)borrowedSurfaces {
120+
return _borrowedSurfaces;
121+
}
122+
123+
- (NSArray*)frontSurfaces {
124+
return _frontSurfaces;
125+
}
126+
127+
- (NSArray*)layers {
128+
return _layers;
129+
}
130+
57131
- (FlutterSurface*)lookupSurface:(nonnull const FlutterMetalTexture*)texture {
58132
for (FlutterSurface* surface in _borrowedSurfaces) {
59133
if (surface.textureId == texture->texture_id) {
@@ -64,14 +138,7 @@ - (FlutterSurface*)lookupSurface:(nonnull const FlutterMetalTexture*)texture {
64138
}
65139

66140
- (FlutterSurface*)backBufferForSize:(CGSize)size {
67-
FlutterSurface* res = nil;
68-
for (FlutterSurface* surface in _backBufferSurfaces) {
69-
if (CGSizeEqualToSize(surface.size, size)) {
70-
res = surface;
71-
[_backBufferSurfaces removeObject:surface];
72-
break;
73-
}
74-
}
141+
FlutterSurface* res = [_backBufferCache getSurfaceForSize:size];
75142
if (res == nil) {
76143
res = [[FlutterSurface alloc] initWithSize:size device:_device];
77144
}
@@ -85,8 +152,7 @@ - (void)commit:(NSArray<FlutterSurfacePresentInfo*>*)surfaces {
85152
[_borrowedSurfaces removeAllObjects];
86153

87154
// Release all unused back buffer surfaces and replace them with front surfaces.
88-
[_backBufferSurfaces removeAllObjects];
89-
[_backBufferSurfaces addObjectsFromArray:_frontSurfaces];
155+
[_backBufferCache replaceWith:_frontSurfaces];
90156

91157
// Front surfaces will be replaced by currently presented surfaces.
92158
[_frontSurfaces removeAllObjects];

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,31 @@
66

77
#import <QuartzCore/QuartzCore.h>
88

9+
/**
10+
* Responsible for caching back buffers to prevent unnecessary IOSurface allocations.
11+
*/
12+
@interface FlutterBackBufferCache : NSObject
13+
14+
/**
15+
* Removes surface with given size from cache (if available) and returns it.
16+
*/
17+
- (nullable FlutterSurface*)getSurfaceForSize:(CGSize)size;
18+
19+
/**
20+
* Removes all cached surface replacing them with new ones.
21+
*/
22+
- (void)replaceWith:(nonnull NSArray<FlutterSurface*>*)surfaces;
23+
24+
@end
25+
926
/**
1027
* Interface to internal properties used for testing.
1128
*/
1229
@interface FlutterSurfaceManager ()
1330

14-
@property(readonly, nonatomic) NSArray<FlutterSurface*>* backBufferSurfaces;
15-
@property(readonly, nonatomic) NSArray<FlutterSurface*>* borrowedSurfaces;
16-
@property(readonly, nonatomic) NSArray<FlutterSurface*>* frontSurfaces;
17-
@property(readonly, nonatomic) NSArray<CALayer*>* layers;
31+
@property(readonly, nonatomic, nonnull) FlutterBackBufferCache* backBufferCache;
32+
@property(readonly, nonatomic, nonnull) NSArray<FlutterSurface*>* borrowedSurfaces;
33+
@property(readonly, nonatomic, nonnull) NSArray<FlutterSurface*>* frontSurfaces;
34+
@property(readonly, nonatomic, nonnull) NSArray<CALayer*>* layers;
1835

1936
@end

0 commit comments

Comments
 (0)