@@ -13,6 +13,7 @@ @interface DisplayLinkManager : NSObject
1313+ (double )displayRefreshRate ;
1414@end
1515
16+ @class FlutterTexture;
1617@class FlutterDrawable;
1718
1819extern CFTimeInterval display_link_target;
@@ -23,10 +24,10 @@ @interface FlutterMetalLayer () {
2324
2425 NSUInteger _nextDrawableId;
2526
26- NSMutableSet <FlutterDrawable *>* _availableDrawables ;
27- NSUInteger _totalDrawables ;
27+ NSMutableSet <FlutterTexture *>* _availableTextures ;
28+ NSUInteger _totalTextures ;
2829
29- FlutterDrawable * _front;
30+ FlutterTexture * _front;
3031
3132 // There must be a CADisplayLink scheduled *on main thread* otherwise
3233 // core animation only updates layers 60 times a second.
@@ -44,25 +45,103 @@ @interface FlutterMetalLayer () {
4445 BOOL _displayLinkForcedMaxRate;
4546}
4647
47- - (void )presentDrawable : (FlutterDrawable*)drawable ;
48+ - (void )presentTexture : (FlutterTexture*)texture ;
49+ - (void )returnTexture : (FlutterTexture*)texture ;
4850
4951@end
5052
51- @interface FlutterDrawable : NSObject < CAMetalDrawable > {
53+ @interface FlutterTexture : NSObject {
5254 id <MTLTexture > _texture;
53- __weak FlutterMetalLayer* _layer;
54- NSUInteger _drawableId;
5555 IOSurface * _surface;
5656 CFTimeInterval _presentedTime;
5757}
5858
59- - (instancetype )initWithTexture : (id <MTLTexture >)texture
59+ @property (readonly , nonatomic ) id <MTLTexture > texture;
60+ @property (readonly , nonatomic ) IOSurface * surface;
61+ @property (readwrite , nonatomic ) CFTimeInterval presentedTime;
62+
63+ @end
64+
65+ @implementation FlutterTexture
66+
67+ @synthesize texture = _texture;
68+ @synthesize surface = _surface;
69+ @synthesize presentedTime = _presentedTime;
70+
71+ - (instancetype )initWithTexture : (id <MTLTexture >)texture surface : (IOSurface *)surface {
72+ if (self = [super init ]) {
73+ _texture = texture;
74+ _surface = surface;
75+ }
76+ return self;
77+ }
78+
79+ @end
80+
81+ @interface FlutterDrawable : NSObject <CAMetalDrawable > {
82+ FlutterTexture* _texture;
83+ __weak FlutterMetalLayer* _layer;
84+ NSUInteger _drawableId;
85+ BOOL _presented;
86+ }
87+
88+ - (instancetype )initWithTexture : (FlutterTexture*)texture
6089 layer : (FlutterMetalLayer*)layer
61- drawableId : (NSUInteger )drawableId
62- surface : (IOSurface *)surface ;
90+ drawableId : (NSUInteger )drawableId ;
6391
64- @property (readonly ) IOSurface * surface;
65- @property (readwrite , nonatomic ) CFTimeInterval presentedTime;
92+ @end
93+
94+ @implementation FlutterDrawable
95+
96+ - (instancetype )initWithTexture : (FlutterTexture*)texture
97+ layer : (FlutterMetalLayer*)layer
98+ drawableId : (NSUInteger )drawableId {
99+ if (self = [super init ]) {
100+ _texture = texture;
101+ _layer = layer;
102+ _drawableId = drawableId;
103+ }
104+ return self;
105+ }
106+
107+ - (id <MTLTexture >)texture {
108+ return self->_texture .texture ;
109+ }
110+
111+ #pragma clang diagnostic push
112+ #pragma clang diagnostic ignored "-Wunguarded-availability-new"
113+ - (CAMetalLayer *)layer {
114+ return (id )self->_layer ;
115+ }
116+ #pragma clang diagnostic pop
117+
118+ - (NSUInteger )drawableID {
119+ return self->_drawableId ;
120+ }
121+
122+ - (CFTimeInterval)presentedTime {
123+ return 0 ;
124+ }
125+
126+ - (void )present {
127+ [_layer presentTexture: self ->_texture];
128+ self->_presented = YES ;
129+ }
130+
131+ - (void )dealloc {
132+ if (!_presented) {
133+ [_layer returnTexture: self ->_texture];
134+ }
135+ }
136+
137+ - (void )addPresentedHandler : (nonnull MTLDrawablePresentedHandler )block {
138+ }
139+
140+ - (void )presentAtTime : (CFTimeInterval)presentationTime {
141+ }
142+
143+ - (void )presentAfterMinimumDuration : (CFTimeInterval)duration {
144+ }
66145
67146@end
68147
@@ -79,7 +158,8 @@ - (instancetype)init {
79158 if (self = [super init ]) {
80159 _preferredDevice = MTLCreateSystemDefaultDevice ();
81160 self.device = self.preferredDevice ;
82- _availableDrawables = [[NSMutableSet alloc ] init ];
161+ self.pixelFormat = MTLPixelFormatBGRA8Unorm ;
162+ _availableTextures = [[NSMutableSet alloc ] init ];
83163
84164 _displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector (onDisplayLink: )];
85165 [self setMaxRefreshRate: [DisplayLinkManager displayRefreshRate ] forceMax: NO ];
@@ -136,15 +216,15 @@ - (BOOL)isKindOfClass:(Class)aClass {
136216}
137217
138218- (void )setDrawableSize : (CGSize)drawableSize {
139- [_availableDrawables removeAllObjects ];
219+ [_availableTextures removeAllObjects ];
140220 _front = nil ;
141- _totalDrawables = 0 ;
221+ _totalTextures = 0 ;
142222 _drawableSize = drawableSize;
143223}
144224
145225- (void )didEnterBackground : (id )notification {
146- [_availableDrawables removeAllObjects ];
147- _totalDrawables = _front != nil ? 1 : 0 ;
226+ [_availableTextures removeAllObjects ];
227+ _totalTextures = _front != nil ? 1 : 0 ;
148228 _displayLink.paused = YES ;
149229}
150230
@@ -185,15 +265,15 @@ - (IOSurface*)createIOSurface {
185265 return (__bridge_transfer IOSurface *)res;
186266}
187267
188- - (id < CAMetalDrawable >) nextDrawable {
268+ - (FlutterTexture*) nextTexture {
189269 @synchronized (self) {
190270 // IOSurface.isInUse to determine when compositor is done with the surface.
191271 // That a rather blunt instrument and we are probably waiting longer than
192272 // we really need to. With triple buffering at 120Hz that results in about
193273 // 2-3 milliseconds wait time at beginning of display link callback.
194274 // With four buffers this number gets close to zero.
195- if (_totalDrawables < 3 ) {
196- ++_totalDrawables ;
275+ if (_totalTextures < 3 ) {
276+ ++_totalTextures ;
197277 IOSurface * surface = [self createIOSurface ];
198278 MTLTextureDescriptor * textureDescriptor =
199279 [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: _pixelFormat
@@ -205,20 +285,18 @@ - (IOSurface*)createIOSurface {
205285 id <MTLTexture > texture = [self .device newTextureWithDescriptor: textureDescriptor
206286 iosurface: (__bridge IOSurfaceRef)surface
207287 plane: 0 ];
208- FlutterDrawable* drawable = [[FlutterDrawable alloc ] initWithTexture: texture
209- layer: self
210- drawableId: _nextDrawableId++
211- surface: surface];
212- return drawable;
288+ FlutterTexture* flutterTexture = [[FlutterTexture alloc ] initWithTexture: texture
289+ surface: surface];
290+ return flutterTexture;
213291 } else {
214292 // Make sure raster thread doesn't have too many drawables in flight.
215- if (_availableDrawables .count == 0 ) {
293+ if (_availableTextures .count == 0 ) {
216294 CFTimeInterval start = CACurrentMediaTime ();
217- while (_availableDrawables .count == 0 && CACurrentMediaTime () - start < 0.1 ) {
295+ while (_availableTextures .count == 0 && CACurrentMediaTime () - start < 0.1 ) {
218296 usleep (100 );
219297 }
220298 CFTimeInterval elapsed = CACurrentMediaTime () - start;
221- if (_availableDrawables .count == 0 ) {
299+ if (_availableTextures .count == 0 ) {
222300 NSLog (@" Waited %f seconds for a drawable, giving up." , elapsed);
223301 return nil ;
224302 } else {
@@ -227,31 +305,42 @@ - (IOSurface*)createIOSurface {
227305 }
228306 // Return first drawable that is not in use or the one that was presented
229307 // the longest time ago.
230- FlutterDrawable * res = nil ;
231- for (FlutterDrawable* drawable in _availableDrawables ) {
232- if (!drawable .surface .isInUse ) {
233- res = drawable ;
308+ FlutterTexture * res = nil ;
309+ for (FlutterTexture* texture in _availableTextures ) {
310+ if (!texture .surface .isInUse ) {
311+ res = texture ;
234312 break ;
235313 }
236- if (res == nil || drawable .presentedTime < res.presentedTime ) {
237- res = drawable ;
314+ if (res == nil || texture .presentedTime < res.presentedTime ) {
315+ res = texture ;
238316 }
239317 }
240- [_availableDrawables removeObject: res];
318+ [_availableTextures removeObject: res];
241319 return res;
242320 }
243321 }
244322}
245323
246- - (void )presentOnMainThread : (FlutterDrawable*)drawable {
324+ - (id <CAMetalDrawable >)nextDrawable {
325+ FlutterTexture* texture = [self nextTexture ];
326+ if (texture == nil ) {
327+ return nil ;
328+ }
329+ FlutterDrawable* drawable = [[FlutterDrawable alloc ] initWithTexture: texture
330+ layer: self
331+ drawableId: _nextDrawableId++];
332+ return drawable;
333+ }
334+
335+ - (void )presentOnMainThread : (FlutterTexture*)texture {
247336 // This is needed otherwise frame gets skipped on touch begin / end. Go figure.
248337 // Might also be placebo
249338 [self setNeedsDisplay ];
250339
251340 [CATransaction begin ];
252341 [CATransaction setDisableActions: YES ];
253- self.contents = drawable .surface ;
254- drawable .presentedTime = CACurrentMediaTime ();
342+ self.contents = texture .surface ;
343+ texture .presentedTime = CACurrentMediaTime ();
255344 [CATransaction commit ];
256345 _displayLink.paused = NO ;
257346 _displayLinkPauseCountdown = 0 ;
@@ -263,63 +352,26 @@ - (void)presentOnMainThread:(FlutterDrawable*)drawable {
263352 }
264353}
265354
266- - (void )presentDrawable : (FlutterDrawable*) drawable {
355+ - (void )presentTexture : (FlutterTexture*) texture {
267356 @synchronized (self) {
268357 if (_front != nil ) {
269- [_availableDrawables addObject: _front];
358+ [_availableTextures addObject: _front];
359+ }
360+ _front = texture;
361+ if ([NSThread isMainThread ]) {
362+ [self presentOnMainThread: texture];
363+ } else {
364+ dispatch_async (dispatch_get_main_queue (), ^{
365+ [self presentOnMainThread: texture];
366+ });
270367 }
271- _front = drawable;
272- dispatch_async (dispatch_get_main_queue (), ^{
273- [self presentOnMainThread: drawable];
274- });
275368 }
276369}
277370
278- @end
279-
280- @implementation FlutterDrawable
281-
282- @synthesize presentedTime = _presentedTime;
283-
284- - (instancetype )initWithTexture : (id <MTLTexture >)texture
285- layer : (FlutterMetalLayer*)layer
286- drawableId : (NSUInteger )drawableId
287- surface : (IOSurface *)surface {
288- if (self = [super init ]) {
289- _texture = texture;
290- _layer = layer;
291- _drawableId = drawableId;
292- _surface = surface;
371+ - (void )returnTexture : (FlutterTexture*)texture {
372+ @synchronized (self) {
373+ [_availableTextures addObject: texture];
293374 }
294- return self;
295- }
296-
297- - (id <MTLTexture >)texture {
298- return self->_texture ;
299- }
300-
301- #pragma clang diagnostic push
302- #pragma clang diagnostic ignored "-Wunguarded-availability-new"
303- - (CAMetalLayer *)layer {
304- return (id )self->_layer ;
305- }
306- #pragma clang diagnostic pop
307-
308- - (NSUInteger )drawableID {
309- return self->_drawableId ;
310- }
311-
312- - (void )present {
313- [_layer presentDrawable: self ];
314- }
315-
316- - (void )addPresentedHandler : (nonnull MTLDrawablePresentedHandler )block {
317- }
318-
319- - (void )presentAtTime : (CFTimeInterval)presentationTime {
320- }
321-
322- - (void )presentAfterMinimumDuration : (CFTimeInterval)duration {
323375}
324376
325377@end
0 commit comments