| Flutter macOS Embedder |

FlutterEmbedderExternalTextureTest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <Foundation/Foundation.h>
6 #import <Metal/Metal.h>
7
8 #include <memory>
9 #include <vector>
10
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"
18 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTexture.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" // nogncheck
24 #include "impeller/entity/mtl/entity_shaders.h" // nogncheck
25 #include "impeller/entity/mtl/framebuffer_blend_shaders.h" // nogncheck
26 #include "impeller/entity/mtl/modern_shaders.h" // nogncheck
27 #include "impeller/renderer/backend/metal/context_mtl.h" // nogncheck
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"
33
34 static std::shared_ptr<impeller::ContextMTL> CreateImpellerContext() {
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),
42 };
43 auto sync_switch = std::make_shared<fml::SyncSwitch>(false);
44 return impeller::ContextMTL::Create(shader_mappings, sync_switch, "Impeller Library");
45 }
46
47 @interface TestExternalTexture : NSObject <FlutterTexture>
48
49 - (nonnull instancetype)initWidth:(size_t)width
50 height:(size_t)height
51 pixelFormatType:(OSType)pixelFormatType;
52
53 @end
54
55 @implementation TestExternalTexture {
56 size_t _width;
57 size_t _height;
58 OSType _pixelFormatType;
59 }
60
61 - (nonnull instancetype)initWidth:(size_t)width
62 height:(size_t)height
63 pixelFormatType:(OSType)pixelFormatType {
64 if (self = [super init]) {
65 _width = width;
66 _height = height;
67 _pixelFormatType = pixelFormatType;
68 }
69 return self;
70 }
71
72 - (CVPixelBufferRef)copyPixelBuffer {
73 return [self pixelBuffer];
74 }
75
76 - (CVPixelBufferRef)pixelBuffer {
77 NSDictionary* options = @{
78 // This key is required to generate SKPicture with CVPixelBufferRef in metal.
79 (NSString*)kCVPixelBufferMetalCompatibilityKey : @YES
80 };
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";
85 return pxbuffer;
86 }
87
88 @end
89
90 namespace flutter::testing {
91
92 // Test-specific name for AutoreleasePoolTest fixture.
93 using FlutterEmbedderExternalTextureTest = AutoreleasePoolTest;
94
95 TEST_F(FlutterEmbedderExternalTextureTest, TestTextureResolution) {
96 // Constants.
97 const size_t width = 100;
98 const size_t height = 100;
99 const int64_t texture_id = 1;
100
101 // Set up the surface.
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));
107
108 // Create a texture.
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,
118 };
119
120 // Callback to resolve the texture.
121 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
122 size_t h) {
123 EXPECT_TRUE(w == width);
124 EXPECT_TRUE(h == height);
125
126 auto texture = std::make_unique<FlutterMetalExternalTexture>();
127 texture->struct_size = sizeof(FlutterMetalExternalTexture);
128 texture->num_textures = 1;
129 texture->height = h;
130 texture->width = w;
131 texture->pixel_format = FlutterMetalExternalTexturePixelFormat::kRGBA;
132 texture->textures = textures.data();
133 return texture;
134 };
135
136 // Render the texture.
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{
143 .canvas = &canvas,
144 .gr_context = grContext,
145 };
146 texture->Paint(context, bounds, /*freeze=*/false, sampling);
147
148 ASSERT_TRUE(mtlTexture != nil);
149
150 gpuSurface->makeImageSnapshot();
151 }
152
153 TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateExternalTexture) {
154 // Constants.
155 const size_t width = 100;
156 const size_t height = 100;
157 const int64_t texture_id = 1;
158
159 // Set up the surface.
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));
165
166 // Create a texture.
167 TestExternalTexture* testExternalTexture =
168 [[TestExternalTexture alloc] initWidth:width
169 height:height
170 pixelFormatType:kCVPixelFormatType_32BGRA];
171 FlutterExternalTexture* textureHolder =
172 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
173 darwinMetalContext:darwinContextMetal];
174
175 // Callback to resolve the texture.
176 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
177 size_t h) {
178 EXPECT_TRUE(w == width);
179 EXPECT_TRUE(h == height);
180
181 auto texture = std::make_unique<FlutterMetalExternalTexture>();
182 [textureHolder populateTexture:texture.get()];
183
184 EXPECT_TRUE(texture->num_textures == 1);
185 EXPECT_TRUE(texture->textures != nullptr);
186 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kRGBA);
187 return texture;
188 };
189
190 // Render the texture.
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{
197 .canvas = &canvas,
198 .gr_context = grContext,
199 };
200 texture->Paint(context, bounds, /*freeze=*/false, sampling);
201
202 gpuSurface->makeImageSnapshot();
203 }
204
205 TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateExternalTextureYUVA) {
206 // Constants.
207 const size_t width = 100;
208 const size_t height = 100;
209 const int64_t texture_id = 1;
210
211 // Set up the surface.
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));
217
218 // Create a texture.
219 TestExternalTexture* testExternalTexture =
220 [[TestExternalTexture alloc] initWidth:width
221 height:height
222 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
223 FlutterExternalTexture* textureHolder =
224 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
225 darwinMetalContext:darwinContextMetal];
226
227 // Callback to resolve the texture.
228 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
229 size_t h) {
230 EXPECT_TRUE(w == width);
231 EXPECT_TRUE(h == height);
232
233 auto texture = std::make_unique<FlutterMetalExternalTexture>();
234 [textureHolder populateTexture:texture.get()];
235
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);
241 return texture;
242 };
243
244 // Render the texture.
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{
251 .canvas = &canvas,
252 .gr_context = grContext,
253 };
254 texture->Paint(context, bounds, /*freeze=*/false, sampling);
255
256 gpuSurface->makeImageSnapshot();
257 }
258
259 TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateExternalTextureYUVA2) {
260 // Constants.
261 const size_t width = 100;
262 const size_t height = 100;
263 const int64_t texture_id = 1;
264
265 // Set up the surface.
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));
271
272 // Create a texture.
273 TestExternalTexture* testExternalTexture =
274 [[TestExternalTexture alloc] initWidth:width
275 height:height
276 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange];
277 FlutterExternalTexture* textureHolder =
278 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
279 darwinMetalContext:darwinContextMetal];
280
281 // Callback to resolve the texture.
282 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
283 size_t h) {
284 EXPECT_TRUE(w == width);
285 EXPECT_TRUE(h == height);
286
287 auto texture = std::make_unique<FlutterMetalExternalTexture>();
288 [textureHolder populateTexture:texture.get()];
289
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);
295 return texture;
296 };
297
298 // Render the texture.
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{
305 .canvas = &canvas,
306 .gr_context = grContext,
307 };
308 texture->Paint(context, bounds, /*freeze=*/false, sampling);
309
310 gpuSurface->makeImageSnapshot();
311 }
312
313 TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateUnsupportedExternalTexture) {
314 // Constants.
315 const size_t width = 100;
316 const size_t height = 100;
317 const int64_t texture_id = 1;
318
319 // Set up the surface.
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));
325
326 // Create a texture.
327 TestExternalTexture* testExternalTexture =
328 [[TestExternalTexture alloc] initWidth:width
329 height:height
330 pixelFormatType:kCVPixelFormatType_420YpCbCr8PlanarFullRange];
331 FlutterExternalTexture* textureHolder =
332 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
333 darwinMetalContext:darwinContextMetal];
334
335 // Callback to resolve the texture.
336 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
337 size_t h) {
338 EXPECT_TRUE(w == width);
339 EXPECT_TRUE(h == height);
340
341 auto texture = std::make_unique<FlutterMetalExternalTexture>();
342 EXPECT_FALSE([textureHolder populateTexture:texture.get()]);
343 return nullptr;
344 };
345
346 // Render the texture.
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{
353 .canvas = &canvas,
354 .gr_context = grContext,
355 };
356 texture->Paint(context, bounds, /*freeze=*/false, sampling);
357 }
358
359 TEST_F(FlutterEmbedderExternalTextureTest, TestTextureResolutionImpeller) {
360 // Constants.
361 const size_t width = 100;
362 const size_t height = 100;
363 const int64_t texture_id = 1;
364
365 // Set up the surface.
366 auto device = ::MTLCreateSystemDefaultDevice();
367 impeller::AiksContext aiks_context(CreateImpellerContext(), nullptr);
368
369 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
370
371 // Create a texture.
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,
380 };
381
382 // Callback to resolve the texture.
383 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
384 size_t h) {
385 EXPECT_TRUE(w == width);
386 EXPECT_TRUE(h == height);
387
388 auto texture = std::make_unique<FlutterMetalExternalTexture>();
389 texture->struct_size = sizeof(FlutterMetalExternalTexture);
390 texture->num_textures = 1;
391 texture->height = h;
392 texture->width = w;
393 texture->pixel_format = FlutterMetalExternalTexturePixelFormat::kRGBA;
394 texture->textures = textures.data();
395 return texture;
396 };
397
398 // Render the texture.
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;
403
404 DisplayListBuilder builder;
405 flutter::Texture::PaintContext context{
406 .canvas = &builder, .gr_context = nullptr, .aiks_context = &aiks_context};
407 texture->Paint(context, bounds, /*freeze=*/false, sampling);
408
409 ASSERT_TRUE(mtlTexture != nil);
410 }
411
412 TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateExternalTextureImpeller) {
413 // Constants.
414 const size_t width = 100;
415 const size_t height = 100;
416 const int64_t texture_id = 1;
417
418 // Set up the surface.
419 FlutterDarwinContextMetalSkia* darwinContextMetal =
420 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
421 impeller::AiksContext aiks_context(CreateImpellerContext(), nullptr);
422 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
423
424 // Create a texture.
425 TestExternalTexture* testExternalTexture =
426 [[TestExternalTexture alloc] initWidth:width
427 height:height
428 pixelFormatType:kCVPixelFormatType_32BGRA];
429 FlutterExternalTexture* textureHolder =
430 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
431 darwinMetalContext:darwinContextMetal];
432
433 // Callback to resolve the texture.
434 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
435 size_t h) {
436 EXPECT_TRUE(w == width);
437 EXPECT_TRUE(h == height);
438
439 auto texture = std::make_unique<FlutterMetalExternalTexture>();
440 [textureHolder populateTexture:texture.get()];
441
442 EXPECT_TRUE(texture->num_textures == 1);
443 EXPECT_TRUE(texture->textures != nullptr);
444 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kRGBA);
445 return texture;
446 };
447
448 // Render the texture.
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;
453
454 DisplayListBuilder builder;
455 flutter::Texture::PaintContext context{
456 .canvas = &builder,
457 .gr_context = nullptr,
458 .aiks_context = &aiks_context,
459 };
460 texture->Paint(context, bounds, /*freeze=*/false, sampling);
461 }
462
463 TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateExternalTextureYUVAImpeller) {
464 // Constants.
465 const size_t width = 100;
466 const size_t height = 100;
467 const int64_t texture_id = 1;
468
469 // Set up the surface.
470 FlutterDarwinContextMetalSkia* darwinContextMetal =
471 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
472 impeller::AiksContext aiks_context(CreateImpellerContext(), nullptr);
473 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
474
475 // Create a texture.
476 TestExternalTexture* testExternalTexture =
477 [[TestExternalTexture alloc] initWidth:width
478 height:height
479 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
480 FlutterExternalTexture* textureHolder =
481 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
482 darwinMetalContext:darwinContextMetal];
483
484 // Callback to resolve the texture.
485 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
486 size_t h) {
487 EXPECT_TRUE(w == width);
488 EXPECT_TRUE(h == height);
489
490 auto texture = std::make_unique<FlutterMetalExternalTexture>();
491 [textureHolder populateTexture:texture.get()];
492
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);
498 return texture;
499 };
500
501 // Render the texture.
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;
506
507 DisplayListBuilder builder;
508 flutter::Texture::PaintContext context{
509 .canvas = &builder, .gr_context = nullptr, .aiks_context = &aiks_context};
510 texture->Paint(context, bounds, /*freeze=*/false, sampling);
511 }
512
513 TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateExternalTextureYUVA2Impeller) {
514 // Constants.
515 const size_t width = 100;
516 const size_t height = 100;
517 const int64_t texture_id = 1;
518
519 // Set up the surface.
520 FlutterDarwinContextMetalSkia* darwinContextMetal =
521 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
522 impeller::AiksContext aiks_context(CreateImpellerContext(), nullptr);
523 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
524
525 // Create a texture.
526 TestExternalTexture* testExternalTexture =
527 [[TestExternalTexture alloc] initWidth:width
528 height:height
529 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange];
530 FlutterExternalTexture* textureHolder =
531 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
532 darwinMetalContext:darwinContextMetal];
533
534 // Callback to resolve the texture.
535 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
536 size_t h) {
537 EXPECT_TRUE(w == width);
538 EXPECT_TRUE(h == height);
539
540 auto texture = std::make_unique<FlutterMetalExternalTexture>();
541 [textureHolder populateTexture:texture.get()];
542
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);
548 return texture;
549 };
550
551 // Render the texture.
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;
556
557 DisplayListBuilder builder;
558 flutter::Texture::PaintContext context{
559 .canvas = &builder, .gr_context = nullptr, .aiks_context = &aiks_context};
560 texture->Paint(context, bounds, /*freeze=*/false, sampling);
561 }
562
563 TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateUnsupportedExternalTextureImpeller) {
564 // Constants.
565 const size_t width = 100;
566 const size_t height = 100;
567 const int64_t texture_id = 1;
568
569 // Set up the surface.
570 FlutterDarwinContextMetalSkia* darwinContextMetal =
571 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
572 impeller::AiksContext aiks_context(CreateImpellerContext(), nullptr);
573 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
574
575 // Create a texture.
576 TestExternalTexture* testExternalTexture =
577 [[TestExternalTexture alloc] initWidth:width
578 height:height
579 pixelFormatType:kCVPixelFormatType_420YpCbCr8PlanarFullRange];
580 FlutterExternalTexture* textureHolder =
581 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
582 darwinMetalContext:darwinContextMetal];
583
584 // Callback to resolve the texture.
585 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
586 size_t h) {
587 EXPECT_TRUE(w == width);
588 EXPECT_TRUE(h == height);
589
590 auto texture = std::make_unique<FlutterMetalExternalTexture>();
591 EXPECT_FALSE([textureHolder populateTexture:texture.get()]);
592 return nullptr;
593 };
594
595 // Render the texture.
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;
600
601 DisplayListBuilder builder;
602 flutter::Texture::PaintContext context{
603 .canvas = &builder, .gr_context = nullptr, .aiks_context = &aiks_context};
604 texture->Paint(context, bounds, /*freeze=*/false, sampling);
605 }
606
607 } // namespace flutter::testing
_pixelFormatType
OSType _pixelFormatType
Definition: FlutterEmbedderExternalTextureTest.mm:58
flutter::testing
Definition: AccessibilityBridgeMacTest.mm:13
_height
size_t _height
Definition: FlutterEmbedderExternalTextureTest.mm:55
FlutterExternalTexture.h
CreateImpellerContext
static std::shared_ptr< impeller::ContextMTL > CreateImpellerContext()
Definition: FlutterEmbedderExternalTextureTest.mm:34
FlutterExternalTexture
Definition: FlutterExternalTexture.h:18
TestExternalTexture
Definition: FlutterEmbedderExternalTextureTest.mm:47
FlutterTexture-p
Definition: FlutterTexture.h:21
flutter::testing::TEST_F
TEST_F(AccessibilityBridgeMacWindowTest, SendsAccessibilityCreateNotificationFlutterViewWindow)
Definition: AccessibilityBridgeMacTest.mm:90
texture_id
int64_t texture_id
Definition: texture_registrar_unittests.cc:24
flutter::testing::FlutterEmbedderExternalTextureTest
AutoreleasePoolTest FlutterEmbedderExternalTextureTest
Definition: FlutterEmbedderExternalTextureTest.mm:93
-[FlutterExternalTexture populateTexture:]
BOOL populateTexture:(nonnull FlutterMetalExternalTexture *metalTexture)