ПрограммированиеСтатьиГрафика

Маленькая статья про Vulkan

Автор:

Это небольшая статья для тех, кто хочет разобраться в основных концепциях нового графического API и его отличиях от предыдущего поколения. Я буду говорить о Vulkan vs OpenGL, но многие вещи можно применить и к другим API нового и старого поколений.

Command Buffers
Graphics Pipeline
Renderpass
Синхронизация
Управление памятью

Command Buffers

Самое главное отличие Vulkan от OpenGL — явная асинхронность работы с GPU. Если в OpenGL драйвер сам решал, когда начинать нагружать видеокарту, то здесь это делает явно само приложение. Когда вы хотите нарисовать треугольник, запустить вычислительный шейдер, скопировать данные в память устройства вам нужно записать command buffer и отправить его в очередь на исполнение. Командные буферы можно использовать повторно, запускать из них вторичные буферы, собирать в цепочки с помощью семафоров. Тут есть достаточно широкий простор для оптимизации рендера.

Graphics Pipeline

Графический конвейер — центральная часть 3D API. Сама структура конвейера не изменилась — те же шейдерные стадии, тесты глубины, параметры блендинга и так далее. Но если в OpenGL параметры пайплайна — глобальная машина состояний, которую нужно настраивать под каждый вызов отрисовки, то в Vulkan он выделен в отдельный объект. Сначала вы создаёте pipeline-объекты, а потом в буфере команд просто устанавливаете нужный, подключаете descriptor sets с ресурсами (UBO, SSBO, текстурами, семплерами), атрибуты вершин и рисуете. Основная задача такого подхода — локализовать очень затратную операцию создания пайплайна на стадии инициализации, и в дальнейшем быстро переключаться между готовыми к применению наборами параметров. Это намного эффективнее ситуации в OpenGL, когда драйвер каждый кадр вынужден много раз проверять корректность запросов приложения. Также в API есть возможность наследования и pipeline cache, которые позволяют ускорять создание конвейера за счет переиспользования уже имеющихся или сохранённых в предыдущей сессии пайплайнов. 

Renderpass

В Vulkan есть еще один связанный с графикой объект, о котором нужно упомянуть, и который отличает его от других nextgen API — это renderpass. Изначально он был добавлен для облегчения жизни на мобильных тайловых GPU, в которых для всех draw call-ов сначала отрабатывает вершинная часть конвейера, а затем для каждого тайла фреймбуфера фрагментный конвейер для полигонов, попавших в тайл. Рендерпасс позволяет явно группировать вызовы отрисовки, которые должны обрабатываться вместе, в отдельные сабпассы. Это не актуально на десктопном железе, но, как пишут AMD, с помощью renderpass здесь тоже можно применить некоторые оптимизации. Кроме этого рендерпассы выполняют еще несколько полезных функций — управление текстурами фреймбуфера (очистка, смена image layout), синхронизация сабпассов, резолв мультисемплинга.

Синхронизация

В силу асинхронной природы работы GPU в Vulkan не гарантируется последовательное выполнение даже для команд в одном буфере, не говоря уже о разных буферах и разных очередях, поэтому все зависимости должны указываться приложением явно. Кроме прописывания зависимостей в рендерпассе есть еще четыре механизма синхронизации – semaphore, fence, event, pipeline barrier. Семафоры — самый часто используемый механизм. Сигнализируют о том, что буфер команд завершил работу и разрешают следующему буферу продолжить выполнение. Для уведомления программы о том же событии используются fences. Events — тонкий инструмент для синхронизации конкретного места в command buffer. Могут и ожидаться и устанавливаться/сбрасываться как в буфере, так и на хосте. Барьер синхронизирует последующие команды буфера с предыдущими.

Управление памятью

Тема, которая многих пугает — ручное управление памятью на устройстве. В Vulkan вы сначала создаёте буфер или текстуру, а потом назначаете для них область памяти с параметрами размера и выравнивания, получеными из функции
vkGetBufferMemoryRequirements или
vkGetImageMemoryRequirements.

Можно не заморачиваться и просто передавать эти параметры в функцию аллокации, а можно при желании выделить большой кусок памяти сразу и утрамбовывать туда свои данные самым эффективным способом. Это единственное место, в котором участвуют указатели в памяти устройства – дальше вся работа ведётся с хендлами текстур и буферов.

Это все основные моменты. Что-то осталось за кадром (вроде устройств, очередей, слоёв, расширений, многопоточности, SPIR-V шейдеров), но это сервисные вещи, о которых можно почитать в туториалах.

Заключение

Несмотря на то, что Vulkan считается более сложным по сравнению с OpenGL (и это конечно так хотя бы из-за введения нескольких новых концепций), в целом это достаточно удобный API с небольшим количеством логично связанных сущностей. Пользоваться им намного приятней, чем немного хаотичным OpenGL.

Куда копать дальше.

Vulkan API «Hello Triangle»
Следующая статья об основах использования Vulkan на примере создания простого приложения.

Vulkan in 30 minutes
Краткий обзор функций API.

LunarG Vulkan SDK
Маст хев для разработки, в комплекте неплохие примеры кода на каждую фичу.

#Vulkan

1 сентября 2016 (Обновление: 28 фев 2019)

Комментарии [13]