Как реализовать HAL аппаратного композитора

HAL композитора оборудования (HWC) объединяет слои, полученные от SurfaceFlinger, уменьшая объем композиции OpenGL ES (GLES) и производительность GPU.

HWC абстрагирует объекты, такие как наложения и 2D-блиттеры, для композитных поверхностей и взаимодействует со специализированным оборудованием для композиции окон, чтобы создавать композитные окна. Используйте HWC для композиции окон вместо SurfaceFlinger, который выполняет композицию с помощью GPU. Большинство графических процессоров не оптимизированы для композиции, и когда графический процессор составляет слои из SurfaceFlinger, приложения не могут использовать графический процессор для собственного рендеринга.

Реализации HWC должны поддерживать:

  • Не менее четырех оверлеев:
    • Строка состояния
    • Системная панель
    • Приложение
    • Обои/фон
  • Слои, размер которых превышает размер экрана (например, обои).
  • Одновременное предварительно умноженное попиксельное альфа-смешивание и альфа-смешивание по плоскостям.
  • Аппаратный путь для воспроизведения защищенного видео
  • Порядок упаковки RGBA, форматы YUV, а также свойства разбиения на фрагменты, перестановки и шага

Чтобы реализовать HWC:

  1. Реализуйте неработающий HWC и отправляйте все задачи композиции в GLES.
  2. Реализуйте алгоритм, который будет делегировать композицию HWC постепенно. Например, делегируйте оверлею только первые три или четыре поверхности.
  3. Оптимизируйте HWC. В частности, могут быть заблокированы:
    • Выбор поверхностей, которые максимально снижают нагрузку на графический процессор, и отправка их в HWC.
    • определять, обновляется ли экран; Если нет, делегируйте композицию GLES вместо HWC, чтобы сэкономить энергию. Когда экран снова обновится, продолжайте выгружать композицию в HWC.
    • Подготовка к распространенным сценариям использования, например:
      • Главный экран, включая строку состояния, системную строку, окно приложения и живые обои.
      • Полноэкранные игры в вертикальном и горизонтальном режимах
      • Полноэкранный просмотр видео с субтитрами и элементами управления воспроизведением.
      • Воспроизведение защищенного видео
      • Разделение экрана

Примитивы HWC

HWC предоставляет два примитива, слои и дисплеи, для представления работы композиции и ее взаимодействия с аппаратным обеспечением дисплея. Кроме того, HWC позволяет управлять вертикальной синхронизацией и предоставляет SurfaceFlinger обратный вызов, чтобы уведомлять его о событиях VSync.

Интерфейс HIDL

В Android 8.0 и более поздних версий для IPC на основе Binder между HWC и SurfaceFlinger используется интерфейс HIDL под названием Composer HAL. Уровень абстрагирования Composer HAL заменяет устаревший интерфейс hwcomposer2.h. Если поставщики предоставляют реализацию Composer HAL для HWC, Composer HAL напрямую принимает вызовы HIDL от SurfaceFlinger. Если поставщики предоставляют устаревшую реализацию HWC, Composer HAL загружает указатели функций из hwcomposer2.h, перенаправляя вызовы HIDL в вызовы указателей функций.

HWC предоставляет функции для определения свойств заданного дисплея; для переключения между различными конфигурациями дисплея (например, разрешение 4k или 1080p) и цветовыми режимами (например, собственный цвет или истинный sRGB); и для включения, выключения дисплея или перехода в режим пониженного энергопотребления, если он поддерживается.

Указатели функций

Если поставщики реализуют Composer HAL напрямую, SurfaceFlinger вызывает его функции через HIDL IPC. Например, чтобы создать слой, SurfaceFlinger вызывает createLayer() в Composer HAL.

Если поставщики реализуют интерфейс hwcomposer2.h, Composer HAL вызывает указатели функций hwcomposer2.h. В комментариях hwcomposer2.h функции интерфейса HWC упоминаются в виде именованных полей в формате lowerCamelCase, которых нет в интерфейсе. Почти каждая функция загружается путем запроса указателя функции с помощью getFunction, предоставляемого hwc2_device_t. Например, функция createLayer – это указатель функции типа HWC2_PFN_CREATE_LAYER, который возвращается, когда в функцию getFunction передается перечисляемое значение HWC2_FUNCTION_CREATE_LAYER.

Подробную документацию по функциям Composer HAL и функциям сквозной передачи HWC можно найти в разделе composer. Подробную документацию по указателям функций HWC можно найти в hwcomposer2.h.

Маркеры слоев и отображения

Слоями и дисплеями управляют дескрипторы, генерируемые HWC. Для SurfaceFlinger псевдонимы непрозрачны.

Когда SurfaceFlinger создает новый слой, он вызывает createLayer, который возвращает тип Layer для прямых реализаций или hwc2_layer_t для сквозных реализаций. Когда SurfaceFlinger изменяет свойство слоя, он передает значение hwc2_layer_t в соответствующую функцию изменения вместе с другой информацией, необходимой для внесения изменений. Тип hwc2_layer_t достаточно велик, чтобы содержать указатель или индекс.

Физические дисплеи создаются при подключении устройств. Когда физический дисплей подключается к системе, HWC создает дескриптор и передает его SurfaceFlinger через обратный вызов hotplug. Виртуальные дисплеи создаются SurfaceFlinger, который вызывает createVirtualDisplay(), чтобы запросить дисплей. Если HWC поддерживает композицию виртуального дисплея, он возвращает дескриптор. Затем SurfaceFlinger делегирует композицию дисплея HWC. Если HWC не поддерживает композицию виртуального дисплея, SurfaceFlinger создает дескриптор и выполняет композицию дисплея.

Показать операции композиции

Один раз за VSync SurfaceFlinger просыпается, если у него есть новый контент для композиции. Новый контент может представлять собой новые буферы изображений из приложений или изменение свойств одного или нескольких слоев. Когда SurfaceFlinger пробуждает его:

  1. Обрабатывает транзакции, если они есть.
  2. Защелкивает новые графические буферы, если они есть.
  3. Если на шаге 1 или 2 содержимое экрана изменилось, выполняется новая композиция.

Чтобы выполнить новую композицию, SurfaceFlinger создает и удаляет слои или изменяет их состояние. Кроме того, он обновляет слои с их текущим содержимым, используя такие вызовы, как setLayerBuffer или setLayerColor. После обновления всех слоев SurfaceFlinger вызывает функцию validateDisplay, которая сообщает HWC о необходимости проверить состояние слоев и определить, как будет выполняться композиция. По умолчанию SurfaceFlinger пытается настроить каждый слой так, чтобы он компоновался HWC. Однако в некоторых случаях SurfaceFlinger компонует слои через резервный графический процессор.

После вызова validateDisplay SurfaceFlinger вызывает getChangedCompositionTypes, чтобы проверить, нужно ли изменить типы композиции слоев перед ее выполнением. Чтобы принять изменения, SurfaceFlinger вызывает acceptDisplayChanges.

Если какой-либо слой отмечен для композиции SurfaceFlinger, SurfaceFlinger компонует их в целевой буфер. Затем SurfaceFlinger вызывает setClientTarget, чтобы передать буфер дисплею. После этого буфер можно будет показать на экране или скомпоновать с другими слоями, которые не были отмечены для композиции SurfaceFlinger. Если ни один слой не отмечен для композиции SurfaceFlinger, SurfaceFlinger пропускает этап композиции.

Наконец, SurfaceFlinger вызывает presentDisplay, чтобы сообщить HWC о необходимости завершить процесс композиции и показать конечный результат.

Несколько экранов

Android 10 поддерживает несколько физических дисплеев. При разработке реализации HWC для Android 7.0 и более поздних версий необходимо учитывать некоторые ограничения, не описанные в определении HWC:

  • Предполагается, что у устройства есть только один внутренний дисплей. Внутренний дисплей – это дисплей, о котором сообщается при первом подключении во время загрузки. После подключения внутреннего дисплея его нельзя отключить.
  • Помимо встроенного экрана, во время работы устройства можно подключать и отключать любое количество внешних дисплеев. Фреймворк предполагает, что все горячие подключения после первого внутреннего дисплея относятся к внешним дисплеям, поэтому, если добавить ещё внутренние дисплеи, они будут неправильно отнесены к категории Display.TYPE_HDMI вместо Display.TYPE_BUILT_IN.

Описанные выше операции SurfaceFlinger выполняются для каждого дисплея, но последовательно для всех активных дисплеев, даже если обновляется контент только одного из них.

Например, если внешний дисплей обновляется, последовательность будет следующей:

// In Android 9 and lower:

// Update state for internal display
// Update state for external display
validateDisplay(<internal display>)
validateDisplay(<external display>)
presentDisplay(<internal display>)
presentDisplay(<external display>)

// In Android 10 and higher:

// Update state for internal display
// Update state for external display
validateInternal(<internal display>)
presentInternal(<internal display>)
validateExternal(<external display>)
presentExternal(<external display>)

Композиция виртуального экрана

Композиция виртуального дисплея похожа на композицию внешнего дисплея. Разница между композицией виртуального и физического дисплеев заключается в том, что виртуальные дисплеи отправляют выходные данные в буфер Gralloc, а не на экран. Hardware Composer (HWC) записывает выходные данные в буфер, предоставляет барьер завершения и отправляет буфер потребителю (например, видеокодеру, графическому процессору, центральному процессору и т. д.). Виртуальные дисплеи могут использовать 2D/blitter или оверлеи, если конвейер дисплея записывает данные в память.

Режимы

После вызова метода validateDisplay() HWC каждый кадр находится в одном из трех режимов:

  • GLES – графический процессор объединяет все слои и записывает их непосредственно в выходной буфер. HWC не участвует в создании композиции.
  • MIXED – GPU объединяет некоторые слои в буфер кадра, а HWC объединяет буфер кадра и оставшиеся слои, записывая результат непосредственно в выходной буфер.
  • HWC – HWC объединяет все слои и записывает их непосредственно в выходной буфер.

Формат вывода

Форматы выходных данных виртуального буфера дисплея зависят от режима:

  • Режим GLES. Драйвер EGL задает формат выходного буфера в dequeueBuffer(), обычно RGBA_8888. Потребитель должен поддерживать формат выходных данных, заданный драйвером, иначе буфер не будет прочитан.
  • Режимы MIXED и HWC. Если потребителю требуется доступ к ЦП, он задает формат. В противном случае используется формат IMPLEMENTATION_DEFINED, а Gralloc выбирает оптимальный формат на основе флагов использования. Например, Gralloc задает формат YCbCr, если потребителем является видеокодер, а HWC может эффективно записывать данные в этом формате.

Барьеры синхронизации

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

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

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

Подробнее о барьерах синхронизации…