Vulkan и низкоуровневая графика на C++
Что такое Vulkan
Vulkan — кроссплатформенный низкоуровневый API к GPU от Khronos Group. Он описывает, как CPU ставит работу GPU в очередь — буферы, изображения, шейдеры, синхронизация, показ кадра в окне. Vulkan не рисует треугольник одной функцией — вы явно создаёте десятки объектов до первого кадра.
Для C++ Vulkan естественен — тонкий C-интерфейс, явное владение ресурсами, минимум скрытой логики в драйвере. Хорошо сочетается с RAII (Идиомы, Память).
Обзор игрового контекста — Разработка игр. Vulkan в индустрии — /encyclopedia/9-spinoff/9-04-razrabotka-igr/114.
Карта 2D/3D-стека в разделе C++
| Уровень | Инструменты | Статьи |
|---|---|---|
| 2D, учебные игры | SFML, SDL, Raylib | SFML — 2D-графика и мультимедиа на C++, SDL — мультимедиа и окна на C++, Raylib — быстрые 2D/3D прототипы на C++ |
| 2D/3D "из коробки" | Siv3D, Raylib | Siv3D — 2D/3D и мультимедиа на C++, Raylib — быстрые 2D/3D прототипы на C++ |
| 3D API | OpenGL, DirectX, Vulkan | OpenGL — 3D-графика на C++, DirectX — графика и мультимедиа на Windows, эта статья |
| Desktop UI | Qt | Qt - кроссплатформенный фреймворк на C++ |
Vulkan — нижний слой: окно даёт SDL или GLFW, рендер — ваш код и шейдеры SPIR-V.
Ключевые понятия
| Термин | Определение |
|---|---|
| Instance | Точка входа в Vulkan; версии API, validation layers |
| Physical / Logical device | Видеокарта и ваш "хэндл" к ней с очередями |
| Queue | Очередь команд GPU (graphics, compute, transfer) |
| Swapchain | Набор изображений для double/triple buffering |
| Render pass | Описание этапов рендера и layout вложений |
| Pipeline | Шейдеры + фиксированные настройки растеризации |
| Command buffer | Записанная последовательность команд GPU |
| Semaphore / Fence | Синхронизация GPU↔GPU и CPU↔GPU |
| SPIR-V | Бинарный формат шейдеров для Vulkan |
Сравнение с OpenGL (выше уровень абстракции) и DirectX 12 (похожая философия на Windows).
Первая цель на Vulkan
Опорная мысль: Vulkan — явное описание работы GPU, а не один вызов "нарисуй".
Минимум на старте:
- Окно (GLFW/SDL) и VkSurface.
- Swapchain и очистка экрана цветом.
- Цикл кадров без ошибок validation layers.
После этого — вершины, индексы, uniform buffer с MVP (OpenGL и шейдеры — та же математика).
Практика с критериями — Практические задания, блок "Графика".
Vulkan и OpenGL — зачем менять API
| Критерий | OpenGL | Vulkan |
|---|---|---|
| Состояние GPU | Часто неявное; драйвер "догадывается" | Явное; задаёте вы |
| Потоки | Один контекст на поток — неудобно | Несколько очередей, параллельная запись команд |
| CPU overhead | Выше на типичных сценах | Ниже при правильной архитектуре |
| Первый треугольник | Быстрее | Дольше (больше объектов) |
| macOS | Deprecated → Metal | MoltenVK (Vulkan поверх Metal) |
Vulkan не заменяет движок (Unreal, Godot). Он нужен, когда вы пишете свой рендер, инструмент визуализации, эмулятор GPU или учебный проект "как устроен кадр изнутри".
Для 2D-игры достаточно Raylib или SFML.
Модель объектов Vulkan
Типичная инициализация — цепочка зависимостей:
Разбор объектов
- Instance — глобальный контекст API; здесь включают validation layers для отладки.
- Physical device — конкретная видеокарта; у неё семейства очередей (graphics, present, transfer).
- Logical device — интерфейс приложения к GPU; из него берут
vkQueueSubmit,vkQueuePresent. - Surface — связь с HWND / Wayland / Android; без surface нет swapchain. Создают через GLFW, SDL (SDL — мультимедиа и окна на C++) или native API.
- Swapchain — 2–3 изображения; рисуете в один буфер, экран показывает другой (double buffering).
- Render pass — какие attachment (color, depth), какие layout памяти GPU между этапами.
- Pipeline — vertex/fragment shader + rasterization, blend, depth test. Смена pipeline дорогая — сортируют draw calls по state.
- Command buffers — записанные команды:
vkCmdBeginRenderPass→ draw →vkCmdEndRenderPass.
Один кадр рендеринга
Упрощённый порядок каждой итерации игрового цикла:
- Дождаться fence — GPU закончил прошлый кадр.
acquireNextImage— индекс следующего изображения swapchain.- Записать command buffer (или переиспользовать) — clear, draw, memory barriers.
- Submit в graphics queue с semaphore.
- Present — показ на экран, согласование semaphores с present queue.
Синхронизация — отдельная дисциплина. Гонки CPU/GPU дают артефакты или ошибки validation. В debug всегда включайте VK_LAYER_KHRONOS_validation — слой объясняет забытые барьеры и layout.
Многопоточная запись command buffers — Особенности языка / потоки.
Шейдеры и SPIR-V
Исходники — GLSL или HLSL; компилятор (glslang, DXC) → SPIR-V (.spv). В C++ загружают бинарник в VkShaderModule.
Роли:
- Vertex shader — позиции, UV, нормали;
- Fragment shader — цвет пикселя;
- Descriptor sets — uniform buffer (MVP), текстуры, samplers.
Дескрипторы типизированы через descriptor set layout — аналог "слота текстуры N" в старых API, но строже.
Теория шейдеров — OpenGL и шейдеры. HLSL в экосистеме Microsoft — DirectX.
Память на GPU
VkBuffer и VkImage живут в device memory. Типы:
- host-visible — CPU может
mapи писать (staging); - device-local — быстрый доступ GPU (статическая геометрия).
Паттерны:
- статика — upload через staging buffer →
vkCmdCopyBuffer→ device-local; - динамика — ring buffer в host-visible с аккуратными барьерами.
Утечки vkDestroy* и descriptor pools так же опасны, как new без delete — Память.
VMA (Vulkan Memory Allocator) упрощает аллокации в реальных проектах.
C++ вокруг Vulkan
Официальный API — C. В C++ проектах:
- Vulkan-Hpp — типобезопасные хэндлы, optional, RAII-обёртки;
- volk — динамическая загрузка
vkGetInstanceProcAddr; - VMA — аллокатор памяти.
Минимальный стек: CMake + GLFW + Vulkan SDK + validation layers.
cmake_minimum_required(VERSION 3.16)
project(vulkan_triangle CXX)
set(CMAKE_CXX_STANDARD 17)
find_package(Vulkan REQUIRED)
find_package(glfw3 REQUIRED)
add_executable(triangle main.cpp)
target_link_libraries(triangle PRIVATE Vulkan::Vulkan glfw)
VULKAN_SDK— переменная окружения к установленному SDK (LunarG).find_package(Vulkan)— импорт targetVulkan::Vulkanв CMake 3.7+.
Сборка — Конфигурация и сборка в C++, CMake — первая программа.
Когда Vulkan избыточен
- 2D-игра или UI — SDL, SFML, Raylib, Qt Quick;
- коммерческий 3D — Unreal / Unity;
- научная визуализация — иногда хватает OpenGL.
Vulkan оправдан при жёстком FPS, multithreaded recording, custom deferred/hybrid pipeline или обучении архитектуре GPU.
Частые ошибки новичка
| Симптом | Причина | Что сделать |
|---|---|---|
| Чёрный экран | пустой command buffer / неверный viewport | begin/end render pass, scissor |
| Артефакты | неверные barriers / layout | validation layers, править по одному |
| Зависания | fence/semaphore out of order | "1 кадр в полёте", потом масштабировать |
| Просадки FPS | пересоздание pipeline каждый кадр | кэш PSO, batching |
Связь с другими темами C++
- RAII и дескрипторы — Идиомы
- Сборка — Конфигурация и сборка в C++, CMake — первая программа
- Потоки — Особенности и расширения языка C++
- Практика — Практические задания по C++
- Соседние API — OpenGL, DirectX, SDL + surface
- 2D-стек — SFML — 2D-графика и мультимедиа на C++, Raylib — быстрые 2D/3D прототипы на C++, Siv3D — 2D/3D и мультимедиа на C++