5 #import <Cocoa/Cocoa.h>
6 #import <Metal/Metal.h>
11 #include "flutter/testing/testing.h"
12 #include "gtest/gtest.h"
17 - (nonnull instancetype)
init;
23 - (instancetype)
init {
24 self = [
super initWithFrame:NSZeroRect];
26 [
self setWantsLayer:YES];
27 self.layer.contentsScale = 2.0;
32 - (void)onPresent:(CGSize)frameSize
33 withBlock:(nonnull dispatch_block_t)block
34 delay:(NSTimeInterval)delay {
35 self.presentedFrameSize = frameSize;
44 id<MTLDevice> device = MTLCreateSystemDefaultDevice();
45 id<MTLCommandQueue> commandQueue = [device newCommandQueue];
46 CALayer* layer =
reinterpret_cast<CALayer*
>(testView.layer);
48 commandQueue:commandQueue
51 wideGamut:enableWideGamut];
56 CGPoint offset = CGPointZero,
58 const std::vector<FlutterRect>& paintRegion = {}) {
72 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
74 id<MTLTexture> metalTexture = (__bridge id)texture.texture;
75 EXPECT_EQ(metalTexture.width, 100ul);
76 EXPECT_EQ(metalTexture.height, 50ul);
77 texture.destruction_callback(texture.user_data);
85 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
89 texture.destruction_callback(texture.user_data);
91 FlutterMetalTexture dummyTexture{.texture_id = 1, .texture =
nullptr, .user_data =
nullptr};
93 EXPECT_EQ(surface1, nil);
96 EXPECT_EQ(surface2, surface);
104 auto surface1 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
109 auto surface2 = [surfaceManager
surfaceForSize:CGSizeMake(110, 110)];
114 auto surface3 = [surfaceManager
surfaceForSize:CGSizeMake(120, 120)];
120 auto surfaceFromCache = [surfaceManager
surfaceForSize:CGSizeMake(110, 110)];
121 EXPECT_EQ(surfaceFromCache, surface2);
126 for (
int i = 0; i < 30 ; ++i) {
143 auto surface1 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
144 EXPECT_TRUE(CGSizeEqualToSize(surface1.size, CGSizeMake(100, 100)));
153 EXPECT_EQ(testView.layer.sublayers.count, 1ul);
157 auto surface2 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
158 EXPECT_TRUE(CGSizeEqualToSize(surface2.size, CGSizeMake(100, 100)));
167 EXPECT_EQ(testView.layer.sublayers.count, 1ull);
170 auto surface3 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
171 EXPECT_EQ(surface3, surface1);
178 auto surface1 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
183 surface1.isInUseOverride = YES;
185 auto surface2 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
189 for (
int i = 0; i < 30 - 1; ++i) {
190 auto surface3 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
195 auto surface4 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
201 inline bool operator==(
const CGRect& lhs,
const CGRect& rhs) {
202 return CGRectEqualToRect(lhs, rhs);
209 EXPECT_EQ(testView.layer.sublayers.count, 0ul);
211 auto surface1_1 = [surfaceManager
surfaceForSize:CGSizeMake(50, 30)];
212 [surfaceManager
presentSurfaces:@[ CreatePresentInfo(surface1_1, CGPointMake(20, 10)) ]
216 EXPECT_EQ(testView.layer.sublayers.count, 1ul);
219 auto surface2_1 = [surfaceManager
surfaceForSize:CGSizeMake(50, 30)];
220 auto surface2_2 = [surfaceManager
surfaceForSize:CGSizeMake(20, 20)];
222 CreatePresentInfo(surface2_1, CGPointMake(20, 10), 1),
223 CreatePresentInfo(surface2_2, CGPointMake(40, 50), 2,
225 FlutterRect{0, 0, 20, 20},
226 FlutterRect{40, 0, 60, 20},
232 EXPECT_EQ(testView.layer.sublayers.count, 2ul);
233 EXPECT_EQ(testView.layer.sublayers[0].zPosition, 1.0);
234 EXPECT_EQ(testView.layer.sublayers[1].zPosition, 2.0);
235 CALayer* firstOverlaySublayer;
237 NSArray<CALayer*>* sublayers = testView.layer.sublayers[1].sublayers;
238 EXPECT_EQ(sublayers.count, 2ul);
239 EXPECT_TRUE(CGRectEqualToRect(sublayers[0].frame, CGRectMake(0, 0, 10, 10)));
240 EXPECT_TRUE(CGRectEqualToRect(sublayers[1].frame, CGRectMake(20, 0, 10, 10)));
241 EXPECT_TRUE(CGRectEqualToRect(sublayers[0].contentsRect, CGRectMake(0, 0, 1, 1)));
242 EXPECT_TRUE(CGRectEqualToRect(sublayers[1].contentsRect, CGRectMake(2, 0, 1, 1)));
243 EXPECT_EQ(sublayers[0].contents, sublayers[1].contents);
244 firstOverlaySublayer = sublayers[0];
250 CreatePresentInfo(surface2_1, CGPointMake(20, 10), 1),
251 CreatePresentInfo(surface2_2, CGPointMake(40, 50), 2,
253 FlutterRect{0, 10, 20, 20},
258 EXPECT_EQ(testView.layer.sublayers.count, 2ul);
260 NSArray<CALayer*>* sublayers = testView.layer.sublayers[1].sublayers;
261 EXPECT_EQ(sublayers.count, 1ul);
262 EXPECT_EQ(sublayers[0], firstOverlaySublayer);
263 EXPECT_TRUE(CGRectEqualToRect(sublayers[0].frame, CGRectMake(0, 5, 10, 5)));
268 CreatePresentInfo(surface2_1, CGPointMake(20, 10), 1),
269 CreatePresentInfo(surface2_2, CGPointMake(40, 50), 2,
271 FlutterRect{0, 0, 20, 20},
272 FlutterRect{40, 0, 60, 20},
278 EXPECT_EQ(testView.layer.sublayers.count, 2ul);
280 NSArray<CALayer*>* sublayers = testView.layer.sublayers[1].sublayers;
281 EXPECT_EQ(sublayers.count, 2ul);
282 EXPECT_EQ(sublayers[0], firstOverlaySublayer);
283 EXPECT_TRUE(CGRectEqualToRect(sublayers[0].frame, CGRectMake(0, 0, 10, 10)));
284 EXPECT_TRUE(CGRectEqualToRect(sublayers[1].frame, CGRectMake(20, 0, 10, 10)));
285 EXPECT_EQ(sublayers[0].contents, sublayers[1].contents);
288 auto surface3_1 = [surfaceManager
surfaceForSize:CGSizeMake(50, 30)];
289 [surfaceManager
presentSurfaces:@[ CreatePresentInfo(surface3_1, CGPointMake(20, 10)) ]
293 EXPECT_EQ(testView.layer.sublayers.count, 1ul);
298 EXPECT_EQ(testView.layer.sublayers.count, 0ul);
306 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
308 id<MTLTexture> metalTexture = (__bridge id)texture.texture;
309 EXPECT_EQ(metalTexture.pixelFormat, MTLPixelFormatBGRA10_XR);
310 texture.destruction_callback(texture.user_data);
317 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
319 id<MTLTexture> metalTexture = (__bridge id)texture.texture;
320 EXPECT_EQ(metalTexture.pixelFormat, MTLPixelFormatBGRA8Unorm);
321 texture.destruction_callback(texture.user_data);
328 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(50, 30)];
329 [surfaceManager
presentSurfaces:@[ CreatePresentInfo(surface, CGPointMake(0, 0)) ]
333 EXPECT_EQ(testView.layer.sublayers.count, 1ul);
334 EXPECT_NE(testView.layer.sublayers[0].contents, nil);
341 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
342 IOSurfaceRef ioSurface = surface.
ioSurface;
343 CFTypeRef colorSpace = IOSurfaceCopyValue(ioSurface, kIOSurfaceColorSpace);
344 if (colorSpace ==
nullptr) {
345 GTEST_FAIL() <<
"IOSurfaceCopyValue returned nullptr for kIOSurfaceColorSpace";
348 EXPECT_TRUE(CFEqual(colorSpace, kCGColorSpaceExtendedSRGB));
349 CFRelease(colorSpace);
356 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
357 IOSurfaceRef ioSurface = surface.
ioSurface;
358 CFTypeRef colorSpace = IOSurfaceCopyValue(ioSurface, kIOSurfaceColorSpace);
359 if (colorSpace ==
nullptr) {
360 GTEST_FAIL() <<
"IOSurfaceCopyValue returned nullptr for kIOSurfaceColorSpace";
363 EXPECT_TRUE(CFEqual(colorSpace, kCGColorSpaceSRGB));
364 CFRelease(colorSpace);
371 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
372 IOSurfaceRef ioSurface = surface.
ioSurface;
373 uint32_t pixelFormat = (uint32_t)IOSurfaceGetPixelFormat(ioSurface);
374 EXPECT_EQ(pixelFormat, (uint32_t)kCVPixelFormatType_40ARGBLEWideGamut);
381 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
382 IOSurfaceRef ioSurface = surface.
ioSurface;
383 uint32_t pixelFormat = (uint32_t)IOSurfaceGetPixelFormat(ioSurface);
384 EXPECT_EQ(pixelFormat, (uint32_t)kCVPixelFormatType_32BGRA);
391 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
392 IOSurfaceRef ioSurface = surface.
ioSurface;
393 size_t bytesPerElement = IOSurfaceGetBytesPerElement(ioSurface);
394 EXPECT_EQ(bytesPerElement, 8ul);
401 auto surface = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
402 IOSurfaceRef ioSurface = surface.
ioSurface;
403 size_t bytesPerElement = IOSurfaceGetBytesPerElement(ioSurface);
404 EXPECT_EQ(bytesPerElement, 4ul);
412 auto wideSurface = [wideManager
surfaceForSize:CGSizeMake(100, 100)];
413 auto wideTexture = wideSurface.asFlutterMetalTexture;
414 id<MTLTexture> wideMetalTexture = (__bridge id)wideTexture.texture;
415 EXPECT_EQ(wideMetalTexture.pixelFormat, MTLPixelFormatBGRA10_XR);
419 wideTexture.destruction_callback(wideTexture.user_data);
422 auto recycledSurface = [wideManager
surfaceForSize:CGSizeMake(100, 100)];
423 auto recycledTexture = recycledSurface.asFlutterMetalTexture;
424 id<MTLTexture> recycledMetalTexture = (__bridge id)recycledTexture.texture;
425 EXPECT_EQ(recycledMetalTexture.pixelFormat, MTLPixelFormatBGRA10_XR);
426 recycledTexture.destruction_callback(recycledTexture.user_data);
434 auto surface1 = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
435 auto texture1 = surface1.asFlutterMetalTexture;
436 id<MTLTexture> metalTexture1 = (__bridge id)texture1.texture;
437 EXPECT_EQ(metalTexture1.pixelFormat, MTLPixelFormatBGRA8Unorm);
439 texture1.destruction_callback(texture1.user_data);
448 auto surface2 = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
449 auto texture2 = surface2.asFlutterMetalTexture;
450 id<MTLTexture> metalTexture2 = (__bridge id)texture2.texture;
451 EXPECT_EQ(metalTexture2.pixelFormat, MTLPixelFormatBGRA10_XR);
452 texture2.destruction_callback(texture2.user_data);
460 auto surface1 = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
461 auto texture1 = surface1.asFlutterMetalTexture;
462 id<MTLTexture> metalTexture1 = (__bridge id)texture1.texture;
463 EXPECT_EQ(metalTexture1.pixelFormat, MTLPixelFormatBGRA10_XR);
465 texture1.destruction_callback(texture1.user_data);
474 auto surface2 = [surfaceManager
surfaceForSize:CGSizeMake(100, 50)];
475 auto texture2 = surface2.asFlutterMetalTexture;
476 id<MTLTexture> metalTexture2 = (__bridge id)texture2.texture;
477 EXPECT_EQ(metalTexture2.pixelFormat, MTLPixelFormatBGRA8Unorm);
478 texture2.destruction_callback(texture2.user_data);
486 auto surface1 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
489 auto surface2 = [surfaceManager
surfaceForSize:CGSizeMake(100, 100)];
FlutterMetalTexture asFlutterMetalTexture()
nullable FlutterSurface * fromFlutterMetalTexture:(nonnull const FlutterMetalTexture *texture)
void setEnableWideGamut:(BOOL enableWideGamut)
nonnull FlutterSurface * surfaceForSize:(CGSize size)
FlutterBackBufferCache * backBufferCache
void presentSurfaces:atTime:notify:(nonnull NSArray< FlutterSurfacePresentInfo * > *surfaces,[atTime] CFTimeInterval presentationTime,[notify] nullable dispatch_block_t notify)
NSArray< FlutterSurface * > * frontSurfaces
std::vector< FlutterRect > paintRegion
CGSize presentedFrameSize
nonnull instancetype init()
TEST(FlutterSurfaceManager, DynamicSwitchNoOpWhenSameValue)
bool operator==(const CGRect &lhs, const CGRect &rhs)
static FlutterSurfacePresentInfo * CreatePresentInfo(FlutterSurface *surface, CGPoint offset=CGPointZero, size_t index=0, const std::vector< FlutterRect > &paintRegion={})
static FlutterSurfaceManager * CreateSurfaceManager(TestView *testView, BOOL enableWideGamut=NO)