Recreate swap chain on window resize.

This commit is contained in:
Ben Vanik 2016-02-17 19:43:42 -08:00
parent a97fa36512
commit ca5902c111
3 changed files with 61 additions and 25 deletions

View File

@ -115,6 +115,17 @@ void VulkanContext::BeginSwap() {
auto provider = static_cast<VulkanProvider*>(provider_);
auto device = provider->device();
// If we have a window see if it's been resized since we last swapped.
// If it has been, we'll need to reinitialize the swap chain before we
// start touching it.
if (target_window_) {
if (target_window_->width() != swap_chain_->surface_width() ||
target_window_->height() != swap_chain_->surface_height()) {
// Resized!
swap_chain_->Reinitialize();
}
}
// Acquire the next image and set it up for use.
swap_chain_->Begin();

View File

@ -32,31 +32,7 @@ namespace vulkan {
VulkanSwapChain::VulkanSwapChain(VulkanInstance* instance, VulkanDevice* device)
: instance_(instance), device_(device) {}
VulkanSwapChain::~VulkanSwapChain() {
for (auto& buffer : buffers_) {
DestroyBuffer(&buffer);
}
if (image_available_semaphore_) {
vkDestroySemaphore(*device_, image_available_semaphore_, nullptr);
}
if (render_pass_) {
vkDestroyRenderPass(*device_, render_pass_, nullptr);
}
if (render_cmd_buffer_) {
vkFreeCommandBuffers(*device_, cmd_pool_, 1, &render_cmd_buffer_);
}
if (cmd_pool_) {
vkDestroyCommandPool(*device_, cmd_pool_, nullptr);
}
// images_ doesn't need to be cleaned up as the swapchain does it implicitly.
if (handle) {
vkDestroySwapchainKHR(*device_, handle, nullptr);
handle = nullptr;
}
if (surface_) {
vkDestroySurfaceKHR(*instance_, surface_, nullptr);
}
}
VulkanSwapChain::~VulkanSwapChain() { Shutdown(); }
bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
surface_ = surface;
@ -338,6 +314,47 @@ void VulkanSwapChain::DestroyBuffer(Buffer* buffer) {
buffer->image = nullptr;
}
bool VulkanSwapChain::Reinitialize() {
// Hacky, but stash the surface so we can reuse it.
auto surface = surface_;
surface_ = nullptr;
Shutdown();
return Initialize(surface);
}
void VulkanSwapChain::Shutdown() {
// TODO(benvanik): properly wait for a clean state.
for (auto& buffer : buffers_) {
DestroyBuffer(&buffer);
}
buffers_.clear();
if (image_available_semaphore_) {
vkDestroySemaphore(*device_, image_available_semaphore_, nullptr);
image_available_semaphore_ = nullptr;
}
if (render_pass_) {
vkDestroyRenderPass(*device_, render_pass_, nullptr);
render_pass_ = nullptr;
}
if (render_cmd_buffer_) {
vkFreeCommandBuffers(*device_, cmd_pool_, 1, &render_cmd_buffer_);
render_cmd_buffer_ = nullptr;
}
if (cmd_pool_) {
vkDestroyCommandPool(*device_, cmd_pool_, nullptr);
cmd_pool_ = nullptr;
}
// images_ doesn't need to be cleaned up as the swapchain does it implicitly.
if (handle) {
vkDestroySwapchainKHR(*device_, handle, nullptr);
handle = nullptr;
}
if (surface_) {
vkDestroySurfaceKHR(*instance_, surface_, nullptr);
surface_ = nullptr;
}
}
bool VulkanSwapChain::Begin() {
// Get the index of the next available swapchain image.
auto err =

View File

@ -41,7 +41,12 @@ class VulkanSwapChain {
// Render command buffer, active inside the render pass from Begin to End.
VkCommandBuffer render_cmd_buffer() const { return render_cmd_buffer_; }
// Initializes the swap chain with the given WSI surface.
bool Initialize(VkSurfaceKHR surface);
// Reinitializes the swap chain with the initial surface.
// The surface will be retained but all other swap chain resources will be
// torn down and recreated with the new surface properties (size/etc).
bool Reinitialize();
// Begins the swap operation, preparing state for rendering.
bool Begin();
@ -58,6 +63,9 @@ class VulkanSwapChain {
bool InitializeBuffer(Buffer* buffer, VkImage target_image);
void DestroyBuffer(Buffer* buffer);
// Safely releases all swap chain resources.
void Shutdown();
VulkanInstance* instance_ = nullptr;
VulkanDevice* device_ = nullptr;