窗口的大小变化事件处理
在之前的学习中,可以绘抽制出三角形了,但是用鼠标来改变窗口的大小时,可以看到,整个窗口会停顿一秒左右或是黑一秒左右,才会反应在过来。给人的感觉不友好。这就需要在窗口的大小发生变化时,做一些事情来处理这种情况。
《vulkan编程指南》中有说明,vulkan中对于窗口的大小变化是有处理的,即窗口大小发生变化时,会触发VK_ERROR_OUT_OF_DATE_KHR信息。但这种触发是不可靠的。需要显示处理。
所以在SceneWidget.h中添加一个成员变量bool m_resize = false;当窗口大小发生变化时,设置值为true,来记录大小是否发生了变量。在SceneWidget::DrawFrame里,检测这个变量,当m_resize值为true或是vkAcquireNextImageKHR函数和vkQueuePresentKHR返回值为VK_ERROR_OUT_OF_DATE_KHR或是VK_SUBOPTIMAL_KHR时,需要做对应的处理。
VK_ERROR_OUT_OF_DATE_KHR:交换链不能再使用,通常发生在窗口大小变化之后。
VK_SUBOPTIMAL_KHR:交换链仍然可以使用,但surface属性已经不能准确匹配。
所以先在SceneWidget:: resizeEvent函数中,将m_resize的值赋成true。然后在DrawFrame函数修改现有的代码进行处理。
在vkAcquireNextImageKHR函数调用之后,判断是否返回VK_ERROR_OUT_OF_DATE_KHR,如果是,则重建交换链
如果返回的是不是VK_ERROR_OUT_OF_DATE_KHR、VK_SUBOPTIMAL_KHR也不是VK_SUCCESS,输出错误日志。
即把原来的if换成下面的:
if (result == VK_ERROR_OUT_OF_DATE_KHR)
{
RecreateSwapChain();
}
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
{
std::cout << "vkAcquireNextImageKHR return failed." << std::endl;
}
同样vkQueuePresentKHR的返回值也要判断,如果返回值是VK_ERROR_OUT_OF_DATE_KHR、VK_SUBOPTIMAL_KHR或者m_resize为true时,重建交换链。
添加如下判断的代码:
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || _bFramebufferResized)
{
m_resize = false;
RecreateSwapChain();
}
else if (result != VK_SUCCESS)
{
std::cout << "failed to present swap chain image!" << std::endl;
}
在SceneWidget.h中添加void RecreateSwapChain()函数,在函数里进行重建操作。
重建交换链调用RecreateSwapChain函数,窗口的大小发生变化,实际上是之前在创建Device时,对物理设备进行检查时,调用:
对m_capabilities中的currentExtent发生了变化。
所以基于这个m_capabilities. currentExtent创建出的对象,都需要删除重建。
在RecreateSwapChain()函数中主要做两个事情。
一:将基于这个m_capabilities. currentExtent创建出的对象删除
二:根据新的m_capabilities. currentExtent的值,把删除的对象再重建出来。
在SceneWidget.h中再添加一个函数,void CleanupSwapchain()进行删除。
然后在RecreateSwapChain()函数中先调用一下vkDeviceWaitIdle(m_device);先等待一下之前的绘制。
调用CleanupSwapchain(),删除之前创建的与m_capabilities. currentExtent相关的对象。
改写之前的SceneWidget::UnInit函数,将其中删除的与m_capabilities. currentExtent相关的对象,放入到CleanupSwapchain()里,并在SceneWidget::UnInit中调用CleanupSwapchain(),调用完成后,再生成这些被删除的对象。
与m_capabilities. currentExtent相关的对象,有:
VkSwapchainKHR、VkSwapchainKHR相关的VkImage和VkImageView、VkRenderPass、VkFrameBuffer、VkGraphicsPipeline(与renderPass相关,还创建了VkGraphicsPipelineLayout)、VkFrameBuffer、深度和颜色相关的VkImage和VkImageView。
运行结果:
改变窗口大小时,就好多了。