diff --git a/CMakeLists.txt b/CMakeLists.txt index 03e0302..939ee7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,26 +16,26 @@ option(VK_BOOTSTRAP_TEST "Test Vk-Bootstrap with glfw and Catch2" OFF) if (VK_BOOTSTRAP_TEST) -set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) -set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) -set(GLFW_INSTALL OFF CACHE BOOL "" FORCE) -set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) -add_subdirectory(ext/glfw) -add_subdirectory(ext/Catch2) + set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) + set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) + set(GLFW_INSTALL OFF CACHE BOOL "" FORCE) + set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) + add_subdirectory(ext/glfw) + add_subdirectory(ext/Catch2) -add_executable(vk-bootstrap-test tests/run_tests.cpp) + 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) + target_link_libraries(vk-bootstrap-test vk-bootstrap) + target_link_libraries(vk-bootstrap-test glfw) + target_link_libraries(vk-bootstrap-test Catch2) -add_executable(vk-bootstrap-triangle example/triangle.cpp) -target_link_libraries(vk-bootstrap-triangle vk-bootstrap) -target_link_libraries(vk-bootstrap-triangle glfw) + add_executable(vk-bootstrap-triangle example/triangle.cpp) + target_link_libraries(vk-bootstrap-triangle vk-bootstrap) + target_link_libraries(vk-bootstrap-triangle glfw) -add_custom_command( - TARGET vk-bootstrap-triangle POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/example/shaders ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR} -) + add_custom_command( + TARGET vk-bootstrap-triangle POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/example/shaders ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR} + ) endif() \ No newline at end of file diff --git a/example/triangle.cpp b/example/triangle.cpp index b38a4c0..45626c1 100644 --- a/example/triangle.cpp +++ b/example/triangle.cpp @@ -42,8 +42,7 @@ int device_initialization (Init& init) { init.window = create_window_glfw (false); vkb::InstanceBuilder instance_builder; - auto instance_ret = - instance_builder.set_default_debug_messenger ().check_and_setup_validation_layers ().build (); + auto instance_ret = instance_builder.use_default_debug_messenger ().request_validation_layers ().build (); if (!instance_ret) { std::cout << static_cast (instance_ret.error ().type) << "\n"; } diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index c12ea24..9183b93 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -158,6 +158,31 @@ const char* validation_layer_name = "VK_LAYER_KHRONOS_validation"; } // namespace detail +SystemInfo::SystemInfo () { + auto available_extensions = + detail::get_vector (vkEnumerateInstanceExtensionProperties, nullptr); + if (available_extensions.has_value ()) { + this->available_extensions = available_extensions.value (); + } + for (auto& ext : this->available_extensions) + if (ext.extensionName == VK_EXT_DEBUG_UTILS_EXTENSION_NAME) + debug_messenger_available = true; + + auto available_layers = detail::get_vector (vkEnumerateInstanceLayerProperties); + if (available_layers.has_value ()) { + available_layers = available_layers.value (); + } + for (auto& layer : this->available_layers) + if (layer.layerName == detail::validation_layer_name) validation_layers_available = true; +} +bool SystemInfo::is_extension_available (const char* extension_name) { + if (!extension_name) return false; + return detail::check_extension_supported (available_extensions, extension_name); +} +bool SystemInfo::is_layer_available (const char* layer_name) { + if (!layer_name) return false; + return detail::check_layer_supported (available_layers, layer_name); +} void destroy_instance (Instance instance) { if (instance.instance != VK_NULL_HANDLE) { if (instance.debug_messenger != nullptr) @@ -165,17 +190,8 @@ void destroy_instance (Instance instance) { vkDestroyInstance (instance.instance, nullptr); } } -InstanceBuilder::InstanceBuilder () { - auto available_extensions = - detail::get_vector (vkEnumerateInstanceExtensionProperties, nullptr); - if (available_extensions.has_value ()) { - system.available_extensions = available_extensions.value (); - } - auto available_layers = detail::get_vector (vkEnumerateInstanceLayerProperties); - if (available_layers.has_value ()) { - system.available_layers = available_layers.value (); - } -} + +SystemInfo InstanceBuilder::get_system_info () { return system; } detail::Expected> InstanceBuilder::build () { @@ -317,18 +333,18 @@ InstanceBuilder& InstanceBuilder::must_enable_layer (const char* layer_name) { info.layers.push_back (layer_name); return *this; } -InstanceBuilder& InstanceBuilder::must_enable_extension (const char* extension_name) { - if (!extension_name) return *this; - info.extensions.push_back (extension_name); - return *this; -} -InstanceBuilder& InstanceBuilder::check_and_add_layer (const char* layer_name) { +InstanceBuilder& InstanceBuilder::request_layer (const char* layer_name) { if (!layer_name) return *this; if (detail::check_layer_supported (system.available_layers, layer_name)) info.layers.push_back (layer_name); return *this; } -InstanceBuilder& InstanceBuilder::check_and_add_extension (const char* extension_name) { +InstanceBuilder& InstanceBuilder::must_enable_extension (const char* extension_name) { + if (!extension_name) return *this; + info.extensions.push_back (extension_name); + return *this; +} +InstanceBuilder& InstanceBuilder::request_extension (const char* extension_name) { if (!extension_name) return *this; if (detail::check_extension_supported (system.available_extensions, extension_name)) info.extensions.push_back (extension_name); @@ -338,14 +354,14 @@ InstanceBuilder& InstanceBuilder::must_enable_validation_layers (bool enable_val info.enable_validation_layers = enable_validation; return *this; } -InstanceBuilder& InstanceBuilder::check_and_setup_validation_layers (bool enable_validation) { - bool available = +InstanceBuilder& InstanceBuilder::request_validation_layers (bool enable_validation) { + info.enable_validation_layers = + enable_validation && detail::check_extension_supported (system.available_extensions, detail::validation_layer_name); - info.enable_validation_layers = available; return *this; } -InstanceBuilder& InstanceBuilder::set_default_debug_messenger () { +InstanceBuilder& InstanceBuilder::use_default_debug_messenger () { info.use_debug_messenger = true; info.debug_callback = default_debug_callback; return *this; diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index d571464..bd90eec 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -97,6 +97,20 @@ template class Expected { /* TODO implement operator == and operator != as friend or global */ } // namespace detail + +struct SystemInfo { + SystemInfo (); + // Returns true if a layer is available + bool is_layer_available (const char* layer_name); + // Returns true if an extension is available + bool is_extension_available (const char* extension_name); + + std::vector available_layers; + std::vector available_extensions; + bool validation_layers_available = false; + bool debug_messenger_available = false; +}; + enum class InstanceError { failed_create_instance, failed_create_debug_messenger, @@ -124,8 +138,10 @@ void destroy_instance (Instance instance); // release instance resources class InstanceBuilder { public: - InstanceBuilder (); // automatically gets available layers and extensions. + // contains useful information about the available vulkan capabilities, like layers and instance extensions. + SystemInfo get_system_info (); + // Create a VkInstance. Return an error if it failed. detail::Expected> build (); // Sets the name of the application. Defaults to "" if none is provided. @@ -141,23 +157,25 @@ class InstanceBuilder { // Loads the specified layer if it is available. - InstanceBuilder& check_and_add_layer (const char* layer_name); + InstanceBuilder& request_layer (const char* layer_name); // Adds a layer to be enabled. Will fail to create an instance if the layer isn't available. InstanceBuilder& must_enable_layer (const char* layer_name); + // Enables the specified extension if it is available. - InstanceBuilder& check_and_add_extension (const char* extension_name); + InstanceBuilder& request_extension (const char* extension_name); // Adds an extension to be enabled. Will fail to create an instance if the extension isn't available. InstanceBuilder& must_enable_extension (const char* extension_name); // Headless Mode does not load the required extensions for presentation. Defaults to false. InstanceBuilder& set_headless (bool headless = false); - // Checks if the validation layers are available and loads them if they are. - InstanceBuilder& check_and_setup_validation_layers (bool enable_validation = true); + // Enables the validation layers. Will fail to create an instance if the validation layers aren't available. - InstanceBuilder& must_enable_validation_layers (bool enable_validation = true); + InstanceBuilder& must_enable_validation_layers (bool require_validation = true); + // Checks if the validation layers are available and loads them if they are. + InstanceBuilder& request_validation_layers (bool enable_validation = true); // Use a default debug callback that prints to standard out. - InstanceBuilder& set_default_debug_messenger (); + InstanceBuilder& use_default_debug_messenger (); // Provide a user defined debug callback. InstanceBuilder& set_debug_callback (PFN_vkDebugUtilsMessengerCallbackEXT callback); // Set what message severity is needed to trigger the callback. @@ -216,10 +234,7 @@ class InstanceBuilder { bool headless_context = false; } info; - struct SystemInfo { - std::vector available_layers; - std::vector available_extensions; - } system; + SystemInfo system; }; const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s); diff --git a/tests/run_tests.cpp b/tests/run_tests.cpp index d455ee8..cff5ba8 100644 --- a/tests/run_tests.cpp +++ b/tests/run_tests.cpp @@ -6,7 +6,7 @@ int test_happy_path () { auto window = create_window_glfw (); vkb::InstanceBuilder instance_builder; - auto instance_ret = instance_builder.set_default_debug_messenger ().build (); + auto instance_ret = instance_builder.use_default_debug_messenger ().build (); if (!instance_ret) { std::cout << static_cast (instance_ret.error ().type) << "\n"; return -1; // couldn't make instance @@ -44,7 +44,7 @@ int test_instance_basic () { vkb::InstanceBuilder builder; auto instance_ret = - builder.check_and_setup_validation_layers () + builder.request_validation_layers () .set_app_name ("test") .set_debug_callback ([] (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -71,13 +71,13 @@ int test_instance_headless () { vkb::InstanceBuilder builder; auto instance_ret = - builder.check_and_setup_validation_layers () + builder.request_validation_layers () .set_headless () .set_app_version (4, 5, 6) .set_app_name ("headless") .set_engine_name ("nick") .set_api_version (1, 0, 34) - .set_default_debug_messenger () + .use_default_debug_messenger () .add_validation_feature_enable (VkValidationFeatureEnableEXT::VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT) .add_validation_feature_disable (VkValidationFeatureDisableEXT::VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT) .add_validation_disable (VkValidationCheckEXT::VK_VALIDATION_CHECK_SHADERS_EXT) @@ -93,7 +93,7 @@ int test_physical_device_selection () { printf ("\nphysical device selection\n"); vkb::InstanceBuilder instance_builder; - auto instance_ret = instance_builder.set_default_debug_messenger ().build (); + auto instance_ret = instance_builder.use_default_debug_messenger ().build (); auto instance = instance_ret.value (); auto window = create_window_glfw (); auto surface = create_surface_glfw (instance.instance, window); @@ -117,7 +117,7 @@ int test_physical_device_selection () { int test_device_creation () { printf ("\ndevice creation\n"); vkb::InstanceBuilder instance_builder; - auto instance_ret = instance_builder.set_default_debug_messenger ().build (); + auto instance_ret = instance_builder.use_default_debug_messenger ().build (); if (!instance_ret.has_value ()) { printf ("couldn't create instance %i\n", static_cast (instance_ret.error ().type)); return -1;