Слои и дисплеи – это два примитива, которые представляют собой композицию и взаимодействие с аппаратным обеспечением дисплея.
Слои
Слой – это основной элемент композиции. Слой – это сочетание поверхности и экземпляра 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, чтобы записать момент включения экрана, а затем воспроизведите запись по кадрам.