5#include "flutter/lib/ui/painting/image_decoder_impeller.h"
9#include "flutter/fml/closure.h"
10#include "flutter/fml/make_copyable.h"
11#include "flutter/fml/trace_event.h"
12#include "flutter/impeller/core/allocator.h"
13#include "flutter/impeller/display_list/dl_image_impeller.h"
14#include "flutter/impeller/renderer/command_buffer.h"
15#include "flutter/impeller/renderer/context.h"
42 for (
int index = 0; index < 3; index++) {
43 float sum = xyz.
vals[index][0] + xyz.
vals[index][1] + xyz.
vals[index][2];
44 abc[index].
fX = xyz.
vals[index][0] / sum;
45 abc[index].
fY = xyz.
vals[index][1] / sum;
52float CalculateArea(
SkPoint abc[3]) {
56 return 0.5f * fabsf(
a.fX *
b.fY +
b.fX * c.
fY -
a.fX * c.
fY - c.
fX *
b.fY -
61static constexpr float kSrgbGamutArea = 0.0982f;
72 LoadGamut(rgb, xyzd50);
73 float area = CalculateArea(rgb);
74 return area > kSrgbGamutArea;
80 std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner,
82 bool supports_wide_gamut,
83 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch)
85 supports_wide_gamut_(supports_wide_gamut),
86 gpu_disabled_switch_(gpu_disabled_switch) {
87 std::promise<std::shared_ptr<impeller::Context>> context_promise;
88 context_ = context_promise.get_future();
90 [promise = std::move(context_promise), io_manager]()
mutable {
91 promise.set_value(io_manager ? io_manager->GetImpellerContext()
115 bool supports_wide_gamut,
116 const std::shared_ptr<impeller::Allocator>& allocator) {
119 std::string decode_error(
"Invalid descriptor (should never happen)");
125 target_size.
width()),
130 auto decode_size = source_size;
133 static_cast<float>(target_size.
width()) / source_size.
width(),
134 static_cast<float>(target_size.
height()) / source_size.
height()));
141 const auto base_image_info = descriptor->
image_info();
142 const bool is_wide_gamut =
143 supports_wide_gamut ? IsWideGamut(base_image_info.colorSpace()) :
false;
152 base_image_info.
makeWH(decode_size.width(), decode_size.height())
158 base_image_info.
makeWH(decode_size.width(), decode_size.height())
164 const auto pixel_format =
166 if (!pixel_format.has_value()) {
168 "Codec pixel format is not supported (SkColorType=%d)",
174 auto bitmap = std::make_shared<SkBitmap>();
175 bitmap->setInfo(image_info);
176 auto bitmap_allocator = std::make_shared<ImpellerAllocator>(allocator);
179 if (!
bitmap->tryAllocPixels(bitmap_allocator.get())) {
180 std::string decode_error(
181 "Could not allocate intermediate for image decompression.");
187 std::string decode_error(
"Could not decompress image.");
192 auto temp_bitmap = std::make_shared<SkBitmap>();
193 temp_bitmap->setInfo(base_image_info);
195 base_image_info, descriptor->
row_bytes(), descriptor->
data());
196 temp_bitmap->setPixelRef(pixel_ref, 0, 0);
198 if (!
bitmap->tryAllocPixels(bitmap_allocator.get())) {
199 std::string decode_error(
200 "Could not allocate intermediate for pixel conversion.");
204 temp_bitmap->readPixels(
bitmap->pixmap());
208 if (
bitmap->dimensions() == target_size) {
209 std::shared_ptr<impeller::DeviceBuffer>
buffer =
210 bitmap_allocator->GetDeviceBuffer();
218 .image_info =
bitmap->info()};
226 const auto scaled_image_info = image_info.
makeDimensions(target_size);
228 auto scaled_bitmap = std::make_shared<SkBitmap>();
229 auto scaled_allocator = std::make_shared<ImpellerAllocator>(allocator);
230 scaled_bitmap->setInfo(scaled_image_info);
231 if (!scaled_bitmap->tryAllocPixels(scaled_allocator.get())) {
232 std::string decode_error(
233 "Could not allocate scaled bitmap for image decompression.");
237 if (!
bitmap->pixmap().scalePixels(
238 scaled_bitmap->pixmap(),
240 FML_LOG(
ERROR) <<
"Could not scale decoded bitmap data.";
242 scaled_bitmap->setImmutable();
244 std::shared_ptr<impeller::DeviceBuffer>
buffer =
245 scaled_allocator->GetDeviceBuffer();
252 .sk_bitmap = scaled_bitmap,
253 .image_info = scaled_bitmap->info()};
258 const std::shared_ptr<impeller::Context>& context,
259 const std::shared_ptr<impeller::DeviceBuffer>&
buffer,
261 const auto pixel_format =
265 "Unsupported pixel format (SkColorType=%d)", image_info.
colorType()));
267 return std::make_pair(
nullptr, decode_error);
272 texture_descriptor.
format = pixel_format.value();
278 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
280 std::string decode_error(
"Could not create Impeller texture.");
282 return std::make_pair(
nullptr, decode_error);
285 dest_texture->SetLabel(
288 auto command_buffer = context->CreateCommandBuffer();
289 if (!command_buffer) {
290 std::string decode_error(
291 "Could not create command buffer for mipmap generation.");
293 return std::make_pair(
nullptr, decode_error);
295 command_buffer->SetLabel(
"Mipmap Command Buffer");
297 auto blit_pass = command_buffer->CreateBlitPass();
299 std::string decode_error(
300 "Could not create blit pass for mipmap generation.");
302 return std::make_pair(
nullptr, decode_error);
304 blit_pass->SetLabel(
"Mipmap Blit Pass");
308 blit_pass->GenerateMipmap(dest_texture);
311 blit_pass->EncodeCommands(context->GetResourceAllocator());
312 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
313 std::string decode_error(
"Failed to submit blit pass command buffer.");
315 return std::make_pair(
nullptr, decode_error);
318 return std::make_pair(
322std::pair<sk_sp<DlImage>, std::string>
324 const std::shared_ptr<impeller::Context>& context,
325 const std::shared_ptr<impeller::DeviceBuffer>&
buffer,
327 const std::shared_ptr<SkBitmap>&
bitmap,
328 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch) {
331 return std::make_pair(
nullptr,
"No Impeller context is available");
334 return std::make_pair(
nullptr,
"No Impeller device buffer is available");
337 std::pair<sk_sp<DlImage>, std::string>
result;
338 gpu_disabled_switch->Execute(
343 .SetIfTrue([&
result, context,
bitmap, gpu_disabled_switch] {
353std::pair<sk_sp<DlImage>, std::string>
355 const std::shared_ptr<impeller::Context>& context,
356 std::shared_ptr<SkBitmap>
bitmap,
357 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch,
362 return std::make_pair(
nullptr,
"No Impeller context is available");
365 return std::make_pair(
nullptr,
"No texture bitmap is available");
367 const auto image_info =
bitmap->info();
368 const auto pixel_format =
372 "Unsupported pixel format (SkColorType=%d)", image_info.colorType()));
374 return std::make_pair(
nullptr, decode_error);
379 texture_descriptor.
format = pixel_format.value();
380 texture_descriptor.
size = {image_info.
width(), image_info.height()};
385 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
387 std::string decode_error(
"Could not create Impeller texture.");
389 return std::make_pair(
nullptr, decode_error);
392 auto mapping = std::make_shared<fml::NonOwnedMapping>(
393 reinterpret_cast<const uint8_t*
>(
bitmap->getAddr(0, 0)),
395 [
bitmap](
auto,
auto)
mutable { bitmap.reset(); }
398 if (!
texture->SetContents(mapping)) {
399 std::string decode_error(
"Could not copy contents into Impeller texture.");
401 return std::make_pair(
nullptr, decode_error);
406 if (texture_descriptor.
mip_count > 1u && create_mips) {
407 std::optional<std::string> decode_error;
413 [context, &
texture, &decode_error] {
414 auto command_buffer = context->CreateCommandBuffer();
415 if (!command_buffer) {
417 "Could not create command buffer for mipmap generation.";
420 command_buffer->SetLabel(
"Mipmap Command Buffer");
422 auto blit_pass = command_buffer->CreateBlitPass();
424 decode_error =
"Could not create blit pass for mipmap generation.";
427 blit_pass->SetLabel(
"Mipmap Blit Pass");
428 blit_pass->GenerateMipmap(
texture);
429 blit_pass->EncodeCommands(context->GetResourceAllocator());
430 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
431 decode_error =
"Failed to submit blit pass command buffer.";
434 command_buffer->WaitUntilScheduled();
436 if (decode_error.has_value()) {
438 return std::make_pair(
nullptr, decode_error.value());
448 uint32_t target_width,
449 uint32_t target_height,
455 auto raw_descriptor = descriptor.
get();
456 raw_descriptor->AddRef();
460 ](
auto image,
auto decode_error) {
461 ui_runner->PostTask([raw_descriptor, p_result,
image, decode_error]() {
462 raw_descriptor->Release();
463 p_result(std::move(
image), decode_error);
469 context = context_.get(),
473 supports_wide_gamut = supports_wide_gamut_,
474 gpu_disabled_switch = gpu_disabled_switch_]() {
476 result(
nullptr,
"No Impeller context is available");
479 auto max_size_supported =
480 context->GetResourceAllocator()->GetMaxTextureSizeSupported();
484 raw_descriptor, target_size, max_size_supported,
485 supports_wide_gamut, context->GetResourceAllocator());
486 if (!bitmap_result.device_buffer) {
487 result(
nullptr, bitmap_result.decode_error);
491 auto upload_texture_and_invoke_result = [
result, context, bitmap_result,
492 gpu_disabled_switch]() {
494 std::string decode_error;
496 context, bitmap_result.device_buffer, bitmap_result.image_info,
497 bitmap_result.sk_bitmap, gpu_disabled_switch);
500 io_runner->PostTask(upload_texture_and_invoke_result);
505 std::shared_ptr<impeller::Allocator> allocator)
506 : allocator_(
std::move(allocator)) {}
528 std::shared_ptr<impeller::DeviceBuffer> device_buffer =
529 allocator_->CreateBuffer(descriptor);
530 if (!device_buffer) {
534 struct ImpellerPixelRef final :
public SkPixelRef {
535 ImpellerPixelRef(
int w,
int h,
void*
s,
size_t r)
538 ~ImpellerPixelRef()
override {}
542 new ImpellerPixelRef(
info.width(),
info.height(),
543 device_buffer->OnGetContents(),
bitmap->rowBytes()));
545 bitmap->setPixelRef(std::move(pixel_ref), 0, 0);
546 buffer_ = std::move(device_buffer);
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
@ kOpaque_SkAlphaType
pixel is opaque
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
@ kBGR_101010x_XR_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
@ kUnknown_SkColorType
uninitialized
bool toXYZD50(skcms_Matrix3x3 *toXYZD50) const
static sk_sp< SkColorSpace > MakeSRGB()
void Decode(fml::RefPtr< ImageDescriptor > descriptor, uint32_t target_width, uint32_t target_height, const ImageResult &result) override
static std::pair< sk_sp< DlImage >, std::string > UploadTextureToStorage(const std::shared_ptr< impeller::Context > &context, std::shared_ptr< SkBitmap > bitmap, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch, impeller::StorageMode storage_mode, bool create_mips=true)
Create a host visible texture from the provided bitmap.
ImageDecoderImpeller(const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, const fml::WeakPtr< IOManager > &io_manager, bool supports_wide_gamut, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch)
static std::pair< sk_sp< DlImage >, std::string > UploadTextureToPrivate(const std::shared_ptr< impeller::Context > &context, const std::shared_ptr< impeller::DeviceBuffer > &buffer, const SkImageInfo &image_info, const std::shared_ptr< SkBitmap > &bitmap, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch)
Create a device private texture from the provided host buffer. This method is only suported on the me...
static DecompressResult DecompressTexture(ImageDescriptor *descriptor, SkISize target_size, impeller::ISize max_texture_size, bool supports_wide_gamut, const std::shared_ptr< impeller::Allocator > &allocator)
~ImageDecoderImpeller() override
std::function< void(sk_sp< DlImage >, std::string)> ImageResult
std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner_
Creates an image descriptor for encoded or decoded image data, describing the width,...
const SkImageInfo & image_info() const
The orientation corrected image info for this image.
SkISize get_scaled_dimensions(float scale)
Gets the scaled dimensions of this image, if backed by an ImageGenerator that can perform efficient s...
int row_bytes() const
The byte length of the first row of the image. Defaults to width() * 4.
bool get_pixels(const SkPixmap &pixmap) const
Gets pixels for this image transformed based on the EXIF orientation tag, if applicable.
bool is_compressed() const
Whether this descriptor represents compressed (encoded) data or not.
sk_sp< SkData > data() const
The underlying buffer for this image.
bool allocPixelRef(SkBitmap *bitmap) override
ImpellerAllocator(std::shared_ptr< impeller::Allocator > allocator)
std::shared_ptr< impeller::DeviceBuffer > GetDeviceBuffer() const
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
virtual void PostTask(const fml::closure &task) override
static BufferView AsBufferView(std::shared_ptr< DeviceBuffer > buffer)
Create a buffer view of this entire buffer.
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
#define FML_DLOG(severity)
#define FML_LOG(severity)
#define FML_DCHECK(condition)
static float max(float r, float g, float b)
static float min(float r, float g, float b)
SK_API sk_sp< SkPixelRef > MakeWithData(const SkImageInfo &, size_t rowBytes, sk_sp< SkData > data)
sk_sp< const SkImage > image
static std::pair< sk_sp< DlImage >, std::string > UnsafeUploadTextureToPrivate(const std::shared_ptr< impeller::Context > &context, const std::shared_ptr< impeller::DeviceBuffer > &buffer, const SkImageInfo &image_info)
Only call this method if the GPU is available.
static SkAlphaType ChooseCompatibleAlphaType(SkAlphaType type)
static SkColorType ChooseCompatibleColorType(SkColorType type)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder h
internal::CopyableLambda< T > MakeCopyable(T lambda)
std::optional< impeller::PixelFormat > ToPixelFormat(SkColorType type)
StorageMode
Specified where the allocation resides and how it is used.
std::string SPrintF(const char *format,...)
static constexpr SkISize Make(int32_t w, int32_t h)
constexpr int32_t width() const
void set(int32_t w, int32_t h)
constexpr int32_t height() const
SkImageInfo makeWH(int newWidth, int newHeight) const
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
SkImageInfo makeDimensions(SkISize newSize) const
SkISize dimensions() const
SkImageInfo makeColorSpace(sk_sp< SkColorSpace > cs) const
SkColorType colorType() const
SkImageInfo makeColorType(SkColorType newColorType) const
std::shared_ptr< impeller::DeviceBuffer > device_buffer
Represents the 2 code paths available when calling |SyncSwitch::Execute|.
constexpr size_t MipCount() const
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
constexpr size_t GetByteSizeOfBaseMipLevel() const
CompressionType compression_type
#define TRACE_EVENT0(category_group, name)