Vulkan API — урок 2. Беглый обзор

Vulkan API — с чего начать изучение?

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

В предыдущем уроке бы запустили несколько строк совершенно не понятного кода, который просто создал окно и загрузил нам одно ядро на все 100 (если кто обратил на это внимание). Теперь же давайте разбираться какие операторы и методы на понадобятся при разработке. Ну что же по порядку:

Шаг 1

VkInstance — через эту штуки все начинается, она создаст нам экземпляр класса. Экземпляр создается путем описания приложения и любых API расширений, которые вы будете использовать.

Далее используем VkPhysicalDevice для выбора одного или нескольких физических устройств,  которые и будут на нас работать. В списке соответственно будут только устройства поддерживающие Vulkan. При помощи данного метода можно так же узнать параметры устройства, на подобии размера VRAM, или предпочтительного устройства, ну и еще множество всего другого.

Шаг 2

Итак, определились с физическим устройством, теперь создадим логическое VkDevice (logical device), в котором описываются множества важных параметров, на подобии многооконного режима, 64-битного режима и т.д. Все это делается при участии VkPhysicalDeviceFeatures.

Следует так же указывать какую очередь вы хотите использовать, в них выполняется большинство операций Vulkan(команды отрисовки и операции с памятью). Для передачи операции на выполнение имеется VkQueue. Очереди делятся на «Семьи» (в других переводах может встретиться другое слово, но смысл думаю вы уловили), каждая семья поддерживает определенный набор операций в своих очередях, как то работа с графикой, вычислениями, памятью. Так же очереди могут использоваться для отделения одного физического устройства от другого, что может оказаться полезным в тех случаях, когда, допустим, одно из устройств несколько устарело и не поддерживает ряд функций Vulkan’a.

Шаг 3

Теперь об окнах. Это все вам не понадобится, если вы интересуетесь закадровым рендерингом, но навряли тут такие собрались, как мне кажется. Для создания окна можно использовать программные интерфейсы платформы или библиотеки, GLFW и SDL к примеру. Как вы уже наверно догадались из предыдущего урока — мы будем использовать GLFW. Нам так же понадобится еще два элемента поверхность (VkSurfaceKHR) и цепочка свопинга (VkSwapChainKHR). Обратите внимание на суффикс KHR, он означает, что эти объекты являются частью расширения Вулкана. Как таковой Vulkan API полностью зависит от платформы, поэтому мы должны использовать стандартизированный WSI (Window System Interface) для взаимодействия с менеджером окон. Поверхность Vulkan’a создается поверх этого окна, GLFW все необходимые операции сделает за нас.

Шаг 4

VkImageView and VkFramebuffer будут использованы для «обертки» (по русски может быть было бы и приятнее использовать слово «Занести» или «Записать», но в оригинале используется слово «wrap» — заворачивать, обертывать. Потому в переводе буду использовать оригинальное значение, когда вы столкнетесь с литературой на английском языке — будет проще понимать, не нужно будет перестраиваться) изображения из цепочки свопинга и дальнейшей отрисовки.

Шаг 5

Рендеринга прохода (проход визуализации) в Vulkan’e описывает тип изображения, которое будет использовано операциями рендеринга, как они будут использоваться и как их нужно обрабатывать.

Шаг 6

VkPipeline создает графический конвейер. Он описывает конфигурируемое состояние видеокарты (размер окна просмотра, глубину буфера операций, программируемое состояние используемых объектов VkShaderModule (которые создаются из байт-кода шейдера))

Одним из наиболее отличительных элементов Vulkan API является то, что почти все настройки графического конвейера должны быть установлены заранее. Это значит, что если вам понадобится переключиться на другой шейдер или немного поменять макет вершины, вам понадобится полностю пересобирать графический конвейер. Потому придется создавать по отдельному объекту VkPipeline для каждой возможной комбинации и ситуёвины. Только лишь самый базовые операции, на подобии изменения размер окна просмотра или очистки цвета, могут быть изменены динамически. Все параметры должны быть указаны в явном виде, нет никаких «цветов накладываемых по умолчанию», и иного подобного. Но эта схема таит ряд преимуществ, ведь вы все делает заранее, а не по факту. Все это увеличивает производительность, больше возможностей для оптимизации драйверов и сред, а так же в системе больше не будет висеть такое количество фоновых процессов, страждущих помочь разработчику и исправить его ошибки, даже когда он их не делал.

Шаг 7

Как уже говорилось ранее — большинство операций в Vulkan’e должны быть поставлены в очередь. Эти операции сначала должны быть добавлены в VkCommandBuffer,причем до того, как они могут быть представлены. Эти буферы ассигнуются из VkCommandPool, который в свою очередь связан с одной из семей очередей. Для отрисовки простого треугольника потребуется:

  • начать рендеринга прохода;
  • привязать графический конвейер;
  • нарисовать 3 вершины;
  • завершение рендеринга прохода;

Поскольку изображение в буфере кадров зависит от того, какие конкретно изображения предоставляет нам цепочка свопинга, нам необходимо записать команду для каждого возможного изображения и выбирать конкретный уже в момент отрисовки. Альтернативой будет запись команд в буфер каждый раз отдельно, но это далеко не столь эффективно.

Шаг 8

Когда команды рисования были завернуты в командный буфер, основной цикл становится достаточно прост:

  1. Получить изображение из цепочки свопинга (vkAcquireNextImageKHR).
  2. Можем выбрать соответствующий командый буфер для этого изображения и выполнить его при помощи vkQueueSubmit.
  3. Возвращаем изображение в цепочку свопинга для вывода на экран, используя vkQueuePresentKHR.

При этом стоит не забывать о асинхронности работы Vulkan’a. Так же возможна ситуация, когда начнет рендериться изображение, которое еще читается для вывода на экран. Так что всегда стоит пользоваться механизмы синхронизации, на подобии семафоров.

Итог

Да, на первый взгляд все может показаться достаточно сложно, но это лишь на первый взгляд. Порог вхождения у Вулкана достаточно высок, но вы легво вольетесь за месяц и далее все пойдет гораздо проще. И самое главное помните, у подобных программ порог вхождения выше, но и скорость разработки и производительность так же будут куда как лучше в итоге, такое ПО сделает из вас специалистов. 😉

Итак, что  на понадобится для рисования простейшего треугольника:

  • Создать VkInstance
  • выбрать видеокарту (VkPhysicalDevice)
  • Создать VkDevice и VkQueue для отрисовки и представления
  • Создать окно, поверхность и цепочку свопинга
  • Обернуть изображение из цепочку свопинга в VkImageView
  • Создать рендеринг прохода указывающий цели визуализации и использования
  • Создание буфера кадров для рендеринга прохода
  • Настроить графический конвейер
  • Асигнировать и записать командный буфер с помощью команд отрисовки для каждой возможного изображения цепочки свопинга
  • Отрисовка кадров путем получения изображения, предоставляя возможность поработать командному буферу и в конце возвращаем изображение обратно в цепочку свопинга

Ждите продолжения завтра!

Main Admin

3 Comments

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *