Слои и дисплеи — это два примитива, которые представляют работу по композиции и взаимодействие с аппаратным обеспечением дисплея.
Слои
Слой — важнейшая единица композиции. Слой — это комбинация поверхности и экземпляра SurfaceControl
. Каждый слой имеет набор свойств, которые определяют, как он взаимодействует с другими слоями. Свойства слоя описаны в таблице ниже.
Свойство | Описание |
---|---|
Позиционный | Определяет, где слой отображается на дисплее. Включает такую информацию, как положение краев слоя и его порядок по оси Z относительно других слоев (должен ли он находиться перед другими слоями или позади них). |
Содержание | Определяет, как содержимое, отображаемое на слое, должно быть представлено в пределах, определенных позиционными свойствами. Включает такую информацию, как обрезка (чтобы расширить часть содержимого для заполнения границ слоя) и преобразование (чтобы отобразить повернутое или перевернутое содержимое). |
Состав | Определяет, как слой должен быть составлен с другими слоями. Включает такую информацию, как режим наложения и значение альфа-канала для альфа-композиции . |
Оптимизация | Предоставляет информацию, которая не является строго необходимой для правильного составления слоя, но может использоваться устройством Hardware Composer (HWC) для оптимизации выполнения композиции. Включает такую информацию, как видимая область слоя и какая часть слоя была обновлена с момента предыдущего кадра. |
Дисплеи
Дисплей — еще одна важная единица композиции. В системе может быть несколько дисплеев, а дисплеи можно добавлять или удалять во время нормальной работы системы. Дисплеи добавляются/удаляются по запросу HWC или по запросу фреймворка. Устройство HWC запрашивает добавление или удаление дисплеев при подключении или отключении внешнего дисплея от устройства, что называется «горячим» подключением . Клиенты запрашивают виртуальные дисплеи , содержимое которых отображается во внеэкранном буфере, а не на физическом дисплее.
Виртуальные дисплеи
SurfaceFlinger поддерживает внутренний дисплей (встроенный в телефон или планшет), внешние дисплеи (например, телевизор, подключенный через HDMI), а также один или несколько виртуальных дисплеев, которые делают композитный вывод доступным в системе. Виртуальные дисплеи можно использовать для записи экрана или отправки экрана по сети. Кадры, созданные для виртуального дисплея, записываются в BufferQueue.
Виртуальные дисплеи могут использовать тот же набор слоев, что и основной дисплей (стек слоев), или иметь собственный набор. Для виртуального дисплея VSYNC отсутствует, поэтому VSYNC для внутреннего дисплея запускает композицию для всех дисплеев.
В поддерживающих их реализациях HWC виртуальные дисплеи могут быть объединены с OpenGL ES (GLES), HWC или с 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
, чтобы запечатлеть процесс включения дисплея, а затем воспроизвести его покадрово.