Rozgrzewanie shaderów i migracja do Impellera
Eliminuj zacięcia przy pierwszym uruchomieniu, wstępnie kompilując shadery i przyjmując renderer Impeller
Rozgrzewanie shaderów i migracja do Impellera to bezpłatna lekcja Flutter Mobile Development na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Flutter Mobile Development, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Flutter Mobile Development zawiera 4 lekcji w sumie.
Dlaczego zacinanie występuje przy pierwszym uruchomieniu
Gdy aplikacja Flutter po raz pierwszy rysuje konkretny efekt, backend GPU musi skompilować bazowy program shaderu na urządzeniu. W starszym backendzie Skia kompilacja ta odbywa się leniwie, dokładnie w środku klatki, która jej potrzebuje.
- Kompilacja shaderu może trwać kilkadziesiąt milisekund.
- Przekracza to budżet 16 ms klatki renderowanej z częstotliwością 60 kl./s, powodując widoczne przycięcie nazywane zacinaniem shaderu.
- Problem jest największy przy pierwszym uruchomieniu, ponieważ nic nie jest jeszcze zapisane w pamięci podręcznej.
Najczęstszymi przyczynami są animacje, przejścia między stronami i rozmycia BackdropFilter.
Gdzie znika czas
Klatka zacinająca się z powodu kompilacji shaderu jest wyraźnie widoczna w widoku Performance narzędzia DevTools jako wysoki słupek wątku rasteryzacji z zdarzeniem ShaderCompilation.
Aby wiarygodnie odtworzyć problem i go zmierzyć, należy uruchomić aplikację w profile mode (nigdy w trybie debug, który jest znacznie wolniejszy i może wprowadzać w błąd):
- Tryb profile zapewnia wydajność zbliżoną do wersji produkcyjnej oraz mechanizmy śledzenia.
- Oś czasu DevTools oznacza zdarzenia kompilacji shaderów, dzięki czemu można potwierdzić przyczynę źródłową przed rozpoczęciem optymalizacji.
// Run the app in profile mode to capture realistic frame timings.
// flutter run --profile
// Then open DevTools > Performance and look for
// 'ShaderCompilation' events on the raster thread.
// flutter run --profile --trace-skiaStrategia rozgrzewania Skia
W starszym backendzie Skia klasycznym rozwiązaniem jest rozgrzewanie shaderów: należy zebrać używane przez aplikację shadery w pakiet, a następnie wstępnie skompilować je podczas uruchamiania, zanim użytkownik zacznie korzystać z aplikacji.
Flutter generuje ten pakiet za pomocą flagi --cache-sksl, która rejestruje programy SkSL (Skia Shader Language) podczas korzystania z aplikacji:
// 1. Run in profile mode, capturing SkSL while you navigate every screen
// and trigger every animation that might cause jank.
// flutter run --profile --cache-sksl --purge-persistent-cache
// 2. In the running app, press 'M' in the terminal to write the
// captured shaders to a JSON file, e.g. flutter_01.sksl.jsonTworzenie pakietu przechwyconych shaderów
Gdy masz już przechwycony plik .sksl.json, dołącz go do kompilacji wydaniowej. Flutter wstępnie kompiluje te shadery podczas fazy rozgrzewania silnika, dzięki czemu są gotowe przed wyświetleniem pierwszej klatki użytkownikowi.
- Przechwytuj shadery na fizycznym urządzeniu podobnym do docelowego sprzętu.
- Wykonuj przechwytywanie ponownie za każdym razem, gdy interfejs znacząco się zmieni.
// Bundle the captured SkSL into a release build:
// flutter build apk --bundle-sksl-path flutter_01.sksl.json
// flutter build ios --bundle-sksl-path flutter_01.sksl.json
// The engine warms up these shaders at launch,
// eliminating compile stalls during animations.Dlaczego rozgrzewanie Skia to rozwiązanie tymczasowe
Rozgrzewanie SkSL działa, ale ma istotne wady, które skłoniły zespół do opracowania głębszego rozwiązania:
- Przechwycone dane są zależne od urządzenia i sterownika; pakiet z jednego układu GPU może nie obejmować innego.
- Po zmianach interfejsu trzeba pamiętać o ponownym przechwyceniu danych, inaczej zacinanie po cichu powróci.
- Obejmuje tylko te shadery, które zostały użyte podczas przechwytywania.
Trwałą odpowiedzią zespołu Fluttera jest nowy silnik renderowania, który w ogóle nie kompiluje shaderów w czasie działania: Impeller.
Jak Impeller eliminuje problem
Impeller wstępnie kompiluje niewielki, stały zestaw shaderów podczas kompilowania silnika, a nie w czasie działania. Zamiast generować dowolne shadery dla każdego wywołania rysowania, składa efekty ze znanych wcześniej programów.
- Brak kompilowania shaderów w czasie działania oznacza brak zacinania przy pierwszym uruchomieniu z założenia.
- Na iOS używa
Metal, a na nowoczesnym AndroidzieVulkan. - Ponieważ shadery są znane z wyprzedzeniem, rozgrzewanie za pomocą
--cache-sksljest zbędne i nieobsługiwane przez Impeller.
Domyślny status Impellera
Impeller jest obecnie domyślnym rendererem na iOS oraz na nowoczesnym Androidzie (na urządzeniach obsługujących Vulkan), zgodnie z najnowszymi stabilnymi wydaniami Fluttera. Na starszym sprzęcie z Androidem bez obsługi Vulkan silnik automatycznie korzysta z backendu OpenGL.
Większość aplikacji uzyskuje te korzyści bez zmian w kodzie. Migracja polega na zweryfikowaniu poprawności wizualnej i obsłudze kilku przypadków brzegowych, w których Impeller i Skia zachowują się inaczej.
Przełączanie Impellera dla poszczególnych platform
Impellerem steruje się za pomocą natywnych manifestów platformy, a nie kodu Dart. Dzięki temu można go włączyć, wyłączyć lub porównać z Skią podczas testów migracji.
Na iOS ustaw flagę w pliku Info.plist, a na Androidzie w pliku AndroidManifest.xml:
<!-- ios/Runner/Info.plist -->
<key>FLTEnableImpeller</key>
<true/>
<!-- android/app/src/main/AndroidManifest.xml (inside <application>) -->
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="true" />Własne shadery nadal wymagają rozgrzewania
Jeśli dostarczają Państwo własne shadery fragmentów GLSL za pomocą FragmentProgram, stanowią one Państwa kod i nie należą do wbudowanego zestawu Impellera. Kompilowanie lub wczytywanie ich na żądanie nadal może zatrzymać renderowanie klatki.
Rozwiązaniem jest wczytanie ich i rozgrzanie podczas uruchamiania aplikacji, zanim zostaną użyte po raz pierwszy w animacji:
import 'package:flutter/material.dart';
class ShaderCache {
static FragmentProgram? ripple;
// Call during startup so the program is ready before first paint.
static Future<void> warmUp() async {
ripple = await FragmentProgram.fromAsset('shaders/ripple.frag');
}
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await ShaderCache.warmUp();
runApp(const MyApp());
}Wstępne renderowanie kosztownych efektów
Nawet po wstępnym skompilowaniu shaderów pierwsze zbudowanie kosztownego widgetu może nadal trwać dłużej niż kolejne. Często stosowaną techniką jest renderowanie ciężkiego efektu poza ekranem podczas ekranu powitalnego lub klatki rozgrzewającej, aby wykonać tę pracę, zanim użytkownik do niego przejdzie.
Po zatwierdzeniu pierwszej klatki można uruchomić jednorazowe renderowanie rozgrzewające trwające jedną klatkę:
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void scheduleWarmUp(VoidCallback warmUpExpensiveEffects) {
// Runs once after the first frame is rendered,
// so warm-up work does not block startup paint.
SchedulerBinding.instance.addPostFrameCallback((_) {
warmUpExpensiveEffects();
});
}Mierzenie efektu
Zawsze potwierdzaj poprawę danymi, a nie przeczuciami. Porównaj najgorszy czas rasteryzacji klatki przed zmianą i po niej, na rzeczywistym urządzeniu, w trybie profile.
Na podstawie przechwyconych czasów renderowania klatek można obliczyć proste statystyki i sprawdzić, czy klatka z 99. percentyla mieści się teraz w budżecie:
void main() {
// Raster times in milliseconds captured before the warm-up fix.
final frames = <double>[8.1, 7.9, 42.6, 8.0, 9.3, 8.2, 7.7];
frames.sort();
final worst = frames.last;
final p50 = frames[frames.length ~/ 2];
const budget = 16.0; // 60fps frame budget
print('p50: ${p50}ms worst: ${worst}ms');
print(worst > budget
? 'Jank present: worst frame exceeds ${budget}ms'
: 'All frames within budget');
}Szybkie sprawdzenie
Migrują Państwo aplikację na poziomie C1 ze Skia do Impellera, aby naprawić zacinanie shaderów przy pierwszym uruchomieniu. Co stanie się z istniejącym pakietem rozgrzewającym SkSL i dlaczego?
Podsumowanie
Wiedzą już Państwo, jak wyeliminować zacinanie shaderów przy pierwszym uruchomieniu we Flutterze:
- Diagnozowanie zatrzymań spowodowanych kompilacją shaderów w widoku Performance narzędzia DevTools, z użyciem trybu profile.
- Rozgrzewanie Skia za pomocą
--cache-sksli--bundle-sksl-pathwstępnie kompiluje przechwycone shadery SkSL, ale jest zależne od urządzenia i kruche. - Impeller to trwałe rozwiązanie: wstępnie kompiluje stały zestaw shaderów podczas kompilowania, dzięki czemu nie ma kompilowania w czasie działania ani zacinania shaderów. Jest domyślny na iOS oraz na nowoczesnym Androidzie (z Vulkanem).
- Impellera można przełączać za pomocą
Info.plistiAndroidManifest.xml; po migracji należy usunąć pakiet SkSL. - Własne shadery FragmentProgram nadal wymagają jawnego rozgrzania podczas uruchamiania.
- Zawsze mierz czas rasteryzacji najgorszej klatki na rzeczywistym urządzeniu, aby potwierdzić poprawę.
Ucz się Dart dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 22
- Lekcje
- 88
Często zadawane pytania
Czy lekcja „Rozgrzewanie shaderów i migracja do Impellera” jest bezpłatna?
Tak — pełny tekst „Rozgrzewanie shaderów i migracja do Impellera” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Flutter Mobile Development, przejdź na CoddyKit PRO. Kurs Flutter Mobile Development zawiera 4 lekcji w sumie.
Co nauczysz się w „Rozgrzewanie shaderów i migracja do Impellera”?
Eliminuj zacięcia przy pierwszym uruchomieniu, wstępnie kompilując shadery i przyjmując renderer Impeller Ćwiczysz Flutter Mobile Development z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Flutter Mobile Development?
Nie wymagamy żadnego doświadczenia. Flutter Mobile Development w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Rozgrzewanie shaderów i migracja do Impellera”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Flutter Mobile Development?
Tak. Każda lekcja Flutter Mobile Development zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Trzy drzewa: Widget, Element i RenderObject
- Profilowanie zacięć za pomocą osi czasu DevTools
- RepaintBoundary, widgety const i ograniczanie przebudowy
- Rozgrzewanie shaderów i migracja do Impellera