窗口调整时Vulkan的pRenderPassBegin->framebuffer无效问题求助
Vulkan窗口调整/全屏切换时帧缓冲无效问题分析
问题现象
我的Vulkan应用在旧笔记本、搭载Intel UHD核显的笔记本上运行正常,但在搭载RTX4060m显卡的新笔记本上,调整窗口大小或切换全屏/窗口模式时,验证层报错renderPassCreateInfo->framebuffer无效,随后程序约1秒后崩溃。
控制台日志
Validationl layer: Searching for ICD drivers named .\nvoglv64.dll Validationl layer: Loading layer library C:\msys2\publicPkg\VulkanSDK\1.3.296.0\Bin\.\VkLayer_khronos_validation.dll Validationl layer: Loading layer library C:\WINDOWS\System32\DriverStore\FileRepository\nvcvegpu.inf_amd64_2b4a4257593cec26\.\nvoglv64.dll Validationl layer: Validation Error: [ VUID-VkRenderPassBeginInfo-framebuffer-parameter ] Object 0: handle = 0x1b359d88860, type = VK_OBJECT_TYPE_INSTANCE; | MessageID = 0xe02fa864 | vkCmdBeginRenderPass(): pRenderPassBegin->framebuffer Invalid VkFramebuffer Object 0x1b35c20bd50. The Vulkan spec states: framebuffer must be a valid VkFramebuffer handle
动态状态配置
VkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
相关代码片段
帧缓冲创建函数
void __fastcall createFramebuffers(void) { swapchainFramebuffers = g_array_sized_new(false, true, sizeof(VkFramebuffer), swapchainImageViews->len); g_array_set_size(swapchainFramebuffers, swapchainImageViews->len); for (uint_fast32_t i = 0; i < swapchainImageViews->len; ++i) { VkImageView imageAttachments[] = { g_array_index(swapchainImageViews, VkImageView, i) }; VkFramebufferCreateInfo framebufferInfo = (const VkFramebufferCreateInfo){ }; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = graphicsRenderPass; framebufferInfo.attachmentCount = 1; framebufferInfo.pAttachments = imageAttachments; framebufferInfo.layers = 1; framebufferInfo.width = swapchain2DExtent.width; framebufferInfo.height = swapchain2DExtent.height; if (vkCreateFramebuffer(logicalGpu, &framebufferInfo, NULL, &g_array_index(swapchainFramebuffers, VkFramebuffer, i)) != VK_SUCCESS) printf_s("Failed to create framebuffer!"); } }
命令缓冲录制函数(问题行标注)
void __fastcall recordCommandBuffer(VkCommandBuffer graphicsCommandBuffer, uint_fast32_t imageIndex) { VkCommandBufferBeginInfo commandBufferUsageInfo = (const VkCommandBufferBeginInfo){ }; commandBufferUsageInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; commandBufferUsageInfo.flags = 0; commandBufferUsageInfo.pInheritanceInfo = NULL; if (vkBeginCommandBuffer(graphicsCommandBuffer, &commandBufferUsageInfo) != VK_SUCCESS) printf_s("Failed to begin recording command buffer!"); VkRenderPassBeginInfo graphicsRenderPassInfo = (const VkRenderPassBeginInfo){ }; graphicsRenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; graphicsRenderPassInfo.renderPass = graphicsRenderPass; graphicsRenderPassInfo.framebuffer = g_array_index(swapchainFramebuffers, VkFramebuffer, imageIndex); //! PROBLEM graphicsRenderPassInfo.renderArea.offset = (VkOffset2D){0, 0}; graphicsRenderPassInfo.renderArea.extent = swapchain2DExtent; graphicsRenderPassInfo.clearValueCount = 1; graphicsRenderPassInfo.pClearValues = (VkClearValue[4]){ 0.0f, 0.0f, 0.0f, 1.0f }; vkCmdBeginRenderPass(graphicsCommandBuffer, &graphicsRenderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(graphicsCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); VkViewport viewport = (const VkViewport){ }; viewport.x = 0.0f; viewport.y = 0.0f; viewport.width = (float)swapchain2DExtent.width; viewport.height = (float)swapchain2DExtent.height; viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor = (const VkRect2D){ }; scissor.offset = (VkOffset2D){0, 0}; scissor.extent = swapchain2DExtent; vkCmdSetViewport(graphicsCommandBuffer, 0, 1, &viewport); vkCmdSetScissor(graphicsCommandBuffer, 0, 1, &scissor); vkCmdDraw(graphicsCommandBuffer, 3, 1, 0, 0); vkCmdEndRenderPass(graphicsCommandBuffer); if (vkEndCommandBuffer(graphicsCommandBuffer) != VK_SUCCESS) printf_s("Failed to end recording command buffer!"); }
问题原因分析
这个问题的核心是窗口尺寸变更后,未正确更新帧缓冲及命令缓冲,导致引用了已失效的VkFramebuffer对象,而NVIDIA驱动对Vulkan对象有效性的校验比Intel核显驱动更严格:
帧缓冲与swapchain尺寸不匹配:窗口resize或全屏切换时,swapchain的
extent会发生变化,原来基于旧尺寸创建的帧缓冲会因为尺寸不匹配而失效,必须销毁并重建适配新尺寸的帧缓冲。你的代码仅实现了初始帧缓冲创建,但没有在窗口尺寸变更时执行销毁旧帧缓冲、更新swapchain2DExtent、重建新帧缓冲的流程。命令缓冲复用未重新录制:如果你的命令缓冲是一次性录制后复用的(当前
recordCommandBuffer的flags为0,没有设置允许复用的标记),旧命令缓冲中会保留对旧帧缓冲的引用,即使重建了新帧缓冲,旧命令缓冲仍会引用无效对象,触发验证层报错。驱动校验差异:Intel核显驱动可能对短暂的无效对象引用容忍度更高,但这属于违反Vulkan规范的行为;NVIDIA驱动的验证层会严格执行规范,及时检测到无效帧缓冲并报错,最终导致程序崩溃。
内容的提问来源于stack exchange,提问作者Brain_driver_not_found
相关产品推荐
相关产品推荐

