Как и в OpenGL, буферы Vulkan API различаются по назначению. Необходимый нам буфер вершин создается с параметром usage = VkBufferUsageFlagBits::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT.
Сами буферы не являются форматированными (в отличии от изображений), что позволяет нам заполнять их как только нам вздумается.
Важным пунктом является то, что сам буфер не является памятью, но определяет области доступные для чтения/записи.
Память
Память в Vulkan API является отдельной сущностью, независимой от буферов и изображений. Как и буферы команд, мы можем только выделить ее из физического устройства:
Тут есть один трудный момент, который скрывался от большинства разработчиков до этого времени. На самом деле даже одна видеокарта может располагать разными участками память с разным предназначением. Так, например, устройство может иметь кучу памяти видимой внутри устройства, но невидимой снаружи и совсем мало для доступа извне.
Такие ограничения хотя и понятны, но тем не менее вносят долю сложности в разработку: нам придется выбирать из доступных типов памяти пригодный для наших нужд.
Сами буферы тоже имеют ограничения на используемую память. Мы можем узнать о них, вызвав:
Процессом вывода примитивов занимаются шейдерные модули. Группа таких модулей объединяется в конвейер, который определяет все этапы и тонкости рисования, но об этом чуть позже.
Создаются шейдеры, по заранее подготовленному исходному коду на шейдерном языке SPIR-V. Последний является промежуточным языком, а потому, в отличии от OpenGL, трансляция теперь становится заботой разработчика. Тем не менее, в состав «LunarG Vulkan SDK» также входит транслятор GLSL->SPIR-V, с помощью которого мы и будем создавать шейдеры для Vulkan.
План:
• Создать вершинный и фрагментный шейдеры на GLSL
• Перевести их в SPIR-V
• Создать из исходного кода шейдерные модули
Исходный код
Каждый шейдер отвечает за отдельную стадию графического конвейера: вершинную, контроля тесселляции, оценки тесселляции, геометрическую или фрагментную. Нам потребуются лишь две стадии: вершинная и фрагментная. Для хранения исходного кода создадим два файла в папке с проектом: 1.vert и 1.frag, и наполним их содержимым:
1.vert:
Как и всегда, упустим объяснение касающиеся GLSL, т.к. это предмет отдельной статьи.
Для перевода исходного кода из GLSL в SPIR-V мы будем использовать утилиту glslangValidator.exe, поставляемую вместе с «LunarG Vulkan SDK» и находящуюся в папке Bin/Bin32. Но есть один нюанс...
Т.к. во время дебага нам придется менять код шейдеров довольно часто, мы создадим batник, который будет транслировать все файлы в папке на SPIR-V:
@echo off
cd %CD%
for %%i in (*.vert) do glslangValidator.exe %%i -V -o %%i.spv
for %%i in (*.frag) do glslangValidator.exe %%i -V -o %%i.spv
pause
И опять таки обойдемся без объяснений вышеперечисленных команд. За нас это уже сделала сеть.
После запуска нам будут предоставлены файлы 1.vert.spv и 1.frag.spv, которые и являются нашим скомпилированными шейдерами.
Последний момент, слегка отдаленный непосредственно от Vulkan API - загрузка кода шейдера:
По аналогии с OpenGL, шейдеры в Vulkan API являются отдельными звеньями, которые могут использоваться в разных конфигурациях в зависимости от задачи.
Создается шейдерный модуль с помощью: