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's Play (SurfaceView), в строке с пометкой SurfaceView будет указано, сколько буферов было поставлено в очередь в определенный момент времени.

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

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

Gralloc

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

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

Например, если формат буфера производителя указывает на RGBA_8888 пикселей, а производитель указывает, что доступ к буферу будет осуществляться из программного обеспечения (то есть приложение будет касаться пикселей на ЦП), Gralloc создает буфер с 4 байтами на пиксель в порядке R-G-B-A. Если производитель указывает, что буфер будет доступен только из оборудования и в качестве текстуры 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…