BufferQueue и Gralloc

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

Распределитель памяти Gralloc выполняет распределение буферов и реализуется через два HIDL-интерфейса, зависящих от поставщика (см. hardware/interfaces/graphics/allocator/ и hardware/interfaces/graphics/mapper/ ). Функция allocate() принимает ожидаемые аргументы (ширину, высоту, формат пикселей), а также набор флагов использования.

Производители и потребители BufferQueue

Потребители создают и владеют структурой данных BufferQueue и могут существовать в других процессах, чем их производители. Когда производителю нужен буфер, он запрашивает свободный буфер у BufferQueue, вызывая dequeueBuffer() , определяя ширину, высоту буфера, формат пикселей и флаги использования. Затем производитель заполняет буфер и возвращает его в очередь, вызывая queueBuffer() . Затем потребитель получает буфер с помощью acquireBuffer() и использует его содержимое. Когда потребитель завершает работу, он возвращает буфер в очередь, вызывая releaseBuffer() . Платформа синхронизации управляет перемещением буферов через графический конвейер Android.

Некоторые характеристики BufferQueue, такие как максимальное количество буферов, которые она может содержать, определяются совместно производителем и потребителем. Однако BufferQueue выделяет буферы по мере необходимости. Буферы сохраняются до тех пор, пока характеристики не изменяются; например, если производитель запрашивает буферы другого размера, старые буферы освобождаются, а новые буферы выделяются по требованию.

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

Отслеживание BufferQueue с помощью Systrace

Чтобы понять, как перемещаются графические буферы, используйте Systrace — инструмент, записывающий активность устройства за короткий период времени. Графический код системного уровня хорошо оснащен, как и большая часть соответствующего кода платформы приложений.

Чтобы использовать Systrace, включите теги gfx , view и sched . Объекты BufferQueue отображаются в трассировке. Например, если вы выполняете трассировку во время работы видео Grafika Play (SurfaceView) , строка с надписью SurfaceView сообщает вам, сколько буферов было поставлено в очередь в любой момент времени.

Значение увеличивается, пока приложение активно, что запускает отрисовку кадров декодером MediaCodec. Значение уменьшается, пока SurfaceFlinger работает и использует буферы. При показе видео со скоростью 30 кадров в секунду значение очереди варьируется от 0 до 1, поскольку дисплей с частотой ~60 кадров в секунду может не отставать от источника. SurfaceFlinger просыпается только тогда, когда нужно выполнить работу, а не 60 раз в секунду. Система пытается уклониться от работы и отключает VSYNC, если ничего не обновляет экран.

Если вы переключитесь на воспроизведение видео Grafika (TextureView) и получите новую трассировку, вы увидите строку с надписью com.android.grafika / com.android.grafika.PlayMovieActivity . Это основной уровень пользовательского интерфейса, который представляет собой еще один BufferQueue. Поскольку TextureView визуализируется на уровне пользовательского интерфейса, а не на отдельном слое, здесь отображаются все обновления, связанные с видео.

Граллок

Распределитель Gralloc HAL hardware/libhardware/include/hardware/gralloc.h выполняет выделение буфера с помощью флагов использования. Флаги использования включают в себя такие атрибуты, как:

  • Как часто будет осуществляться доступ к памяти из программного обеспечения (ЦП)
  • Как часто будет осуществляться доступ к памяти с аппаратного обеспечения (GPU)
  • Будет ли память использоваться в качестве текстуры OpenGL ES (GLES)
  • Будет ли память использоваться видеокодером

Например, если формат буфера производителя указывает RGBA_8888 пикселей, и производитель указывает, что доступ к буферу будет осуществляться из программного обеспечения (это означает, что приложение будет касаться пикселей на ЦП), Gralloc создает буфер с 4 байтами на пиксель в порядке RGBA. Если вместо этого производитель указывает, что доступ к его буферу будет осуществляться только с аппаратного обеспечения, и в качестве текстуры GLES Gralloc может делать все, что хочет драйвер GLES, например упорядочивание BGRA, нелинейные макеты с возможностью поворота и альтернативные цветовые форматы. Разрешение оборудованию использовать предпочтительный формат может повысить производительность.

Некоторые значения не могут быть объединены на определенных платформах. Например, для флага видеокодера могут потребоваться пиксели YUV, поэтому добавить доступ к программному обеспечению и указать RGBA_8888 не удастся.

Дескриптор, возвращаемый Gralloc, можно передавать между процессами через Binder.

Защищенные буферы

Флаг использования Gralloc GRALLOC_USAGE_PROTECTED позволяет отображать графический буфер только через аппаратно защищенный путь. Эти плоскости наложения являются единственным способом отображения содержимого DRM (буферы, защищенные DRM, недоступны для SurfaceFlinger или драйвера OpenGL ES).

Видео, защищенное DRM, может быть представлено только в плоскости наложения. Видеопроигрыватели, поддерживающие защищенный контент, должны быть реализованы с помощью SurfaceView. Программное обеспечение, работающее на незащищенном оборудовании, не может читать или записывать буфер; пути, защищенные аппаратным обеспечением, должны появиться в оверлее Hardware Composer (т. е. защищенные видео исчезнут с дисплея, если Hardware Composer переключится на композицию OpenGL ES).

Подробную информацию о защищенном контенте см. в разделе DRM .