Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
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
309
310} // namespace testing
311} // namespace flutter
const char * backend
int count
@ kTopLeft_GrSurfaceOrigin
Definition GrTypes.h:148
@ kUnpremul_SkAlphaType
pixel components are independent of alpha
Definition SkAlphaType.h:30
@ kR16G16B16A16_unorm_SkColorType
pixel with a little endian uint16_t for red, green, blue
Definition SkColorType.h:50
static bool ok(int result)
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
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
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:1686
@ kFlutterPlatformViewMutationTypeTransformation
Definition embedder.h:1698
@ kFlutterOpenGLTargetTypeFramebuffer
Definition embedder.h:304
@ kFlutterOpenGLTargetTypeTexture
Definition embedder.h:301
@ kFlutterBackingStoreTypeMetal
Specifies a Metal backing store. This is backed by a Metal texture.
Definition embedder.h:1744
@ kFlutterBackingStoreTypeVulkan
Specifies a Vulkan backing store. This is backed by a Vulkan VkImage.
Definition embedder.h:1746
@ kFlutterBackingStoreTypeSoftware
Specified an software allocation for Flutter to render into using the CPU.
Definition embedder.h:1742
@ kFlutterBackingStoreTypeOpenGL
Definition embedder.h:1740
SkMatrix SkMatrixMake(const FlutterTransformation &xformation)
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
static bool b
struct MyStruct a[10]
#define FML_LOG(severity)
Definition logging.h:82
#define FML_CHECK(condition)
Definition logging.h:85
SK_API sk_sp< SkImage > DeferredFromEncodedData(sk_sp< SkData > encoded, std::optional< SkAlphaType > alphaType=std::nullopt)
static constexpr skcms_Matrix3x3 kRec2020
static constexpr skcms_TransferFunction kRec2020
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
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
FlutterBackingStoreType type
Specifies the type of backing store.
Definition embedder.h:1760
FlutterOpenGLBackingStore open_gl
The description of the OpenGL backing store.
Definition embedder.h:1766
FlutterSize size
The size of the layer (in physical pixels).
Definition embedder.h:1835
FlutterOpenGLTargetType type
Definition embedder.h:1608
FlutterPlatformViewMutationType type
The type of the mutation described by the subsequent union.
Definition embedder.h:1703
const FlutterPlatformViewMutation ** mutations
Definition embedder.h:1734
double height
Definition embedder.h:423
double width
Definition embedder.h:422
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
size_t computeByteSize(size_t rowBytes) const
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
#define ERROR(message)