Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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 ()
 
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.
 
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 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 80 of file image_decoder_impeller.cc.

86 : ImageDecoder(runners, std::move(concurrent_task_runner), io_manager),
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()
94 : nullptr);
95 }));
96}
ImageDecoder(const TaskRunners &runners, std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner, fml::WeakPtr< IOManager > io_manager)
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
virtual void PostTask(const fml::closure &task) override
internal::CopyableLambda< T > MakeCopyable(T lambda)

◆ ~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 449 of file image_decoder_impeller.cc.

452 {
453 FML_DCHECK(descriptor);
454 FML_DCHECK(p_result);
455
456 // Wrap the result callback so that it can be invoked from any thread.
457 auto raw_descriptor = descriptor.get();
458 raw_descriptor->AddRef();
459 ImageResult result = [p_result, //
460 raw_descriptor, //
461 ui_runner = runners_.GetUITaskRunner() //
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);
466 });
467 };
468
469 concurrent_task_runner_->PostTask(
470 [raw_descriptor, //
471 context = context_.get(), //
472 target_size = SkISize::Make(target_width, target_height), //
473 io_runner = runners_.GetIOTaskRunner(), //
474 result,
475 supports_wide_gamut = supports_wide_gamut_, //
476 gpu_disabled_switch = gpu_disabled_switch_]() {
477 if (!context) {
478 result(nullptr, "No Impeller context is available");
479 return;
480 }
481 auto max_size_supported =
482 context->GetResourceAllocator()->GetMaxTextureSizeSupported();
483
484 // Always decompress on the concurrent runner.
485 auto bitmap_result = DecompressTexture(
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);
490 return;
491 }
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()) {
497 std::tie(image, decode_error) = UploadTextureToPrivate(
498 context, bitmap_result.device_buffer, bitmap_result.image_info,
499 bitmap_result.sk_bitmap, gpu_disabled_switch);
500 result(image, decode_error);
501 } else {
502 std::tie(image, decode_error) = UploadTextureToStorage(
503 context, bitmap_result.sk_bitmap, gpu_disabled_switch,
505 /*create_mips=*/true);
506 result(image, decode_error);
507 }
508 };
509 // TODO(jonahwilliams):
510 // https://github.com/flutter/flutter/issues/123058 Technically we
511 // don't need to post tasks to the io runner, but without this
512 // forced serialization we can end up overloading the GPU and/or
513 // competing with raster workloads.
514 io_runner->PostTask(upload_texture_and_invoke_result);
515 });
516}
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 > 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
std::shared_ptr< fml::ConcurrentTaskRunner > concurrent_task_runner_
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
T * get() const
Definition ref_ptr.h:116
sk_sp< SkImage > image
Definition examples.cpp:29
GAsyncResult * result
#define FML_DCHECK(condition)
Definition logging.h:103
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.
  1. If the decoded image isn't the requested target size, resize it.

Definition at line 113 of file image_decoder_impeller.cc.

118 {
119 TRACE_EVENT0("impeller", __FUNCTION__);
120 if (!descriptor) {
121 std::string decode_error("Invalid descriptor (should never happen)");
122 FML_DLOG(ERROR) << decode_error;
123 return DecompressResult{.decode_error = decode_error};
124 }
125
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),
129 target_size.height()));
130
131 const SkISize source_size = descriptor->image_info().dimensions();
132 auto decode_size = source_size;
133 if (descriptor->is_compressed()) {
134 decode_size = descriptor->get_scaled_dimensions(std::max(
135 static_cast<float>(target_size.width()) / source_size.width(),
136 static_cast<float>(target_size.height()) / source_size.height()));
137 }
138
139 //----------------------------------------------------------------------------
140 /// 1. Decode the image.
141 ///
142
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;
147 ChooseCompatibleAlphaType(base_image_info.alphaType());
148 SkImageInfo image_info;
149 if (is_wide_gamut) {
153 image_info =
154 base_image_info.makeWH(decode_size.width(), decode_size.height())
158 } else {
159 image_info =
160 base_image_info.makeWH(decode_size.width(), decode_size.height())
162 ChooseCompatibleColorType(base_image_info.colorType()))
164 }
165
166 const auto pixel_format =
168 if (!pixel_format.has_value()) {
169 std::string decode_error(impeller::SPrintF(
170 "Codec pixel format is not supported (SkColorType=%d)",
171 image_info.colorType()));
172 FML_DLOG(ERROR) << decode_error;
173 return DecompressResult{.decode_error = decode_error};
174 }
175
176 auto bitmap = std::make_shared<SkBitmap>();
177 bitmap->setInfo(image_info);
178 auto bitmap_allocator = std::make_shared<ImpellerAllocator>(allocator);
179
180 if (descriptor->is_compressed()) {
181 if (!bitmap->tryAllocPixels(bitmap_allocator.get())) {
182 std::string decode_error(
183 "Could not allocate intermediate for image decompression.");
184 FML_DLOG(ERROR) << decode_error;
185 return DecompressResult{.decode_error = decode_error};
186 }
187 // Decode the image into the image generator's closest supported size.
188 if (!descriptor->get_pixels(bitmap->pixmap())) {
189 std::string decode_error("Could not decompress image.");
190 FML_DLOG(ERROR) << decode_error;
191 return DecompressResult{.decode_error = decode_error};
192 }
193 } else {
194 auto temp_bitmap = std::make_shared<SkBitmap>();
195 temp_bitmap->setInfo(base_image_info);
196 auto pixel_ref = SkMallocPixelRef::MakeWithData(
197 base_image_info, descriptor->row_bytes(), descriptor->data());
198 temp_bitmap->setPixelRef(pixel_ref, 0, 0);
199
200 if (!bitmap->tryAllocPixels(bitmap_allocator.get())) {
201 std::string decode_error(
202 "Could not allocate intermediate for pixel conversion.");
203 FML_DLOG(ERROR) << decode_error;
204 return DecompressResult{.decode_error = decode_error};
205 }
206 temp_bitmap->readPixels(bitmap->pixmap());
207 bitmap->setImmutable();
208 }
209
210 if (bitmap->dimensions() == target_size) {
211 std::shared_ptr<impeller::DeviceBuffer> buffer =
212 bitmap_allocator->GetDeviceBuffer();
213 if (!buffer) {
214 return DecompressResult{.decode_error = "Unable to get device buffer"};
215 }
216 buffer->Flush();
217
218 return DecompressResult{.device_buffer = std::move(buffer),
219 .sk_bitmap = bitmap,
220 .image_info = bitmap->info()};
221 }
222
223 //----------------------------------------------------------------------------
224 /// 2. If the decoded image isn't the requested target size, resize it.
225 ///
226
227 TRACE_EVENT0("impeller", "DecodeScale");
228 const auto scaled_image_info = image_info.makeDimensions(target_size);
229
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.");
236 FML_DLOG(ERROR) << decode_error;
237 return DecompressResult{.decode_error = decode_error};
238 }
239 if (!bitmap->pixmap().scalePixels(
240 scaled_bitmap->pixmap(),
242 FML_LOG(ERROR) << "Could not scale decoded bitmap data.";
243 }
244 scaled_bitmap->setImmutable();
245
246 std::shared_ptr<impeller::DeviceBuffer> buffer =
247 scaled_allocator->GetDeviceBuffer();
248 buffer->Flush();
249
250 if (!buffer) {
251 return DecompressResult{.decode_error = "Unable to get device buffer"};
252 }
253 return DecompressResult{.device_buffer = std::move(buffer),
254 .sk_bitmap = scaled_bitmap,
255 .image_info = scaled_bitmap->info()};
256}
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
SK_API sk_sp< SkPixelRef > MakeWithData(const SkImageInfo &, size_t rowBytes, sk_sp< SkData > data)
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
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
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
SkImageInfo makeDimensions(SkISize newSize) const
SkImageInfo makeColorSpace(sk_sp< SkColorSpace > cs) const
SkColorType colorType() const
SkImageInfo makeColorType(SkColorType newColorType) const
Type height
Definition size.h:23
Type width
Definition size.h:22
#define ERROR(message)
#define TRACE_EVENT0(category_group, name)

◆ 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 325 of file image_decoder_impeller.cc.

330 {
331 TRACE_EVENT0("impeller", __FUNCTION__);
332 if (!context) {
333 return std::make_pair(nullptr, "No Impeller context is available");
334 }
335 if (!buffer) {
336 return std::make_pair(nullptr, "No Impeller device buffer is available");
337 }
338
339 std::pair<sk_sp<DlImage>, std::string> result;
340 gpu_disabled_switch->Execute(
342 .SetIfFalse([&result, context, buffer, image_info] {
343 result = UnsafeUploadTextureToPrivate(context, buffer, image_info);
344 })
345 .SetIfTrue([&result, context, bitmap, gpu_disabled_switch] {
346 // create_mips is false because we already know the GPU is disabled.
347 result =
348 UploadTextureToStorage(context, bitmap, gpu_disabled_switch,
350 /*create_mips=*/false);
351 }));
352 return result;
353}
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 |SyncSwitchExecute|.
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 356 of file image_decoder_impeller.cc.

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