Wenn deine Flutter-App nur beim ersten Start ruckelt: Shader Compilation Jank vollständig verstehen

Eine Animation, die im Debug-Modus butterweich mit 60fps läuft, sorgt kaum ist der Release-Build im Store gelandet für Beschwerden von neuen Geräten: „Ruckelt total.“ Öffnet man die App zum Nachstellen erneut auf dem eigenen Entwicklertelefon, läuft alles einwandfrei. Auch in den Logs, die das QA-Team schickt, findet sich keine Exception. Selbst wenn man überall const-Widgets ergänzt, auf ListView.builder umstellt und RepaintBoundary einbaut, bleibt das Symptom bestehen. Passt dieses Muster genau, steckt der Übeltäter mit hoher Wahrscheinlichkeit nicht im Widget-Baum, sondern im Shader Compilation Jank.
Dieser Artikel geht über Allgemeinplätze wie „Benutze const-Widgets“ oder „Halte die build-Methode schlank“ hinaus. Stattdessen klärt er, warum dieses Problem im Debug-Modus grundsätzlich unsichtbar bleibt und erst in Profile- oder Release-Builds auf echten Geräten sichtbar wird, worauf man in den DevTools konkret achten muss, und wie sich der vielzitierte SkSL-Warmup-Prozess in aktuellen Flutter-Versionen tatsächlich verändert hat – belegt durch einen direkten Abgleich von Quellcode und offizieller Dokumentation.
Die wichtigsten Punkte
- Shader Compilation Jank ist ein Stall, der entsteht, weil die GPU für eine draw-Operation, die sie zum ersten Mal sieht, pro Gerät und zur Laufzeit neu einen Shader/eine Pipeline erzeugen muss. Ist der Shader einmal kompiliert, tritt das Problem für diese Operation nicht mehr auf.
- Der Debug-Modus basiert auf JIT, wodurch dieses Problem von vornherein anders kaschiert wird, und Profile-/Release-Modus sind auf Emulatoren/Simulatoren komplett deaktiviert – man muss also zwingend auf einem echten Gerät prüfen.
- Im Frame-Chart der DevTools-Performance-Ansicht sind dunkelrot dargestellte Frames die Signatur eines Shader-Compilation-Spikes.
- Der klassische SkSL-Warmup-Ablauf über
flutter run --profile --cache-skslgefolgt von--bundle-sksl-pathwurde ab Flutter 3.32 (Stable, Mai 2025) vollständig aus der CLI entfernt. Wer diesen Befehl heute noch 1:1 ausführt, bekommt nur noch einen Fehler. - Seit Impeller zum Standard-Renderer geworden ist, ist ein Großteil dieses Problems strukturell verschwunden – aber bei benutzerdefinierten Fragment-Shadern oder dem Fallback-Pfad auf älteren Android-Geräten lauern weiterhin Fallstricke.
Was Jank und das Frame-Budget in der Praxis wirklich bedeuten
Die offizielle Flutter-Dokumentation definiert Jank so: „Wenn ein Frame deutlich länger braucht als üblich und dadurch gedroppt wird, wirkt die Animation ruckelig. Braucht ein Frame beispielsweise zehnmal so lange wie sonst, wird er mit hoher Wahrscheinlichkeit gedroppt – mit dem Ergebnis, dass die Animation stockt.“ Entscheidend ist: Ein einzelner, gelegentlich sehr langsamer Frame zieht die gefühlte Gesamtperformance nach unten. Nicht die durchschnittliche Frame-Zeit, sondern der schlechteste Frame (worst frame) ist die eigentlich relevante Kennzahl.
- 60-Hz-Display: Laut offizieller Dokumentation muss jeder Frame innerhalb von „etwa 16 ms“ gerendert sein, damit kein Jank entsteht.
- 120-Hz-Display: Auf unterstützten Geräten strebt Flutter auch 120fps an, wodurch sich das Frame-Budget rechnerisch auf rund 8,3 ms verkürzt (1000 ms ÷ 120). Weil sich das Budget mehr als halbiert, wirkt derselbe Shader-Compilation-Stall auf einem 120-Hz-Gerät gefühlt deutlich schlimmer.
Dieses Budget verteilt sich auf zwei Threads.
- UI-Thread: Führt in der Dart-VM den App-Code und den Flutter-Framework-Code aus. Er erzeugt den Layer-Tree mit Widget-Builds, Layout und Paint-Kommandos und übergibt ihn an den Raster-Thread. Die offizielle Dokumentation warnt ausdrücklich: „Blockiere diesen Thread nicht.“
- Raster-Thread: Nimmt den Layer-Tree entgegen und zeichnet ihn tatsächlich auf der GPU. Skia und Impeller laufen auf diesem Thread. Man kann ihn nicht direkt beeinflussen – ist er langsam, liegt das letztlich immer an dem, was der Dart-Code angeordnet hat (was gezeichnet werden soll). Nebenbei: Dieser Thread hieß früher „GPU-Thread“, und im Hilfetext des
--trace-skia-Flags steht bis heute unverändert „raster thread (formerly known as the GPU thread)“ – ein kleines Relikt der Umbenennung.
Shader Compilation Jank tritt so gut wie immer im Raster-Thread auf. Das Fingerabdruck-Muster dieses Problems: Der UI-Thread-Graph sieht unauffällig aus, während im GPU-/Raster-Graph allein ein großer roter Balken ausschlägt.
Warum sich das Problem im Debug-Modus nicht reproduzieren lässt
Hier liegt der Punkt, an dem dieses Problem am häufigsten missverstanden wird. Flutters Build-Modi sind kein simpler Optimierungsschalter, sondern vollständig unterschiedliche Ausführungspfade.
- Debug-Modus: Laut offizieller Dokumentation „für einen schnellen Entwicklungs- und Ausführungszyklus kompiliert, nicht optimiert für Ausführungsgeschwindigkeit, Binärgröße oder Deployment“. Asserts sind aktiviert, und DevTools kann für Source-Level-Debugging angehängt werden.
- Profile-Modus: Definiert als Modus, der „einige Debugging-Fähigkeiten behält, aber genug Performance für Profiling bietet“, und ist auf Mobilgeräten dem Release-Modus fast identisch (zusätzlich sind nur Tracing und einige Service-Extensions aktiviert). Und entscheidend: „Der Profile-Modus ist auf Emulatoren/Simulatoren deaktiviert, weil deren Verhalten nicht die reale Performance widerspiegelt.“
- Release-Modus: Asserts werden entfernt, Debugging-Informationen werden gestrippt, und der Modus ist „für schnellen Start, schnelle Ausführung und geringe Paketgröße optimiert“.
Das heißt: Weil der Debug-Modus „Ausführungsgeschwindigkeit“ von vornherein gar nicht als Optimierungsziel hat, treten Performance-Probleme dort entweder ganz anders auf oder gar nicht erst zutage. Hinzu kommt, dass die Shader-Kompilierung grundsätzlich von der konkreten GPU-Hardware und den Treibern des jeweiligen Geräts abhängt. Der Dokumentationskommentar der ShaderWarmUp-Klasse im Flutter-Framework beschreibt das so:
„Dieses Warmup muss auf jedem Gerät individuell ausgeführt werden, da die Shader-Kompilierung von der jeweiligen GPU-Hardware und den Treibern dieses Geräts abhängt. Da die Engine geräteunabhängig ist, kann dies nicht bereits zum Zeitpunkt der Flutter-Engine-Kompilierung vorberechnet werden.“
Dieselbe Dokumentation gibt sogar konkret an, wie lange das Kompilieren eines einzelnen Shaders dauern kann: „Die Kompilierung kann langsam sein (20–200 ms).“ Ballen sich auf einem einzigen Screen fünf, sechs erstmals gesehene Kombinationen aus Gradient, Blur, Schatten und benutzerdefiniertem ShapeBorder, kann rein rechnerisch ein Raster-Spike im Bereich von 100–1000 ms entstehen (das ist ausdrücklich nur die theoretische Spanne aus der simplen Multiplikation der in der Dokumentation genannten Kompilierkosten pro Shader). Das frisst auf einen Schlag mehrere Dutzend Frame-Budgets von je 16 ms bei 60 Hz auf – für die Nutzerin oder den Nutzer sieht das aus, als würde der Bildschirm kurz einfrieren und dann weiterlaufen.
Und diese Kompilierung passiert pro Gerät, und zwar nur in dem Moment, in dem dieses Gerät die betreffende Zeichenoperation zum ersten Mal sieht. Das vertraute Testgerät des Entwicklers hat den Cache möglicherweise schon aufgewärmt, weil dieser Screen dort schon x-mal geöffnet wurde (dieser Cache geht allerdings bei Neuinstallation, Update oder OS-Cache-Löschung wieder verloren) – ein Gerät hingegen, auf dem die App gerade eben aus dem Store geladen wurde, befindet sich im „kalten“ Zustand und begegnet allen Shadern zum ersten Mal. Genau deshalb ist der Bericht „tritt nur auf neuen Geräten auf“ kein Reproduzierbarkeits-Problem, sondern ein exakt vorhersehbares, strukturelles Ergebnis.
Die wahre Ursache in der DevTools-Performance-Ansicht aufspüren
Schritt 1: Unbedingt im Profile-Modus auf einem echten Gerät ausführen
flutter run --profile
Da der Profile-Modus auf Emulatoren/Simulatoren grundsätzlich deaktiviert ist, muss ein echtes Gerät angeschlossen werden – idealerweise ein günstiges, neueres Gerät, das dem ähnelt, auf dem das Problem gemeldet wurde.
Schritt 2: Dunkelrote Frames im Frame-Chart finden
Öffnet man den Performance-Tab der DevTools, wird für jeden Frame ein Balkenpaar aus UI-Thread und Raster-Thread angezeigt. Die offizielle Dokumentation erklärt: „Frames, in denen eine Shader-Kompilierung stattfindet, werden dunkelrot dargestellt.“ Genau diese Farbe ist der visuelle Fingerabdruck von Shader Compilation Jank. Während bei gewöhnlichem Jank (Build-/Layout-Überlastung) zuerst der UI-Thread-Balken rot ausschlägt, zeigt Shader Compilation Jank das Muster, dass allein der Raster-Thread-Balken um mehrere hundert Millisekunden nach oben schießt.
Schritt 3: Den Call-Stack in den Timeline Events prüfen
Klickt man auf den verdächtigen Frame und wechselt in den Tab Timeline Events, lässt sich genau das Muster finden, auf das die Dokumentation der ShaderWarmUp-Klasse hinweist: Ein während der Animation auffällig lang laufender GrGLProgramBuilder::finalize-Aufruf, dessen übergeordneter Aufruf den Namen einer draw-Operation in der Form XyzOp trägt (etwa FillRectOp oder CircularRRectOp). Das bedeutet, dass genau diese draw-Operation eine neue Shader-Kompilierung ausgelöst hat. (Diese Trace-Namen gelten für das Skia-Backend – unter Impeller erscheinen andere, nach Pipeline-Erstellung benannte Events.)
Schritt 4: Mit „Enhance tracing“ höhere Auflösung erzielen
Im Dropdown „Enhance tracing“ des Performance-Tabs gibt es drei Optionen.
- Track Widget Builds: Zeigt
build()-Methodenereignisse und Widget-Namen in der Timeline - Track Layouts: Zeigt Layout-Ereignisse von Render-Objekten
- Track Paints: Zeigt Paint-Ereignisse von Render-Objekten
Wie die offizielle Dokumentation aber warnt, „können diese Optionen die Frame-Zeit selbst beeinflussen“. Man sollte sie also nur zum Eingrenzen der Ursache aktivieren und für die eigentliche Messung wieder ausschalten. Schaltet man im selben Tab unter „More debugging options“ Clip-, Opacity- oder Physical-Shape-Layer einzeln ab, lässt sich zusätzlich isoliert prüfen, ob übermäßiges Clipping oder Schatteneffekte eine neue Pipeline auslösen.
Schritt 5: Reproduzierbarkeit mit --trace-skia und --purge-persistent-cache sicherstellen
flutter run --profile --trace-skia
Laut Hilfetext ist --trace-skia „nützlich zum Debuggen des Raster-Threads (früher GPU-Thread genannt)“ und standardmäßig deaktiviert, da der Overhead hoch ist. Das in der Praxis wichtigste Flag ist aber ein anderes.
flutter run --profile --purge-persistent-cache
Dieses Flag existiert unverändert auch im aktuellen Stable-Flutter, und der Hilfetext beschreibt es exakt so: „Löscht alle vorhandenen persistenten Caches. Dadurch lässt sich Shader Compilation Jank, der normalerweise nur beim allerersten App-Start auftritt, reproduzieren – oder Fixes für Compilation Jank (z. B. Shader-Warmup) lassen sich zuverlässig testen.“ Es handelt sich also um das offizielle Mittel, um selbst auf dem abgenutzten Testgerät eines Entwicklers zwangsweise den Zustand „erster Start auf einem neuen Gerät“ herzustellen. Wer bei QA oder Regressionstests dieses Flag weglässt und nur wiederholt startet, sieht ausschließlich den bereits aufgewärmten Cache – und kann das Problem dauerhaft übersehen.
Der SkSL-Warmup-Cache: die klassische Lösung – und die Falle in der Praxis
Die meisten im Netz kursierenden Tutorials empfehlen an dieser Stelle folgenden Ablauf.
# 1. Im Profile-Modus ausführen und die tatsächlich auftretenden Shader aufzeichnen
flutter run --profile --cache-sksl
# 2. Die App ausgiebig bedienen, um möglichst viele Animationen/Übergänge auszulösen, dann beenden
# → Unter build/ wird eine .sksl.json-Cache-Datei erzeugt
# 3. Diesen Cache in den Release-Build bundeln
flutter build apk --release --bundle-sksl-path flutter_01.sksl.json
flutter build appbundle --release --bundle-sksl-path flutter_01.sksl.json
flutter build ios --release --bundle-sksl-path flutter_01.sksl.json
Dieser Ablauf sollte das strukturelle Problem der Skia-Ära umgehen, bei dem die GPU auf einem neuen Gerät erstmals gesehene Shader zur Laufzeit kompilieren musste. Die Idee: Die während der App-Nutzung tatsächlich verwendeten Shader-Kombinationen vorab aufzeichnen, sie als Cache in den Build packen und beim App-Start gesammelt vorbereiten – damit während der Animation keine Stalls mehr auftreten.
Genau hier liegt die praktische Falle. Führt man den obigen Befehl unverändert in einer aktuellen Flutter-Version aus, funktioniert er nicht. Im GitHub-Issue flutter/flutter#171585 findet sich tatsächlich der Fall eines Entwicklers, der unter Flutter 3.32 oder neuer --bundle-sksl-path verwenden wollte und die Fehlermeldung Could not find an option named '--bundle-sksl-path' erhielt. Schaut man sich die Commit-Historie des Flutter-Repositorys direkt an, wird die Ursache klar: Der am 10. Februar 2025 gemergte Commit 33a4c95de07 („remove SkSL bundling and dump skp on compilation“) hat sämtliche SkSL-Bundling-Optionen aus flutter run, flutter build apk/appbundle/ios und flutter drive entfernt. Die Commit-Message erklärt das so:
„Das SkSL-Precompile war ohnehin nur auf iOS sinnvoll. Auf anderen Plattformen wurde davon abgeraten, weil Skia Shader pro Ziel-Architektur generiert und der Cache auf anderen Geräten dadurch ungültig sein konnte. Jetzt ist Skia auf iOS aber gar nicht mehr verfügbar.“
Diese Änderung ist ab Flutter 3.32.0 (Stable, Mai 2025) enthalten. Prüft man tatsächlich mit einem lokal installierten Flutter-3.44-SDK flutter run --help -v, flutter build apk --help -v und flutter build web --help -v, taucht der String cache-sksl oder bundle-sksl-path an keiner einzigen Stelle mehr auf. Mit anderen Worten: Der Ratschlag „Erzeuge einen SkSL-Warmup-Cache und bundle ihn“ ist auf Basis aktueller Flutter-Versionen schlicht kein ausführbarer Ablauf mehr. Auch die neueste Version der offiziellen Dokumentation (docs.flutter.dev/perf/rendering-performance) hat den Mobile-Ratschlag zu Shader Compilation Jank durch den einen Satz „Stelle sicher, dass du Impeller, Flutters Standard-Renderer, verwendest“ ersetzt.
Was also tun, wenn man diesem Problem heute begegnet
- Zunächst: Lass Impeller einfach eingeschaltet. Solange man es nicht explizit mit
--no-enable-impellerdeaktiviert, ist Impeller in aktuellen Flutter-Versionen bereits der Standard. Wie im folgenden Abschnitt erklärt, übernimmt Impeller strukturell genau die Aufgabe, die früher der SkSL-Cache erledigt hat. - Die
ShaderWarmUp-API existiert im Framework nach wie vor. Registriert man vor dem Aufruf vonrunAppeine benutzerdefinierteShaderWarmUp-Subklasse anPaintingBinding.shaderWarmUp, lassen sich repräsentative draw-Operationen beim App-Start vorab auf eine Offscreen-Canvas zeichnen und die Kompilierkosten so in die Startverzögerung verschieben. Allerdings ist die Dokumentation dieser API selbst noch an Skia-Ära-Konzepten wieGrGLProgramBuilderoder--trace-skiaorientiert, weshalb sie im Impeller-Pfad keinen so verlässlichen Effekt mehr garantiert wie früher. - Bei Legacy-Projekten bleibt der alte Ablauf gültig. Ist ein Projekt auf eine Version vor Flutter 3.32 fixiert oder verwendet unter Android explizit mit
--no-enable-impellernoch den alten Skia/OpenGL-Pfad, funktioniert die Kombination aus--cache-sksl/--bundle-sksl-pathinnerhalb dieser Version weiterhin. Ohne einen konkreten Migrationsplan sich dauerhaft auf diesen Pfad zu verlassen, ist allerdings nicht empfehlenswert.
Was sich seit der Einführung von Impeller geändert hat – und welche Grenzen bleiben
Impeller „behebt“ Shader Compilation Jank nicht, sondern verfolgt den Ansatz, den Zeitpunkt, zu dem das Problem auftritt, komplett zu verschieben. Die offizielle Dokumentation nennt vier Designziele:
- Vorhersehbarkeit (Predictable): Kompilierungs- und Caching-Entscheidungen werden bereits vor der Ausführung fest getroffen
- Instrumentierbarkeit (Instrumentable): Grafik-Ressourcen werden gelabelt, was Profiling und Capture erleichtert
- Portabilität (Portable): Shader werden einmal geschrieben und in backend-spezifische Formate wie Metal/Vulkan/GLES übersetzt
- Modern & nebenläufig (Modern & concurrent): Nutzt moderne Grafik-APIs und verteilt Arbeit auf mehrere Threads
Der aktuelle Stand nach Plattform sieht so aus (laut offizieller Dokumentation docs.flutter.dev/perf/impeller).
| Plattform | Status |
|---|---|
| iOS | Impeller ist der einzig unterstützte Renderer. Ein Zurückwechseln zu Skia ist nicht möglich |
| Android | Standardmäßig aktiv ab API 29 (seit Flutter 3.27). Geräte unter API 29 oder ohne Vulkan-Unterstützung fallen automatisch auf Impellers Legacy-OpenGL-Backend zurück |
| macOS | Opt-in über das Flag --enable-impeller; die Opt-out-Möglichkeit soll in einer künftigen Version ganz entfallen |
| Web | Verwendet noch Skia (CanvasKit). Eine künftige Impeller-Einführung wird erwähnt |
Eine interessante Randnotiz: Ausgerechnet in der CLI-Hilfe von Flutter selbst steht noch ein veralteter Text. Ruft man mit flutter run --help -v die Beschreibung von --enable-impeller auf, liest man dort bis heute: „Impeller is the default renderer on iOS. On Android, Impeller is available but not the default.“ Verfolgt man die Funktion addEnableImpellerFlag im flutter_tools-Quellcode per Git Blame zurück, wurde dieser Text im März 2023 verfasst – also genau zu dem Zeitpunkt, als Impeller gerade eingeführt wurde – und seither kein einziges Mal aktualisiert. Da offizielle Dokumentation und Release Notes die tatsächliche Änderung der Standardwerte korrekt widerspiegeln, sollte man diesen Text in der CLI-Hilfe nicht als reales Verhalten, sondern als vernachlässigten, veralteten Beschreibungsstring einordnen. Selbst so eine kleine Unstimmigkeit sorgt in der Praxis dafür, dass man ins Grübeln gerät: „Ist Impeller in meinem Projekt jetzt eigentlich aktiv oder nicht?“
Der eigentliche Mechanismus, mit dem Impeller Jank beseitigt
Der Kernpunkt ist: „Der Großteil der Shader wird bereits zur Build-Zeit der Engine offline vorkompiliert.“ Geht man hier noch einen Schritt tiefer, findet sich im Quellcode der Impeller-Engine (shell/common/switch_defs.h, common/settings.h) ein interner Switch namens impeller-lazy-shader-mode, dessen Kommentar Folgendes erklärt:
„Ob die Initialisierung aller vom Impeller-Backend benötigten PSOs (Pipeline State Objects) verzögert werden soll. Standardmäßig false.“
Das heißt: Im Standardzustand (false) initialisiert Impeller sämtliche benötigten PSOs bereits eager, also sofort beim App-Start. Was Entwickler früher manuell über ein selbst geschriebenes ShaderWarmUp erledigen mussten – nämlich die Kompilierkosten vom Animationsverlauf in den Start zu verschieben –, übernimmt Impeller nun standardmäßig auf Engine-Ebene. Setzt man in der Android-AndroidManifest.xml das Metadatum io.flutter.embedding.android.ImpellerLazyShaderInitialization auf true, lässt sich diese Initialisierung verzögern und der Kaltstart dadurch etwas beschleunigen – der Preis dafür ist allerdings, dass beim ersten tatsächlichen Gebrauch wieder ein Stall auftreten kann, ähnlich wie zu SkSL-Zeiten. Die korrekte Lesart ist also nicht „mit Impeller gibt es grundsätzlich keinen Jank mehr“, sondern der Standardwert des Trade-offs hat sich verschoben.
Grenzen, die dennoch bestehen bleiben
- Benutzerdefinierte Fragment-Shader:
.frag-Assets, die übershaders:in derpubspec.yamlregistriert sind, kompiliertimpellerczur Build-Zeit offline in backend-spezifische Formate. Ungewöhnliche Kombinationen aus Blend-Modes,BackdropFilterundPlatformView-Compositing-Pfaden können jedoch außerhalb der vorkompilierten Pipeline-Menge liegen, sodass in seltenen Fällen bei der ersten Nutzung noch ein Stall auftritt. Das Flutter-Team bittet darum, solche Regressionen als Issue mit dem Präfix[Impeller]zu melden. - Ältere Android-Geräte ohne Vulkan-Unterstützung: Impellers OpenGL-Fallback-Pfad ist nicht so gut optimiert wie der Vulkan-Pfad.
- Web: Basiert weiterhin auf CanvasKit, weshalb hier die Eigenheiten der Skia-Ära bestehen bleiben.
Die Verbesserung anhand von Vorher/Nachher-Daten verifizieren
Ob ein Fix tatsächlich wirkt, sollte man nicht nach Gefühl, sondern anhand von Zahlen prüfen. Dazu legt man ein reproduzierbares Szenario fest (z. B. App starten → einen Detail-Screen mit vielen Gradients und Schatten öffnen → die Liste dreimal scrollen). Dieses Szenario führt man unter den folgenden zwei Bedingungen jeweils aus und vergleicht die Frame-Liste im DevTools-Performance-Tab.
- Vor dem Fix, mit gelöschtem Cache: Mit
flutter run --profile --purge-persistent-cacheausführen, um „erster Start auf einem neuen Gerät“ zu reproduzieren - Nach dem Fix, unter identischen Bedingungen: Nach Anwendung der Impeller-Prüfung bzw. Warmup-Maßnahmen erneut mit
--purge-persistent-cacheausführen
Beim Vergleich zählt nicht der Durchschnitt, sondern die Raster-Zeit des schlechtesten Frames (worst frame). Vor der Verbesserung sollte ein bestimmter Frame das Budget (16 ms bzw. 8,3 ms) um ein Vielfaches überschreiten und dunkelrot markiert sein; nach der Verbesserung prüft man im selben Szenario, ob dieser Spike verschwunden ist und alle Frames innerhalb des Budgets liegen – visuell im Frame-Chart und auf Ebene des Call-Stacks in den Timeline Events. Möchte man in der CI einen Performance-Regressionstest ergänzen, sollte man dasselbe Szenario mit flutter drive automatisieren und bei jedem Lauf --purge-persistent-cache erzwingen – entscheidend, damit ein „aufgewärmter Cache“ eine Regression nicht unbemerkt lässt.
Checkliste
- Wurde versucht, das Problem ausschließlich in einem Profile- oder Release-Build auf einem echten Gerät zu reproduzieren (im Emulator/Debug-Modus ist es von vornherein nicht sichtbar)?
- Wurden im DevTools-Performance-Tab dunkelrote Frames im Raster-Thread überprüft?
- Wurde mit
--purge-persistent-cacheder Zustand „erster Start auf einem neuen Gerät“ erzwungen und getestet? - Wurde geprüft, ob Impeller in der aktuellen Flutter-Version tatsächlich aktiv ist (und nicht versehentlich per
--no-enable-impellerdeaktiviert wurde)? - Ist bekannt, dass
--cache-sksl/--bundle-sksl-pathab Flutter 3.32 entfernt wurden? - Werden Screens mit benutzerdefinierten
.frag-Shadern oder ungewöhnlichen Blend-Modes/BackdropFilter separat in Betracht gezogen? - Wurde vorher/nachher anhand der Raster-Zeit des schlechtesten Frames verglichen?