You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Eagerly initializeAiksContext on the raster thread during Shell::Create instead of waiting until SurfaceView.surfaceCreated #195920
Problem:
On Android (both OpenGL ES and Vulkan), impeller::Context is created during Shell::Create, but AiksContext and ContentContext are not constructed until the Android SurfaceView finishes layout and fires surfaceCreated—250–300 ms later during cold start on a mokey device.
Because ContentContext is what enqueues default render pipelines onto PipelineCompileQueueGLES or the concurrent worker pool on Vulkan, the background shader compilation threads sit idle during the entire 250–300 ms window while the UI thread is initializing the Dart root isolate, registering plugins, and running the initial widget build/layout. When the first frame is finally rasterized, Rasterizer::Draw stalls waiting for those default pipelines to finish compiling.
Proposed Change:
During Shell::Create, once the impeller::Context is set up on the raster thread, eagerly construct the shared AiksContext. This immediately kicks off background default pipeline compilation in parallel with Dart isolate startup and Android view layout, and removes ContentContext construction from the synchronous surfaceCreated latch on the platform thread.
I have a quick-and-dirty prototype that I can share, which unfortunately AI assistants have not been able to massage into something land-able. This work appears to require the clever and thoughtful touch of a real human bean. I can also share perfetto traces showing the speedup, but GitHub won't let me attach them to this issue.
Okay, i spent some time poking around here. I think the easiest thing is not to fiddle around with ownership and creation time, but just split out the logic for warming up shaders from ContentContext into a static function and allow it to be exercised once the Context is created.
There is a minor gotcha with that approach though (any approach really). On opengles the hard work for creating shaders is agnostic to the pixel format of the surface you are drawing to. On vulkan, when you create the Context, you don't know the pixel format of the surface and the pixel format is information compiled into the pipeline, so you might compile the wrong variant and throw it away. However, the process is a fair bit lighter on vulkan.
Thanks zach. I was going to measure today but that sounds promising. I can try to get it cleaned up and in review. There is an outstanding question if we just want to do it for opengles though.
OpenGL ES is where the biggest latency issues are AFAIU, so that makes sense. Let me know if it would be helpful for me get Vulkan numbers as well though. My agent is happy to run benchmarks and gather Perfetto traces while I eat lunch =)
I re-ran benchmarks against tip-of-tree on mokey with and without #196069. That change is a regression on Vulkan when the first frame doesn't use many shaders, but positive everywhere else. The issue is that the mokey only has two big cores and starting shader warming more eagerly creates more contention in the Vulkan backend. On a device with more cores, the change could be an improvement for Vulkan as well, but it might be more safe to reland only for OpenGL ES, if possible.
Summary Across All 4 Configurations on mokey (Clean Uninstalled Runs, $n=3$ each)
Benchmark & Backend
timeToFirstFrameMicros (Without $\rightarrow$ With Prewarm)
GPURasterizer::Draw Start (Without $\rightarrow$ With Prewarm)
GPURasterizer::Draw Duration (Without $\rightarrow$ With Prewarm)
timeToFirstFrameRasterizedMicros (Without $\rightarrow$ With Prewarm)
Activity
walley892 commentedon Nov 3, 2026
@zanderso Great minds think alike (and so do ours, apparently) #195546.
zanderso commentedon Nov 3, 2026
Cool. Any thoughts on expanding that PR or doing a subsequent one that also works for OpenGL?
gaaclarke commentedon Nov 5, 2026
Here's a sequence diagram demonstrating zach's observation.
gaaclarke commentedon Nov 5, 2026
Okay, i spent some time poking around here. I think the easiest thing is not to fiddle around with ownership and creation time, but just split out the logic for warming up shaders from ContentContext into a static function and allow it to be exercised once the Context is created.
There is a minor gotcha with that approach though (any approach really). On opengles the hard work for creating shaders is agnostic to the pixel format of the surface you are drawing to. On vulkan, when you create the Context, you don't know the pixel format of the surface and the pixel format is information compiled into the pipeline, so you might compile the wrong variant and throw it away. However, the process is a fair bit lighter on vulkan.
Anyways here is the alternative sequence diagram
And a prototype PR: #196069
I haven't measured it yet. The change is pretty minimal compared to the other ideas being considered. So, promising.
zanderso commentedon Nov 6, 2026
I tried the prototype in #196069 on OpenGL ES on mokey, and it reduced time to first frame by ~160ms.
gaaclarke commentedon Nov 6, 2026
Thanks zach. I was going to measure today but that sounds promising. I can try to get it cleaned up and in review. There is an outstanding question if we just want to do it for opengles though.
zanderso commentedon Nov 6, 2026
OpenGL ES is where the biggest latency issues are AFAIU, so that makes sense. Let me know if it would be helpful for me get Vulkan numbers as well though. My agent is happy to run benchmarks and gather Perfetto traces while I eat lunch =)
zanderso commentedon Nov 6, 2026
Improvement in startup latency on Vulkan on mokey is a little under 100ms.
zanderso commentedon Nov 6, 2026
Here's what I'm using to benchmark, by the way: https://github.com/zanderso/flutter_startup_stress
[android]: prewarms shaders when the context is created (flutter#196069)
zanderso commentedon Nov 12, 2026
I re-ran benchmarks against tip-of-tree on mokey with and without #196069. That change is a regression on Vulkan when the first frame doesn't use many shaders, but positive everywhere else. The issue is that the mokey only has two big cores and starting shader warming more eagerly creates more contention in the Vulkan backend. On a device with more cores, the change could be an improvement for Vulkan as well, but it might be more safe to reland only for OpenGL ES, if possible.
Summary Across All 4 Configurations on$n=3$ each)
mokey(Clean Uninstalled Runs,timeToFirstFrameMicros(WithoutGPURasterizer::DrawStart (WithoutGPURasterizer::DrawDuration (WithouttimeToFirstFrameRasterizedMicros(Withoutcomplex_layout(Vulkan)162.3225.2 ms(+62.9 ms)331.8456.7 ms(+124.9 ms)129.554.3 ms(-75.2 ms)464.5527.2 ms(+62.7 ms / +13.5%)complex_layout(OpenGL ES)175.7188.4 ms(+12.7 ms)338.3336.7 ms(-1.6 ms)88.465.6 ms(-22.8 ms)428.8404.3 ms(-24.5 ms / -5.7%)flutter_startup_stress(Vulkan)278.2349.2 ms(+71.0 ms)462.3555.9 ms(+93.6 ms)251.964.9 ms(-187.1 ms)717.6647.1 ms(-70.5 ms / -9.8%)flutter_startup_stress(OpenGL ES)278.8300.8 ms(+22.0 ms)454.8462.7 ms(+7.9 ms)294.7151.0 ms(-143.7 ms)751.9616.3 ms(-135.5 ms / -18.0%)Revert: [android]: prewarms shaders when the context is created (flut…