5 #import <Foundation/Foundation.h>
6 #import <Metal/Metal.h>
11 #include "flutter/display_list/display_list.h"
12 #include "flutter/display_list/dl_builder.h"
13 #import "flutter/display_list/skia/dl_sk_canvas.h"
14 #include "flutter/fml/synchronization/sync_switch.h"
15 #include "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h"
16 #import "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.h"
17 #import "flutter/shell/platform/darwin/graphics/FlutterDarwinExternalTextureMetal.h"
19 #include "flutter/shell/platform/embedder/embedder.h"
20 #include "flutter/shell/platform/embedder/embedder_external_texture_metal.h"
21 #include "flutter/testing/autoreleasepool_test.h"
22 #include "flutter/testing/testing.h"
23 #include "impeller/display_list/aiks_context.h"
24 #include "impeller/entity/mtl/entity_shaders.h"
25 #include "impeller/entity/mtl/framebuffer_blend_shaders.h"
26 #include "impeller/entity/mtl/modern_shaders.h"
27 #include "impeller/renderer/backend/metal/context_mtl.h"
28 #include "third_party/googletest/googletest/include/gtest/gtest.h"
29 #include "third_party/skia/include/core/SkImage.h"
30 #include "third_party/skia/include/core/SkSamplingOptions.h"
31 #include "third_party/skia/include/core/SkSurface.h"
32 #include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
35 std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
36 std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_data,
37 impeller_entity_shaders_length),
38 std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_data,
39 impeller_modern_shaders_length),
40 std::make_shared<fml::NonOwnedMapping>(impeller_framebuffer_blend_shaders_data,
41 impeller_framebuffer_blend_shaders_length),
43 auto sync_switch = std::make_shared<fml::SyncSwitch>(
false);
44 return impeller::ContextMTL::Create(shader_mappings, sync_switch,
"Impeller Library");
49 - (nonnull instancetype)initWidth:(
size_t)width
51 pixelFormatType:(OSType)pixelFormatType;
61 - (nonnull instancetype)initWidth:(
size_t)width
63 pixelFormatType:(OSType)pixelFormatType {
64 if (
self = [super init]) {
72 - (CVPixelBufferRef)copyPixelBuffer {
73 return [
self pixelBuffer];
76 - (CVPixelBufferRef)pixelBuffer {
77 NSDictionary* options = @{
79 (NSString*)kCVPixelBufferMetalCompatibilityKey : @YES
81 CVPixelBufferRef pxbuffer = NULL;
82 CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, _width, _width,
_pixelFormatType,
83 (__bridge CFDictionaryRef)options, &pxbuffer);
84 FML_CHECK(status == kCVReturnSuccess && pxbuffer !=
nullptr) <<
"Failed to create pixel buffer";
97 const size_t width = 100;
98 const size_t height = 100;
102 FlutterDarwinContextMetalSkia* darwinContextMetal =
103 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
104 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
105 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
106 sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
109 MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init];
110 textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm;
111 textureDescriptor.width = width;
112 textureDescriptor.height = height;
113 textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
114 id<MTLTexture> mtlTexture =
115 [darwinContextMetal.device newTextureWithDescriptor:textureDescriptor];
116 std::vector<FlutterMetalTextureHandle> textures = {
117 (__bridge FlutterMetalTextureHandle)mtlTexture,
121 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
123 EXPECT_TRUE(w == width);
124 EXPECT_TRUE(h == height);
126 auto texture = std::make_unique<FlutterMetalExternalTexture>();
127 texture->struct_size =
sizeof(FlutterMetalExternalTexture);
128 texture->num_textures = 1;
131 texture->pixel_format = FlutterMetalExternalTexturePixelFormat::kRGBA;
132 texture->textures = textures.data();
137 std::unique_ptr<flutter::Texture> texture =
138 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
139 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
140 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
141 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
142 flutter::Texture::PaintContext context{
144 .gr_context = grContext,
146 texture->Paint(context, bounds,
false, sampling);
148 ASSERT_TRUE(mtlTexture != nil);
150 gpuSurface->makeImageSnapshot();
155 const size_t width = 100;
156 const size_t height = 100;
160 FlutterDarwinContextMetalSkia* darwinContextMetal =
161 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
162 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
163 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
164 sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
170 pixelFormatType:kCVPixelFormatType_32BGRA];
173 darwinMetalContext:darwinContextMetal];
176 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
178 EXPECT_TRUE(w == width);
179 EXPECT_TRUE(h == height);
181 auto texture = std::make_unique<FlutterMetalExternalTexture>();
184 EXPECT_TRUE(texture->num_textures == 1);
185 EXPECT_TRUE(texture->textures !=
nullptr);
186 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kRGBA);
191 std::unique_ptr<flutter::Texture> texture =
192 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
193 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
194 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
195 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
196 flutter::Texture::PaintContext context{
198 .gr_context = grContext,
200 texture->Paint(context, bounds,
false, sampling);
202 gpuSurface->makeImageSnapshot();
207 const size_t width = 100;
208 const size_t height = 100;
212 FlutterDarwinContextMetalSkia* darwinContextMetal =
213 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
214 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
215 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
216 sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
222 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
225 darwinMetalContext:darwinContextMetal];
228 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
230 EXPECT_TRUE(w == width);
231 EXPECT_TRUE(h == height);
233 auto texture = std::make_unique<FlutterMetalExternalTexture>();
236 EXPECT_TRUE(texture->num_textures == 2);
237 EXPECT_TRUE(texture->textures !=
nullptr);
238 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kYUVA);
239 EXPECT_TRUE(texture->yuv_color_space ==
240 FlutterMetalExternalTextureYUVColorSpace::kBT601LimitedRange);
245 std::unique_ptr<flutter::Texture> texture =
246 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
247 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
248 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
249 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
250 flutter::Texture::PaintContext context{
252 .gr_context = grContext,
254 texture->Paint(context, bounds,
false, sampling);
256 gpuSurface->makeImageSnapshot();
261 const size_t width = 100;
262 const size_t height = 100;
266 FlutterDarwinContextMetalSkia* darwinContextMetal =
267 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
268 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
269 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
270 sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
276 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange];
279 darwinMetalContext:darwinContextMetal];
282 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
284 EXPECT_TRUE(w == width);
285 EXPECT_TRUE(h == height);
287 auto texture = std::make_unique<FlutterMetalExternalTexture>();
290 EXPECT_TRUE(texture->num_textures == 2);
291 EXPECT_TRUE(texture->textures !=
nullptr);
292 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kYUVA);
293 EXPECT_TRUE(texture->yuv_color_space ==
294 FlutterMetalExternalTextureYUVColorSpace::kBT601FullRange);
299 std::unique_ptr<flutter::Texture> texture =
300 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
301 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
302 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
303 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
304 flutter::Texture::PaintContext context{
306 .gr_context = grContext,
308 texture->Paint(context, bounds,
false, sampling);
310 gpuSurface->makeImageSnapshot();
315 const size_t width = 100;
316 const size_t height = 100;
320 FlutterDarwinContextMetalSkia* darwinContextMetal =
321 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
322 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
323 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
324 sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
330 pixelFormatType:kCVPixelFormatType_420YpCbCr8PlanarFullRange];
333 darwinMetalContext:darwinContextMetal];
336 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
338 EXPECT_TRUE(w == width);
339 EXPECT_TRUE(h == height);
341 auto texture = std::make_unique<FlutterMetalExternalTexture>();
342 EXPECT_FALSE([textureHolder populateTexture:texture.get()]);
347 std::unique_ptr<flutter::Texture> texture =
348 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
349 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
350 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
351 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
352 flutter::Texture::PaintContext context{
354 .gr_context = grContext,
356 texture->Paint(context, bounds,
false, sampling);
361 const size_t width = 100;
362 const size_t height = 100;
366 auto device = ::MTLCreateSystemDefaultDevice();
369 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
372 MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init];
373 textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm;
374 textureDescriptor.width = width;
375 textureDescriptor.height = height;
376 textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
377 id<MTLTexture> mtlTexture = [device newTextureWithDescriptor:textureDescriptor];
378 std::vector<FlutterMetalTextureHandle> textures = {
379 (__bridge FlutterMetalTextureHandle)mtlTexture,
383 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
385 EXPECT_TRUE(w == width);
386 EXPECT_TRUE(h == height);
388 auto texture = std::make_unique<FlutterMetalExternalTexture>();
389 texture->struct_size =
sizeof(FlutterMetalExternalTexture);
390 texture->num_textures = 1;
393 texture->pixel_format = FlutterMetalExternalTexturePixelFormat::kRGBA;
394 texture->textures = textures.data();
399 std::unique_ptr<flutter::Texture> texture =
400 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
401 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
402 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
404 DisplayListBuilder builder;
405 flutter::Texture::PaintContext context{
406 .canvas = &builder, .gr_context =
nullptr, .aiks_context = &aiks_context};
407 texture->Paint(context, bounds,
false, sampling);
409 ASSERT_TRUE(mtlTexture != nil);
414 const size_t width = 100;
415 const size_t height = 100;
419 FlutterDarwinContextMetalSkia* darwinContextMetal =
420 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
422 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
428 pixelFormatType:kCVPixelFormatType_32BGRA];
431 darwinMetalContext:darwinContextMetal];
434 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
436 EXPECT_TRUE(w == width);
437 EXPECT_TRUE(h == height);
439 auto texture = std::make_unique<FlutterMetalExternalTexture>();
442 EXPECT_TRUE(texture->num_textures == 1);
443 EXPECT_TRUE(texture->textures !=
nullptr);
444 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kRGBA);
449 std::unique_ptr<flutter::Texture> texture =
450 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
451 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
452 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
454 DisplayListBuilder builder;
455 flutter::Texture::PaintContext context{
457 .gr_context =
nullptr,
458 .aiks_context = &aiks_context,
460 texture->Paint(context, bounds,
false, sampling);
465 const size_t width = 100;
466 const size_t height = 100;
470 FlutterDarwinContextMetalSkia* darwinContextMetal =
471 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
473 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
479 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
482 darwinMetalContext:darwinContextMetal];
485 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
487 EXPECT_TRUE(w == width);
488 EXPECT_TRUE(h == height);
490 auto texture = std::make_unique<FlutterMetalExternalTexture>();
493 EXPECT_TRUE(texture->num_textures == 2);
494 EXPECT_TRUE(texture->textures !=
nullptr);
495 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kYUVA);
496 EXPECT_TRUE(texture->yuv_color_space ==
497 FlutterMetalExternalTextureYUVColorSpace::kBT601LimitedRange);
502 std::unique_ptr<flutter::Texture> texture =
503 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
504 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
505 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
507 DisplayListBuilder builder;
508 flutter::Texture::PaintContext context{
509 .canvas = &builder, .gr_context =
nullptr, .aiks_context = &aiks_context};
510 texture->Paint(context, bounds,
false, sampling);
515 const size_t width = 100;
516 const size_t height = 100;
520 FlutterDarwinContextMetalSkia* darwinContextMetal =
521 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
523 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
529 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange];
532 darwinMetalContext:darwinContextMetal];
535 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
537 EXPECT_TRUE(w == width);
538 EXPECT_TRUE(h == height);
540 auto texture = std::make_unique<FlutterMetalExternalTexture>();
543 EXPECT_TRUE(texture->num_textures == 2);
544 EXPECT_TRUE(texture->textures !=
nullptr);
545 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kYUVA);
546 EXPECT_TRUE(texture->yuv_color_space ==
547 FlutterMetalExternalTextureYUVColorSpace::kBT601FullRange);
552 std::unique_ptr<flutter::Texture> texture =
553 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
554 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
555 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
557 DisplayListBuilder builder;
558 flutter::Texture::PaintContext context{
559 .canvas = &builder, .gr_context =
nullptr, .aiks_context = &aiks_context};
560 texture->Paint(context, bounds,
false, sampling);
565 const size_t width = 100;
566 const size_t height = 100;
570 FlutterDarwinContextMetalSkia* darwinContextMetal =
571 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
573 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
579 pixelFormatType:kCVPixelFormatType_420YpCbCr8PlanarFullRange];
582 darwinMetalContext:darwinContextMetal];
585 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
587 EXPECT_TRUE(w == width);
588 EXPECT_TRUE(h == height);
590 auto texture = std::make_unique<FlutterMetalExternalTexture>();
591 EXPECT_FALSE([textureHolder populateTexture:texture.get()]);
596 std::unique_ptr<flutter::Texture> texture =
597 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
598 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
599 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
601 DisplayListBuilder builder;
602 flutter::Texture::PaintContext context{
603 .canvas = &builder, .gr_context =
nullptr, .aiks_context = &aiks_context};
604 texture->Paint(context, bounds,
false, sampling);