mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Adds test to verify wide gamut indexed png decompression fix for Skia. (flutter/engine#45399)
fixes https://github.com/flutter/flutter/issues/133013 depends on skia fix: https://skia-review.googlesource.com/c/skia/+/751696 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
This commit is contained in:
parent
357107d9a8
commit
47da5d4f07
@ -189,6 +189,8 @@
|
||||
../../../flutter/lib/ui/compositing/scene_builder_unittests.cc
|
||||
../../../flutter/lib/ui/fixtures
|
||||
../../../flutter/lib/ui/hooks_unittests.cc
|
||||
../../../flutter/lib/ui/painting/image_decoder_no_gl_unittests.cc
|
||||
../../../flutter/lib/ui/painting/image_decoder_no_gl_unittests.h
|
||||
../../../flutter/lib/ui/painting/image_decoder_unittests.cc
|
||||
../../../flutter/lib/ui/painting/image_dispose_unittests.cc
|
||||
../../../flutter/lib/ui/painting/image_encoding_unittests.cc
|
||||
|
||||
@ -233,6 +233,7 @@ if (enable_unittests) {
|
||||
"fixtures/hello_loop_2.gif",
|
||||
"fixtures/hello_loop_2.webp",
|
||||
"fixtures/FontManifest.json",
|
||||
"fixtures/WideGamutIndexed.png",
|
||||
"//flutter/third_party/txt/third_party/fonts/Roboto-Medium.ttf",
|
||||
]
|
||||
}
|
||||
@ -262,6 +263,8 @@ if (enable_unittests) {
|
||||
sources = [
|
||||
"compositing/scene_builder_unittests.cc",
|
||||
"hooks_unittests.cc",
|
||||
"painting/image_decoder_no_gl_unittests.cc",
|
||||
"painting/image_decoder_no_gl_unittests.h",
|
||||
"painting/image_dispose_unittests.cc",
|
||||
"painting/image_encoding_unittests.cc",
|
||||
"painting/image_generator_registry_unittests.cc",
|
||||
|
||||
BIN
engine/src/flutter/lib/ui/fixtures/WideGamutIndexed.png
Normal file
BIN
engine/src/flutter/lib/ui/fixtures/WideGamutIndexed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,220 @@
|
||||
// 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 "flutter/lib/ui/painting/image_decoder_no_gl_unittests.h"
|
||||
|
||||
#include "flutter/fml/endianness.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
// Tests are disabled for fuchsia.
|
||||
#if defined(OS_FUCHSIA)
|
||||
#pragma GCC diagnostic ignored "-Wunreachable-code"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsPngWithPLTE(const uint8_t* bytes, size_t size) {
|
||||
constexpr std::string_view kPngMagic = "\x89PNG\x0d\x0a\x1a\x0a";
|
||||
constexpr std::string_view kPngPlte = "PLTE";
|
||||
constexpr uint32_t kLengthBytes = 4;
|
||||
constexpr uint32_t kTypeBytes = 4;
|
||||
constexpr uint32_t kCrcBytes = 4;
|
||||
|
||||
if (size < kPngMagic.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(bytes, kPngMagic.data(), kPngMagic.size()) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t* end = bytes + size;
|
||||
const uint8_t* loc = bytes + kPngMagic.size();
|
||||
while (loc + kLengthBytes + kTypeBytes <= end) {
|
||||
uint32_t chunk_length =
|
||||
fml::BigEndianToArch(*reinterpret_cast<const uint32_t*>(loc));
|
||||
|
||||
if (memcmp(loc + kLengthBytes, kPngPlte.data(), kPngPlte.size()) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
loc += kLengthBytes + kTypeBytes + chunk_length + kCrcBytes;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
float HalfToFloat(uint16_t half) {
|
||||
switch (half) {
|
||||
case 0x7c00:
|
||||
return std::numeric_limits<float>::infinity();
|
||||
case 0xfc00:
|
||||
return -std::numeric_limits<float>::infinity();
|
||||
}
|
||||
bool negative = half >> 15;
|
||||
uint16_t exponent = (half >> 10) & 0x1f;
|
||||
uint16_t fraction = half & 0x3ff;
|
||||
float fExponent = exponent - 15.0f;
|
||||
float fFraction = static_cast<float>(fraction) / 1024.f;
|
||||
float pow_value = powf(2.0f, fExponent);
|
||||
return (negative ? -1.f : 1.f) * pow_value * (1.0f + fFraction);
|
||||
}
|
||||
|
||||
float DecodeBGR10(uint32_t x) {
|
||||
const float max = 1.25098f;
|
||||
const float min = -0.752941f;
|
||||
const float intercept = min;
|
||||
const float slope = (max - min) / 1024.0f;
|
||||
return (x * slope) + intercept;
|
||||
}
|
||||
|
||||
sk_sp<SkData> OpenFixtureAsSkData(const char* name) {
|
||||
auto fixtures_directory =
|
||||
fml::OpenDirectory(GetFixturesPath(), false, fml::FilePermission::kRead);
|
||||
if (!fixtures_directory.is_valid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto fixture_mapping =
|
||||
fml::FileMapping::CreateReadOnly(fixtures_directory, name);
|
||||
|
||||
if (!fixture_mapping) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkData::ReleaseProc on_release = [](const void* ptr, void* context) -> void {
|
||||
delete reinterpret_cast<fml::FileMapping*>(context);
|
||||
};
|
||||
|
||||
auto data = SkData::MakeWithProc(fixture_mapping->GetMapping(),
|
||||
fixture_mapping->GetSize(), on_release,
|
||||
fixture_mapping.get());
|
||||
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
// The data is now owned by Skia.
|
||||
fixture_mapping.release();
|
||||
return data;
|
||||
}
|
||||
|
||||
TEST(ImageDecoderNoGLTest, ImpellerWideGamutDisplayP3) {
|
||||
#if defined(OS_FUCHSIA)
|
||||
GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
|
||||
#endif
|
||||
auto data = OpenFixtureAsSkData("DisplayP3Logo.png");
|
||||
auto image = SkImages::DeferredFromEncodedData(data);
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
ASSERT_EQ(SkISize::Make(100, 100), image->dimensions());
|
||||
|
||||
ImageGeneratorRegistry registry;
|
||||
std::shared_ptr<ImageGenerator> generator =
|
||||
registry.CreateCompatibleGenerator(data);
|
||||
ASSERT_TRUE(generator);
|
||||
|
||||
auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
|
||||
std::move(generator));
|
||||
|
||||
ASSERT_FALSE(
|
||||
IsPngWithPLTE(descriptor->data()->bytes(), descriptor->data()->size()));
|
||||
|
||||
#if IMPELLER_SUPPORTS_RENDERING
|
||||
std::shared_ptr<impeller::Allocator> allocator =
|
||||
std::make_shared<impeller::TestImpellerAllocator>();
|
||||
std::optional<DecompressResult> wide_result =
|
||||
ImageDecoderImpeller::DecompressTexture(
|
||||
descriptor.get(), SkISize::Make(100, 100), {100, 100},
|
||||
/*supports_wide_gamut=*/true, allocator);
|
||||
ASSERT_TRUE(wide_result.has_value());
|
||||
ASSERT_EQ(wide_result->image_info.colorType(), kRGBA_F16_SkColorType);
|
||||
ASSERT_TRUE(wide_result->image_info.colorSpace()->isSRGB());
|
||||
|
||||
const SkPixmap& wide_pixmap = wide_result->sk_bitmap->pixmap();
|
||||
const uint16_t* half_ptr = static_cast<const uint16_t*>(wide_pixmap.addr());
|
||||
bool found_deep_red = false;
|
||||
for (int i = 0; i < wide_pixmap.width() * wide_pixmap.height(); ++i) {
|
||||
float red = HalfToFloat(*half_ptr++);
|
||||
float green = HalfToFloat(*half_ptr++);
|
||||
float blue = HalfToFloat(*half_ptr++);
|
||||
half_ptr++; // alpha
|
||||
if (fabsf(red - 1.0931f) < 0.01f && fabsf(green - -0.2268f) < 0.01f &&
|
||||
fabsf(blue - -0.1501f) < 0.01f) {
|
||||
found_deep_red = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(found_deep_red);
|
||||
std::optional<DecompressResult> narrow_result =
|
||||
ImageDecoderImpeller::DecompressTexture(
|
||||
descriptor.get(), SkISize::Make(100, 100), {100, 100},
|
||||
/*supports_wide_gamut=*/false, allocator);
|
||||
|
||||
ASSERT_TRUE(narrow_result.has_value());
|
||||
ASSERT_EQ(narrow_result->image_info.colorType(), kRGBA_8888_SkColorType);
|
||||
#endif // IMPELLER_SUPPORTS_RENDERING
|
||||
}
|
||||
|
||||
TEST(ImageDecoderNoGLTest, ImpellerWideGamutIndexedPng) {
|
||||
#if defined(OS_FUCHSIA)
|
||||
GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
|
||||
#endif
|
||||
auto data = OpenFixtureAsSkData("WideGamutIndexed.png");
|
||||
auto image = SkImages::DeferredFromEncodedData(data);
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
ASSERT_EQ(SkISize::Make(100, 100), image->dimensions());
|
||||
|
||||
ImageGeneratorRegistry registry;
|
||||
std::shared_ptr<ImageGenerator> generator =
|
||||
registry.CreateCompatibleGenerator(data);
|
||||
ASSERT_TRUE(generator);
|
||||
|
||||
auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
|
||||
std::move(generator));
|
||||
|
||||
ASSERT_TRUE(
|
||||
IsPngWithPLTE(descriptor->data()->bytes(), descriptor->data()->size()));
|
||||
|
||||
#if IMPELLER_SUPPORTS_RENDERING
|
||||
std::shared_ptr<impeller::Allocator> allocator =
|
||||
std::make_shared<impeller::TestImpellerAllocator>();
|
||||
std::optional<DecompressResult> wide_result =
|
||||
ImageDecoderImpeller::DecompressTexture(
|
||||
descriptor.get(), SkISize::Make(100, 100), {100, 100},
|
||||
/*supports_wide_gamut=*/true, allocator);
|
||||
ASSERT_EQ(wide_result->image_info.colorType(), kBGR_101010x_XR_SkColorType);
|
||||
ASSERT_TRUE(wide_result->image_info.colorSpace()->isSRGB());
|
||||
|
||||
const SkPixmap& wide_pixmap = wide_result->sk_bitmap->pixmap();
|
||||
const uint32_t* pixel_ptr = static_cast<const uint32_t*>(wide_pixmap.addr());
|
||||
bool found_deep_red = false;
|
||||
for (int i = 0; i < wide_pixmap.width() * wide_pixmap.height(); ++i) {
|
||||
uint32_t pixel = *pixel_ptr++;
|
||||
float blue = DecodeBGR10((pixel >> 0) & 0x3ff);
|
||||
float green = DecodeBGR10((pixel >> 10) & 0x3ff);
|
||||
float red = DecodeBGR10((pixel >> 20) & 0x3ff);
|
||||
if (fabsf(red - 1.0931f) < 0.01f && fabsf(green - -0.2268f) < 0.01f &&
|
||||
fabsf(blue - -0.1501f) < 0.01f) {
|
||||
found_deep_red = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(found_deep_red);
|
||||
std::optional<DecompressResult> narrow_result =
|
||||
ImageDecoderImpeller::DecompressTexture(
|
||||
descriptor.get(), SkISize::Make(100, 100), {100, 100},
|
||||
/*supports_wide_gamut=*/false, allocator);
|
||||
|
||||
ASSERT_TRUE(narrow_result.has_value());
|
||||
ASSERT_EQ(narrow_result->image_info.colorType(), kRGBA_8888_SkColorType);
|
||||
#endif // IMPELLER_SUPPORTS_RENDERING
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
@ -0,0 +1,102 @@
|
||||
// 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 <stdint.h>
|
||||
|
||||
#include "flutter/impeller/core/allocator.h"
|
||||
#include "flutter/impeller/core/device_buffer.h"
|
||||
#include "flutter/impeller/core/formats.h"
|
||||
#include "flutter/impeller/geometry/size.h"
|
||||
#include "flutter/lib/ui/painting/image_decoder.h"
|
||||
#include "flutter/lib/ui/painting/image_decoder_impeller.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class TestImpellerTexture : public Texture {
|
||||
public:
|
||||
explicit TestImpellerTexture(TextureDescriptor desc) : Texture(desc) {}
|
||||
|
||||
void SetLabel(std::string_view label) override {}
|
||||
bool IsValid() const override { return true; }
|
||||
ISize GetSize() const { return GetTextureDescriptor().size; }
|
||||
|
||||
bool OnSetContents(const uint8_t* contents, size_t length, size_t slice) {
|
||||
return true;
|
||||
}
|
||||
bool OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
|
||||
size_t slice) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class TestImpellerDeviceBuffer : public DeviceBuffer {
|
||||
public:
|
||||
explicit TestImpellerDeviceBuffer(DeviceBufferDescriptor desc)
|
||||
: DeviceBuffer(desc) {
|
||||
bytes_ = static_cast<uint8_t*>(malloc(desc.size));
|
||||
}
|
||||
|
||||
~TestImpellerDeviceBuffer() { free(bytes_); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Texture> AsTexture(Allocator& allocator,
|
||||
const TextureDescriptor& descriptor,
|
||||
uint16_t row_bytes) const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SetLabel(const std::string& label) override { return true; }
|
||||
|
||||
bool SetLabel(const std::string& label, Range range) override { return true; }
|
||||
|
||||
uint8_t* OnGetContents() const override { return bytes_; }
|
||||
|
||||
bool OnCopyHostBuffer(const uint8_t* source,
|
||||
Range source_range,
|
||||
size_t offset) override {
|
||||
for (auto i = source_range.offset; i < source_range.length; i++, offset++) {
|
||||
bytes_[offset] = source[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t* bytes_;
|
||||
};
|
||||
|
||||
class TestImpellerAllocator : public impeller::Allocator {
|
||||
public:
|
||||
TestImpellerAllocator() {}
|
||||
|
||||
~TestImpellerAllocator() = default;
|
||||
|
||||
private:
|
||||
uint16_t MinimumBytesPerRow(PixelFormat format) const override { return 0; }
|
||||
|
||||
ISize GetMaxTextureSizeSupported() const override {
|
||||
return ISize{2048, 2048};
|
||||
}
|
||||
|
||||
std::shared_ptr<DeviceBuffer> OnCreateBuffer(
|
||||
const DeviceBufferDescriptor& desc) override {
|
||||
return std::make_shared<TestImpellerDeviceBuffer>(desc);
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> OnCreateTexture(
|
||||
const TextureDescriptor& desc) override {
|
||||
return std::make_shared<TestImpellerTexture>(desc);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
float HalfToFloat(uint16_t half);
|
||||
float DecodeBGR10(uint32_t x);
|
||||
sk_sp<SkData> OpenFixtureAsSkData(const char* name);
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
@ -11,6 +11,7 @@
|
||||
#include "flutter/impeller/renderer/context.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_no_gl_unittests.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"
|
||||
@ -34,81 +35,6 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class TestImpellerTexture : public Texture {
|
||||
public:
|
||||
explicit TestImpellerTexture(TextureDescriptor desc) : Texture(desc) {}
|
||||
|
||||
void SetLabel(std::string_view label) override {}
|
||||
bool IsValid() const override { return true; }
|
||||
ISize GetSize() const { return GetTextureDescriptor().size; }
|
||||
|
||||
bool OnSetContents(const uint8_t* contents, size_t length, size_t slice) {
|
||||
return true;
|
||||
}
|
||||
bool OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
|
||||
size_t slice) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class TestImpellerDeviceBuffer : public DeviceBuffer {
|
||||
public:
|
||||
explicit TestImpellerDeviceBuffer(DeviceBufferDescriptor desc)
|
||||
: DeviceBuffer(desc) {
|
||||
bytes_ = static_cast<uint8_t*>(malloc(desc.size));
|
||||
}
|
||||
|
||||
~TestImpellerDeviceBuffer() { free(bytes_); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Texture> AsTexture(Allocator& allocator,
|
||||
const TextureDescriptor& descriptor,
|
||||
uint16_t row_bytes) const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SetLabel(const std::string& label) override { return true; }
|
||||
|
||||
bool SetLabel(const std::string& label, Range range) override { return true; }
|
||||
|
||||
uint8_t* OnGetContents() const override { return bytes_; }
|
||||
|
||||
bool OnCopyHostBuffer(const uint8_t* source,
|
||||
Range source_range,
|
||||
size_t offset) override {
|
||||
for (auto i = source_range.offset; i < source_range.length; i++, offset++) {
|
||||
bytes_[offset] = source[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t* bytes_;
|
||||
};
|
||||
|
||||
class TestImpellerAllocator : public impeller::Allocator {
|
||||
public:
|
||||
TestImpellerAllocator() {}
|
||||
|
||||
~TestImpellerAllocator() = default;
|
||||
|
||||
private:
|
||||
uint16_t MinimumBytesPerRow(PixelFormat format) const override { return 0; }
|
||||
|
||||
ISize GetMaxTextureSizeSupported() const override {
|
||||
return ISize{2048, 2048};
|
||||
}
|
||||
|
||||
std::shared_ptr<DeviceBuffer> OnCreateBuffer(
|
||||
const DeviceBufferDescriptor& desc) override {
|
||||
return std::make_shared<TestImpellerDeviceBuffer>(desc);
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> OnCreateTexture(
|
||||
const TextureDescriptor& desc) override {
|
||||
return std::make_shared<TestImpellerTexture>(desc);
|
||||
}
|
||||
};
|
||||
|
||||
class TestImpellerContext : public impeller::Context {
|
||||
public:
|
||||
TestImpellerContext() = default;
|
||||
@ -240,36 +166,6 @@ class TestIOManager final : public IOManager {
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(TestIOManager);
|
||||
};
|
||||
|
||||
static sk_sp<SkData> OpenFixtureAsSkData(const char* name) {
|
||||
auto fixtures_directory =
|
||||
fml::OpenDirectory(GetFixturesPath(), false, fml::FilePermission::kRead);
|
||||
if (!fixtures_directory.is_valid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto fixture_mapping =
|
||||
fml::FileMapping::CreateReadOnly(fixtures_directory, name);
|
||||
|
||||
if (!fixture_mapping) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkData::ReleaseProc on_release = [](const void* ptr, void* context) -> void {
|
||||
delete reinterpret_cast<fml::FileMapping*>(context);
|
||||
};
|
||||
|
||||
auto data = SkData::MakeWithProc(fixture_mapping->GetMapping(),
|
||||
fixture_mapping->GetSize(), on_release,
|
||||
fixture_mapping.get());
|
||||
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
// The data is now owned by Skia.
|
||||
fixture_mapping.release();
|
||||
return data;
|
||||
}
|
||||
|
||||
class ImageDecoderFixtureTest : public FixtureTest {};
|
||||
|
||||
TEST_F(ImageDecoderFixtureTest, CanCreateImageDecoder) {
|
||||
@ -417,24 +313,6 @@ TEST_F(ImageDecoderFixtureTest, ValidImageResultsInSuccess) {
|
||||
latch.Wait();
|
||||
}
|
||||
|
||||
namespace {
|
||||
float HalfToFloat(uint16_t half) {
|
||||
switch (half) {
|
||||
case 0x7c00:
|
||||
return std::numeric_limits<float>::infinity();
|
||||
case 0xfc00:
|
||||
return -std::numeric_limits<float>::infinity();
|
||||
}
|
||||
bool negative = half >> 15;
|
||||
uint16_t exponent = (half >> 10) & 0x1f;
|
||||
uint16_t fraction = half & 0x3ff;
|
||||
float fExponent = exponent - 15.0f;
|
||||
float fFraction = static_cast<float>(fraction) / 1024.f;
|
||||
float pow_value = powf(2.0f, fExponent);
|
||||
return (negative ? -1.f : 1.f) * pow_value * (1.0f + fFraction);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_F(ImageDecoderFixtureTest, ImpellerUploadToSharedNoGpu) {
|
||||
#if !IMPELLER_SUPPORTS_RENDERING
|
||||
GTEST_SKIP() << "Impeller only test.";
|
||||
@ -491,57 +369,6 @@ TEST_F(ImageDecoderFixtureTest, ImpellerNullColorspace) {
|
||||
#endif // IMPELLER_SUPPORTS_RENDERING
|
||||
}
|
||||
|
||||
TEST_F(ImageDecoderFixtureTest, ImpellerWideGamutDisplayP3) {
|
||||
auto data = OpenFixtureAsSkData("DisplayP3Logo.png");
|
||||
auto image = SkImages::DeferredFromEncodedData(data);
|
||||
ASSERT_TRUE(image != nullptr);
|
||||
ASSERT_EQ(SkISize::Make(100, 100), image->dimensions());
|
||||
|
||||
ImageGeneratorRegistry registry;
|
||||
std::shared_ptr<ImageGenerator> generator =
|
||||
registry.CreateCompatibleGenerator(data);
|
||||
ASSERT_TRUE(generator);
|
||||
|
||||
auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
|
||||
std::move(generator));
|
||||
|
||||
#if IMPELLER_SUPPORTS_RENDERING
|
||||
std::shared_ptr<impeller::Allocator> allocator =
|
||||
std::make_shared<impeller::TestImpellerAllocator>();
|
||||
std::optional<DecompressResult> wide_result =
|
||||
ImageDecoderImpeller::DecompressTexture(
|
||||
descriptor.get(), SkISize::Make(100, 100), {100, 100},
|
||||
/*supports_wide_gamut=*/true, allocator);
|
||||
ASSERT_TRUE(wide_result.has_value());
|
||||
ASSERT_EQ(wide_result->image_info.colorType(), kRGBA_F16_SkColorType);
|
||||
ASSERT_TRUE(wide_result->image_info.colorSpace()->isSRGB());
|
||||
|
||||
const SkPixmap& wide_pixmap = wide_result->sk_bitmap->pixmap();
|
||||
const uint16_t* half_ptr = static_cast<const uint16_t*>(wide_pixmap.addr());
|
||||
bool found_deep_red = false;
|
||||
for (int i = 0; i < wide_pixmap.width() * wide_pixmap.height(); ++i) {
|
||||
float red = HalfToFloat(*half_ptr++);
|
||||
float green = HalfToFloat(*half_ptr++);
|
||||
float blue = HalfToFloat(*half_ptr++);
|
||||
half_ptr++; // alpha
|
||||
if (fabsf(red - 1.0931f) < 0.01f && fabsf(green - -0.2268f) < 0.01f &&
|
||||
fabsf(blue - -0.1501f) < 0.01f) {
|
||||
found_deep_red = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_TRUE(found_deep_red);
|
||||
std::optional<DecompressResult> narrow_result =
|
||||
ImageDecoderImpeller::DecompressTexture(
|
||||
descriptor.get(), SkISize::Make(100, 100), {100, 100},
|
||||
/*supports_wide_gamut=*/false, allocator);
|
||||
|
||||
ASSERT_TRUE(narrow_result.has_value());
|
||||
ASSERT_EQ(narrow_result->image_info.colorType(), kRGBA_8888_SkColorType);
|
||||
#endif // IMPELLER_SUPPORTS_RENDERING
|
||||
}
|
||||
|
||||
TEST_F(ImageDecoderFixtureTest, ImpellerPixelConversion32F) {
|
||||
auto info = SkImageInfo::Make(10, 10, SkColorType::kRGBA_F32_SkColorType,
|
||||
SkAlphaType::kUnpremul_SkAlphaType);
|
||||
@ -570,16 +397,6 @@ TEST_F(ImageDecoderFixtureTest, ImpellerPixelConversion32F) {
|
||||
#endif // IMPELLER_SUPPORTS_RENDERING
|
||||
}
|
||||
|
||||
namespace {
|
||||
float DecodeBGR10(uint32_t x) {
|
||||
const float max = 1.25098f;
|
||||
const float min = -0.752941f;
|
||||
const float intercept = min;
|
||||
const float slope = (max - min) / 1024.0f;
|
||||
return (x * slope) + intercept;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_F(ImageDecoderFixtureTest, ImpellerWideGamutDisplayP3Opaque) {
|
||||
auto data = OpenFixtureAsSkData("DisplayP3Logo.jpg");
|
||||
auto image = SkImages::DeferredFromEncodedData(data);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user