diff --git a/CMakeLists.txt b/CMakeLists.txt index 3463bc4..611b162 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,15 +3,7 @@ project(VulkanBootstrap) find_package(Vulkan REQUIRED) -add_library(vk-bootstrap - src/VkBootstrap.h - src/Util.h - src/Instance.h - src/Device.h - src/Swapchain.h - src/Instance.cpp - src/Device.cpp - src/Swapchain.cpp) +add_library(vk-bootstrap src/VkBootstrap.h src/VkBootstrap.cpp) target_include_directories(vk-bootstrap PUBLIC src) @@ -31,5 +23,6 @@ add_executable(vk-bootstrap-test tests/run_tests.cpp) target_link_libraries(vk-bootstrap-test vk-bootstrap) target_link_libraries(vk-bootstrap-test glfw) +target_link_libraries(vk-bootstrap-test Catch2) -endif(VK_BOOTSTRAP_TEST) \ No newline at end of file +endif() \ No newline at end of file diff --git a/README.md b/README.md index 33544af..30d9e10 100644 --- a/README.md +++ b/README.md @@ -13,29 +13,29 @@ This library simplifies the tedious process of: ## Example ```cpp -vkbs::InstanceBuilder builder; +vkb::InstanceBuilder builder; builder.setup_validation_layers() .set_app_name ("example") .set_default_debug_messenger (); auto inst_ret = builder.build (); -vkbs::Instance inst; +vkb::Instance inst; if (inst_ret.has_value()) { // successfully created instance inst = inst_ret.value(); } -vkbs::PhysicalDeviceSelector(inst); +vkb::PhysicalDeviceSelector(inst); selector.set_surface (/* from user created window*/) .set_minimum_version (1, 0) .require_dedicated_transfer_queue(); auto phys_ret = selector.select (); -vkbs::PhysicalDevice phys; +vkb::PhysicalDevice phys; if (phys_ret.has_value()) { // successfully selected a sufficient physical device phys = phys_ret.value(); } -vkbs::DeviceBuilder device_builder(phys_dev); +vkb::DeviceBuilder device_builder(phys_dev); auto dev_ret = device_builder.build (); if(dev_ret.has_value()){ // successfully created a vulkan device diff --git a/src/Device.h b/src/Device.h deleted file mode 100644 index 5c90ebd..0000000 --- a/src/Device.h +++ /dev/null @@ -1,180 +0,0 @@ -#pragma once - -#include "Util.h" - -#include "Instance.h" - -namespace vkbs -{ -namespace detail -{ - -struct SurfaceSupportDetails -{ - VkSurfaceCapabilitiesKHR capabilities; - std::vector formats; - std::vector present_modes; -}; - -Expected query_surface_support_details ( - VkPhysicalDevice phys_device, VkSurfaceKHR surface); - -struct QueueFamilies -{ - int graphics = -1; - int present = -1; - int transfer = -1; - int compute = -1; - int sparse = -1; - uint32_t count_graphics = 0; - uint32_t count_transfer = 0; - uint32_t count_compute = 0; - uint32_t count_sparse = 0; -}; - -VkFormat find_supported_format (VkPhysicalDevice physical_device, - const std::vector& candidates, - VkImageTiling tiling, - VkFormatFeatureFlags features); - -bool check_device_extension_support (VkPhysicalDevice device, std::vector extensions); - -detail::QueueFamilies find_queue_families (VkPhysicalDevice physDevice, VkSurfaceKHR windowSurface); - -bool supports_features (VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested); - -} // namespace detail - -// ---- Physical Device ---- // - -struct PhysicalDevice -{ - VkPhysicalDevice phys_device = VK_NULL_HANDLE; - VkSurfaceKHR surface = VK_NULL_HANDLE; - - VkPhysicalDeviceProperties physical_device_properties{}; - VkPhysicalDeviceFeatures physical_device_features{}; - VkPhysicalDeviceMemoryProperties memory_properties{}; - - detail::QueueFamilies queue_family_properties; -}; - -namespace detail -{ -void populate_physical_device_details (PhysicalDevice physical_device); -} // namespace detail - -struct PhysicalDeviceSelector -{ - public: - PhysicalDeviceSelector (Instance instance); - - detail::Expected select (); - - PhysicalDeviceSelector& set_surface (VkSurfaceKHR instance); - - PhysicalDeviceSelector& prefer_discrete (bool prefer_discrete = true); - PhysicalDeviceSelector& prefer_integrated (bool prefer_integrated = true); - PhysicalDeviceSelector& allow_fallback (bool fallback = true); - - PhysicalDeviceSelector& require_present (bool require = true); - PhysicalDeviceSelector& require_dedicated_transfer_queue (); - PhysicalDeviceSelector& require_dedicated_compute_queue (); - - PhysicalDeviceSelector& required_device_memory_size (VkDeviceSize size); - PhysicalDeviceSelector& desired_device_memory_size (VkDeviceSize size); - - PhysicalDeviceSelector& add_required_extension (std::string extension); - PhysicalDeviceSelector& add_desired_extension (std::string extension); - - PhysicalDeviceSelector& set_desired_version (uint32_t major, uint32_t minor); - PhysicalDeviceSelector& set_minimum_version (uint32_t major = 1, uint32_t minor = 0); - - PhysicalDeviceSelector& set_required_features (VkPhysicalDeviceFeatures features); - - private: - struct PhysicalDeviceInfo - { - VkInstance instance = VK_NULL_HANDLE; - VkSurfaceKHR surface = VK_NULL_HANDLE; - bool headless = false; - } info; - - struct SelectionCriteria - { - bool prefer_discrete = true; - bool prefer_integrated = false; - bool allow_fallback = true; - bool require_present = true; - bool require_dedicated_transfer_queue = false; - bool require_dedicated_compute_queue = false; - VkDeviceSize required_mem_size = 0; - VkDeviceSize desired_mem_size = 0; - - std::vector required_extensions; - std::vector desired_extensions; - - uint32_t required_version = VK_MAKE_VERSION (1, 0, 0); - uint32_t desired_version = VK_MAKE_VERSION (1, 0, 0); - - VkPhysicalDeviceFeatures required_features{}; - - } criteria; - - enum class Suitable - { - yes, - partial, - no - }; - - Suitable is_device_suitable (VkPhysicalDevice phys_device); -}; - -// ---- Device ---- // - -struct Device -{ - VkDevice device = VK_NULL_HANDLE; - VkAllocationCallbacks* allocator = VK_NULL_HANDLE; - PhysicalDevice physical_device; - VkSurfaceKHR surface = VK_NULL_HANDLE; -}; - -void destroy_device (Device device); - -class DeviceBuilder -{ - public: - DeviceBuilder (PhysicalDevice device); - detail::Expected build (); - - template DeviceBuilder& add_pNext (T* structure); - - private: - struct DeviceInfo - { - VkDeviceCreateFlags flags; - VkBaseOutStructure* pNext_chain = nullptr; - VkAllocationCallbacks* allocator = VK_NULL_HANDLE; - PhysicalDevice physical_device; - std::vector extensions; - } info; -}; - -// ---- Queue ---- // - -namespace detail -{ -VkQueue get_queue (Device const& device, uint32_t family, uint32_t index = 0); -} - -detail::Expected get_queue_present (Device const& device); -detail::Expected get_queue_graphics (Device const& device, uint32_t index = 0); -detail::Expected get_queue_compute (Device const& device, uint32_t index = 0); -detail::Expected get_queue_transfer (Device const& device, uint32_t index = 0); -detail::Expected get_queue_sparse (Device const& device, uint32_t index = 0); - - - -} // namespace vkbs \ No newline at end of file diff --git a/src/Instance.cpp b/src/Instance.cpp deleted file mode 100644 index 7bc5c9b..0000000 --- a/src/Instance.cpp +++ /dev/null @@ -1,349 +0,0 @@ -#include "Instance.h" - -#include -#include - -namespace vkbs -{ - -const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s) -{ - switch (s) - { - case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: - return "VERBOSE"; - case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: - return "ERROR"; - case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: - return "WARNING"; - case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: - return "INFO"; - default: - return "UNKNOWN"; - } -} -const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s) -{ - switch (s) - { - case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT: - return "General"; - case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: - return "Validation"; - case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: - return "Performance"; - default: - return "Unknown"; - } -} - -namespace detail -{ - -VkResult create_debug_utils_messenger (VkInstance instance, - PFN_vkDebugUtilsMessengerCallbackEXT debug_callback, - VkDebugUtilsMessageSeverityFlagsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkAllocationCallbacks* pAllocator, - VkDebugUtilsMessengerEXT* pDebugMessenger) -{ - if (debug_callback == nullptr) debug_callback = default_debug_callback; - VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {}; - messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - messengerCreateInfo.messageSeverity = severity; - messengerCreateInfo.messageType = type; - messengerCreateInfo.pfnUserCallback = debug_callback; - - - auto vkCreateDebugUtilsMessengerEXT_func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr ( - instance, "vkCreateDebugUtilsMessengerEXT"); - if (vkCreateDebugUtilsMessengerEXT_func != nullptr) - { - return vkCreateDebugUtilsMessengerEXT_func (instance, &messengerCreateInfo, pAllocator, pDebugMessenger); - } - else - { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } -} - -void destroy_debug_utils_messenger ( - VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) -{ - auto vkDestroyDebugUtilsMessengerEXT_func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr ( - instance, "vkDestroyDebugUtilsMessengerEXT"); - if (vkDestroyDebugUtilsMessengerEXT_func != nullptr) - { - vkDestroyDebugUtilsMessengerEXT_func (instance, debugMessenger, pAllocator); - } -} - -VkBool32 default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData) -{ - auto ms = DebugMessageSeverity (messageSeverity); - auto mt = DebugMessageType (messageType); - printf ("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage); - return VK_FALSE; -} - -bool check_layers_supported (std::vector layer_names) -{ - auto available_layers = detail::get_vector (vkEnumerateInstanceLayerProperties); - if (!available_layers.has_value ()) return false; // maybe report error? - bool all_found = true; - for (const auto& layer_name : layer_names) - { - bool found = false; - for (const auto& layer_properties : available_layers.value ()) - { - if (strcmp (layer_name, layer_properties.layerName) == 0) - { - found = true; - break; - } - } - if (!found) all_found = false; - } - - return all_found; -} - -} // namespace detail - -void destroy_instance (Instance instance) -{ - if (instance.debug_messenger != nullptr) - detail::destroy_debug_utils_messenger (instance.instance, instance.debug_messenger, instance.allocator); - if (instance.instance != VK_NULL_HANDLE) - vkDestroyInstance (instance.instance, instance.allocator); -} - -detail::Expected InstanceBuilder::build () -{ - - VkApplicationInfo app_info = {}; - app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app_info.pNext = nullptr; - app_info.pApplicationName = info.app_name.c_str (); - app_info.applicationVersion = info.application_version; - app_info.pEngineName = info.engine_name.c_str (); - app_info.engineVersion = info.engine_version; - app_info.apiVersion = info.api_version; - - std::vector extensions; - for (auto& ext : info.extensions) - extensions.push_back (ext.c_str ()); - if (info.debug_callback != nullptr) - { - extensions.push_back (VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } - - if (!info.headless_context) - { - extensions.push_back (VK_KHR_SURFACE_EXTENSION_NAME); -#if defined(_WIN32) - extentions.push_back (VK_KHR_WIN32_SURFACE_EXTENSION_NAME); -#elif defined(VK_USE_PLATFORM_ANDROID_KHR) - extentions.push_back (VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); -#elif defined(_DIRECT2DISPLAY) - extentions.push_back (VK_KHR_DISPLAY_EXTENSION_NAME); -#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) - extentions.push_back (VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); -#elif defined(VK_USE_PLATFORM_XCB_KHR) - extentions.push_back (VK_KHR_XCB_SURFACE_EXTENSION_NAME); -#elif defined(VK_USE_PLATFORM_X11_HKR) - extentions.push_back (VK_KHR_X11_SURFACE_EXTENSION_NAME); -#elif defined(VK_USE_PLATFORM_IOS_MVK) - extentions.push_back (VK_MVK_IOS_SURFACE_EXTENSION_NAME); -#elif defined(VK_USE_PLATFORM_MACOS_MVK) - extentions.push_back (VK_MVK_MACOS_SURFACE_EXTENSION_NAME); -#endif - } - - std::vector layers; - for (auto& layer : info.layers) - layers.push_back (layer.c_str ()); - - if (info.enable_validation_layers) - { - layers.push_back ("VK_LAYER_KHRONOS_validation"); - } - bool all_layers_supported = detail::check_layers_supported (layers); - if (!all_layers_supported) - { - return detail::Error{ VK_ERROR_LAYER_NOT_PRESENT, "Not all layers supported!" }; - } - - VkBaseOutStructure pNext_chain; - pNext_chain.pNext = (VkBaseOutStructure*)info.pNext; - if (info.use_debug_messenger) - { - VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {}; - messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - messengerCreateInfo.messageSeverity = info.debug_message_severity; - messengerCreateInfo.messageType = info.debug_message_type; - messengerCreateInfo.pfnUserCallback = info.debug_callback; - detail::pNext_append (&pNext_chain, &messengerCreateInfo); - } - - if (info.enabled_validation_features.size () != 0 || info.disabled_validation_features.size ()) - { - VkValidationFeaturesEXT features{}; - features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; - features.pNext = nullptr; - features.enabledValidationFeatureCount = info.enabled_validation_features.size (); - features.pEnabledValidationFeatures = info.enabled_validation_features.data (); - features.disabledValidationFeatureCount = info.disabled_validation_features.size (); - features.pDisabledValidationFeatures = info.disabled_validation_features.data (); - detail::pNext_append (&pNext_chain, &features); - } - - if (info.disabled_validation_checks.size () != 0) - { - VkValidationFlagsEXT checks{}; - checks.sType = VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT; - checks.pNext = nullptr; - checks.disabledValidationCheckCount = info.disabled_validation_checks.size (); - checks.pDisabledValidationChecks = info.disabled_validation_checks.data (); - detail::pNext_append (&pNext_chain, &checks); - } - - VkInstanceCreateInfo instance_create_info = {}; - instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instance_create_info.pNext = pNext_chain.pNext; - instance_create_info.flags = info.flags; - instance_create_info.pApplicationInfo = &app_info; - instance_create_info.enabledExtensionCount = static_cast (extensions.size ()); - instance_create_info.ppEnabledExtensionNames = extensions.data (); - instance_create_info.enabledLayerCount = static_cast (layers.size ()); - instance_create_info.ppEnabledLayerNames = layers.data (); - - Instance instance; - VkResult res = vkCreateInstance (&instance_create_info, info.allocator, &instance.instance); - if (res != VK_SUCCESS) return detail::Error{ res, "Failed to create instance" }; - - res = detail::create_debug_utils_messenger (instance.instance, - info.debug_callback, - info.debug_message_severity, - info.debug_message_type, - info.allocator, - &instance.debug_messenger); - if (res != VK_SUCCESS) - return detail::Error{ res, "Failed to create setup debug callback" }; - - if (info.headless_context) - { - instance.headless = true; - } - return instance; -} - -InstanceBuilder& InstanceBuilder::set_app_name (std::string app_name) -{ - info.app_name = app_name; - return *this; -} -InstanceBuilder& InstanceBuilder::set_engine_name (std::string engine_name) -{ - info.engine_name = engine_name; - return *this; -} - -InstanceBuilder& InstanceBuilder::set_app_version (uint32_t major, uint32_t minor, uint32_t patch) -{ - info.application_version = VK_MAKE_VERSION (major, minor, patch); - return *this; -} -InstanceBuilder& InstanceBuilder::set_engine_version (uint32_t major, uint32_t minor, uint32_t patch) -{ - info.engine_version = VK_MAKE_VERSION (major, minor, patch); - return *this; -} -InstanceBuilder& InstanceBuilder::set_api_version (uint32_t major, uint32_t minor, uint32_t patch) -{ - info.api_version = VK_MAKE_VERSION (major, minor, patch); - return *this; -} - -InstanceBuilder& InstanceBuilder::add_layer (std::string layer_name) -{ - info.layers.push_back (layer_name); - return *this; -} -InstanceBuilder& InstanceBuilder::add_extension (std::string extension_name) -{ - info.extensions.push_back (extension_name); - return *this; -} - -InstanceBuilder& InstanceBuilder::setup_validation_layers (bool enable_validation) -{ - info.enable_validation_layers = enable_validation; - return *this; -} -InstanceBuilder& InstanceBuilder::set_default_debug_messenger () -{ - info.use_debug_messenger = true; - info.debug_callback = detail::default_debug_callback; - return *this; -} - -InstanceBuilder& InstanceBuilder::set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback) -{ - info.use_debug_messenger = true; - info.debug_callback = callback; - return *this; -} -InstanceBuilder& InstanceBuilder::set_headless (bool headless) -{ - info.headless_context = headless; - return *this; -} - -InstanceBuilder& InstanceBuilder::set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity) -{ - info.debug_message_severity = severity; - return *this; -} -InstanceBuilder& InstanceBuilder::add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity) -{ - info.debug_message_severity = info.debug_message_severity | severity; - return *this; -} -InstanceBuilder& InstanceBuilder::set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type) -{ - info.debug_message_type = type; - return *this; -} -InstanceBuilder& InstanceBuilder::add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type) -{ - info.debug_message_type = info.debug_message_type | type; - return *this; -} - -InstanceBuilder& InstanceBuilder::add_validation_disable (VkValidationCheckEXT check) -{ - info.disabled_validation_checks.push_back (check); - return *this; -} -InstanceBuilder& InstanceBuilder::add_validation_feature_enable (VkValidationFeatureEnableEXT enable) -{ - info.enabled_validation_features.push_back (enable); - return *this; -} -InstanceBuilder& InstanceBuilder::add_validation_feature_disable (VkValidationFeatureDisableEXT disable) -{ - info.disabled_validation_features.push_back (disable); - return *this; -} - -InstanceBuilder& InstanceBuilder::set_allocator_callback (VkAllocationCallbacks* allocator) -{ - info.allocator = allocator; - return *this; -} - -} // namespace vkbs \ No newline at end of file diff --git a/src/Instance.h b/src/Instance.h deleted file mode 100644 index f1cf4c5..0000000 --- a/src/Instance.h +++ /dev/null @@ -1,113 +0,0 @@ -#pragma once - -#include "Util.h" - -namespace vkbs -{ - -const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s); -const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s); - -namespace detail -{ -VkResult create_debug_utils_messenger (VkInstance instance, - PFN_vkDebugUtilsMessengerCallbackEXT debug_callback, - VkDebugUtilsMessageSeverityFlagsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkAllocationCallbacks* pAllocator, - VkDebugUtilsMessengerEXT* pDebugMessenger); - -void destroy_debug_utils_messenger ( - VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator); - -static VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData); - -bool check_layers_supported (std::vector layer_names); - -} // namespace detail - -struct Instance -{ - VkInstance instance = VK_NULL_HANDLE; - VkAllocationCallbacks* allocator = VK_NULL_HANDLE; - VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE; - bool headless = false; - bool validation_enabled = false; - bool debug_callback_enabled = false; -}; - -void destroy_instance (Instance instance); // release instance resources - -class InstanceBuilder -{ - public: - detail::Expected build (); // use builder pattern - - InstanceBuilder& set_app_name (std::string app_name); - InstanceBuilder& set_engine_name (std::string engine_name); - - InstanceBuilder& set_app_version (uint32_t major, uint32_t minor, uint32_t patch); - InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch); - InstanceBuilder& set_api_version (uint32_t major, uint32_t minor, uint32_t patch); - - InstanceBuilder& add_layer (std::string app_name); - InstanceBuilder& add_extension (std::string app_name); - - InstanceBuilder& setup_validation_layers (bool enable_validation = true); - InstanceBuilder& set_headless (bool headless = false); - - InstanceBuilder& set_default_debug_messenger (); - InstanceBuilder& set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback); - InstanceBuilder& set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity); - InstanceBuilder& add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity); - InstanceBuilder& set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type); - InstanceBuilder& add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type); - - InstanceBuilder& add_validation_disable (VkValidationCheckEXT check); - InstanceBuilder& add_validation_feature_enable (VkValidationFeatureEnableEXT enable); - InstanceBuilder& add_validation_feature_disable (VkValidationFeatureDisableEXT disable); - - InstanceBuilder& set_allocator_callback (VkAllocationCallbacks* allocator); - - private: - struct InstanceInfo - { - // VkApplicationInfo - std::string app_name; - std::string engine_name; - uint32_t application_version = 0; - uint32_t engine_version = 0; - uint32_t api_version = VK_MAKE_VERSION (1, 0, 0); - - // VkInstanceCreateInfo - std::vector layers; - std::vector extensions; - VkInstanceCreateFlags flags = 0; - void* pNext = nullptr; - VkAllocationCallbacks* allocator = nullptr; - - // debug callback - PFN_vkDebugUtilsMessengerCallbackEXT debug_callback = nullptr; - VkDebugUtilsMessageSeverityFlagsEXT debug_message_severity = - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - VkDebugUtilsMessageTypeFlagsEXT debug_message_type = - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - - // validation features - std::vector disabled_validation_checks; - std::vector enabled_validation_features; - std::vector disabled_validation_features; - - // booleans - bool ignore_non_critical_issues = true; - bool enable_validation_layers = false; - bool use_debug_messenger = false; - bool headless_context = false; - } info; -}; - -} // namespace vkbs \ No newline at end of file diff --git a/src/Swapchain.cpp b/src/Swapchain.cpp deleted file mode 100644 index 26621a2..0000000 --- a/src/Swapchain.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include "Swapchain.h" - -namespace vkbs -{ -namespace detail -{ -VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector const& availableFormats) -{ - for (const auto& availableFormat : availableFormats) - { - if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) - { - return availableFormat; - } - } - - return availableFormats[0]; -} - -VkPresentModeKHR choose_swap_present_mode (std::vector const& availablePresentModes) -{ - for (const auto& availablePresentMode : availablePresentModes) - { - if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) - { - return availablePresentMode; - } - } - - return VK_PRESENT_MODE_FIFO_KHR; -} - -VkExtent2D choose_swap_extent ( - VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height) -{ - if (capabilities.currentExtent.width != UINT32_MAX) - { - return capabilities.currentExtent; - } - else - { - const int WIDTH = 800; - const int HEIGHT = 600; - VkExtent2D actualExtent = { WIDTH, HEIGHT }; - - actualExtent.width = std::max (capabilities.minImageExtent.width, - std::min (capabilities.maxImageExtent.width, actualExtent.width)); - actualExtent.height = std::max (capabilities.minImageExtent.height, - std::min (capabilities.maxImageExtent.height, actualExtent.height)); - - return actualExtent; - } -} -} // namespace detail - -SwapchainBuilder::SwapchainBuilder (Device const& device) -{ - info.device = device.device; - info.physical_device = device.physical_device; - info.surface = device.surface; -} - -detail::Expected SwapchainBuilder::build () -{ - auto surface_support = - detail::query_surface_support_details (info.physical_device.phys_device, info.surface); - if (!surface_support.has_value ()) - return detail::Error{ surface_support.error ().error_code, "can't get surface support" }; - VkSurfaceFormatKHR surfaceFormat = - detail::choose_swapchain_surface_format (surface_support.value ().formats); - VkPresentModeKHR presentMode = detail::choose_swap_present_mode (surface_support.value ().present_modes); - VkExtent2D extent = detail::choose_swap_extent (surface_support.value ().capabilities); - - uint32_t imageCount = surface_support.value ().capabilities.minImageCount + 1; - if (surface_support.value ().capabilities.maxImageCount > 0 && - imageCount > surface_support.value ().capabilities.maxImageCount) - { - imageCount = surface_support.value ().capabilities.maxImageCount; - } - - VkSwapchainCreateInfoKHR swapchain_create_info = {}; - swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchain_create_info.surface = info.surface; - - swapchain_create_info.minImageCount = imageCount; - swapchain_create_info.imageFormat = surfaceFormat.format; - swapchain_create_info.imageColorSpace = surfaceFormat.colorSpace; - swapchain_create_info.imageExtent = extent; - swapchain_create_info.imageArrayLayers = 1; - swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - - detail::QueueFamilies indices = - detail::find_queue_families (info.physical_device.phys_device, info.surface); - uint32_t queueFamilyIndices[] = { static_cast (indices.graphics), - static_cast (indices.present) }; - - if (indices.graphics != indices.present) - { - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - swapchain_create_info.queueFamilyIndexCount = 2; - swapchain_create_info.pQueueFamilyIndices = queueFamilyIndices; - } - else - { - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - } - - swapchain_create_info.preTransform = surface_support.value ().capabilities.currentTransform; - swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchain_create_info.presentMode = presentMode; - swapchain_create_info.clipped = VK_TRUE; - swapchain_create_info.oldSwapchain = info.old_swapchain; - Swapchain swapchain; - VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain); - if (res != VK_SUCCESS) - { - return detail::Error{ res, "Failed to create swapchain" }; - } - auto swapchain_images = - detail::get_vector (vkGetSwapchainImagesKHR, info.device, swapchain.swapchain); - - swapchain.image_format = surfaceFormat.format; - swapchain.extent = extent; - - return swapchain; -} -detail::Expected SwapchainBuilder::recreate (Swapchain const& swapchain) -{ - info.old_swapchain = swapchain.swapchain; - return build (); -} - -void SwapchainBuilder::destroy (Swapchain const& swapchain) -{ - vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocator); -} - - -SwapchainBuilder& SwapchainBuilder::set_desired_format (VkFormat format) -{ - info.desired_format = format; - return *this; -} -SwapchainBuilder& SwapchainBuilder::set_fallback_format (VkFormat format) -{ - info.fallback_format = format; - return *this; -} -SwapchainBuilder& SwapchainBuilder::set_desired_present_mode (VkPresentModeKHR present_mode) -{ - info.desired_present_mode = present_mode; - return *this; -} -SwapchainBuilder& SwapchainBuilder::set_fallback_present_mode (VkPresentModeKHR present_mode) -{ - info.fallback_present_mode = present_mode; - return *this; -} - - - -} // namespace vkbs \ No newline at end of file diff --git a/src/Swapchain.h b/src/Swapchain.h deleted file mode 100644 index 450ecb8..0000000 --- a/src/Swapchain.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "Util.h" -#include "Instance.h" -#include "Device.h" - -namespace vkbs -{ -namespace detail -{ -VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector const& availableFormats); -VkPresentModeKHR choose_swap_present_mode (std::vector const& availablePresentModes); -VkExtent2D choose_swap_extent (VkSurfaceCapabilitiesKHR const& capabilities); -} // namespace detail - -struct Swapchain -{ - VkDevice device = VK_NULL_HANDLE; - VkSwapchainKHR swapchain = VK_NULL_HANDLE; - VkAllocationCallbacks* allocator = VK_NULL_HANDLE; - std::vector images; - VkFormat image_format = VK_FORMAT_UNDEFINED; - VkExtent2D extent = { 0, 0 }; -}; - -class SwapchainBuilder -{ - public: - SwapchainBuilder (Device const& device); - - detail::Expected build (); - detail::Expected recreate (Swapchain const& swapchain); - void destroy (Swapchain const& swapchain); - - SwapchainBuilder& set_desired_format (VkFormat format); - SwapchainBuilder& set_fallback_format (VkFormat format); - - SwapchainBuilder& set_desired_present_mode (VkPresentModeKHR present_mode); - SwapchainBuilder& set_fallback_present_mode (VkPresentModeKHR present_mode); - - - private: - struct SwapchainInfo - { - VkDevice device = VK_NULL_HANDLE; - PhysicalDevice physical_device; - VkSurfaceKHR surface = VK_NULL_HANDLE; - VkSwapchainKHR old_swapchain = VK_NULL_HANDLE; - VkFormat desired_format = VK_FORMAT_R8G8B8A8_UNORM; - VkFormat fallback_format = VK_FORMAT_R8G8B8A8_UNORM; - VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_FIFO_KHR; - VkPresentModeKHR fallback_present_mode = VK_PRESENT_MODE_FIFO_KHR; - std::vector acceptable_present_modes; - uint32_t desired_width = 256; - uint32_t desired_height = 256; - } info; -}; -} // namespace vkbs \ No newline at end of file diff --git a/src/Util.h b/src/Util.h deleted file mode 100644 index 209cd7c..0000000 --- a/src/Util.h +++ /dev/null @@ -1,170 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#include - -namespace vkbs -{ - -namespace detail -{ - -template struct Error -{ - T error_code; - const char* msg; -}; -template class Expected -{ - public: - Expected (const E& expect) : m_expect{ expect }, m_init{ true } {} - Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {} - Expected (const Error& error) : m_error{ error }, m_init{ false } {} - Expected (Error&& error) : m_error{ std::move (error) }, m_init{ false } {} - ~Expected () { destroy (); } - Expected (Expected const& expected) : m_init (expected.m_init) - { - if (m_init) - new (&m_expect) E{ expected.m_expect }; - else - new (&m_error) Error{ expected.m_error }; - } - Expected (Expected&& expected) : m_init (expected.m_init) - { - if (m_init) - new (&m_expect) E{ std::move (expected.m_expect) }; - else - new (&m_error) Error{ std::move (expected.m_error) }; - expected.destroy (); - } - - Expected& operator= (const E& expect) - { - destroy (); - m_init = true; - new (&m_expect) E{ expect }; - return *this; - } - Expected& operator= (E&& expect) - { - destroy (); - m_init = true; - new (&m_expect) E{ std::move (expect) }; - return *this; - } - Expected& operator= (const Error& error) - { - destroy (); - m_init = false; - new (&m_error) Error{ error }; - return *this; - } - Expected& operator= (Error&& error) - { - destroy (); - m_init = false; - new (&m_error) Error{ std::move (error) }; - return *this; - } - // clang-format off - const E* operator-> () const { assert (m_init); return &m_expect; } - E* operator-> () { assert (m_init); return &m_expect; } - const E& operator* () const& { assert (m_init); return m_expect; } - E& operator* () & { assert (m_init); return m_expect; } - E&& operator* () && { assert (m_init); return std::move (m_expect); } - const E& value () const& { assert (m_init); return m_expect; } - E& value () & { assert (m_init); return m_expect; } - const E&& value () const&& { assert (m_init); return std::move (m_expect); } - E&& value () && { assert (m_init); return std::move (m_expect); } - const Error& error () const& { assert (!m_init); return m_error; } - Error& error () & { assert (!m_init); return m_error; } - const Error&& error () const&& { assert (!m_init); return std::move (m_error); } - Error&& error () && { assert (!m_init); return move (m_error); } - // clang-format on - bool has_value () const { return m_init; } - explicit operator bool () const { return m_init; } - - private: - void destroy () - { - if (m_init) - m_expect.~E (); - else - m_error.~Error (); - } - union - { - E m_expect; - Error m_error; - }; - bool m_init; -}; - -/* TODO implement operator == and operator != as friend or global */ - - -// Helper for robustly executing the two-call pattern -template -auto get_vector_init (F&& f, T init, Ts&&... ts) -> Expected, VkResult> -{ - uint32_t count = 0; - std::vector results; - VkResult err; - do - { - err = f (ts..., &count, nullptr); - if (err) - { - return Error{ err, "" }; - }; - results.resize (count, init); - err = f (ts..., &count, results.data ()); - } while (err == VK_INCOMPLETE); - if (err) - { - return Error{ err, "" }; - }; - return results; -} - -template -auto get_vector (F&& f, Ts&&... ts) -> Expected, VkResult> -{ - return get_vector_init (f, T (), ts...); -} - -template -auto get_vector_noerror (F&& f, T init, Ts&&... ts) -> std::vector -{ - uint32_t count = 0; - std::vector results; - f (ts..., &count, nullptr); - results.resize (count, init); - f (ts..., &count, results.data ()); - return results; -} -template -auto get_vector_noerror (F&& f, Ts&&... ts) -> std::vector -{ - return get_vector_noerror (f, T (), ts...); -} - -template void pNext_append (VkBaseOutStructure* chain, T* structure) -{ - if (chain == nullptr) return; - - while (chain->pNext != nullptr) - { - chain = chain->pNext; - } - chain->pNext = (VkBaseOutStructure*)structure; -} - -} // namespace detail - -} // namespace vkbs \ No newline at end of file diff --git a/src/Device.cpp b/src/VkBootstrap.cpp similarity index 54% rename from src/Device.cpp rename to src/VkBootstrap.cpp index 84ce757..61fbe6d 100644 --- a/src/Device.cpp +++ b/src/VkBootstrap.cpp @@ -1,10 +1,369 @@ -#include "Device.h" +#include "VkBootstrap.h" -#include +#include +#include -namespace vkbs +namespace vkb { +const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s) +{ + switch (s) + { + case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + return "VERBOSE"; + case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + return "ERROR"; + case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + return "WARNING"; + case VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + return "INFO"; + default: + return "UNKNOWN"; + } +} +const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s) +{ + switch (s) + { + case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT: + return "General"; + case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: + return "Validation"; + case VkDebugUtilsMessageTypeFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: + return "Performance"; + default: + return "Unknown"; + } +} + +namespace detail +{ + +VkResult create_debug_utils_messenger (VkInstance instance, + PFN_vkDebugUtilsMessengerCallbackEXT debug_callback, + VkDebugUtilsMessageSeverityFlagsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkAllocationCallbacks* pAllocator, + VkDebugUtilsMessengerEXT* pDebugMessenger) +{ + if (debug_callback == nullptr) debug_callback = default_debug_callback; + VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {}; + messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + messengerCreateInfo.pNext = nullptr; + messengerCreateInfo.messageSeverity = severity; + messengerCreateInfo.messageType = type; + messengerCreateInfo.pfnUserCallback = debug_callback; + + + auto vkCreateDebugUtilsMessengerEXT_func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr ( + instance, "vkCreateDebugUtilsMessengerEXT"); + if (vkCreateDebugUtilsMessengerEXT_func != nullptr) + { + return vkCreateDebugUtilsMessengerEXT_func (instance, &messengerCreateInfo, pAllocator, pDebugMessenger); + } + else + { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } +} + +void destroy_debug_utils_messenger ( + VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) +{ + auto vkDestroyDebugUtilsMessengerEXT_func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr ( + instance, "vkDestroyDebugUtilsMessengerEXT"); + if (vkDestroyDebugUtilsMessengerEXT_func != nullptr) + { + vkDestroyDebugUtilsMessengerEXT_func (instance, debugMessenger, pAllocator); + } +} + +VkBool32 default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) +{ + auto ms = DebugMessageSeverity (messageSeverity); + auto mt = DebugMessageType (messageType); + printf ("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage); + return VK_FALSE; +} + +bool check_layers_supported (std::vector layer_names) +{ + auto available_layers = detail::get_vector (vkEnumerateInstanceLayerProperties); + if (!available_layers.has_value ()) + { + return false; // maybe report error? + } + bool all_found = true; + for (const auto& layer_name : layer_names) + { + bool found = false; + for (const auto& layer_properties : available_layers.value ()) + { + if (strcmp (layer_name, layer_properties.layerName) == 0) + { + found = true; + break; + } + } + if (!found) all_found = false; + } + + return all_found; +} +template +void setup_pNext_chain (T& structure, std::vector& structs) +{ + structure.pNext = nullptr; + if (structs.size () <= 0) return; + for (int i = 0; i < structs.size () - 1; i++) + { + VkBaseOutStructure* cur = reinterpret_cast (&structs[i]); + cur = reinterpret_cast (&structs[i + 1]); + } + structure.pNext = &structs.at (0); +} +} // namespace detail + +void destroy_instance (Instance instance) +{ + if (instance.debug_messenger != nullptr) + detail::destroy_debug_utils_messenger (instance.instance, instance.debug_messenger, instance.allocator); + if (instance.instance != VK_NULL_HANDLE) + vkDestroyInstance (instance.instance, instance.allocator); +} + +detail::Expected InstanceBuilder::build () +{ + + VkApplicationInfo app_info = {}; + app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app_info.pNext = nullptr; + app_info.pApplicationName = info.app_name.c_str (); + app_info.applicationVersion = info.application_version; + app_info.pEngineName = info.engine_name.c_str (); + app_info.engineVersion = info.engine_version; + app_info.apiVersion = info.api_version; + + std::vector extensions; + for (auto& ext : info.extensions) + extensions.push_back (ext.c_str ()); + if (info.debug_callback != nullptr) + { + extensions.push_back ("VK_EXT_debug_utils"); + } + + if (!info.headless_context) + { + extensions.push_back (VK_KHR_SURFACE_EXTENSION_NAME); +#if defined(_WIN32) + extensions.push_back (VK_KHR_WIN32_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_ANDROID_KHR) + extensions.push_back (VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); +#elif defined(_DIRECT2DISPLAY) + extensions.push_back (VK_KHR_DISPLAY_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) + extensions.push_back (VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_XCB_KHR) + extensions.push_back (VK_KHR_XCB_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_X11_HKR) + extensions.push_back (VK_KHR_X11_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_IOS_MVK) + extensions.push_back (VK_MVK_IOS_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_MACOS_MVK) + extensions.push_back (VK_MVK_MACOS_SURFACE_EXTENSION_NAME); +#endif + } + std::vector layers; + for (auto& layer : info.layers) + layers.push_back (layer.c_str ()); + + if (info.enable_validation_layers) + { + layers.push_back ("VK_LAYER_KHRONOS_validation"); + } + bool all_layers_supported = detail::check_layers_supported (layers); + if (!all_layers_supported) + { + return detail::Error{ VK_ERROR_LAYER_NOT_PRESENT, "Not all layers supported!" }; + } + + VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {}; + if (info.use_debug_messenger) + { + messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + messengerCreateInfo.pNext = nullptr; + messengerCreateInfo.messageSeverity = info.debug_message_severity; + messengerCreateInfo.messageType = info.debug_message_type; + messengerCreateInfo.pfnUserCallback = info.debug_callback; + info.pNext_elements.push_back (reinterpret_cast (&messengerCreateInfo)); + } + + VkValidationFeaturesEXT features{}; + if (info.enabled_validation_features.size () != 0 || info.disabled_validation_features.size ()) + { + features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; + features.pNext = nullptr; + features.enabledValidationFeatureCount = info.enabled_validation_features.size (); + features.pEnabledValidationFeatures = info.enabled_validation_features.data (); + features.disabledValidationFeatureCount = info.disabled_validation_features.size (); + features.pDisabledValidationFeatures = info.disabled_validation_features.data (); + info.pNext_elements.push_back (reinterpret_cast (&features)); + } + + VkValidationFlagsEXT checks{}; + if (info.disabled_validation_checks.size () != 0) + { + checks.sType = VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT; + checks.pNext = nullptr; + checks.disabledValidationCheckCount = info.disabled_validation_checks.size (); + checks.pDisabledValidationChecks = info.disabled_validation_checks.data (); + info.pNext_elements.push_back (reinterpret_cast (&checks)); + } + + VkInstanceCreateInfo instance_create_info = {}; + instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + detail::setup_pNext_chain (instance_create_info, info.pNext_elements); + instance_create_info.flags = info.flags; + instance_create_info.pApplicationInfo = &app_info; + instance_create_info.enabledExtensionCount = static_cast (extensions.size ()); + instance_create_info.ppEnabledExtensionNames = extensions.data (); + instance_create_info.enabledLayerCount = static_cast (layers.size ()); + instance_create_info.ppEnabledLayerNames = layers.data (); + + Instance instance; + VkResult res = vkCreateInstance (&instance_create_info, nullptr, &instance.instance); + if (res != VK_SUCCESS) return detail::Error{ res, "Failed to create instance" }; + + if (info.use_debug_messenger) + { + res = detail::create_debug_utils_messenger (instance.instance, + info.debug_callback, + info.debug_message_severity, + info.debug_message_type, + info.allocator, + &instance.debug_messenger); + if (res != VK_SUCCESS) + { + return detail::Error{ res, "Failed to create setup debug callback" }; + } + } + + if (info.headless_context) + { + instance.headless = true; + } + return instance; +} + +InstanceBuilder& InstanceBuilder::set_app_name (std::string app_name) +{ + info.app_name = app_name; + return *this; +} +InstanceBuilder& InstanceBuilder::set_engine_name (std::string engine_name) +{ + info.engine_name = engine_name; + return *this; +} + +InstanceBuilder& InstanceBuilder::set_app_version (uint32_t major, uint32_t minor, uint32_t patch) +{ + info.application_version = VK_MAKE_VERSION (major, minor, patch); + return *this; +} +InstanceBuilder& InstanceBuilder::set_engine_version (uint32_t major, uint32_t minor, uint32_t patch) +{ + info.engine_version = VK_MAKE_VERSION (major, minor, patch); + return *this; +} +InstanceBuilder& InstanceBuilder::set_api_version (uint32_t major, uint32_t minor, uint32_t patch) +{ + info.api_version = VK_MAKE_VERSION (major, minor, patch); + return *this; +} + +InstanceBuilder& InstanceBuilder::add_layer (std::string layer_name) +{ + info.layers.push_back (layer_name); + return *this; +} +InstanceBuilder& InstanceBuilder::add_extension (std::string extension_name) +{ + info.extensions.push_back (extension_name); + return *this; +} + +InstanceBuilder& InstanceBuilder::setup_validation_layers (bool enable_validation) +{ + info.enable_validation_layers = enable_validation; + return *this; +} +InstanceBuilder& InstanceBuilder::set_default_debug_messenger () +{ + info.use_debug_messenger = true; + info.debug_callback = detail::default_debug_callback; + return *this; +} + +InstanceBuilder& InstanceBuilder::set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback) +{ + info.use_debug_messenger = true; + info.debug_callback = callback; + return *this; +} +InstanceBuilder& InstanceBuilder::set_headless (bool headless) +{ + info.headless_context = headless; + return *this; +} + +InstanceBuilder& InstanceBuilder::set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity) +{ + info.debug_message_severity = severity; + return *this; +} +InstanceBuilder& InstanceBuilder::add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity) +{ + info.debug_message_severity = info.debug_message_severity | severity; + return *this; +} +InstanceBuilder& InstanceBuilder::set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type) +{ + info.debug_message_type = type; + return *this; +} +InstanceBuilder& InstanceBuilder::add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type) +{ + info.debug_message_type = info.debug_message_type | type; + return *this; +} + +InstanceBuilder& InstanceBuilder::add_validation_disable (VkValidationCheckEXT check) +{ + info.disabled_validation_checks.push_back (check); + return *this; +} +InstanceBuilder& InstanceBuilder::add_validation_feature_enable (VkValidationFeatureEnableEXT enable) +{ + info.enabled_validation_features.push_back (enable); + return *this; +} +InstanceBuilder& InstanceBuilder::add_validation_feature_disable (VkValidationFeatureDisableEXT disable) +{ + info.disabled_validation_features.push_back (disable); + return *this; +} + +InstanceBuilder& InstanceBuilder::set_allocator_callback (VkAllocationCallbacks* allocator) +{ + info.allocator = allocator; + return *this; +} + namespace detail { Expected query_surface_support_details ( @@ -428,12 +787,12 @@ detail::Expected DeviceBuilder::build () std::vector extensions; for (auto& ext : info.extensions) extensions.push_back (ext.c_str ()); - if (info.physical_device.surface != VK_NULL_HANDLE) - extensions.push_back ({ VK_KHR_SWAPCHAIN_EXTENSION_NAME }); + // if (info.physical_device.surface != VK_NULL_HANDLE) + // extensions.push_back ({ VK_KHR_SWAPCHAIN_EXTENSION_NAME }); VkDeviceCreateInfo device_create_info = {}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_create_info.pNext = info.pNext_chain; + detail::setup_pNext_chain (device_create_info, info.pNext_chain); device_create_info.flags = info.flags; device_create_info.queueCreateInfoCount = static_cast (queueCreateInfos.size ()); device_create_info.pQueueCreateInfos = queueCreateInfos.data (); @@ -453,10 +812,7 @@ detail::Expected DeviceBuilder::build () template DeviceBuilder& DeviceBuilder::add_pNext (T* structure) { - if (info.pNext_chain == nullptr) - info.pNext_chain = (VkBaseOutStructure*)structure; - else - detail::pNext_append (info.pNext_chain, structure); + info.pNext_chain.push_back (reinterpret_cast (structure)); return *this; } @@ -505,5 +861,162 @@ detail::Expected get_queue_sparse (Device const& device, uint return detail::get_queue (device, device.physical_device.queue_family_properties.sparse, index); } +namespace detail +{ +VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector const& availableFormats) +{ + for (const auto& availableFormat : availableFormats) + { + if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + return availableFormat; + } + } -} // namespace vkbs \ No newline at end of file + return availableFormats[0]; +} + +VkPresentModeKHR choose_swap_present_mode (std::vector const& availablePresentModes) +{ + for (const auto& availablePresentMode : availablePresentModes) + { + if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) + { + return availablePresentMode; + } + } + + return VK_PRESENT_MODE_FIFO_KHR; +} + +VkExtent2D choose_swap_extent ( + VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height) +{ + if (capabilities.currentExtent.width != UINT32_MAX) + { + return capabilities.currentExtent; + } + else + { + const int WIDTH = 800; + const int HEIGHT = 600; + VkExtent2D actualExtent = { WIDTH, HEIGHT }; + + actualExtent.width = std::max (capabilities.minImageExtent.width, + std::min (capabilities.maxImageExtent.width, actualExtent.width)); + actualExtent.height = std::max (capabilities.minImageExtent.height, + std::min (capabilities.maxImageExtent.height, actualExtent.height)); + + return actualExtent; + } +} +} // namespace detail + +SwapchainBuilder::SwapchainBuilder (Device const& device) +{ + info.device = device.device; + info.physical_device = device.physical_device; + info.surface = device.surface; +} + +detail::Expected SwapchainBuilder::build () +{ + auto surface_support = + detail::query_surface_support_details (info.physical_device.phys_device, info.surface); + if (!surface_support.has_value ()) + return detail::Error{ surface_support.error ().error_code, "can't get surface support" }; + VkSurfaceFormatKHR surfaceFormat = + detail::choose_swapchain_surface_format (surface_support.value ().formats); + VkPresentModeKHR presentMode = detail::choose_swap_present_mode (surface_support.value ().present_modes); + VkExtent2D extent = detail::choose_swap_extent ( + surface_support.value ().capabilities, info.desired_width, info.desired_height); + + uint32_t imageCount = surface_support.value ().capabilities.minImageCount + 1; + if (surface_support.value ().capabilities.maxImageCount > 0 && + imageCount > surface_support.value ().capabilities.maxImageCount) + { + imageCount = surface_support.value ().capabilities.maxImageCount; + } + + VkSwapchainCreateInfoKHR swapchain_create_info = {}; + swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchain_create_info.surface = info.surface; + + swapchain_create_info.minImageCount = imageCount; + swapchain_create_info.imageFormat = surfaceFormat.format; + swapchain_create_info.imageColorSpace = surfaceFormat.colorSpace; + swapchain_create_info.imageExtent = extent; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + detail::QueueFamilies indices = + detail::find_queue_families (info.physical_device.phys_device, info.surface); + uint32_t queueFamilyIndices[] = { static_cast (indices.graphics), + static_cast (indices.present) }; + + if (indices.graphics != indices.present) + { + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchain_create_info.queueFamilyIndexCount = 2; + swapchain_create_info.pQueueFamilyIndices = queueFamilyIndices; + } + else + { + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + } + + swapchain_create_info.preTransform = surface_support.value ().capabilities.currentTransform; + swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchain_create_info.presentMode = presentMode; + swapchain_create_info.clipped = VK_TRUE; + swapchain_create_info.oldSwapchain = info.old_swapchain; + Swapchain swapchain; + VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain); + if (res != VK_SUCCESS) + { + return detail::Error{ res, "Failed to create swapchain" }; + } + auto swapchain_images = + detail::get_vector (vkGetSwapchainImagesKHR, info.device, swapchain.swapchain); + + swapchain.image_format = surfaceFormat.format; + swapchain.extent = extent; + + return swapchain; +} +detail::Expected SwapchainBuilder::recreate (Swapchain const& swapchain) +{ + info.old_swapchain = swapchain.swapchain; + return build (); +} + +void SwapchainBuilder::destroy (Swapchain const& swapchain) +{ + vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocator); +} + + +SwapchainBuilder& SwapchainBuilder::set_desired_format (VkFormat format) +{ + info.desired_format = format; + return *this; +} +SwapchainBuilder& SwapchainBuilder::set_fallback_format (VkFormat format) +{ + info.fallback_format = format; + return *this; +} +SwapchainBuilder& SwapchainBuilder::set_desired_present_mode (VkPresentModeKHR present_mode) +{ + info.desired_present_mode = present_mode; + return *this; +} +SwapchainBuilder& SwapchainBuilder::set_fallback_present_mode (VkPresentModeKHR present_mode) +{ + info.fallback_present_mode = present_mode; + return *this; +} + + + +} // namespace vkb \ No newline at end of file diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index 61bd673..f4f0788 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -1,5 +1,482 @@ #pragma once -#include "Instance.h" -#include "Device.h" -#include "Swapchain.h" \ No newline at end of file +#include + +#include +#include +#include + +#include + +namespace vkb +{ + +namespace detail +{ + +template struct Error +{ + T error_code; + const char* msg; +}; +template class Expected +{ + public: + Expected (const E& expect) : m_expect{ expect }, m_init{ true } {} + Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {} + Expected (const Error& error) : m_error{ error }, m_init{ false } {} + Expected (Error&& error) : m_error{ std::move (error) }, m_init{ false } {} + ~Expected () { destroy (); } + Expected (Expected const& expected) : m_init (expected.m_init) + { + if (m_init) + new (&m_expect) E{ expected.m_expect }; + else + new (&m_error) Error{ expected.m_error }; + } + Expected (Expected&& expected) : m_init (expected.m_init) + { + if (m_init) + new (&m_expect) E{ std::move (expected.m_expect) }; + else + new (&m_error) Error{ std::move (expected.m_error) }; + expected.destroy (); + } + + Expected& operator= (const E& expect) + { + destroy (); + m_init = true; + new (&m_expect) E{ expect }; + return *this; + } + Expected& operator= (E&& expect) + { + destroy (); + m_init = true; + new (&m_expect) E{ std::move (expect) }; + return *this; + } + Expected& operator= (const Error& error) + { + destroy (); + m_init = false; + new (&m_error) Error{ error }; + return *this; + } + Expected& operator= (Error&& error) + { + destroy (); + m_init = false; + new (&m_error) Error{ std::move (error) }; + return *this; + } + // clang-format off + const E* operator-> () const { assert (m_init); return &m_expect; } + E* operator-> () { assert (m_init); return &m_expect; } + const E& operator* () const& { assert (m_init); return m_expect; } + E& operator* () & { assert (m_init); return m_expect; } + E&& operator* () && { assert (m_init); return std::move (m_expect); } + const E& value () const& { assert (m_init); return m_expect; } + E& value () & { assert (m_init); return m_expect; } + const E&& value () const&& { assert (m_init); return std::move (m_expect); } + E&& value () && { assert (m_init); return std::move (m_expect); } + const Error& error () const& { assert (!m_init); return m_error; } + Error& error () & { assert (!m_init); return m_error; } + const Error&& error () const&& { assert (!m_init); return std::move (m_error); } + Error&& error () && { assert (!m_init); return move (m_error); } + // clang-format on + bool has_value () const { return m_init; } + explicit operator bool () const { return m_init; } + + private: + void destroy () + { + if (m_init) + m_expect.~E (); + else + m_error.~Error (); + } + union + { + E m_expect; + Error m_error; + }; + bool m_init; +}; + +/* TODO implement operator == and operator != as friend or global */ + + +// Helper for robustly executing the two-call pattern +template +auto get_vector_init (F&& f, T init, Ts&&... ts) -> Expected, VkResult> +{ + uint32_t count = 0; + std::vector results; + VkResult err; + do + { + err = f (ts..., &count, nullptr); + if (err) + { + return Error{ err, "" }; + }; + results.resize (count, init); + err = f (ts..., &count, results.data ()); + } while (err == VK_INCOMPLETE); + if (err) + { + return Error{ err, "" }; + }; + return results; +} + +template +auto get_vector (F&& f, Ts&&... ts) -> Expected, VkResult> +{ + return get_vector_init (f, T (), ts...); +} + +template +auto get_vector_noerror (F&& f, T init, Ts&&... ts) -> std::vector +{ + uint32_t count = 0; + std::vector results; + f (ts..., &count, nullptr); + results.resize (count, init); + f (ts..., &count, results.data ()); + return results; +} +template +auto get_vector_noerror (F&& f, Ts&&... ts) -> std::vector +{ + return get_vector_noerror (f, T (), ts...); +} + +VkResult create_debug_utils_messenger (VkInstance instance, + PFN_vkDebugUtilsMessengerCallbackEXT debug_callback, + VkDebugUtilsMessageSeverityFlagsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkAllocationCallbacks* pAllocator, + VkDebugUtilsMessengerEXT* pDebugMessenger); + +void destroy_debug_utils_messenger ( + VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator); + +static VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData); + +bool check_layers_supported (std::vector layer_names); + +} // namespace detail + +const char* DebugMessageSeverity (VkDebugUtilsMessageSeverityFlagBitsEXT s); +const char* DebugMessageType (VkDebugUtilsMessageTypeFlagsEXT s); + + +struct Instance +{ + VkInstance instance = VK_NULL_HANDLE; + VkAllocationCallbacks* allocator = VK_NULL_HANDLE; + VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE; + bool headless = false; + bool validation_enabled = false; + bool debug_callback_enabled = false; +}; + +void destroy_instance (Instance instance); // release instance resources + +class InstanceBuilder +{ + public: + detail::Expected build (); // use builder pattern + + InstanceBuilder& set_app_name (std::string app_name); + InstanceBuilder& set_engine_name (std::string engine_name); + + InstanceBuilder& set_app_version (uint32_t major, uint32_t minor, uint32_t patch); + InstanceBuilder& set_engine_version (uint32_t major, uint32_t minor, uint32_t patch); + InstanceBuilder& set_api_version (uint32_t major, uint32_t minor, uint32_t patch); + + InstanceBuilder& add_layer (std::string app_name); + InstanceBuilder& add_extension (std::string app_name); + + InstanceBuilder& setup_validation_layers (bool enable_validation = true); + InstanceBuilder& set_headless (bool headless = false); + + InstanceBuilder& set_default_debug_messenger (); + InstanceBuilder& set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback); + InstanceBuilder& set_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity); + InstanceBuilder& add_debug_messenger_severity (VkDebugUtilsMessageSeverityFlagsEXT severity); + InstanceBuilder& set_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type); + InstanceBuilder& add_debug_messenger_type (VkDebugUtilsMessageTypeFlagsEXT type); + + InstanceBuilder& add_validation_disable (VkValidationCheckEXT check); + InstanceBuilder& add_validation_feature_enable (VkValidationFeatureEnableEXT enable); + InstanceBuilder& add_validation_feature_disable (VkValidationFeatureDisableEXT disable); + + InstanceBuilder& set_allocator_callback (VkAllocationCallbacks* allocator); + + private: + struct InstanceInfo + { + // VkApplicationInfo + std::string app_name; + std::string engine_name; + uint32_t application_version = 0; + uint32_t engine_version = 0; + uint32_t api_version = VK_MAKE_VERSION (1, 0, 0); + + // VkInstanceCreateInfo + std::vector layers; + std::vector extensions; + VkInstanceCreateFlags flags = 0; + std::vector pNext_elements; + VkAllocationCallbacks* allocator = nullptr; + + // debug callback + PFN_vkDebugUtilsMessengerCallbackEXT debug_callback = nullptr; + VkDebugUtilsMessageSeverityFlagsEXT debug_message_severity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + VkDebugUtilsMessageTypeFlagsEXT debug_message_type = + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + + // validation features + std::vector disabled_validation_checks; + std::vector enabled_validation_features; + std::vector disabled_validation_features; + + // booleans + bool ignore_non_critical_issues = true; + bool enable_validation_layers = false; + bool use_debug_messenger = false; + bool headless_context = false; + } info; +}; + +namespace detail +{ + +struct SurfaceSupportDetails +{ + VkSurfaceCapabilitiesKHR capabilities; + std::vector formats; + std::vector present_modes; +}; + +Expected query_surface_support_details ( + VkPhysicalDevice phys_device, VkSurfaceKHR surface); + +struct QueueFamilies +{ + int graphics = -1; + int present = -1; + int transfer = -1; + int compute = -1; + int sparse = -1; + uint32_t count_graphics = 0; + uint32_t count_transfer = 0; + uint32_t count_compute = 0; + uint32_t count_sparse = 0; +}; + +VkFormat find_supported_format (VkPhysicalDevice physical_device, + const std::vector& candidates, + VkImageTiling tiling, + VkFormatFeatureFlags features); + +bool check_device_extension_support (VkPhysicalDevice device, std::vector extensions); + +detail::QueueFamilies find_queue_families (VkPhysicalDevice physDevice, VkSurfaceKHR windowSurface); + +bool supports_features (VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeatures requested); + +} // namespace detail + +// ---- Physical Device ---- // + +struct PhysicalDevice +{ + VkPhysicalDevice phys_device = VK_NULL_HANDLE; + VkSurfaceKHR surface = VK_NULL_HANDLE; + + VkPhysicalDeviceProperties physical_device_properties{}; + VkPhysicalDeviceFeatures physical_device_features{}; + VkPhysicalDeviceMemoryProperties memory_properties{}; + + detail::QueueFamilies queue_family_properties; +}; + +namespace detail +{ +void populate_physical_device_details (PhysicalDevice physical_device); +} // namespace detail + +struct PhysicalDeviceSelector +{ + public: + PhysicalDeviceSelector (Instance instance); + + detail::Expected select (); + + PhysicalDeviceSelector& set_surface (VkSurfaceKHR instance); + + PhysicalDeviceSelector& prefer_discrete (bool prefer_discrete = true); + PhysicalDeviceSelector& prefer_integrated (bool prefer_integrated = true); + PhysicalDeviceSelector& allow_fallback (bool fallback = true); + + PhysicalDeviceSelector& require_present (bool require = true); + PhysicalDeviceSelector& require_dedicated_transfer_queue (); + PhysicalDeviceSelector& require_dedicated_compute_queue (); + + PhysicalDeviceSelector& required_device_memory_size (VkDeviceSize size); + PhysicalDeviceSelector& desired_device_memory_size (VkDeviceSize size); + + PhysicalDeviceSelector& add_required_extension (std::string extension); + PhysicalDeviceSelector& add_desired_extension (std::string extension); + + PhysicalDeviceSelector& set_desired_version (uint32_t major, uint32_t minor); + PhysicalDeviceSelector& set_minimum_version (uint32_t major = 1, uint32_t minor = 0); + + PhysicalDeviceSelector& set_required_features (VkPhysicalDeviceFeatures features); + + private: + struct PhysicalDeviceInfo + { + VkInstance instance = VK_NULL_HANDLE; + VkSurfaceKHR surface = VK_NULL_HANDLE; + bool headless = false; + } info; + + struct SelectionCriteria + { + bool prefer_discrete = true; + bool prefer_integrated = false; + bool allow_fallback = true; + bool require_present = true; + bool require_dedicated_transfer_queue = false; + bool require_dedicated_compute_queue = false; + VkDeviceSize required_mem_size = 0; + VkDeviceSize desired_mem_size = 0; + + std::vector required_extensions; + std::vector desired_extensions; + + uint32_t required_version = VK_MAKE_VERSION (1, 0, 0); + uint32_t desired_version = VK_MAKE_VERSION (1, 0, 0); + + VkPhysicalDeviceFeatures required_features{}; + + } criteria; + + enum class Suitable + { + yes, + partial, + no + }; + + Suitable is_device_suitable (VkPhysicalDevice phys_device); +}; + +// ---- Device ---- // + +struct Device +{ + VkDevice device = VK_NULL_HANDLE; + VkAllocationCallbacks* allocator = VK_NULL_HANDLE; + PhysicalDevice physical_device; + VkSurfaceKHR surface = VK_NULL_HANDLE; +}; + +void destroy_device (Device device); + +class DeviceBuilder +{ + public: + DeviceBuilder (PhysicalDevice device); + detail::Expected build (); + + template DeviceBuilder& add_pNext (T* structure); + + private: + struct DeviceInfo + { + VkDeviceCreateFlags flags; + std::vector pNext_chain; + VkAllocationCallbacks* allocator = VK_NULL_HANDLE; + PhysicalDevice physical_device; + std::vector extensions; + } info; +}; + +// ---- Queue ---- // + +namespace detail +{ +VkQueue get_queue (Device const& device, uint32_t family, uint32_t index = 0); +} + +detail::Expected get_queue_present (Device const& device); +detail::Expected get_queue_graphics (Device const& device, uint32_t index = 0); +detail::Expected get_queue_compute (Device const& device, uint32_t index = 0); +detail::Expected get_queue_transfer (Device const& device, uint32_t index = 0); +detail::Expected get_queue_sparse (Device const& device, uint32_t index = 0); + + +namespace detail +{ +VkSurfaceFormatKHR choose_swapchain_surface_format (std::vector const& availableFormats); +VkPresentModeKHR choose_swap_present_mode (std::vector const& availablePresentModes); +VkExtent2D choose_swap_extent ( + VkSurfaceCapabilitiesKHR const& capabilities, uint32_t desired_width, uint32_t desired_height); +} // namespace detail + +struct Swapchain +{ + VkDevice device = VK_NULL_HANDLE; + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + VkAllocationCallbacks* allocator = VK_NULL_HANDLE; + std::vector images; + VkFormat image_format = VK_FORMAT_UNDEFINED; + VkExtent2D extent = { 0, 0 }; +}; + +class SwapchainBuilder +{ + public: + SwapchainBuilder (Device const& device); + + detail::Expected build (); + detail::Expected recreate (Swapchain const& swapchain); + void destroy (Swapchain const& swapchain); + + SwapchainBuilder& set_desired_format (VkFormat format); + SwapchainBuilder& set_fallback_format (VkFormat format); + + SwapchainBuilder& set_desired_present_mode (VkPresentModeKHR present_mode); + SwapchainBuilder& set_fallback_present_mode (VkPresentModeKHR present_mode); + + + private: + struct SwapchainInfo + { + VkDevice device = VK_NULL_HANDLE; + PhysicalDevice physical_device; + VkSurfaceKHR surface = VK_NULL_HANDLE; + VkSwapchainKHR old_swapchain = VK_NULL_HANDLE; + VkFormat desired_format = VK_FORMAT_R8G8B8A8_UNORM; + VkFormat fallback_format = VK_FORMAT_R8G8B8A8_UNORM; + VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_FIFO_KHR; + VkPresentModeKHR fallback_present_mode = VK_PRESENT_MODE_FIFO_KHR; + std::vector acceptable_present_modes; + uint32_t desired_width = 256; + uint32_t desired_height = 256; + } info; +}; + +} // namespace vkb \ No newline at end of file diff --git a/tests/run_tests.cpp b/tests/run_tests.cpp index 747bb2a..bc4bc16 100644 --- a/tests/run_tests.cpp +++ b/tests/run_tests.cpp @@ -1,10 +1,15 @@ #include +#include +#include + #include "VkBootstrap.h" #define GLFW_INCLUDE_VULKAN #include "GLFW/glfw3.h" +#include "catch2/catch.hpp" + GLFWwindow* create_window_glfw () { glfwInit (); @@ -30,27 +35,34 @@ int test_happy_path () { auto window = create_window_glfw (); - vkbs::InstanceBuilder instance_builder; + vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.set_default_debug_messenger ().build (); - if (!instance_ret) return -1; // couldn't make instance - vkbs::Instance instance = instance_ret.value (); + if (!instance_ret) + { + std::cout << instance_ret.error ().msg << "\n"; + return -1; // couldn't make instance + } + vkb::Instance instance = instance_ret.value (); + printf ("made instance\n"); auto surface = create_surface_glfw (instance.instance, window); - vkbs::PhysicalDeviceSelector phys_device_selector (instance); + vkb::PhysicalDeviceSelector phys_device_selector (instance); auto phys_device_ret = phys_device_selector.set_surface (surface).select (); if (!phys_device_ret) return -2; // couldn't select physical device - vkbs::PhysicalDevice physical_device = phys_device_ret.value (); + vkb::PhysicalDevice physical_device = phys_device_ret.value (); + printf ("made physical device\n"); - vkbs::DeviceBuilder device_builder (physical_device); + vkb::DeviceBuilder device_builder (physical_device); auto device_ret = device_builder.build (); - if (!device_ret) return -3; // couldn't create device - vkbs::Device device = device_ret.value (); + if (!device_ret) return -1; // couldn't create device + vkb::Device device = device_ret.value (); + printf ("made device\n"); // possible swapchain creation... - vkbs::destroy_device (device); - vkbs::destroy_instance (instance); + vkb::destroy_device (device); + vkb::destroy_instance (instance); destroy_window_glfw (window); return 0; } @@ -59,7 +71,7 @@ int test_happy_path () int test_instance_basic () { - vkbs::InstanceBuilder builder; + vkb::InstanceBuilder builder; auto instance_ret = builder.setup_validation_layers () @@ -68,8 +80,8 @@ int test_instance_basic () VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) -> VkBool32 { - auto ms = vkbs::DebugMessageSeverity (messageSeverity); - auto mt = vkbs::DebugMessageType (messageType); + auto ms = vkb::DebugMessageSeverity (messageSeverity); + auto mt = vkb::DebugMessageType (messageType); printf ("[%s: %s](user defined)\n%s\n", ms, mt, pCallbackData->pMessage); return VK_FALSE; }) @@ -85,7 +97,7 @@ int test_instance_basic () int test_instance_headless () { - vkbs::InstanceBuilder builder; + vkb::InstanceBuilder builder; auto instance_ret = builder.setup_validation_layers () .set_headless () @@ -104,13 +116,13 @@ int test_instance_headless () int test_physical_device_selection () { - vkbs::InstanceBuilder instance_builder; + vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.set_default_debug_messenger ().build (); auto instance = instance_ret.value (); auto window = create_window_glfw (); auto surface = create_surface_glfw (instance.instance, window); - vkbs::PhysicalDeviceSelector selector (instance); + vkb::PhysicalDeviceSelector selector (instance); auto phys_dev_ret = selector.set_surface (surface) .add_desired_extension (VK_KHR_MULTIVIEW_EXTENSION_NAME) .add_required_extension (VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME) @@ -121,24 +133,24 @@ int test_physical_device_selection () { return -1; } - vkbs::destroy_instance (instance); + vkb::destroy_instance (instance); destroy_window_glfw (window); return 0; } int test_device_creation () { - vkbs::InstanceBuilder instance_builder; + vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.set_default_debug_messenger ().build (); auto instance = instance_ret.value (); auto window = create_window_glfw (); auto surface = create_surface_glfw (instance.instance, window); - vkbs::PhysicalDeviceSelector selector (instance); + vkb::PhysicalDeviceSelector selector (instance); auto phys_dev_ret = selector.set_surface (surface).select (); auto phys_dev = phys_dev_ret.value (); - vkbs::DeviceBuilder device_builder (phys_dev); + vkb::DeviceBuilder device_builder (phys_dev); auto dev_ret = device_builder.build (); if (!dev_ret.has_value ()) { @@ -146,8 +158,8 @@ int test_device_creation () return -1; } - vkbs::destroy_device (dev_ret.value ()); - vkbs::destroy_instance (instance); + vkb::destroy_device (dev_ret.value ()); + vkb::destroy_instance (instance); destroy_window_glfw (window); return 0; } diff --git a/tests/test.cpp b/tests/test.cpp new file mode 100644 index 0000000..f4e4ac9 --- /dev/null +++ b/tests/test.cpp @@ -0,0 +1,11 @@ + +#include + +#define GLFW_INCLUDE_VULKAN +#include "GLFW/glfw3.h" + +#include + +#include "VkBootstrap.h" + +#define CATCH_CONFIG_MAIN