From 62596a40e72ce313bb4ddbcc6653d2dd75fc1e98 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Thu, 2 Jun 2022 11:16:31 -0700 Subject: [PATCH] [Impeller] Decode images at nearest supported size, and then resize of necessary. (flutter/engine#33767) --- .../lib/ui/painting/image_decoder_impeller.cc | 45 +++++++++++++++++-- .../lib/ui/painting/image_decoder_impeller.h | 4 ++ .../ui/painting/image_decoder_unittests.cc | 6 +++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc b/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc index e05b95f5920..30b8c216621 100644 --- a/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc +++ b/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc @@ -4,6 +4,8 @@ #include "flutter/lib/ui/painting/image_decoder_impeller.h" +#include + #include "flutter/fml/closure.h" #include "flutter/fml/make_copyable.h" #include "flutter/fml/trace_event.h" @@ -13,6 +15,7 @@ #include "flutter/impeller/renderer/texture.h" #include "flutter/lib/ui/painting/image_decoder_skia.h" #include "impeller/base/strings.h" +#include "include/core/SkSize.h" #include "third_party/skia/include/core/SkPixmap.h" namespace flutter { @@ -53,8 +56,9 @@ static std::optional ToPixelFormat(SkColorType type) { return std::nullopt; } -static std::shared_ptr DecompressTexture(ImageDescriptor* descriptor, - SkISize target_size) { +std::shared_ptr ImageDecoderImpeller::DecompressTexture( + ImageDescriptor* descriptor, + SkISize target_size) { TRACE_EVENT0("impeller", __FUNCTION__); if (!descriptor) { FML_DLOG(ERROR) << "Invalid descriptor."; @@ -67,9 +71,18 @@ static std::shared_ptr DecompressTexture(ImageDescriptor* descriptor, return nullptr; } + const SkISize source_size = descriptor->image_info().dimensions(); + auto decode_size = descriptor->get_scaled_dimensions(std::max( + static_cast(target_size.width()) / source_size.width(), + static_cast(target_size.height()) / source_size.height())); + + //---------------------------------------------------------------------------- + /// 1. Decode the image into the image generator's closest supported size. + /// + const auto base_image_info = descriptor->image_info(); const auto image_info = - base_image_info.makeWH(target_size.width(), target_size.height()) + base_image_info.makeWH(decode_size.width(), decode_size.height()) .makeColorType(ChooseCompatibleColorType(base_image_info.colorType())) .makeAlphaType( ChooseCompatibleAlphaType(base_image_info.alphaType())); @@ -92,7 +105,31 @@ static std::shared_ptr DecompressTexture(ImageDescriptor* descriptor, return nullptr; } - return bitmap; + if (decode_size == target_size) { + return bitmap; + } + + //---------------------------------------------------------------------------- + /// 2. If the decoded image isn't the requested target size, resize it. + /// + + TRACE_EVENT0("impeller", "DecodeScale"); + const auto scaled_image_info = image_info.makeDimensions(target_size); + + auto scaled_bitmap = std::make_shared(); + if (!scaled_bitmap->tryAllocPixels(scaled_image_info)) { + FML_LOG(ERROR) + << "Could not allocate scaled bitmap for image decompression."; + return nullptr; + } + if (!bitmap->pixmap().scalePixels( + scaled_bitmap->pixmap(), + SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone))) { + FML_LOG(ERROR) << "Could not scale decoded bitmap data."; + } + scaled_bitmap->setImmutable(); + + return scaled_bitmap; } static sk_sp UploadTexture(std::shared_ptr context, diff --git a/engine/src/flutter/lib/ui/painting/image_decoder_impeller.h b/engine/src/flutter/lib/ui/painting/image_decoder_impeller.h index 47a1bfde60d..c5d38c13549 100644 --- a/engine/src/flutter/lib/ui/painting/image_decoder_impeller.h +++ b/engine/src/flutter/lib/ui/painting/image_decoder_impeller.h @@ -31,6 +31,10 @@ class ImageDecoderImpeller final : public ImageDecoder { uint32_t target_height, const ImageResult& result) override; + static std::shared_ptr DecompressTexture( + ImageDescriptor* descriptor, + SkISize target_size); + private: using FutureContext = std::shared_future>; FutureContext context_; diff --git a/engine/src/flutter/lib/ui/painting/image_decoder_unittests.cc b/engine/src/flutter/lib/ui/painting/image_decoder_unittests.cc index 0c56b17c4e3..f6d7cb7696f 100644 --- a/engine/src/flutter/lib/ui/painting/image_decoder_unittests.cc +++ b/engine/src/flutter/lib/ui/painting/image_decoder_unittests.cc @@ -6,6 +6,7 @@ #include "flutter/fml/mapping.h" #include "flutter/fml/synchronization/waitable_event.h" #include "flutter/lib/ui/painting/image_decoder.h" +#include "flutter/lib/ui/painting/image_decoder_impeller.h" #include "flutter/lib/ui/painting/image_decoder_skia.h" #include "flutter/lib/ui/painting/multi_frame_codec.h" #include "flutter/runtime/dart_vm.h" @@ -586,6 +587,11 @@ TEST(ImageDecoderTest, VerifySimpleDecoding) { descriptor.get(), 6, 2, fml::tracing::TraceFlow("")) ->dimensions(), SkISize::Make(6, 2)); + + ASSERT_EQ(ImageDecoderImpeller::DecompressTexture(descriptor.get(), + SkISize::Make(6, 2)) + ->dimensions(), + SkISize::Make(6, 2)); } TEST(ImageDecoderTest, VerifySubpixelDecodingPreservesExifOrientation) {