Привет всем, в эфире Асахи Лина!✨
marcan попросил меня написать статью о M1 GPU, и вот она готова ~! Это был долгий проект, растянувшийся на несколько месяцев, и было о чём поведать, так что, надеюсь, вам понравится!
Что такое GPU
Пожалуй, вы знаете, что такое GPU, но известно ли вам, как он работает под капотом? Давайте посмотрим! Почти у всех современных GPU одни и те же основные компоненты:
Набор шейдерных ядер, обрабатывающих треугольники (вершинные данные) и пиксели (фрагментные данные), выполняя программы, определяемые пользователем. Они используют разные кастомные наборы инструкций для каждого GPU!
Блоки растеризации, семплеры текстур, блоки вывода рендеринга, а также другие элементы, работающие вместе с шейдерами для перегона треугольников из приложения в пиксели на экране. Точный принцип работы этих механизмов отличается от GPU к GPU!
Командный процессор, принимающий от приложения команды на отрисовку и задающий шейдерные ядра, на которых эти команды будут выполняться. В частности, это данные, описывающие, какие треугольники рисовать, какие глобальные атрибуты использовать, какие текстуры будут задействованы, какие шейдерные программы, а также где именно в памяти будет сохраняться окончательный вариант изображения. Затем эти данные передаются через шейдерные ядра и другие блоки той программе, которая и выполняет рендеринг на GPU.
Блок управления памятью (MMU), отвечающий за ограничение доступа к тем областям памяти, что принадлежат конкретному приложению, использующему GPU. Поэтому различные приложения не могут друг друга обвалить или вмешаться в работу друг друга.
(Это очень упрощённая картина, на самом деле в работе участвует ещё множество элементов, варьирующихся от GPU к GPU, но выше я перечислила самые важные компоненты!)
Чтобы при обращении со всеми этими «шестерёнками» соблюдалась разумная безопасность, драйверы современных GPU делятся на две группы: драйверы пользовательского пространства и драйверы ядра. В данном случае та часть, что относится к пользовательскому пространству, отвечает за компиляцию шейдерных программ и трансляцию вызовов API (как при работе с OpenGL или Vulkan) в списки конкретных команд, которые командный процессор будет применять при рендеринге сцены. Пространство ядра, в свою очередь, отвечает за управление блоками MMU и операции выделения/высвобождения памяти от разных приложений, а также решает, как и когда отправлять различные команды в процессор, их обрабатывающий. Таким образом работают все современные драйверы для GPU во всех крупных операционных системах!
Между драйвером пользовательского пространства и драйвером ядра обычно расположен своего рода кастомный API, настраиваемый для каждого семейства GPU. Обычно эти API отличаются для каждого драйвера! В Linux такие интерфейсы называются UAPI, но в каждой ОС есть подобная сущность. Именно этот UAPI позволяет пользовательскому пространству запрашивать у ядра выделение/высвобождение памяти и отправлять в GPU списки команд.
Таким образом, чтобы подружить M1 GPU с Asahi Linux, требуются две составляющие: драйвер ядра и драйвер пользовательского пространства! 🚀
Алисса подключается к проекту
C самого начала, ещё в 2021 году, когда история Asahi Linux только начиналась, Алисса Розенцвейг присоединилась к проекту и приступила к обратной разработке M1 GPU. Вместе с Дугаллом Джонсоном (сосредоточившимся на документировании архитектуры шейдеров GPU), она начала обратную разработку со всех компонентов пользовательского пространства, в том числе, шейдеров и всех структур списка команд, необходимых для налаживания рендеринга. Это огромный кусок работы, но менее чем через месяц она уже отрисовывала свой первый треугольник! Она чудо. Если вы ещё не читали серию её статей по разделке M1 GPU, обязательно зайдите к ней на сайт и взгляните! ✨✨
Но подождите, как же она может работать над драйвером пользовательского пространства, не затрагивая при этом драйвера ядра? Легко, ведь она делала это на macOS! Алисса достаточно преуспела в обратной разработке GPU-драйвера для UAPI под macOS и научилась выделять память, а также передавать собственные команды на GPU. Таким образом, она смогла заниматься разработкой драйвера для пользовательского пространства, не беспокоясь о том, что там происходит в ядре. Это так круто! Она принялась писать драйвер M1 GPU OpenGL для Mesa — это стек для Linux, позволяющий обрабатывать графику в пользовательском пространстве, а спустя всего пару месяцев она уже userspace прошла 75% тестов на совместимость с OpenGL ES 2, всё под macOS!
Ранее в этом году она успела так продвинуться в работе, что уже гоняла игры на целиком опенсорсном стеке Mesa OpenGL, который работает поверх драйвера ядра Apple под macOS! Но аналогичного драйвера ядра Linux на тот момент всё ещё не существовало… и пришло время это исправить! ✨
Таинственная прошивка GPU
В апреле текущего года я решила постепенно разобраться, как написать драйвер ядра для M1 GPU! К тому моменту, как я приступила к работе, Скотт Мэнзелл уже успел предварительно расследовать эту проблему… и уже было ясно, что перед нами не обычный GPU. Первую пару месяцев я писала и улучшала трассировщик гипервизора m1n1 для GPU и то, что я обнаружила, показалось мне очень, очень необычным для мира GPU в целом.
Как правило, драйвер GPU отвечает за такие операции, как планирование работы и расстановка приоритетов для задач в GPU, а также за вытеснение тех заданий, чьё выполнение чрезмерно затягивается; таким образом, гарантируется, что приложения честно используют ЦП. Иногда драйвер отвечает за управление питанием, а в других случаях это делается через выделенную прошивку, работающую на сопроцессоре управления питанием. Бывает и так, что предусмотрена отдельная прошивка, в которой реализованы определённые детали обработки команд, но она, как правило, не видна драйверу ядра. В конце концов, особенно в сравнительно простых GPU «для мобильных устройств», например в ARM Mali, предусматривается конкретный аппаратный интерфейс, заставляющий GPU отображать что-либо. Обычно этот интерфейс весьма прост: в нём есть блок управления памятью (MMU), действующий как стандартный MMU или IOMMU в ЦП, а также процессор команд. Процессор команд принимает указатели, направленные непосредственно в командные буферы пользовательского пространства, например, в те или иные регистры или в кольцевой буфер. Таким образом, драйверу ядра почти не остаётся работы, кроме как управлять памятью и назначать работу в GPU, а подсистема непосредственного управления рендерингом (DRM) в ядре Linux и так предоставляет массу вспомогательных функций, упрощающих написание драйверов! Здесь есть некоторые хитрые аспекты, например, вытеснение, но они не принципиальны, если нужно заставить GPU работать с совершенно новым драйвером. Однако M1 GPU устроен иначе…
У этого GPU, как и у других элементов чипа M1, есть сопроцессор под названием “ASC”. На нём работает прошивка Apple, и он управляет GPU. Этот сопроцессор – полноценный ЦП ARM64, работающий на проприетарной операционной системе реального времени от Apple, она называется RTKit… и он отвечает за всё! Он управляет питанием, планированием и вытеснением команд, восстановлением после отказов и даже счётчиками производительности, статистикой и такими вещами как измерение температуры! На самом деле, драйвер ядра macOS вообще не обменивается информацией с аппаратной частью GPU. Вся коммуникация с GPU осуществляется через прошивку, при этом используются хранимые в памяти разделяемые структуры данных, сообщающие процессору, что делать. И таких структур много…
Данные инициализации применяются для того, чтобы сконфигурировать настройки управления питанием в прошивке, а также другие глобальные конфигурационные данные GPU, в том числе, таблицы преобразования цветовых пространств — а вдруг понадобится?! В этих структурах данных почти по 1000 полей, и мы пока даже не все их охарактеризовали!
Конвейеры доставки — это кольцевой буфер, применяемый для выстраивания очередей задач, стоящих на обработку в этом GPU.
Управляющие сообщения для устройств, при помощи которых контролируются глобальные операции, выполняемые в GPU.
Сообщения о событиях, которые прошивка отправляет обратно драйверу, если что-нибудь случится (например, завершится выполнение команды — удачно или неудачно).
Статистика, логи прошивки и трассировочные сообщения, в которых содержатся данные о состоянии GPU и отладочная информация.
Очереди команд — это список всех задач от одного приложения, стоящих в очереди на обработку в GPU.
Информация о буферах, статистика и страничные списки — это структуры данных, используемые для управления тайловыми вершинными буферами.
Контекстные структуры и другие компоненты, позволяющие прошивке GPU отслеживать происходящее.
Команды рендеринга вершин. Они сообщают той части GPU, что занята обработкой вершин и замощением, как обрабатывать команды и шейдеры из пользовательского пространства, чтобы прогонять «вершинную» часть работы в рамках целого прохода визуализации.
Команды рендеринга фрагментов. Они сообщают той части GPU, что занята обработкой фрагментов и растрированием, как отображать тайловые вершинные данные, поступающие в кадровый буфер после фактической обработки вершин.
На самом деле, всё ещё сложнее! Команды рендеринга вершин и фрагментов — это очень запутанные структуры, внутри которых вложено множество других структур. Каждая такая команда содержит указатель на «микропоследовательность» более мелких команд, интерпретируемых прошивкой GPU — представьте себе, например, собственный виртуальный ЦП! Как правило, при помощи этих команд задаётся проход визуализации, далее процессор дожидается, пока он завершится, и производит очистку… но здесь поддерживаются и такие вещи, как команды по расстановке временных меток, и даже циклы и арифметика! Безумие! И все эти структуры нужно наполнять подробнейшей информацией о том, что должно отображаться: в частности, записывать сюда указатели на буферы глубины и трафаретные буферы, размер кадрового буфера. Здесь нужно указывать, включена ли MSAA (множественная выборка сглаживания) и как она сконфигурирована, ставить указатели на конкретные вспомогательные шейдерные программы и на многое другое!
Фактически, прошивка GPU странным образом соотносится с блоками управления памятью GPU. Она использует те же самые таблицы страниц! Прошивка буквально берёт тот же самый базовый указатель на таблицу страниц, который используется блоком управления памятью GPU и конфигурирует его как свою таблицу страниц для ARM64. Поэтому память GPU — это память прошивки! Это дичь! Здесь есть разделяемое «ядерное» адресное пространство (подобное адресному пространству ядра в Linux), и именно это пространство прошивка использует для себя, а также (в основном) для коммуникации с драйвером. Далее есть несколько буферов, которые совместно используются прошивкой и аппаратным обеспечением GPU как таковым, а также имеют адреса «пользовательского пространства», распределённые по отдельным адресным пространствам для каждого приложения, использующего GPU.
Так можно ли вынести всю эту сложность в пользовательское пространство и именно там организовать настройку всех этих команд, отвечающих за рендеринг вершин и фрагментов? Нетушки! Поскольку все эти структуры лежат в разделяемом адресном пространстве ядра вместе с самой прошивкой и оперируют целым роем указателей, направленных друг на друга, они не разграничены между отдельными процессами, использующими GPU! Поэтому нельзя предоставить приложениям непосредственный доступ к ним, ведь они могут нарушить друг другу рендеринг. По всем этим причинам Алисса отыскала все эти детали рендеринга в macOS UAPI…
Драйверы для GPU на Python?!
Поскольку организовать правильную работу всех этих структур критически важно, чтобы GPU работал, а прошивка не отказывала, мне требовалось изыскать способ, как бы с ними быстро поэкспериментировать, не отвлекаясь от обратной разработки. К счастью, в проекте Asahi Linux уже имелся инструмент для этой цели: фреймворк m1n1 для Python! Поскольку в то время я уже писала трассировщик GPU для гипервизора m1n1 и заполняла определения структур в Python, я решила просто поставить задачу с ног на голову и взяться за написание драйвера ядра GPU на Python. Для этого я собиралась воспользоваться всё теми же определениями структур. Python отлично для этого подходит, поскольку в нём очень легко организовать перебор! Ещё лучше, что я уже могу общаться с базовыми протоколами RTKit и разбирать логи отказов. Кроме того, я доработала предназначенные для этого инструменты, чтобы точно видеть, что именно происходит с прошивкой, когда она отказывает. Чтобы всё это сделать, просто запускаем скрипты на той машине, где ведём разработку. Машина для разработки подключается к машине M1 по USB, поэтому её можно с лёгкостью перезагрузить, как только вам захочется что-нибудь протестировать. При этом цикл тестирования очень быстрый!
Поначалу драйвер большей частью представлял собой ворох жёстко закодированных структур, но в конце концов мне удалось все их наладить и отобразить треугольник!
🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺
🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺
🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺
🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺
🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺
🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺
🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺
🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺🔺
— Asahi Linya / 朝日りにゃ〜 // @lina@vt.social (@LinaAsahi) June 1, 2022
Это была просто наскоро сварганенная демка, но… прежде, чем приступать к разработке драйвера ядра Linux, я хотела убедиться, что действительно хорошо во всём разобралась, и только затем как следует проектировать драйвер. Просто отобразить кадр не составляет труда, но я хотела добиться, чтобы отображалось множество кадров, а также протестировать такие вещи, как конкурентность и вытеснение. Так что мне в самом деле требовался настоящий «драйвер ядра», но на Python его же не сделать, так?!
Оказывается, что у Mesa есть библиотека под названием drm-shim. Она подменяет интерфейс ядра Linux DRM, ставя на его место формальную реализацию, обрабатываемую в пользовательском пространстве. Обычно используется для таких вещей, как непрерывная интеграция шейдеров, но подходит и для более авантюрных вещей, вот, например… что, если вставить в drm_shim интерпретатор Python, и вызывать из неё весь тот драйвер-прототип, который я напишу на Python?
Могла бы я запускать Inochi2D поверх Mesa, вместе с Алиссиным драйвером Mesa M1 для GPU, работающим поверх drm-shim? А в drm_shim работал бы встроенный интерпретатор Python, посылавший бы команды моему драйверу-прототипу, написанному на Python. Этот драйвер был бы разработан на основе фреймворка m1n1 и общался бы по USB с реальной машиной M1, пересылая туда-сюда все данные. Таким образом, я могла бы сама управлять прошивкой GPU и рендерингом? Насколько смехотворно бы всё получилось?
Настолько, что даже работает! ✨
🔺🐇🧊👩🔺🐇🧊👩
✨✨ФУРЫЧИТ!!!! ✨✨
🔺🐇🧊👩🔺🐇🧊👩
Я сама себя отобразила на M1 GPU, воспользовавшись опенсорсным драйвером, который работал как eGPU по USB!!!!!!!!
При помощи m1n1 от @AsahiLinux в исполнении @marcan42 и Ко, а также драйвера mesa от @alyssarzg и моего драйвера ядра, написанного на Python – и этот драйвер управляет @Inochi2D!! 🚀 pic.twitter.com/xQdfLch64U
— Asahi Linya / 朝日りにゃ〜 // @lina@vt.social (@LinaAsahi) June 17, 2022
Новый язык для ядра Linux
Заставив работать криповый драйверный стек Mesa+Python, я постепенно стала осознавать, как должен работать драйвер ядра в конечном виде, и что он должен делать. А задач у него много! Не просматривается никакого способа жонглировать более чем 100 структурами данных, вовлечёнными в его работу и, если хотя бы что-то пойдёт не так, то всё может сломаться! Прошивка не выполняет вообще никакой проверки исправности (вероятно, ради производительности), и, если наткнётся на какие-нибудь дефектные указатели или данные, то просто аварийно завершится или вслепую затрёт информацию! Хуже того, если откажет прошивка, то единственный способ её восстановить – целиком перезагрузить машину! 😱
DRM-драйверы для ядра Linux написаны на C, а C – не тот язык, на котором хотелось бы писать сложное управление структурами данных. Мне пришлось бы вручную отслеживать время жизни каждого объекта GPU, и, если бы я хоть где-нибудь ошиблась, то могла бы спровоцировать спонтанные отказы или даже уязвимости в системе безопасности. Как же мне всё это вытянуть? Слишком много вещей, которые могли бы пойти не так, а C мне вообще не поможет в случае чего!
В довершение всего этого мне также пришлось бы поддерживать сразу много версий прошивки, а Apple не поддерживает стабильность определений структур прошивки от версии к версии! В качестве эксперимента я уже добавила поддержку для второй версии, и в итоге мне пришлось вносить в структуры данных более 100 изменений. В демке с Python это можно было бы сделать при помощи причудливого метапрограммирования, поставив поля структур в зависимость от номера версии… но в С ничего подобного нет. Придётся прибегать к уловкам из разряда «много раз компилировать весь драйвер с разными #define»!
Но на горизонте замаячил новый язык…
Примерно в то же время пошли слухи, будто Rust вскоре официально включат в ядро Linux. В проекте Rust for Linux велась работа над тем, чтобы такая официальная поддержка была добавлена в ближайшие несколько лет, и складывалось впечатление, будто официального мерджа ждать уже недолго. А могу я… написать драйвер для GPU на Rust?
У меня не так много опыта с Rust, но из того, что я читала, сложилось впечатление, будто этот язык гораздо лучше С подходит для написания драйвера GPU! Особенно меня заинтересовали две вещи: поможет ли Rust смоделировать времена жизни структур, применяемых в прошивке GPU (даже притом, что эти структуры связаны с указателями GPU, которые, с точки зрения ЦП, реальными указателями не являются), и можно ли решить проблему множественности версий при помощи макросов Rust.
Итак, прежде, чем переходить непосредственно к разработке ядра, я обратилась за помощью к экспертам по Rust и написала пробный прототип объектной модели GPU, на простом Rust для пользовательского пространства. В сообществе Rust меня приняли супер любезно, а несколько человек за руку провели через все сложности! Что бы я делала без вашей помощи! ❤
Причём создалось впечатление, будто всё должно работать! Но Rust по-прежнему не относится к мейнстримовому Linux… и я попадала на неизведанную территорию, так как ранее никто ничего подобного не делал. Требовался известный азарт… но, чем больше я задумывалась об этом, тем явственнее сердце подсказывало, что путь лежит через Rust. Поболтала на эту тему со специалистами из поддержки Linux DRM и с другими ребятами, и они, как мне показалось, отнеслись к этой идее с энтузиазмом или хотя бы благосклонно, так что …
Я решила попробовать!
Начала Rust
Поскольку мне предстояло создать первый в истории написанный на Rust драйвер ядра Linux для работы с GPU, работа меня ждала большая. Мне нужно было написать не только сам драйвер, но и абстракции Rust для графической подсистемы Linux DRM. Притом, что из Rust можно делать вызовы прямо в функции C, в данном случае не обеспечиваются никакие свойственные Rust гарантии безопасности. Поэтому, чтобы спокойно использовать код C из Rust, сначала нужно написать обёртки, из которых получился бы безопасный Rust-подобный API. Мне пришлось написать почти 1500 строк кода на одни только абстракции, а чтобы спроектировать хорошую и безопасную систему, потребовалось подробно всё продумывать и переписывать!
18 августа я принялась писать драйвер на Rust. Поначалу работа с блоками управления памятью опиралась на код C (частично скопированный из драйвера Panfrost), хотя, позже я решила переписать весь этот код на Rust. В течение нескольких следующих недель я добавила объектную систему Rust GPU, которую ранее прототипировала, а затем повторно реализовала на Rust все прочие части того демо-драйвера, который уже был написан у меня на Python.
Чем больше я работала с Rust, тем сильнее в него влюблялась! Такое ощущение, что сам дизайн Rust ведёт тебя к качественным абстракциям и грамотным вариантам проектирования. Компилятор очень придирчив, но если уж код компилируется, то можно не сомневаться, что этот код будет работать надёжно. Иногда приходилось помучиться, чтобы применяемый мной вариант устроил компилятор, а потом выяснялось, что в спроектированной мной модели в самом деле были фундаментальные проблемы!
Драйвер медленно срастался, и 24 сентября у меня наконец-то был kmscube, чтобы отобразить первый куб при помощи моего новоиспечённого драйвера на Rust!
🧊🧊🧊🧊🧊🧊🧊🧊
🧊🧊🧊🧊🧊🧊🧊🧊
🧊 C U B E 🧊
🧊🧊🧊🧊🧊🧊🧊🧊
🧊🧊🧊🧊🧊🧊🧊🧊
Работает!!!!
Он не отображается на HDMI, так как что-то не так с kmsro, но он работает!!!! Отображает!!! Вращающийся кубик!!! С моего драйвера для Linux, написанного на Rust!!!!!!!!!
🦀✨✨✨✨✨✨✨✨✨✨🦀 pic.twitter.com/8duIAvnG4a
— Asahi Linya / 朝日りにゃ〜 // @lina@vt.social (@LinaAsahi) September 24, 2022
А потом произошло кое-что волшебное.
🦀🐧🍎🔻🧊🇼👩🔥🦊⚙️
Neverball, Firefox + YouTube и @Inochi2D, сеанс в GNOME Wayland!!!
Всё работает одновременно под Apple M1 Mac Mini с моим драйвером ядра Linux на Rust Linux и с драйвером Mesa для M1 GPU от @alyssarzg!!!
🦀🐧🍎🔻🧊🇼👩🔥🦊⚙️
▶️https://t.co/g0R1JZI6Pe pic.twitter.com/ek879MVc2D
— Asahi Linya / 朝日りにゃ〜 // @lina@vt.social (@LinaAsahi) September 29, 2022
Всего через несколько дней мне уже удавалось запускать полноценный сеанс для GNOME на ПК!
Rust волшебный!
Как правило, когда вы пишете совершенно новый драйвер ядра, да ещё такой сложный, как этот, попытка перейти от простых демо-приложений к полноценной настольной версии со множеством приложений, конкурентно использующих GPU, провоцирует всевозможные условия гонок, утечки памяти, проблемы с высвобождением после использования и прочие гадости на любой вкус.
Но всего этого просто… не случилось! Мне всего лишь потребовалось устранить несколько багов в логике, одну проблему в самом ядре кода, управлявшего памятью, после чего всё остальное работало стабильно! Rust поистине волшебный! Безопасность в нём на таком уровне, что спроектированный драйвер гарантированно получится безопасным на уровне потоков и на уровне памяти, если только нет проблем в немногочисленных небезопасных разделах. В самом деле, Rust ведёт вас не только к безопасным, но и просто к хорошим вариантам проектирования.
Разумеется, в коде всегда найдётся несколько небезопасных участков, но, поскольку Rust всегда ориентирует нас на использование безопасных абстракций, не составляет труда держать общую поверхность возникновения возможных багов минимальной. Кое-какие проблемы с безопасностью всё-таки есть! Например, у меня был баг в абстракции для управления памятью DRM, который мог бы привести к такой неприятности: аллокатор будет освобождён ещё до того, как окажется высвобождена вся выделенная им память. Но, поскольку баги такого рода специфичны для конкретного участка кода, обычно они кажутся явными и очевидными (поэтому их находят при аудите или ревью кода). Это вам не трудноуловимые условия гонок и не такие случаи ошибок, которые захватывают весь драйвер. Вы постепенно уменьшаете количество возможных багов, так, что в итоге остаётся беспокоиться о минимальном количестве – всего-то и дел, что продумать конкретные модули кода и участки, релевантные с точки зрения безопасности, каждый в отдельности. Их взаимодействия с прочим кодом можно не учитывать. Это сложно описать, если вы не пробовали Rust, но разница в самом деле огромна!
O, а ещё нужно сказать об обработке ошибок и об очистке. Вся эта коварная обработка ошибок в стиле goto cleanup, которая нужна в C, чтобы прибрать за собой ресурсы, в Rust просто… исчезает. Одно лишь это ценно само по себе. Плюс, вы получаете реальные итераторы, а подсчёт ссылок здесь автоматический! ❤
Просто нравится видеть, как все странные и чреватые ошибками паттерны программирования ядра из C превращаются в красивый код на Rust. ♥
Только посмотрите, ни одного `of_node_put()` где бы то ни было!
Никаких странных макросов итераторов!
Нет `goto err_put_foo`!
Обработка ошибок в один символ!
🦀 pic.twitter.com/59X0jThkfZ
— Asahi Linya / 朝日りにゃ〜 // @lina@vt.social (@LinaAsahi) October 21, 2022
Объединяем усилия
Когда разработка драйвера ядра легла на верный курс, пришло время скооперироваться с Алиссой и взяться за общее дело! Она, уже не стеснённая необходимостью всё тестировать только на macOS, стала всерьёз улучшать драйвер Mesa! Я ей даже немного помогла ^^.
Мы выступили с совместным докладом на XDC 2022, и на тот момент всю информацию к лекции мы демонстрировали на M1, пользуясь нашими драйверами! С тех пор мы занимались добавлением новых фич, фиксили баги, а также улучшали производительность, каждая со своей стороны. Я добавила поддержку для семейства M1 Pro/Max/Ultra и M2 на стороне ядра, а также многое доработала по внесению дополнительных и более качественных отладочных инструментов. Также улучшила производительность при выделении памяти. Моя коллега методично улучшала соответствие с GL, так что совместимость с OpenGL ES 2.0 уже практически полная, а совместимость с 3.0 превышает 96%! Она также добавила множество новых фич и оптимизаций производительности, и теперь уже можно играть в такие игры, как Xonotic и Quake в качестве 4K!
А поскольку за управление питанием GPU отвечает прошивка, всё это просто работает. Я тестировала Xonotic при 1080p в рамках сеанса GNOME, и заряда батареи хватало более чем на 8 часов! 🚀
Что насчёт поддержки Vulkan? Не волнуйтесь… над этим работает Ella! ✨✨
VKCUBE на @AsahiLinux !!! pic.twitter.com/a7pMcLurpT
— @ella@tech.lgbt (@EllaStanforth) October 23, 2022
Что дальше?
Нам всё ещё предстоит долгий путь! Тот UAPI, которым мы сейчас пользуемся — это по-прежнему прототип, и остаётся ещё много новых фич, которые требуется добавить или перепроектировать, чтобы в будущем у нас мог поддерживаться полноценный драйвер Vulkan. Поскольку Linux требует, чтобы UAPI оставался стабильным и обратно совместимым от версии к версии (а macOS не требует), это означает, что ещё много месяцев драйвер не попадёт в стабильную ветку, пока мы не будем полнее представлять параметры рендеринга GPU и не реализуем все новые возможности проектирования, требуемые для Vulkan. Производительность актуального UAPI также ограничена… он даже пока не может конкурентно выполнять рендеринг на GPU одновременно с обработкой на ЦП!
Конечно же, остаётся ещё масса работы со стороны пользовательского пространства, нужно улучшать соответствие и производительность, а также добавлять поддержку для новых расширений и возможностей GL! Некоторые возможности, например, замощение и геометрические шейдеры, реализовать очень непросто (так как их требуется частично или полностью эмулировать), поэтому в ближайшей и даже отдалённой перспективе не ждите полной поддержки OpenGL 3.2+.
Но даже с учётом этих ограничений сегодня эти драйверы обеспечивают стабильную работу с программами для ПК, и производительность улучшается из недели в неделю! Wayland сейчас работает на этих машинах восхитительно гладко, точно как на нативной macOS! Xorg тоже работает с учётом некоторых усовершенствований, которые я не так давно внесла в драйвер дисплея, хотя не удивляйтесь возможным проблемам с разрывом изображения и с vsync из-за ограничений Xorg. Wayland – это в самом деле будущее новых платформ! 💫
Итак, где всё это можно взять? У нас ещё далеко не всё готово! Прямо сейчас стек драйвера сложно как собирать, так и устанавливать (вам потребуются кастомные сборки m1n1, ядра и mesa), поэтому, пожалуйста, наберитесь терпения! Нам ещё осталось зачистить несколько концов… но, надеемся, мы сможем добавить всё это в Asahi Linux в качестве добровольно подключаемой тестовой сборки ещё до конца текущего года! ✨✨
Если вам интересно следить за моей работой над GPU, подпишитесь на меня в @lina@vt.social или на мой канал на YouTube! Завтра я планирую разбираться, как вычисляется энергопотребление для M1 Pro/Max/Ultra и M2, надеюсь, вы ко мне присоединитесь! ✨
Если хотите поддержать мою работу, то можете задонатить мне в фонд Asahi Linux для marcan на GitHub Sponsors или Patreon, это мне также пригодится! А если вам не терпится увидеть драйвер для Vulkan, посмотрите страницу Эллы на GitHub Sponsors! Алисса сама донатов не принимает, но она будет благодарна, если вы пожертвуете на благотворительность, например, в Software Freedom Conservancy. (Правда, может быть, настанет день, и она разрешит мне купить ей M2… ^^;;)