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/core/texture.h"
14#include "flutter/impeller/display_list/dl_image_impeller.h"
15#include "flutter/impeller/renderer/command_buffer.h"
16#include "flutter/impeller/renderer/context.h"
17#include "flutter/lib/ui/painting/image_decoder_skia.h"
44 for (
int index = 0; index < 3; index++) {
45 float sum = xyz.
vals[index][0] + xyz.
vals[index][1] + xyz.
vals[index][2];
46 abc[index].
fX = xyz.
vals[index][0] / sum;
47 abc[index].
fY = xyz.
vals[index][1] / sum;
54float CalculateArea(
SkPoint abc[3]) {
58 return 0.5f * fabsf(
a.fX *
b.fY +
b.fX * c.
fY -
a.fX * c.
fY - c.
fX *
b.fY -
63static constexpr float kSrgbGamutArea = 0.0982f;
74 LoadGamut(rgb, xyzd50);
75 float area = CalculateArea(rgb);
76 return area > kSrgbGamutArea;
82 std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner,
84 bool supports_wide_gamut,
85 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch)
87 supports_wide_gamut_(supports_wide_gamut),
88 gpu_disabled_switch_(gpu_disabled_switch) {
89 std::promise<std::shared_ptr<impeller::Context>> context_promise;
90 context_ = context_promise.get_future();
92 [promise = std::move(context_promise), io_manager]()
mutable {
93 promise.set_value(io_manager ? io_manager->GetImpellerContext()
117 bool supports_wide_gamut,
118 const std::shared_ptr<impeller::Allocator>& allocator) {
121 std::string decode_error(
"Invalid descriptor (should never happen)");
126 target_size.
set(std::min(
static_cast<int32_t
>(max_texture_size.
width),
127 target_size.
width()),
128 std::min(
static_cast<int32_t
>(max_texture_size.
height),
132 auto decode_size = source_size;
135 static_cast<float>(target_size.
width()) / source_size.
width(),
136 static_cast<float>(target_size.
height()) / source_size.
height()));
143 const auto base_image_info = descriptor->
image_info();
144 const bool is_wide_gamut =
145 supports_wide_gamut ? IsWideGamut(base_image_info.colorSpace()) :
false;
154 base_image_info.
makeWH(decode_size.width(), decode_size.height())
160 base_image_info.
makeWH(decode_size.width(), decode_size.height())
166 const auto pixel_format =
168 if (!pixel_format.has_value()) {
170 "Codec pixel format is not supported (SkColorType=%d)",
176 auto bitmap = std::make_shared<SkBitmap>();
177 bitmap->setInfo(image_info);
178 auto bitmap_allocator = std::make_shared<ImpellerAllocator>(allocator);
181 if (!
bitmap->tryAllocPixels(bitmap_allocator.get())) {
182 std::string decode_error(
183 "Could not allocate intermediate for image decompression.");
189 std::string decode_error(
"Could not decompress image.");
194 auto temp_bitmap = std::make_shared<SkBitmap>();
195 temp_bitmap->setInfo(base_image_info);
197 base_image_info, descriptor->
row_bytes(), descriptor->
data());
198 temp_bitmap->setPixelRef(pixel_ref, 0, 0);
200 if (!
bitmap->tryAllocPixels(bitmap_allocator.get())) {
201 std::string decode_error(
202 "Could not allocate intermediate for pixel conversion.");
206 temp_bitmap->readPixels(
bitmap->pixmap());
210 if (
bitmap->dimensions() == target_size) {
211 std::shared_ptr<impeller::DeviceBuffer>
buffer =
212 bitmap_allocator->GetDeviceBuffer();
220 .image_info =
bitmap->info()};
228 const auto scaled_image_info = image_info.
makeDimensions(target_size);
230 auto scaled_bitmap = std::make_shared<SkBitmap>();
231 auto scaled_allocator = std::make_shared<ImpellerAllocator>(allocator);
232 scaled_bitmap->setInfo(scaled_image_info);
233 if (!scaled_bitmap->tryAllocPixels(scaled_allocator.get())) {
234 std::string decode_error(
235 "Could not allocate scaled bitmap for image decompression.");
239 if (!
bitmap->pixmap().scalePixels(
240 scaled_bitmap->pixmap(),
242 FML_LOG(
ERROR) <<
"Could not scale decoded bitmap data.";
244 scaled_bitmap->setImmutable();
246 std::shared_ptr<impeller::DeviceBuffer>
buffer =
247 scaled_allocator->GetDeviceBuffer();
254 .sk_bitmap = scaled_bitmap,
255 .image_info = scaled_bitmap->info()};
260 const std::shared_ptr<impeller::Context>& context,
261 const std::shared_ptr<impeller::DeviceBuffer>&
buffer,
263 const auto pixel_format =
267 "Unsupported pixel format (SkColorType=%d)", image_info.
colorType()));
269 return std::make_pair(
nullptr, decode_error);
274 texture_descriptor.
format = pixel_format.value();
280 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
282 std::string decode_error(
"Could not create Impeller texture.");
284 return std::make_pair(
nullptr, decode_error);
287 dest_texture->SetLabel(
290 auto command_buffer = context->CreateCommandBuffer();
291 if (!command_buffer) {
292 std::string decode_error(
293 "Could not create command buffer for mipmap generation.");
295 return std::make_pair(
nullptr, decode_error);
297 command_buffer->SetLabel(
"Mipmap Command Buffer");
299 auto blit_pass = command_buffer->CreateBlitPass();
301 std::string decode_error(
302 "Could not create blit pass for mipmap generation.");
304 return std::make_pair(
nullptr, decode_error);
306 blit_pass->SetLabel(
"Mipmap Blit Pass");
310 blit_pass->GenerateMipmap(dest_texture);
313 blit_pass->EncodeCommands(context->GetResourceAllocator());
314 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
315 std::string decode_error(
"Failed to submit blit pass command buffer.");
317 return std::make_pair(
nullptr, decode_error);
320 return std::make_pair(
324std::pair<sk_sp<DlImage>, std::string>
326 const std::shared_ptr<impeller::Context>& context,
327 const std::shared_ptr<impeller::DeviceBuffer>&
buffer,
329 const std::shared_ptr<SkBitmap>&
bitmap,
330 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch) {
333 return std::make_pair(
nullptr,
"No Impeller context is available");
336 return std::make_pair(
nullptr,
"No Impeller device buffer is available");
339 std::pair<sk_sp<DlImage>, std::string>
result;
340 gpu_disabled_switch->Execute(
345 .SetIfTrue([&
result, context,
bitmap, gpu_disabled_switch] {
355std::pair<sk_sp<DlImage>, std::string>
357 const std::shared_ptr<impeller::Context>& context,
358 std::shared_ptr<SkBitmap>
bitmap,
359 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch,
364 return std::make_pair(
nullptr,
"No Impeller context is available");
367 return std::make_pair(
nullptr,
"No texture bitmap is available");
369 const auto image_info =
bitmap->info();
370 const auto pixel_format =
374 "Unsupported pixel format (SkColorType=%d)", image_info.colorType()));
376 return std::make_pair(
nullptr, decode_error);
381 texture_descriptor.
format = pixel_format.value();
382 texture_descriptor.
size = {image_info.
width(), image_info.height()};
387 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
389 std::string decode_error(
"Could not create Impeller texture.");
391 return std::make_pair(
nullptr, decode_error);
394 auto mapping = std::make_shared<fml::NonOwnedMapping>(
395 reinterpret_cast<const uint8_t*
>(
bitmap->getAddr(0, 0)),
397 [
bitmap](
auto,
auto)
mutable { bitmap.reset(); }
400 if (!
texture->SetContents(mapping)) {
401 std::string decode_error(
"Could not copy contents into Impeller texture.");
403 return std::make_pair(
nullptr, decode_error);
408 if (texture_descriptor.
mip_count > 1u && create_mips) {
409 std::optional<std::string> decode_error;
415 [context, &
texture, &decode_error] {
416 auto command_buffer = context->CreateCommandBuffer();
417 if (!command_buffer) {
419 "Could not create command buffer for mipmap generation.";
422 command_buffer->SetLabel(
"Mipmap Command Buffer");
424 auto blit_pass = command_buffer->CreateBlitPass();
426 decode_error =
"Could not create blit pass for mipmap generation.";
429 blit_pass->SetLabel(
"Mipmap Blit Pass");
430 blit_pass->GenerateMipmap(
texture);
431 blit_pass->EncodeCommands(context->GetResourceAllocator());
432 if (!context->GetCommandQueue()->Submit({command_buffer}).ok()) {
433 decode_error =
"Failed to submit blit pass command buffer.";
436 command_buffer->WaitUntilScheduled();
438 if (decode_error.has_value()) {
440 return std::make_pair(
nullptr, decode_error.value());
450 uint32_t target_width,
451 uint32_t target_height,
457 auto raw_descriptor = descriptor.
get();
458 raw_descriptor->AddRef();
462 ](
auto image,
auto decode_error) {
463 ui_runner->PostTask([raw_descriptor, p_result,
image, decode_error]() {
464 raw_descriptor->Release();
465 p_result(std::move(
image), decode_error);
471 context = context_.get(),
475 supports_wide_gamut = supports_wide_gamut_,
476 gpu_disabled_switch = gpu_disabled_switch_]() {
478 result(
nullptr,
"No Impeller context is available");
481 auto max_size_supported =
482 context->GetResourceAllocator()->GetMaxTextureSizeSupported();
486 raw_descriptor, target_size, max_size_supported,
487 supports_wide_gamut, context->GetResourceAllocator());
488 if (!bitmap_result.device_buffer) {
489 result(
nullptr, bitmap_result.decode_error);
492 auto upload_texture_and_invoke_result = [
result, context, bitmap_result,
493 gpu_disabled_switch]() {
495 std::string decode_error;
496 if (context->GetCapabilities()->SupportsBufferToTextureBlits()) {
498 context, bitmap_result.device_buffer, bitmap_result.image_info,
499 bitmap_result.sk_bitmap, gpu_disabled_switch);
503 context, bitmap_result.sk_bitmap, gpu_disabled_switch,
514 io_runner->PostTask(upload_texture_and_invoke_result);
519 std::shared_ptr<impeller::Allocator> allocator)
520 : allocator_(
std::move(allocator)) {}
542 std::shared_ptr<impeller::DeviceBuffer> device_buffer =
543 allocator_->CreateBuffer(descriptor);
544 if (!device_buffer) {
548 struct ImpellerPixelRef final :
public SkPixelRef {
549 ImpellerPixelRef(
int w,
int h,
void*
s,
size_t r)
552 ~ImpellerPixelRef()
override {}
556 new ImpellerPixelRef(
info.width(),
info.height(),
557 device_buffer->OnGetContents(),
bitmap->rowBytes()));
559 bitmap->setPixelRef(std::move(pixel_ref), 0, 0);
560 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)
SK_API sk_sp< SkPixelRef > MakeWithData(const SkImageInfo &, size_t rowBytes, sk_sp< SkData > data)
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
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 |SyncSwitchExecute|.
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)