Инфраструктура прямого рендеринга ( DRI ) — это фреймворк, включающий современный графический стек Linux , который позволяет непривилегированным программам пользовательского пространства выдавать команды графическому оборудованию, не конфликтуя с другими программами. [6] Основное применение DRI — предоставление аппаратного ускорения для реализации OpenGL в Mesa . DRI также был адаптирован для предоставления ускорения OpenGL на консоли кадрового буфера без запущенного сервера отображения . [7]
Реализация DRI распределена по X-серверу и связанным с ним клиентским библиотекам, Mesa 3D и подсистеме ядра Direct Rendering Manager . [6] Весь его исходный код является свободным программным обеспечением .
В классической архитектуре X Window System X-сервер является единственным процессом с эксклюзивным доступом к графическому оборудованию , и, следовательно, тем, который фактически выполняет рендеринг в буфере кадров . Все, что делают X-клиенты, — это взаимодействуют с X-сервером для отправки команд рендеринга. Эти команды не зависят от оборудования, что означает, что протокол X11 предоставляет API , который абстрагирует графическое устройство, поэтому X-клиентам не нужно знать или беспокоиться о специфике базового оборудования. Любой аппаратно-зависимый код находится внутри Device Dependent X , части X-сервера, которая управляет каждым типом видеокарты или графического адаптера и которую также часто называют видео- или графическим драйвером .
Рост 3D-рендеринга показал ограничения этой архитектуры. 3D-графические приложения, как правило, производят большие объемы команд и данных, все из которых должны быть отправлены на X-сервер для рендеринга. По мере увеличения объема межпроцессного взаимодействия (IPC) между X-клиентом и X-сервером производительность 3D-рендеринга снизилась до такой степени, что разработчики X-драйверов пришли к выводу, что для использования возможностей 3D-аппаратуры новейших видеокарт требуется новая архитектура без IPC. X-клиенты должны иметь прямой доступ к графическому оборудованию, а не полагаться на другой процесс для этого, что экономит все накладные расходы IPC. Этот подход называется «прямым рендерингом» в отличие от «косвенного рендеринга», предоставляемого классической архитектурой X. Инфраструктура прямого рендеринга была изначально разработана, чтобы позволить любому X-клиенту выполнять 3D-рендеринг с использованием этого подхода «прямого рендеринга».
Ничто не мешает использовать DRI для реализации ускоренного прямого 2D-рендеринга в X-клиенте. [3] Просто ни у кого не возникало необходимости делать это, поскольку производительность косвенного 2D-рендеринга была достаточно хороша.
Базовая архитектура инфраструктуры прямого рендеринга включает три основных компонента: [8]
В оригинальной архитектуре DRI, из-за размера памяти видеокарт того времени, существовал один экземпляр переднего буфера экрана и заднего буфера (а также вспомогательного буфера глубины и буфера трафарета ), совместно используемый всеми клиентами DRI и X-сервером. [11] [12] Все они визуализировались непосредственно в задний буфер, который заменялся передним буфером во время интервала вертикального гашения . [11] Для визуализации в задний буфер процесс DRI должен гарантировать, что визуализация была обрезана до области, зарезервированной для его окна . [11] [12]
Синхронизация с X-сервером осуществлялась посредством сигналов и буфера общей памяти , называемого SAREA. [12] Доступ к устройству DRM был исключительным, поэтому любой клиент DRI должен был заблокировать его в начале операции рендеринга . Другие пользователи устройства, включая X-сервер, тем временем были заблокированы и должны были ждать, пока блокировка не будет снята в конце текущей операции рендеринга, даже если между обеими операциями не возникнет конфликта. [12] Другим недостатком было то, что операции не сохраняли распределение памяти после того, как текущий процесс DRI снял блокировку с устройства, поэтому любые данные, загруженные в графическую память, такие как текстуры, терялись для предстоящих операций, что оказывало значительное влияние на производительность графики.
В настоящее время DRI1 считается полностью устаревшим и не подлежит использованию.
Из-за растущей популярности композитных оконных менеджеров , таких как Compiz , инфраструктуру прямого рендеринга пришлось перепроектировать так, чтобы клиенты X также могли поддерживать перенаправление на «внеэкранные пиксельные карты» при выполнении прямого рендеринга. Обычные клиенты X уже уважали перенаправление на отдельную пиксельную карту, предоставляемую X-сервером в качестве цели рендеринга — так называемую внеэкранную пиксельную карту — но клиенты DRI продолжали выполнять рендеринг напрямую в общий буфер, эффективно обходя композитный оконный менеджер. [11] [13] Окончательным решением было изменить способ, которым DRI обрабатывал буферы рендеринга, что привело к совершенно другому расширению DRI с новым набором операций, а также к серьезным изменениям в Direct Rendering Manager . [3] Новое расширение было названо «DRI2», хотя это не более поздняя версия, а другое расширение, даже несовместимое с исходным DRI — на самом деле оба они долгое время сосуществовали в X-сервере.
В DRI2 вместо одного общего (заднего) буфера каждый клиент DRI получает свой собственный закрытый задний буфер [11] [12] —вместе с их связанными буферами глубины и трафарета — для рендеринга содержимого своего окна с использованием аппаратного ускорения . Затем клиент DRI заменяет его на ложный « передний буфер », [12] который используется менеджером окон композитинга в качестве одного из источников для составления (построения) окончательного заднего буфера экрана, который заменяется на интервале VBLANK реальным передним буфером.
Для обработки всех этих новых буферов Direct Rendering Manager должен был включить новую функциональность, в частности, менеджер графической памяти . DRI2 изначально был разработан с использованием экспериментального менеджера памяти TTM , [11] [13], но позже он был переписан для использования GEM после того, как он был выбран в качестве окончательного менеджера памяти DRM. [14] Новая внутренняя модель управления буфером DRI2 также решила два основных узких места производительности, присутствовавших в исходной реализации DRI:
В DRI2 распределение частных внеэкранных буферов (задний буфер, поддельный передний буфер, буфер глубины, буфер трафарета, ...) для окна выполняется самим X-сервером. [15] [16] Клиенты DRI извлекают эти буферы для выполнения рендеринга в окне, вызывая такие операции, как DRI2GetBuffers и DRI2GetBuffersWithFormat, доступные в расширении DRI2. [3] Внутри себя DRI2 использует имена GEM — тип глобального дескриптора, предоставляемый API GEM , который позволяет двум процессам, получающим доступ к устройству DRM, ссылаться на один и тот же буфер — для передачи «ссылок» на эти буферы через протокол X11 . [16] Причина, по которой X-сервер отвечает за распределение буферов рендеринга окна, заключается в том, что расширение GLX позволяет нескольким X-клиентам выполнять рендеринг OpenGL совместно в одном и том же окне. [15] Таким образом, X-сервер управляет всем жизненным циклом буферов рендеринга на протяжении всего процесса рендеринга и знает, когда он может безопасно переработать или отбросить их. Когда выполняется изменение размера окна, X-сервер также отвечает за выделение новых буферов рендеринга, соответствующих новому размеру окна, и уведомление об изменении клиента(ов) DRI, рендерящих в окне, с помощью события InvalidateBuffers, чтобы они могли получить имена GEM новых буферов. [15]
Расширение DRI2 предоставляет другие основные операции для клиентов DRI, такие как определение того, какое устройство DRM и драйвер им следует использовать ( DRI2Connect ) или прохождение аутентификации X-сервером для использования возможностей рендеринга и буферизации устройства DRM ( DRI2Authenticate ). [3] Представление отрисованных буферов на экране выполняется с помощью запросов DRI2CopyRegion и DRI2SwapBuffers . DRI2CopyRegion можно использовать для копирования между поддельным передним буфером и настоящим передним буфером, но он не обеспечивает никакой синхронизации с интервалом вертикального гашения, поэтому может вызвать разрывы . DRI2SwapBuffers , с другой стороны, выполняет синхронизированный с VBLANK обмен между задним и передним буфером, если он поддерживается и оба буфера имеют одинаковый размер, или копирование ( blit ) в противном случае. [3] [15]
Хотя DRI2 был значительным улучшением по сравнению с исходным DRI, новое расширение также внесло некоторые новые проблемы. [15] [16] В 2013 году была разработана третья итерация инфраструктуры прямого рендеринга, известная как DRI3, для исправления этих проблем. [17]
Основные отличия DRI3 от DRI2:
Выделение буфера на стороне клиента нарушает предположения GLX в том смысле, что больше невозможно, чтобы несколько приложений GLX выполняли совместный рендеринг в одном окне. С положительной стороны, тот факт, что клиент DRI отвечает за свои собственные буферы на протяжении всего их жизненного цикла, дает много преимуществ. Например, клиенту DRI3 легко гарантировать, что размер буферов рендеринга всегда соответствует текущему размеру окна, и тем самым устранить артефакты из-за отсутствия синхронизации размеров буферов между клиентом и сервером, которые мешали изменению размера окна в DRI2. [15] [16] [18] Также достигается более высокая производительность, поскольку теперь клиенты DRI3 экономят дополнительный цикл ожидания отправки буферов рендеринга сервером X. [16] Клиенты DRI3, и особенно менеджеры окон композитора, могут воспользоваться сохранением старых буферов предыдущих кадров и повторным использованием их в качестве основы для рендеринга только поврежденных частей окна в качестве еще одной оптимизации производительности. [15] [16] Расширение DRI3 больше не нужно изменять для поддержки новых конкретных форматов буфера, поскольку теперь они обрабатываются напрямую между драйвером клиента DRI и драйвером ядра DRM. [15] Использование файловых дескрипторов, с другой стороны, позволяет ядру выполнять безопасную очистку любого неиспользуемого объекта буфера GEM — того, который не имеет ссылки на него. [15] [16]
Технически DRI3 состоит из двух различных расширений: расширения «DRI3» и расширения «Present». [17] [19] Основной целью расширения DRI3 является реализация механизма для совместного использования буферов прямой визуализации между клиентами DRI и X-сервером. [18] [19] [20] Клиенты DRI выделяют и используют объекты буферов GEM в качестве целей визуализации, в то время как X-сервер представляет эти буферы визуализации с помощью типа объекта X11, называемого «pixmap». DRI3 предоставляет две операции, DRI3PixmapFromBuffer и DRI3BufferFromPixmap , одна для создания pixmap (в «пространстве X-сервера») из объекта буфера GEM (в «пространстве клиента DRI»), а другая для выполнения обратного действия и получения объекта буфера GEM из pixmap X. [18] [19] [20] В этих операциях DRI3 объекты буфера GEM передаются как дескрипторы файлов DMA-BUF вместо имен GEM. DRI3 также предоставляет способ совместного использования объектов синхронизации между клиентом DRI и X-сервером, что позволяет обоим осуществлять последовательный доступ к общему буферу. [19] В отличие от DRI2, начальная операция DRI3Open — первая, которую каждый клиент DRI должен запросить, чтобы узнать, какое устройство DRM использовать — возвращает уже открытый дескриптор файла узлу устройства вместо имени файла узла устройства, при этом любая требуемая процедура аутентификации уже выполнена заранее X-сервером. [18] [19]
DRI3 не предоставляет механизма для отображения отрендеренных буферов на экране, но полагается на другое расширение, Present , чтобы сделать это. [20] Present так назван, потому что его основная задача — «представить» буферы на экране, то есть он обрабатывает обновление буфера кадра, используя содержимое отрендеренных буферов, предоставленных клиентскими приложениями. [19] Обновления экрана должны выполняться в надлежащее время, обычно во время интервала VBLANK , чтобы избежать артефактов отображения, таких как разрывы . Present также обрабатывает синхронизацию обновлений экрана с интервалом VBLANK. [21] Он также информирует X-клиента о моменте, когда каждый буфер действительно отображается на экране, с помощью событий, поэтому клиент может синхронизировать свой процесс рендеринга с текущей частотой обновления экрана.
Present принимает любую пиксельную карту X в качестве источника для обновления экрана. [21] Поскольку пиксельные карты являются стандартными объектами X, Present может использоваться не только клиентами DRI3, выполняющими прямой рендеринг, но и любым клиентом X, рендерящим пиксельную карту любыми способами. [18] Например, большинство существующих приложений GTK+ и Qt, не основанных на GL , использовали рендеринг пиксельной карты с двойной буферизацией с помощью XRender . Расширение Present также может использоваться этими приложениями для достижения эффективных и неразрывных обновлений экрана. Вот почему Present был разработан как отдельное автономное расширение, а не как часть DRI3. [18]
Помимо возможности синхронизации не-GL X-клиентов с VBLANK, Present имеет и другие преимущества. Производительность графики DRI3 выше, поскольку Present эффективнее DRI2 в подкачке буферов. [19] Ряд расширений OpenGL, которые не были доступны в DRI2, теперь поддерживаются на основе новых функций, предоставляемых Present. [19]
Present предоставляет X-клиентам две основные операции: обновление области окна с использованием части или всего содержимого пиксельной карты ( PresentPixmap ) и установка типа событий представления, связанных с определенным окном, о которых клиент хочет получать уведомления ( PresentSelectInput ). [19] [21] Существует три события представления, о которых окно может уведомить X-клиента: когда текущая операция представления — обычно из вызова PresentPixmap — завершена ( PresentCompleteNotify ), когда пиксельная карта, используемая операцией PresentPixmap , готова к повторному использованию ( PresentIdleNotify ) и когда изменяется конфигурация окна — в основном размер окна ( PresentConfigureNotify ). [19] [21] Выполняет ли операция PresentPixmap прямое копирование ( blit ) в передний буфер или замену всего заднего буфера на передний буфер — это внутренняя деталь реализации расширения Present, а не явный выбор X-клиента, как это было в DRI2.
Было написано несколько драйверов DRI с открытым исходным кодом, включая драйверы для ATI Mach64, ATI Rage128, ATI Radeon, 3dfx Voodoo3 через Voodoo5, Matrox G200 через G400, SiS 300-series, Intel i810 через i965, S3 Savage, графических чипсетов VIA UniChrome и nouveau для Nvidia . Некоторые поставщики графических решений написали драйверы DRI с закрытым исходным кодом, включая ATI и PowerVR Kyro.
Различные версии DRI реализованы в различных операционных системах, в том числе в ядре Linux , FreeBSD , NetBSD , OpenBSD и OpenSolaris .
Проект был начат Йенсом Оуэном и Кевином Э. Мартином из Precision Insight (финансируется Silicon Graphics и Red Hat ). [1] [22] Впервые он был широко доступен как часть XFree86 4.0 [1] [23] и теперь является частью X.Org Server . В настоящее время он поддерживается сообществом свободного программного обеспечения .
Работа над DRI2 началась на X Developers Summit 2007 года по предложению Кристиана Хёгсберга . [24] [25] Сам Хёгсберг написал новое расширение DRI2 и модификации для Mesa и GLX . [26] В марте 2008 года DRI2 был в основном готов, [27] [28] [29] но его не удалось включить в версию X.Org Server 1.5 [14] и пришлось ждать версии 1.6 в феврале 2009 года. [30] Расширение DRI2 было официально включено в выпуск X11R7.5 в октябре 2009 года. [31] Первая публичная версия протокола DRI2 (2.0) была анонсирована в апреле 2009 года. [32] С тех пор было несколько ревизий, последней из которых была версия 2.8 от июля 2012 года. [4]
Из-за ряда ограничений DRI2, новое расширение под названием DRI-Next было предложено Кейтом Паккардом и Эммой Анхольт на конференции разработчиков X.Org 2012. [15] Расширение было предложено снова как DRI3000 на Linux.conf.au 2013. [16] [17] Расширения DRI3 и Present были разработаны в 2013 году и объединены в выпуск X.Org Server 1.15 от декабря 2013 года. [33] [34] Первая и единственная версия протокола DRI3 (1.0) была выпущена в ноябре 2013 года. [5]