ARTICLE AD BOX
I am using Vulkan and GLFW to draw a window. When I resize it multiple times, first swapchain creation starts to fail every other time, and then after an indefinite amount of errors, X11 just crashes my window and prints errors. I am on Linux 6.18.13-arch1-1, EndeavourOS, KDE 6, mesa driver for the AMD GPU.
[dbg::LOG_INFO] GLFW required instance extensions: [dbg::LOG_INFO] VK_KHR_surface [dbg::LOG_INFO] VK_KHR_xcb_surface [dbg::LOG_INFO] Selected physical device: AMD Radeon RX 7600 (RADV NAVI33) [dbg::LOG_INFO] VulkanNRI initialized with device: AMD Radeon RX 7600 (RADV NAVI33) [dbg::LOG_INFO] Chosen surface format: B8G8R8A8Unorm, color space: SrgbNonlinear [dbg::LOG_INFO] Creating swapchain for window with size 800x600 ... logs loading fonts, will skip [dbg::LOG_INFO] Creating swapchain for window with size 789x626 ... 284 logs of me resizing the window [dbg::LOG_INFO] Creating swapchain for window with size 438x531 [dbg::LOG_ERROR] Failed to create swapchain: failed_create_swapchain [dbg::LOG_INFO] Creating swapchain for window with size 524x503 [dbg::LOG_INFO] Creating swapchain for window with size 605x482 [dbg::LOG_ERROR] Failed to create swapchain: failed_create_swapchain [dbg::LOG_INFO] Creating swapchain for window with size 667x466 [dbg::LOG_INFO] Creating swapchain for window with size 698x456 [dbg::LOG_ERROR] Failed to create swapchain: failed_create_swapchain ... 33 errors like this total [dbg::LOG_INFO] Creating swapchain for window with size 958x497 [dbg::LOG_INFO] Creating swapchain for window with size 885x507 [dbg::LOG_ERROR] Failed to create swapchain: failed_create_swapchain X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 149 () Minor opcode of failed request: 4 Value in failed request: 0x6000e74 Serial number of failed request: 12370 Current serial number in output stream: 12386My code for creating swapchain:
void VulkanWindow::createSwapChain(uint32_t &width, uint32_t &height) { this->width = width; this->height = height; auto &nri = static_cast<VulkanNRI &>(this->nri); if (this->surface == nullptr) { THROW_RUNTIME_ERR("surface is not set for VulkanWindow!"); } vk::SurfaceCapabilitiesKHR capabilities; VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(nri.getPhysicalDevice(), *surface, (VkSurfaceCapabilitiesKHR *)&capabilities); if (res != VK_SUCCESS) { if (swapChain) vkDestroySwapchainKHR(nri.getDevice(), swapChain, nullptr); swapChain = vkb::Swapchain(); return; } width = capabilities.maxImageExtent.width; height = capabilities.maxImageExtent.height; dbLog(dbg::LOG_INFO, "Creating swapchain for window with size ", width, "x", height); vkb::SwapchainBuilder swapchainBuilder{nri.getPhysicalDevice(), nri.getDevice(), *surface}; swapchainBuilder.set_desired_present_mode((VkPresentModeKHR)vk::PresentModeKHR::eFifo); swapchainBuilder.set_desired_format((VkSurfaceFormatKHR)vk::SurfaceFormatKHR(surfaceFormat, surfaceColorSpace)); swapchainBuilder.set_desired_extent(width, height); swapchainBuilder.set_desired_min_image_count(capabilities.minImageCount + 1); swapchainBuilder.set_required_min_image_count(capabilities.minImageCount); if (swapChain != VK_NULL_HANDLE) swapchainBuilder.set_old_swapchain(swapChain); swapchainBuilder.set_image_usage_flags( VkImageUsageFlags(vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst)); swapchainBuilder.set_pre_transform_flags(VkSurfaceTransformFlagBitsKHR(vk::SurfaceTransformFlagBitsKHR::eIdentity)); auto swapchainResult = swapchainBuilder.build(); if (!swapchainResult.has_value()) { dbLog(dbg::LOG_ERROR, "Failed to create swapchain: ", swapchainResult.error().message()); if (swapChain) vkDestroySwapchainKHR(nri.getDevice(), swapChain, nullptr); this->swapChainImages.clear(); swapChain = vkb::Swapchain(); return; } swapChain = std::move(swapchainResult.value()); this->swapChainImages.clear(); std::vector<vk::Image> swapChainImages; uint32_t imageCount; vkGetSwapchainImagesKHR(nri.getDevice(), swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(nri.getDevice(), swapChain, &imageCount, (VkImage *)swapChainImages.data()); for (const auto &image : swapChainImages) { VulkanImage2D nriImage = VulkanImage2D(nri, image, vk::ImageLayout::eUndefined, vk::Format::eB8G8R8A8Unorm, nri.getDevice(), width, height); VulkanRenderTarget renderTarget = VulkanRenderTarget(nri, nriImage); this->swapChainImages.emplace_back(std::move(nriImage), std::move(renderTarget)); this->swapChainImages.back().image.transitionLayout( *commandBuffer, vk::ImageLayout::ePresentSrcKHR, vk::AccessFlagBits::eNone, vk::AccessFlagBits::eNone, vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eBottomOfPipe); } }Not the cleanest method at all. Always creates a swapchain with the maximal possible resolution. Here 'NRI' is my concept of a native interface. On the start of a frame I do the equivalent of:
glfwPollEvents(); if (swapChain == nullptr) { createSwapChain(width, height); // skip frame } else { // render everything and present. If present fails or returns SUBOPTIMAL, call createSwapChain() }Web searches tell me that I may be leaking X11 drawable surfaces, but I am destroying my old swapchains. Please help, will thank very much.
