Manage X11 display and harden surface recovery

Reuse and store the X11 Display pointer (as void*) so createSurface
doesn't repeatedly open displays. Close the display during cleanup and
before device recreation.

Add a short 200ms delay in recreateDevice to let the GPU driver
stabilize, and explicitly recheck surface support and query surface
capabilities before recreating the swapchain.
This commit is contained in:
ubuntu1804 2025-11-11 17:10:32 +08:00
parent 1845e6113e
commit 3c52aa1ca3
2 changed files with 62 additions and 5 deletions

View File

@ -8,6 +8,7 @@
#include <QCloseEvent>
#include <QWindow>
#include <QApplication>
#include <QThread>
#include <algorithm>
#include <cmath>
@ -35,6 +36,7 @@ VulkanWidget::VulkanWidget(QWidget *parent)
, m_surface(VK_NULL_HANDLE)
, m_swapchain(VK_NULL_HANDLE)
, m_commandPool(VK_NULL_HANDLE)
, m_x11Display(nullptr)
, m_initialized(false)
, m_renderingEnabled(false)
, m_needsResize(false)
@ -342,12 +344,22 @@ bool VulkanWidget::createSurface()
#elif defined(__linux__)
VkXlibSurfaceCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
// Get X11 display - use default display
createInfo.dpy = XOpenDisplay(nullptr);
if (!createInfo.dpy) {
qDebug() << "Failed to open X11 display";
return false;
// Reuse existing X11 display or open a new one
Display* x11Display = static_cast<Display*>(m_x11Display);
if (!x11Display) {
x11Display = XOpenDisplay(nullptr);
if (!x11Display) {
qDebug() << "Failed to open X11 display";
return false;
}
m_x11Display = x11Display;
qDebug() << "X11 display opened and stored";
} else {
qDebug() << "Reusing existing X11 display";
}
createInfo.dpy = x11Display;
createInfo.window = static_cast<Window>(window->winId());
VkResult result = vkCreateXlibSurfaceKHR(m_instance, &createInfo, nullptr, &m_surface);
@ -1071,6 +1083,15 @@ void VulkanWidget::cleanupVulkan()
if (m_surface != VK_NULL_HANDLE) {
vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
}
// Close X11 display if it was opened (Linux only)
#ifdef __linux__
if (m_x11Display) {
XCloseDisplay(static_cast<Display*>(m_x11Display));
m_x11Display = nullptr;
qDebug() << "X11 display closed";
}
#endif
// Cleanup instance
if (m_instance != VK_NULL_HANDLE) {
@ -1303,7 +1324,22 @@ bool VulkanWidget::recreateDevice()
qDebug() << "Surface destroyed";
}
// Close and reset X11 display (Linux only) - will be reopened when creating new surface
#ifdef __linux__
if (m_x11Display) {
XCloseDisplay(static_cast<Display*>(m_x11Display));
m_x11Display = nullptr;
qDebug() << "X11 display closed for recreation";
}
#endif
// Now recreate everything from surface onwards
// Important: Add a small delay to let the GPU driver fully reset
// This prevents VK_ERROR_SURFACE_LOST_KHR on some systems
qDebug() << "Waiting for GPU driver to stabilize...";
QThread::msleep(200); // 200ms delay
// Step 1: Recreate surface
if (!createSurface()) {
setError("Failed to recreate surface after device lost");
@ -1311,6 +1347,16 @@ bool VulkanWidget::recreateDevice()
}
qDebug() << "Surface recreated";
// Verify the physical device still supports this surface
VkBool32 surfaceSupported = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, m_queueFamilyIndex, m_surface, &surfaceSupported);
if (!surfaceSupported) {
qDebug() << "Physical device no longer supports the surface after recovery";
setError("Surface not supported by physical device after recovery");
return false;
}
qDebug() << "Surface support verified";
// Step 2: Recreate logical device
if (!createDevice()) {
setError("Failed to recreate device after device lost");
@ -1319,6 +1365,16 @@ bool VulkanWidget::recreateDevice()
qDebug() << "Logical device recreated";
// Step 3: Recreate swapchain
// Query surface capabilities again to ensure they're current
VkSurfaceCapabilitiesKHR surfaceCaps;
VkResult capsResult = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &surfaceCaps);
if (capsResult != VK_SUCCESS) {
qDebug() << "Failed to query surface capabilities, error:" << capsResult;
setError("Failed to query surface capabilities after device lost");
return false;
}
qDebug() << "Surface capabilities validated";
if (!createSwapchain()) {
setError("Failed to recreate swapchain after device lost");
return false;

View File

@ -214,6 +214,7 @@ private:
VkSurfaceKHR m_surface;
VkSwapchainKHR m_swapchain;
VkCommandPool m_commandPool;
void* m_x11Display; // X11 Display pointer (Linux only), stored as void* to avoid X11 header dependency
std::vector<VkCommandBuffer> m_commandBuffers;
std::vector<VkSemaphore> m_imageAvailableSemaphores;
std::vector<VkSemaphore> m_renderFinishedSemaphores;