Skip to content

Commit

Permalink
Avoid depending on STB in //flutter/impeller/image. (flutter#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
chinmaygarde authored and dnfield committed Apr 27, 2022
1 parent a781e2f commit 555faba
Show file tree
Hide file tree
Showing 365 changed files with 133 additions and 78,302 deletions.
11 changes: 8 additions & 3 deletions impeller/image/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@
import("//flutter/impeller/tools/impeller.gni")

impeller_component("image") {
public = [
"compressed_image.h",
"decompressed_image.h",
]

sources = [
"backends/skia/compressed_image_skia.cc",
"backends/skia/compressed_image_skia.h",
"compressed_image.cc",
"compressed_image.h",
"decompressed_image.cc",
"decompressed_image.h",
]

deps = [ "../third_party/stb" ]
deps = [ "//third_party/skia" ]

public_deps = [
"../base",
Expand Down
73 changes: 73 additions & 0 deletions impeller/image/backends/skia/compressed_image_skia.cc
Original file line number Diff line number Diff line change
@@ -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 <memory>

#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<const fml::Mapping> 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<const fml::Mapping>(source_);
auto sk_data = SkData::MakeWithProc(
source_->GetMapping(), source_->GetSize(),
[](const void* ptr, void* context) {
delete reinterpret_cast<decltype(src)>(context);
},
src);

auto generator = SkImageGenerator::MakeFromEncoded(sk_data);
if (!generator) {
return {};
}

auto info = SkImageInfo::MakeN32Premul(generator->getInfo().dimensions());

auto bitmap = std::make_shared<SkBitmap>();
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<fml::NonOwnedMapping>(
reinterpret_cast<const uint8_t*>(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
25 changes: 25 additions & 0 deletions impeller/image/backends/skia/compressed_image_skia.h
Original file line number Diff line number Diff line change
@@ -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<const fml::Mapping> allocation);

~CompressedImageSkia() override;

// |CompressedImage|
DecompressedImage Decode() const override;

private:
FML_DISALLOW_COPY_AND_ASSIGN(CompressedImageSkia);
};

} // namespace impeller
81 changes: 11 additions & 70 deletions impeller/image/compressed_image.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,82 +4,23 @@

#include "impeller/image/compressed_image.h"

#include <stb_image.h>

#include "impeller/base/validation.h"
#include "impeller/image/backends/skia/compressed_image_skia.h"

namespace impeller {

CompressedImage::CompressedImage(
std::shared_ptr<const fml::Mapping> sourceAllocation)
: source_(std::move(sourceAllocation)) {}

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<const fml::NonOwnedMapping>(
decoded, // bytes
width * height * comps * sizeof(stbi_uc), // byte size
[](const uint8_t* data, size_t size) {
::stbi_image_free(const_cast<uint8_t*>(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;
std::shared_ptr<CompressedImage> CompressedImage::Create(
std::shared_ptr<const fml::Mapping> allocation) {
// There is only one backend today.
if (!allocation) {
return nullptr;
}
return std::make_shared<CompressedImageSkia>(std::move(allocation));
}

if (components == DecompressedImage::Format::kInvalid) {
VALIDATION_LOG << "Could not detect image components when decoding.";
return {};
}
CompressedImage::CompressedImage(std::shared_ptr<const fml::Mapping> allocation)
: source_(std::move(allocation)) {}

return DecompressedImage{
ISize{width, height}, // size
components, // components
std::move(dest_allocation) // allocation
};
}
CompressedImage::~CompressedImage() = default;

bool CompressedImage::IsValid() const {
return static_cast<bool>(source_);
Expand Down
15 changes: 10 additions & 5 deletions impeller/image/compressed_image.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#pragma once

#include <memory>

#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
#include "impeller/geometry/size.h"
Expand All @@ -15,16 +17,19 @@ class ImageSource;

class CompressedImage {
public:
CompressedImage(std::shared_ptr<const fml::Mapping> sourceAllocation);
static std::shared_ptr<CompressedImage> Create(
std::shared_ptr<const fml::Mapping> allocation);

~CompressedImage();
virtual ~CompressedImage();

[[nodiscard]] DecompressedImage Decode() const;
[[nodiscard]] virtual DecompressedImage Decode() const = 0;

bool IsValid() const;

private:
std::shared_ptr<const fml::Mapping> source_;
protected:
const std::shared_ptr<const fml::Mapping> source_;

CompressedImage(std::shared_ptr<const fml::Mapping> allocation);
};

} // namespace impeller
8 changes: 6 additions & 2 deletions impeller/playground/playground.mm
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,18 @@ static void PlaygroundKeyCallback(GLFWwindow* window,

std::shared_ptr<Texture> 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;
Expand Down
12 changes: 0 additions & 12 deletions impeller/third_party/stb/BUILD.gn

This file was deleted.

11 changes: 0 additions & 11 deletions impeller/third_party/stb/STBImplementation.c

This file was deleted.

Loading

0 comments on commit 555faba

Please sign in to comment.