diff options
| author | vimene <vincent.menegaux@gmail.com> | 2025-12-20 17:25:51 +0100 |
|---|---|---|
| committer | vimene <vincent.menegaux@gmail.com> | 2025-12-20 17:25:51 +0100 |
| commit | e3a465293b92ed30e220f2c70f67fb9adf3b0403 (patch) | |
| tree | 7b0fa7bd693b467811d8f010c29b159051254beb | |
| parent | 8024a6d59a4595f69f03466b66f4ea2eea87fcf9 (diff) | |
| download | engine-e3a465293b92ed30e220f2c70f67fb9adf3b0403.tar.gz | |
create present queue and lots of code refactoring
- wait idle on present queue instead of graphics queue
- assume only one bit of VkDebugUtilsMessageSeverityFlagBitsEXT is set;
it seems to be always the case
- rename every _create_info to _ci
- print less debug information, by reducing debug output to warning and
up, and by removing printing of all of devices properties
- make as much blocks and lambdas as possible to contain every variable
to a small scope
- use designator lists everywhere
- rename device to physical_device, and logical_device to device
| -rw-r--r-- | src/Makefile.am | 1 | ||||
| -rw-r--r-- | src/engine.cpp | 1403 | ||||
| -rw-r--r-- | src/vulkan_utils.hpp | 24 |
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 |
