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"
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;
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)