Flutter Engine
The Flutter Engine
embedder_unittests_util.cc
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#define FML_USED_ON_EMBEDDER
6
7#include <limits>
8#include <utility>
9
10#include "flutter/shell/platform/embedder/tests/embedder_test_backingstore_producer.h"
11#include "flutter/shell/platform/embedder/tests/embedder_unittests_util.h"
12
17
18namespace flutter {
19namespace testing {
20
22 GrDirectContext* context) {
23 const auto image_info =
25 auto surface = context ? SkSurfaces::RenderTarget(
26 context, // context
27 skgpu::Budgeted::kNo, // budgeted
28 image_info, // image info
29 1, // sample count
30 kTopLeft_GrSurfaceOrigin, // surface origin
31 nullptr, // surface properties
32 false // mipmaps
33
34 )
35 : SkSurfaces::Raster(image_info);
36 FML_CHECK(surface != nullptr);
37 return surface;
38}
39
40// Normalizes the color-space, color-type and alpha-type for comparison.
42 // To avoid clipping, convert to a very wide gamut, and a high bit depth.
45 SkImageInfo norm_image_info =
48 SkAlphaType::kUnpremul_SkAlphaType, norm_colorspace);
49 size_t row_bytes = norm_image_info.minRowBytes();
50 size_t size = norm_image_info.computeByteSize(row_bytes);
52 if (!data) {
53 FML_CHECK(false) << "Unable to allocate data.";
54 }
55
56 bool success = image->readPixels(norm_image_info, data->writable_data(),
57 row_bytes, 0, 0);
58 if (!success) {
59 FML_CHECK(false) << "Unable to read pixels.";
60 }
61
62 return data;
63}
64
66 if (!a || !b) {
67 return false;
68 }
69
70 FML_CHECK(!a->isTextureBacked());
71 FML_CHECK(!b->isTextureBacked());
72
73 sk_sp<SkData> normalized_a = NormalizeImage(a);
74 sk_sp<SkData> normalized_b = NormalizeImage(b);
75
76 return normalized_a->equals(normalized_b.get());
77}
78
80 const std::string& name) {
81 switch (backend) {
83 return "vk_" + name;
84 default:
85 return name;
86 }
87}
88
91 bool opengl_framebuffer) {
92 switch (backend) {
96 if (opengl_framebuffer) {
99 }
106 }
107}
108
111 bool opengl_framebuffer) {
112 switch (backend) {
114 backing_store.type = kFlutterBackingStoreTypeVulkan;
115 break;
117 if (opengl_framebuffer) {
118 backing_store.type = kFlutterBackingStoreTypeOpenGL;
120 } else {
121 backing_store.type = kFlutterBackingStoreTypeOpenGL;
123 }
124 break;
126 backing_store.type = kFlutterBackingStoreTypeMetal;
127 break;
130 break;
131 }
132}
133
134bool WriteImageToDisk(const fml::UniqueFD& directory,
135 const std::string& name,
136 const sk_sp<SkImage>& image) {
137 if (!image) {
138 return false;
139 }
140
141 auto data = SkPngEncoder::Encode(nullptr, image.get(), {});
142
143 if (!data) {
144 return false;
145 }
146
147 fml::NonOwnedMapping mapping(static_cast<const uint8_t*>(data->data()),
148 data->size());
149 return WriteAtomically(directory, name.c_str(), mapping);
150}
151
152bool ImageMatchesFixture(const std::string& fixture_file_name,
153 const sk_sp<SkImage>& scene_image) {
154 fml::FileMapping fixture_image_mapping(OpenFixture(fixture_file_name));
155
156 FML_CHECK(fixture_image_mapping.GetSize() != 0u)
157 << "Could not find fixture: " << fixture_file_name;
158
159 auto encoded_image = SkData::MakeWithoutCopy(
160 fixture_image_mapping.GetMapping(), fixture_image_mapping.GetSize());
161 auto fixture_image =
162 SkImages::DeferredFromEncodedData(std::move(encoded_image))
163 ->makeRasterImage();
164
165 FML_CHECK(fixture_image) << "Could not create image from fixture: "
166 << fixture_file_name;
167
168 FML_CHECK(scene_image) << "Invalid scene image.";
169
170 auto scene_image_subset = scene_image->makeSubset(
171 nullptr,
172 SkIRect::MakeWH(fixture_image->width(), fixture_image->height()));
173
174 FML_CHECK(scene_image_subset)
175 << "Could not create image subset for fixture comparison: "
176 << scene_image_subset;
177
178 const auto images_are_same =
179 RasterImagesAreSame(scene_image_subset, fixture_image);
180
181 // If the images are not the same, this predicate is going to indicate test
182 // failure. Dump both the actual image and the expectation to disk to the
183 // test author can figure out what went wrong.
184 if (!images_are_same) {
185 const auto fixtures_path = GetFixturesPath();
186
187 const auto actual_file_name = "actual_" + fixture_file_name;
188 const auto expect_file_name = "expectation_" + fixture_file_name;
189
190 auto fixtures_fd = OpenFixturesDirectory();
191
192 FML_CHECK(
193 WriteImageToDisk(fixtures_fd, actual_file_name, scene_image_subset))
194 << "Could not write file to disk: " << actual_file_name;
195
196 FML_CHECK(WriteImageToDisk(fixtures_fd, expect_file_name, fixture_image))
197 << "Could not write file to disk: " << expect_file_name;
198
199 FML_LOG(ERROR) << "Image did not match expectation." << std::endl
200 << "Expected:"
201 << fml::paths::JoinPaths({fixtures_path, expect_file_name})
202 << std::endl
203 << "Got:"
204 << fml::paths::JoinPaths({fixtures_path, actual_file_name})
205 << std::endl;
206 }
207 return images_are_same;
208}
209
210bool ImageMatchesFixture(const std::string& fixture_file_name,
211 std::future<sk_sp<SkImage>>& scene_image) {
212 return ImageMatchesFixture(fixture_file_name, scene_image.get());
213}
214
216 const std::vector<uint8_t>& bytes) {
217 SkPixmap pixmap;
218 auto ok = surface->peekPixels(&pixmap);
219 if (!ok) {
220 return false;
221 }
222
223 auto matches = (pixmap.rowBytes() == bytes.size()) &&
224 (memcmp(bytes.data(), pixmap.addr(), bytes.size()) == 0);
225
226 if (!matches) {
227 FML_LOG(ERROR) << "SkImage pixel data didn't match bytes.";
228
229 {
230 const uint8_t* addr = static_cast<const uint8_t*>(pixmap.addr());
231 std::stringstream stream;
232 for (size_t i = 0; i < pixmap.computeByteSize(); ++i) {
233 stream << "0x" << std::setfill('0') << std::setw(2) << std::uppercase
234 << std::hex << static_cast<int>(addr[i]);
235 if (i != pixmap.computeByteSize() - 1) {
236 stream << ", ";
237 }
238 }
239 FML_LOG(ERROR) << " Actual: " << stream.str();
240 }
241 {
242 std::stringstream stream;
243 for (auto b = bytes.begin(); b != bytes.end(); ++b) {
244 stream << "0x" << std::setfill('0') << std::setw(2) << std::uppercase
245 << std::hex << static_cast<int>(*b);
246 if (b != bytes.end() - 1) {
247 stream << ", ";
248 }
249 }
250 FML_LOG(ERROR) << " Expected: " << stream.str();
251 }
252 }
253
254 return matches;
255}
256
257bool SurfacePixelDataMatchesBytes(std::future<SkSurface*>& surface_future,
258 const std::vector<uint8_t>& bytes) {
259 return SurfacePixelDataMatchesBytes(surface_future.get(), bytes);
260}
261
263 const FlutterPlatformViewMutation** mutations,
264 size_t count,
266 const std::function<void(const FlutterPlatformViewMutation& mutation)>&
267 handler) {
268 if (mutations == nullptr) {
269 return;
270 }
271
272 for (size_t i = 0; i < count; ++i) {
273 const FlutterPlatformViewMutation* mutation = mutations[i];
274 if (mutation->type != type) {
275 continue;
276 }
277
278 handler(*mutation);
279 }
280}
281
283 const FlutterPlatformView* view,
285 const std::function<void(const FlutterPlatformViewMutation& mutation)>&
286 handler) {
288 handler);
289}
290
292 const FlutterPlatformViewMutation** mutations,
293 size_t count) {
294 SkMatrix collected;
295
298 [&](const auto& mutation) {
299 collected.preConcat(SkMatrixMake(mutation.transformation));
300 });
301
302 return collected;
303}
304
307 view->mutations_count);
308}
309
310} // namespace testing
311} // namespace flutter
const char * backend
int count
Definition: FontMgrTest.cpp:50
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
kUnpremul_SkAlphaType
@ kR16G16B16A16_unorm_SkColorType
pixel with a little endian uint16_t for red, green, blue
Definition: SkColorType.h:50
static bool ok(int result)
GLenum type
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
Definition: SkData.h:116
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
bool equals(const SkData *other) const
Definition: SkData.cpp:43
sk_sp< SkImage > makeRasterImage(GrDirectContext *, CachingHint cachingHint=kDisallow_CachingHint) const
Definition: SkImage.cpp:267
bool readPixels(GrDirectContext *context, const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint cachingHint=kAllow_CachingHint) const
Definition: SkImage.cpp:42
int width() const
Definition: SkImage.h:285
int height() const
Definition: SkImage.h:291
virtual sk_sp< SkImage > makeSubset(GrDirectContext *direct, const SkIRect &subset) const =0
SkMatrix & preConcat(const SkMatrix &other)
Definition: SkMatrix.cpp:674
size_t rowBytes() const
Definition: SkPixmap.h:145
size_t computeByteSize() const
Definition: SkPixmap.h:231
const void * addr() const
Definition: SkPixmap.h:153
size_t GetSize() const override
const uint8_t * GetMapping() const override
T * get() const
Definition: SkRefCnt.h:303
FlutterPlatformViewMutationType
Definition: embedder.h:1688
@ kFlutterPlatformViewMutationTypeTransformation
Definition: embedder.h:1700
@ kFlutterOpenGLTargetTypeFramebuffer
Definition: embedder.h:306
@ kFlutterOpenGLTargetTypeTexture
Definition: embedder.h:303
@ kFlutterBackingStoreTypeMetal
Specifies a Metal backing store. This is backed by a Metal texture.
Definition: embedder.h:1746
@ kFlutterBackingStoreTypeVulkan
Specifies a Vulkan backing store. This is backed by a Vulkan VkImage.
Definition: embedder.h:1748
@ kFlutterBackingStoreTypeSoftware
Specified an software allocation for Flutter to render into using the CPU.
Definition: embedder.h:1744
@ kFlutterBackingStoreTypeOpenGL
Definition: embedder.h:1742
SkMatrix SkMatrixMake(const FlutterTransformation &xformation)
VkSurfaceKHR surface
Definition: main.cc:49
static bool b
struct MyStruct a[10]
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_CHECK(condition)
Definition: logging.h:85
Dart_NativeFunction function
Definition: fuchsia.cc:51
SK_API sk_sp< SkImage > DeferredFromEncodedData(sk_sp< SkData > encoded, std::optional< SkAlphaType > alphaType=std::nullopt)
static constexpr skcms_Matrix3x3 kRec2020
Definition: SkColorSpace.h:93
static constexpr skcms_TransferFunction kRec2020
Definition: SkColorSpace.h:54
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
sk_sp< const SkImage > image
Definition: SkRecords.h:269
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
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)
const char * GetFixturesPath()
Returns the directory containing the test fixture for the target if this target has fixtures configur...
bool WriteImageToDisk(const fml::UniqueFD &directory, const std::string &name, const sk_sp< SkImage > &image)
sk_sp< SkSurface > CreateRenderSurface(const FlutterLayer &layer, GrDirectContext *context)
void FilterMutationsByType(const FlutterPlatformViewMutation **mutations, size_t count, FlutterPlatformViewMutationType type, const std::function< void(const FlutterPlatformViewMutation &mutation)> &handler)
static sk_sp< SkData > NormalizeImage(const sk_sp< SkImage > &image)
bool SurfacePixelDataMatchesBytes(SkSurface *surface, const std::vector< uint8_t > &bytes)
fml::UniqueFD OpenFixture(const std::string &fixture_name)
Opens a fixture of the given file name.
Definition: testing.cc:37
fml::UniqueFD OpenFixturesDirectory()
Opens the fixtures directory for the unit-test harness.
Definition: testing.cc:23
void ConfigureBackingStore(FlutterBackingStore &backing_store, EmbedderTestContextType backend, bool opengl_framebuffer)
Configures per-backend properties for a given backing store.
bool RasterImagesAreSame(const sk_sp< SkImage > &a, const sk_sp< SkImage > &b)
SkMatrix GetTotalMutationTransformationMatrix(const FlutterPlatformViewMutation **mutations, size_t count)
std::string FixtureNameForBackend(EmbedderTestContextType backend, const std::string &name)
Prepends a prefix to the name which is unique to the test context type. This is useful for tests that...
bool ImageMatchesFixture(const std::string &fixture_file_name, const sk_sp< SkImage > &scene_image)
EmbedderTestBackingStoreProducer::RenderTargetType GetRenderTargetFromBackend(EmbedderTestContextType backend, bool opengl_framebuffer)
Resolves a render target type for a given backend description. This is useful for tests that use Embe...
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition: switches.h:41
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
std::string JoinPaths(std::initializer_list< std::string > components)
Definition: paths.cc:14
bool WriteAtomically(const fml::UniqueFD &base_directory, const char *file_name, const Mapping &mapping)
Definition: file_posix.cc:191
def matches(file)
Definition: gen_manifest.py:38
FlutterBackingStoreType type
Specifies the type of backing store.
Definition: embedder.h:1762
FlutterOpenGLBackingStore open_gl
The description of the OpenGL backing store.
Definition: embedder.h:1768
FlutterSize size
The size of the layer (in physical pixels).
Definition: embedder.h:1837
FlutterOpenGLTargetType type
Definition: embedder.h:1610
FlutterPlatformViewMutationType type
The type of the mutation described by the subsequent union.
Definition: embedder.h:1705
const FlutterPlatformViewMutation ** mutations
Definition: embedder.h:1736
size_t mutations_count
Definition: embedder.h:1723
double height
Definition: embedder.h:425
double width
Definition: embedder.h:424
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
static SkImageInfo MakeN32Premul(int width, int height)
size_t minRowBytes() const
Definition: SkImageInfo.h:517
size_t computeByteSize(size_t rowBytes) const
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
#define ERROR(message)
Definition: elf_loader.cc:260