8
8
#import < Metal/Metal.h>
9
9
#include < algorithm>
10
10
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
+
11
69
@implementation FlutterSurfacePresentInfo
12
70
@end
13
71
@@ -17,9 +75,9 @@ @interface FlutterSurfaceManager () {
17
75
CALayer * _containingLayer;
18
76
__weak id <FlutterSurfaceManagerDelegate> _delegate;
19
77
20
- // Available (cached) back buffer surfaces. These will be removed during
78
+ // Available (cached) back buffer surfaces. These will be cleared during
21
79
// present and replaced by current frong surfaces.
22
- NSMutableArray <FlutterSurface*>* _backBufferSurfaces ;
80
+ FlutterBackBufferCache* _backBufferCache ;
23
81
24
82
// Surfaces that currently obtained through backBufferForSize waiting to be
25
83
// presented. This is used to keep the surface alive because the non compositor
@@ -46,14 +104,30 @@ - (instancetype)initWithDevice:(id<MTLDevice>)device
46
104
_containingLayer = containingLayer;
47
105
_delegate = delegate;
48
106
49
- _backBufferSurfaces = [NSMutableArray array ];
107
+ _backBufferCache = [[FlutterBackBufferCache alloc ] init ];
50
108
_borrowedSurfaces = [NSMutableArray array ];
51
109
_frontSurfaces = [NSMutableArray array ];
52
110
_layers = [NSMutableArray array ];
53
111
}
54
112
return self;
55
113
}
56
114
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
+
57
131
- (FlutterSurface*)lookupSurface : (nonnull const FlutterMetalTexture*)texture {
58
132
for (FlutterSurface* surface in _borrowedSurfaces) {
59
133
if (surface.textureId == texture->texture_id ) {
@@ -64,14 +138,7 @@ - (FlutterSurface*)lookupSurface:(nonnull const FlutterMetalTexture*)texture {
64
138
}
65
139
66
140
- (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];
75
142
if (res == nil ) {
76
143
res = [[FlutterSurface alloc ] initWithSize: size device: _device];
77
144
}
@@ -85,8 +152,7 @@ - (void)commit:(NSArray<FlutterSurfacePresentInfo*>*)surfaces {
85
152
[_borrowedSurfaces removeAllObjects ];
86
153
87
154
// Release all unused back buffer surfaces and replace them with front surfaces.
88
- [_backBufferSurfaces removeAllObjects ];
89
- [_backBufferSurfaces addObjectsFromArray: _frontSurfaces];
155
+ [_backBufferCache replaceWith: _frontSurfaces];
90
156
91
157
// Front surfaces will be replaced by currently presented surfaces.
92
158
[_frontSurfaces removeAllObjects ];
0 commit comments