Prevent rendering during close and validate surface
Add m_isClosing flag and closeEvent to stop rendering, stop the render timer and wait for device idle. Guard swapchain creation and recreation to abort when closing. Check Vulkan return values and detect invalid surface capabilities to avoid crashes during window teardown.
This commit is contained in:
parent
2c7119d190
commit
e34cb5883a
|
|
@ -5,6 +5,7 @@
|
|||
#include <QHideEvent>
|
||||
#include <QResizeEvent>
|
||||
#include <QPaintEvent>
|
||||
#include <QCloseEvent>
|
||||
#include <QWindow>
|
||||
#include <QApplication>
|
||||
#include <algorithm>
|
||||
|
|
@ -52,6 +53,7 @@ VulkanWidget::VulkanWidget(QWidget *parent)
|
|||
, m_lastLockFrameCount(0)
|
||||
, m_lockPaintFrameCount(0)
|
||||
, m_lockCount(0)
|
||||
, m_isClosing(false)
|
||||
{
|
||||
// Set widget attributes for native window
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
|
|
@ -483,9 +485,20 @@ bool VulkanWidget::createSwapchain()
|
|||
qDebug() << "Widget size:" << width() << "x" << height();
|
||||
qDebug() << "Device pixel ratio:" << devicePixelRatioF();
|
||||
|
||||
// Don't create swapchain if closing
|
||||
if (m_isClosing) {
|
||||
qDebug() << "Aborting swapchain creation - widget is closing";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Query surface capabilities
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &capabilities);
|
||||
VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &capabilities);
|
||||
|
||||
if (result != VK_SUCCESS) {
|
||||
qDebug() << "Failed to get surface capabilities, error code:" << result;
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "Surface capabilities - current extent:"
|
||||
<< capabilities.currentExtent.width << "x" << capabilities.currentExtent.height;
|
||||
|
|
@ -494,6 +507,16 @@ bool VulkanWidget::createSwapchain()
|
|||
qDebug() << "Surface capabilities - max extent:"
|
||||
<< capabilities.maxImageExtent.width << "x" << capabilities.maxImageExtent.height;
|
||||
|
||||
// Validate surface capabilities - detect invalid/corrupted values
|
||||
// This can happen when the window is being destroyed
|
||||
if (capabilities.currentExtent.width > 16384 || capabilities.currentExtent.height > 16384 ||
|
||||
capabilities.minImageExtent.width > 16384 || capabilities.minImageExtent.height > 16384 ||
|
||||
capabilities.maxImageExtent.width > 1000000 || capabilities.maxImageExtent.height > 1000000) {
|
||||
qDebug() << "ERROR: Invalid surface capabilities detected - surface may be destroyed";
|
||||
qDebug() << "This usually happens when the window is being closed";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Query surface formats
|
||||
uint32_t formatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr);
|
||||
|
|
@ -576,9 +599,9 @@ bool VulkanWidget::createSwapchain()
|
|||
createInfo.clipped = VK_TRUE;
|
||||
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
VkResult result = vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapchain);
|
||||
if (result != VK_SUCCESS) {
|
||||
qDebug() << "Failed to create swapchain, error code:" << result;
|
||||
VkResult swapchainResult = vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapchain);
|
||||
if (swapchainResult != VK_SUCCESS) {
|
||||
qDebug() << "Failed to create swapchain, error code:" << swapchainResult;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -607,9 +630,9 @@ bool VulkanWidget::createSwapchain()
|
|||
viewInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
VkImageView imageView;
|
||||
result = vkCreateImageView(m_device, &viewInfo, nullptr, &imageView);
|
||||
if (result != VK_SUCCESS) {
|
||||
qDebug() << "Failed to create image view" << i << ", error code:" << result;
|
||||
VkResult viewResult = vkCreateImageView(m_device, &viewInfo, nullptr, &imageView);
|
||||
if (viewResult != VK_SUCCESS) {
|
||||
qDebug() << "Failed to create image view" << i << ", error code:" << viewResult;
|
||||
return false;
|
||||
}
|
||||
m_swapchainImageViews[i] = reinterpret_cast<void*>(imageView);
|
||||
|
|
@ -686,6 +709,12 @@ bool VulkanWidget::recreateSwapchain()
|
|||
{
|
||||
qDebug() << "Recreating swapchain...";
|
||||
|
||||
// Don't recreate if closing
|
||||
if (m_isClosing) {
|
||||
qDebug() << "Aborting swapchain recreation - widget is closing";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for device to be idle
|
||||
vkDeviceWaitIdle(m_device);
|
||||
|
||||
|
|
@ -710,7 +739,8 @@ bool VulkanWidget::recreateSwapchain()
|
|||
|
||||
void VulkanWidget::renderFrame()
|
||||
{
|
||||
if (!m_initialized) {
|
||||
// Don't render if closing or not initialized
|
||||
if (!m_initialized || m_isClosing) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -993,6 +1023,29 @@ void VulkanWidget::hideEvent(QHideEvent *event)
|
|||
setRenderingEnabled(false);
|
||||
}
|
||||
|
||||
void VulkanWidget::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
qDebug() << "VulkanWidget closeEvent - stopping rendering and cleaning up";
|
||||
|
||||
// Set closing flag to prevent any further rendering attempts
|
||||
m_isClosing = true;
|
||||
|
||||
// Stop the render timer immediately
|
||||
if (m_renderTimer) {
|
||||
m_renderTimer->stop();
|
||||
qDebug() << "Render timer stopped on close";
|
||||
}
|
||||
|
||||
// Wait for device to be idle before accepting close event
|
||||
if (m_device != VK_NULL_HANDLE) {
|
||||
vkDeviceWaitIdle(m_device);
|
||||
qDebug() << "Vulkan device idle on close";
|
||||
}
|
||||
|
||||
// Accept the close event
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
void VulkanWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
|
|
|
|||
|
|
@ -62,6 +62,11 @@ protected:
|
|||
*/
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
|
||||
/**
|
||||
* @brief Qt事件:窗口关闭时
|
||||
*/
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
/**
|
||||
* @brief Qt事件:组件大小改变时
|
||||
*/
|
||||
|
|
@ -208,6 +213,7 @@ private:
|
|||
bool m_renderingEnabled;
|
||||
bool m_needsResize;
|
||||
bool m_needsLockedFrameUpdate; // 是否需要渲染锁屏帧(锁屏时只渲染一帧)
|
||||
bool m_isClosing; // 标记窗口正在关闭,防止在销毁过程中继续渲染
|
||||
int m_frameCount;
|
||||
uint32_t m_queueFamilyIndex;
|
||||
uint32_t m_currentFrame;
|
||||
|
|
|
|||
Loading…
Reference in New Issue