diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index cd8f6a5..fa540f1 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -106,44 +106,42 @@ VkBool32 default_debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageS } namespace detail { -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 check_layer_supported (std::vector available_layers, const char* layer_name) { + if (!layer_name) return false; + for (const auto& layer_properties : available_layers) { + if (strcmp (layer_name, layer_properties.layerName) == 0) { + return true; + } } + return false; +} + +bool check_layers_supported (std::vector available_layers, std::vector layer_names) { 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; - } - } + bool found = check_layer_supported (available_layers, layer_name); if (!found) all_found = false; } - return all_found; } -bool check_extensions_supported (std::vector extension_names) { - auto available_extensions = - detail::get_vector (vkEnumerateInstanceExtensionProperties, nullptr); - if (!available_extensions.has_value ()) { - return false; // maybe report error? +bool check_extension_supported (std::vector available_extensions, const char* extension_name) { + if (!extension_name) return false; + for (const auto& layer_properties : available_extensions) { + if (strcmp (extension_name, layer_properties.extensionName) == 0) { + return true; + } } + return false; +} + +bool check_extensions_supported (std::vector available_extensions, + std::vector extension_names) { bool all_found = true; for (const auto& extension_name : extension_names) { - bool found = false; - for (const auto& layer_properties : available_extensions.value ()) { - if (strcmp (extension_name, layer_properties.extensionName) == 0) { - found = true; - break; - } - } + bool found = check_extension_supported (available_extensions, extension_name); if (!found) all_found = false; } - return all_found; } @@ -156,6 +154,8 @@ void setup_pNext_chain (T& structure, std::vector const& st } structure.pNext = structs.at (0); } +const char* validation_layer_name = "VK_LAYER_KHRONOS_validation"; + } // namespace detail void destroy_instance (Instance instance) { @@ -165,6 +165,17 @@ 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 (); + } +} detail::Expected> InstanceBuilder::build () { @@ -200,7 +211,7 @@ detail::Expected> InstanceBuilder::build extensions.push_back ("VK_KHR_metal_surface"); #endif } - bool all_extensions_supported = detail::check_extensions_supported (extensions); + bool all_extensions_supported = detail::check_extensions_supported (system.available_extensions, extensions); if (!all_extensions_supported) { return detail::Error{ InstanceError::requested_extensions_not_present }; } @@ -210,9 +221,9 @@ detail::Expected> InstanceBuilder::build layers.push_back (layer); if (info.enable_validation_layers) { - layers.push_back ("VK_LAYER_KHRONOS_validation"); + layers.push_back (detail::validation_layer_name); } - bool all_layers_supported = detail::check_layers_supported (layers); + bool all_layers_supported = detail::check_layers_supported (system.available_layers, layers); if (!all_layers_supported) { return detail::Error{ InstanceError::requested_layers_not_present }; } @@ -280,10 +291,12 @@ detail::Expected> InstanceBuilder::build } InstanceBuilder& InstanceBuilder::set_app_name (const char* app_name) { + if (!app_name) return *this; info.app_name = app_name; return *this; } InstanceBuilder& InstanceBuilder::set_engine_name (const char* engine_name) { + if (!engine_name) return *this; info.engine_name = engine_name; return *this; } @@ -300,17 +313,38 @@ InstanceBuilder& InstanceBuilder::set_api_version (uint32_t major, uint32_t mino return *this; } InstanceBuilder& InstanceBuilder::add_layer (const char* layer_name) { + if (!layer_name) return *this; info.layers.push_back (layer_name); return *this; } InstanceBuilder& InstanceBuilder::add_extension (const char* extension_name) { + if (!extension_name) return *this; info.extensions.push_back (extension_name); return *this; } +bool InstanceBuilder::check_and_add_layer (const char* layer_name) { + if (!layer_name) return false; + bool available = detail::check_layer_supported (system.available_layers, layer_name); + if (available) info.layers.push_back (layer_name); + return available; +} +bool InstanceBuilder::check_and_add_extension (const char* extension_name) { + if (!extension_name) return false; + bool available = detail::check_extension_supported (system.available_extensions, extension_name); + if (available) info.extensions.push_back (extension_name); + return available; +} InstanceBuilder& InstanceBuilder::setup_validation_layers (bool enable_validation) { info.enable_validation_layers = enable_validation; return *this; } +bool InstanceBuilder::check_and_setup_validation_layers (bool enable_validation) { + bool available = + detail::check_extension_supported (system.available_extensions, detail::validation_layer_name); + setup_validation_layers (available); + return available; +} + InstanceBuilder& InstanceBuilder::set_default_debug_messenger () { info.use_debug_messenger = true; info.debug_callback = default_debug_callback; @@ -394,25 +428,6 @@ Expected> query_surfac return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () }; } - -// Given a list of formats, return a format supported by the hardware, else return VK_FORMAT_UNDEFINED -VkFormat find_supported_format (VkPhysicalDevice physical_device, - const std::vector& candidates, - VkImageTiling tiling, - VkFormatFeatureFlags features) { - for (VkFormat format : candidates) { - VkFormatProperties props; - vkGetPhysicalDeviceFormatProperties (physical_device, format, &props); - - if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) { - return format; - } else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) { - return format; - } - } - return VK_FORMAT_UNDEFINED; -} - std::vector check_device_extension_support ( VkPhysicalDevice device, std::vector desired_extensions) { auto available_extensions = @@ -491,12 +506,15 @@ bool supports_features (VkPhysicalDeviceFeatures supported, VkPhysicalDeviceFeat } } // namespace detail +// finds the first queue which supports graphics operations. returns -1 if none is found int get_graphics_queue_index (std::vector const& families) { for (int i = 0; i < families.size (); i++) { if (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) return i; } return -1; } +// finds a compute queue which is distinct from the graphics queue and tries to find one without transfer support +// returns -1 if none is found int get_distinct_compute_queue_index (std::vector const& families) { int compute = -1; for (int i = 0; i < families.size (); i++) { @@ -511,6 +529,8 @@ int get_distinct_compute_queue_index (std::vector const } return compute; } +// finds a transfer queue which is distinct from the graphics queue and tries to find one without compute support +// returns -1 if none is found int get_distinct_transfer_queue_index (std::vector const& families) { int transfer = -1; for (int i = 0; i < families.size (); i++) { @@ -523,8 +543,29 @@ int get_distinct_transfer_queue_index (std::vector cons } } } + return transfer; +} +// finds the first queue which supports only compute (not graphics or transfer). returns -1 if none is found +int get_dedicated_compute_queue_index (std::vector const& families) { + for (int i = 0; i < families.size (); i++) { + if ((families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) && + (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 && + (families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) == 0) + return i; + } return -1; } +// finds the first queue which supports only transfer (not graphics or compute). returns -1 if none is found +int get_dedicated_transfer_queue_index (std::vector const& families) { + for (int i = 0; i < families.size (); i++) { + if ((families[i].queueFlags & VK_QUEUE_TRANSFER_BIT) && + (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0 && + (families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0) + return i; + } + return -1; +} +// finds the first queue which supports presenting. returns -1 if none is found int get_present_queue_index (VkPhysicalDevice const phys_device, VkSurfaceKHR const surface, std::vector const& families) { diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index 3726fc0..233199f 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -124,6 +124,8 @@ void destroy_instance (Instance instance); // release instance resources class InstanceBuilder { public: + InstanceBuilder(); //automatically gets available layers and extensions + detail::Expected> build (); // use builder pattern InstanceBuilder& set_app_name (const char* app_name); @@ -133,11 +135,11 @@ class InstanceBuilder { 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 (const char* app_name); - InstanceBuilder& add_extension (const char* app_name); + InstanceBuilder& add_layer (const char* layer_name); + InstanceBuilder& add_extension (const char* extension_name); - bool check_and_add_layer (const char* app_name); - bool check_and_add_extension (const char* app_name); + bool check_and_add_layer (const char* layer_name); + bool check_and_add_extension (const char* extension_name); InstanceBuilder& setup_validation_layers (bool enable_validation = true); InstanceBuilder& set_headless (bool headless = false); @@ -189,6 +191,11 @@ class InstanceBuilder { bool use_debug_messenger = false; bool headless_context = false; } info; + + struct SystemInfo { + std::vector available_layers; + std::vector available_extensions; + } system; }; const char* to_string_message_severity (VkDebugUtilsMessageSeverityFlagBitsEXT s); diff --git a/tests/common.h b/tests/common.h index 6782e96..3104501 100644 --- a/tests/common.h +++ b/tests/common.h @@ -10,29 +10,24 @@ #include "../src/VkBootstrap.h" -GLFWwindow* create_window_glfw (bool resize = true) -{ +GLFWwindow* create_window_glfw (bool resize = true) { glfwInit (); glfwWindowHint (GLFW_CLIENT_API, GLFW_NO_API); if (!resize) glfwWindowHint (GLFW_RESIZABLE, GLFW_FALSE); return glfwCreateWindow (640, 480, "Vulkan Triangle", NULL, NULL); } -void destroy_window_glfw (GLFWwindow* window) -{ +void destroy_window_glfw (GLFWwindow* window) { glfwDestroyWindow (window); glfwTerminate (); } -VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window) -{ +VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window) { VkSurfaceKHR surface = nullptr; VkResult err = glfwCreateWindowSurface (instance, window, NULL, &surface); - if (err) - { + if (err) { const char* error_msg; int ret = glfwGetError (&error_msg); - if (ret != 0) - { + if (ret != 0) { std::cout << ret << " "; if (error_msg != nullptr) std::cout << error_msg; std::cout << "\n"; @@ -40,4 +35,7 @@ VkSurfaceKHR create_surface_glfw (VkInstance instance, GLFWwindow* window) surface = nullptr; } return surface; +} +void destroy_surface (VkInstance instance, VkSurfaceKHR surface) { + vkDestroySurfaceKHR (instance, surface, nullptr); } \ No newline at end of file diff --git a/tests/run_tests.cpp b/tests/run_tests.cpp index 957730c..e73816b 100644 --- a/tests/run_tests.cpp +++ b/tests/run_tests.cpp @@ -31,6 +31,7 @@ int test_happy_path () { // possible swapchain creation... vkb::destroy_device (device); + destroy_surface (instance.instance, surface); vkb::destroy_instance (instance); destroy_window_glfw (window); return 0; @@ -107,6 +108,7 @@ int test_physical_device_selection () { if (!phys_dev_ret.has_value ()) { return -1; } + destroy_surface (instance.instance, surface); vkb::destroy_instance (instance); destroy_window_glfw (window); return 0; @@ -139,8 +141,8 @@ int test_device_creation () { printf ("couldn't create device %i\n", static_cast (dev_ret.error ().type)); return -1; } - vkb::destroy_device (dev_ret.value ()); + destroy_surface (instance.instance, surface); vkb::destroy_instance (instance); destroy_window_glfw (window); return 0;