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 video (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_USAGE_PROTECTED позволяет отображать графический буфер только через аппаратно защищенный путь. Эти плоскости наложения являются единственным способом отображения содержимого DRM (к буферам, защищенным DRM, не может получить доступ SurfaceFlinger или драйвер OpenGL ES).

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

Подробнее о защищенном содержимом см. DRM .