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.
This commit is contained in:
Charles Giessen 2020-06-08 14:28:32 -06:00
parent e2c65e7ec1
commit 8a053cadc3
5 changed files with 240 additions and 75 deletions

View File

@ -219,6 +219,29 @@ for (uint32_t i = 0; i < static_cast<uint32_t>(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();
```

View File

@ -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<VkDynamicState> 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<uint32_t> (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;

View File

@ -1240,6 +1240,7 @@ Result<SurfaceSupportDetails> 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<Swapchain> SwapchainBuilder::build () const { return build (VK_NULL_HANDLE); }
detail::Result<Swapchain> SwapchainBuilder::build (VkSwapchainKHR old_swapchain) const {
detail::Result<Swapchain> SwapchainBuilder::build () const {
if (info.surface == VK_NULL_HANDLE) {
return detail::Error{ SwapchainError::surface_handle_not_provided };
}
@ -1325,36 +1330,48 @@ detail::Result<Swapchain> 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<VkSurfaceTransformFlagBitsKHR> (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<Swapchain> 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<Swapchain> SwapchainBuilder::build (VkSwapchainKHR old_swapchain)
swapchain.allocation_callbacks = info.allocation_callbacks;
return swapchain;
}
detail::Result<Swapchain> SwapchainBuilder::recreate (Swapchain const& swapchain) const {
return build (swapchain.swapchain);
}
detail::Result<std::vector<VkImage>> Swapchain::get_images () {
std::vector<VkImage> swapchain_images;
@ -1433,9 +1447,13 @@ void Swapchain::destroy_image_views (std::vector<VkImageView> 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<VkSurfaceFormatKHR>& formats) const {
formats.push_back ({ VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR });

View File

@ -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<std::vector<VkImage>> 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<std::vector<VkImageView>> get_image_views ();
void destroy_image_views (std::vector<VkImageView> const& image_views);
};
@ -536,25 +536,62 @@ class SwapchainBuilder {
SwapchainBuilder (Device const& device, VkSurfaceKHR const surface);
detail::Result<Swapchain> build () const;
detail::Result<Swapchain> recreate (Swapchain const& swapchain) 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 <typename T> SwapchainBuilder& add_pNext (T* structure) {
info.pNext_chain.push_back (reinterpret_cast<VkBaseOutStructure*> (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<VkSurfaceFormatKHR>& formats) const;
void add_desired_present_modes (std::vector<VkPresentModeKHR>& modes) const;
// for use in swapchain recreation
detail::Result<Swapchain> build (VkSwapchainKHR old_swapchain) const;
struct SwapchainInfo {
VkPhysicalDevice physical_device = VK_NULL_HANDLE;
VkDevice device = VK_NULL_HANDLE;
std::vector<VkBaseOutStructure*> pNext_chain;
VkSwapchainCreateFlagBitsKHR create_flags = static_cast<VkSwapchainCreateFlagBitsKHR> (0);
VkSurfaceKHR surface = VK_NULL_HANDLE;
VkSwapchainKHR old_swapchain = VK_NULL_HANDLE;
std::vector<VkSurfaceFormatKHR> desired_formats;
std::vector<VkPresentModeKHR> 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<VkBaseOutStructure*> pNext_elements;
VkSurfaceTransformFlagBitsKHR pre_transform = static_cast<VkSurfaceTransformFlagBitsKHR> (0);
VkCompositeAlphaFlagBitsKHR composite_alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
std::vector<VkPresentModeKHR> desired_present_modes;
bool clipped = true;
VkSwapchainKHR old_swapchain = VK_NULL_HANDLE;
VkAllocationCallbacks* allocation_callbacks = VK_NULL_HANDLE;
} info;
};

View File

@ -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 ());