Flutter Mobile Development · Lezione

Riscaldamento degli shader e migrazione a Impeller

Elimini gli scatti al primo avvio precompilando gli shader e adottando il renderer Impeller.

Lezione 4 di 413 passaggi

Riscaldamento degli shader e migrazione a Impeller è una lezione Flutter Mobile Development gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Flutter Mobile Development, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Flutter Mobile Development include 4 lezioni in totale.

Perché si verifica il jank al primo avvio

La prima volta che un'app Flutter disegna un determinato effetto, il backend GPU deve compilare il programma shader sottostante sul dispositivo. Con il backend Skia legacy, questa compilazione avviene in modo lazy, proprio nel frame che ne ha bisogno.

  • La compilazione di uno shader può richiedere decine di millisecondi.
  • Questo supera il budget di 16 ms di un frame a 60 fps e produce uno scatto visibile chiamato shader jank.
  • Il problema è più grave proprio al primo avvio, perché non è ancora presente alcuna cache.

Le cause più comuni sono le animazioni, le transizioni tra pagine e le sfocature di BackdropFilter.

Dove va a finire il tempo

Un frame con jank causato dalla compilazione di shader è chiaramente visibile nella vista Performance di DevTools come una barra alta del thread raster con un evento ShaderCompilation.

Per riprodurlo e misurarlo in modo affidabile, esegua l'app in profile mode (mai in debug mode, che è molto più lento e fuorviante):

  • La profile mode offre prestazioni simili a quelle di una release con gli hook per il tracing.
  • La timeline di DevTools contrassegna gli eventi di compilazione degli shader, così può confermare la causa principale prima di ottimizzare.
// 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-skia

La strategia di warm-up di Skia

Con il backend Skia legacy, la correzione classica è lo shader warm-up: raccolga gli shader usati dalla sua app in un bundle, quindi li precompili all'avvio prima che l'utente interagisca con l'app.

Flutter genera questo bundle per Lei con il flag --cache-sksl, che registra i programmi SkSL (Skia Shader Language) mentre usa l'app:

// 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.json

Creare il bundle degli shader acquisiti

Quando dispone del file .sksl.json acquisito, lo includa nella build di release. Flutter precompila questi shader durante la fase di warm-up del motore, così sono pronti prima del primo frame visualizzato dall'utente.

  • Esegua l'acquisizione su un dispositivo fisico simile all'hardware di destinazione.
  • Ripeta l'acquisizione ogni volta che l'interfaccia cambia in modo significativo.
// 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.

Perché il warm-up di Skia è solo un cerotto

Il warm-up SkSL funziona, ma presenta svantaggi concreti che hanno motivato una soluzione più profonda:

  • L'acquisizione è specifica per dispositivo e driver; un bundle creato per una GPU potrebbe non coprirne un'altra.
  • Deve ricordarsi di ripetere l'acquisizione dopo le modifiche all'interfaccia, altrimenti il jank ritorna senza avvisi.
  • Copre solo gli shader che ha utilizzato durante l'acquisizione.

La risposta definitiva del team Flutter è un nuovo motore di rendering che non compila affatto gli shader durante l'esecuzione: Impeller.

Come Impeller elimina il problema

Impeller precompila un insieme ridotto e fisso di shader durante la compilazione del motore, anziché durante l'esecuzione. Invece di generare shader arbitrari per ogni chiamata di disegno, compone gli effetti usando questi programmi noti in anticipo.

  • Nessuna compilazione degli shader durante l'esecuzione significa nessun shader jank al primo avvio per progettazione.
  • Usa Metal su iOS e Vulkan sulle versioni moderne di Android.
  • Poiché gli shader sono noti in anticipo, il warm-up con --cache-sksl non è necessario né supportato con Impeller.

Stato predefinito di Impeller

Impeller è ora il renderer predefinito su iOS e sulle versioni moderne di Android (dispositivi che supportano Vulkan), nelle versioni stabili recenti di Flutter. Sui dispositivi Android meno recenti privi di Vulkan, il motore passa automaticamente a un backend OpenGL.

La maggior parte delle app ottiene questo vantaggio senza modifiche al codice. Il lavoro di migrazione consiste nel verificare la correttezza visiva e nel gestire i pochi casi limite in cui Impeller e Skia si comportano diversamente.

Attivare o disattivare Impeller per piattaforma

Controlla Impeller tramite i manifest nativi della piattaforma, non tramite codice Dart. In questo modo può attivarlo, disattivarlo o confrontarlo con Skia durante i test di migrazione.

Su iOS, imposti il flag in Info.plist; su Android, in 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" />

Gli shader personalizzati richiedono ancora il warm-up

Se distribuisce i suoi shader fragment GLSL tramite FragmentProgram, questi fanno parte del suo codice e non dell'insieme integrato di Impeller. Compilarli o caricarli su richiesta può ancora bloccare un frame.

La soluzione consiste nel caricarli e prepararli durante l'avvio dell'app, prima che vengano usati per la prima volta in un'animazione:

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());
}

Pre-renderizzare gli effetti costosi

Anche con gli shader precompilati, la prima build di un widget costoso può richiedere più tempo delle build successive. Una tecnica comune consiste nel renderizzare l'effetto pesante fuori schermo durante una schermata di avvio o un frame di warm-up, così il lavoro viene completato prima che l'utente vi acceda.

Può eseguire un rendering di warm-up di un frame dopo il commit del primo frame:

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();
  });
}

Misurare il miglioramento

Confermi sempre il miglioramento con i dati, non con le sensazioni. Confronti il tempo raster del frame peggiore prima e dopo, su un dispositivo reale e in profile mode.

Può calcolare semplici statistiche a partire dai tempi dei frame acquisiti per verificare che ora il frame al 99° percentile rientri nel budget:

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');
}

Verifica rapida

Migra un'app di livello C1 da Skia a Impeller per risolvere il jank degli shader al primo avvio. Che cosa succede al bundle di warm-up SkSL esistente e perché?

Riepilogo

Ora sa come eliminare il jank degli shader al primo avvio in Flutter:

  • Diagnostichi i blocchi dovuti alla compilazione degli shader nella vista Performance di DevTools usando la profile mode.
  • Il warm-up di Skia con --cache-sksl e --bundle-sksl-path precompila gli SkSL acquisiti, ma è specifico per dispositivo e fragile.
  • Impeller è la soluzione definitiva: precompila un insieme fisso di shader durante la build, quindi non c'è compilazione durante l'esecuzione e, per progettazione, non c'è shader jank. È il renderer predefinito su iOS e su Android moderno (Vulkan).
  • Attivi o disattivi Impeller tramite Info.plist e AndroidManifest.xml; dopo la migrazione, elimini il bundle SkSL.
  • Gli shader personalizzati di FragmentProgram richiedono ancora un warm-up esplicito all'avvio.
  • Misuri sempre il tempo raster del frame peggiore su un dispositivo reale per confermare il miglioramento.
Gratis per iniziare

Impara Dart con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
22
Lezioni
88

Domande Frequenti

La lezione «Riscaldamento degli shader e migrazione a Impeller» è gratuita?

Sì — il testo completo di «Riscaldamento degli shader e migrazione a Impeller» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Flutter Mobile Development, passa a CoddyKit PRO. Il corso Flutter Mobile Development include 4 lezioni in totale.

Cosa imparerò in «Riscaldamento degli shader e migrazione a Impeller»?

Elimini gli scatti al primo avvio precompilando gli shader e adottando il renderer Impeller. Eserciti Flutter Mobile Development con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Flutter Mobile Development?

Non è richiesta alcuna esperienza precedente. Flutter Mobile Development su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Riscaldamento degli shader e migrazione a Impeller»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Flutter Mobile Development?

Sì. Ogni lezione Flutter Mobile Development include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. I tre alberi: Widget, Element e RenderObject
  2. Profilazione degli scatti con la Timeline di DevTools
  3. RepaintBoundary, widget const e riduzione dei rebuild
  4. Riscaldamento degli shader e migrazione a Impeller
← Torna a Flutter Mobile Development