-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Avoid encoding metal commands while the GPU is unavailable when decoding images. #42349
Conversation
… when decoding images.
gaaclarke
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good for the most part. The only thing that should get changed is removing the conditional compilation. I think we should treat sync_switch as a nonnull parameter instead. Also, I want clarity in for the true branches of the syncswitches. We should have comments that at least explain their omission.
| FML_DLOG(ERROR) << decode_error; | ||
| return std::make_pair(nullptr, decode_error); | ||
| std::optional<std::string> decode_error; | ||
| #if FML_OS_IOS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other platforms also have a sync switch that is never switched off, so there's no need to introduce conditional compilation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, that will actually make this more testable too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can refactor UploadToPrivate to work more nicely if we're on iOS.
| return std::make_pair(nullptr, decode_error); | ||
| std::optional<std::string> decode_error; | ||
| #if FML_OS_IOS | ||
| gpu_disabled_switch->Execute(fml::SyncSwitch::Handlers().SetIfFalse( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the true branch be setting decode_error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No - added a comment. We only need to do this unconditionally for GL,and we'll always unconditionally do it for GL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We ripped out opengl for iOS right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct
lib/ui/painting/image_decoder.h
Outdated
| std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner, | ||
| fml::WeakPtr<IOManager> io_manager); | ||
| fml::WeakPtr<IOManager> io_manager, | ||
| const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch = nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everyone should have a syncswitch so there's no need to support nullptr.
| [&needs_upload, &image, &decode_error, &context, | ||
| &bitmap_result] { | ||
| needs_upload = false; | ||
| FML_LOG(ERROR) << "Yay"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stray log.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(removed the one below too)
| #endif | ||
| FML_DCHECK(gpu_disabled_switch); | ||
| if (gpu_disabled_switch) { | ||
| gpu_disabled_switch->Execute(fml::SyncSwitch::Handlers().SetIfFalse( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's worth adding a comment about the omission of a true branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got moved and there's no longer an omission.
|
Added a test. Ideally this would get a screenshot based test on a real device, but that will probably take some more time to write. For now the test I added validates that if the sync switch is disabled we do not create any command buffers. |
| result = UnsafeUploadTextureToPrivate(context, buffer, image_info); | ||
| }) | ||
| .SetIfTrue([&result, context, bitmap, gpu_disabled_switch] { | ||
| // create_mips is false because we already know the GPU is disabled. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this result in suboptimal rendering based on when the gpu is disabled? Are we going to get bug reports about blurry images that we can't source back to coming from backgrounded apps?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can result in suboptimal rendering. We could choose to build mips when the GPU is available again, but that's going to be a more invasive/risky change. I'd like this to be cherry pickable.
| return std::make_pair(nullptr, decode_error); | ||
| std::optional<std::string> decode_error; | ||
| #if FML_OS_IOS | ||
| gpu_disabled_switch->Execute(fml::SyncSwitch::Handlers().SetIfFalse( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We ripped out opengl for iOS right?
shell/common/engine_unittests.cc
Outdated
| /*font_collection=*/std::make_shared<FontCollection>(), | ||
| /*runtime_controller=*/std::move(runtime_controller_)); | ||
| /*runtime_controller=*/std::move(runtime_controller_), | ||
| /*gpu_disabled_switch=*/nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: make syncswitches here since technically it isn't supposed to be null. We could also add a dcheck that it isn't null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| return; | ||
| } | ||
| command_buffer->WaitUntilScheduled(); | ||
| })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't something we should solve now, but we'll eventually need a solution to defer generating mipmaps. Not generating mipmaps will cause min filtered images to continue appearing more blurry than Skia once we start properly setting the mip bias.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed flutter/flutter#127697
| return; | ||
| } | ||
| blit_pass->SetLabel("Mipmap Blit Pass"); | ||
| blit_pass->GenerateMipmap(texture); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The texture.NeedsMipmapGeneration() check also needs to be removed from render_pass_mtl.mm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we change that to a DLOG on iOS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ifdef'd it out for IOS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to rethink these safety checks in general and have the HAL be less opinionated about it. While it's unsafe for GLES and probably worth tracking in some way, fully mipmapped textures can be uploaded and/or single mip levels can be replaced individually (albeit, Impeller doesn't support this yet). One example is storing radiance maps for image based lighting.
Co-authored-by: gaaclarke <[email protected]>
Co-authored-by: gaaclarke <[email protected]>
bdero
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…navailable when decoding images. (flutter/engine#42349)
…127702) flutter/engine@858d975...eed12f3 2023-05-26 [email protected] Started executing vulkan unit tests with validation on macos (flutter/engine#42337) 2023-05-26 [email protected] [Impeller] Avoid encoding metal commands while the GPU is unavailable when decoding images. (flutter/engine#42349) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Issue: flutter/flutter#126878 Picks in #42349 and #42175 The reason for the second is that the first creates many more conflicts without it, and resolving them was a lot easier. The second PR is also very low risk and improves error messaging.
Fixes flutter/flutter#126878
This disables device private upload on iOS when backgrounded, and disables mipmap generation when backgrounded.
We don't have a good way to test the core problem in this repo because it only reproduces on physical iOS hardware - simulators don't really care if you do this stuff in the background.
I'll write a devicelab test in the framework to capture this. In the mean time it can be reviewed.
We could consider making the IOManager a shared_ptr instead of having an fml::WeakPtr and that'd clean up some of the extra arguments to engine construction - or we could consider vending the sync switch from impeller::Context unconditionally, but it's pretty iOS specific...