7 #import <Metal/Metal.h>
11 #include "flutter/fml/logging.h"
48 [NSColor yellowColor],
50 [NSColor magentaColor],
52 [NSColor purpleColor],
53 [NSColor orangeColor],
56 return colors[layer % colors.count];
66 const std::vector<FlutterRect>& paintRegion) {
68 while (layer.sublayers.count > paintRegion.size()) {
69 [layer.sublayers.lastObject removeFromSuperlayer];
72 while (layer.sublayers.count < paintRegion.size()) {
73 CALayer* newLayer = [CALayer layer];
74 [layer addSublayer:newLayer];
77 for (
size_t i = 0; i < paintRegion.size(); i++) {
78 CALayer* subLayer = [layer.sublayers objectAtIndex:i];
79 const auto& rect = paintRegion[i];
80 subLayer.frame = CGRectMake(rect.left / scale, rect.top / scale,
81 (rect.right - rect.left) / scale, (rect.bottom - rect.top) / scale);
83 double width = surfaceSize.width;
84 double height = surfaceSize.height;
86 subLayer.contentsRect =
87 CGRectMake(rect.left / width, rect.top / height, (rect.right - rect.left) / width,
88 (rect.bottom - rect.top) / height);
90 if (borderColor != nil) {
92 subLayer.borderColor = borderColor.CGColor;
93 subLayer.borderWidth = 1.0;
96 subLayer.contents = (__bridge id)surface;
102 - (instancetype)initWithDevice:(
id<MTLDevice>)device
103 commandQueue:(
id<MTLCommandQueue>)commandQueue
104 layer:(CALayer*)containingLayer
106 if (
self = [super init]) {
108 _commandQueue = commandQueue;
109 _containingLayer = containingLayer;
110 _delegate = delegate;
113 _frontSurfaces = [NSMutableArray array];
114 _layers = [NSMutableArray array];
120 return _backBufferCache;
124 return _frontSurfaces;
132 FlutterSurface* surface = [_backBufferCache removeSurfaceForSize:size];
133 if (surface == nil) {
134 surface = [[
FlutterSurface alloc] initWithSize:size device:_device];
139 - (BOOL)enableSurfaceDebugInfo {
140 if (_enableSurfaceDebugInfo == nil) {
141 _enableSurfaceDebugInfo =
142 [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTEnableSurfaceDebugInfo"];
143 if (_enableSurfaceDebugInfo == nil) {
144 _enableSurfaceDebugInfo = @NO;
147 return [_enableSurfaceDebugInfo boolValue];
151 FML_DCHECK([NSThread isMainThread]);
154 [_backBufferCache replaceSurfaces:_frontSurfaces];
157 [_frontSurfaces removeAllObjects];
159 [_frontSurfaces addObject:info.surface];
163 while (_layers.count > _frontSurfaces.count) {
164 [_layers.lastObject removeFromSuperlayer];
165 [_layers removeLastObject];
167 while (_layers.count < _frontSurfaces.count) {
168 CALayer* layer = [CALayer layer];
169 [_containingLayer addSublayer:layer];
170 [_layers addObject:layer];
173 bool enableSurfaceDebugInfo =
self.enableSurfaceDebugInfo;
176 for (
size_t i = 0; i < surfaces.count; ++i) {
178 CALayer* layer = _layers[i];
179 CGFloat scale = _containingLayer.contentsScale;
181 layer.frame = CGRectMake(info.
offset.x / scale, info.
offset.y / scale,
185 layer.frame = CGRectZero;
190 layer.zPosition = info.
zIndex;
193 if (enableSurfaceDebugInfo) {
194 if (_infoLayer == nil) {
195 _infoLayer = [[CATextLayer alloc] init];
196 [_containingLayer addSublayer:_infoLayer];
197 _infoLayer.fontSize = 15;
198 _infoLayer.foregroundColor = [NSColor yellowColor].CGColor;
199 _infoLayer.frame = CGRectMake(15, 15, 300, 100);
200 _infoLayer.contentsScale = _containingLayer.contentsScale;
201 _infoLayer.zPosition = 100000;
203 _infoLayer.string = [NSString stringWithFormat:@"Surface count: %li", _layers.count];
207 static CGSize GetRequiredFrameSize(NSArray<FlutterSurfacePresentInfo*>* surfaces) {
208 CGSize size = CGSizeZero;
217 id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
218 [commandBuffer commit];
219 [commandBuffer waitUntilScheduled];
222 CGSize size = GetRequiredFrameSize(surfaces);
224 [_delegate onPresent:size
226 [
self commit:surfaces];
246 - (instancetype)init {
247 if (
self = [super init]) {
248 self->_surfaces = [[NSMutableArray alloc] init];
254 @
synchronized(
self) {
256 if (CGSizeEqualToSize(surface.
size, size)) {
259 [_surfaces removeObject:surface];
268 @
synchronized(
self) {
269 [_surfaces removeAllObjects];
270 [_surfaces addObjectsFromArray:surfaces];
274 [
self performSelectorOnMainThread:@selector(reschedule) withObject:nil waitUntilDone:NO];
278 @
synchronized(
self) {
279 return _surfaces.count;
284 @
synchronized(
self) {
285 [_surfaces removeAllObjects];
290 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onIdle) object:nil];
291 [
self performSelector:@selector(onIdle) withObject:nil afterDelay:kIdleDelay];
295 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onIdle) object:nil];