Платформа синхронизации

Платформа синхронизации явно описывает зависимости между различными асинхронными операциями в графической системе Android. Платформа предоставляет API, который позволяет компонентам указывать, когда буферы освобождены. Платформа также позволяет передавать примитивы синхронизации между драйверами из ядра в пользовательское пространство и между самими процессами пользовательского пространства.

Например, приложение может ставить в очередь работу для выполнения в графическом процессоре. Графический процессор начинает рисовать это изображение. Хотя изображение еще не было отрисовано в памяти, указатель буфера передается композитору окон вместе с забором, который указывает, когда работа графического процессора будет завершена. Компоновщик окон заранее начинает обработку и передает работу контроллеру дисплея. Подобным образом работа центрального процессора выполняется заранее. После завершения работы графического процессора контроллер дисплея немедленно отображает изображение.

Платформа синхронизации также позволяет разработчикам использовать ресурсы синхронизации в своих собственных аппаратных компонентах. Наконец, платформа обеспечивает видимость графического конвейера, что помогает при отладке.

Явная синхронизация

Явная синхронизация позволяет производителям и потребителям графических буферов сигнализировать о завершении использования буфера. Явная синхронизация реализована в пространстве ядра.

Преимущества явной синхронизации:

  • Меньше вариаций поведения между устройствами
  • Лучшая поддержка отладки
  • Улучшенные показатели тестирования

Платформа синхронизации имеет три типа объектов:

  • sync_timeline
  • sync_pt
  • sync_fence

sync_timeline

sync_timeline является монотонно возрастающей шкале времени , что производители должны осуществлять для каждого экземпляра драйвера, такие как контекст GL, контроллер дисплея, или 2D блиттер. sync_timeline подсчитывает работа представлена в ядро для конкретного аппаратного обеспечения. sync_timeline предоставляет гарантию о порядке операций и позволяет реализации аппаратно-специфические.

Следуйте этим рекомендациям при реализации sync_timeline :

  • Задайте полезные имена для всех драйверов, графиков и ограждений, чтобы упростить отладку.
  • Реализовать timeline_value_str и pt_value_str операторов в сроки , чтобы сделать отладку вывода более читаемым.
  • Осуществить заливку driver_data дать библиотеки в пользовательском пространстве, например, в библиотеке GL, доступ к конфиденциальным данным временной шкалы, при желании. data_driver позволяет поставщикам передавать информацию о непреложной sync_fence и sync_pts в командных строк сборки на их основе.
  • Не позволяйте пользовательскому пространству явно создавать или сигнализировать о заборе. Явное создание сигналов / ограждений приводит к атаке типа «отказ в обслуживании», которая останавливает работу конвейера.
  • Не доступа sync_timeline , sync_pt или sync_fence элементов в явном виде. API предоставляет все необходимые функции.

sync_pt

sync_pt является одиночным значением или точкой на sync_timeline . Точка имеет три состояния: активное, сигнальное и ошибка. Точки начинаются в активном состоянии и переходят в сигнальное состояние или состояние ошибки. Например, когда изображение потребитель больше не нуждается в буфере, sync_pt не сигнализируется так что производитель изображения знает , что это нормально для записи в буфер снова.

sync_fence

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

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

Заборы, как sync_pt ценности, начать активную и изменения состояния на основании состояния их точек. Если все sync_pt значения становятся сигналом, то sync_fence становится сигнальным. Если один sync_pt попадает в состояние ошибки, вся sync_fence имеет состояние ошибки.

Членство в sync_fence неизменно после забора создается. Чтобы получить более одной точки в ограждении, выполняется слияние, при котором точки от двух отдельных ограждений добавляются к третьему ограждению. Если одна из этих точек была сигнализирована в исходном ограждении, а другая - нет, третье ограждение также не будет в сигнальном состоянии.

Чтобы реализовать явную синхронизацию, предоставьте следующее:

  • Подсистема пространства ядра, которая реализует структуру синхронизации для конкретного драйвера оборудования. Драйверы, которым необходимо учитывать ограничения, обычно представляют собой все, что обращается к Hardware Composer или взаимодействует с ним. Ключевые файлы включают:
    • Основная реализация:
      • kernel/common/include/linux/sync.h
      • kernel/common/drivers/base/sync.c
    • Документация на kernel/common/Documentation/sync.txt
    • Библиотека для связи с пространством ядра в platform/system/core/libsync
  • Поставщик должен предоставить соответствующие заборы синхронизации в качестве параметров validateDisplay() и presentDisplay() функций в HAL.
  • Два заборные связанные расширений GL ( EGL_ANDROID_native_fence_sync и EGL_ANDROID_wait_sync ) и поддержка ограды в графическом драйвере.

Пример использования: реализация драйвера дисплея

Чтобы использовать API, поддерживающий функцию синхронизации, разработайте драйвер дисплея, который имеет функцию буфера дисплея. Перед тем существовала рамка синхронизации, эта функция будет получать dma-buf объекты, поместить эти буфера на дисплее, а также блок в то время как буфер был виден. Например:

/*
 * assumes buffer is ready to be displayed.  returns when buffer is no longer on
 * screen.
 */
void display_buffer(struct dma_buf *buffer);

С рамками синхронизации, то display_buffer функция является более сложной. При отображении буфера он связан с забором, который указывает, когда буфер будет готов. Вы можете встать в очередь и приступить к работе после того, как уберется забор.

Очередь и начало работы после расчистки забора ничего не блокируют. Вы сразу же возвращаете собственный забор, что гарантирует, когда буфер будет отключен от дисплея. Когда вы ставите буферы в очередь, ядро ​​перечисляет зависимости с фреймворком синхронизации:

/*
 * displays buffer when fence is signaled.  returns immediately with a fence
 * that signals when buffer is no longer displayed.
 */
struct sync_fence* display_buffer(struct dma_buf *buffer, struct sync_fence
*fence);

Синхронизация интеграции

В этом разделе объясняется, как интегрировать структуру синхронизации в пространстве ядра с частями пользовательского пространства платформы Android и драйверами, которые должны взаимодействовать друг с другом. Объекты пространства ядра представлены как файловые дескрипторы в пространстве пользователя.

Соглашения об интеграции

Следуйте соглашениям об интерфейсе Android HAL:

  • Если API предоставляет файловый дескриптор , который ссылается на sync_pt , водитель поставщика или HAL с помощью API должен закрыть дескриптор файла.
  • Если драйвер поставщика или HAL передает дескриптор файла , который содержит sync_pt к функции API, драйвер поставщика или HAL близко не должен файл дескриптора.
  • Чтобы продолжить использование файлового дескриптора ограждения, драйвер поставщика или HAL должен продублировать дескриптор.

Объект ограждения переименовывается каждый раз, когда проходит через BufferQueue. Поддержка забора Kernel позволяет изгороди иметь строки для имен, поэтому структура синхронизации использует имя окна и буфер индекса , который в очередь назвать забор, например, SurfaceView:0 . Это полезно при отладке , чтобы определить источник в тупике , как имена появляются в выводе /d/sync и ошибки отчетов.

Интеграция с ANativeWindow

ANativeWindow знает о заборе. dequeueBuffer , queueBuffer и cancelBuffer имеют параметры забора.

Интеграция OpenGL ES

Интеграция синхронизации OpenGL ES основана на двух расширениях EGL:

  • EGL_ANDROID_native_fence_sync обеспечивает способ обернуть или создать собственные Android дескрипторы забор файлов в EGLSyncKHR объектов.
  • EGL_ANDROID_wait_sync позволяет GPU стороны киосков , а не CPU стороны, что делает ожидание GPU для EGLSyncKHR . EGL_ANDROID_wait_sync расширение такое же , как EGL_KHR_wait_sync расширения.

Для того, чтобы использовать эти расширения независимо друг от друга, осуществлять EGL_ANDROID_native_fence_sync расширения вместе с соответствующей поддержкой ядра. Далее, включите EGL_ANDROID_wait_sync расширение в драйвере. EGL_ANDROID_native_fence_sync расширение состоит из отдельного нативного забора EGLSyncKHR типа объекта. В результате расширения , которые применяются к существующим EGLSyncKHR типов объектов не обязательно применимы к EGL_ANDROID_native_fence объектов, избегая нежелательных взаимодействий.

EGL_ANDROID_native_fence_sync расширение использует соответствующий родной забор файл атрибут дескриптора , который может быть установлен только во время создания и не может быть непосредственно опрашивается вперед от существующего объекта синхронизации. Для этого атрибута можно установить один из двух режимов:

  • Действительный дескриптор файла ограда оборачивает существующий родной Android дескриптор ограды файла в качестве EGLSyncKHR объекта.
  • -1 создает родной Android дескриптор файла ограда из EGLSyncKHR объекта.

Используйте DupNativeFenceFD() вызов функции для извлечения EGLSyncKHR объекта из нативного дескриптора Android ограды файла. Это дает тот же результат, что и запрос атрибута set, но придерживается соглашения о том, что получатель закрывает ограждение (отсюда и операция дублирования). Наконец, уничтожая EGLSyncKHR объект закрывает внутренний атрибут забор.

Интеграция с Hardware Composer

Hardware Composer обрабатывает три типа ограждений синхронизации:

  • Приобретать ограждения передаются вместе с входными буферами к setLayerBuffer и setClientTarget вызовов. Они представляют собой ожидающую запись в буфер и должны сигнализировать до того, как SurfaceFlinger или HWC попытается прочитать из связанного буфера для выполнения композиции.
  • Заборы релиза извлекается после вызова presentDisplay с помощью getReleaseFences вызова. Они представляют ожидающее чтение из предыдущего буфера на том же уровне. Ограничение высвобождения сигнализирует, когда HWC больше не использует предыдущий буфер, потому что текущий буфер заменил предыдущий буфер на дисплее. Ограничения выпуска передаются обратно в приложение вместе с предыдущими буферами, которые будут заменены во время текущей композиции. Приложение должно дождаться, пока не будет сигнализировать о высвобождении, прежде чем записывать новое содержимое в буфер, который был ему возвращен.
  • Современные заборы возвращаются, один за кадр, как часть вызова presentDisplay . Существующие ограждения представляют, когда композиция этого кадра завершена, или, альтернативно, когда результат композиции предыдущего кадра больше не нужен. Для физических дисплеев, presentDisplay возвращает настоящие изгороди , когда на экране появляется текущий кадр. После возврата имеющихся ограждений можно снова записать в целевой буфер SurfaceFlinger, если это применимо. Для виртуальных дисплеев текущие ограждения возвращаются, когда их можно безопасно читать из выходного буфера.