Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
image_decoder_no_gl_unittests.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
6#include <memory>
7
10#include "include/core/SkColorType.h"
11
12namespace flutter {
13namespace testing {
14
15// Tests are disabled for fuchsia.
16#if defined(OS_FUCHSIA)
17#pragma GCC diagnostic ignored "-Wunreachable-code"
18#endif
19
20namespace {
21
22bool IsPngWithPLTE(const uint8_t* bytes, size_t size) {
23 constexpr std::string_view kPngMagic = "\x89PNG\x0d\x0a\x1a\x0a";
24 constexpr std::string_view kPngPlte = "PLTE";
25 constexpr uint32_t kLengthBytes = 4;
26 constexpr uint32_t kTypeBytes = 4;
27 constexpr uint32_t kCrcBytes = 4;
28
29 if (size < kPngMagic.size()) {
30 return false;
31 }
32
33 if (memcmp(bytes, kPngMagic.data(), kPngMagic.size()) != 0) {
34 return false;
35 }
36
37 const uint8_t* end = bytes + size;
38 const uint8_t* loc = bytes + kPngMagic.size();
39 while (loc + kLengthBytes + kTypeBytes <= end) {
40 uint32_t chunk_length =
41 fml::BigEndianToArch(*reinterpret_cast<const uint32_t*>(loc));
42
43 if (memcmp(loc + kLengthBytes, kPngPlte.data(), kPngPlte.size()) == 0) {
44 return true;
45 }
46
47 loc += kLengthBytes + kTypeBytes + chunk_length + kCrcBytes;
48 }
49
50 return false;
51}
52
53} // namespace
54
55float HalfToFloat(uint16_t half) {
56 switch (half) {
57 case 0x7c00:
58 return std::numeric_limits<float>::infinity();
59 case 0xfc00:
60 return -std::numeric_limits<float>::infinity();
61 }
62 bool negative = half >> 15;
63 uint16_t exponent = (half >> 10) & 0x1f;
64 uint16_t fraction = half & 0x3ff;
65 float fExponent = exponent - 15.0f;
66 float fFraction = static_cast<float>(fraction) / 1024.f;
67 float pow_value = powf(2.0f, fExponent);
68 return (negative ? -1.f : 1.f) * pow_value * (1.0f + fFraction);
69}
70
71float DecodeBGR10(uint32_t x) {
72 const float max = 1.25098f;
73 const float min = -0.752941f;
74 const float intercept = min;
75 const float slope = (max - min) / 1024.0f;
76 return (x * slope) + intercept;
77}
78
79TEST(ImageDecoderNoGLTest, ImpellerWideGamutDisplayP3) {
80#if defined(OS_FUCHSIA)
81 GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
82#endif
83 auto data = flutter::testing::OpenFixtureAsSkData("DisplayP3Logo.png");
84 auto image = SkImages::DeferredFromEncodedData(data);
85 std::shared_ptr<impeller::Capabilities> capabilities =
88 .Build();
89 ASSERT_TRUE(image != nullptr);
90 ASSERT_EQ(SkISize::Make(100, 100), image->dimensions());
91
93 std::shared_ptr<ImageGenerator> generator =
95 ASSERT_TRUE(generator);
96
97 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
98 std::move(generator));
99
100 ASSERT_FALSE(
101 IsPngWithPLTE(descriptor->data()->bytes(), descriptor->data()->size()));
102
103#if IMPELLER_SUPPORTS_RENDERING
104 std::shared_ptr<impeller::Allocator> allocator =
105 std::make_shared<impeller::TestImpellerAllocator>();
106 absl::StatusOr<ImageDecoderImpeller::DecompressResult> wide_result =
108 descriptor.get(), {.target_width = 100, .target_height = 100},
109 {100, 100},
110 /*supports_wide_gamut=*/true, capabilities, allocator);
111 ASSERT_TRUE(wide_result.ok());
112 ASSERT_EQ(wide_result->image_info.format,
114
115 const uint16_t* half_ptr = reinterpret_cast<const uint16_t*>(
116 wide_result->device_buffer->OnGetContents());
117 bool found_deep_red = false;
118 for (int i = 0; i < wide_result->image_info.size.width *
119 wide_result->image_info.size.height;
120 ++i) {
121 float red = HalfToFloat(*half_ptr++);
122 float green = HalfToFloat(*half_ptr++);
123 float blue = HalfToFloat(*half_ptr++);
124 half_ptr++; // alpha
125 if (fabsf(red - 1.0931f) < 0.01f && fabsf(green - -0.2268f) < 0.01f &&
126 fabsf(blue - -0.1501f) < 0.01f) {
127 found_deep_red = true;
128 break;
129 }
130 }
131
132 ASSERT_TRUE(found_deep_red);
133 absl::StatusOr<ImageDecoderImpeller::DecompressResult> narrow_result =
135 descriptor.get(), {.target_width = 100, .target_height = 100},
136 {100, 100},
137 /*supports_wide_gamut=*/false, capabilities, allocator);
138
139 ASSERT_TRUE(narrow_result.ok());
140 ASSERT_EQ(narrow_result->image_info.format,
142#endif // IMPELLER_SUPPORTS_RENDERING
143}
144
145TEST(ImageDecoderNoGLTest, ImpellerWideGamutIndexedPng) {
146#if defined(OS_FUCHSIA)
147 GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
148#endif
149 auto data = flutter::testing::OpenFixtureAsSkData("WideGamutIndexed.png");
150 auto image = SkImages::DeferredFromEncodedData(data);
151 std::shared_ptr<impeller::Capabilities> capabilities =
154 .Build();
155 ASSERT_TRUE(image != nullptr);
156 ASSERT_EQ(SkISize::Make(100, 100), image->dimensions());
157
158 ImageGeneratorRegistry registry;
159 std::shared_ptr<ImageGenerator> generator =
161 ASSERT_TRUE(generator);
162
163 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
164 std::move(generator));
165
166 ASSERT_TRUE(
167 IsPngWithPLTE(descriptor->data()->bytes(), descriptor->data()->size()));
168
169#if IMPELLER_SUPPORTS_RENDERING
170 std::shared_ptr<impeller::Allocator> allocator =
171 std::make_shared<impeller::TestImpellerAllocator>();
172 absl::StatusOr<ImageDecoderImpeller::DecompressResult> wide_result =
174 descriptor.get(), {.target_width = 100, .target_height = 100},
175 {100, 100},
176 /*supports_wide_gamut=*/true, capabilities, allocator);
177 ASSERT_TRUE(wide_result.ok());
178 ASSERT_EQ(wide_result->image_info.format,
180
181 const uint32_t* pixel_ptr = reinterpret_cast<const uint32_t*>(
182 wide_result->device_buffer->OnGetContents());
183 bool found_deep_red = false;
184 for (int i = 0; i < wide_result->image_info.size.width *
185 wide_result->image_info.size.height;
186 ++i) {
187 uint32_t pixel = *pixel_ptr++;
188 float blue = DecodeBGR10((pixel >> 0) & 0x3ff);
189 float green = DecodeBGR10((pixel >> 10) & 0x3ff);
190 float red = DecodeBGR10((pixel >> 20) & 0x3ff);
191 if (fabsf(red - 1.0931f) < 0.01f && fabsf(green - -0.2268f) < 0.01f &&
192 fabsf(blue - -0.1501f) < 0.01f) {
193 found_deep_red = true;
194 break;
195 }
196 }
197
198 ASSERT_TRUE(found_deep_red);
199 absl::StatusOr<ImageDecoderImpeller::DecompressResult> narrow_result =
201 descriptor.get(), {.target_width = 100, .target_height = 100},
202 {100, 100},
203 /*supports_wide_gamut=*/false, capabilities, allocator);
204
205 ASSERT_TRUE(narrow_result.ok());
206 ASSERT_EQ(narrow_result->image_info.format,
208#endif // IMPELLER_SUPPORTS_RENDERING
209}
210
211TEST(ImageDecoderNoGLTest, ImpellerRGBA32FDecode) {
212#if defined(OS_FUCHSIA)
213 GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
214#endif
215
216#if IMPELLER_SUPPORTS_RENDERING
217 // 1. Create a 1x1 pixel with float RGBA values.
218 float pixel_data[] = {1.0f, 0.5f, 0.25f, 1.0f}; // R, G, B, A
219 sk_sp<SkData> sk_data = SkData::MakeWithCopy(pixel_data, sizeof(pixel_data));
220 auto immutable_buffer =
221 fml::MakeRefCounted<ImmutableBuffer>(std::move(sk_data));
222
223 // 2. Create an ImageDescriptor using the private constructor.
224 ImageDescriptor::ImageInfo image_info = {
225 .width = 1,
226 .height = 1,
228 .alpha_type = kUnpremul_SkAlphaType,
229 };
230 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(
231 immutable_buffer->data(), image_info, sizeof(pixel_data));
232
233 // Set up Impeller capabilities and allocator.
234 std::shared_ptr<impeller::Capabilities> capabilities =
237 .Build();
238 std::shared_ptr<impeller::Allocator> allocator =
239 std::make_shared<impeller::TestImpellerAllocator>();
240
241 // 3. Call ImageDecoderImpeller::DecompressTexture with this ImageDescriptor.
242 absl::StatusOr<ImageDecoderImpeller::DecompressResult> result =
244 descriptor.get(),
245 /*options=*/
246 {.target_width = 1,
247 .target_height = 1,
248 .target_format =
249 ImageDecoder::TargetPixelFormat::kR32G32B32A32Float},
250 /*max_texture_size=*/{1, 1},
251 /*supports_wide_gamut=*/true, capabilities, allocator);
252
253 // 4. Assert that wide_result->image_info.format is
254 // impeller::PixelFormat::kR32G32B32A32Float.
255 ASSERT_TRUE(result.ok());
256 ASSERT_EQ(result->image_info.format,
258
259 // Optionally, verify the pixel data if needed.
260 const float* decompressed_pixel_ptr =
261 reinterpret_cast<const float*>(result->device_buffer->OnGetContents());
262 ASSERT_NE(decompressed_pixel_ptr, nullptr);
263 EXPECT_EQ(decompressed_pixel_ptr[0], 1.0f); // R
264 EXPECT_EQ(decompressed_pixel_ptr[1], 0.5f); // G
265 EXPECT_EQ(decompressed_pixel_ptr[2], 0.25f); // B
266 EXPECT_EQ(decompressed_pixel_ptr[3], 1.0f); // A
267
268#endif // IMPELLER_SUPPORTS_RENDERING
269}
270
271TEST(ImageDecoderNoGLTest, ImpellerR32FDecode) {
272#if defined(OS_FUCHSIA)
273 GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
274#endif
275
276#if !IMPELLER_SUPPORTS_RENDERING
277 GTEST_SKIP() << "test only supported on impeller";
278#else
279 // 1. Create a 1x1 pixel with float RGBA values.
280 float pixel_data[] = {1.0f};
281 sk_sp<SkData> sk_data = SkData::MakeWithCopy(pixel_data, sizeof(pixel_data));
282 auto immutable_buffer =
283 fml::MakeRefCounted<ImmutableBuffer>(std::move(sk_data));
284
285 // 2. Create an ImageDescriptor using the private constructor.
286 ImageDescriptor::ImageInfo image_info = {
287 .width = 1,
288 .height = 1,
290 .alpha_type = kUnpremul_SkAlphaType,
291 };
292 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(
293 immutable_buffer->data(), image_info, sizeof(pixel_data));
294
295 // Set up Impeller capabilities and allocator.
296 std::shared_ptr<impeller::Capabilities> capabilities =
299 .Build();
300 std::shared_ptr<impeller::Allocator> allocator =
301 std::make_shared<impeller::TestImpellerAllocator>();
302
303 // 3. Call ImageDecoderImpeller::DecompressTexture with this ImageDescriptor.
304 absl::StatusOr<ImageDecoderImpeller::DecompressResult> result =
306 descriptor.get(),
307 /*options=*/
308 {.target_width = 1,
309 .target_height = 1,
310 .target_format = ImageDecoder::TargetPixelFormat::kR32Float},
311 /*max_texture_size=*/{1, 1},
312 /*supports_wide_gamut=*/true, capabilities, allocator);
313
314 // 4. Assert that wide_result->image_info.format is
315 // impeller::PixelFormat::kR32G32B32A32Float.
316 ASSERT_TRUE(result.ok());
317 ASSERT_EQ(result->image_info.format, impeller::PixelFormat::kR32Float);
318
319 // Optionally, verify the pixel data if needed.
320 const float* decompressed_pixel_ptr =
321 reinterpret_cast<const float*>(result->device_buffer->OnGetContents());
322 ASSERT_NE(decompressed_pixel_ptr, nullptr);
323 EXPECT_EQ(decompressed_pixel_ptr[0], 1.0f);
324
325#endif // IMPELLER_SUPPORTS_RENDERING
326}
327
328TEST(ImageDecoderNoGLTest, ImpellerUnmultipliedAlphaPng) {
329#if defined(OS_FUCHSIA)
330 GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
331#endif
332 auto data = flutter::testing::OpenFixtureAsSkData("unmultiplied_alpha.png");
333 auto image = SkImages::DeferredFromEncodedData(data);
334 std::shared_ptr<impeller::Capabilities> capabilities =
337 .Build();
338 ASSERT_TRUE(image != nullptr);
339 ASSERT_EQ(SkISize::Make(11, 11), image->dimensions());
340
341 ImageGeneratorRegistry registry;
342 std::shared_ptr<ImageGenerator> generator =
344 ASSERT_TRUE(generator);
345
346 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
347 std::move(generator));
348
349#if IMPELLER_SUPPORTS_RENDERING
350 std::shared_ptr<impeller::Allocator> allocator =
351 std::make_shared<impeller::TestImpellerAllocator>();
352 absl::StatusOr<ImageDecoderImpeller::DecompressResult> result =
354 descriptor.get(), {.target_width = 11, .target_height = 11}, {11, 11},
355 /*supports_wide_gamut=*/true, capabilities, allocator);
356 ASSERT_TRUE(result.ok());
357 ASSERT_EQ(result->image_info.format,
359
360 const uint32_t* pixel_ptr =
361 reinterpret_cast<const uint32_t*>(result->device_buffer->OnGetContents());
362 // Test the upper left pixel is premultiplied and not solid red.
363 ASSERT_EQ(*pixel_ptr, (uint32_t)0x1000001);
364 // Test a pixel in the green box is still green.
365 ASSERT_EQ(*(pixel_ptr + 11 * 4 + 4), (uint32_t)0xFF00FF00);
366
367#endif // IMPELLER_SUPPORTS_RENDERING
368}
369
370} // namespace testing
371} // namespace flutter
static absl::StatusOr< DecompressResult > DecompressTexture(ImageDescriptor *descriptor, const ImageDecoder::Options &options, impeller::ISize max_texture_size, bool supports_wide_gamut, const std::shared_ptr< const impeller::Capabilities > &capabilities, const std::shared_ptr< impeller::Allocator > &allocator)
Keeps a priority-ordered registry of image generator builders to be used when decoding images....
std::shared_ptr< ImageGenerator > CreateCompatibleGenerator(const sk_sp< SkData > &buffer)
Walks the list of image generator builders in descending priority order until a compatible ImageGener...
CapabilitiesBuilder & SetSupportsTextureToTextureBlits(bool value)
std::unique_ptr< Capabilities > Build()
int32_t x
FlutterVulkanImage * image
std::shared_ptr< ImpellerAllocator > allocator
sk_sp< SkData > OpenFixtureAsSkData(const std::string &fixture_name)
Opens a fixture of the given file name and returns a Skia SkData holding its contents.
Definition testing.cc:63
TEST(NativeAssetsManagerTest, NoAvailableAssets)
float HalfToFloat(uint16_t half)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all 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
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 switch_defs.h:36
constexpr T BigEndianToArch(T n)
Convert a known big endian value to match the endianness of the current architecture....
Definition endianness.h:59
const size_t end