@@ -80,9 +80,11 @@ ImageDecoderImpeller::ImageDecoderImpeller(
8080 const TaskRunners& runners,
8181 std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner,
8282 const fml::WeakPtr<IOManager>& io_manager,
83- bool supports_wide_gamut)
83+ bool supports_wide_gamut,
84+ const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch)
8485 : ImageDecoder(runners, std::move(concurrent_task_runner), io_manager),
85- supports_wide_gamut_ (supports_wide_gamut) {
86+ supports_wide_gamut_ (supports_wide_gamut),
87+ gpu_disabled_switch_(gpu_disabled_switch) {
8688 std::promise<std::shared_ptr<impeller::Context>> context_promise;
8789 context_ = context_promise.get_future ();
8890 runners_.GetIOTaskRunner ()->PostTask (fml::MakeCopyable (
@@ -246,18 +248,11 @@ DecompressResult ImageDecoderImpeller::DecompressTexture(
246248 .image_info = scaled_bitmap->info ()};
247249}
248250
249- std::pair<sk_sp<DlImage>, std::string>
250- ImageDecoderImpeller::UploadTextureToPrivate (
251+ // / Only call this method if the GPU is available.
252+ static std::pair<sk_sp<DlImage>, std::string> UnsafeUploadTextureToPrivate (
251253 const std::shared_ptr<impeller::Context>& context,
252254 const std::shared_ptr<impeller::DeviceBuffer>& buffer,
253255 const SkImageInfo& image_info) {
254- TRACE_EVENT0 (" impeller" , __FUNCTION__);
255- if (!context) {
256- return std::make_pair (nullptr , " No Impeller context is available" );
257- }
258- if (!buffer) {
259- return std::make_pair (nullptr , " No Impeller device buffer is available" );
260- }
261256 const auto pixel_format =
262257 impeller::skia_conversions::ToPixelFormat (image_info.colorType ());
263258 if (!pixel_format) {
@@ -318,10 +313,40 @@ ImageDecoderImpeller::UploadTextureToPrivate(
318313 impeller::DlImageImpeller::Make (std::move (dest_texture)), std::string ());
319314}
320315
316+ std::pair<sk_sp<DlImage>, std::string>
317+ ImageDecoderImpeller::UploadTextureToPrivate (
318+ const std::shared_ptr<impeller::Context>& context,
319+ const std::shared_ptr<impeller::DeviceBuffer>& buffer,
320+ const SkImageInfo& image_info,
321+ std::shared_ptr<SkBitmap> bitmap,
322+ const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch) {
323+ TRACE_EVENT0 (" impeller" , __FUNCTION__);
324+ if (!context) {
325+ return std::make_pair (nullptr , " No Impeller context is available" );
326+ }
327+ if (!buffer) {
328+ return std::make_pair (nullptr , " No Impeller device buffer is available" );
329+ }
330+
331+ std::pair<sk_sp<DlImage>, std::string> result;
332+ gpu_disabled_switch->Execute (
333+ fml::SyncSwitch::Handlers ()
334+ .SetIfFalse ([&result, context, buffer, image_info] {
335+ result = UnsafeUploadTextureToPrivate (context, buffer, image_info);
336+ })
337+ .SetIfTrue ([&result, context, bitmap, gpu_disabled_switch] {
338+ // create_mips is false because we already know the GPU is disabled.
339+ result = UploadTextureToShared (context, bitmap, gpu_disabled_switch,
340+ /* create_mips=*/ false );
341+ }));
342+ return result;
343+ }
344+
321345std::pair<sk_sp<DlImage>, std::string>
322346ImageDecoderImpeller::UploadTextureToShared (
323347 const std::shared_ptr<impeller::Context>& context,
324348 std::shared_ptr<SkBitmap> bitmap,
349+ const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch,
325350 bool create_mips) {
326351 TRACE_EVENT0 (" impeller" , __FUNCTION__);
327352 if (!context) {
@@ -370,32 +395,40 @@ ImageDecoderImpeller::UploadTextureToShared(
370395 texture->SetLabel (impeller::SPrintF (" ui.Image(%p)" , texture.get ()).c_str ());
371396
372397 if (texture_descriptor.mip_count > 1u && create_mips) {
373- auto command_buffer = context->CreateCommandBuffer ();
374- if (!command_buffer) {
375- std::string decode_error (
376- " Could not create command buffer for mipmap generation." );
377- FML_DLOG (ERROR) << decode_error;
378- return std::make_pair (nullptr , decode_error);
398+ std::optional<std::string> decode_error;
399+
400+ // The only platform that needs mipmapping unconditionally is GL.
401+ // GL based platforms never disable GPU access.
402+ // This is only really needed for iOS.
403+ gpu_disabled_switch->Execute (fml::SyncSwitch::Handlers ().SetIfFalse (
404+ [context, &texture, &decode_error] {
405+ auto command_buffer = context->CreateCommandBuffer ();
406+ if (!command_buffer) {
407+ decode_error =
408+ " Could not create command buffer for mipmap generation." ;
409+ return ;
410+ }
411+ command_buffer->SetLabel (" Mipmap Command Buffer" );
412+
413+ auto blit_pass = command_buffer->CreateBlitPass ();
414+ if (!blit_pass) {
415+ decode_error = " Could not create blit pass for mipmap generation." ;
416+ return ;
417+ }
418+ blit_pass->SetLabel (" Mipmap Blit Pass" );
419+ blit_pass->GenerateMipmap (texture);
420+
421+ blit_pass->EncodeCommands (context->GetResourceAllocator ());
422+ if (!command_buffer->SubmitCommands ()) {
423+ decode_error = " Failed to submit blit pass command buffer." ;
424+ return ;
425+ }
426+ command_buffer->WaitUntilScheduled ();
427+ }));
428+ if (decode_error.has_value ()) {
429+ FML_DLOG (ERROR) << decode_error.value ();
430+ return std::make_pair (nullptr , decode_error.value ());
379431 }
380- command_buffer->SetLabel (" Mipmap Command Buffer" );
381-
382- auto blit_pass = command_buffer->CreateBlitPass ();
383- if (!blit_pass) {
384- std::string decode_error (
385- " Could not create blit pass for mipmap generation." );
386- FML_DLOG (ERROR) << decode_error;
387- return std::make_pair (nullptr , decode_error);
388- }
389- blit_pass->SetLabel (" Mipmap Blit Pass" );
390- blit_pass->GenerateMipmap (texture);
391-
392- blit_pass->EncodeCommands (context->GetResourceAllocator ());
393- if (!command_buffer->SubmitCommands ()) {
394- std::string decode_error (" Failed to submit blit pass command buffer." );
395- FML_DLOG (ERROR) << decode_error;
396- return std::make_pair (nullptr , decode_error);
397- }
398- command_buffer->WaitUntilScheduled ();
399432 }
400433
401434 return std::make_pair (impeller::DlImageImpeller::Make (std::move (texture)),
@@ -429,8 +462,8 @@ void ImageDecoderImpeller::Decode(fml::RefPtr<ImageDescriptor> descriptor,
429462 target_size = SkISize::Make (target_width, target_height), //
430463 io_runner = runners_.GetIOTaskRunner (), //
431464 result,
432- supports_wide_gamut = supports_wide_gamut_ //
433- ]() {
465+ supports_wide_gamut = supports_wide_gamut_, //
466+ gpu_disabled_switch = gpu_disabled_switch_ ]() {
434467 if (!context) {
435468 result (nullptr , " No Impeller context is available" );
436469 return ;
@@ -446,24 +479,28 @@ void ImageDecoderImpeller::Decode(fml::RefPtr<ImageDescriptor> descriptor,
446479 result (nullptr , bitmap_result.decode_error );
447480 return ;
448481 }
449- auto upload_texture_and_invoke_result = [result, context,
450- bitmap_result ]() {
451- // TODO(jonahwilliams): remove ifdef once blit from buffer to
452- // texture is implemented on other platforms.
482+ auto upload_texture_and_invoke_result = [result, context, bitmap_result,
483+ gpu_disabled_switch ]() {
484+ // TODO(jonahwilliams): remove ifdef once blit from buffer
485+ // to texture is implemented on other platforms.
453486 sk_sp<DlImage> image;
454487 std::string decode_error;
488+
455489#ifdef FML_OS_IOS
456490 std::tie (image, decode_error) = UploadTextureToPrivate (
457- context, bitmap_result.device_buffer , bitmap_result.image_info );
491+ context, bitmap_result.device_buffer , bitmap_result.image_info ,
492+ bitmap_result.sk_bitmap , gpu_disabled_switch);
458493#else
459494 std::tie (image, decode_error) =
460- UploadTextureToShared (context, bitmap_result.sk_bitmap );
461- #endif
495+ UploadTextureToShared (context, bitmap_result.sk_bitmap ,
496+ gpu_disabled_switch, /* create_mips=*/ true );
497+ #endif // FML_OS_IOS
462498 result (image, decode_error);
463499 };
464- // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/123058
465- // Technically we don't need to post tasks to the io runner, but without
466- // this forced serialization we can end up overloading the GPU and/or
500+ // TODO(jonahwilliams):
501+ // https://github.com/flutter/flutter/issues/123058 Technically we
502+ // don't need to post tasks to the io runner, but without this
503+ // forced serialization we can end up overloading the GPU and/or
467504 // competing with raster workloads.
468505 io_runner->PostTask (upload_texture_and_invoke_result);
469506 });
0 commit comments