Bifrost встречается с GNOME: Вперед и вверх до нуля
Ссылка на оригинал - https://www.collabora.com/news-and-blog/blog/2020/06/05/bifrost-meets-gnome-onwa…, автор публикации - Alyssa Rosenzweig
В нашем последнем обновлении блога для Panfrost, бесплатного графического драйвера с открытым исходным кодом для современных графических процессоров Mali, мы объявили о начальной поддержке архитектуры Bifrost. С тех пор мы расширили эту поддержку до всех основных функций OpenGL ES 2.0 и даже некоторых функций настольного OpenGL 2.1. С помощью свободного программного обеспечения чип Mali G31 теперь может запускать композиторы Wayland с нулевой копией графики, включая GNOME 3. Мы можем запустить любую сцену в glmark2-es2, и можно играть в 3D-игры, такие как Neverball. Кроме того, мы можем поддерживать аппаратно-ускоренные видеоплееры mpv и Kodi. Скриншоты выше сделаны с платы Mali G31 под управлением Panfrost.
Все вышеперечисленное включено в upstream Mesa без необходимости установки патчей вне дерева, а предстоящая поддержка Bifrost включена с помощью переменной окружения PAN_MESA_DEBUG=bifrost.
Оболочка GNOME |
Neverball |
Новые опкоды
Создание этих новых приложений потребовало реализации многих новых арифметических операций с плавающей точкой, включая сравнение, выборку и дополнительные преобразования типов. Кроме того, я добавил начальную поддержку целочисленной арифметики и побитовых операций, используемых для непосредственной реализации целочисленных типов, а также булевых чисел. Хотя требуется несколько кодов операций арифметического логического блока (ALU), это не является препятствием на архитектурах с обычными кодировками инструкций.
К сожалению, Bifrost не является регулярной архитектурой и имеет десятки различных кодировок инструкций для экономии места. Добавление опкодов в компилятор по-прежнему является рутинной задачей, но требует добавления довольно большого количества кода. Кроме того, дублирование может привести к ошибкам, поэтому, как только я добавляю новый опкод, я добавляю комплексные тесты на реальном оборудовании, перебирая различные комбинации размера операнда и модификаторов, чтобы проверить все особые случаи упаковки.
В итоге, покрытие тестами устраняет целые классы ошибок компилятора, которые обычно поражают новые драйверы, что позволяет нашему драйверу Bifrost с открытым исходным кодом процветать, несмотря на такую причудливую архитектуру.
Помимо новых операционных кодов ALU, я расширил поддержку текстур, чтобы сделать возможными простые операции с текстурами из вершинных шейдеров, что встречается в сцене рельефа glmark2. Графические процессоры Mali используют немного разные кодировки для операций с фрагментами и вершинными текстурами, поскольку фрагментные шейдеры могут автоматически вычислять параметр уровня детализации на основе соседних фрагментов, в то время как в вершинных шейдерах нет понятия соседних фрагментов.
Наконец, я добавил начальную поддержку потока управления (ветвление) для операторов if/else и циклов. Так как Bifrost - это архитектура Single Instruction, Multiple Thread (SIMT), в которой несколько потоков выполняют один и тот же шейдер в синхронном режиме, ветвление является сложным делом, если потоки расходятся. Большая часть сложностей решается аппаратно, но и этого достаточно, чтобы реализация ветвления оказалась на несколько порядков сложнее, чем в Midgard. Тем не менее, этого достаточно для сцены цикла glmark2, и всегда есть место для улучшения.
Более простой IR
Конечно, прогресс Бифроста не является препятствием для улучшения нашей поддержки Мидгарда. Вдохновленный уроками, полученными при разработке промежуточного представления Bifrost, о чем я писал ранее в блоге, я пересмотрел и наше промежуточное представление Midgard. Основное внимание было сосредоточено на двух аспектах:
Упростить, чтобы обеспечить более быструю и эффективную оптимизацию в меньшем количестве строк кода.
Обобщить IR для поддержки не-32-битных операций.
Для этого я реализовал общие помощники для вывода модификаторов инструкций, таких как насыщенность. Рассмотрим шейдер, который возводит переменную в квадрат и насыщает ее в диапазоне [0, 1].
X = clamp(X * X, 0.0, 1.0);
В NIR, общем промежуточном представлении Mesa, используемом во всех драйверах, эта строка может выглядеть следующим образом, используя опкод fsat NIR для зажима в [0, 1]:
ssa_10 = fmul ssa_9, ssa_9
ssa_11 = fsat ssa_10
Наше оборудование имеет встроенную поддержку для насыщения результатов инструкций с плавающей точкой. Есть несколько подходов, чтобы воспользоваться этим. Один из них - использовать встроенную обработку насыщения в NIR, как это делал компилятор Midgard. При проходе NIR инструкция fsat может быть включена в умножение, создавая NIR:
ssa_10 = fmul.sat ssa_9, ssa_9
Затем наш внутренний компилятор может напрямую использовать флаг .sat. Хотя это простой подход, он негибкий, поскольку аппаратное обеспечение может использовать модификаторы, которые NIR не выражает. Например, в графических процессорах Mali есть операция .clamp_positive, которая бесплатно выполняет max(x, 0.0) над результатом. Если бы мы написали X = max(X * X, 0.0), NIR мог бы дать нам код с использованием специальной инструкции fclamp_positive:
ssa_10 = fmul ssa_9, ssa_9
ssa_11 = fclamp_positive ssa_10
Однако, он не смог бы встроить модификатор без существенных изменений, затрагивающих общий код. Второй подход заключается в том, чтобы скомпилировать это в две инструкции в IR и использовать второй проход распространения в нашем внутреннем IR для их объединения.
10 = fmul 9, 9 10 = fmul.pos 9, 9
11 = fclamp_positive ssa_10
Однако есть и третий вариант, объединяющий оба случая и упрощающий работу компилятора: вывод модификаторов в общем виде при трансляции NIR в наш backend IR. Это позволяет нам использовать специфичные для архитектуры модификаторы, например .pos, при этом исходный NIR остается доступным для эффективной работы. Такой подход позволил нам заменить сотни строк оптимизаций для модификаторов с плавающей точкой и побитовых инверсий, одновременно оптимизируя новые паттерны, которые оригинальный дизайн не мог оптимизировать, что обещает экономию в сложности кода и повышение производительности. Поскольку этот подход является универсальным, он позволяет нам оптимизировать не только программы Midgard, но и модификаторы Bifrost.
Midgard FP16
С помощью более простого компилятора я смог добавить в компилятор Midgard поддержку 16-битных вычислений, чтобы уменьшить давление на регистры и улучшить количество потоков (заполняемость) благодаря механизму разделения регистров архитектуры. Как уже писалось в блоге, наш компилятор Bifrost создан для поддержки этого с первого дня, и благодаря полученным там урокам я смог перенести улучшения в Midgard.
Для подготовки я добавил типы в IR, чтобы избежать пропусков компилятора, требующих вывода типов, что является сложным и чреватым ошибками процессом. Как только размеры типов были сохранены в чистом виде, я добавил дополнительную поддержку в упаковочные процедуры компилятора Midgard, чтобы обработать некоторые нерешенные детали 16-битных инструкций. Midgard значительно проще упаковывать, чем Bifrost; в то время как 16-битные и 32-битные инструкции в Bifrost включают отдельные инструкции с резко различающимися опкодами и форматами, Midgard имеет единый подход, который - несмотря на присущие ему ограничения - освежает. Потребовались различные исправления в компиляторе; тем не менее, упрощенный IR оправдал свой дизайн и теперь способен поддерживать 16-битные операции.
Большая часть кода, необходимого для FP16, теперь находится в Mesa, но по умолчанию отключена в ожидании дальнейшего тестирования. Тем не менее, для самых смелых вы можете установить PAN_MESA_DEBUG=fp16 в последней сборке master. Остерегайтесь: здесь водятся драконы.
Цветовые маски
Если отойти от компилятора, то интересным улучшением является новая обработка отрисовки с цветовой маской. Типичный рисунок в OpenGL, который не использует смешивание или цветовые маски, может выглядеть следующим образом:
glColorMask(true, true, true, true, true);
glDepthMask(true);
glDrawArrays(GL_TRIANGLES, 0, 15);
Поскольку смешивание отключено и все цветовые каналы (RGBA) записываются одновременно, этому рисунку не нужно читать из буфера цвета (tilebuffer). Но что если при рисовании не записывать ни в один цветовой канал?
glColorMask(false, false, false, false, false);
glDepthMask(true);
glDrawArrays(GL_TRIANGLES, 0, 15);
Наивно полагать, что графический процессор должен был бы прочитать предыдущий цвет и сразу же записать его обратно - но это расточительно. Вместо этого мы можем определить случай, когда цвет не записывается, и отказаться от любого доступа к буферу цветов, пропуская и чтение, и запись.
Можем ли мы полностью пропустить рисование? Если нет побочных эффектов, то можно, но обычно приложения маскируют цвет, одновременно размаскируя буфер глубины, который не зависит от вычисления цвета. У Midgard есть решение.
Даже если требуется обновление глубины/трафарета, пока шейдер вычисляет только цвет без побочных эффектов, нет причин запускать шейдер. В то время как Bifrost этого не делает, Midgard позволяет драйверу указать отрисовку без шейдера, экономя не только чтение/запись буфера цвета, но и выполнение шейдера.
Вклад сообщества
В дополнение к нашей работе над производительностью Midgard, хакер сообщества Panfrost Icecream95 непрерывно улучшает стек Midgard.
Со времени нашего последнего сообщения в блоге они внесли значительный вклад в исправление ошибки, связанной с обработкой инструкций отбрасывания. Для справки, концептуально OpenGL сначала запускает фрагментный шейдер для каждого пикселя на экране, а затем выполняет тестирование глубины. На практике современное оборудование пытается выполнить тестирование глубины до запуска шейдера, известное как "раннее z" тестирование, чтобы избежать ненужного выполнения шейдера для окклюдированных пикселей.
Однако в играх используется директива OpenGL discard, позволяющая шейдерам удалять фрагменты, которые могут мешать оптимизации типа early-z. Драйвер отвечает за обнаружение таких ситуаций, отключение этих оптимизаций и включение соответствующих стандартам путей возврата, включая тестирование "late-z". После того, как Icecream95 исследовал проблемы с обработкой Panfrost тестирования глубины в присутствии инструкций отбрасывания, они смогли исправить ошибки рендеринга во многих играх, включая SuperTuxKart, OpenMW и RVGL.
Что касается производительности, то в прошлом они значительно оптимизировали процедуры черепичной обработки Panfrost и вычисления min/max индексов Mesa, а также добавили поддержку текстур со сжатием ASTC и ETC.
Некоторые скриншоты игр на Panfrost (Mali T760), улучшенных патчами Icecream95:
Снимаем шляпу перед участником сообщества!
Счетчики производительности
Последняя область, над которой мы работаем, - это передача счетчиков производительности Mali в пользовательское пространство в Panfrost, что позволяет нам выявлять узкие места в драйвере, а другим разработчикам - выявлять узкие места в своих приложениях, работающих на Panfrost. Около года у нас была экспериментальная поддержка передачи необработанных счетчиков из пространства ядра. Коллаборационисты Антонио Каджиано и Рохан Гарг, совместно с Icecream95 и другими соавторами, работали над интеграцией этих счетчиков в Perfetto, чтобы обеспечить высокоуровневый анализ с элегантным пользовательским интерфейсом свободного программного обеспечения.
Perfetto с Panfrost на Mali T760
Заглядывая в будущее
За прошедшие 3 месяца с начала работы над Bifrost мы с коллегой Томей Визозо прошли путь от пробного использования нового компилятора и потока команд в марте до запуска реальных программ к маю. Благодаря усилиям по реинжинирингу в тандеме с сообществом свободного программного обеспечения мы уверены, что в борьбе с проприетарными блобами и последующими хаками программное обеспечение с открытым исходным кодом одержит верх.
Заглядывая в будущее, мы планируем улучшить охват Bifrost в OpenGL ES 2.0, чтобы поддерживать больше 3D-игр, теперь, когда базовый ускоренный рабочий стол работает. Мы также планируем улучшить производительность компилятора Bifrost, чтобы приблизиться к производительности проприетарного стека, как мы это сделали для Midgard. Больше всего нам хотелось бы создать сообщество вокруг драйвера, основными ценностями которого будут свобода программного обеспечения и открытый подход.
Это сработало для Freedreno, Etnaviv и Lima. Это сработало для Panfrost на Мидгарде. И я уверен, что это снова сработает на Бифросте.
Счастливого взлома.
Хотите больше полезных советов? Смотрите и подписывайтесь на наш канал! Здесь я публикую лучшие советы для пользователей Андроид, Windows, iOS и Mac OS. Также вы можете задать мне любой вопрос, подписавшись на канал.