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