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

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

Слои

Слой — важнейшая единица композиции. Слой представляет собой комбинацию поверхности и экземпляра SurfaceControl . Каждый слой имеет набор свойств, определяющих его взаимодействие с другими слоями. Свойства слоя описаны в следующей таблице:

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

Дисплеи

Дисплей — ещё одна важная единица композиции. Система может иметь несколько дисплеев, которые можно добавлять и удалять в процессе обычной работы системы. Дисплеи добавляются и удаляются по запросу HWC или фреймворка. Устройство HWC запрашивает добавление или удаление дисплеев при подключении или отключении внешнего дисплея, что называется «горячим подключением» . Клиенты запрашивают виртуальные дисплеи , содержимое которых отображается во внеэкранном буфере, а не на физическом дисплее.

Виртуальные дисплеи

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

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

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

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

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

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

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

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

Пример исследования: моделирование вторичных дисплеев

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

При подключении виртуального дисплея к видимому слою создаётся замкнутый контур, в котором комбинированный экран отображается в окне. Это окно теперь является частью комбинированного вывода, поэтому при следующем обновлении комбинированное изображение внутри окна также будет отображать его содержимое. Чтобы увидеть это в действии, включите параметры разработчика в настройках , выберите «Имитировать дополнительные дисплеи» и включите окно. Чтобы увидеть вторичные дисплеи в действии, используйте screenrecord для записи процесса включения дисплея, а затем воспроизведите его покадрово.