aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am1
-rw-r--r--src/engine.cpp1403
-rw-r--r--src/vulkan_utils.hpp24
3 files changed, 727 insertions, 701 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index f7b34f3..ad18692 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,6 +8,7 @@ engine_SOURCES = \
engine.cpp \
renderer.hpp renderer.cpp \
obj_parser.hpp obj_parser.cpp \
+ vulkan_utils.hpp \
fb/chfb.hpp fb/chfb.cpp fb/pixfb.hpp fb/pixfb.cpp \
math/vector.hpp \
math/mat4.hpp \
diff --git a/src/engine.cpp b/src/engine.cpp
index 31f72d0..fa5814f 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -11,7 +11,6 @@
#include <utility>
#include <iterator>
#include <memory>
-#include <utility>
#include <numbers>
#include <optional>
#include <algorithm>
@@ -45,6 +44,7 @@
#include "ctrl/mouse.hpp"
#include "renderer.hpp"
#include "obj_parser.hpp"
+#include "vulkan_utils.hpp"
using
engine::Renderer,
@@ -346,37 +346,18 @@ static bool check_validation_layer_support() {
}
static std::string severity_to_str(VkDebugUtilsMessageSeverityFlagBitsEXT severity) {
- std::string s;
- bool first = true;
- if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
- if (!first)
- s += ", ";
- else
- first = false;
- s += "VERBOSE";
- }
- if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
- if (!first)
- s += ", ";
- else
- first = false;
- s += "INFO";
- }
- if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
- if (!first)
- s += ", ";
- else
- first = false;
- s += "WARNING";
- }
- if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
- if (!first)
- s += ", ";
- else
- first = false;
- s += "ERROR";
+ switch (severity) {
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
+ return "VERBOSE";
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
+ return "INFO";
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
+ return "WARNING";
+ case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
+ return "ERROR";
+ default:
+ std::unreachable();
}
- return s;
}
// TODO: remove [[maybe_unused]]
@@ -389,22 +370,22 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
return VK_FALSE;
}
-static void populate_msger_create_info(VkDebugUtilsMessengerCreateInfoEXT& msger_create_info) {
- msger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
- msger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
- | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
- | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
+static void populate_msger_ci(VkDebugUtilsMessengerCreateInfoEXT& msger_ci) {
+ msger_ci.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
+ msger_ci.messageSeverity =
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
- msger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
+ msger_ci.messageType =
+ VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
- msger_create_info.pfnUserCallback = debug_callback;
- msger_create_info.pUserData = nullptr;
+ msger_ci.pfnUserCallback = debug_callback;
+ msger_ci.pUserData = nullptr;
}
static std::tuple<std::optional<uint32_t>, std::optional<uint32_t>> find_queue_family_indices(
VkPhysicalDevice physical_device, const std::vector<VkQueueFamilyProperties2>& queue_family_properties, VkSurfaceKHR surface) {
- std::optional<uint32_t> graphics_queue_family_index, presentation_queue_family_index;
+ std::optional<uint32_t> graphics_queue_family_index, present_queue_family_index;
for (uint32_t i = 0; i < queue_family_properties.size(); i++) {
const auto& prop = queue_family_properties[i];
bool is_graphics_queue = (prop.queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) != static_cast<VkQueueFlags>(0);
@@ -415,15 +396,15 @@ static std::tuple<std::optional<uint32_t>, std::optional<uint32_t>> find_queue_f
}
if (is_graphics_queue && is_presentation_queue) {
graphics_queue_family_index = i;
- presentation_queue_family_index = i;
+ present_queue_family_index = i;
break;
} else if (is_graphics_queue && !graphics_queue_family_index) {
graphics_queue_family_index = i;
- } else if (is_presentation_queue && !presentation_queue_family_index) {
- presentation_queue_family_index = i;
+ } else if (is_presentation_queue && !present_queue_family_index) {
+ present_queue_family_index = i;
}
}
- return { graphics_queue_family_index, presentation_queue_family_index };
+ return { graphics_queue_family_index, present_queue_family_index };
}
static void transition_image_layout(VkCommandBuffer cmd_buf, VkImage img,
@@ -472,11 +453,7 @@ static int main_graphical() {
GLFWwindow* window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Engine", nullptr, nullptr);
// init Vulkan
- std::cout << "Vulkan loader version: "
- << VK_API_VERSION_MAJOR(VK_HEADER_VERSION_COMPLETE)
- << "." << VK_API_VERSION_MINOR(VK_HEADER_VERSION_COMPLETE)
- << "." << VK_API_VERSION_PATCH(VK_HEADER_VERSION_COMPLETE)
- << std::endl;
+ std::cout << "Vulkan loader version: " << engine::myvk::api { VK_HEADER_VERSION_COMPLETE } << std::endl;
// init Vulkan - create instance
if (enable_validation_layers && !check_validation_layer_support()) {
@@ -484,100 +461,102 @@ static int main_graphical() {
std::exit(EXIT_FAILURE);
}
- VkApplicationInfo app_info{};
- app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- app_info.pApplicationName = "engine - test";
- app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
- app_info.pEngineName = "engine";
- app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
- app_info.apiVersion = VK_API_VERSION_1_4;
-
- std::vector<const char*> extensions;
-
- {
- uint32_t glfw_extension_count;
- const char** glfw_extensions;
- glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
- extensions.insert(extensions.end(), glfw_extensions, glfw_extensions + glfw_extension_count);
- }
-
- if (enable_validation_layers) {
- extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
- }
+ auto instance = [&]() {
+ VkApplicationInfo app_info {
+ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+ .pNext = nullptr,
+ .pApplicationName = "engine - test",
+ .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
+ .pEngineName = "engine",
+ .engineVersion = VK_MAKE_VERSION(1, 0, 0),
+ .apiVersion = VK_API_VERSION_1_4,
+ };
- uint32_t extension_count;
- if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr); res != VK_SUCCESS) {
- std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
- std::vector<VkExtensionProperties> available_extensions(extension_count);
- if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, available_extensions.data()); res != VK_SUCCESS) {
- std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ std::vector<const char*> extensions;
- std::cout << "vulkan extensions:\n";
- for (const auto& extension : available_extensions) {
- std::cout
- << (std::ranges::find_if(extensions, [avail_ext_name=extension.extensionName](const auto& ext_name) { return strcmp(ext_name, avail_ext_name) == 0; })
- != extensions.end() ? "*" : " ");
- std::cout << " " << extension.extensionName << "\n";
- }
+ {
+ uint32_t glfw_extension_count;
+ const char** glfw_extensions;
+ glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
+ extensions.insert(extensions.end(), glfw_extensions, glfw_extensions + glfw_extension_count);
+ }
- std::cout << "\n";
+ if (enable_validation_layers) {
+ extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+ }
- std::cout << "required extensions:\n";
- for (const auto& extension_name : extensions)
- std::cout << " " << extension_name << "\n";
+ uint32_t extension_count;
+ if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr); res != VK_SUCCESS) {
+ std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ std::vector<VkExtensionProperties> available_extensions(extension_count);
+ if (VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, available_extensions.data()); res != VK_SUCCESS) {
+ std::cerr << "failed to enumerate instance extension properties, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
- VkInstanceCreateInfo create_info{};
- create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- create_info.pApplicationInfo = &app_info;
+ std::cout << "required instance extensions:\n";
+ for (const auto& extension_name : extensions) {
+ std::cout << (std::ranges::find_if(available_extensions, [&](const auto& avail_ext) {
+ return strcmp(avail_ext.extensionName, extension_name) == 0;
+ }) == available_extensions.end() ? "!" : " ");
+ std::cout << " " << extension_name << "\n";
+ }
- create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
- create_info.ppEnabledExtensionNames = extensions.data();
+ VkInstanceCreateInfo instance_ci {
+ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .pApplicationInfo = &app_info,
+ .enabledLayerCount = {},
+ .ppEnabledLayerNames = {},
+ .enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
+ .ppEnabledExtensionNames = extensions.data(),
+ };
- VkDebugUtilsMessengerCreateInfoEXT inst_msger_create_info{};
- if (enable_validation_layers) {
- create_info.enabledLayerCount = static_cast<uint32_t>(validation_layers.size());
- create_info.ppEnabledLayerNames = validation_layers.data();
-
- populate_msger_create_info(inst_msger_create_info);
- create_info.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &inst_msger_create_info;
- } else {
- create_info.enabledLayerCount = 0;
- create_info.pNext = nullptr;
- }
+ VkDebugUtilsMessengerCreateInfoEXT inst_msger_ci{};
+ if (enable_validation_layers) {
+ populate_msger_ci(inst_msger_ci);
+ instance_ci.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &inst_msger_ci;
+ instance_ci.enabledLayerCount = static_cast<uint32_t>(validation_layers.size());
+ instance_ci.ppEnabledLayerNames = validation_layers.data();
+ }
- VkInstance instance;
- if (VkResult res = vkCreateInstance(&create_info, nullptr, &instance); res != VK_SUCCESS) {
- std::cerr << "failed to create instance, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ VkInstance instance;
+ if (VkResult res = vkCreateInstance(&instance_ci, nullptr, &instance); res != VK_SUCCESS) {
+ std::cerr << "failed to create instance, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return instance;
+ }();
VkDebugUtilsMessengerEXT debug_messenger;
if (enable_validation_layers) {
- VkDebugUtilsMessengerCreateInfoEXT msger_create_info{};
- populate_msger_create_info(msger_create_info);
+ VkDebugUtilsMessengerCreateInfoEXT msger_ci{};
+ populate_msger_ci(msger_ci);
auto create_debug_messenger = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
if (!create_debug_messenger) {
std::cerr << "failed to set up debug messenger!" << std::endl;
std::exit(EXIT_FAILURE);
}
- create_debug_messenger(instance, &msger_create_info, nullptr, &debug_messenger);
+ create_debug_messenger(instance, &msger_ci, nullptr, &debug_messenger);
}
// create window surface
- VkSurfaceKHR surface;
- if (VkResult res = glfwCreateWindowSurface(instance, window, nullptr, &surface); res != VK_SUCCESS) {
- std::cerr << "failed to create window surface, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ auto surface = [&]() {
+ VkSurfaceKHR surface;
+ if (VkResult res = glfwCreateWindowSurface(instance, window, nullptr, &surface); res != VK_SUCCESS) {
+ std::cerr << "failed to create window surface, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return surface;
+ }();
// select physical device and queues
- auto [device, graphics_queue_family_index, presentation_queue_family_index, device_features] = [instance, surface]() {
- std::optional<VkPhysicalDevice> device;
+ auto [physical_device, graphics_queue_family_index, present_queue_family_index, device_features] = [&]() {
+ std::optional<VkPhysicalDevice> physical_device;
uint32_t res_graphics_queue_family_index, res_presentation_queue_family_index;
VkPhysicalDeviceFeatures2 res_features;
@@ -586,236 +565,208 @@ static int main_graphical() {
std::cerr << "failed to enumerate physical devices, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
- std::vector<VkPhysicalDevice> physical_devices(physical_devices_count);
- if (VkResult res = vkEnumeratePhysicalDevices(instance, &physical_devices_count, physical_devices.data()); res != VK_SUCCESS) {
+ std::vector<VkPhysicalDevice> avail_physical_devices(physical_devices_count);
+ if (VkResult res = vkEnumeratePhysicalDevices(instance, &physical_devices_count, avail_physical_devices.data()); res != VK_SUCCESS) {
std::cerr << "failed to enumerate physical devices, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
- if (physical_devices.empty()) {
+ if (avail_physical_devices.empty()) {
std::cerr << "failed to find physical devices with Vulkan support" << std::endl;
std::exit(EXIT_FAILURE);
}
- for (const auto& physical_device : physical_devices) {
+ std::cout << "devices:" << std::endl;
+
+ for (const auto& avail_physical_device : avail_physical_devices) {
VkPhysicalDeviceProperties2 properties{};
properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- vkGetPhysicalDeviceProperties2(physical_device, &properties);
+ vkGetPhysicalDeviceProperties2(avail_physical_device, &properties);
+
+ std::cout << " " << properties.properties.deviceName << ":" << std::endl;
+ std::cout << " apiVersion: " << engine::myvk::api { properties.properties.apiVersion } << std::endl;
VkPhysicalDeviceFeatures2 features{};
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
- vkGetPhysicalDeviceFeatures2(physical_device, &features);
+ vkGetPhysicalDeviceFeatures2(avail_physical_device, &features);
// TODO: found a better name, too confusing with device_exts
uint32_t ext_props_count;
- if (VkResult res = vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &ext_props_count, nullptr); res != VK_SUCCESS) {
- std::cerr << "failed to enumerate device extension properties, error code: " << string_VkResult(res) << std::endl;
+ if (VkResult res = vkEnumerateDeviceExtensionProperties(avail_physical_device, nullptr, &ext_props_count, nullptr); res != VK_SUCCESS) {
+ std::cerr << "failed to enumerate physical device extension properties, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
std::vector<VkExtensionProperties> ext_props(ext_props_count);
- if (VkResult res = vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &ext_props_count, ext_props.data()); res != VK_SUCCESS) {
- std::cerr << "failed to enumerate device extension properties, error code: " << string_VkResult(res) << std::endl;
+ if (VkResult res = vkEnumerateDeviceExtensionProperties(avail_physical_device, nullptr, &ext_props_count, ext_props.data()); res != VK_SUCCESS) {
+ std::cerr << "failed to enumerate physical device extension properties, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
+ std::cout << " required physical device extensions:" << std::endl;
+ for (const auto& ext : device_exts) {
+ std::cout << " " << (std::ranges::find_if(ext_props, [&](const auto& avail_ext) {
+ return strcmp(avail_ext.extensionName, ext) == 0;
+ }) == ext_props.end() ? "!" : " ");
+ std::cout << " " << ext << std::endl;
+ }
+
uint32_t queue_family_properties_count;
- vkGetPhysicalDeviceQueueFamilyProperties2(physical_device, &queue_family_properties_count, nullptr);
+ vkGetPhysicalDeviceQueueFamilyProperties2(avail_physical_device, &queue_family_properties_count, nullptr);
std::vector<VkQueueFamilyProperties2> queue_family_properties(queue_family_properties_count);
for (auto& elt : queue_family_properties)
elt.sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2;
- vkGetPhysicalDeviceQueueFamilyProperties2(physical_device, &queue_family_properties_count, queue_family_properties.data());
-
- std::cout << "structure type: " << string_VkStructureType(properties.sType) << std::endl;
- std::cout << "pNext: " << properties.pNext << std::endl;
- std::cout << "apiVersion: (variant " << VK_API_VERSION_VARIANT(properties.properties.apiVersion) << ") "
- << VK_API_VERSION_MAJOR(properties.properties.apiVersion)
- << "." << VK_API_VERSION_MINOR(properties.properties.apiVersion)
- << "." << VK_API_VERSION_PATCH(properties.properties.apiVersion)
- << std::endl;
- std::cout << "driverVersion: " << properties.properties.driverVersion << std::endl;
- std::cout << "vendorID: " << properties.properties.vendorID << std::endl;
- std::cout << "deviceID: " << properties.properties.deviceID << std::endl;
- std::cout << "deviceType: " << string_VkPhysicalDeviceType(properties.properties.deviceType) << std::endl;
- std::cout << "deviceName: " << properties.properties.deviceName << std::endl;
- // pipelineCacheUUID[VK_UUID_SIZE]
- // limits
- std::cout << "sparseProperties:" << std::endl;
- std::cout << std::boolalpha;
- std::cout << " residencyStandard2DBlockShape: " << static_cast<bool>(properties.properties.sparseProperties.residencyStandard2DBlockShape) << std::endl;
- std::cout << " residencyStandard2DMultisampleBlockShape: "
- << static_cast<bool>(properties.properties.sparseProperties.residencyStandard2DMultisampleBlockShape) << std::endl;
- std::cout << " residencyStandard3DBlockShape: " << static_cast<bool>(properties.properties.sparseProperties.residencyStandard3DBlockShape) << std::endl;
- std::cout << " residencyAlignedMipSize: " << static_cast<bool>(properties.properties.sparseProperties.residencyAlignedMipSize) << std::endl;
- std::cout << " residencyNonResidentStrict: " << static_cast<bool>(properties.properties.sparseProperties.residencyNonResidentStrict) << std::endl;
- std::cout << std::noboolalpha;
- std::cout << "features:" << std::endl;
- std::cout << std::boolalpha;
- std::cout << " robustBufferAccess: " << static_cast<bool>(features.features.robustBufferAccess) << std::endl;
- std::cout << " fullDrawIndexUint32: " << static_cast<bool>(features.features.fullDrawIndexUint32) << std::endl;
- std::cout << " imageCubeArray: " << static_cast<bool>(features.features.imageCubeArray) << std::endl;
- std::cout << " independentBlend: " << static_cast<bool>(features.features.independentBlend) << std::endl;
- std::cout << " geometryShader: " << static_cast<bool>(features.features.geometryShader) << std::endl;
- std::cout << " tessellationShader: " << static_cast<bool>(features.features.tessellationShader) << std::endl;
- std::cout << " sampleRateShading: " << static_cast<bool>(features.features.sampleRateShading) << std::endl;
- std::cout << " dualSrcBlend: " << static_cast<bool>(features.features.dualSrcBlend) << std::endl;
- std::cout << " logicOp: " << static_cast<bool>(features.features.logicOp) << std::endl;
- std::cout << " multiDrawIndirect: " << static_cast<bool>(features.features.multiDrawIndirect) << std::endl;
- std::cout << " drawIndirectFirstInstance: " << static_cast<bool>(features.features.drawIndirectFirstInstance) << std::endl;
- std::cout << " depthClamp: " << static_cast<bool>(features.features.depthClamp) << std::endl;
- std::cout << " depthBiasClamp: " << static_cast<bool>(features.features.depthBiasClamp) << std::endl;
- std::cout << " fillModeNonSolid: " << static_cast<bool>(features.features.fillModeNonSolid) << std::endl;
- std::cout << " depthBounds: " << static_cast<bool>(features.features.depthBounds) << std::endl;
- std::cout << " wideLines: " << static_cast<bool>(features.features.wideLines) << std::endl;
- std::cout << " largePoints: " << static_cast<bool>(features.features.largePoints) << std::endl;
- std::cout << " alphaToOne: " << static_cast<bool>(features.features.alphaToOne) << std::endl;
- std::cout << " multiViewport: " << static_cast<bool>(features.features.multiViewport) << std::endl;
- std::cout << " samplerAnisotropy: " << static_cast<bool>(features.features.samplerAnisotropy) << std::endl;
- std::cout << " textureCompressionETC2: " << static_cast<bool>(features.features.textureCompressionETC2) << std::endl;
- std::cout << " textureCompressionASTC_LDR: " << static_cast<bool>(features.features.textureCompressionASTC_LDR) << std::endl;
- std::cout << " textureCompressionBC: " << static_cast<bool>(features.features.textureCompressionBC) << std::endl;
- std::cout << " occlusionQueryPrecise: " << static_cast<bool>(features.features.occlusionQueryPrecise) << std::endl;
- std::cout << " pipelineStatisticsQuery: " << static_cast<bool>(features.features.pipelineStatisticsQuery) << std::endl;
- std::cout << " vertexPipelineStoresAndAtomics: " << static_cast<bool>(features.features.vertexPipelineStoresAndAtomics) << std::endl;
- std::cout << " fragmentStoresAndAtomics: " << static_cast<bool>(features.features.fragmentStoresAndAtomics) << std::endl;
- std::cout << " shaderTessellationAndGeometryPointSize: " << static_cast<bool>(features.features.shaderTessellationAndGeometryPointSize) << std::endl;
- std::cout << " shaderImageGatherExtended: " << static_cast<bool>(features.features.shaderImageGatherExtended) << std::endl;
- std::cout << " shaderStorageImageExtendedFormats: " << static_cast<bool>(features.features.shaderStorageImageExtendedFormats) << std::endl;
- std::cout << " shaderStorageImageMultisample: " << static_cast<bool>(features.features.shaderStorageImageMultisample) << std::endl;
- std::cout << " shaderStorageImageReadWithoutFormat: " << static_cast<bool>(features.features.shaderStorageImageReadWithoutFormat) << std::endl;
- std::cout << " shaderStorageImageWriteWithoutFormat: " << static_cast<bool>(features.features.shaderStorageImageWriteWithoutFormat) << std::endl;
- std::cout << " shaderUniformBufferArrayDynamicIndexing: " << static_cast<bool>(features.features.shaderUniformBufferArrayDynamicIndexing) << std::endl;
- std::cout << " shaderSampledImageArrayDynamicIndexing: " << static_cast<bool>(features.features.shaderSampledImageArrayDynamicIndexing) << std::endl;
- std::cout << " shaderStorageBufferArrayDynamicIndexing: " << static_cast<bool>(features.features.shaderStorageBufferArrayDynamicIndexing) << std::endl;
- std::cout << " shaderStorageImageArrayDynamicIndexing: " << static_cast<bool>(features.features.shaderStorageImageArrayDynamicIndexing) << std::endl;
- std::cout << " shaderClipDistance: " << static_cast<bool>(features.features.shaderClipDistance) << std::endl;
- std::cout << " shaderCullDistance: " << static_cast<bool>(features.features.shaderCullDistance) << std::endl;
- std::cout << " shaderFloat64: " << static_cast<bool>(features.features.shaderFloat64) << std::endl;
- std::cout << " shaderInt64: " << static_cast<bool>(features.features.shaderInt64) << std::endl;
- std::cout << " shaderInt16: " << static_cast<bool>(features.features.shaderInt16) << std::endl;
- std::cout << " shaderResourceResidency: " << static_cast<bool>(features.features.shaderResourceResidency) << std::endl;
- std::cout << " shaderResourceMinLod: " << static_cast<bool>(features.features.shaderResourceMinLod) << std::endl;
- std::cout << " sparseBinding: " << static_cast<bool>(features.features.sparseBinding) << std::endl;
- std::cout << " sparseResidencyBuffer: " << static_cast<bool>(features.features.sparseResidencyBuffer) << std::endl;
- std::cout << " sparseResidencyImage2D: " << static_cast<bool>(features.features.sparseResidencyImage2D) << std::endl;
- std::cout << " sparseResidencyImage3D: " << static_cast<bool>(features.features.sparseResidencyImage3D) << std::endl;
- std::cout << " sparseResidency2Samples: " << static_cast<bool>(features.features.sparseResidency2Samples) << std::endl;
- std::cout << " sparseResidency4Samples: " << static_cast<bool>(features.features.sparseResidency4Samples) << std::endl;
- std::cout << " sparseResidency8Samples: " << static_cast<bool>(features.features.sparseResidency8Samples) << std::endl;
- std::cout << " sparseResidency16Samples: " << static_cast<bool>(features.features.sparseResidency16Samples) << std::endl;
- std::cout << " sparseResidencyAliased: " << static_cast<bool>(features.features.sparseResidencyAliased) << std::endl;
- std::cout << " variableMultisampleRate: " << static_cast<bool>(features.features.variableMultisampleRate) << std::endl;
- std::cout << " inheritedQueries: " << static_cast<bool>(features.features.inheritedQueries) << std::endl;
- std::cout << std::noboolalpha;
- std::cout << "extensions:" << std::endl;
- for (const auto& ext : ext_props) {
- std::cout
- << (std::ranges::find_if(device_exts, [ext_name=ext.extensionName](const auto& device_ext) { return strcmp(ext_name, device_ext) == 0; })
- != device_exts.end() ? "*" : " ");
- std::cout << " " << ext.extensionName << std::endl;
- }
+ vkGetPhysicalDeviceQueueFamilyProperties2(avail_physical_device, &queue_family_properties_count, queue_family_properties.data());
- auto [graphics_queue_family_index, presentation_queue_family_index] = find_queue_family_indices(physical_device, queue_family_properties, surface);
- std::cout << "graphics queue family index: ";
+ auto [graphics_queue_family_index, present_queue_family_index] = find_queue_family_indices(avail_physical_device, queue_family_properties, surface);
+ std::cout << " graphics queue family index: ";
if (graphics_queue_family_index)
std::cout << *graphics_queue_family_index;
else
std::cout << "none";
std::cout << std::endl;
- std::cout << "presentation queue family index: ";
- if (presentation_queue_family_index)
- std::cout << *presentation_queue_family_index;
+ std::cout << " presentation queue family index: ";
+ if (present_queue_family_index)
+ std::cout << *present_queue_family_index;
else
std::cout << "none";
std::cout << std::endl;
- bool is_suitable = [&properties, &queue_family_properties, &ext_props, &graphics_queue_family_index, &presentation_queue_family_index]() {
+ bool is_suitable = [&]() {
if (VK_API_VERSION_VARIANT(properties.properties.apiVersion) != 0
|| properties.properties.apiVersion < VK_API_VERSION_1_4)
return false;
- if (!graphics_queue_family_index || !presentation_queue_family_index)
+ if (!graphics_queue_family_index || !present_queue_family_index)
return false;
- if (std::ranges::find_if_not(device_exts, [&ext_props](const auto& device_ext) {
+ if (std::ranges::find_if_not(device_exts, [&](const auto& device_ext) {
return std::ranges::find_if(ext_props,
- [device_ext](const auto& ext_prop) { return strcmp(ext_prop.extensionName, device_ext) == 0; })
+ [&](const auto& ext_prop) { return strcmp(ext_prop.extensionName, device_ext) == 0; })
!= ext_props.end();
}) != device_exts.end())
return false;
return true;
}();
- std::cout << "is_suitable: " << std::boolalpha << is_suitable << std::noboolalpha;
- if (!device && is_suitable) {
+ std::cout << " is_suitable: " << std::boolalpha << is_suitable << std::noboolalpha;
+ if (!physical_device && is_suitable) {
std::cout << " (picking this one)";
- device = physical_device;
+ physical_device = avail_physical_device;
res_graphics_queue_family_index = *graphics_queue_family_index;
- res_presentation_queue_family_index = *presentation_queue_family_index;
+ res_presentation_queue_family_index = *present_queue_family_index;
res_features = features;
}
std::cout << std::endl;
}
- if (!device) {
+ std::cout << std::endl;
+
+ if (!physical_device) {
std::cerr << "no suitable physical device found" << std::endl;
std::exit(EXIT_FAILURE);
}
return std::tuple<VkPhysicalDevice, uint32_t, uint32_t, VkPhysicalDeviceFeatures2>
- { *device, res_graphics_queue_family_index, res_presentation_queue_family_index, res_features };
+ { *physical_device, res_graphics_queue_family_index, res_presentation_queue_family_index, res_features };
}();
- // TODO: We only create the graphics queue, I don't know if we have to also create the
- // presentation queue. They don't create it in the official Vulkan tutorial, but it might cause
- // a bug on some rare platforms where there is no queue that's both graphics and presentation.
- // IDK.
- float queue_priority = .5f;
- VkDeviceQueueCreateInfo deviceQueueCreateInfo{};
- deviceQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- deviceQueueCreateInfo.queueFamilyIndex = graphics_queue_family_index;
- deviceQueueCreateInfo.queueCount = 1;
- deviceQueueCreateInfo.pQueuePriorities = &queue_priority;
-
- VkDeviceCreateInfo device_create_info{};
- device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- device_create_info.queueCreateInfoCount = 1;
- device_create_info.pQueueCreateInfos = &deviceQueueCreateInfo;
- device_create_info.enabledExtensionCount = static_cast<uint32_t>(device_exts.size());
- device_create_info.ppEnabledExtensionNames = device_exts.data();
- // we get device features while selecting the physical device
- device_create_info.pNext = &device_features;
-
- VkPhysicalDeviceVulkan13Features device_vk13_features{};
- device_vk13_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
- device_vk13_features.synchronization2 = VK_TRUE;
- device_vk13_features.dynamicRendering = VK_TRUE;
- device_features.pNext = &device_vk13_features;
-
- VkPhysicalDeviceExtendedDynamicStateFeaturesEXT device_eds_features{};
- device_eds_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
- device_eds_features.extendedDynamicState = VK_TRUE;
- device_vk13_features.pNext = &device_eds_features;
-
- // TODO: rename to just "device", and rename "device" to "physical_device"
- VkDevice logical_device;
- if (VkResult res = vkCreateDevice(device, &device_create_info, nullptr, &logical_device); res != VK_SUCCESS) {
- std::cerr << "failed to create device: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ auto device = [&]() {
+ // TODO: really weird way of making a single structure if
+ // graphics_queue_family_index == present_queue_family_index
+ // here, in this cas, we create both *CreateInfo, and then tell VkDeviceCreateInfo that
+ // there is only a single element
+ std::array queue_priorities { .5f, .5f };
+ std::array device_queue_cis {
+ VkDeviceQueueCreateInfo {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .queueFamilyIndex = graphics_queue_family_index,
+ .queueCount = 1,
+ .pQueuePriorities = &queue_priorities[0],
+ },
+ VkDeviceQueueCreateInfo {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .queueFamilyIndex = present_queue_family_index,
+ .queueCount = 1,
+ .pQueuePriorities = &queue_priorities[1],
+ },
+ };
- VkQueue graphics_queue;
- vkGetDeviceQueue(logical_device, graphics_queue_family_index, 0, &graphics_queue);
+ VkPhysicalDeviceExtendedDynamicStateFeaturesEXT device_eds_features {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT,
+ .pNext = {},
+ .extendedDynamicState = VK_TRUE,
+ };
- VkQueue presentation_queue;
- vkGetDeviceQueue(logical_device, presentation_queue_family_index, 0, &presentation_queue);
+ VkPhysicalDeviceVulkan13Features device_vk13_features {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
+ .pNext = &device_eds_features,
+ .robustImageAccess = {},
+ .inlineUniformBlock = {},
+ .descriptorBindingInlineUniformBlockUpdateAfterBind = {},
+ .pipelineCreationCacheControl = {},
+ .privateData = {},
+ .shaderDemoteToHelperInvocation = {},
+ .shaderTerminateInvocation = {},
+ .subgroupSizeControl = {},
+ .computeFullSubgroups = {},
+ .synchronization2 = VK_TRUE,
+ .textureCompressionASTC_HDR = {},
+ .shaderZeroInitializeWorkgroupMemory = {},
+ .dynamicRendering = VK_TRUE,
+ .shaderIntegerDotProduct = {},
+ .maintenance4 = {},
+ };
+
+ device_features.pNext = &device_vk13_features;
+
+ VkDeviceCreateInfo device_ci {
+ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ .pNext = &device_features,
+ .flags = {},
+ .queueCreateInfoCount =
+ (graphics_queue_family_index == present_queue_family_index ? static_cast<uint32_t>(1) : static_cast<uint32_t>(2)),
+ .pQueueCreateInfos = device_queue_cis.data(),
+ .enabledLayerCount = {},
+ .ppEnabledLayerNames = {},
+ .enabledExtensionCount = static_cast<uint32_t>(device_exts.size()),
+ .ppEnabledExtensionNames = device_exts.data(),
+ .pEnabledFeatures = {},
+ };
+
+ VkDevice device;
+ if (VkResult res = vkCreateDevice(physical_device, &device_ci, nullptr, &device); res != VK_SUCCESS) {
+ std::cerr << "failed to create device: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return device;
+ }();
+
+ auto [graphics_queue, present_queue] = [&]() {
+ const auto map_family_to_queue = [&](uint32_t queue_family_index) {
+ VkQueue queue;
+ vkGetDeviceQueue(device, queue_family_index, 0, &queue);
+ return queue;
+ };
+ return std::tuple {
+ map_family_to_queue(graphics_queue_family_index),
+ map_family_to_queue(present_queue_family_index),
+ };
+ }();
// create swap chain
// TODO: should probably use version 2 of theses functions, but glfwCreateWindowSurface return
// version 1, so for now we will use version 1
- VkSurfaceCapabilitiesKHR surface_capabilities;
- if (VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &surface_capabilities); res != VK_SUCCESS) {
- std::cerr << "failed to get physical device surface capabilities, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ auto surface_capabilities = [&]() {
+ VkSurfaceCapabilitiesKHR surface_capabilities;
+ if (VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surface_capabilities); res != VK_SUCCESS) {
+ std::cerr << "failed to get physical device surface capabilities, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return surface_capabilities;
+ }();
- VkExtent2D swapchain_extent = [surface_capabilities, window]() {
+ auto swapchain_extent = [&]() {
if (surface_capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
return surface_capabilities.currentExtent;
int width, height;
@@ -826,14 +777,14 @@ static int main_graphical() {
};
}();
- VkSurfaceFormatKHR surface_format = [device, surface]() {
+ auto surface_format = [&]() {
uint32_t surface_formats_count;
- if (VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &surface_formats_count, nullptr); res != VK_SUCCESS) {
+ if (VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &surface_formats_count, nullptr); res != VK_SUCCESS) {
std::cerr << "failed to get physical device surface formats, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
std::vector<VkSurfaceFormatKHR> surface_formats(surface_formats_count);
- if (VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &surface_formats_count, surface_formats.data()); res != VK_SUCCESS) {
+ if (VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &surface_formats_count, surface_formats.data()); res != VK_SUCCESS) {
std::cerr << "failed to get physical device surface formats, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
@@ -849,14 +800,14 @@ static int main_graphical() {
std::exit(EXIT_FAILURE);
}();
- VkPresentModeKHR present_mode = [device, surface]() {
+ auto present_mode = [&]() {
uint32_t present_modes_count;
- if (VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_modes_count, nullptr); res != VK_SUCCESS) {
+ if (VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_modes_count, nullptr); res != VK_SUCCESS) {
std::cerr << "failed to get physical device present modes, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
std::vector<VkPresentModeKHR> present_modes(present_modes_count);
- if (VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_modes_count, present_modes.data()); res != VK_SUCCESS) {
+ if (VkResult res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &present_modes_count, present_modes.data()); res != VK_SUCCESS) {
std::cerr << "failed to get physical device present modes, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
@@ -868,417 +819,463 @@ static int main_graphical() {
return VK_PRESENT_MODE_FIFO_KHR;
}();
- // TODO: remove unnecessary static_cast<uint32_t>, but at this moment I'm not sure where they
- // are necessary
- uint32_t min_image_count = std::max(static_cast<uint32_t>(3), surface_capabilities.minImageCount + static_cast<uint32_t>(1));
- if (surface_capabilities.maxImageCount > 0 && surface_capabilities.maxImageCount < min_image_count)
- min_image_count = surface_capabilities.maxImageCount;
-
- // might not be used, but if we do, we have to keep it in memory until the call to vkCreateSwapchainKHR()
- std::array<uint32_t, 2> queue_family_indices;
- VkSwapchainCreateInfoKHR swapchain_create_info{};
- swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- swapchain_create_info.flags = VkSwapchainCreateFlagsKHR{};
- swapchain_create_info.surface = surface;
- swapchain_create_info.minImageCount = min_image_count;
- swapchain_create_info.imageFormat = surface_format.format;
- swapchain_create_info.imageColorSpace = surface_format.colorSpace;
- swapchain_create_info.imageExtent = swapchain_extent;
- swapchain_create_info.imageArrayLayers = 1;
- swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- swapchain_create_info.preTransform = surface_capabilities.currentTransform;
- swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- swapchain_create_info.presentMode = present_mode;
- swapchain_create_info.clipped = VK_TRUE;
- if (graphics_queue_family_index == presentation_queue_family_index) {
- swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- } else {
- swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
- queue_family_indices[0] = graphics_queue_family_index;
- queue_family_indices[1] = presentation_queue_family_index;
- swapchain_create_info.queueFamilyIndexCount = 2;
- swapchain_create_info.pQueueFamilyIndices = queue_family_indices.data();
- }
-
- VkSwapchainKHR swapchain;
- if (VkResult res = vkCreateSwapchainKHR(logical_device, &swapchain_create_info, nullptr, &swapchain); res != VK_SUCCESS) {
- std::cerr << "failed create swapchain, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
-
- uint32_t swapchain_imgs_count;
- if (VkResult res = vkGetSwapchainImagesKHR(logical_device, swapchain, &swapchain_imgs_count, nullptr); res != VK_SUCCESS) {
- std::cerr << "failed to get swapchain images, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
- std::vector<VkImage> swapchain_imgs(swapchain_imgs_count);
- if (VkResult res = vkGetSwapchainImagesKHR(logical_device, swapchain, &swapchain_imgs_count, swapchain_imgs.data()); res != VK_SUCCESS) {
- std::cerr << "failed to get swapchain images, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
-
- std::vector<VkImageView> swapchain_img_views(swapchain_imgs.size());
- for (uint32_t i = 0; i < swapchain_imgs.size(); i++) {
- VkImageViewCreateInfo img_view_create_info {
- .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
- .pNext = {},
- .flags = {},
- .image = swapchain_imgs[i],
- .viewType = VK_IMAGE_VIEW_TYPE_2D,
- .format = surface_format.format,
- .components = {},
- .subresourceRange = { // VkImageSubresourceRange
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .baseMipLevel = 0,
- .levelCount = 1,
- .baseArrayLayer = 0,
- .layerCount = 1,
- },
+ auto swapchain = [&]() {
+ // TODO: remove unnecessary static_cast<uint32_t>, but at this moment I'm not sure where they
+ // are necessary
+ uint32_t min_image_count = std::max(static_cast<uint32_t>(3), surface_capabilities.minImageCount + static_cast<uint32_t>(1));
+ if (surface_capabilities.maxImageCount > 0 && surface_capabilities.maxImageCount < min_image_count)
+ min_image_count = surface_capabilities.maxImageCount;
+
+ // might not be used, but if we do, we have to keep it in memory until the call to vkCreateSwapchainKHR()
+ std::array<uint32_t, 2> queue_family_indices;
+ VkSwapchainCreateInfoKHR swapchain_ci {
+ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+ .pNext = nullptr,
+ .flags = {},
+ .surface = surface,
+ .minImageCount = min_image_count,
+ .imageFormat = surface_format.format,
+ .imageColorSpace = surface_format.colorSpace,
+ .imageExtent = swapchain_extent,
+ .imageArrayLayers = 1,
+ .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ .imageSharingMode = {},
+ .queueFamilyIndexCount = {},
+ .pQueueFamilyIndices = {},
+ .preTransform = surface_capabilities.currentTransform,
+ .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ .presentMode = present_mode,
+ .clipped = VK_TRUE,
+ .oldSwapchain = {},
};
- if (VkResult res = vkCreateImageView(logical_device, &img_view_create_info, nullptr, &swapchain_img_views[i]); res != VK_SUCCESS) {
- std::cerr << "failed to create image view, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
+ if (graphics_queue_family_index == present_queue_family_index) {
+ swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ } else {
+ swapchain_ci.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+ queue_family_indices[0] = graphics_queue_family_index;
+ queue_family_indices[1] = present_queue_family_index;
+ swapchain_ci.queueFamilyIndexCount = 2;
+ swapchain_ci.pQueueFamilyIndices = queue_family_indices.data();
}
- }
- // reading shader file
- VkShaderModule shader_module;
- {
- // shader code has to be 32-bits aligned, which is the case with the default allocator
- std::vector<char> shader_code;
- {
- const char* shader_file_name = SHADERSDIR "/shader.spv";
- std::ifstream shader_file(shader_file_name, std::ios::ate | std::ios::binary);
- if (!shader_file.is_open()) {
- std::cerr << "file `" << shader_file_name << "'not found" << std::endl; // TODO: improve
- std::exit(EXIT_SUCCESS);
- }
- shader_code.resize(shader_file.tellg());
- shader_file.seekg(0, std::ios::beg);
- shader_file.read(shader_code.data(), static_cast<std::streamsize>(shader_code.size()));
+ VkSwapchainKHR swapchain;
+ if (VkResult res = vkCreateSwapchainKHR(device, &swapchain_ci, nullptr, &swapchain); res != VK_SUCCESS) {
+ std::cerr << "failed create swapchain, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
}
+ return swapchain;
+ }();
- VkShaderModuleCreateInfo shader_module_create_info {
- .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .codeSize = shader_code.size(),
- .pCode = reinterpret_cast<const uint32_t*>(shader_code.data()),
- };
- if (VkResult res = vkCreateShaderModule(logical_device, &shader_module_create_info, nullptr, &shader_module); res != VK_SUCCESS) {
- std::cerr << "failed to create shader module, error code: " << string_VkResult(res) << std::endl;
+ auto swapchain_imgs = [&]() {
+ uint32_t swapchain_imgs_count;
+ if (VkResult res = vkGetSwapchainImagesKHR(device, swapchain, &swapchain_imgs_count, nullptr); res != VK_SUCCESS) {
+ std::cerr << "failed to get swapchain images, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
- }
-
- std::array pl_shader_stage_create_infos {
- VkPipelineShaderStageCreateInfo {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .stage = VK_SHADER_STAGE_VERTEX_BIT,
- .module = shader_module,
- .pName = "vert_main",
- .pSpecializationInfo = nullptr,
- },
- VkPipelineShaderStageCreateInfo {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
- .module = shader_module,
- .pName = "frag_main",
- .pSpecializationInfo = nullptr,
- },
- };
-
- std::array<VkDynamicState, 2> dynamic_states {
- VK_DYNAMIC_STATE_VIEWPORT,
- VK_DYNAMIC_STATE_SCISSOR,
- };
- VkPipelineDynamicStateCreateInfo pl_dyn_state_create_info {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .dynamicStateCount = static_cast<uint32_t>(dynamic_states.size()),
- .pDynamicStates = dynamic_states.data(),
- };
-
- VkPipelineVertexInputStateCreateInfo pl_vert_in_state_create_info {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .vertexBindingDescriptionCount = 0,
- .pVertexBindingDescriptions = nullptr,
- .vertexAttributeDescriptionCount = 0,
- .pVertexAttributeDescriptions = nullptr,
- };
-
- VkPipelineInputAssemblyStateCreateInfo pl_in_asm_state_create_info {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
- .primitiveRestartEnable = VK_FALSE,
- };
-
- VkPipelineViewportStateCreateInfo pl_viewport_state_create_info {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .viewportCount = 1,
- .pViewports = {},
- .scissorCount = 1,
- .pScissors = {},
- };
-
- VkPipelineRasterizationStateCreateInfo pl_raster_state_create_info {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .depthClampEnable = VK_FALSE,
- .rasterizerDiscardEnable = VK_FALSE,
- .polygonMode = VK_POLYGON_MODE_FILL,
- .cullMode = VK_CULL_MODE_BACK_BIT,
- .frontFace = VK_FRONT_FACE_CLOCKWISE,
- .depthBiasEnable = VK_FALSE,
- .depthBiasConstantFactor = {},
- .depthBiasClamp = {},
- .depthBiasSlopeFactor = {},
- .lineWidth = 1.f,
- };
-
- VkPipelineMultisampleStateCreateInfo pl_ms_state_create_info {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
- .sampleShadingEnable = VK_FALSE,
- .minSampleShading = {},
- .pSampleMask = {},
- .alphaToCoverageEnable = VK_FALSE,
- .alphaToOneEnable = VK_FALSE,
- };
-
- VkPipelineColorBlendAttachmentState pl_col_blend_attachment_state {
- .blendEnable = VK_FALSE,
- .srcColorBlendFactor = {},
- .dstColorBlendFactor = {},
- .colorBlendOp = {},
- .srcAlphaBlendFactor = {},
- .dstAlphaBlendFactor = {},
- .alphaBlendOp = {},
- .colorWriteMask = VK_COLOR_COMPONENT_R_BIT
- | VK_COLOR_COMPONENT_G_BIT
- | VK_COLOR_COMPONENT_B_BIT
- | VK_COLOR_COMPONENT_A_BIT,
- };
-
- VkPipelineColorBlendStateCreateInfo pl_col_blend_state_create_info {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .logicOpEnable = VK_FALSE,
- .logicOp = {},
- .attachmentCount = 1,
- .pAttachments = &pl_col_blend_attachment_state,
- .blendConstants = { 0.f, 0.f, 0.f, 0.f },
- };
+ std::vector<VkImage> swapchain_imgs(swapchain_imgs_count);
+ if (VkResult res = vkGetSwapchainImagesKHR(device, swapchain, &swapchain_imgs_count, swapchain_imgs.data()); res != VK_SUCCESS) {
+ std::cerr << "failed to get swapchain images, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return swapchain_imgs;
+ }();
- VkPipelineLayoutCreateInfo pl_layout_create_info {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- .setLayoutCount = 0,
- .pSetLayouts = {},
- .pushConstantRangeCount = 0,
- .pPushConstantRanges = {},
- };
+ auto swapchain_img_views = [&]() {
+ std::vector<VkImageView> swapchain_img_views(swapchain_imgs.size());
+ for (uint32_t i = 0; i < swapchain_imgs.size(); i++) {
+ VkImageViewCreateInfo img_view_ci {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ .pNext = {},
+ .flags = {},
+ .image = swapchain_imgs[i],
+ .viewType = VK_IMAGE_VIEW_TYPE_2D,
+ .format = surface_format.format,
+ .components = {},
+ .subresourceRange = { // VkImageSubresourceRange
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1,
+ },
+ };
+ if (VkResult res = vkCreateImageView(device, &img_view_ci, nullptr, &swapchain_img_views[i]); res != VK_SUCCESS) {
+ std::cerr << "failed to create image view, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ }
+ return swapchain_img_views;
+ }();
- VkPipelineLayout pl_layout;
- if (VkResult res = vkCreatePipelineLayout(logical_device, &pl_layout_create_info, nullptr, &pl_layout); res != VK_SUCCESS) {
- std::cerr << "failed to create pipeline layout, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ auto [pl_layout, graphics_pl] = [&]() {
+ // reading shader file
+ auto shader_module = [&]() {
+ // shader code has to be 32-bits aligned, which is the case with the default allocator
+ std::vector<char> shader_code;
+ {
+ const char* shader_file_name = SHADERSDIR "/shader.spv";
+ std::ifstream shader_file(shader_file_name, std::ios::ate | std::ios::binary);
+ if (!shader_file.is_open()) {
+ std::cerr << "file `" << shader_file_name << "'not found" << std::endl; // TODO: improve
+ std::exit(EXIT_SUCCESS);
+ }
+ shader_code.resize(shader_file.tellg());
+ shader_file.seekg(0, std::ios::beg);
+ shader_file.read(shader_code.data(), static_cast<std::streamsize>(shader_code.size()));
+ }
- VkPipelineRenderingCreateInfo pl_render_create_info {
- .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
- .pNext = nullptr,
- .viewMask = {},
- .colorAttachmentCount = 1,
- .pColorAttachmentFormats = &surface_format.format,
- .depthAttachmentFormat = {},
- .stencilAttachmentFormat = {},
- };
+ VkShaderModuleCreateInfo shader_module_ci {
+ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .codeSize = shader_code.size(),
+ .pCode = reinterpret_cast<const uint32_t*>(shader_code.data()),
+ };
+ VkShaderModule shader_module;
+ if (VkResult res = vkCreateShaderModule(device, &shader_module_ci, nullptr, &shader_module); res != VK_SUCCESS) {
+ std::cerr << "failed to create shader module, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return shader_module;
+ }();
+
+ auto [pl_layout, graphics_pl] = [&]() {
+ std::array pl_shader_stage_create_infos {
+ VkPipelineShaderStageCreateInfo {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .stage = VK_SHADER_STAGE_VERTEX_BIT,
+ .module = shader_module,
+ .pName = "vert_main",
+ .pSpecializationInfo = nullptr,
+ },
+ VkPipelineShaderStageCreateInfo {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .module = shader_module,
+ .pName = "frag_main",
+ .pSpecializationInfo = nullptr,
+ },
+ };
+
+ std::array dynamic_states {
+ VkDynamicState { VK_DYNAMIC_STATE_VIEWPORT },
+ VkDynamicState { VK_DYNAMIC_STATE_SCISSOR },
+ };
+ VkPipelineDynamicStateCreateInfo pl_dyn_state_ci {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .dynamicStateCount = static_cast<uint32_t>(dynamic_states.size()),
+ .pDynamicStates = dynamic_states.data(),
+ };
+
+ VkPipelineVertexInputStateCreateInfo pl_vert_in_state_ci {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .vertexBindingDescriptionCount = 0,
+ .pVertexBindingDescriptions = nullptr,
+ .vertexAttributeDescriptionCount = 0,
+ .pVertexAttributeDescriptions = nullptr,
+ };
+
+ VkPipelineInputAssemblyStateCreateInfo pl_in_asm_state_ci {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+ .primitiveRestartEnable = VK_FALSE,
+ };
+
+ VkPipelineViewportStateCreateInfo pl_viewport_state_ci {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .viewportCount = 1,
+ .pViewports = {},
+ .scissorCount = 1,
+ .pScissors = {},
+ };
+
+ VkPipelineRasterizationStateCreateInfo pl_raster_state_ci {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .depthClampEnable = VK_FALSE,
+ .rasterizerDiscardEnable = VK_FALSE,
+ .polygonMode = VK_POLYGON_MODE_FILL,
+ .cullMode = VK_CULL_MODE_BACK_BIT,
+ .frontFace = VK_FRONT_FACE_CLOCKWISE,
+ .depthBiasEnable = VK_FALSE,
+ .depthBiasConstantFactor = {},
+ .depthBiasClamp = {},
+ .depthBiasSlopeFactor = {},
+ .lineWidth = 1.f,
+ };
+
+ VkPipelineMultisampleStateCreateInfo pl_ms_state_ci {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
+ .sampleShadingEnable = VK_FALSE,
+ .minSampleShading = {},
+ .pSampleMask = {},
+ .alphaToCoverageEnable = VK_FALSE,
+ .alphaToOneEnable = VK_FALSE,
+ };
+
+ VkPipelineColorBlendAttachmentState pl_col_blend_attachment_state {
+ .blendEnable = VK_FALSE,
+ .srcColorBlendFactor = {},
+ .dstColorBlendFactor = {},
+ .colorBlendOp = {},
+ .srcAlphaBlendFactor = {},
+ .dstAlphaBlendFactor = {},
+ .alphaBlendOp = {},
+ .colorWriteMask =
+ VK_COLOR_COMPONENT_R_BIT
+ | VK_COLOR_COMPONENT_G_BIT
+ | VK_COLOR_COMPONENT_B_BIT
+ | VK_COLOR_COMPONENT_A_BIT,
+ };
+
+ VkPipelineColorBlendStateCreateInfo pl_col_blend_state_ci {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .logicOpEnable = VK_FALSE,
+ .logicOp = {},
+ .attachmentCount = 1,
+ .pAttachments = &pl_col_blend_attachment_state,
+ .blendConstants = { 0.f, 0.f, 0.f, 0.f },
+ };
+
+ auto pl_layout = [&]() {
+ VkPipelineLayoutCreateInfo pl_layout_ci {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .setLayoutCount = 0,
+ .pSetLayouts = {},
+ .pushConstantRangeCount = 0,
+ .pPushConstantRanges = {},
+ };
+
+ VkPipelineLayout pl_layout;
+ if (VkResult res = vkCreatePipelineLayout(device, &pl_layout_ci, nullptr, &pl_layout); res != VK_SUCCESS) {
+ std::cerr << "failed to create pipeline layout, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return pl_layout;
+ }();
- VkGraphicsPipelineCreateInfo graphics_pl_create_info {
- .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
- .pNext = &pl_render_create_info,
- .flags = {},
- .stageCount = 2,
- .pStages = pl_shader_stage_create_infos.data(),
- .pVertexInputState = &pl_vert_in_state_create_info,
- .pInputAssemblyState = &pl_in_asm_state_create_info,
- .pTessellationState = {},
- .pViewportState = &pl_viewport_state_create_info,
- .pRasterizationState = &pl_raster_state_create_info,
- .pMultisampleState = &pl_ms_state_create_info,
- .pDepthStencilState = {},
- .pColorBlendState = &pl_col_blend_state_create_info,
- .pDynamicState = &pl_dyn_state_create_info,
- .layout = pl_layout,
- .renderPass = nullptr,
- .subpass = {},
- .basePipelineHandle = {},
- .basePipelineIndex = {},
- };
+ VkPipelineRenderingCreateInfo pl_render_ci {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
+ .pNext = nullptr,
+ .viewMask = {},
+ .colorAttachmentCount = 1,
+ .pColorAttachmentFormats = &surface_format.format,
+ .depthAttachmentFormat = {},
+ .stencilAttachmentFormat = {},
+ };
+
+ VkGraphicsPipelineCreateInfo graphics_pl_ci {
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .pNext = &pl_render_ci,
+ .flags = {},
+ .stageCount = 2,
+ .pStages = pl_shader_stage_create_infos.data(),
+ .pVertexInputState = &pl_vert_in_state_ci,
+ .pInputAssemblyState = &pl_in_asm_state_ci,
+ .pTessellationState = {},
+ .pViewportState = &pl_viewport_state_ci,
+ .pRasterizationState = &pl_raster_state_ci,
+ .pMultisampleState = &pl_ms_state_ci,
+ .pDepthStencilState = {},
+ .pColorBlendState = &pl_col_blend_state_ci,
+ .pDynamicState = &pl_dyn_state_ci,
+ .layout = pl_layout,
+ .renderPass = nullptr,
+ .subpass = {},
+ .basePipelineHandle = {},
+ .basePipelineIndex = {},
+ };
+
+ VkPipeline graphics_pl;
+ if (VkResult res = vkCreateGraphicsPipelines(device, nullptr, 1, &graphics_pl_ci, nullptr, &graphics_pl); res != VK_SUCCESS) {
+ std::cerr << "failed to pipeline, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return std::tuple { pl_layout, graphics_pl };
+ }();
- VkPipeline graphics_pl;
- if (VkResult res = vkCreateGraphicsPipelines(logical_device, nullptr, 1, &graphics_pl_create_info, nullptr, &graphics_pl); res != VK_SUCCESS) {
- std::cerr << "failed to pipeline, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ vkDestroyShaderModule(device, shader_module, nullptr);
- // destroy when pipeline creation is finished
- vkDestroyShaderModule(logical_device, shader_module, nullptr);
+ return std::tuple { pl_layout, graphics_pl };
+ }();
- VkCommandPoolCreateInfo cmd_pool_ci {
- .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
- .pNext = nullptr,
- .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
- .queueFamilyIndex = graphics_queue_family_index,
- };
- VkCommandPool cmd_pool;
- if (VkResult res = vkCreateCommandPool(logical_device, &cmd_pool_ci, nullptr, &cmd_pool); res != VK_SUCCESS) {
- std::cerr << "failed to create command pool, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ auto cmd_pool = [&]() {
+ VkCommandPoolCreateInfo cmd_pool_ci {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
+ .queueFamilyIndex = graphics_queue_family_index,
+ };
+ VkCommandPool cmd_pool;
+ if (VkResult res = vkCreateCommandPool(device, &cmd_pool_ci, nullptr, &cmd_pool); res != VK_SUCCESS) {
+ std::cerr << "failed to create command pool, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return cmd_pool;
+ }();
- VkCommandBufferAllocateInfo cmd_buf_ai {
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
- .pNext = nullptr,
- .commandPool = cmd_pool,
- .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
- .commandBufferCount = 1,
- };
- VkCommandBuffer cmd_buf;
- if (VkResult res = vkAllocateCommandBuffers(logical_device, &cmd_buf_ai, &cmd_buf); res != VK_SUCCESS) {
- std::cerr << "failed to allocate command buffer, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ auto cmd_buf = [&]() {
+ VkCommandBufferAllocateInfo cmd_buf_ai {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .pNext = nullptr,
+ .commandPool = cmd_pool,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .commandBufferCount = 1,
+ };
+ VkCommandBuffer cmd_buf;
+ if (VkResult res = vkAllocateCommandBuffers(device, &cmd_buf_ai, &cmd_buf); res != VK_SUCCESS) {
+ std::cerr << "failed to allocate command buffer, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return cmd_buf;
+ }();
// create sync objects
- VkSemaphore sem_present_complete, sem_render_finished;
- VkFence fence_draw;
-
- // TODO: I don't know if I have to use 2 different VkSemaphoreCreateInfo, but for now, let's do
- // this so we're sure it'll work
- VkSemaphoreCreateInfo sem_present_complete_ci {
- .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- };
- if (VkResult res = vkCreateSemaphore(logical_device, &sem_present_complete_ci, nullptr, &sem_present_complete); res != VK_SUCCESS) {
- std::cerr << "failed to create present complete semaphore, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ auto [sem_present_complete, sem_render_finished] = [&]() {
+ const auto create_semaphore = [&](const char* name) {
+ VkSemaphoreCreateInfo sem_ci {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ };
+ VkSemaphore sem;
+ if (VkResult res = vkCreateSemaphore(device, &sem_ci, nullptr, &sem); res != VK_SUCCESS) {
+ std::cerr << "failed to create " << name << " semaphore, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return sem;
+ };
+ return std::tuple {
+ create_semaphore("present complete"),
+ create_semaphore("render finished"),
+ };
+ }();
std::cout << "sem_present_complete: " << sem_present_complete << std::endl;
- VkSemaphoreCreateInfo sem_render_finished_ci {
- .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
- .pNext = nullptr,
- .flags = {},
- };
- if (VkResult res = vkCreateSemaphore(logical_device, &sem_render_finished_ci, nullptr, &sem_render_finished); res != VK_SUCCESS) {
- std::cerr << "failed to create render finished semaphore, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
std::cout << "sem_render_finished: " << sem_render_finished << std::endl;
- VkFenceCreateInfo fence_draw_ci {
- .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
- .pNext = nullptr,
- .flags = VK_FENCE_CREATE_SIGNALED_BIT,
- };
- if (VkResult res = vkCreateFence(logical_device, &fence_draw_ci, nullptr, &fence_draw); res != VK_SUCCESS) {
- std::cerr << "failed to create draw semaphore, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ auto fence_draw = [&]() {
+ VkFenceCreateInfo fence_draw_ci {
+ .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = VK_FENCE_CREATE_SIGNALED_BIT,
+ };
+ VkFence fence_draw;
+ if (VkResult res = vkCreateFence(device, &fence_draw_ci, nullptr, &fence_draw); res != VK_SUCCESS) {
+ std::cerr << "failed to create draw semaphore, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return fence_draw;
+ }();
std::cout << "fence_draw: " << fence_draw << std::endl;
// main loop
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
- if (VkResult res = vkQueueWaitIdle(graphics_queue); res != VK_SUCCESS) {
+ if (VkResult res = vkQueueWaitIdle(present_queue); res != VK_SUCCESS) {
std::cerr << "failed to wait idle for graphics queue, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
- uint32_t img_idx;
- if (VkResult res = vkAcquireNextImageKHR(logical_device, swapchain,
- std::numeric_limits<uint64_t>::max(), sem_present_complete, nullptr, &img_idx); res != VK_SUCCESS) {
- std::cerr << "failed to acquire next image, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
- }
+ auto img_idx = [&]() {
+ uint32_t img_idx;
+ if (VkResult res = vkAcquireNextImageKHR(device, swapchain,
+ std::numeric_limits<uint64_t>::max(), sem_present_complete, nullptr, &img_idx); res != VK_SUCCESS) {
+ std::cerr << "failed to acquire next image, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return img_idx;
+ }();
// record command buffer
- VkCommandBufferBeginInfo cmd_buf_bi {
- .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
- .pNext = nullptr,
- .flags = {},
- .pInheritanceInfo = {},
- };
- if (VkResult res = vkBeginCommandBuffer(cmd_buf, &cmd_buf_bi); res != VK_SUCCESS) {
- std::cerr << "failed to begin command buffer, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
+ {
+ VkCommandBufferBeginInfo cmd_buf_bi {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .pInheritanceInfo = {},
+ };
+ if (VkResult res = vkBeginCommandBuffer(cmd_buf, &cmd_buf_bi); res != VK_SUCCESS) {
+ std::cerr << "failed to begin command buffer, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
}
+
transition_image_layout(cmd_buf, swapchain_imgs[img_idx],
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
{}, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT);
- VkClearValue clear_val { .color = { .float32 = { 0.f, 0.f, 0.f, 1.f } }, };
- VkRenderingAttachmentInfo attachment_info {
- .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
- .pNext = nullptr,
- .imageView = swapchain_img_views[img_idx],
- .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
- .resolveMode = {},
- .resolveImageView = {},
- .resolveImageLayout = {},
- .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
- .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
- .clearValue = clear_val,
- };
- VkRenderingInfo render_info {
- .sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
- .pNext = nullptr,
- .flags = {},
- .renderArea = { .offset { 0, 0 }, .extent = swapchain_extent },
- .layerCount = 1,
- .viewMask = {},
- .colorAttachmentCount = 1,
- .pColorAttachments = &attachment_info,
- .pDepthAttachment = {},
- .pStencilAttachment = {},
- };
- vkCmdBeginRendering(cmd_buf, &render_info);
+
+ {
+ VkClearValue clear_val { .color = { .float32 = { 0.f, 0.f, 0.f, 1.f } }, };
+ VkRenderingAttachmentInfo attachment_info {
+ .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
+ .pNext = nullptr,
+ .imageView = swapchain_img_views[img_idx],
+ .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ .resolveMode = {},
+ .resolveImageView = {},
+ .resolveImageLayout = {},
+ .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+ .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+ .clearValue = clear_val,
+ };
+ VkRenderingInfo render_info {
+ .sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
+ .pNext = nullptr,
+ .flags = {},
+ .renderArea = { .offset { 0, 0 }, .extent = swapchain_extent },
+ .layerCount = 1,
+ .viewMask = {},
+ .colorAttachmentCount = 1,
+ .pColorAttachments = &attachment_info,
+ .pDepthAttachment = {},
+ .pStencilAttachment = {},
+ };
+ vkCmdBeginRendering(cmd_buf, &render_info);
+ }
+
vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pl);
- VkViewport viewport {
- .x = 0.f,
- .y = 0.f,
- .width = static_cast<float>(swapchain_extent.width),
- .height = static_cast<float>(swapchain_extent.height),
- .minDepth = 0.f,
- .maxDepth = 1.f,
- };
- vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
+ {
+ VkViewport viewport {
+ .x = 0.f,
+ .y = 0.f,
+ .width = static_cast<float>(swapchain_extent.width),
+ .height = static_cast<float>(swapchain_extent.height),
+ .minDepth = 0.f,
+ .maxDepth = 1.f,
+ };
+ vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
+ }
- VkRect2D scissor {
- .offset = { 0, 0 },
- .extent = swapchain_extent,
- };
- vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
+ {
+ VkRect2D scissor {
+ .offset = { 0, 0 },
+ .extent = swapchain_extent,
+ };
+ vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
+ }
vkCmdDraw(cmd_buf, 3, 1, 0, 0);
@@ -1294,66 +1291,70 @@ static int main_graphical() {
std::exit(EXIT_FAILURE);
}
- if (VkResult res = vkResetFences(logical_device, 1, &fence_draw); res != VK_SUCCESS) {
+ if (VkResult res = vkResetFences(device, 1, &fence_draw); res != VK_SUCCESS) {
std::cerr << "failed to reset draw fence, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
- VkPipelineStageFlags pl_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- VkSubmitInfo submit_info {
- .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
- .pNext = nullptr,
- .waitSemaphoreCount = 1,
- .pWaitSemaphores = &sem_present_complete,
- .pWaitDstStageMask = &pl_stage_flags,
- .commandBufferCount = 1,
- .pCommandBuffers = &cmd_buf,
- .signalSemaphoreCount = 1,
- .pSignalSemaphores = &sem_render_finished,
- };
- if (VkResult res = vkQueueSubmit(graphics_queue, 1, &submit_info, fence_draw); res != VK_SUCCESS) {
- std::cerr << "failed to submit queue, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
+ {
+ VkPipelineStageFlags pl_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ VkSubmitInfo submit_info {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ .pNext = nullptr,
+ .waitSemaphoreCount = 1,
+ .pWaitSemaphores = &sem_present_complete,
+ .pWaitDstStageMask = &pl_stage_flags,
+ .commandBufferCount = 1,
+ .pCommandBuffers = &cmd_buf,
+ .signalSemaphoreCount = 1,
+ .pSignalSemaphores = &sem_render_finished,
+ };
+ if (VkResult res = vkQueueSubmit(graphics_queue, 1, &submit_info, fence_draw); res != VK_SUCCESS) {
+ std::cerr << "failed to submit queue, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
}
- if (VkResult res = vkWaitForFences(logical_device, 1, &fence_draw, VK_TRUE, std::numeric_limits<uint64_t>::max()); res != VK_SUCCESS) {
+ if (VkResult res = vkWaitForFences(device, 1, &fence_draw, VK_TRUE, std::numeric_limits<uint64_t>::max()); res != VK_SUCCESS) {
std::cerr << "failed to wait for draw fence, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
- VkPresentInfoKHR present_info {
- .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
- .pNext = nullptr,
- .waitSemaphoreCount = 1,
- .pWaitSemaphores = &sem_render_finished,
- .swapchainCount = 1,
- .pSwapchains = &swapchain,
- .pImageIndices = &img_idx,
- .pResults = nullptr,
- };
- if (VkResult res = vkQueuePresentKHR(presentation_queue, &present_info); res != VK_SUCCESS) {
- std::cerr << "failed to present, error code: " << string_VkResult(res) << std::endl;
- std::exit(EXIT_FAILURE);
+ {
+ VkPresentInfoKHR present_info {
+ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+ .pNext = nullptr,
+ .waitSemaphoreCount = 1,
+ .pWaitSemaphores = &sem_render_finished,
+ .swapchainCount = 1,
+ .pSwapchains = &swapchain,
+ .pImageIndices = &img_idx,
+ .pResults = nullptr,
+ };
+ if (VkResult res = vkQueuePresentKHR(present_queue, &present_info); res != VK_SUCCESS) {
+ std::cerr << "failed to present, error code: " << string_VkResult(res) << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
}
}
- if (VkResult res = vkDeviceWaitIdle(logical_device); res != VK_SUCCESS) {
+ if (VkResult res = vkDeviceWaitIdle(device); res != VK_SUCCESS) {
std::cerr << "failed to wait idle for device, error code: " << string_VkResult(res) << std::endl;
std::exit(EXIT_FAILURE);
}
// cleanup
- vkDestroyFence(logical_device, fence_draw, nullptr);
- vkDestroySemaphore(logical_device, sem_render_finished, nullptr);
- vkDestroySemaphore(logical_device, sem_present_complete, nullptr);
- vkDestroyCommandPool(logical_device, cmd_pool, nullptr);
- vkDestroyPipeline(logical_device, graphics_pl, nullptr);
- vkDestroyPipelineLayout(logical_device, pl_layout, nullptr);
+ vkDestroyFence(device, fence_draw, nullptr);
+ vkDestroySemaphore(device, sem_render_finished, nullptr);
+ vkDestroySemaphore(device, sem_present_complete, nullptr);
+ vkDestroyCommandPool(device, cmd_pool, nullptr);
+ vkDestroyPipeline(device, graphics_pl, nullptr);
+ vkDestroyPipelineLayout(device, pl_layout, nullptr);
for (const auto img_view : swapchain_img_views)
- vkDestroyImageView(logical_device, img_view, nullptr);
- vkDestroySwapchainKHR(logical_device, swapchain, nullptr);
+ vkDestroyImageView(device, img_view, nullptr);
+ vkDestroySwapchainKHR(device, swapchain, nullptr);
vkDestroySurfaceKHR(instance, surface, nullptr);
- vkDestroyDevice(logical_device, nullptr);
+ vkDestroyDevice(device, nullptr);
if (enable_validation_layers) {
auto destroy_debug_messenger = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
diff --git a/src/vulkan_utils.hpp b/src/vulkan_utils.hpp
new file mode 100644
index 0000000..8e6f617
--- /dev/null
+++ b/src/vulkan_utils.hpp
@@ -0,0 +1,24 @@
+#ifndef VULKAN_UTILS_HPP
+#define VULKAN_UTILS_HPP
+
+#include <ostream>
+// I don't know if we should directly include vulkan or not
+#define GLFW_INCLUDE_VULKAN
+#include <GLFW/glfw3.h>
+
+namespace engine::myvk {
+
+struct api { uint32_t raw; };
+
+constexpr std::ostream& operator<<(std::ostream& os, const api& api) {
+ // this code is unreadable but it amuses me
+ return (VK_API_VERSION_VARIANT(api.raw) == 0 ? os : os << "(variant "
+ << VK_API_VERSION_VARIANT(api.raw) << ") ")
+ << VK_API_VERSION_MAJOR (api.raw) << "."
+ << VK_API_VERSION_MINOR (api.raw) << "."
+ << VK_API_VERSION_PATCH (api.raw);
+}
+
+}
+
+#endif // VULKAN_UTILS_HPP