От Skia к Impeller: эволюция графического движка в кроссплатформенной разработке на Flutter

Привет! Меня зовут Павел Шалимов и я flutter разработчик в InstaDev/мобильный продакшн. В этой статье мы сосредоточимся на графическом движке Impeller и его предшественнике Skia.

Flutter — это открытый и мощный фреймворк для создания кроссплатформенных мобильных, веб- и настольных приложений с использованием языка программирования Dart. За короткое время с момента выпуска Flutter приобрел огромную популярность благодаря своей производительности, гибкости и возможности создания красивого пользовательского интерфейса.

Одним из ключевых компонентов Flutter является его графический движок, который отвечает за отрисовку пользовательского интерфейса и обеспечение высокой производительности приложений. 

В чём различия Skia и Impeller

9c536cbe2ee31cd3375eaf9858229850.png

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_sets, поэтому отражение шейдера во время выполнения также отсутствует. Целью является исполняемый файл под названием impellerc, который никогда не поставляется в двоичном виде или в виде артефакта.

И посмотрим одним глазком ещё на парочку интересных:

  • shader_archive — Создаёт постоянную библиотеку шейдерных блобов. В основном это используется рендер бэкендами, в которых нет понятия библиотеки шейдеров. В Impeller все шейдеры упакованы в одну библиотеку, которая содержит манифест всех шейдеров библиотеки вместе с самими предварительно скомпилированными шейдерами. В отличие от Metal, такие бэкэнды, как OpenGL ES и Vulkan, не имеют такой концепции. Для этих бэкэндов используется blobcat для создания единой библиотеки шейдеров, которая будет упакована вместе с движком.

  • scene — Содержит экспериментальный рендерер 3D-моделей.

И что же у нас получается в итоге?

Кратко сравним Skia и Impeller и посмотрим, насколько оправдана разработка нового графического движка и замена им текущего:

  1. Архитектура и принцип работы:

    • Skia: Это движок рендеринга 2D, который компилирует шейдеры во время выполнения приложения, что может привести к некоторым проблемам с производительностью и заиканием анимаций при первом запуске.

    • Impeller: Это новый графический движок, разработанный специально для Flutter, который компилирует шейдеры во время сборки самого движка. Это обеспечивает более предсказуемую производительность и устраняет проблемы с заиканием анимаций.

  2. Цели разработки:

    • Skia: Создан для обеспечения широкого спектра функций рендеринга 2D и используется в различных продуктах Google.

    • Impeller: Разработан с учетом специфики Flutter и целенаправленно нацелен на оптимизацию производительности и улучшение пользовательского опыта.

  3. Совместимость и независимость:

    • Skia: Используется в различных продуктах Google и имеет широкую поддержку для различных графических API.

    • Impeller: Независим от конкретного графического API и обеспечивает возможность создавать шейдеры один раз и адаптировать их к различным рендер бэкендам.

  4. Поддержка функций:

    • Skia: Обладает обширным набором функций для работы с рендерингом 2D, но не поддерживает 3D.

    • Impeller: Потенциально поддерживает 3D и обеспечивает более предсказуемую производительность при рендеринге пользовательского интерфейса.

Выводы

Impeller выглядит как закономерный апгрейд для флаттера, который давно напрашивался, а Skia, к сожалению, уже перестала отвечать высоким запросам современной разработки мобильных приложений, так что уход на покой был делом времени. 

Вместе с производительностью и гибкостью, которые предоставляет Flutter, Impeller представляет собой важный шаг в развитии возможностей этого фреймворка. 

Его стремление к оптимизации производительности и использованию современных графических API открывает новые перспективы для разработчиков, обеспечивая при этом отличный пользовательский опыт. 

При этом, конечно, существуют и минусы, например, использование Vulkan API для смартфонов на Android несомненно отсечёт часть не самых новых устройств, которые не поддерживают Vulkan, но это проблемы временные, а пока не сомневайтесь, что в будущем Impeller продолжит развиваться, отвечая на запросы разработчиков и обеспечивая современные решения для создания качественных приложений на всех платформах.

© Habrahabr.ru