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:
parent
1845e6113e
commit
3c52aa1ca3
|
|
@ -8,6 +8,7 @@
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QThread>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
|
@ -35,6 +36,7 @@ VulkanWidget::VulkanWidget(QWidget *parent)
|
||||||
, m_surface(VK_NULL_HANDLE)
|
, m_surface(VK_NULL_HANDLE)
|
||||||
, m_swapchain(VK_NULL_HANDLE)
|
, m_swapchain(VK_NULL_HANDLE)
|
||||||
, m_commandPool(VK_NULL_HANDLE)
|
, m_commandPool(VK_NULL_HANDLE)
|
||||||
|
, m_x11Display(nullptr)
|
||||||
, m_initialized(false)
|
, m_initialized(false)
|
||||||
, m_renderingEnabled(false)
|
, m_renderingEnabled(false)
|
||||||
, m_needsResize(false)
|
, m_needsResize(false)
|
||||||
|
|
@ -342,12 +344,22 @@ bool VulkanWidget::createSurface()
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
VkXlibSurfaceCreateInfoKHR createInfo = {};
|
VkXlibSurfaceCreateInfoKHR createInfo = {};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
|
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
|
||||||
// Get X11 display - use default display
|
|
||||||
createInfo.dpy = XOpenDisplay(nullptr);
|
// Reuse existing X11 display or open a new one
|
||||||
if (!createInfo.dpy) {
|
Display* x11Display = static_cast<Display*>(m_x11Display);
|
||||||
|
if (!x11Display) {
|
||||||
|
x11Display = XOpenDisplay(nullptr);
|
||||||
|
if (!x11Display) {
|
||||||
qDebug() << "Failed to open X11 display";
|
qDebug() << "Failed to open X11 display";
|
||||||
return false;
|
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());
|
createInfo.window = static_cast<Window>(window->winId());
|
||||||
|
|
||||||
VkResult result = vkCreateXlibSurfaceKHR(m_instance, &createInfo, nullptr, &m_surface);
|
VkResult result = vkCreateXlibSurfaceKHR(m_instance, &createInfo, nullptr, &m_surface);
|
||||||
|
|
@ -1072,6 +1084,15 @@ void VulkanWidget::cleanupVulkan()
|
||||||
vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
|
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
|
// Cleanup instance
|
||||||
if (m_instance != VK_NULL_HANDLE) {
|
if (m_instance != VK_NULL_HANDLE) {
|
||||||
vkDestroyInstance(m_instance, nullptr);
|
vkDestroyInstance(m_instance, nullptr);
|
||||||
|
|
@ -1303,7 +1324,22 @@ bool VulkanWidget::recreateDevice()
|
||||||
qDebug() << "Surface destroyed";
|
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
|
// 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
|
// Step 1: Recreate surface
|
||||||
if (!createSurface()) {
|
if (!createSurface()) {
|
||||||
setError("Failed to recreate surface after device lost");
|
setError("Failed to recreate surface after device lost");
|
||||||
|
|
@ -1311,6 +1347,16 @@ bool VulkanWidget::recreateDevice()
|
||||||
}
|
}
|
||||||
qDebug() << "Surface recreated";
|
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
|
// Step 2: Recreate logical device
|
||||||
if (!createDevice()) {
|
if (!createDevice()) {
|
||||||
setError("Failed to recreate device after device lost");
|
setError("Failed to recreate device after device lost");
|
||||||
|
|
@ -1319,6 +1365,16 @@ bool VulkanWidget::recreateDevice()
|
||||||
qDebug() << "Logical device recreated";
|
qDebug() << "Logical device recreated";
|
||||||
|
|
||||||
// Step 3: Recreate swapchain
|
// 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()) {
|
if (!createSwapchain()) {
|
||||||
setError("Failed to recreate swapchain after device lost");
|
setError("Failed to recreate swapchain after device lost");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,7 @@ private:
|
||||||
VkSurfaceKHR m_surface;
|
VkSurfaceKHR m_surface;
|
||||||
VkSwapchainKHR m_swapchain;
|
VkSwapchainKHR m_swapchain;
|
||||||
VkCommandPool m_commandPool;
|
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<VkCommandBuffer> m_commandBuffers;
|
||||||
std::vector<VkSemaphore> m_imageAvailableSemaphores;
|
std::vector<VkSemaphore> m_imageAvailableSemaphores;
|
||||||
std::vector<VkSemaphore> m_renderFinishedSemaphores;
|
std::vector<VkSemaphore> m_renderFinishedSemaphores;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue