Flutter Engine
The Flutter Engine
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#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"
14#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTexture.h"
15#include "flutter/shell/platform/embedder/embedder.h"
16#include "flutter/shell/platform/embedder/embedder_external_texture_metal.h"
17#include "flutter/testing/autoreleasepool_test.h"
18#include "flutter/testing/testing.h"
19#include "third_party/googletest/googletest/include/gtest/gtest.h"
24
25@interface TestExternalTexture : NSObject <FlutterTexture>
26
27- (nonnull instancetype)initWidth:(size_t)width
28 height:(size_t)height
29 pixelFormatType:(OSType)pixelFormatType;
30
31@end
32
33@implementation TestExternalTexture {
34 size_t _width;
35 size_t _height;
37}
38
39- (nonnull instancetype)initWidth:(size_t)width
40 height:(size_t)height
41 pixelFormatType:(OSType)pixelFormatType {
42 if (self = [super init]) {
43 _width = width;
45 _pixelFormatType = pixelFormatType;
46 }
47 return self;
48}
49
50- (CVPixelBufferRef)copyPixelBuffer {
51 return [self pixelBuffer];
52}
53
54- (CVPixelBufferRef)pixelBuffer {
55 NSDictionary* options = @{
56 // This key is required to generate SKPicture with CVPixelBufferRef in metal.
57 (NSString*)kCVPixelBufferMetalCompatibilityKey : @YES
58 };
59 CVPixelBufferRef pxbuffer = NULL;
60 CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, _width, _width, _pixelFormatType,
61 (__bridge CFDictionaryRef)options, &pxbuffer);
62 FML_CHECK(status == kCVReturnSuccess && pxbuffer != nullptr) << "Failed to create pixel buffer";
63 return pxbuffer;
64}
65
66@end
67
68namespace flutter::testing {
69
70// Test-specific name for AutoreleasePoolTest fixture.
72
74 // Constants.
75 const size_t width = 100;
76 const size_t height = 100;
77 const int64_t texture_id = 1;
78
79 // Set up the surface.
80 FlutterDarwinContextMetalSkia* darwinContextMetal =
81 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
83 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
85
86 // Create a texture.
87 MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init];
88 textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm;
89 textureDescriptor.width = width;
90 textureDescriptor.height = height;
91 textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
92 id<MTLTexture> mtlTexture =
93 [darwinContextMetal.device newTextureWithDescriptor:textureDescriptor];
94 std::vector<FlutterMetalTextureHandle> textures = {
95 (__bridge FlutterMetalTextureHandle)mtlTexture,
96 };
97
98 // Callback to resolve the texture.
100 size_t h) {
101 EXPECT_TRUE(w == width);
102 EXPECT_TRUE(h == height);
103
104 auto texture = std::make_unique<FlutterMetalExternalTexture>();
105 texture->struct_size = sizeof(FlutterMetalExternalTexture);
106 texture->num_textures = 1;
107 texture->height = h;
108 texture->width = w;
110 texture->textures = textures.data();
111 return texture;
112 };
113
114 // Render the texture.
115 std::unique_ptr<flutter::Texture> texture =
116 std::make_unique<EmbedderExternalTextureMetal>(texture_id, callback);
117 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
119 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
121 .canvas = &canvas,
122 .gr_context = grContext,
123 };
124 texture->Paint(context, bounds, /*freeze=*/false, sampling);
125
126 ASSERT_TRUE(mtlTexture != nil);
127
128 gpuSurface->makeImageSnapshot();
129}
130
131TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateExternalTexture) {
132 // Constants.
133 const size_t width = 100;
134 const size_t height = 100;
135 const int64_t texture_id = 1;
136
137 // Set up the surface.
138 FlutterDarwinContextMetalSkia* darwinContextMetal =
139 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
141 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
143
144 // Create a texture.
145 TestExternalTexture* testExternalTexture =
146 [[TestExternalTexture alloc] initWidth:width
147 height:height
148 pixelFormatType:kCVPixelFormatType_32BGRA];
149 FlutterExternalTexture* textureHolder =
150 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
151 darwinMetalContext:darwinContextMetal];
152
153 // Callback to resolve the texture.
155 size_t h) {
156 EXPECT_TRUE(w == width);
157 EXPECT_TRUE(h == height);
158
159 auto texture = std::make_unique<FlutterMetalExternalTexture>();
160 [textureHolder populateTexture:texture.get()];
161
162 EXPECT_TRUE(texture->num_textures == 1);
163 EXPECT_TRUE(texture->textures != nullptr);
165 return texture;
166 };
167
168 // Render the texture.
169 std::unique_ptr<flutter::Texture> texture =
170 std::make_unique<EmbedderExternalTextureMetal>(texture_id, callback);
171 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
173 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
175 .canvas = &canvas,
176 .gr_context = grContext,
177 };
178 texture->Paint(context, bounds, /*freeze=*/false, sampling);
179
180 gpuSurface->makeImageSnapshot();
181}
182
183TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateExternalTextureYUVA) {
184 // Constants.
185 const size_t width = 100;
186 const size_t height = 100;
187 const int64_t texture_id = 1;
188
189 // Set up the surface.
190 FlutterDarwinContextMetalSkia* darwinContextMetal =
191 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
193 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
195
196 // Create a texture.
197 TestExternalTexture* testExternalTexture =
198 [[TestExternalTexture alloc] initWidth:width
199 height:height
200 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
201 FlutterExternalTexture* textureHolder =
202 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
203 darwinMetalContext:darwinContextMetal];
204
205 // Callback to resolve the texture.
207 size_t h) {
208 EXPECT_TRUE(w == width);
209 EXPECT_TRUE(h == height);
210
211 auto texture = std::make_unique<FlutterMetalExternalTexture>();
212 [textureHolder populateTexture:texture.get()];
213
214 EXPECT_TRUE(texture->num_textures == 2);
215 EXPECT_TRUE(texture->textures != nullptr);
217 EXPECT_TRUE(texture->yuv_color_space ==
219 return texture;
220 };
221
222 // Render the texture.
223 std::unique_ptr<flutter::Texture> texture =
224 std::make_unique<EmbedderExternalTextureMetal>(texture_id, callback);
225 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
227 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
229 .canvas = &canvas,
230 .gr_context = grContext,
231 };
232 texture->Paint(context, bounds, /*freeze=*/false, sampling);
233
234 gpuSurface->makeImageSnapshot();
235}
236
237TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateExternalTextureYUVA2) {
238 // Constants.
239 const size_t width = 100;
240 const size_t height = 100;
241 const int64_t texture_id = 1;
242
243 // Set up the surface.
244 FlutterDarwinContextMetalSkia* darwinContextMetal =
245 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
247 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
249
250 // Create a texture.
251 TestExternalTexture* testExternalTexture =
252 [[TestExternalTexture alloc] initWidth:width
253 height:height
254 pixelFormatType:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange];
255 FlutterExternalTexture* textureHolder =
256 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
257 darwinMetalContext:darwinContextMetal];
258
259 // Callback to resolve the texture.
261 size_t h) {
262 EXPECT_TRUE(w == width);
263 EXPECT_TRUE(h == height);
264
265 auto texture = std::make_unique<FlutterMetalExternalTexture>();
266 [textureHolder populateTexture:texture.get()];
267
268 EXPECT_TRUE(texture->num_textures == 2);
269 EXPECT_TRUE(texture->textures != nullptr);
271 EXPECT_TRUE(texture->yuv_color_space ==
273 return texture;
274 };
275
276 // Render the 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());
281 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
283 .canvas = &canvas,
284 .gr_context = grContext,
285 };
286 texture->Paint(context, bounds, /*freeze=*/false, sampling);
287
288 gpuSurface->makeImageSnapshot();
289}
290
291TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateUnsupportedExternalTexture) {
292 // Constants.
293 const size_t width = 100;
294 const size_t height = 100;
295 const int64_t texture_id = 1;
296
297 // Set up the surface.
298 FlutterDarwinContextMetalSkia* darwinContextMetal =
299 [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
301 GrDirectContext* grContext = darwinContextMetal.mainContext.get();
303
304 // Create a texture.
305 TestExternalTexture* testExternalTexture =
306 [[TestExternalTexture alloc] initWidth:width
307 height:height
308 pixelFormatType:kCVPixelFormatType_420YpCbCr8PlanarFullRange];
309 FlutterExternalTexture* textureHolder =
310 [[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
311 darwinMetalContext:darwinContextMetal];
312
313 // Callback to resolve the texture.
315 size_t h) {
316 EXPECT_TRUE(w == width);
317 EXPECT_TRUE(h == height);
318
319 auto texture = std::make_unique<FlutterMetalExternalTexture>();
320 EXPECT_FALSE([textureHolder populateTexture:texture.get()]);
321 return nullptr;
322 };
323
324 // Render the texture.
325 std::unique_ptr<flutter::Texture> texture =
326 std::make_unique<EmbedderExternalTextureMetal>(texture_id, callback);
327 SkRect bounds = SkRect::MakeWH(info.width(), info.height());
329 DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
331 .canvas = &canvas,
332 .gr_context = grContext,
333 };
334 texture->Paint(context, bounds, /*freeze=*/false, sampling);
335}
336
337} // namespace flutter::testing
const char * options
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
sk_sp< SkImage > makeImageSnapshot()
Definition: SkSurface.cpp:90
Backend implementation of |DlCanvas| for |SkCanvas|.
Definition: dl_sk_canvas.h:20
std::function< std::unique_ptr< FlutterMetalExternalTexture >(int64_t, size_t, size_t)> ExternalTextureCallback
T * get() const
Definition: SkRefCnt.h:303
@ kBT601LimitedRange
Definition: embedder.h:613
@ kBT601FullRange
Definition: embedder.h:612
@ kRGBA
Definition: embedder.h:607
@ kYUVA
Definition: embedder.h:606
const void * FlutterMetalTextureHandle
Alias for id<MTLTexture>.
Definition: embedder.h:602
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
#define FML_CHECK(condition)
Definition: logging.h:85
BOOL populateTexture:(nonnull FlutterMetalExternalTexture *metalTexture)
FlTexture * texture
static bool init()
Optional< SkRect > bounds
Definition: SkRecords.h:189
SkSamplingOptions sampling
Definition: SkRecords.h:337
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
TEST_F(DisplayListTest, Defaults)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder h
Definition: switches.h:59
SkScalar w
int32_t height
int32_t width
static SkImageInfo MakeN32Premul(int width, int height)
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
int64_t texture_id
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678