FlutterSeniorTechnical

Что такое 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, включая производительность, память и сопровождение.

Sources

Related topics