Direct Rendering Manager ( DRM ) — это подсистема ядра Linux, отвечающая за взаимодействие с графическими процессорами современных видеокарт . DRM предоставляет API , который программы пользовательского пространства могут использовать для отправки команд и данных в графический процессор и выполнения таких операций, как настройка режима отображения . DRM был впервые разработан как компонент пространства ядра инфраструктуры прямого рендеринга X-сервера [1] , но с тех пор он использовался другими альтернативами графического стека, такими как Wayland , и автономными приложениями и библиотеками, такими как SDL2 и Kodi .
Программы пользовательского пространства могут использовать API DRM для управления графическим процессором для выполнения аппаратно-ускоренного 3D-рендеринга и декодирования видео , а также вычислений GPGPU .
В ядре Linux уже был API под названием fbdev , используемый для управления кадровым буфером графического адаптера [2], но его нельзя было использовать для обработки потребностей современного видеооборудования на базе 3D-ускорителя. Эти устройства обычно требуют настройки и управления очередью команд в своей памяти для отправки команд на графический процессор, а также требуют управления буферами и свободным пространством в этой памяти. [3] Первоначально программы пользовательского пространства (такие как X Server ) напрямую управляли этими ресурсами, но обычно они действовали так, как будто они были единственными, кто имел к ним доступ. Когда две или более программ пытались управлять одним и тем же оборудованием одновременно и устанавливать его ресурсы каждая по-своему, в большинстве случаев это заканчивалось катастрофой. [3]
Direct Rendering Manager был создан для того, чтобы позволить нескольким программам совместно использовать ресурсы видеооборудования. [4] DRM получает эксклюзивный доступ к GPU и отвечает за инициализацию и поддержку очереди команд, памяти и любых других аппаратных ресурсов. Программы, желающие использовать GPU, отправляют запросы в DRM, который действует как арбитр и заботится о том, чтобы избежать возможных конфликтов.
Область DRM была расширена за эти годы, чтобы охватить больше функций, которые ранее обрабатывались программами пользовательского пространства, такими как управление буфером кадров и настройка режима , объекты совместного использования памяти и синхронизация памяти. [5] [6] Некоторые из этих расширений получили конкретные названия, такие как Graphics Execution Manager (GEM) или kernel mode-setting (KMS), и терминология преобладает, когда функциональность, которую они предоставляют, упоминается конкретно. Но они на самом деле являются частями всей подсистемы DRM ядра.
Тенденция включать два GPU в компьютер — дискретный GPU и интегрированный — привела к новым проблемам, таким как переключение GPU , которые также необходимо было решить на уровне DRM. Для того чтобы соответствовать технологии Nvidia Optimus , DRM была снабжена возможностями разгрузки GPU, называемыми PRIME. [7]
Direct Rendering Manager находится в пространстве ядра , поэтому программы пользовательского пространства должны использовать системные вызовы ядра для запроса его служб. Однако DRM не определяет свои собственные настраиваемые системные вызовы. Вместо этого он следует принципу Unix « все есть файл », чтобы предоставлять доступ к графическим процессорам через пространство имен файловой системы, используя файлы устройств в /dev
иерархии. Каждый графический процессор, обнаруженный DRM, называется устройством DRM , и для взаимодействия с ним создается файл устройства (где X — порядковый номер). [8] [9] Программы пользовательского пространства, которые хотят взаимодействовать с графическим процессором, должны открыть этот файл и использовать вызовы ioctl для связи с DRM. Различные ioctl соответствуют различным функциям API DRM ./dev/dri/cardX
Библиотека libdrm была создана для облегчения интерфейса программ пользовательского пространства с подсистемой DRM. Эта библиотека является просто оберткой , которая предоставляет функцию , написанную на языке C, для каждого ioctl API DRM, а также константы, структуры и другие вспомогательные элементы. [10] Использование libdrm не только позволяет избежать прямого раскрытия интерфейса ядра приложениям, но и предоставляет обычные преимущества повторного использования и совместного использования кода между программами.
DRM состоит из двух частей: общего «ядра DRM» и специального («драйвера DRM») для каждого типа поддерживаемого оборудования. [11] Ядро DRM обеспечивает базовую структуру, в которой могут регистрироваться различные драйверы DRM, а также предоставляет пользовательскому пространству минимальный набор ioctl с общей, аппаратно-независимой функциональностью. [8] Драйвер DRM, с другой стороны, реализует аппаратно-зависимую часть API, специфичную для типа поддерживаемого им графического процессора; он должен обеспечивать реализацию оставшихся ioctl, не охваченных ядром DRM, но он также может расширять API, предлагая дополнительные ioctl с дополнительной функциональностью, доступной только на таком оборудовании. [8] Когда конкретный драйвер DRM предоставляет расширенный API, libdrm пользовательского пространства также расширяется дополнительной библиотекой libdrm- driver , которая может использоваться пользовательским пространством для взаимодействия с дополнительными ioctl.
Ядро DRM экспортирует несколько интерфейсов в пользовательские приложения, которые обычно предназначены для использования через соответствующие libdrm
функции-оболочки. Кроме того, драйверы экспортируют интерфейсы, специфичные для устройств, для использования драйверами пользовательского пространства и приложениями, поддерживающими устройства, через файлы ioctls и sysfs . Внешние интерфейсы включают: отображение памяти, управление контекстом, операции DMA , управление AGP , управление vblank , управление ограждением, управление памятью и управление выводом.
В API DRM есть несколько операций (ioctl), которые либо в целях безопасности, либо из-за проблем параллелизма должны быть ограничены для использования одним процессом пользовательского пространства на устройство. [8] Чтобы реализовать это ограничение, DRM ограничивает такие ioctl, чтобы они вызывались только процессом, который считается «главным» для устройства DRM, обычно называемым DRM-Master . Только один из всех процессов, у которых открыт узел устройства , будет иметь свой файловый дескриптор , помеченный как главный, в частности первый, вызывающий ioctl SET_MASTER . Любая попытка использовать один из этих ограниченных ioctl, не будучи DRM-Master, вернет ошибку. Процесс также может отказаться от своей роли главного процесса и позволить другому процессу получить ее, вызвав ioctl DROP_MASTER ./dev/dri/cardX
X -сервер (или любой другой сервер отображения ) — это, как правило, процесс, который получает статус DRM-Master на каждом устройстве DRM, которым он управляет, обычно при открытии соответствующего узла устройства во время своего запуска, и сохраняет эти привилегии в течение всего графического сеанса до его завершения или выхода из строя.
Для оставшихся процессов пользовательского пространства есть другой способ получить привилегию для вызова некоторых ограниченных операций на устройстве DRM, называемый DRM-Auth . Это в основном метод аутентификации на устройстве DRM, чтобы доказать ему, что процесс имеет одобрение DRM-Master на получение таких привилегий. Процедура состоит из: [12] : 13
Из-за увеличения размера видеопамяти и растущей сложности графических API, таких как OpenGL , стратегия повторной инициализации состояния видеокарты при каждом переключении контекста была слишком затратной с точки зрения производительности. Кроме того, современным рабочим столам Linux требовался оптимальный способ совместного использования внеэкранных буферов с менеджером композитинга . Эти требования привели к разработке новых методов управления графическими буферами внутри ядра. Graphics Execution Manager (GEM) появился как один из таких методов. [6]
GEM предоставляет API с явными примитивами управления памятью . [6] Через GEM программа пользовательского пространства может создавать, обрабатывать и уничтожать объекты памяти, находящиеся в видеопамяти GPU. Эти объекты, называемые «объектами GEM», [14] являются постоянными с точки зрения программы пользовательского пространства и не нуждаются в перезагрузке каждый раз, когда программа восстанавливает контроль над GPU. Когда программе пользовательского пространства требуется фрагмент видеопамяти (для хранения буфера кадров , текстуры или любых других данных, требуемых GPU [15] ), она запрашивает выделение у драйвера DRM с помощью API GEM. Драйвер DRM отслеживает используемую видеопамять и может выполнить запрос, если есть свободная память, возвращая «дескриптор» в пользовательское пространство для дальнейшего обращения к выделенной памяти в последующих операциях. [6] [14] API GEM также предоставляет операции для заполнения буфера и его освобождения, когда он больше не нужен. Память из невыпущенных дескрипторов GEM восстанавливается, когда процесс пользовательского пространства закрывает дескриптор файла устройства DRM — намеренно или из-за его завершения. [16]
GEM также позволяет двум или более процессам пользовательского пространства , использующим одно и то же устройство DRM (следовательно, один и тот же драйвер DRM), совместно использовать объект GEM. [16] Дескрипторы GEM — это локальные 32-битные целые числа, уникальные для процесса, но повторяемые в других процессах, поэтому не подходят для совместного использования. Необходимо глобальное пространство имен, и GEM предоставляет его с помощью глобальных дескрипторов, называемых именами GEM . Имя GEM ссылается на один и только один объект GEM, созданный в одном и том же устройстве DRM одним и тем же драйвером DRM, с помощью уникального 32-битного целого числа . GEM предоставляет операцию flink для получения имени GEM из дескриптора GEM. [16] [12] : 16 Затем процесс может передать это имя GEM (32-битное целое число) другому процессу, используя любой доступный механизм IPC . [12] : 15 Имя GEM может использоваться процессом-получателем для получения локального дескриптора GEM, указывающего на исходный объект GEM.
К сожалению, использование имен GEM для совместного использования буферов не является безопасным. [12] : 16 [17] [18] Вредоносный сторонний процесс, получающий доступ к тому же устройству DRM, может попытаться угадать имя GEM буфера, совместно используемого двумя другими процессами, просто проверив 32-битные целые числа. [19] [18] После того, как имя GEM найдено, его содержимое может быть доступно и изменено, что нарушит конфиденциальность и целостность информации буфера. Этот недостаток был преодолен позже с введением поддержки DMA-BUF в DRM, поскольку DMA-BUF представляет буферы в пользовательском пространстве как файловые дескрипторы, которые могут безопасно совместно использоваться .
Другой важной задачей для любой системы управления видеопамятью, помимо управления пространством видеопамяти, является управление синхронизацией памяти между GPU и CPU. Текущие архитектуры памяти очень сложны и обычно включают в себя различные уровни кэшей для системной памяти, а иногда и для видеопамяти. Поэтому менеджеры видеопамяти также должны управлять согласованностью кэшей , чтобы гарантировать, что данные, совместно используемые CPU и GPU, являются согласованными. [20] Это означает, что часто внутренние компоненты управления видеопамятью сильно зависят от аппаратных деталей GPU и архитектуры памяти, и, следовательно, зависят от драйвера. [21]
GEM изначально был разработан инженерами Intel для предоставления менеджера видеопамяти для драйвера i915. [20] Семейство Intel GMA 9xx представляет собой интегрированные графические процессоры с архитектурой Uniform Memory Architecture (UMA), где графический процессор и центральный процессор совместно используют физическую память, и нет выделенной VRAM. [22] GEM определяет «домены памяти» для синхронизации памяти, и хотя эти домены памяти не зависят от графического процессора, [6] они специально разработаны с учетом архитектуры памяти UMA, что делает их менее подходящими для других архитектур памяти, таких как архитектуры с отдельной VRAM. По этой причине другие драйверы DRM решили предоставить программам пользовательского пространства API GEM, но внутри они реализовали другой менеджер памяти, более подходящий для их конкретной аппаратной части и архитектуры памяти. [23]
API GEM также предоставляет ioctl для управления потоком выполнения (буферы команд), но они специфичны для Intel и должны использоваться с Intel i915 и более поздними графическими процессорами. [6] Ни один другой драйвер DRM не пытался реализовать какую-либо часть API GEM, кроме ioctl, специфичных для управления памятью.
Translation Table Maps (TTM) — это название универсального менеджера памяти для графических процессоров, который был разработан до GEM. [5] [14] Он был специально разработан для управления различными типами памяти, к которым может обращаться графический процессор, включая выделенную видеопамять (обычно устанавливаемую в видеокарту) и системную память, доступную через блок управления памятью ввода-вывода, называемый таблицей перераспределения графических адресов (GART). [5] TTM также должен обрабатывать части видеопамяти, которые не адресуются напрямую центральным процессором, и делать это с максимально возможной производительностью, учитывая, что графические приложения пользовательского пространства обычно работают с большими объемами видеоданных. Другим важным вопросом было поддержание согласованности между различными задействованными типами памяти и кэшами.
Основная концепция TTM — это «буферные объекты», области видеопамяти, которые в какой-то момент должны быть адресуемы графическим процессором. [5] Когда графическое приложение пользовательского пространства хочет получить доступ к определенному буферному объекту (обычно для заполнения его содержимым), TTM может потребовать переместить его в тип памяти, адресуемый центральным процессором. Дальнейшие перемещения — или операции отображения GART — могут произойти, когда графическому процессору требуется доступ к буферному объекту, но он еще не находится в адресном пространстве графического процессора. Каждая из этих операций перемещения должна обрабатывать любые связанные данные и проблемы с когерентностью кэша. [5]
Еще одной важной концепцией TTM являются ограждения . Ограждения по сути являются механизмом управления параллелизмом между CPU и GPU. [24] Ограждение отслеживает, когда объект буфера больше не используется GPU, как правило, для уведомления любого процесса пользовательского пространства, имеющего к нему доступ. [5]
Тот факт, что TTM пытался управлять всеми видами архитектур памяти, включая те, что с выделенной VRAM и без нее, подходящим способом и предоставлять все возможные функции в менеджере памяти для использования с любым типом оборудования, привел к чрезмерно сложному решению с API, намного большим, чем требовалось. [24] [14] Некоторые разработчики DRM считали, что он не будет хорошо сочетаться с каким-либо конкретным драйвером, особенно с API. Когда GEM появился как более простой менеджер памяти, его API был предпочтительнее, чем у TTM. Но некоторые разработчики драйверов посчитали, что подход, принятый TTM, больше подходит для дискретных видеокарт с выделенной видеопамятью и IOMMU, поэтому они решили использовать TTM внутренне, при этом выставляя свои буферные объекты как объекты GEM и, таким образом, поддерживая API GEM. [23] Примерами текущих драйверов, использующих TTM в качестве внутреннего менеджера памяти, но предоставляющих API GEM, являются драйвер radeon для видеокарт AMD и драйвер nouveau для видеокарт NVIDIA.
API общего доступа к буферу DMA (часто сокращенно DMA-BUF) — это внутренний API ядра Linux, разработанный для предоставления универсального механизма для совместного использования буферов DMA на нескольких устройствах, возможно, управляемых различными типами драйверов устройств. [25] [26] Например, устройство Video4Linux и устройство графического адаптера могут совместно использовать буферы через DMA-BUF для достижения нулевой копии данных видеопотока, созданного первым и потребляемого последним. Любой драйвер устройства Linux может реализовать этот API как экспортер, как пользователь (потребитель) или и то, и другое.
Эта функция была впервые использована в DRM для реализации PRIME, решения для разгрузки GPU, которое использует DMA-BUF для совместного использования результирующих буферов кадров между драйверами DRM дискретного и интегрированного GPU. [27] : 13 Важной особенностью DMA-BUF является то, что общий буфер представляется в пространстве пользователя как файловый дескриптор . [14] [12] : 17 Для разработки PRIME в API DRM были добавлены два новых ioctl, один для преобразования локального дескриптора GEM в файловый дескриптор DMA-BUF, а другой для прямо противоположной операции.
Эти два новых ioctl позже были повторно использованы как способ исправления неотъемлемой небезопасности совместного использования буфера GEM. [12] : 17 В отличие от имен GEM, дескрипторы файлов не могут быть угаданы (они не являются глобальным пространством имен), и операционные системы Unix предоставляют безопасный способ передачи их через сокет домена Unix с использованием семантики SCM_RIGHTS. [14] [28] : 11 Процесс, который хочет совместно использовать объект GEM с другим процессом, может преобразовать свой локальный дескриптор GEM в файловый дескриптор DMA-BUF и передать его получателю, который, в свою очередь, может получить свой собственный дескриптор GEM из полученного файлового дескриптора. [12] : 16 Этот метод используется DRI3 для совместного использования буферов между клиентом и X-сервером [29] , а также Wayland .
Для правильной работы видеокарта или графический адаптер должны установить режим — комбинацию разрешения экрана , глубины цвета и частоты обновления — который находится в диапазоне значений, поддерживаемых им самим и подключенным дисплеем . Эта операция называется настройкой режима , [30] и обычно требует прямого доступа к графическому оборудованию, т. е. возможности записи в определенные регистры контроллера дисплея видеокарты . [31] [32] Операция установки режима должна быть выполнена до начала использования кадрового буфера , а также когда режим требуется изменить приложением или пользователем.
В ранние дни программы пользовательского пространства, которые хотели использовать графический буфер кадров, также отвечали за предоставление операций по установке режима, [3] и поэтому им нужно было работать с привилегированным доступом к видеооборудованию. В операционных системах типа Unix наиболее ярким примером был X-сервер , и его реализация установки режима находилась в драйвере DDX для каждого конкретного типа видеокарты. [33] Этот подход, позже названный настройкой режима пользовательского пространства или UMS, [34] [35] создает несколько проблем. [36] [30] Он не только нарушает изоляцию, которую операционные системы должны обеспечивать между программами и оборудованием, вызывая проблемы как стабильности, так и безопасности, но и может оставить графическое оборудование в несогласованном состоянии, если две или более программ пользовательского пространства попытаются выполнить установку режима одновременно. Чтобы избежать этих конфликтов, X-сервер стал на практике единственной программой пользовательского пространства, которая выполняла операции по установке режима; остальные программы пользовательского пространства полагались на X-сервер для установки соответствующего режима и обработки любых других операций, связанных с установкой режима. Первоначально настройка режима выполнялась исключительно во время процесса запуска X-сервера, но позже X-сервер получил возможность делать это во время работы. [37] Расширение XFree86-VidModeExtension было представлено в XFree86 3.1.2, чтобы позволить любому X-клиенту запрашивать изменения modeline (разрешения) на X-сервере. [38] [39] Расширение VidMode позже было заменено более общим расширением XRandR .
Однако это был не единственный код, выполняющий настройку режима в системе Linux . Во время процесса загрузки системы ядро Linux должно установить минимальный текстовый режим для виртуальной консоли (на основе стандартных режимов, определенных расширениями VESA BIOS ). [40] Также драйвер кадрового буфера ядра Linux содержал код настройки режима для настройки устройств кадрового буфера. [2] Чтобы избежать конфликтов настройки режима, сервер XFree86 — а позже и сервер X.Org — обрабатывал случай, когда пользователь переключался из графической среды в текстовую виртуальную консоль , сохраняя свое состояние настройки режима и восстанавливая его, когда пользователь переключался обратно в X. [41] Этот процесс вызывал раздражающее мерцание при переходе, а также мог дать сбой, что приводило к поврежденному или непригодному для использования выводу. [42]
Подход к настройке режима пользовательского пространства также вызывал другие проблемы: [43] [42]
Для решения этих проблем код настройки режима был перемещен в одно место внутри ядра, а именно в существующий модуль DRM. [36] [37] [44] [42] [43] Затем каждый процесс, включая X-сервер, должен был иметь возможность отдавать ядру команды на выполнение операций настройки режима, и ядро должно было гарантировать, что параллельные операции не приведут к несогласованному состоянию. Новый API ядра и код, добавленный в модуль DRM для выполнения этих операций настройки режима, были названы Kernel Mode-Setting (KMS). [30]
Kernel Mode-Setting предоставляет несколько преимуществ. Самым непосредственным, конечно, является удаление дублирующего кода настройки режима как из ядра (консоль Linux, fbdev), так и из пользовательского пространства (драйверы X Server DDX). KMS также упрощает написание альтернативных графических систем, которым теперь не нужно реализовывать свой собственный код настройки режима. [42] [43] Предоставляя централизованное управление режимами, KMS решает проблемы мерцания при переключении между консолью и X, а также между различными экземплярами X (быстрое переключение пользователей). [41] [44] Поскольку он доступен в ядре, его также можно использовать в начале процесса загрузки, избавляя от мерцания из-за смены режима на этих ранних этапах.
Тот факт, что KMS является частью ядра, позволяет ему использовать ресурсы, доступные только в пространстве ядра, такие как прерывания . [45] Например, восстановление режима после процесса приостановки/возобновления значительно упрощается, поскольку управляется самим ядром, и, между прочим, повышает безопасность (больше нет инструментов пространства пользователя, требующих прав root). Ядро также позволяет легко подключать новые устройства отображения в горячем режиме , решая давнюю проблему. [45] Настройка режима также тесно связана с управлением памятью, поскольку буферы кадров по сути являются буферами памяти, поэтому настоятельно рекомендуется тесная интеграция с диспетчером графической памяти. Это главная причина, по которой код настройки режима ядра был включен в DRM, а не как отдельная подсистема. [44]
Чтобы избежать нарушения обратной совместимости API DRM, Kernel Mode-Setting предоставляется как дополнительная функция драйвера определенных драйверов DRM. [46] Любой драйвер DRM может предоставить флаг DRIVER_MODESET при регистрации в ядре DRM, чтобы указать, что он поддерживает API KMS. [8] Драйверы, реализующие Kernel Mode-Setting, часто называются драйверами KMS , чтобы отличать их от устаревших — без KMS — драйверов DRM.
KMS был принят до такой степени, что некоторые драйверы, в которых отсутствует 3D-ускорение (или для которых поставщик оборудования не хочет его раскрывать или реализовывать), тем не менее, реализуют KMS API без остальной части DRM API, что позволяет серверам отображения (таким как Wayland ) работать с легкостью. [47] [48]
KMS моделирует и управляет выходными устройствами как серией абстрактных аппаратных блоков, обычно встречающихся на конвейере вывода дисплея контроллера дисплея . Эти блоки: [49]
В последние годы предпринимаются постоянные усилия по приданию атомарности некоторым обычным операциям, относящимся к API KMS, в частности, операциям по настройке режима и перелистыванию страниц . [33] [52] Этот улучшенный API KMS — это то, что называется Atomic Display (ранее известный как атомарная настройка режима и атомарный или ядерный перелистывание страниц ).
Целью атомарной настройки режима является обеспечение правильного изменения режима в сложных конфигурациях с множественными ограничениями, путем избегания промежуточных шагов, которые могут привести к несогласованному или недопустимому состоянию видео; [52] он также позволяет избежать рискованных состояний видео, когда неудачный процесс настройки режима должен быть отменен («откат»). [53] : 9 Атомарная настройка режима позволяет заранее узнать, подходит ли определенная конкретная конфигурация режима, предоставляя возможности тестирования режима. [52] Когда атомарный режим проверен и его действительность подтверждена, его можно применить с помощью одной неделимой (атомарной) операции фиксации . Операции проверки и фиксации предоставляются одним и тем же новым ioctl с разными флагами.
С другой стороны, атомарное перелистывание страниц позволяет обновлять несколько плоскостей на одном и том же выходе (например, первичную плоскость, плоскость курсора и, возможно, некоторые наложения или вторичные плоскости), синхронизируя все это в пределах одного интервала VBLANK , обеспечивая правильное отображение без разрывов. [53] : 9,14 [52] Это требование особенно актуально для мобильных и встраиваемых контроллеров дисплеев, которые, как правило, используют несколько плоскостей/наложений для экономии энергии.
Новый атомарный API построен на старом KMS API. Он использует ту же модель и объекты (CRTC, кодировщики, соединители, плоскости, ...), но с увеличивающимся числом свойств объектов, которые можно изменять. [52] Атомарный процесс основан на изменении соответствующих свойств для построения состояния, которое мы хотим протестировать или зафиксировать. Свойства, которые мы хотим изменить, зависят от того, хотим ли мы выполнить настройку режима (в основном свойства CRTC, кодировщиков и соединителей) или перелистывание страниц (обычно свойства плоскостей). ioctl одинаков для обоих случаев, разница заключается в списке свойств, передаваемых с каждым из них. [54]
В оригинальном API DRM устройство DRM используется как для привилегированных (настройка режима, другое управление дисплеем), так и для непривилегированных (рендеринг, вычисления GPGPU ) операций. [9] По соображениям безопасности открытие связанного файла устройства DRM требует специальных привилегий, «эквивалентных привилегиям root». [55] Это приводит к архитектуре, в которой только некоторые надежные программы пользовательского пространства (X-сервер, графический компоновщик, ...) имеют полный доступ к API DRM, включая привилегированные части, такие как API modeset. Другие приложения пользовательского пространства, которые хотят визуализировать или выполнять вычисления GPGPU, должны быть предоставлены владельцем устройства DRM («DRM Master») с помощью специального интерфейса аутентификации. [56] Затем аутентифицированные приложения могут визуализировать или выполнять вычисления, используя ограниченную версию API DRM без привилегированных операций. Такая конструкция накладывает серьезные ограничения: всегда должен быть запущен графический сервер (X-сервер, композитор Wayland, ...), действующий как DRM-Master устройства DRM, чтобы другим программам пользовательского пространства могло быть предоставлено использование устройства, даже в случаях, не связанных с каким-либо графическим отображением, например вычислениями GPGPU. [55] [56]/dev/dri/cardX
Концепция «узлов рендеринга» пытается решить эти сценарии, разделяя API пользовательского пространства DRM на два интерфейса — один привилегированный и один непривилегированный — и используя отдельные файлы устройств (или «узлы») для каждого из них. [9] Для каждого найденного графического процессора его соответствующий драйвер DRM — если он поддерживает функцию узлов рендеринга — создает файл устройства , называемый узлом рендеринга , в дополнение к основному узлу . [56] [9] Клиенты, использующие модель прямого рендеринга, и приложения, которые хотят воспользоваться вычислительными возможностями графического процессора, могут сделать это без необходимости дополнительных привилегий, просто открыв любой существующий узел рендеринга и отправив операции графического процессора с использованием ограниченного подмножества API DRM, поддерживаемого этими узлами, — при условии, что у них есть разрешения файловой системы на открытие файла устройства. Серверы отображения, композиторы и любые другие программы, которым требуется API modeset или любая другая привилегированная операция, должны открыть стандартный основной узел, который предоставляет доступ к полному API DRM, и использовать его как обычно. Узлы рендеринга явно запрещают операцию GEM flink , чтобы предотвратить совместное использование буфера с использованием небезопасных глобальных имен GEM; для совместного использования буферов с другим клиентом, включая графический сервер, можно использовать только файловые дескрипторы PRIME (DMA-BUF). [9] [56]/dev/dri/renderDX
/dev/dri/cardX
Подсистема Linux DRM включает в себя бесплатные и открытые драйверы для поддержки оборудования от 3 основных производителей графических процессоров для настольных компьютеров (AMD, NVIDIA и Intel), а также от растущего числа мобильных интеграторов графических процессоров и систем на чипе (SoC). Качество каждого драйвера сильно различается в зависимости от степени сотрудничества производителя и других факторов.
Также в следующей таблице для исторических целей приведен ряд драйверов для устаревшего оборудования.
Direct Rendering Manager разрабатывается в ядре Linux , а его исходный код находится в /drivers/gpu/drm
каталоге исходного кода Linux. Подсистемный сопровождающий — Дэйв Эйрли, а другие сопровождающие заботятся о конкретных драйверах. [127] Как обычно при разработке ядра Linux, подсопровождающие и участники DRM отправляют свои патчи с новыми функциями и исправлениями ошибок главному сопровождающему DRM, который интегрирует их в свой собственный репозиторий Linux . Сопровождающий DRM, в свою очередь, отправляет все эти патчи, готовые к включению в основную линейку, Линусу Торвальдсу всякий раз, когда собирается выпустить новую версию Linux. Торвальдс, как главный сопровождающий всего ядра, имеет последнее слово в вопросе о том, подходит ли патч для включения в ядро.
По историческим причинам исходный код библиотеки libdrm поддерживается под эгидой проекта Mesa . [128]
В 1999 году, разрабатывая DRI для XFree86 , Precision Insight создала первую версию DRM для видеокарт 3dfx , как патч ядра Linux , включенный в исходный код Mesa . [129] Позже в том же году код DRM был включен в ядро Linux 2.3.18 в каталоге для символьных устройств . [130] В последующие годы количество поддерживаемых видеокарт росло. Когда в январе 2001 года был выпущен Linux 2.4.0, уже поддерживались Creative Labs GMX 2000, Intel i810, Matrox G200/G400 и ATI Rage 128, в дополнение к картам 3dfx Voodoo3, [131] и этот список расширился в серии 2.4.x, с драйверами для карт ATI Radeon , некоторых видеокарт SiS и Intel 830M и последующих интегрированных графических процессоров./drivers/char/drm/
Разделение DRM на два компонента, ядро DRM и драйвер DRM, называемое разделением ядра DRM/личности , было осуществлено во второй половине 2004 года [11] [132] и объединено в версию ядра 2.6.11. [133] Это разделение позволило нескольким драйверам DRM для нескольких устройств работать одновременно, открывая путь к поддержке нескольких графических процессоров.
Идея размещения всего кода настройки видеорежима в одном месте внутри ядра признавалась годами, [134] [135] но производители видеокарт утверждали, что единственный способ сделать настройку режима — это использовать процедуры, предоставленные ими самими и содержащиеся в Video BIOS каждой видеокарты. Такой код должен был выполняться с использованием реального режима x86 , что не позволяло его вызывать ядру, работающему в защищенном режиме . [44] Ситуация изменилась, когда Люк Верхаген и другие разработчики нашли способ сделать настройку режима нативно, а не на основе BIOS, [136] [44] показав, что это можно сделать с помощью обычного кода ядра, и заложив основу для того, что впоследствии стало настройкой режима ядра . В мае 2007 года Джесси Барнс ( Intel ) опубликовал первое предложение по API drm-modesetting и работающую собственную реализацию настройки режима для графических процессоров Intel в драйвере DRM i915. [42] В декабре 2007 года Джером Глисс начал добавлять собственный код настройки режима для карт ATI в драйвер Radeon DRM. [137] [138] Работа над API и драйверами продолжалась в течение 2008 года, но была отложена из-за необходимости менеджера памяти также в пространстве ядра для обработки кадровых буферов. [139]
В октябре 2008 г. ядро Linux 2.6.27 принесло значительную реорганизацию исходного кода , перед некоторыми значительными предстоящими изменениями. Дерево исходного кода DRM было перемещено в его собственный исходный каталог /drivers/gpu/drm/
, а различные драйверы были перемещены в их собственные подкаталоги. Заголовки также были перемещены в новый /include/drm
каталог. [140]
Возрастающая сложность управления видеопамятью привела к нескольким подходам к решению этой проблемы. Первой попыткой был менеджер памяти Translation Table Maps (TTM), разработанный Томасом Хеллстромом ( Tungsten Graphics ) в сотрудничестве с Эммой Анхольт (Intel) и Дэйвом Эйрли ( Red Hat ). [5] TTM был предложен для включения в основную ветку ядра 2.6.25 в ноябре 2007 года, [5] и снова в мае 2008 года, но был отвергнут в пользу нового подхода, называемого Graphics Execution Manager (GEM). [24] GEM был впервые разработан Кейтом Паккардом и Эммой Анхольт из Intel как более простое решение для управления памятью для их драйвера i915. [6] GEM был хорошо принят и включён в ядро Linux версии 2.6.28, выпущенное в декабре 2008 года. [141] Между тем, TTM пришлось ждать до сентября 2009 года, чтобы окончательно встроить его в Linux 2.6.31 в качестве требования нового драйвера Radeon KMS DRM. [142]
С управлением памятью для обработки объектов буфера разработчики DRM наконец смогли добавить в ядро уже готовый API и код для настройки режима . Этот расширенный API называется настройкой режима ядра (KMS), а драйверы, которые его реализуют, часто называются драйверами KMS . В марте 2009 года KMS был объединен с версией ядра Linux 2.6.29, [30] [143] вместе с поддержкой KMS для драйвера i915. [144] API KMS был открыт для программ пользовательского пространства с libdrm 2.4.3. [145] Драйвер пользовательского пространства X.Org DDX для видеокарт Intel также был первым, кто использовал новые API GEM и KMS. [146] Поддержка KMS для драйвера Radeon DRM была добавлена в выпуск Linux 2.6.31 в сентябре 2009 года. [147] [148] [149] Новый драйвер Radeon KMS использовал менеджер памяти TTM, но открывал совместимые с GEM интерфейсы и ioctl вместо TTM. [23]
С 2006 года проект nouveau разрабатывал бесплатный программный драйвер DRM для графических процессоров NVIDIA вне официального ядра Linux. В 2010 году исходный код nouveau был объединен с Linux 2.6.33 в качестве экспериментального драйвера. [58] [59] На момент объединения драйвер уже был преобразован в KMS, и за API GEM он использовал TTM в качестве своего менеджера памяти. [150]
Новый API KMS, включая API GEM, стал важной вехой в развитии DRM, но это не помешало API совершенствоваться в последующие годы. KMS получил поддержку перелистывания страниц в сочетании с асинхронными уведомлениями VBLANK в Linux 2.6.33 [151] [152] — только для драйвера i915, radeon и nouveau добавили ее позже во время выпуска Linux 2.6.38. [153] Новый интерфейс перелистывания страниц был добавлен в libdrm 2.4.17. [154] В начале 2011 года, во время цикла выпуска Linux 2.6.39, в API KMS были добавлены так называемые немые буферы — аппаратно-независимый неускоренный способ обработки простых буферов, пригодных для использования в качестве кадровых буферов. [155] [156] Цель состояла в том, чтобы уменьшить сложность таких приложений, как Plymouth , которым не нужно использовать специальные ускоренные операции, предоставляемые специфичными для драйвера ioctl. [157] Эта функция была представлена libdrm, начиная с версии 2.4.25. [158] Позже в том же году она также получила новый основной тип объектов, называемый planes . Planes были разработаны для представления аппаратных наложений, поддерживаемых механизмом сканирования. [159] [160] Поддержка plane была объединена в Linux 3.3. [161] и libdrm 2.4.30. Еще одной концепцией, добавленной в API — во время выпусков Linux 3.5 [162] и libdrm 2.4.36 [163] — были generic object properties , метод добавления generic значений к любому объекту KMS. Свойства особенно полезны для установки специального поведения или функций для таких объектов, как CRTC и planes.
Раннее доказательство концепции обеспечения разгрузки GPU между драйверами DRM было разработано Дэйвом Эйрли в 2010 году. [7] [164] Поскольку Эйрли пытался имитировать технологию NVIDIA Optimus , он решил назвать ее «PRIME». [7] Эйрли возобновил свою работу над PRIME в конце 2011 года, но на основе нового механизма совместного использования буфера DMA-BUF, представленного ядром Linux 3.3. [165] Базовая инфраструктура DMA-BUF PRIME была завершена в марте 2012 года [166] и объединена с выпуском Linux 3.4, [167] [168] [169], а также с libdrm 2.4.34. [170] Позже, во время выпуска Linux 3.5, несколько драйверов DRM реализовали поддержку PRIME, включая i915 для карт Intel, radeon для карт AMD и nouveau для карт NVIDIA. [171] [172]
В последние годы DRM API постепенно расширялся новыми и улучшенными функциями. В 2013 году в рамках GSoC Дэвид Херрманн разработал функцию множественных узлов рендеринга . [55] Его код был добавлен в ядро Linux версии 3.12 в качестве экспериментальной функции [173] [174], поддерживаемой драйверами i915, [175] radeon [176] и nouveau [177] , и включенной по умолчанию с Linux 3.17. [77] В 2014 году Мэтт Ропер (Intel) разработал концепцию универсальных плоскостей (или унифицированных плоскостей ), с помощью которой буферы кадров ( первичные плоскости ), наложения ( вторичные плоскости ) и курсоры ( плоскости курсора ) рассматриваются как один тип объекта с унифицированным API. [178] Поддержка универсальных плоскостей обеспечивает более согласованный DRM API с меньшим количеством более общих ioctl . [33] Для поддержания обратной совместимости API эта функция представлена ядром DRM как дополнительная возможность, которую может предоставить драйвер DRM. Поддержка универсальной плоскости дебютировала в Linux 3.15 [179] и libdrm 2.4.55. [180] Несколько драйверов, таких как Intel i915, [181] уже реализовали ее.
Самым последним усовершенствованием API DRM является API атомарной установки режима , который привносит атомарность в операции установки режима и перелистывания страниц на устройстве DRM. Идея атомарного API для установки режима была впервые предложена в начале 2012 года. [182] Вилле Сырьяля (Intel) взял на себя задачу разработки и внедрения такого атомарного API. [183] Основываясь на его работе, Роб Кларк ( Texas Instruments ) применил аналогичный подход, направленный на реализацию атомарных перелистываний страниц. [184] Позже в 2013 году обе предложенные функции были объединены в одну с использованием одного ioctl для обеих задач. [185] Поскольку это было требованием, функция должна была дождаться поддержки универсальных плоскостей, которые будут объединены в середине 2014 года. [181] Во второй половине 2014 года атомарный код был значительно улучшен Дэниелом Веттером (Intel) и другими разработчиками DRM [186] : 18 для того, чтобы облегчить переход существующих драйверов KMS на новую атомарную структуру. [187] Вся эта работа была окончательно объединена в релизах Linux 3.19 [188] и Linux 4.0 [189] [190] [191] и включена по умолчанию с Linux 4.2. [192] libdrm предоставила новый атомарный API с версии 2.4.62. [193] Несколько драйверов уже были преобразованы в новый атомарный API. [194] К 2018 году в ядро Linux было добавлено десять новых драйверов DRM, основанных на этой новой атомарной модели. [195]
Подсистема ядра Direct Rendering Manager изначально была разработана для использования с новой Direct Rendering Infrastructure сервера отображения XFree86 4.0, позже унаследованной его преемником, X.Org Server . Таким образом, основными пользователями DRM были клиенты DRI, которые ссылались на аппаратно-ускоренную реализацию OpenGL , которая находится в библиотеке Mesa 3D , а также сам X Server. В настоящее время DRM также используется несколькими композиторами Wayland , включая референсного композитора Weston . kmscon — это реализация виртуальной консоли, которая работает в пространстве пользователя с использованием средств DRM KMS. [196]
В 2015 году версия 358.09 (бета) фирменного драйвера Nvidia GeForce получила поддержку интерфейса настройки режима DRM, реализованного в виде нового BLOB-объекта ядра под названием nvidia-modeset.ko
. Этот новый компонент драйвера работает совместно с nvidia.ko
модулем ядра для программирования движка дисплея (т. е. контроллера дисплея) графического процессора. [197]
по сути имеет дело с объектами графического буфера (которые могут содержать текстуры, буферы рендеринга, шейдеры или все виды других объектов состояния и данных, используемых графическим процессором)
GEM flink много проблем. Имена flink являются глобальными, что позволяет любому, у кого есть доступ к устройству, получить доступ к содержимому данных flink.
-flink не предоставляет никаких частных пространств имен для приложений и серверов. Вместо этого предоставляется только одно глобальное пространство имен для каждого узла DRM. Вредоносные аутентифицированные приложения могут атаковать других клиентов с помощью подбора "имен" буферов gem
Многие современные высокопроизводительные графические процессоры поставляются со своими собственными менеджерами памяти. Они даже включают несколько различных кэшей, которые необходимо синхронизировать во время доступа. [...]. Поэтому управление памятью на графических процессорах сильно зависит от драйверов и оборудования.
программируются множеством способов, но большая часть инициализации и настройки режима выполняется через отображенный в память ввод-вывод. Это всего лишь набор регистров, доступных ЦП через его стандартное адресное пространство памяти. Регистры в этом адресном пространстве разделены на диапазоны, отвечающие за различные функции видеокарты, такие как настройка режима, управление выходом или конфигурация тактовой частоты.
Исторически X-сервер отвечал за сохранение состояния вывода при запуске и его восстановление при переключении обратно в текстовый режим. Быстрое переключение пользователей осуществлялось с помощью переключателя VT, поэтому переключение с X-сервера первого пользователя приводило к однократному миганию для перехода в текстовый режим, а затем немедленному повторному миганию для перехода в сеанс второго пользователя.
тонкое ограничение заключается в том, что драйвер не может обрабатывать прерывания, поэтому не существует поддержки монитора с возможностью горячего подключения.
Драйвер DRM/KMS теперь полностью работает, хотя все еще без DMA. О, и он написан на Rust, хотя в основном он просто полон сырых небезопасных блоков.
Круто то, что поскольку у нас есть "нормальный" драйвер DRM/KMS (и помощь от @[email protected]), мы можем просто делать такие вещи, как... запускать Wayland! Weston на iPod Nano 5G.
использует встроенный чип дисплея, интегрированный в чип управления Hi1710, и использует IP-ядро SM750
считаю, что лучшим решением этой проблемы является предоставление ядром единого комплексного драйвера устройства для каждой части видеооборудования. Это означает, что конфликтующие драйверы, такие как fbdev и DRM, должны быть объединены в сотрудничающую систему. Это также означает, что следует предотвратить подталкивание оборудования из пользовательского пространства, пока загружен драйвер устройства на основе ядра.
в подсистему DRM интегрировано 17 драйверов, поддерживающих атомарную настройку режима.