Графический API, который почти исчез: эксперимент Vulkan без дескрипторов и байндингов
NoGraphicsAPI — прототип на Vulkan 1.4, проверяющий идею Себастьяна Аалтонена: что останется от графического API, если убрать дескрипторные наборы и раздельные привязки ресурсов.
Есть особый жанр программистских проектов — не библиотека для продакшена, а мысленный эксперимент, доведённый до работающего кода. NoGraphicsAPI Себбьи (sebbbi, он же Себастьян Аалтонен) относится именно к этому жанру. Это реализация идей из его блог-поста и доклада на SIGGRAPH под названием "No Graphics API" — попытка понять, сколько от привычного графического API останется, если убрать почти всё, что мы привыкли считать обязательным.
Отправная точка проста и радикальна: что если шейдеры работают напрямую с 64-битными GPU-указателями, дескрипторы текстур и семплеров живут в памяти, которой владеет само приложение, а синхронизация описывает не состояния ресурсов, а хазарды — то есть конкретные конфликты доступа к памяти и исполнению. Звучит как список ограничений, но по факту это список удалений: исчезают буферные объекты, дескрипторные наборы, layout-ы дескрипторов, layout-ы пайплайнов, объекты семплеров как публичные сущности API.
Как это устроено на практике
В README подробно расписано, как каждая идея блога легла на Vulkan 1.4. GPU-указатели заменяют буферные объекты и байндинги: функция create_gpu_heap() возвращает сырой аллокейшн с GPU-адресом и, если память замаплена, ещё и CPU-адресом. Команды, работающие по адресам, принимают GpuRange {gpu, size} напрямую, а шейдеры следуют типизированным 64-битным указателям — что при выборке вершин, что при работе с произвольными структурами данных.
Приложения сами владеют кучами дескрипторов. Кучи для текстур и семплеров — это замапленные GPU-кучи: приложение само выбирает слоты, записывает дескрипторы через CPU-адрес, привязывает GPU-диапазон и передаёт в шейдеры уже 32-битные индексы. Это переворачивает привычную модель, где драйвер и рантайм API управляют жизненным циклом дескрипторных наборов, — здесь этим занимается сама программа.
Корневые данные сведены к одному небольшому пейлоаду: общая структура на C++/Slang копируется через vkCmdPushDataEXT для каждого draw или dispatch, а её поля-указатели — это GPU-адреса. Авторы честно отмечают отличие от оригинальной идеи блога: там предполагались GPU-резидентные, специфичные для каждой стадии корни, здесь же графические стадии делят один CPU-предоставленный корень — компромисс между чистотой концепции и практичностью реализации на конкретном железе.
Барьеры в этой модели описывают хазарды исполнения и памяти, а не списки переходов состояний для каждого ресурса по отдельности. Публичный API даёт только глобальные барьеры по стадиям и доступу; обычные текстуры при этом остаются в едином unified layout — ещё одно упрощение, убирающее целый класс типичных для графических API ошибок с layout-транзишенами.
В итоге состояние байндинга пайплайна становится совсем компактным: PSO содержит только шейдеры и fixed-function состояние, а данные приходят через корень и кучи дескрипторов. Отправка команд в очередь явная и асинхронная — приложения сами предоставляют временные точки (timeline points) для переиспользования ресурсов и отложенного уничтожения, а отправленные командные буферы одноразовые.
Что реально реализовано
Важная деталь: это не манифест, а работающий бэкенд. Vulkan-реализация уже существует и проверяется тремя примерами приложений. Метал-бэкенд не реализован — вместо кода в репозитории лежит документ с предложенным маппингом на дизайн Metal 4 и списком открытых вопросов, которые пока не решены. Это честная позиция: авторы не делают вид, что кроссплатформенность уже готова, а фиксируют, где именно упирается идея в особенности другого API.
Центральные для бэкенда расширения — это, в частности, VK_EXT_descriptor_heap для дескрипторных куч, которыми владеет приложение. Показательно и то, чего бэкенд намеренно не создаёт: ни VkDescriptorSetLayout, ни VkDescriptorPool, ни VkDescriptorSet, ни VkPipelineLayout — вся эта инфраструктура, обычно занимающая солидную часть кода любого современного рендерера, просто отсутствует как класс.
В репозитории отдельно есть документ, который раскладывает соответствие идей блога и их вулкановской реализации на три категории: то, что реализовано буквально, то, что изменено под влиянием особенностей Vulkan, и то, что осталось за пределами прототипа. Такая честность — редкость для экспериментальных репозиториев, где чаще либо всё называют революцией, либо не документируют вовсе.
Почему это интересно не только графическим программистам
GPU-архитектура последних лет медленно движется в сторону того, что раньше делал только драйвер: bindless-текстуры, дескрипторные буферы, явное управление памятью через указатели — всё это уже частично появлялось в разных API. NoGraphicsAPI не изобретает эти механизмы, а собирает их в единую, последовательную модель и проверяет её работоспособностью на живых примерах. Это ценно само по себе — не как готовый фреймворк, а как доказательство того, что убрать посредника между приложением и GPU можно куда дальше, чем принято думать, и код при этом продолжает работать.
Войти, чтобы оценить материал
Комментарии
Войти, чтобы оставить комментарий