[Vulkan] Propagate swap chain initialization errors
This commit is contained in:
parent
7ae5795cb8
commit
4ca8cafc1b
|
@ -94,7 +94,7 @@ bool VulkanContext::Initialize() {
|
||||||
#endif // XE_PLATFORM_WIN32
|
#endif // XE_PLATFORM_WIN32
|
||||||
swap_chain_ = std::make_unique<VulkanSwapChain>(provider->instance(),
|
swap_chain_ = std::make_unique<VulkanSwapChain>(provider->instance(),
|
||||||
provider->device());
|
provider->device());
|
||||||
if (!swap_chain_->Initialize(surface)) {
|
if (swap_chain_->Initialize(surface) != VK_SUCCESS) {
|
||||||
XELOGE("Unable to initialize swap chain");
|
XELOGE("Unable to initialize swap chain");
|
||||||
vkDestroySurfaceKHR(*provider->instance(), surface, nullptr);
|
vkDestroySurfaceKHR(*provider->instance(), surface, nullptr);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -34,25 +34,31 @@ VulkanSwapChain::VulkanSwapChain(VulkanInstance* instance, VulkanDevice* device)
|
||||||
|
|
||||||
VulkanSwapChain::~VulkanSwapChain() { Shutdown(); }
|
VulkanSwapChain::~VulkanSwapChain() { Shutdown(); }
|
||||||
|
|
||||||
bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||||
surface_ = surface;
|
surface_ = surface;
|
||||||
|
|
||||||
VkBool32 surface_supported = false;
|
VkBool32 surface_supported = false;
|
||||||
auto err = vkGetPhysicalDeviceSurfaceSupportKHR(
|
auto status = vkGetPhysicalDeviceSurfaceSupportKHR(
|
||||||
*device_, device_->queue_family_index(), surface, &surface_supported);
|
*device_, device_->queue_family_index(), surface, &surface_supported);
|
||||||
assert_true(surface_supported);
|
assert_true(surface_supported);
|
||||||
CheckResult(err, "vkGetPhysicalDeviceSurfaceSupportKHR");
|
CheckResult(status, "vkGetPhysicalDeviceSurfaceSupportKHR");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Query supported target formats.
|
// Query supported target formats.
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
err =
|
status =
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR(*device_, surface_, &count, nullptr);
|
vkGetPhysicalDeviceSurfaceFormatsKHR(*device_, surface_, &count, nullptr);
|
||||||
CheckResult(err, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
CheckResult(status, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
||||||
std::vector<VkSurfaceFormatKHR> surface_formats;
|
std::vector<VkSurfaceFormatKHR> surface_formats;
|
||||||
surface_formats.resize(count);
|
surface_formats.resize(count);
|
||||||
err = vkGetPhysicalDeviceSurfaceFormatsKHR(*device_, surface_, &count,
|
status = vkGetPhysicalDeviceSurfaceFormatsKHR(*device_, surface_, &count,
|
||||||
surface_formats.data());
|
surface_formats.data());
|
||||||
CheckResult(err, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
CheckResult(status, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// If the format list includes just one entry of VK_FORMAT_UNDEFINED the
|
// If the format list includes just one entry of VK_FORMAT_UNDEFINED the
|
||||||
// surface has no preferred format.
|
// surface has no preferred format.
|
||||||
|
@ -69,19 +75,29 @@ bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||||
|
|
||||||
// Query surface min/max/caps.
|
// Query surface min/max/caps.
|
||||||
VkSurfaceCapabilitiesKHR surface_caps;
|
VkSurfaceCapabilitiesKHR surface_caps;
|
||||||
err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(*device_, surface_,
|
status = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(*device_, surface_,
|
||||||
&surface_caps);
|
&surface_caps);
|
||||||
CheckResult(err, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
|
CheckResult(status, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Query surface properties so we can configure ourselves within bounds.
|
// Query surface properties so we can configure ourselves within bounds.
|
||||||
std::vector<VkPresentModeKHR> present_modes;
|
std::vector<VkPresentModeKHR> present_modes;
|
||||||
err = vkGetPhysicalDeviceSurfacePresentModesKHR(*device_, surface_, &count,
|
status = vkGetPhysicalDeviceSurfacePresentModesKHR(*device_, surface_, &count,
|
||||||
nullptr);
|
nullptr);
|
||||||
CheckResult(err, "vkGetPhysicalDeviceSurfacePresentModesKHR");
|
CheckResult(status, "vkGetPhysicalDeviceSurfacePresentModesKHR");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
present_modes.resize(count);
|
present_modes.resize(count);
|
||||||
err = vkGetPhysicalDeviceSurfacePresentModesKHR(*device_, surface_, &count,
|
status = vkGetPhysicalDeviceSurfacePresentModesKHR(*device_, surface_, &count,
|
||||||
present_modes.data());
|
present_modes.data());
|
||||||
CheckResult(err, "vkGetPhysicalDeviceSurfacePresentModesKHR");
|
CheckResult(status, "vkGetPhysicalDeviceSurfacePresentModesKHR");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate swapchain target dimensions.
|
// Calculate swapchain target dimensions.
|
||||||
VkExtent2D extent = surface_caps.currentExtent;
|
VkExtent2D extent = surface_caps.currentExtent;
|
||||||
|
@ -162,10 +178,10 @@ bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||||
XELOGVK(" imageSharingMode = %s", to_string(create_info.imageSharingMode));
|
XELOGVK(" imageSharingMode = %s", to_string(create_info.imageSharingMode));
|
||||||
XELOGVK(" queueFamilyCount = %u", create_info.queueFamilyIndexCount);
|
XELOGVK(" queueFamilyCount = %u", create_info.queueFamilyIndexCount);
|
||||||
|
|
||||||
err = vkCreateSwapchainKHR(*device_, &create_info, nullptr, &handle);
|
status = vkCreateSwapchainKHR(*device_, &create_info, nullptr, &handle);
|
||||||
if (err) {
|
if (status != VK_SUCCESS) {
|
||||||
XELOGE("Failed to create swapchain: %s", to_string(err));
|
XELOGE("Failed to create swapchain: %s", to_string(status));
|
||||||
return false;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the pool used for transient buffers, so we can reset them all at
|
// Create the pool used for transient buffers, so we can reset them all at
|
||||||
|
@ -175,8 +191,11 @@ bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||||
cmd_pool_info.pNext = nullptr;
|
cmd_pool_info.pNext = nullptr;
|
||||||
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
cmd_pool_info.queueFamilyIndex = device_->queue_family_index();
|
cmd_pool_info.queueFamilyIndex = device_->queue_family_index();
|
||||||
err = vkCreateCommandPool(*device_, &cmd_pool_info, nullptr, &cmd_pool_);
|
status = vkCreateCommandPool(*device_, &cmd_pool_info, nullptr, &cmd_pool_);
|
||||||
CheckResult(err, "vkCreateCommandPool");
|
CheckResult(status, "vkCreateCommandPool");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Primary command buffer
|
// Primary command buffer
|
||||||
VkCommandBufferAllocateInfo cmd_buffer_info;
|
VkCommandBufferAllocateInfo cmd_buffer_info;
|
||||||
|
@ -185,15 +204,22 @@ bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||||
cmd_buffer_info.commandPool = cmd_pool_;
|
cmd_buffer_info.commandPool = cmd_pool_;
|
||||||
cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
cmd_buffer_info.commandBufferCount = 2;
|
cmd_buffer_info.commandBufferCount = 2;
|
||||||
err = vkAllocateCommandBuffers(*device_, &cmd_buffer_info, &cmd_buffer_);
|
status = vkAllocateCommandBuffers(*device_, &cmd_buffer_info, &cmd_buffer_);
|
||||||
CheckResult(err, "vkCreateCommandBuffer");
|
CheckResult(status, "vkCreateCommandBuffer");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Make two command buffers we'll do all our primary rendering from.
|
// Make two command buffers we'll do all our primary rendering from.
|
||||||
VkCommandBuffer command_buffers[2];
|
VkCommandBuffer command_buffers[2];
|
||||||
cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
|
cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
|
||||||
cmd_buffer_info.commandBufferCount = 2;
|
cmd_buffer_info.commandBufferCount = 2;
|
||||||
err = vkAllocateCommandBuffers(*device_, &cmd_buffer_info, command_buffers);
|
status =
|
||||||
CheckResult(err, "vkCreateCommandBuffer");
|
vkAllocateCommandBuffers(*device_, &cmd_buffer_info, command_buffers);
|
||||||
|
CheckResult(status, "vkCreateCommandBuffer");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
render_cmd_buffer_ = command_buffers[0];
|
render_cmd_buffer_ = command_buffers[0];
|
||||||
copy_cmd_buffer_ = command_buffers[1];
|
copy_cmd_buffer_ = command_buffers[1];
|
||||||
|
@ -238,53 +264,75 @@ bool VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||||
render_pass_info.pSubpasses = &render_subpass;
|
render_pass_info.pSubpasses = &render_subpass;
|
||||||
render_pass_info.dependencyCount = 0;
|
render_pass_info.dependencyCount = 0;
|
||||||
render_pass_info.pDependencies = nullptr;
|
render_pass_info.pDependencies = nullptr;
|
||||||
err = vkCreateRenderPass(*device_, &render_pass_info, nullptr, &render_pass_);
|
status =
|
||||||
CheckResult(err, "vkCreateRenderPass");
|
vkCreateRenderPass(*device_, &render_pass_info, nullptr, &render_pass_);
|
||||||
|
CheckResult(status, "vkCreateRenderPass");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a semaphore we'll use to synchronize with the swapchain.
|
// Create a semaphore we'll use to synchronize with the swapchain.
|
||||||
VkSemaphoreCreateInfo semaphore_info;
|
VkSemaphoreCreateInfo semaphore_info;
|
||||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
semaphore_info.pNext = nullptr;
|
semaphore_info.pNext = nullptr;
|
||||||
semaphore_info.flags = 0;
|
semaphore_info.flags = 0;
|
||||||
err = vkCreateSemaphore(*device_, &semaphore_info, nullptr,
|
status = vkCreateSemaphore(*device_, &semaphore_info, nullptr,
|
||||||
&image_available_semaphore_);
|
&image_available_semaphore_);
|
||||||
CheckResult(err, "vkCreateSemaphore");
|
CheckResult(status, "vkCreateSemaphore");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Create another semaphore used to synchronize writes to the swap image.
|
// Create another semaphore used to synchronize writes to the swap image.
|
||||||
err = vkCreateSemaphore(*device_, &semaphore_info, nullptr,
|
status = vkCreateSemaphore(*device_, &semaphore_info, nullptr,
|
||||||
&image_usage_semaphore_);
|
&image_usage_semaphore_);
|
||||||
CheckResult(err, "vkCreateSemaphore");
|
CheckResult(status, "vkCreateSemaphore");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Get images we will be presenting to.
|
// Get images we will be presenting to.
|
||||||
// Note that this may differ from our requested amount.
|
// Note that this may differ from our requested amount.
|
||||||
uint32_t actual_image_count = 0;
|
uint32_t actual_image_count = 0;
|
||||||
std::vector<VkImage> images;
|
std::vector<VkImage> images;
|
||||||
err = vkGetSwapchainImagesKHR(*device_, handle, &actual_image_count, nullptr);
|
status =
|
||||||
CheckResult(err, "vkGetSwapchainImagesKHR");
|
vkGetSwapchainImagesKHR(*device_, handle, &actual_image_count, nullptr);
|
||||||
|
CheckResult(status, "vkGetSwapchainImagesKHR");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
images.resize(actual_image_count);
|
images.resize(actual_image_count);
|
||||||
err = vkGetSwapchainImagesKHR(*device_, handle, &actual_image_count,
|
status = vkGetSwapchainImagesKHR(*device_, handle, &actual_image_count,
|
||||||
images.data());
|
images.data());
|
||||||
CheckResult(err, "vkGetSwapchainImagesKHR");
|
CheckResult(status, "vkGetSwapchainImagesKHR");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Create all buffers.
|
// Create all buffers.
|
||||||
buffers_.resize(images.size());
|
buffers_.resize(images.size());
|
||||||
for (size_t i = 0; i < buffers_.size(); ++i) {
|
for (size_t i = 0; i < buffers_.size(); ++i) {
|
||||||
if (!InitializeBuffer(&buffers_[i], images[i])) {
|
status = InitializeBuffer(&buffers_[i], images[i]);
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
XELOGE("Failed to initialize a swapchain buffer");
|
XELOGE("Failed to initialize a swapchain buffer");
|
||||||
return false;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffers_[i].image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
buffers_[i].image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
XELOGVK("Swap chain initialized successfully!");
|
XELOGVK("Swap chain initialized successfully!");
|
||||||
return true;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanSwapChain::InitializeBuffer(Buffer* buffer, VkImage target_image) {
|
VkResult VulkanSwapChain::InitializeBuffer(Buffer* buffer,
|
||||||
|
VkImage target_image) {
|
||||||
DestroyBuffer(buffer);
|
DestroyBuffer(buffer);
|
||||||
buffer->image = target_image;
|
buffer->image = target_image;
|
||||||
|
|
||||||
|
VkResult status;
|
||||||
|
|
||||||
// Create an image view for the presentation image.
|
// Create an image view for the presentation image.
|
||||||
// This will be used as a framebuffer attachment.
|
// This will be used as a framebuffer attachment.
|
||||||
VkImageViewCreateInfo image_view_info;
|
VkImageViewCreateInfo image_view_info;
|
||||||
|
@ -303,9 +351,12 @@ bool VulkanSwapChain::InitializeBuffer(Buffer* buffer, VkImage target_image) {
|
||||||
image_view_info.subresourceRange.levelCount = 1;
|
image_view_info.subresourceRange.levelCount = 1;
|
||||||
image_view_info.subresourceRange.baseArrayLayer = 0;
|
image_view_info.subresourceRange.baseArrayLayer = 0;
|
||||||
image_view_info.subresourceRange.layerCount = 1;
|
image_view_info.subresourceRange.layerCount = 1;
|
||||||
auto err = vkCreateImageView(*device_, &image_view_info, nullptr,
|
status = vkCreateImageView(*device_, &image_view_info, nullptr,
|
||||||
&buffer->image_view);
|
&buffer->image_view);
|
||||||
CheckResult(err, "vkCreateImageView");
|
CheckResult(status, "vkCreateImageView");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the framebuffer used to render into this image.
|
// Create the framebuffer used to render into this image.
|
||||||
VkImageView attachments[] = {buffer->image_view};
|
VkImageView attachments[] = {buffer->image_view};
|
||||||
|
@ -320,11 +371,14 @@ bool VulkanSwapChain::InitializeBuffer(Buffer* buffer, VkImage target_image) {
|
||||||
framebuffer_info.width = surface_width_;
|
framebuffer_info.width = surface_width_;
|
||||||
framebuffer_info.height = surface_height_;
|
framebuffer_info.height = surface_height_;
|
||||||
framebuffer_info.layers = 1;
|
framebuffer_info.layers = 1;
|
||||||
err = vkCreateFramebuffer(*device_, &framebuffer_info, nullptr,
|
status = vkCreateFramebuffer(*device_, &framebuffer_info, nullptr,
|
||||||
&buffer->framebuffer);
|
&buffer->framebuffer);
|
||||||
CheckResult(err, "vkCreateFramebuffer");
|
CheckResult(status, "vkCreateFramebuffer");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanSwapChain::DestroyBuffer(Buffer* buffer) {
|
void VulkanSwapChain::DestroyBuffer(Buffer* buffer) {
|
||||||
|
@ -340,7 +394,7 @@ void VulkanSwapChain::DestroyBuffer(Buffer* buffer) {
|
||||||
buffer->image = nullptr;
|
buffer->image = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanSwapChain::Reinitialize() {
|
VkResult VulkanSwapChain::Reinitialize() {
|
||||||
// Hacky, but stash the surface so we can reuse it.
|
// Hacky, but stash the surface so we can reuse it.
|
||||||
auto surface = surface_;
|
auto surface = surface_;
|
||||||
surface_ = nullptr;
|
surface_ = nullptr;
|
||||||
|
|
|
@ -47,11 +47,11 @@ class VulkanSwapChain {
|
||||||
VkCommandBuffer copy_cmd_buffer() const { return copy_cmd_buffer_; }
|
VkCommandBuffer copy_cmd_buffer() const { return copy_cmd_buffer_; }
|
||||||
|
|
||||||
// Initializes the swap chain with the given WSI surface.
|
// Initializes the swap chain with the given WSI surface.
|
||||||
bool Initialize(VkSurfaceKHR surface);
|
VkResult Initialize(VkSurfaceKHR surface);
|
||||||
// Reinitializes the swap chain with the initial surface.
|
// Reinitializes the swap chain with the initial surface.
|
||||||
// The surface will be retained but all other swap chain resources will be
|
// The surface will be retained but all other swap chain resources will be
|
||||||
// torn down and recreated with the new surface properties (size/etc).
|
// torn down and recreated with the new surface properties (size/etc).
|
||||||
bool Reinitialize();
|
VkResult Reinitialize();
|
||||||
|
|
||||||
// Waits on and signals a semaphore in this operation.
|
// Waits on and signals a semaphore in this operation.
|
||||||
void WaitAndSignalSemaphore(VkSemaphore sem);
|
void WaitAndSignalSemaphore(VkSemaphore sem);
|
||||||
|
@ -69,7 +69,7 @@ class VulkanSwapChain {
|
||||||
VkFramebuffer framebuffer = nullptr;
|
VkFramebuffer framebuffer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool InitializeBuffer(Buffer* buffer, VkImage target_image);
|
VkResult InitializeBuffer(Buffer* buffer, VkImage target_image);
|
||||||
void DestroyBuffer(Buffer* buffer);
|
void DestroyBuffer(Buffer* buffer);
|
||||||
|
|
||||||
// Safely releases all swap chain resources.
|
// Safely releases all swap chain resources.
|
||||||
|
|
Loading…
Reference in New Issue