Flutter Engine
The Flutter Engine
Public Member Functions | Static Public Member Functions | List of all members
flutter::ImageDecoderImpeller Class Referencefinal

#include <image_decoder_impeller.h>

Inheritance diagram for flutter::ImageDecoderImpeller:
flutter::ImageDecoder

Public Member Functions

 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)
 
 ~ImageDecoderImpeller () override
 
void Decode (fml::RefPtr< ImageDescriptor > descriptor, uint32_t target_width, uint32_t target_height, const ImageResult &result) override
 
- Public Member Functions inherited from flutter::ImageDecoder
virtual ~ImageDecoder ()
 
virtual void Decode (fml::RefPtr< ImageDescriptor > descriptor, uint32_t target_width, uint32_t target_height, const ImageResult &result)=0
 
fml::WeakPtr< ImageDecoderGetWeakPtr () const
 

Static Public Member Functions

static DecompressResult DecompressTexture (ImageDescriptor *descriptor, SkISize target_size, impeller::ISize max_texture_size, bool supports_wide_gamut, const std::shared_ptr< impeller::Allocator > &allocator)
 
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 metal backend. More...
 
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. More...
 
- Static Public Member Functions inherited from flutter::ImageDecoder
static std::unique_ptr< ImageDecoderMake (const Settings &settings, const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, fml::WeakPtr< IOManager > io_manager, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch)
 

Additional Inherited Members

- Public Types inherited from flutter::ImageDecoder
using ImageResult = std::function< void(sk_sp< DlImage >, std::string)>
 
- Protected Member Functions inherited from flutter::ImageDecoder
 ImageDecoder (const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, fml::WeakPtr< IOManager > io_manager)
 
- Protected Attributes inherited from flutter::ImageDecoder
TaskRunners runners_
 
std::shared_ptr< fml::ConcurrentTaskRunnerconcurrent_task_runner_
 
fml::WeakPtr< IOManagerio_manager_
 

Detailed Description

Definition at line 47 of file image_decoder_impeller.h.

Constructor & Destructor Documentation

◆ ImageDecoderImpeller()

flutter::ImageDecoderImpeller::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 
)

Definition at line 78 of file image_decoder_impeller.cc.

84 : ImageDecoder(runners, std::move(concurrent_task_runner), io_manager),
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()
92 : nullptr);
93 }));
94}
ImageDecoder(const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, fml::WeakPtr< IOManager > io_manager)
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
Definition: task_runners.cc:38
virtual void PostTask(const fml::closure &task) override
Definition: task_runner.cc:24
internal::CopyableLambda< T > MakeCopyable(T lambda)
Definition: make_copyable.h:57

◆ ~ImageDecoderImpeller()

flutter::ImageDecoderImpeller::~ImageDecoderImpeller ( )
overridedefault

Member Function Documentation

◆ Decode()

void flutter::ImageDecoderImpeller::Decode ( fml::RefPtr< ImageDescriptor descriptor,
uint32_t  target_width,
uint32_t  target_height,
const ImageResult result 
)
overridevirtual

Implements flutter::ImageDecoder.

Definition at line 447 of file image_decoder_impeller.cc.

450 {
451 FML_DCHECK(descriptor);
452 FML_DCHECK(p_result);
453
454 // Wrap the result callback so that it can be invoked from any thread.
455 auto raw_descriptor = descriptor.get();
456 raw_descriptor->AddRef();
457 ImageResult result = [p_result, //
458 raw_descriptor, //
459 ui_runner = runners_.GetUITaskRunner() //
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);
464 });
465 };
466
467 concurrent_task_runner_->PostTask(
468 [raw_descriptor, //
469 context = context_.get(), //
470 target_size = SkISize::Make(target_width, target_height), //
471 io_runner = runners_.GetIOTaskRunner(), //
472 result,
473 supports_wide_gamut = supports_wide_gamut_, //
474 gpu_disabled_switch = gpu_disabled_switch_]() {
475 if (!context) {
476 result(nullptr, "No Impeller context is available");
477 return;
478 }
479 auto max_size_supported =
480 context->GetResourceAllocator()->GetMaxTextureSizeSupported();
481
482 // Always decompress on the concurrent runner.
483 auto bitmap_result = DecompressTexture(
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);
488 return;
489 }
490
491 auto upload_texture_and_invoke_result = [result, context, bitmap_result,
492 gpu_disabled_switch]() {
494 std::string decode_error;
495 std::tie(image, decode_error) = UploadTextureToPrivate(
496 context, bitmap_result.device_buffer, bitmap_result.image_info,
497 bitmap_result.sk_bitmap, gpu_disabled_switch);
498 result(image, decode_error);
499 };
500 io_runner->PostTask(upload_texture_and_invoke_result);
501 });
502}
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)
std::function< void(sk_sp< DlImage >, std::string)> ImageResult
Definition: image_decoder.h:35
std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner_
Definition: image_decoder.h:51
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
Definition: task_runners.cc:34
T * get() const
Definition: ref_ptr.h:116
GAsyncResult * result
#define FML_DCHECK(condition)
Definition: logging.h:103
sk_sp< const SkImage > image
Definition: SkRecords.h:269
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20

◆ DecompressTexture()

DecompressResult flutter::ImageDecoderImpeller::DecompressTexture ( ImageDescriptor descriptor,
SkISize  target_size,
impeller::ISize  max_texture_size,
bool  supports_wide_gamut,
const std::shared_ptr< impeller::Allocator > &  allocator 
)
static
  1. Decode the image.
  2. If the decoded image isn't the requested target size, resize it.

Definition at line 111 of file image_decoder_impeller.cc.

116 {
117 TRACE_EVENT0("impeller", __FUNCTION__);
118 if (!descriptor) {
119 std::string decode_error("Invalid descriptor (should never happen)");
120 FML_DLOG(ERROR) << decode_error;
121 return DecompressResult{.decode_error = decode_error};
122 }
123
124 target_size.set(std::min(static_cast<int32_t>(max_texture_size.width),
125 target_size.width()),
126 std::min(static_cast<int32_t>(max_texture_size.height),
127 target_size.height()));
128
129 const SkISize source_size = descriptor->image_info().dimensions();
130 auto decode_size = source_size;
131 if (descriptor->is_compressed()) {
132 decode_size = descriptor->get_scaled_dimensions(std::max(
133 static_cast<float>(target_size.width()) / source_size.width(),
134 static_cast<float>(target_size.height()) / source_size.height()));
135 }
136
137 //----------------------------------------------------------------------------
138 /// 1. Decode the image.
139 ///
140
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;
145 ChooseCompatibleAlphaType(base_image_info.alphaType());
146 SkImageInfo image_info;
147 if (is_wide_gamut) {
151 image_info =
152 base_image_info.makeWH(decode_size.width(), decode_size.height())
156 } else {
157 image_info =
158 base_image_info.makeWH(decode_size.width(), decode_size.height())
160 ChooseCompatibleColorType(base_image_info.colorType()))
162 }
163
164 const auto pixel_format =
166 if (!pixel_format.has_value()) {
167 std::string decode_error(impeller::SPrintF(
168 "Codec pixel format is not supported (SkColorType=%d)",
169 image_info.colorType()));
170 FML_DLOG(ERROR) << decode_error;
171 return DecompressResult{.decode_error = decode_error};
172 }
173
174 auto bitmap = std::make_shared<SkBitmap>();
175 bitmap->setInfo(image_info);
176 auto bitmap_allocator = std::make_shared<ImpellerAllocator>(allocator);
177
178 if (descriptor->is_compressed()) {
179 if (!bitmap->tryAllocPixels(bitmap_allocator.get())) {
180 std::string decode_error(
181 "Could not allocate intermediate for image decompression.");
182 FML_DLOG(ERROR) << decode_error;
183 return DecompressResult{.decode_error = decode_error};
184 }
185 // Decode the image into the image generator's closest supported size.
186 if (!descriptor->get_pixels(bitmap->pixmap())) {
187 std::string decode_error("Could not decompress image.");
188 FML_DLOG(ERROR) << decode_error;
189 return DecompressResult{.decode_error = decode_error};
190 }
191 } else {
192 auto temp_bitmap = std::make_shared<SkBitmap>();
193 temp_bitmap->setInfo(base_image_info);
194 auto pixel_ref = SkMallocPixelRef::MakeWithData(
195 base_image_info, descriptor->row_bytes(), descriptor->data());
196 temp_bitmap->setPixelRef(pixel_ref, 0, 0);
197
198 if (!bitmap->tryAllocPixels(bitmap_allocator.get())) {
199 std::string decode_error(
200 "Could not allocate intermediate for pixel conversion.");
201 FML_DLOG(ERROR) << decode_error;
202 return DecompressResult{.decode_error = decode_error};
203 }
204 temp_bitmap->readPixels(bitmap->pixmap());
205 bitmap->setImmutable();
206 }
207
208 if (bitmap->dimensions() == target_size) {
209 std::shared_ptr<impeller::DeviceBuffer> buffer =
210 bitmap_allocator->GetDeviceBuffer();
211 if (!buffer) {
212 return DecompressResult{.decode_error = "Unable to get device buffer"};
213 }
214 buffer->Flush();
215
216 return DecompressResult{.device_buffer = std::move(buffer),
217 .sk_bitmap = bitmap,
218 .image_info = bitmap->info()};
219 }
220
221 //----------------------------------------------------------------------------
222 /// 2. If the decoded image isn't the requested target size, resize it.
223 ///
224
225 TRACE_EVENT0("impeller", "DecodeScale");
226 const auto scaled_image_info = image_info.makeDimensions(target_size);
227
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.");
234 FML_DLOG(ERROR) << decode_error;
235 return DecompressResult{.decode_error = decode_error};
236 }
237 if (!bitmap->pixmap().scalePixels(
238 scaled_bitmap->pixmap(),
240 FML_LOG(ERROR) << "Could not scale decoded bitmap data.";
241 }
242 scaled_bitmap->setImmutable();
243
244 std::shared_ptr<impeller::DeviceBuffer> buffer =
245 scaled_allocator->GetDeviceBuffer();
246 buffer->Flush();
247
248 if (!buffer) {
249 return DecompressResult{.decode_error = "Unable to get device buffer"};
250 }
251 return DecompressResult{.device_buffer = std::move(buffer),
252 .sk_bitmap = scaled_bitmap,
253 .image_info = scaled_bitmap->info()};
254}
SkAlphaType
Definition: SkAlphaType.h:26
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
SkColorType
Definition: SkColorType.h:19
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kBGR_101010x_XR_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
Definition: SkColorType.h:31
static sk_sp< SkColorSpace > MakeSRGB()
#define FML_DLOG(severity)
Definition: logging.h:102
#define FML_LOG(severity)
Definition: logging.h:82
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
SK_API sk_sp< SkPixelRef > MakeWithData(const SkImageInfo &, size_t rowBytes, sk_sp< SkData > data)
Definition: bitmap.py:1
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
Definition: switches.h:126
std::optional< impeller::PixelFormat > ToPixelFormat(SkColorType type)
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
uint32_t color_type
uint32_t alpha_type
Definition: SkSize.h:16
constexpr int32_t width() const
Definition: SkSize.h:36
void set(int32_t w, int32_t h)
Definition: SkSize.h:24
constexpr int32_t height() const
Definition: SkSize.h:37
SkImageInfo makeWH(int newWidth, int newHeight) const
Definition: SkImageInfo.h:444
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
Definition: SkImageInfo.h:466
SkImageInfo makeDimensions(SkISize newSize) const
Definition: SkImageInfo.h:454
SkImageInfo makeColorSpace(sk_sp< SkColorSpace > cs) const
SkColorType colorType() const
Definition: SkImageInfo.h:373
SkImageInfo makeColorType(SkColorType newColorType) const
Definition: SkImageInfo.h:475
Type height
Definition: size.h:23
Type width
Definition: size.h:22
#define ERROR(message)
Definition: elf_loader.cc:260
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131

◆ UploadTextureToPrivate()

std::pair< sk_sp< DlImage >, std::string > flutter::ImageDecoderImpeller::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 
)
static

Create a device private texture from the provided host buffer. This method is only suported on the metal backend.

Parameters
contextThe Impeller graphics context.
bufferA host buffer containing the image to be uploaded.
image_infoFormat information about the particular image.
bitmapA bitmap containg the image to be uploaded.
gpu_disabled_switchWhether the GPU is available command encoding.
Returns
A DlImage.

Definition at line 323 of file image_decoder_impeller.cc.

328 {
329 TRACE_EVENT0("impeller", __FUNCTION__);
330 if (!context) {
331 return std::make_pair(nullptr, "No Impeller context is available");
332 }
333 if (!buffer) {
334 return std::make_pair(nullptr, "No Impeller device buffer is available");
335 }
336
337 std::pair<sk_sp<DlImage>, std::string> result;
338 gpu_disabled_switch->Execute(
340 .SetIfFalse([&result, context, buffer, image_info] {
341 result = UnsafeUploadTextureToPrivate(context, buffer, image_info);
342 })
343 .SetIfTrue([&result, context, bitmap, gpu_disabled_switch] {
344 // create_mips is false because we already know the GPU is disabled.
345 result =
346 UploadTextureToStorage(context, bitmap, gpu_disabled_switch,
348 /*create_mips=*/false);
349 }));
350 return result;
351}
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.
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.
Represents the 2 code paths available when calling |SyncSwitch::Execute|.
Definition: sync_switch.h:35

◆ UploadTextureToStorage()

std::pair< sk_sp< DlImage >, std::string > flutter::ImageDecoderImpeller::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 
)
static

Create a host visible texture from the provided bitmap.

Parameters
contextThe Impeller graphics context.
bitmapA bitmap containg the image to be uploaded.
create_mipsWhether mipmaps should be generated for the given image.
gpu_disabled_switchWhether the GPU is available for mipmap creation.
Returns
A DlImage.

Definition at line 354 of file image_decoder_impeller.cc.

359 {
360 TRACE_EVENT0("impeller", __FUNCTION__);
361 if (!context) {
362 return std::make_pair(nullptr, "No Impeller context is available");
363 }
364 if (!bitmap) {
365 return std::make_pair(nullptr, "No texture bitmap is available");
366 }
367 const auto image_info = bitmap->info();
368 const auto pixel_format =
369 impeller::skia_conversions::ToPixelFormat(image_info.colorType());
370 if (!pixel_format) {
371 std::string decode_error(impeller::SPrintF(
372 "Unsupported pixel format (SkColorType=%d)", image_info.colorType()));
373 FML_DLOG(ERROR) << decode_error;
374 return std::make_pair(nullptr, decode_error);
375 }
376
377 impeller::TextureDescriptor texture_descriptor;
378 texture_descriptor.storage_mode = storage_mode;
379 texture_descriptor.format = pixel_format.value();
380 texture_descriptor.size = {image_info.width(), image_info.height()};
381 texture_descriptor.mip_count =
382 create_mips ? texture_descriptor.size.MipCount() : 1;
383
384 auto texture =
385 context->GetResourceAllocator()->CreateTexture(texture_descriptor);
386 if (!texture) {
387 std::string decode_error("Could not create Impeller texture.");
388 FML_DLOG(ERROR) << decode_error;
389 return std::make_pair(nullptr, decode_error);
390 }
391
392 auto mapping = std::make_shared<fml::NonOwnedMapping>(
393 reinterpret_cast<const uint8_t*>(bitmap->getAddr(0, 0)), // data
394 texture_descriptor.GetByteSizeOfBaseMipLevel(), // size
395 [bitmap](auto, auto) mutable { bitmap.reset(); } // proc
396 );
397
398 if (!texture->SetContents(mapping)) {
399 std::string decode_error("Could not copy contents into Impeller texture.");
400 FML_DLOG(ERROR) << decode_error;
401 return std::make_pair(nullptr, decode_error);
402 }
403
404 texture->SetLabel(impeller::SPrintF("ui.Image(%p)", texture.get()).c_str());
405
406 if (texture_descriptor.mip_count > 1u && create_mips) {
407 std::optional<std::string> decode_error;
408
409 // The only platform that needs mipmapping unconditionally is GL.
410 // GL based platforms never disable GPU access.
411 // This is only really needed for iOS.
412 gpu_disabled_switch->Execute(fml::SyncSwitch::Handlers().SetIfFalse(
413 [context, &texture, &decode_error] {
414 auto command_buffer = context->CreateCommandBuffer();
415 if (!command_buffer) {
416 decode_error =
417 "Could not create command buffer for mipmap generation.";
418 return;
419 }
420 command_buffer->SetLabel("Mipmap Command Buffer");
421
422 auto blit_pass = command_buffer->CreateBlitPass();
423 if (!blit_pass) {
424 decode_error = "Could not create blit pass for mipmap generation.";
425 return;
426 }
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.";
432 return;
433 }
434 command_buffer->WaitUntilScheduled();
435 }));
436 if (decode_error.has_value()) {
437 FML_DLOG(ERROR) << decode_error.value();
438 return std::make_pair(nullptr, decode_error.value());
439 }
440 }
441
442 return std::make_pair(impeller::DlImageImpeller::Make(std::move(texture)),
443 std::string());
444}
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
if(end==-1)
FlTexture * texture
constexpr size_t MipCount() const
Definition: size.h:115
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
constexpr size_t GetByteSizeOfBaseMipLevel() const

The documentation for this class was generated from the following files: