От Skia к Impeller: эволюция графического движка в кроссплатформенной разработке на Flutter
Привет! Меня зовут Павел Шалимов и я flutter разработчик в InstaDev/мобильный продакшн. В этой статье мы сосредоточимся на графическом движке Impeller и его предшественнике Skia.
Flutter — это открытый и мощный фреймворк для создания кроссплатформенных мобильных, веб- и настольных приложений с использованием языка программирования Dart. За короткое время с момента выпуска Flutter приобрел огромную популярность благодаря своей производительности, гибкости и возможности создания красивого пользовательского интерфейса.
Одним из ключевых компонентов Flutter является его графический движок, который отвечает за отрисовку пользовательского интерфейса и обеспечение высокой производительности приложений.
В чём различия Skia и Impeller
Impeller и Skia — это два разных движка рендеринга, которые используются в Flutter для отображения графического интерфейса пользователя.
Пожалуй, главное их отличие в том, что они по-разному подходят к компиляции и исполнению шейдеров — программ, которые запускаются на GPU (Graphics Processing Unit, графический процессор) и определяют, как отрисовывать различные формы и цвета на экране.
Skia — это движок рендеринга 2D, который был разработан Google и используется во многих продуктах, таких как Chrome, Android и Flutter, и имеет обширный набор функций для рендеринга и работы с графикой. Skia компилирует шейдеры во время выполнения, то есть когда приложение уже запущено на устройстве. Это позволяет Skia адаптироваться к различным графическим API, таким как OpenGL, Vulkan или Metal, и генерировать оптимальные шейдеры для каждого из них.
Однако, этот процесс компиляции может занимать значительное время и приводить к снижению производительности и заиканию анимаций, особенно при первом запуске приложения или при первом использовании шейдера.
Impeller — это новый движок рендеринга, который был разработан командой Flutter специально для Flutter с целью улучшить производительность и устранить проблему заикания анимаций.
Его API и алгоритмы рендеринга разработаны с учетом особенностей Flutter и целенаправленно нацелены на минимизацию накладных расходов и оптимизацию производительности.
Impeller предназначен для замены Skia и потенциально обеспечивает поддержку 3D, которая ранее не была возможна с Skia, так как он исключительно поддерживает 2D. В отличие от Skia, Impeller компилирует шейдеры во время сборки самого движка Flutter. Это означает, что приложения, работающие с Impeller, уже имеют все необходимые шейдеры в скомпилированном виде, и они могут использоваться без заиканий в анимациях.
При этом Impeller никак не влияет на размер приложения или на скорость его запуска относительно Skia.
При создании Impeller разработчики преследовали следующие цели:
Достичь предсказуемой производительности: Impeller компилирует все шейдеры и отражения во время сборки движка. Он создает все объекты состояния конвейера заранее. Движок контролирует кэширование и кэширует явно.
Обеспечить инструментируемость: Impeller помечает и маркирует все графические ресурсы, такие как текстуры и буферы. Он может захватывать и сохранять анимации без влияния на производительность рендеринга за кадр.
Дать независимость: Flutter не связывает Impeller с конкретным клиентским графическим API. Вы можете создавать шейдеры один раз и преобразовывать их в специфичные для бэкенда форматы по мере необходимости.
Использовать современные графические API: Impeller использует, но не зависит от, функций, доступных в современных API, таких как Metal и Vulkan.
Использовать параллелизм: Impeller может распределять нагрузку одного кадра по нескольким потокам, если это необходимо.
А что под капотом у Impeller?
Impeller — достаточно комплексная система, и в рамках этой статьи мы рассмотрим не все её компоненты, а только самые важные:
aiks
— Это самый верхний слой Impeller, он оборачивает слойentity
в API, напоминающий Skia. Это упрощает механическую замену вызовов Skia их аналогами Impeller, даже несмотря на то, что API фреймворка entity в Impeller отличается от API в Skia. (Интересный факт — название aiks это skia наоборот)entity
— Расположен на один уровень вышеrenderer
и предоставляет фреймворк для создания 2D-рендереров. Большинство объектов состояния конвейера, созданных из шейдеров, созданных во время сборки, находятся здесь. Тут же находится фреймворки оптимизации проходов рендеринга (render-pass optimisation) и перезаписи проходов (pass-rewriting). Это позволяет создавать компонуемые оптимизации 2D-рендеринга (например, свертывание проходов или полное их исключение).renderer
— Самый нижний уровень рендеринга, который по-прежнему не зависит от графического бэкенда. Позволяет пользователям собирать рендерер с нуля с небольшими ограничениями. Имеет утилиты для создания распределителей, генерации объектов состояния конвейера из биндингов, созданныхcompiler
, для настройки проходов рендеринга, для управления большими юниформ-буферами, тесселяторами и т. д.compiler
— это автономный компилятор шейдеров, он берет исходный код шейдера GLSL 4.60 и преобразует его в представление шейдера, специфичное для графического бэкенда (например, Metal Shading Language). Он также генерирует биндинги C++, чьи вызовы могут включать в качестве GN (GN — это система мета-сборки, которая генерирует файлы сборки для Ninja)source_set
s, поэтому отражение шейдера во время выполнения также отсутствует. Целью является исполняемый файл под названиемimpellerc
, который никогда не поставляется в двоичном виде или в виде артефакта.
И посмотрим одним глазком ещё на парочку интересных:
shader_archive
— Создаёт постоянную библиотеку шейдерных блобов. В основном это используется рендер бэкендами, в которых нет понятия библиотеки шейдеров. В Impeller все шейдеры упакованы в одну библиотеку, которая содержит манифест всех шейдеров библиотеки вместе с самими предварительно скомпилированными шейдерами. В отличие от Metal, такие бэкэнды, как OpenGL ES и Vulkan, не имеют такой концепции. Для этих бэкэндов используетсяblobcat
для создания единой библиотеки шейдеров, которая будет упакована вместе с движком.scene
— Содержит экспериментальный рендерер 3D-моделей.
И что же у нас получается в итоге?
Кратко сравним Skia и Impeller и посмотрим, насколько оправдана разработка нового графического движка и замена им текущего:
Архитектура и принцип работы:
Skia: Это движок рендеринга 2D, который компилирует шейдеры во время выполнения приложения, что может привести к некоторым проблемам с производительностью и заиканием анимаций при первом запуске.
Impeller: Это новый графический движок, разработанный специально для Flutter, который компилирует шейдеры во время сборки самого движка. Это обеспечивает более предсказуемую производительность и устраняет проблемы с заиканием анимаций.
Цели разработки:
Skia: Создан для обеспечения широкого спектра функций рендеринга 2D и используется в различных продуктах Google.
Impeller: Разработан с учетом специфики Flutter и целенаправленно нацелен на оптимизацию производительности и улучшение пользовательского опыта.
Совместимость и независимость:
Skia: Используется в различных продуктах Google и имеет широкую поддержку для различных графических API.
Impeller: Независим от конкретного графического API и обеспечивает возможность создавать шейдеры один раз и адаптировать их к различным рендер бэкендам.
Поддержка функций:
Skia: Обладает обширным набором функций для работы с рендерингом 2D, но не поддерживает 3D.
Impeller: Потенциально поддерживает 3D и обеспечивает более предсказуемую производительность при рендеринге пользовательского интерфейса.
Выводы
Impeller выглядит как закономерный апгрейд для флаттера, который давно напрашивался, а Skia, к сожалению, уже перестала отвечать высоким запросам современной разработки мобильных приложений, так что уход на покой был делом времени.
Вместе с производительностью и гибкостью, которые предоставляет Flutter, Impeller представляет собой важный шаг в развитии возможностей этого фреймворка.
Его стремление к оптимизации производительности и использованию современных графических API открывает новые перспективы для разработчиков, обеспечивая при этом отличный пользовательский опыт.
При этом, конечно, существуют и минусы, например, использование Vulkan API для смартфонов на Android несомненно отсечёт часть не самых новых устройств, которые не поддерживают Vulkan, но это проблемы временные, а пока не сомневайтесь, что в будущем Impeller продолжит развиваться, отвечая на запросы разработчиков и обеспечивая современные решения для создания качественных приложений на всех платформах.