50 [NSColor yellowColor],
52 [NSColor magentaColor],
54 [NSColor purpleColor],
55 [NSColor orangeColor],
58 return colors[layer % colors.count];
68 const std::vector<FlutterRect>& paintRegion) {
70 while (layer.sublayers.count > paintRegion.size()) {
71 [layer.sublayers.lastObject removeFromSuperlayer];
74 while (layer.sublayers.count < paintRegion.size()) {
75 CALayer* newLayer = [CALayer layer];
76 [layer addSublayer:newLayer];
79 for (
size_t i = 0;
i < paintRegion.size();
i++) {
80 CALayer* subLayer = [layer.sublayers objectAtIndex:i];
81 const auto& rect = paintRegion[i];
82 subLayer.frame = CGRectMake(rect.left / scale, rect.top / scale,
83 (rect.right - rect.left) / scale, (rect.bottom - rect.top) / scale);
85 double width = surfaceSize.width;
86 double height = surfaceSize.height;
88 subLayer.contentsRect =
89 CGRectMake(rect.left /
width, rect.top /
height, (rect.right - rect.left) /
width,
90 (rect.bottom - rect.top) /
height);
92 if (borderColor != nil) {
94 subLayer.borderColor = borderColor.CGColor;
95 subLayer.borderWidth = 1.0;
104- (instancetype)initWithDevice:(
id<MTLDevice>)device
105 commandQueue:(
id<MTLCommandQueue>)commandQueue
106 layer:(CALayer*)containingLayer
107 delegate:(__weak
id<FlutterSurfaceManagerDelegate>)delegate {
108 if (
self = [super init]) {
110 _commandQueue = commandQueue;
111 _containingLayer = containingLayer;
112 _delegate = delegate;
115 _frontSurfaces = [NSMutableArray array];
116 _layers = [NSMutableArray array];
122 return _backBufferCache;
125- (NSArray*)frontSurfaces {
126 return _frontSurfaces;
135 if (surface == nil) {
141- (
BOOL)enableSurfaceDebugInfo {
142 if (_enableSurfaceDebugInfo == nil) {
143 _enableSurfaceDebugInfo =
144 [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTEnableSurfaceDebugInfo"];
145 if (_enableSurfaceDebugInfo == nil) {
146 _enableSurfaceDebugInfo = @NO;
149 return [_enableSurfaceDebugInfo boolValue];
156 [_backBufferCache returnSurfaces:_frontSurfaces];
159 [_frontSurfaces removeAllObjects];
161 [_frontSurfaces addObject:info.surface];
165 while (_layers.count > _frontSurfaces.count) {
166 [_layers.lastObject removeFromSuperlayer];
167 [_layers removeLastObject];
169 while (_layers.count < _frontSurfaces.count) {
170 CALayer* layer = [CALayer layer];
171 [_containingLayer addSublayer:layer];
172 [_layers addObject:layer];
175 bool enableSurfaceDebugInfo =
self.enableSurfaceDebugInfo;
178 for (
size_t i = 0;
i < surfaces.count; ++
i) {
180 CALayer* layer = _layers[i];
181 CGFloat scale = _containingLayer.contentsScale;
183 layer.frame = CGRectMake(info.
offset.x / scale, info.
offset.y / scale,
187 layer.frame = CGRectZero;
192 layer.zPosition = info.
zIndex;
195 if (enableSurfaceDebugInfo) {
196 if (_infoLayer == nil) {
197 _infoLayer = [[CATextLayer alloc] init];
198 [_containingLayer addSublayer:_infoLayer];
199 _infoLayer.fontSize = 15;
200 _infoLayer.foregroundColor = [NSColor yellowColor].CGColor;
201 _infoLayer.frame = CGRectMake(15, 15, 300, 100);
202 _infoLayer.contentsScale = _containingLayer.contentsScale;
203 _infoLayer.zPosition = 100000;
205 _infoLayer.string = [NSString stringWithFormat:@"Surface count: %li", _layers.count];
209static CGSize GetRequiredFrameSize(NSArray<FlutterSurfacePresentInfo*>* surfaces) {
210 CGSize
size = CGSizeZero;
219 atTime:(CFTimeInterval)presentationTime
220 notify:(dispatch_block_t)notify {
221 id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
222 [commandBuffer commit];
223 [commandBuffer waitUntilScheduled];
225 CGSize
size = GetRequiredFrameSize(surfaces);
227 CFTimeInterval delay = 0;
229 if (presentationTime > 0) {
241 CFTimeInterval minPresentationTime = (presentationTime + _lastPresentationTime) / 2.0;
242 CFTimeInterval now = CACurrentMediaTime();
243 delay = std::max(minPresentationTime - now, 0.0);
245 [_delegate onPresent:size
247 _lastPresentationTime = presentationTime;
248 [CATransaction begin];
249 [CATransaction setDisableActions:YES];
250 [
self commit:surfaces];
254 [CATransaction commit];
278- (instancetype)init {
279 if (
self = [super init]) {
280 self->_surfaces = [[NSMutableArray alloc] init];
281 self->_surfaceAge = [NSMapTable weakToStrongObjectsMapTable];
287 NSNumber* age = [_surfaceAge objectForKey:surface];
288 return age != nil ? age.intValue : 0;
292 [_surfaceAge setObject:@(age) forKey:surface];
296 @
synchronized(
self) {
298 if (_surfaces.firstObject != nil && !CGSizeEqualToSize(_surfaces.firstObject.size, size)) {
299 [_surfaces removeAllObjects];
309 (res == nil || [
self ageForSurface:res] > [
self ageForSurface:
surface])) {
314 [_surfaces removeObject:res];
320- (void)returnSurfaces:(nonnull NSArray<
FlutterSurface*>*)returnedSurfaces {
321 @
synchronized(
self) {
323 [
self setAge:0 forSurface:surface];
326 [
self setAge:[
self ageForSurface:surface] + 1 forSurface:surface];
329 [_surfaces addObjectsFromArray:returnedSurfaces];
336 [_surfaces filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FlutterSurface* surface,
337 NSDictionary* bindings) {
338 return [
self ageForSurface:surface] < kSurfaceEvictionAge;
343 [
self performSelectorOnMainThread:@selector(reschedule) withObject:nil waitUntilDone:NO];
347 @
synchronized(
self) {
348 return _surfaces.count;
353 @
synchronized(
self) {
354 [_surfaces removeAllObjects];
359 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onIdle) object:nil];
360 [
self performSelector:@selector(onIdle) withObject:nil afterDelay:kIdleDelay];
364 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onIdle) object:nil];
static void UpdateContentSubLayers(CALayer *layer, IOSurfaceRef surface, CGFloat scale, CGSize surfaceSize, NSColor *borderColor, const std::vector< FlutterRect > &paintRegion)
static NSColor * GetBorderColorForLayer(int layer)
static const double kIdleDelay
static const int kSurfaceEvictionAge
NSMutableArray< FlutterSurface * > * _surfaces
NSMapTable< FlutterSurface *, NSNumber * > * _surfaceAge
CALayer * _containingLayer
id< MTLCommandQueue > _commandQueue
NSMutableArray< FlutterSurface * > * _frontSurfaces
__weak id< FlutterSurfaceManagerDelegate > _delegate
FlutterBackBufferCache * _backBufferCache
CFTimeInterval _lastPresentationTime
NSMutableArray< CALayer * > * _layers
NSNumber * _enableSurfaceDebugInfo
const FlutterLayer ** layers
#define FML_DCHECK(condition)
std::vector< FlutterRect > paintRegion
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size