Слои и дисплеи

Слои и дисплеи – это два примитива, которые представляют собой композицию и взаимодействие с аппаратным обеспечением дисплея.

Слои

Слой – это основной элемент композиции. Слой – это сочетание поверхности и экземпляра SurfaceControl. У каждого слоя есть набор свойств, определяющих его взаимодействие с другими слоями. Свойства слоев описаны в таблице ниже.

Свойство Описание
Позиционный Определяет, где слой будет отображаться на экране. Содержит информацию, например о положении краев слоя и его порядке наложения относительно других слоев (должен ли он быть поверх или под другими слоями).
Контент Указывает, как контент слоя отображается в границах, заданных свойствами положения. В частности, можно обрезать контент, чтобы он заполнил границы слоя, или преобразовать его, чтобы он отображался повернутым или отраженным.
Композиция Определяет, как слой должен быть объединен с другими слоями. Включает информацию о режиме смешивания и значение альфа-канала для всего слоя, которое используется при альфа-композитинге.
Оптимизация Предоставляет информацию, которая не является строго необходимой для правильной композиции слоев, но которую устройство Hardware Composer (HWC) может использовать для оптимизации производительности композиции. Это включает видимую область слоя и часть, обновленную с момента предыдущего кадра.

Дисплеи

Дисплей – ещё один важный элемент композиции. В системе может быть несколько дисплеев, которые можно добавлять и удалять во время работы. Дисплеи добавляются или удаляются по запросу HWC или фреймворка.

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

Виртуальные экраны

SurfaceFlinger поддерживает внутренний дисплей (встроенный в телефон или планшет), внешние дисплеи (например, телевизор, подключенный через HDMI) и один или несколько виртуальных дисплеев, которые делают составной вывод доступным в системе. Виртуальные дисплеи можно использовать для записи экрана или передачи изображения с него по сети. Кадры, созданные для виртуального дисплея, записываются в BufferQueue.

Виртуальные дисплеи могут использовать тот же набор слоев, что и основной дисплей (стек слоев), или иметь собственный набор. Для виртуального дисплея нет VSync, поэтому VSync для внутреннего дисплея запускает композицию для всех дисплеев.

В реализациях HWC, которые их поддерживают, виртуальные дисплеи можно компоновать с помощью OpenGL ES (GLES), HWC или и того, и другого. В реализациях, не поддерживающих композицию, виртуальные дисплеи всегда составляются с помощью GLES.

Пример использования: screenrecord

Команда screenrecord позволяет пользователю записать все, что появляется на экране, в виде MP4-файла на диске. Для этого система получает составные кадры от SurfaceFlinger, записывает их в видеокодер, а затем записывает закодированные видеоданные в файл. Видеокодеки управляются отдельным процессом (mediaserver), поэтому большие буферы графики должны перемещаться по системе. Задача усложняется тем, что нужно записать видео с разрешением Full HD и частотой 60 кадров в секунду. Ключевым элементом эффективной работы является BufferQueue.

Класс MediaCodec позволяет приложению предоставлять данные в виде необработанных байтов в буферах или через поверхность. Когда screenrecord запрашивает доступ к видеокодеру, процесс mediaserver создает BufferQueue, подключается к стороне потребителя, а затем передает сторону производителя обратно в screenrecord в виде поверхности.

Затем утилита screenrecord запрашивает у SurfaceFlinger создание виртуального дисплея, который отражает основной дисплей (то есть имеет все те же слои), и направляет его для отправки выходных данных на поверхность, полученную из процесса mediaserver. В этом случае SurfaceFlinger является производителем буферов, а не потребителем.

После завершения настройки screenrecord активируется, когда появляются закодированные данные. Когда приложения рисуют, их буферы передаются в SurfaceFlinger, который объединяет их в один буфер, отправляемый непосредственно видеокодировщику в процессе mediaserver. Процесс screenrecord никогда не получает полные кадры. Внутренние процессы mediaserver перемещают буферы по-своему, также передавая данные по дескриптору, что позволяет минимизировать издержки.

Пример использования: имитация дополнительных экранов

WindowManager может запросить у SurfaceFlinger создание видимого слоя, для которого SurfaceFlinger выступает в качестве потребителя BufferQueue. Также можно попросить SurfaceFlinger создать виртуальный дисплей, для которого SurfaceFlinger действует как производитель BufferQueue.

Если подключить виртуальный дисплей к видимому слою, будет создан замкнутый контур, в котором скомпонованный экран появится в окне. Теперь это окно является частью композитного вывода, поэтому при следующем обновлении композитное изображение внутри окна также будет содержать содержимое окна. Чтобы увидеть, как это работает, включите Для разработчиков в настройках, выберите Имитировать дополнительные экраны и включите окно. Чтобы увидеть, как работают дополнительные экраны, используйте screenrecord, чтобы записать момент включения экрана, а затем воспроизведите запись по кадрам.