diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index 6ee9851..75f3c54 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -442,6 +442,8 @@ const char* to_string(SwapchainError err) { CASE_TO_STRING(SwapchainError, failed_create_swapchain) CASE_TO_STRING(SwapchainError, failed_get_swapchain_images) CASE_TO_STRING(SwapchainError, failed_create_swapchain_image_views) + CASE_TO_STRING(SwapchainError, required_min_image_count_too_low) + CASE_TO_STRING(SwapchainError, required_usage_or_features_not_supported) default: return ""; } @@ -1583,21 +1585,19 @@ enum class SurfaceSupportError { surface_handle_null, failed_get_surface_capabilities, failed_enumerate_surface_formats, - failed_enumerate_present_modes + failed_enumerate_present_modes, + no_suitable_format }; struct SurfaceSupportErrorCategory : std::error_category { const char* name() const noexcept override { return "vbk_surface_support"; } std::string message(int err) const override { switch (static_cast(err)) { - case SurfaceSupportError::surface_handle_null: - return "surface_handle_null"; - case SurfaceSupportError::failed_get_surface_capabilities: - return "failed_get_surface_capabilities"; - case SurfaceSupportError::failed_enumerate_surface_formats: - return "failed_enumerate_surface_formats"; - case SurfaceSupportError::failed_enumerate_present_modes: - return "failed_enumerate_present_modes"; + CASE_TO_STRING(SurfaceSupportError, surface_handle_null) + CASE_TO_STRING(SurfaceSupportError, failed_get_surface_capabilities) + CASE_TO_STRING(SurfaceSupportError, failed_enumerate_surface_formats) + CASE_TO_STRING(SurfaceSupportError, failed_enumerate_present_modes) + CASE_TO_STRING(SurfaceSupportError, no_suitable_format) default: return ""; } @@ -1633,7 +1633,7 @@ Result query_surface_support_details(VkPhysicalDevice phy return SurfaceSupportDetails{ capabilities, formats, present_modes }; } -VkSurfaceFormatKHR find_surface_format(VkPhysicalDevice phys_device, +Result find_surface_format(VkPhysicalDevice phys_device, std::vector const& available_formats, std::vector const& desired_formats, VkFormatFeatureFlags feature_flags) { @@ -1648,8 +1648,8 @@ VkSurfaceFormatKHR find_surface_format(VkPhysicalDevice phys_device, } } - // use the first available one if any desired formats aren't found - return available_formats[0]; + // If no format supports the provided feature, we report that no format is suitable to the user request + return { make_error_code(SurfaceSupportError::no_suitable_format) }; } VkPresentModeKHR find_present_mode(std::vector const& available_resent_modes, @@ -1664,6 +1664,11 @@ VkPresentModeKHR find_present_mode(std::vector const& availabl return VK_PRESENT_MODE_FIFO_KHR; } +bool is_unextended_present_mode(VkPresentModeKHR present_mode) { + return (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) || (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) || + (present_mode == VK_PRESENT_MODE_FIFO_KHR) || (present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR); +} + template T minimum(T a, T b) { return a < b ? a : b; } template T maximum(T a, T b) { return a > b ? a : b; } @@ -1767,8 +1772,10 @@ Result SwapchainBuilder::build() const { image_count = surface_support.capabilities.maxImageCount; } - VkSurfaceFormatKHR surface_format = + auto surface_format_ret = detail::find_surface_format(info.physical_device, surface_support.formats, desired_formats, info.format_feature_flags); + if (!surface_format_ret.has_value()) return Error{ SwapchainError::required_usage_or_features_not_supported }; + auto surface_format = surface_format_ret.value(); VkExtent2D extent = detail::find_extent(surface_support.capabilities, info.desired_width, info.desired_height); @@ -1782,6 +1789,11 @@ Result SwapchainBuilder::build() const { VkPresentModeKHR present_mode = detail::find_present_mode(surface_support.present_modes, desired_present_modes); + if (detail::is_unextended_present_mode(present_mode) && + (info.image_usage_flags & surface_support.capabilities.supportedUsageFlags) != info.image_usage_flags) { + return Error{ SwapchainError::required_usage_or_features_not_supported }; + } + VkSurfaceTransformFlagBitsKHR pre_transform = info.pre_transform; if (info.pre_transform == static_cast(0)) pre_transform = surface_support.capabilities.currentTransform; @@ -1977,7 +1989,7 @@ SwapchainBuilder& SwapchainBuilder::add_format_feature_flags(VkFormatFeatureFlag return *this; } SwapchainBuilder& SwapchainBuilder::use_default_format_feature_flags() { - info.format_feature_flags = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; + info.format_feature_flags = 0; return *this; } SwapchainBuilder& SwapchainBuilder::set_image_array_layer_count(uint32_t array_layer_count) { diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index 313ec64..256bfc7 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -213,6 +213,7 @@ enum class SwapchainError { failed_get_swapchain_images, failed_create_swapchain_image_views, required_min_image_count_too_low, + required_usage_or_features_not_supported }; std::error_code make_error_code(InstanceError instance_error); @@ -841,6 +842,7 @@ class SwapchainBuilder { SwapchainBuilder& use_default_present_mode_selection(); // Set the bitmask of the image usage for acquired swapchain images. + // If the surface capabilities cannot allow it, building the swapchain will result in the `SwapchainError::required_usage_or_features_not_supported` error. SwapchainBuilder& set_image_usage_flags(VkImageUsageFlags usage_flags); // Add a image usage to the bitmask for acquired swapchain images. SwapchainBuilder& add_image_usage_flags(VkImageUsageFlags usage_flags); @@ -849,11 +851,14 @@ class SwapchainBuilder { SwapchainBuilder& use_default_image_usage_flags(); // Set the bitmask of the format feature flag for acquired swapchain images. + // If the desired formats cannot allow it, building the swapchain will result in the + // `SwapchainError::required_usage_or_features_not_supported` error. Use this functionnality only if you require + // formats to support a set of feature flags that are not already implied by set_image_usage_flags SwapchainBuilder& set_format_feature_flags(VkFormatFeatureFlags feature_flags); // Add a format feature to the bitmask for acquired swapchain images. SwapchainBuilder& add_format_feature_flags(VkFormatFeatureFlags feature_flags); // Use the default format feature bitmask values. This is the default if no format features - // are provided. The default is VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT + // are provided. The default is 0 SwapchainBuilder& use_default_format_feature_flags(); // Set the number of views in for multiview/stereo surface @@ -922,7 +927,7 @@ class SwapchainBuilder { uint32_t min_image_count = 0; uint32_t required_min_image_count = 0; VkImageUsageFlags image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - VkFormatFeatureFlags format_feature_flags = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; + VkFormatFeatureFlags format_feature_flags = 0; uint32_t graphics_queue_index = 0; uint32_t present_queue_index = 0; VkSurfaceTransformFlagBitsKHR pre_transform = static_cast(0); diff --git a/tests/bootstrap_tests.cpp b/tests/bootstrap_tests.cpp index 24fbe84..e0a367d 100644 --- a/tests/bootstrap_tests.cpp +++ b/tests/bootstrap_tests.cpp @@ -305,6 +305,7 @@ TEST_CASE("Swapchain", "[VkBootstrap.bootstrap]") { vkb::SwapchainBuilder swapchain_builder(device); auto swapchain_ret = swapchain_builder.set_desired_extent(256, 256) .set_desired_format({ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }) + .add_fallback_format({ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }) .set_desired_present_mode(VK_PRESENT_MODE_IMMEDIATE_KHR) .set_pre_transform_flags(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) .set_composite_alpha_flags(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)