diff --git a/engine/src/flutter/impeller/image/BUILD.gn b/engine/src/flutter/impeller/image/BUILD.gn index 5475257810b..0d61d2deeb7 100644 --- a/engine/src/flutter/impeller/image/BUILD.gn +++ b/engine/src/flutter/impeller/image/BUILD.gn @@ -5,14 +5,19 @@ import("//flutter/impeller/tools/impeller.gni") impeller_component("image") { - sources = [ - "compressed_image.cc", + public = [ "compressed_image.h", - "decompressed_image.cc", "decompressed_image.h", ] - deps = [ "../third_party/stb" ] + sources = [ + "backends/skia/compressed_image_skia.cc", + "backends/skia/compressed_image_skia.h", + "compressed_image.cc", + "decompressed_image.cc", + ] + + deps = [ "//third_party/skia" ] public_deps = [ "../base", diff --git a/engine/src/flutter/impeller/image/backends/skia/compressed_image_skia.cc b/engine/src/flutter/impeller/image/backends/skia/compressed_image_skia.cc new file mode 100644 index 00000000000..0b3fc9da192 --- /dev/null +++ b/engine/src/flutter/impeller/image/backends/skia/compressed_image_skia.cc @@ -0,0 +1,73 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/image/backends/skia/compressed_image_skia.h" + +#include + +#include "impeller/base/validation.h" +#include "third_party/skia/include/core/SkData.h" +#include "third_party/skia/include/core/SkImageGenerator.h" +#include "third_party/skia/include/core/SkPixmap.h" + +namespace impeller { + +CompressedImageSkia::CompressedImageSkia( + std::shared_ptr allocation) + : CompressedImage(std::move(allocation)) {} + +CompressedImageSkia::~CompressedImageSkia() = default; + +// |CompressedImage| +DecompressedImage CompressedImageSkia::Decode() const { + if (!IsValid()) { + return {}; + } + if (source_->GetSize() == 0u) { + return {}; + } + + auto src = new std::shared_ptr(source_); + auto sk_data = SkData::MakeWithProc( + source_->GetMapping(), source_->GetSize(), + [](const void* ptr, void* context) { + delete reinterpret_cast(context); + }, + src); + + auto generator = SkImageGenerator::MakeFromEncoded(sk_data); + if (!generator) { + return {}; + } + + auto info = SkImageInfo::MakeN32Premul(generator->getInfo().dimensions()); + + auto bitmap = std::make_shared(); + if (!bitmap->tryAllocPixels(info)) { + VALIDATION_LOG << "Could not allocate arena for decompressing image."; + return {}; + } + + if (!generator->getPixels(bitmap->pixmap())) { + VALIDATION_LOG << "Could not decompress image into arena."; + return {}; + } + + auto mapping = std::make_shared( + reinterpret_cast(bitmap->pixmap().addr()), // data + bitmap->pixmap().rowBytes() * bitmap->pixmap().height(), // size + [bitmap](const uint8_t* data, size_t size) mutable { + bitmap.reset(); + } // proc + ); + + return { + {bitmap->pixmap().dimensions().fWidth, + bitmap->pixmap().dimensions().fHeight}, // size + DecompressedImage::Format::kRGBA, // format + mapping // allocation + }; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/image/backends/skia/compressed_image_skia.h b/engine/src/flutter/impeller/image/backends/skia/compressed_image_skia.h new file mode 100644 index 00000000000..856c5304cc3 --- /dev/null +++ b/engine/src/flutter/impeller/image/backends/skia/compressed_image_skia.h @@ -0,0 +1,25 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "flutter/fml/macros.h" +#include "impeller/image/compressed_image.h" + +namespace impeller { + +class CompressedImageSkia final : public CompressedImage { + public: + CompressedImageSkia(std::shared_ptr allocation); + + ~CompressedImageSkia() override; + + // |CompressedImage| + DecompressedImage Decode() const override; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(CompressedImageSkia); +}; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/image/compressed_image.cc b/engine/src/flutter/impeller/image/compressed_image.cc index 0837be17e24..15b4e01487b 100644 --- a/engine/src/flutter/impeller/image/compressed_image.cc +++ b/engine/src/flutter/impeller/image/compressed_image.cc @@ -4,83 +4,24 @@ #include "impeller/image/compressed_image.h" -#include - -#include "impeller/base/validation.h" +#include "impeller/image/backends/skia/compressed_image_skia.h" namespace impeller { -CompressedImage::CompressedImage( - std::shared_ptr sourceAllocation) - : source_(std::move(sourceAllocation)) {} +std::shared_ptr CompressedImage::Create( + std::shared_ptr allocation) { + // There is only one backend today. + if (!allocation) { + return nullptr; + } + return std::make_shared(std::move(allocation)); +} + +CompressedImage::CompressedImage(std::shared_ptr allocation) + : source_(std::move(allocation)) {} CompressedImage::~CompressedImage() = default; -DecompressedImage CompressedImage::Decode() const { - if (!source_) { - return {}; - } - - int width = 0; - int height = 0; - int comps = 0; - - stbi_uc* decoded = - ::stbi_load_from_memory(source_->GetMapping(), // Source Data - source_->GetSize(), // Source Data Size - &width, // Out: Width - &height, // Out: Height - &comps, // Out: Components - STBI_default); - - if (decoded == nullptr) { - VALIDATION_LOG << "Could not decode image from host memory."; - return {}; - } - - auto dest_allocation = std::make_shared( - decoded, // bytes - width * height * comps * sizeof(stbi_uc), // byte size - [](const uint8_t* data, size_t size) { - ::stbi_image_free(const_cast(data)); - } // release proc - ); - - /* - * Make sure we got a valid component set. - */ - auto components = DecompressedImage::Format::kInvalid; - - switch (comps) { - case STBI_grey: - components = DecompressedImage::Format::kGrey; - break; - case STBI_grey_alpha: - components = DecompressedImage::Format::kGreyAlpha; - break; - case STBI_rgb: - components = DecompressedImage::Format::kRGB; - break; - case STBI_rgb_alpha: - components = DecompressedImage::Format::kRGBA; - break; - default: - components = DecompressedImage::Format::kInvalid; - break; - } - - if (components == DecompressedImage::Format::kInvalid) { - VALIDATION_LOG << "Could not detect image components when decoding."; - return {}; - } - - return DecompressedImage{ - ISize{width, height}, // size - components, // components - std::move(dest_allocation) // allocation - }; -} - bool CompressedImage::IsValid() const { return static_cast(source_); } diff --git a/engine/src/flutter/impeller/image/compressed_image.h b/engine/src/flutter/impeller/image/compressed_image.h index 7b79096f3d3..58c5a5050d6 100644 --- a/engine/src/flutter/impeller/image/compressed_image.h +++ b/engine/src/flutter/impeller/image/compressed_image.h @@ -4,6 +4,8 @@ #pragma once +#include + #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" #include "impeller/geometry/size.h" @@ -15,16 +17,19 @@ class ImageSource; class CompressedImage { public: - CompressedImage(std::shared_ptr sourceAllocation); + static std::shared_ptr Create( + std::shared_ptr allocation); - ~CompressedImage(); + virtual ~CompressedImage(); - [[nodiscard]] DecompressedImage Decode() const; + [[nodiscard]] virtual DecompressedImage Decode() const = 0; bool IsValid() const; - private: - std::shared_ptr source_; + protected: + const std::shared_ptr source_; + + CompressedImage(std::shared_ptr allocation); }; } // namespace impeller diff --git a/engine/src/flutter/impeller/playground/playground.mm b/engine/src/flutter/impeller/playground/playground.mm index 52b2c11599e..be65b582ad6 100644 --- a/engine/src/flutter/impeller/playground/playground.mm +++ b/engine/src/flutter/impeller/playground/playground.mm @@ -195,14 +195,18 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) { std::shared_ptr Playground::CreateTextureForFixture( const char* fixture_name) const { - CompressedImage compressed_image( + auto compressed_image = CompressedImage::Create( flutter::testing::OpenFixtureAsMapping(fixture_name)); + if (!compressed_image) { + VALIDATION_LOG << "Could not create compressed image."; + return nullptr; + } // The decoded image is immediately converted into RGBA as that format is // known to be supported everywhere. For image sources that don't need 32 // bit pixel strides, this is overkill. Since this is a test fixture we // aren't necessarily trying to eke out memory savings here and instead // favor simplicity. - auto image = compressed_image.Decode().ConvertToRGBA(); + auto image = compressed_image->Decode().ConvertToRGBA(); if (!image.IsValid()) { VALIDATION_LOG << "Could not find fixture named " << fixture_name; return nullptr;