51 [NSColor yellowColor],
53 [NSColor magentaColor],
55 [NSColor purpleColor],
56 [NSColor orangeColor],
59 return colors[layer % colors.count];
69 const std::vector<FlutterRect>& paintRegion) {
71 while (layer.sublayers.count > paintRegion.size()) {
72 [layer.sublayers.lastObject removeFromSuperlayer];
75 while (layer.sublayers.count < paintRegion.size()) {
76 CALayer* newLayer = [CALayer layer];
77 [layer addSublayer:newLayer];
80 for (
size_t i = 0;
i < paintRegion.size();
i++) {
81 CALayer* subLayer = [layer.sublayers objectAtIndex:i];
82 const auto& rect = paintRegion[i];
83 subLayer.frame = CGRectMake(rect.left / scale, rect.top / scale,
84 (rect.right - rect.left) / scale, (rect.bottom - rect.top) / scale);
86 double width = surfaceSize.width;
87 double height = surfaceSize.height;
89 subLayer.contentsRect =
90 CGRectMake(rect.left /
width, rect.top /
height, (rect.right - rect.left) /
width,
91 (rect.bottom - rect.top) /
height);
93 if (borderColor != nil) {
95 subLayer.borderColor = borderColor.CGColor;
96 subLayer.borderWidth = 1.0;
105- (instancetype)initWithDevice:(
id<MTLDevice>)device
106 commandQueue:(
id<MTLCommandQueue>)commandQueue
107 layer:(CALayer*)containingLayer
108 delegate:(__weak
id<FlutterSurfaceManagerDelegate>)delegate
109 wideGamut:(
BOOL)wideGamut {
110 if (
self = [super init]) {
112 _commandQueue = commandQueue;
113 _containingLayer = containingLayer;
114 _delegate = delegate;
115 _wideGamut = wideGamut;
117 _frontSurfaces = [NSMutableArray array];
118 _layers = [NSMutableArray array];
123- (void)setEnableWideGamut:(
BOOL)enableWideGamut {
125 if (_wideGamut == enableWideGamut) {
128 _wideGamut = enableWideGamut;
131 [_backBufferCache flush];
134 [_frontSurfaces removeAllObjects];
138 return _backBufferCache;
141- (NSArray*)frontSurfaces {
142 return _frontSurfaces;
151 if (surface == nil) {
157- (
BOOL)enableSurfaceDebugInfo {
158 if (_enableSurfaceDebugInfo == nil) {
159 _enableSurfaceDebugInfo =
160 [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTEnableSurfaceDebugInfo"];
161 if (_enableSurfaceDebugInfo == nil) {
162 _enableSurfaceDebugInfo = @NO;
165 return [_enableSurfaceDebugInfo boolValue];
174 if (info.surface.isWideGamut != _wideGamut) {
180 [_backBufferCache returnSurfaces:_frontSurfaces];
183 [_frontSurfaces removeAllObjects];
185 [_frontSurfaces addObject:info.surface];
189 while (_layers.count > _frontSurfaces.count) {
190 [_layers.lastObject removeFromSuperlayer];
191 [_layers removeLastObject];
193 while (_layers.count < _frontSurfaces.count) {
194 CALayer* layer = [CALayer layer];
195 [_containingLayer addSublayer:layer];
196 [_layers addObject:layer];
199 bool enableSurfaceDebugInfo =
self.enableSurfaceDebugInfo;
202 for (
size_t i = 0;
i < surfaces.count; ++
i) {
204 CALayer* layer = _layers[i];
205 CGFloat scale = _containingLayer.contentsScale;
207 layer.frame = CGRectMake(info.
offset.x / scale, info.
offset.y / scale,
211 layer.frame = CGRectZero;
216 layer.zPosition = info.
zIndex;
219 if (enableSurfaceDebugInfo) {
220 if (_infoLayer == nil) {
221 _infoLayer = [[CATextLayer alloc] init];
222 [_containingLayer addSublayer:_infoLayer];
223 _infoLayer.fontSize = 15;
224 _infoLayer.foregroundColor = [NSColor yellowColor].CGColor;
225 _infoLayer.frame = CGRectMake(15, 15, 300, 100);
226 _infoLayer.contentsScale = _containingLayer.contentsScale;
227 _infoLayer.zPosition = 100000;
229 _infoLayer.string = [NSString stringWithFormat:@"Surface count: %li", _layers.count];
233static CGSize GetRequiredFrameSize(NSArray<FlutterSurfacePresentInfo*>* surfaces) {
234 CGSize
size = CGSizeZero;
243 atTime:(CFTimeInterval)presentationTime
244 notify:(dispatch_block_t)notify {
245 id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
246 [commandBuffer commit];
247 [commandBuffer waitUntilScheduled];
249 CGSize
size = GetRequiredFrameSize(surfaces);
251 CFTimeInterval delay = 0;
253 if (presentationTime > 0) {
265 CFTimeInterval minPresentationTime = (presentationTime + _lastPresentationTime) / 2.0;
266 CFTimeInterval now = CACurrentMediaTime();
267 delay = std::max(minPresentationTime - now, 0.0);
269 [_delegate onPresent:size
271 _lastPresentationTime = presentationTime;
272 [CATransaction begin];
273 [CATransaction setDisableActions:YES];
274 [
self commit:surfaces];
278 [CATransaction commit];
302- (instancetype)init {
303 if (
self = [super init]) {
304 self->_surfaces = [[NSMutableArray alloc] init];
305 self->_surfaceAge = [NSMapTable weakToStrongObjectsMapTable];
311 NSNumber* age = [_surfaceAge objectForKey:surface];
312 return age != nil ? age.intValue : 0;
316 [_surfaceAge setObject:@(age) forKey:surface];
320 @
synchronized(
self) {
322 if (_surfaces.firstObject != nil && !CGSizeEqualToSize(_surfaces.firstObject.size, size)) {
323 [_surfaces removeAllObjects];
333 (res == nil || [
self ageForSurface:res] > [
self ageForSurface:
surface])) {
338 [_surfaces removeObject:res];
344- (void)returnSurfaces:(nonnull NSArray<
FlutterSurface*>*)returnedSurfaces {
345 @
synchronized(
self) {
347 [
self setAge:0 forSurface:surface];
350 [
self setAge:[
self ageForSurface:surface] + 1 forSurface:surface];
353 [_surfaces addObjectsFromArray:returnedSurfaces];
360 [_surfaces filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(FlutterSurface* surface,
361 NSDictionary* bindings) {
362 return [
self ageForSurface:surface] < kSurfaceEvictionAge;
367 [
self performSelectorOnMainThread:@selector(reschedule) withObject:nil waitUntilDone:NO];
371 @
synchronized(
self) {
372 [_surfaces removeAllObjects];
377 @
synchronized(
self) {
378 return _surfaces.count;
387 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onIdle) object:nil];
388 [
self performSelector:@selector(onIdle) withObject:nil afterDelay:kIdleDelay];
392 [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