From 8a053cadc3acaf00e941ba728c171f0b4781d55d Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Mon, 8 Jun 2020 14:28:32 -0600 Subject: [PATCH] Polished SwapchainBuilder. Redid swapchain recreation. To recreate a swapchain now requires making a new SwapchainBuilder or keeping the old one around. Removed the recreate function since its purpose was unclear. Introduced set_old_swapchain to allow recyling the old swapchain. Updated documentation and getting started guide. --- docs/getting_started.md | 25 ++++++++- example/triangle.cpp | 114 ++++++++++++++++++++++++++++++-------- src/VkBootstrap.cpp | 90 ++++++++++++++++++++---------- src/VkBootstrap.h | 78 +++++++++++++++++++------- tests/bootstrap_tests.cpp | 8 ++- 5 files changed, 240 insertions(+), 75 deletions(-) diff --git a/docs/getting_started.md b/docs/getting_started.md index 5312327..38224ee 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -219,6 +219,29 @@ for (uint32_t i = 0; i < static_cast(queue_families.size ()); i++) { } ``` ## Swapchain -// TODO +Creating a swapchain follows the same form outlined by `vkb::InstanceBuilder` and `vkb::DeviceBuilder`. Create the `vkb::SwapchainBuilder`, provide `vkb::Device`, call the appropriate builder functions, and call `build()`. +```cpp +vkb::SwapchainBuilder swapchain_builder{ device }; +auto swap_ret = swapchain_builder.build (); +if !(swap_ret){ + +} +vkb::swapchain swapchain = swap_ret.value(); +``` + +By default, the swapchain will use the VK_FORMAT_B8G8R8A8_SRGB or VK_FORMAT_R8G8B8A8_SRGB image format with the color space VK_COLOR_SPACE_SRGB_NONLINEAR_KHR. The present mode will default to VK_PRESENT_MODE_MAILBOX_KHR if available and fallback to VK_PRESENT_MODE_FIFO_KHR. The image usage default flag is VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT. + +Recreating the swapchain is equivalent to creating a new swapchain but providing the old swapchain as a source. Be sure to not use the same `VkSwapchainKHR` again as it expires when it is recycled after trying to create a new swapchain. +```cpp +vkb::SwapchainBuilder swapchain_builder{ device }; +auto swap_ret = swapchain_builder.set_old_swapchain (vkb_swapchain) + .build (); +if !(swap_ret){ + // If it failed to create a swapchain, the old swapchain handle is invalid. + vkb_swapchain.swapchain = VK_NULL_HANDLE; +} +// Note that this is the same vkb::Swapchain which was fed into vkb::SwapchainBuilder +vkb_swapchain = swap_ret.value(); +``` diff --git a/example/triangle.cpp b/example/triangle.cpp index 1bdbe12..9ba0819 100644 --- a/example/triangle.cpp +++ b/example/triangle.cpp @@ -39,7 +39,7 @@ struct RenderData { }; int device_initialization (Init& init) { - init.window = create_window_glfw ("Vulkan Triangle", false); + init.window = create_window_glfw ("Vulkan Triangle", true); vkb::InstanceBuilder instance_builder; auto instance_ret = instance_builder.use_default_debug_messenger ().request_validation_layers ().build (); @@ -67,17 +67,24 @@ int device_initialization (Init& init) { } init.device = device_ret.value (); + return 0; +} + +int create_swapchain (Init& init) { vkb::SwapchainBuilder swapchain_builder{ init.device }; - auto swap_ret = - swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build (); + auto swap_ret = swapchain_builder.use_default_format_selection () + .use_default_present_mode_selection () + .set_old_swapchain (init.swapchain) + .build (); if (!swap_ret) { - std::cout << swap_ret.error ().message () << "\n"; + std::cout << swap_ret.error ().message () << " " << swap_ret.vk_result () << "\n"; return -1; } init.swapchain = swap_ret.value (); return 0; } + int get_queues (Init& init, RenderData& data) { auto gq = init.device.get_queue (vkb::QueueType::graphics); if (!gq.has_value ()) { @@ -267,23 +274,31 @@ int create_graphics_pipeline (Init& init, RenderData& data) { return -1; // failed to create pipeline layout } - VkGraphicsPipelineCreateInfo pipelineInfo = {}; - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.stageCount = 2; - pipelineInfo.pStages = shader_stages; - pipelineInfo.pVertexInputState = &vertex_input_info; - pipelineInfo.pInputAssemblyState = &input_assembly; - pipelineInfo.pViewportState = &viewport_state; - pipelineInfo.pRasterizationState = &rasterizer; - pipelineInfo.pMultisampleState = &multisampling; - pipelineInfo.pColorBlendState = &color_blending; - pipelineInfo.layout = data.pipeline_layout; - pipelineInfo.renderPass = data.render_pass; - pipelineInfo.subpass = 0; - pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + std::vector dynamic_states = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + + VkPipelineDynamicStateCreateInfo dynamic_info = {}; + dynamic_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_info.dynamicStateCount = static_cast (dynamic_states.size ()); + dynamic_info.pDynamicStates = dynamic_states.data (); + + VkGraphicsPipelineCreateInfo pipeline_info = {}; + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.stageCount = 2; + pipeline_info.pStages = shader_stages; + pipeline_info.pVertexInputState = &vertex_input_info; + pipeline_info.pInputAssemblyState = &input_assembly; + pipeline_info.pViewportState = &viewport_state; + pipeline_info.pRasterizationState = &rasterizer; + pipeline_info.pMultisampleState = &multisampling; + pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_info; + pipeline_info.layout = data.pipeline_layout; + pipeline_info.renderPass = data.render_pass; + pipeline_info.subpass = 0; + pipeline_info.basePipelineHandle = VK_NULL_HANDLE; if (vkCreateGraphicsPipelines ( - init.device.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &data.graphics_pipeline) != VK_SUCCESS) { + init.device.device, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &data.graphics_pipeline) != VK_SUCCESS) { std::cout << "failed to create pipline\n"; return -1; // failed to create graphics pipeline } @@ -361,6 +376,21 @@ int create_command_buffers (Init& init, RenderData& data) { render_pass_info.clearValueCount = 1; render_pass_info.pClearValues = &clearColor; + VkViewport viewport = {}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = (float)init.swapchain.extent.width; + viewport.height = (float)init.swapchain.extent.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = { 0, 0 }; + scissor.extent = init.swapchain.extent; + + vkCmdSetViewport (data.command_buffers[i], 0, 1, &viewport); + vkCmdSetScissor (data.command_buffers[i], 0, 1, &scissor); + vkCmdBeginRenderPass (data.command_buffers[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline (data.command_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, data.graphics_pipeline); @@ -401,17 +431,47 @@ int create_sync_objects (Init& init, RenderData& data) { return 0; } +int recreate_swapchain (Init& init, RenderData& data) { + vkDeviceWaitIdle (init.device.device); + + vkDestroyCommandPool (init.device.device, data.command_pool, nullptr); + + for (auto framebuffer : data.framebuffers) { + vkDestroyFramebuffer (init.device.device, framebuffer, nullptr); + } + + init.swapchain.destroy_image_views (data.swapchain_image_views); + + int created_swapchain = create_swapchain (init); + while (created_swapchain != 0) { + init.swapchain.swapchain = VK_NULL_HANDLE; + created_swapchain = create_swapchain (init); + } + if (0 != create_framebuffers (init, data)) return -1; + if (0 != create_command_pool (init, data)) return -1; + if (0 != create_command_buffers (init, data)) return -1; + return 0; +} + int draw_frame (Init& init, RenderData& data) { vkWaitForFences (init.device.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX); uint32_t image_index = 0; - vkAcquireNextImageKHR (init.device.device, + VkResult result = vkAcquireNextImageKHR (init.device.device, init.swapchain.swapchain, UINT64_MAX, data.available_semaphores[data.current_frame], VK_NULL_HANDLE, &image_index); + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + return recreate_swapchain (init, data); + return 0; + } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + std::cout << "failed to recreate swapchain. Error " << result << "\n"; + return -1; + } + if (data.image_in_flight[image_index] != VK_NULL_HANDLE) { vkWaitForFences (init.device.device, 1, &data.image_in_flight[image_index], VK_TRUE, UINT64_MAX); } @@ -452,7 +512,14 @@ int draw_frame (Init& init, RenderData& data) { present_info.pImageIndices = &image_index; - vkQueuePresentKHR (data.present_queue, &present_info); + result = vkQueuePresentKHR (data.present_queue, &present_info); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { + return recreate_swapchain (init, data); + return 0; + } else if (result != VK_SUCCESS) { + std::cout << "failed to present swapchain image\n"; + return -1; + } data.current_frame = (data.current_frame + 1) % MAX_FRAMES_IN_FLIGHT; return 0; @@ -475,9 +542,7 @@ void cleanup (Init& init, RenderData& data) { vkDestroyPipelineLayout (init.device.device, data.pipeline_layout, nullptr); vkDestroyRenderPass (init.device.device, data.render_pass, nullptr); - for (auto imageView : data.swapchain_image_views) { - vkDestroyImageView (init.device.device, imageView, nullptr); - } + init.swapchain.destroy_image_views (data.swapchain_image_views); vkb::destroy_swapchain (init.swapchain); vkb::destroy_device (init.device); @@ -491,6 +556,7 @@ int main () { RenderData render_data; if (0 != device_initialization (init)) return -1; + if (0 != create_swapchain (init)) return -1; if (0 != get_queues (init, render_data)) return -1; if (0 != create_render_pass (init, render_data)) return -1; if (0 != create_graphics_pipeline (init, render_data)) return -1; diff --git a/src/VkBootstrap.cpp b/src/VkBootstrap.cpp index 45f17b9..7737fea 100644 --- a/src/VkBootstrap.cpp +++ b/src/VkBootstrap.cpp @@ -1240,6 +1240,7 @@ Result query_surface_support_details (VkPhysicalDevice ph present_modes, vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface); if (present_modes_ret != VK_SUCCESS) return { make_error_code (SurfaceSupportError::failed_enumerate_present_modes), present_modes_ret }; + return SurfaceSupportDetails{ capabilities, formats, present_modes }; } @@ -1291,6 +1292,11 @@ VkExtent2D find_extent ( } } // namespace detail +void destroy_swapchain (Swapchain const& swapchain) { + if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE) + vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocation_callbacks); +} + SwapchainBuilder::SwapchainBuilder (Device const& device) { info.device = device.device; info.physical_device = device.physical_device.physical_device; @@ -1314,8 +1320,7 @@ SwapchainBuilder::SwapchainBuilder (Device const& device, VkSurfaceKHR const sur info.present_queue_index = graphics.value (); } -detail::Result SwapchainBuilder::build () const { return build (VK_NULL_HANDLE); } -detail::Result SwapchainBuilder::build (VkSwapchainKHR old_swapchain) const { +detail::Result SwapchainBuilder::build () const { if (info.surface == VK_NULL_HANDLE) { return detail::Error{ SwapchainError::surface_handle_not_provided }; } @@ -1325,36 +1330,48 @@ detail::Result SwapchainBuilder::build (VkSwapchainKHR old_swapchain) auto desired_present_modes = info.desired_present_modes; if (desired_present_modes.size () == 0) add_desired_present_modes (desired_present_modes); - auto surface_support = detail::query_surface_support_details (info.physical_device, info.surface); - if (!surface_support.has_value ()) + auto surface_support_ret = detail::query_surface_support_details (info.physical_device, info.surface); + if (!surface_support_ret.has_value ()) return detail::Error{ SwapchainError::failed_query_surface_support_details, - surface_support.vk_result () }; - VkSurfaceFormatKHR surface_format = - detail::find_surface_format (surface_support.value ().formats, desired_formats); - VkPresentModeKHR present_mode = - detail::find_present_mode (surface_support.value ().present_modes, desired_present_modes); - VkExtent2D extent = detail::find_extent ( - surface_support.value ().capabilities, info.desired_width, info.desired_height); + surface_support_ret.vk_result () }; + auto surface_support = surface_support_ret.value (); - 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; + uint32_t image_count = surface_support.capabilities.minImageCount + 1; + if (surface_support.capabilities.maxImageCount > 0 && image_count > surface_support.capabilities.maxImageCount) { + image_count = surface_support.capabilities.maxImageCount; } + VkSurfaceFormatKHR surface_format = detail::find_surface_format (surface_support.formats, desired_formats); + + VkExtent2D extent = + detail::find_extent (surface_support.capabilities, info.desired_width, info.desired_height); + + uint32_t image_array_layers = info.array_layer_count; + if (surface_support.capabilities.maxImageArrayLayers < info.array_layer_count) + image_array_layers = surface_support.capabilities.maxImageArrayLayers; + if (info.array_layer_count == 0) image_array_layers = 1; + + uint32_t queue_family_indices[] = { info.graphics_queue_index, info.present_queue_index }; + + + VkPresentModeKHR present_mode = + detail::find_present_mode (surface_support.present_modes, desired_present_modes); + + VkSurfaceTransformFlagBitsKHR pre_transform = info.pre_transform; + if (info.pre_transform == static_cast (0)) + pre_transform = surface_support.capabilities.currentTransform; VkSwapchainCreateInfoKHR swapchain_create_info = {}; swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - detail::setup_pNext_chain (swapchain_create_info, info.pNext_elements); + detail::setup_pNext_chain (swapchain_create_info, info.pNext_chain); + swapchain_create_info.flags = info.create_flags; swapchain_create_info.surface = info.surface; - swapchain_create_info.minImageCount = imageCount; + swapchain_create_info.minImageCount = image_count; swapchain_create_info.imageFormat = surface_format.format; swapchain_create_info.imageColorSpace = surface_format.colorSpace; swapchain_create_info.imageExtent = extent; - swapchain_create_info.imageArrayLayers = info.array_layer_count; + swapchain_create_info.imageArrayLayers = image_array_layers; swapchain_create_info.imageUsage = info.image_usage_flags; - uint32_t queue_family_indices[] = { info.graphics_queue_index, info.present_queue_index }; - if (info.graphics_queue_index != info.present_queue_index) { swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; swapchain_create_info.queueFamilyIndexCount = 2; @@ -1363,11 +1380,11 @@ detail::Result SwapchainBuilder::build (VkSwapchainKHR old_swapchain) 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.preTransform = pre_transform; + swapchain_create_info.compositeAlpha = info.composite_alpha; swapchain_create_info.presentMode = present_mode; swapchain_create_info.clipped = info.clipped; - swapchain_create_info.oldSwapchain = old_swapchain; + swapchain_create_info.oldSwapchain = info.old_swapchain; Swapchain swapchain{}; VkResult res = vkCreateSwapchainKHR ( info.device, &swapchain_create_info, info.allocation_callbacks, &swapchain.swapchain); @@ -1385,9 +1402,6 @@ detail::Result SwapchainBuilder::build (VkSwapchainKHR old_swapchain) swapchain.allocation_callbacks = info.allocation_callbacks; return swapchain; } -detail::Result SwapchainBuilder::recreate (Swapchain const& swapchain) const { - return build (swapchain.swapchain); -} detail::Result> Swapchain::get_images () { std::vector swapchain_images; @@ -1433,9 +1447,13 @@ void Swapchain::destroy_image_views (std::vector const& image_views vkDestroyImageView (device, image_view, allocation_callbacks); } } -void destroy_swapchain (Swapchain const& swapchain) { - if (swapchain.device != VK_NULL_HANDLE && swapchain.swapchain != VK_NULL_HANDLE) - vkDestroySwapchainKHR (swapchain.device, swapchain.swapchain, swapchain.allocation_callbacks); +SwapchainBuilder& SwapchainBuilder::set_old_swapchain (VkSwapchainKHR old_swapchain) { + info.old_swapchain = old_swapchain; + return *this; +} +SwapchainBuilder& SwapchainBuilder::set_old_swapchain (Swapchain const& swapchain) { + info.old_swapchain = swapchain.swapchain; + return *this; } SwapchainBuilder& SwapchainBuilder::set_desired_extent (uint32_t width, uint32_t height) { info.desired_width = width; @@ -1451,6 +1469,7 @@ SwapchainBuilder& SwapchainBuilder::add_fallback_format (VkSurfaceFormatKHR form return *this; } SwapchainBuilder& SwapchainBuilder::use_default_format_selection () { + info.desired_formats.clear (); add_desired_formats (info.desired_formats); return *this; } @@ -1464,6 +1483,7 @@ SwapchainBuilder& SwapchainBuilder::add_fallback_present_mode (VkPresentModeKHR return *this; } SwapchainBuilder& SwapchainBuilder::use_default_present_mode_selection () { + info.desired_present_modes.clear (); add_desired_present_modes (info.desired_present_modes); return *this; } @@ -1491,6 +1511,18 @@ SwapchainBuilder& SwapchainBuilder::set_clipped (bool clipped) { info.clipped = clipped; return *this; } +SwapchainBuilder& SwapchainBuilder::set_create_flags (VkSwapchainCreateFlagBitsKHR create_flags) { + info.create_flags = create_flags; + return *this; +} +SwapchainBuilder& SwapchainBuilder::set_pre_transform_flags (VkSurfaceTransformFlagBitsKHR pre_transform_flags) { + info.pre_transform = pre_transform_flags; + return *this; +} +SwapchainBuilder& SwapchainBuilder::set_composite_alpha_flags (VkCompositeAlphaFlagBitsKHR composite_alpha_flags) { + info.composite_alpha = composite_alpha_flags; + return *this; +} void SwapchainBuilder::add_desired_formats (std::vector& formats) const { formats.push_back ({ VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }); diff --git a/src/VkBootstrap.h b/src/VkBootstrap.h index 2b6eeab..d7abb3f 100644 --- a/src/VkBootstrap.h +++ b/src/VkBootstrap.h @@ -107,7 +107,7 @@ enum class InstanceError { failed_create_debug_messenger, requested_layers_not_present, requested_extensions_not_present, - windowing_extensions_not_present, + windowing_extensions_not_present, }; enum class PhysicalDeviceError { no_surface_provided, @@ -519,11 +519,11 @@ struct Swapchain { VkExtent2D extent = { 0, 0 }; VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE; - // Returns a vector of VkImage handles to the swapchain + // Returns a vector of VkImage handles to the swapchain. detail::Result> get_images (); - // Returns a vector of VkImageView's to the VkImage's of the swapchain - // VkImageViews must be destroyed + // Returns a vector of VkImageView's to the VkImage's of the swapchain. + // VkImageViews must be destroyed. detail::Result> get_image_views (); void destroy_image_views (std::vector const& image_views); }; @@ -534,27 +534,64 @@ class SwapchainBuilder { public: SwapchainBuilder (Device const& device); SwapchainBuilder (Device const& device, VkSurfaceKHR const surface); - - detail::Result build () const; - detail::Result recreate (Swapchain const& swapchain) const; + detail::Result build () const; + + // Set the oldSwapchain member of VkSwapchainCreateInfoKHR. + // For use in rebuilding a swapchain. + SwapchainBuilder& set_old_swapchain (VkSwapchainKHR old_swapchain); + SwapchainBuilder& set_old_swapchain (Swapchain const& swapchain); + + + // Desired size of the swapchain. By default, the swapchain will use the size + // of the window being drawn to. SwapchainBuilder& set_desired_extent (uint32_t width, uint32_t height); + // When determining the surface format, make this the first to be used if supported. SwapchainBuilder& set_desired_format (VkSurfaceFormatKHR format); + // Add this swapchain format to the end of the list of formats selected from. SwapchainBuilder& add_fallback_format (VkSurfaceFormatKHR format); + // Use the default swapchain formats. This is done if no formats are provided. SwapchainBuilder& use_default_format_selection (); + // When determining the present mode, make this the first to be used if supported. SwapchainBuilder& set_desired_present_mode (VkPresentModeKHR present_mode); + // Add this present mode to the end of the list of present modes selected from. SwapchainBuilder& add_fallback_present_mode (VkPresentModeKHR present_mode); + // Use the default presentation mode. This is done if no present modes are provided. SwapchainBuilder& use_default_present_mode_selection (); - SwapchainBuilder& set_image_usage_flags(VkImageUsageFlags usage_flags); - SwapchainBuilder& add_image_usage_flags(VkImageUsageFlags usage_flags); - SwapchainBuilder& use_default_image_usage_flags(); + // Set the bitmask of the image usage for acquired swapchain images. + 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); + // Use the default image usage bitmask values. This is the default if no image usages + // are provided. The default is VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + SwapchainBuilder& use_default_image_usage_flags (); - SwapchainBuilder& set_image_array_layer_count(uint32_t array_layer_count = 1); + // Set the number of views in for multiview/stereo surface + SwapchainBuilder& set_image_array_layer_count (uint32_t array_layer_count); - SwapchainBuilder& set_clipped(bool clipped = true); + // Set whether the Vulkan implementation is allowed to discard rendering operations that + // affect regions of the surface that are not visible. Default is true. + // Note: Applications should use the default of true if they do not expect to read back the content + // of presentable images before presenting them or after reacquiring them, and if their fragment + // shaders do not have any side effects that require them to run for all pixels in the presentable image. + SwapchainBuilder& set_clipped (bool clipped = true); + + // Set the VkSwapchainCreateFlagBitsKHR. + SwapchainBuilder& set_create_flags (VkSwapchainCreateFlagBitsKHR create_flags); + // Set the transform to be applied, like a 90 degree rotation. Default is the current transform. + SwapchainBuilder& set_pre_transform_flags (VkSurfaceTransformFlagBitsKHR pre_transform_flags); + // Set the alpha channel to be used with other windows in on the system. Default is VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR. + SwapchainBuilder& set_composite_alpha_flags (VkCompositeAlphaFlagBitsKHR composite_alpha_flags); + + // Add a structure to the pNext chain of VkSwapchainCreateInfoKHR. + // The structure must be valid when SwapchainBuilder::build() is called. + template SwapchainBuilder& add_pNext (T* structure) { + info.pNext_chain.push_back (reinterpret_cast (structure)); + return *this; + } // Provide custom allocation callbacks. SwapchainBuilder& set_allocation_callbacks (VkAllocationCallbacks* callbacks); @@ -562,24 +599,25 @@ class SwapchainBuilder { private: void add_desired_formats (std::vector& formats) const; void add_desired_present_modes (std::vector& modes) const; - // for use in swapchain recreation - detail::Result build (VkSwapchainKHR old_swapchain) const; struct SwapchainInfo { VkPhysicalDevice physical_device = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE; + std::vector pNext_chain; + VkSwapchainCreateFlagBitsKHR create_flags = static_cast (0); VkSurfaceKHR surface = VK_NULL_HANDLE; - VkSwapchainKHR old_swapchain = VK_NULL_HANDLE; std::vector desired_formats; - std::vector desired_present_modes; uint32_t desired_width = 256; uint32_t desired_height = 256; - VkImageUsageFlags image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - uint32_t array_layer_count = 1; - bool clipped = true; + uint32_t array_layer_count = 1; + VkImageUsageFlags image_usage_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; uint32_t graphics_queue_index = 0; uint32_t present_queue_index = 0; - std::vector pNext_elements; + VkSurfaceTransformFlagBitsKHR pre_transform = static_cast (0); + VkCompositeAlphaFlagBitsKHR composite_alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + std::vector desired_present_modes; + bool clipped = true; + VkSwapchainKHR old_swapchain = VK_NULL_HANDLE; VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE; } info; }; diff --git a/tests/bootstrap_tests.cpp b/tests/bootstrap_tests.cpp index 3e094ab..1bcbdbf 100644 --- a/tests/bootstrap_tests.cpp +++ b/tests/bootstrap_tests.cpp @@ -225,6 +225,10 @@ TEST_CASE ("Swapchain", "[VkBootstrap.bootstrap]") { swapchain_builder.set_desired_extent (256, 256) .set_desired_format ({ VK_FORMAT_R8G8B8A8_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) + .set_clipped (false) + .set_image_array_layer_count (1) .build (); REQUIRE (swapchain_ret.has_value ()); @@ -234,6 +238,7 @@ TEST_CASE ("Swapchain", "[VkBootstrap.bootstrap]") { vkb::SwapchainBuilder swapchain_builder (device); auto swapchain_ret = swapchain_builder.use_default_format_selection () .use_default_present_mode_selection () + .use_default_image_usage_flags () .build (); REQUIRE (swapchain_ret.has_value ()); @@ -245,7 +250,8 @@ TEST_CASE ("Swapchain", "[VkBootstrap.bootstrap]") { REQUIRE (swapchain_ret.has_value ()); auto swapchain = swapchain_ret.value (); - auto recreated_swapchain_ret = swapchain_builder.recreate (swapchain); + + auto recreated_swapchain_ret = swapchain_builder.set_old_swapchain (swapchain).build (); REQUIRE (recreated_swapchain_ret.has_value ()); vkb::destroy_swapchain (recreated_swapchain_ret.value ());