5 #import <Foundation/Foundation.h>
6 #import <Metal/Metal.h>
11 #import "flutter/display_list/skia/dl_sk_canvas.h"
12 #import "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.h"
13 #import "flutter/shell/platform/darwin/graphics/FlutterDarwinExternalTextureMetal.h"
15 #include "flutter/shell/platform/embedder/embedder.h"
16 #include "flutter/shell/platform/embedder/embedder_external_texture_metal.h"
17 #import "flutter/testing/testing.h"
18 #include "third_party/googletest/googletest/include/gtest/gtest.h"
19 #include "third_party/skia/include/core/SkImage.h"
20 #include "third_party/skia/include/core/SkSamplingOptions.h"
21 #include "third_party/skia/include/core/SkSurface.h"
22 #include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
26 - (nonnull instancetype)initWidth:(
size_t)width
28 pixelFormatType:(OSType)pixelFormatType;
38 - (nonnull instancetype)initWidth:(
size_t)width
40 pixelFormatType:(OSType)pixelFormatType {
41 if (
self = [super init]) {
49 - (CVPixelBufferRef)copyPixelBuffer {
50 return [
self pixelBuffer];
53 - (CVPixelBufferRef)pixelBuffer {
54 NSDictionary* options = @{
56 (NSString*)kCVPixelBufferMetalCompatibilityKey : @YES
58 CVPixelBufferRef pxbuffer = NULL;
59 CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, _width, _width,
_pixelFormatType,
60 (__bridge CFDictionaryRef)options, &pxbuffer);
61 NSAssert(status == kCVReturnSuccess && pxbuffer != NULL,
@"Failed to create pixel buffer.");
69 TEST(FlutterEmbedderExternalTextureUnittests, TestTextureResolution) {
71 const size_t width = 100;
72 const size_t height = 100;
76 FlutterDarwinContextMetalSkia* darwinContextMetal =
77 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
78 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
79 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
80 sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
83 MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init];
84 textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm;
85 textureDescriptor.width = width;
86 textureDescriptor.height = height;
87 textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
88 id<MTLTexture> mtlTexture =
89 [darwinContextMetal.device newTextureWithDescriptor:textureDescriptor];
90 std::vector<FlutterMetalTextureHandle> textures = {
91 (__bridge FlutterMetalTextureHandle)mtlTexture,
95 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
97 EXPECT_TRUE(w == width);
98 EXPECT_TRUE(h == height);
100 FlutterMetalExternalTexture* texture =
new FlutterMetalExternalTexture();
101 texture->struct_size =
sizeof(FlutterMetalExternalTexture);
102 texture->num_textures = 1;
105 texture->pixel_format = FlutterMetalExternalTexturePixelFormat::kRGBA;
106 texture->textures = textures.data();
108 return std::unique_ptr<FlutterMetalExternalTexture>(texture);
112 std::unique_ptr<flutter::Texture> texture =
113 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
114 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
115 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
116 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
117 flutter::Texture::PaintContext context{
119 .gr_context = grContext,
121 texture->Paint(context, bounds,
false, sampling);
123 ASSERT_TRUE(mtlTexture != nil);
125 gpuSurface->makeImageSnapshot();
128 TEST(FlutterEmbedderExternalTextureUnittests, TestPopulateExternalTexture) {
130 const size_t width = 100;
131 const size_t height = 100;
135 FlutterDarwinContextMetalSkia* darwinContextMetal =
136 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
137 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
138 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
139 sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
145 pixelFormatType:kCVPixelFormatType_32BGRA];
148 darwinMetalContext:darwinContextMetal];
151 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
153 EXPECT_TRUE(w == width);
154 EXPECT_TRUE(h == height);
156 FlutterMetalExternalTexture* texture =
new FlutterMetalExternalTexture();
159 EXPECT_TRUE(texture->num_textures == 1);
160 EXPECT_TRUE(texture->textures !=
nullptr);
161 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kRGBA);
163 return std::unique_ptr<FlutterMetalExternalTexture>(texture);
167 std::unique_ptr<flutter::Texture> texture =
168 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
169 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
170 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
171 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
172 flutter::Texture::PaintContext context{
174 .gr_context = grContext,
176 texture->Paint(context, bounds,
false, sampling);
178 gpuSurface->makeImageSnapshot();
181 TEST(FlutterEmbedderExternalTextureUnittests, TestPopulateExternalTextureYUVA) {
183 const size_t width = 100;
184 const size_t height = 100;
188 FlutterDarwinContextMetalSkia* darwinContextMetal =
189 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
190 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
191 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
192 sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
198 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
201 darwinMetalContext:darwinContextMetal];
204 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
206 EXPECT_TRUE(w == width);
207 EXPECT_TRUE(h == height);
209 FlutterMetalExternalTexture* texture =
new FlutterMetalExternalTexture();
212 EXPECT_TRUE(texture->num_textures == 2);
213 EXPECT_TRUE(texture->textures !=
nullptr);
214 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kYUVA);
215 EXPECT_TRUE(texture->yuv_color_space ==
216 FlutterMetalExternalTextureYUVColorSpace::kBT601LimitedRange);
218 return std::unique_ptr<FlutterMetalExternalTexture>(texture);
222 std::unique_ptr<flutter::Texture> texture =
223 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
224 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
225 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
226 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
227 flutter::Texture::PaintContext context{
229 .gr_context = grContext,
231 texture->Paint(context, bounds,
false, sampling);
233 gpuSurface->makeImageSnapshot();
236 TEST(FlutterEmbedderExternalTextureUnittests, TestPopulateExternalTextureYUVA2) {
238 const size_t width = 100;
239 const size_t height = 100;
243 FlutterDarwinContextMetalSkia* darwinContextMetal =
244 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
245 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
246 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
247 sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
253 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange];
256 darwinMetalContext:darwinContextMetal];
259 EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t
texture_id,
size_t w,
261 EXPECT_TRUE(w == width);
262 EXPECT_TRUE(h == height);
264 FlutterMetalExternalTexture* texture =
new FlutterMetalExternalTexture();
267 EXPECT_TRUE(texture->num_textures == 2);
268 EXPECT_TRUE(texture->textures !=
nullptr);
269 EXPECT_TRUE(texture->pixel_format == FlutterMetalExternalTexturePixelFormat::kYUVA);
270 EXPECT_TRUE(texture->yuv_color_space ==
271 FlutterMetalExternalTextureYUVColorSpace::kBT601FullRange);
273 return std::unique_ptr<FlutterMetalExternalTexture>(texture);
277 std::unique_ptr<flutter::Texture> texture =
278 std::make_unique<EmbedderExternalTextureMetal>(
texture_id, callback);
279 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
280 DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
281 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
282 flutter::Texture::PaintContext context{
284 .gr_context = grContext,
286 texture->Paint(context, bounds,
false, sampling);
288 gpuSurface->makeImageSnapshot();