From f5c318af14d08b6fdf9995360f0ce7299dfaffd1 Mon Sep 17 00:00:00 2001 From: John McDole Date: Mon, 8 Jul 2024 16:26:00 -0700 Subject: [PATCH 1/2] Impeller really wants premultiplied alpha Fixes #151210 by premultiplying alpha in the rare case we get straight alpha. --- lib/ui/painting/image_decoder_impeller.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index 7060d33dcb612..76a5b25202f14 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -205,6 +205,25 @@ DecompressResult ImageDecoderImpeller::DecompressTexture( bitmap->setImmutable(); } + // If the image is unpremultiplied, fix it. + if (alpha_type == SkAlphaType::kUnpremul_SkAlphaType) { + // Single copy of ImpellerAllocator crashes. + auto premul_allocator = std::make_shared(allocator); + auto premul_bitmap = std::make_shared(); + premul_bitmap->setInfo(bitmap->info().makeAlphaType(kPremul_SkAlphaType)); + if (!premul_bitmap->tryAllocPixels(premul_allocator.get())) { + std::string decode_error( + "Could not allocate intermediate for premultiplication conversion."); + FML_DLOG(ERROR) << decode_error; + return DecompressResult{.decode_error = decode_error}; + } + // readPixels() handles converting pixels to premultiplied form. + bitmap->readPixels(premul_bitmap->pixmap()); + premul_bitmap->setImmutable(); + bitmap_allocator = premul_allocator; + bitmap = premul_bitmap; + } + if (bitmap->dimensions() == target_size) { std::shared_ptr buffer = bitmap_allocator->GetDeviceBuffer(); From 43f4d9ebb76c3f5f94620cacdf780c9000664ca6 Mon Sep 17 00:00:00 2001 From: John McDole Date: Tue, 9 Jul 2024 16:06:33 -0700 Subject: [PATCH 2/2] Add test for straight->premultiplied alpha in impeller --- lib/ui/BUILD.gn | 1 + lib/ui/fixtures/unmultiplied_alpha.png | Bin 0 -> 104 bytes .../painting/image_decoder_no_gl_unittests.cc | 37 ++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 lib/ui/fixtures/unmultiplied_alpha.png diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index f512b191ae05f..e4a24a0d9630d 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -237,6 +237,7 @@ if (enable_unittests) { "fixtures/hello_loop_2.gif", "fixtures/hello_loop_2.webp", "fixtures/FontManifest.json", + "fixtures/unmultiplied_alpha.png", "fixtures/WideGamutIndexed.png", "//flutter/third_party/txt/third_party/fonts/Roboto-Medium.ttf", ] diff --git a/lib/ui/fixtures/unmultiplied_alpha.png b/lib/ui/fixtures/unmultiplied_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..0ad70cd1d423ebf7f2c59abde87ab1df0ea79b57 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqh9Er&xK0ulgh#9u%zFYvLq&;06 wLn;`Pf1E#Xz(Xf(L4T40J2Rj5QD*UT3}sg)o}ciw%o?QJ)78&qol`;+08A$ucmMzZ literal 0 HcmV?d00001 diff --git a/lib/ui/painting/image_decoder_no_gl_unittests.cc b/lib/ui/painting/image_decoder_no_gl_unittests.cc index 975282328b48b..d935fa2e3e9f9 100644 --- a/lib/ui/painting/image_decoder_no_gl_unittests.cc +++ b/lib/ui/painting/image_decoder_no_gl_unittests.cc @@ -5,6 +5,7 @@ #include "flutter/lib/ui/painting/image_decoder_no_gl_unittests.h" #include "flutter/fml/endianness.h" +#include "include/core/SkColorType.h" namespace flutter { namespace testing { @@ -186,5 +187,41 @@ TEST(ImageDecoderNoGLTest, ImpellerWideGamutIndexedPng) { #endif // IMPELLER_SUPPORTS_RENDERING } +TEST(ImageDecoderNoGLTest, ImepllerUnmultipliedAlphaPng) { +#if defined(OS_FUCHSIA) + GTEST_SKIP() << "Fuchsia can't load the test fixtures."; +#endif + auto data = flutter::testing::OpenFixtureAsSkData("unmultiplied_alpha.png"); + auto image = SkImages::DeferredFromEncodedData(data); + ASSERT_TRUE(image != nullptr); + ASSERT_EQ(SkISize::Make(11, 11), image->dimensions()); + + ImageGeneratorRegistry registry; + std::shared_ptr generator = + registry.CreateCompatibleGenerator(data); + ASSERT_TRUE(generator); + + auto descriptor = fml::MakeRefCounted(std::move(data), + std::move(generator)); + +#if IMPELLER_SUPPORTS_RENDERING + std::shared_ptr allocator = + std::make_shared(); + std::optional result = + ImageDecoderImpeller::DecompressTexture( + descriptor.get(), SkISize::Make(11, 11), {11, 11}, + /*supports_wide_gamut=*/true, allocator); + ASSERT_EQ(result->image_info.colorType(), kRGBA_8888_SkColorType); + + const SkPixmap& pixmap = result->sk_bitmap->pixmap(); + const uint32_t* pixel_ptr = static_cast(pixmap.addr()); + // Test the upper left pixel is premultiplied and not solid red. + ASSERT_EQ(*pixel_ptr, (uint32_t)0x1000001); + // Test a pixel in the green box is still green. + ASSERT_EQ(*(pixel_ptr + 11 * 4 + 4), (uint32_t)0xFF00FF00); + +#endif // IMPELLER_SUPPORTS_RENDERING +} + } // namespace testing } // namespace flutter