Что такое rendering pipeline во Flutter и как работает Skia/Impeller?
Flutter рендерит кадры через этапы Build → Layout → Paint → Compositing → Rasterization в двух потоках (UI и Raster). Skia компилирует шейдеры в рантайме; Impeller предкомпилирует их заранее, устраняя jank.
Rendering Pipeline во Flutter
Flutter рисует каждый кадр самостоятельно, минуя нативные UI-компоненты платформы. Это обеспечивает пиксельную идентичность на всех платформах и предсказуемую производительность.
Этапы рендеринга
Каждый кадр проходит через несколько фаз в строгой последовательности:
- Build — вызываются методы
build()виджетов, формируется дерево Element и RenderObject. - Layout — RenderObject получают constraints от родителей (BoxConstraints) и вычисляют свои размеры снизу вверх. Один проход: O(n).
- Paint — RenderObject записывают drawing commands в PictureRecorder (Canvas API). Это команды, а не пиксели.
- Compositing — слои (Layer tree) собираются в сцену. RepaintBoundary создаёт отдельный слой.
- Rasterization — scene передаётся в rendering backend (Skia или Impeller), который растеризует её и отправляет в GPU framebuffer через platform view.
Два потока
Flutter использует два основных потока:
- UI thread (Dart) — выполняет Build/Layout/Paint, управляет виджетами и бизнес-логикой.
- Raster thread — выполняет Compositing и Rasterization; взаимодействует с GPU через Skia/Impeller.
Skia
Skia — C++ графическая библиотека от Google (также используется в Chrome). Flutter использовал Skia как основной backend с самого начала. Особенности:
- Компилирует GLSL-шейдеры в рантайме при первом использовании — источник shader compilation jank.
- Поддерживает Vulkan, OpenGL ES, Metal.
- На iOS Flutter использует Metal через Skia (SkSL шейдеры транслируются в MSL).
Impeller
Impeller — новый rendering backend, разработанный командой Flutter, стал дефолтным на iOS (Flutter 3.10) и Android (Flutter 3.16+). Ключевые отличия:
- Нет runtime shader compilation — все шейдеры предкомпилированы в офлайн на этапе сборки Flutter Engine. Это полностью устраняет shader jank.
- Использует Metal на iOS и Vulkan на Android (fallback на OpenGL ES).
- Новая архитектура tessellation — кривые Безье растеризуются через tessellation, а не через Skia Path rendering.
- Более предсказуемое время кадра.
Как проверить активный backend
# Проверить, используется ли Impeller
flutter run --verbose 2>&1 | grep -i impeller
# Принудительно включить Impeller (Android)
flutter run --enable-impeller
# Принудительно выключить (если есть баги)
flutter run --no-enable-impeller
// Программная проверка backend в коде
import 'package:flutter/foundation.dart';
void printBackend() {
// Доступно только через FlutterEngine internals
// На практике проверяется через dart:ui version info
debugPrint('DartVM: ${Platform.version}');
}
Raster Cache
Flutter кэширует растеризованные слои в GPU texture, чтобы не рерастеризовать статичные части UI каждый кадр. RepaintBoundary указывает engine создать отдельный кэшируемый слой:
// Статичный виджет с дорогостоящим рисованием
RepaintBoundary(
child: ComplexStaticChart(),
)
Подводные камни
- Raster cache занимает GPU-память — слишком много RepaintBoundary приведёт к OOM на устройствах с малым объёмом памяти.
- Impeller пока не поддерживает все функции Skia (некоторые DrawPath операции работают иначе) — возможны визуальные артефакты при миграции.
- На Android Impeller требует Vulkan 1.1 — старые устройства (Android 7-8) используют fallback на OpenGL ES с деградацией производительности.
- Анимации
Opacityчерез виджет создают отдельный compositing слой для каждого кадра — используйтеAnimatedOpacityсalwaysIncludeSemanticsилиFadeTransition. - Использование
saveLayerв CustomPainter крайне дорого — каждый вызов создаёт offscreen framebuffer. - Platform Views (AndroidView, UiKitView) прерывают Flutter rendering pipeline и переключаются на нативный render — смешивание создаёт ограничения для Impeller.
- Layer tree с глубокой вложенностью ClipRRect увеличивает время compositing — старайтесь минимизировать число clip-операций.
Common mistakes
- Сводить «rendering pipeline во Flutter и как работает Skia/Impeller» к синтаксису и не объяснять render tree.
- Игнорировать жизненный цикл, основной поток или момент освобождения ресурсов в сценарии flutter-27.
- Выбирать API по привычке, не проверяя состояние, ошибки, доступность и платформенные ограничения.
What the interviewer is testing
- Формулирует точную модель для «rendering pipeline во Flutter и как работает Skia/Impeller» и подтверждает ее корректным примером.
- Умеет связать ответ с frame scheduling, тестированием и отладкой на устройстве.
- Называет ограничения подхода flutter-27, включая производительность, память и сопровождение.