Repository navigation
Description
Description
On Android with Impeller's OpenGL ES backend, calling Image.toByteData() on an image made by Picture.toImage() crashes the app if the call happens while Flutter has no window surface. This happens, for example, right after the app goes to the background, or before the surface is created.
This is a regression on main, caused by #191747. Flutter 3.47.5 does not crash in the same scenario.
This was encountered when trying to debug #193428 (comment) with the linked repro app.
Steps to reproduce
- Use an Android device on Impeller OpenGL ES. A device that uses Vulkan can be forced onto OpenGL ES in a debug or profile build by adding this to
AndroidManifest.xml:<meta-data android:name="io.flutter.embedding.android.ImpellerBackend" android:value="opengles" />
- In a loop, draw something into a
Picture, calltoImage(), then calltoByteData()on the result. - Send the app to the background (or cover it with another activity) while the loop is running.
Using the repro app at #193428 (comment) works (if needed, modify it to force OpenGL ES instead of Vulkan).
Expected results
No crash.
Actual results
The app crashes on the raster thread.
Release/profile builds (SIGSEGV, null or garbage pointer):
BlitCopyBufferToTextureCommandGLES::Encode blit_command_gles.cc:227
EncodeCommandsInReactor blit_pass_gles.cc
ReactorGLES::FlushOps / React reactor_gles.cc
BlitPassGLES::EncodeCommands
ContentContext::ContentContext content_context.cc
AiksContext::AiksContext
...
Debug builds fail at an earlier DCHECK:
[FATAL:flutter/impeller/renderer/backend/gles/reactor_gles.cc(204)] Check failed: CanReactOnCurrentThread().
ReactorGLES::CreateUntrackedHandle reactor_gles.cc:204
TextureGLES::TextureGLES
ContentContext::ContentContext content_context.cc:606
AiksContext::AiksContext
Rasterizer::GetAiksContext rasterizer.h:724
ImageEncodingImpeller::ConvertDlImageToSkImage image_encoding_impeller.cc:157
...
Root cause
On OpenGL ES, GL calls only work on a thread that has a GL context "current". Normally the raster thread uses the window surface's context.
toByteData() on a raster-owned image runs on the raster thread and asks Rasterizer::GetAiksContext() for an AiksContext (here). When there is no window surface, GetAiksContext() builds a new AiksContext. Building one makes GL calls, so it requires a current GL context. With no surface, no GL context is current on the raster thread, so we end up crashing. In debug builds, a DCHECK catches the GL call made without a current context before a crash. Release/profile builds end up crashing later due to invalid pointers caused by this (here).
This started with #191747 (87c02198123, "[wimp] Turn on multithreading for wimp"), which made ImageEncodingImpeller::ConvertDlImageToSkImage get an AiksContext from GetAiksContext(). Before that, toByteData() never built an AiksContext, which is why 3.47.5 is not affected.
Activity
[Impeller] Make a GL context current before constructing an AiksConte…
[Impeller] Make a GL context current before constructing an AiksConte…