微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

升级到 1.2.162.1 后: vkQueueWaitIdle == VK_ERROR_DEVICE_LOST

如何解决升级到 1.2.162.1 后: vkQueueWaitIdle == VK_ERROR_DEVICE_LOST

我最近将我的光线追踪渲染器从 Vulkan SDK 版本 1.2.148.0 升级到 1.2.162.1。 这是必要的,因为光线追踪扩展超出了测试版,因此现在适用于非测试版 图形驱动程序(我的 RTX 2070 SUPER 版本为 461.40)。它需要我对渲染器的光线跟踪方面进行相当多的更改 感谢 nvidia 教程。

不幸的是,曾经可以工作的代码现在开始导致错误。 在许多情况下,提交单个时间命令会导致 vkQueueWaitIdle 失败并显示 VK_ERROR_DEVICE_LOST,从而导致验证错误,表示我正在尝试在命令缓冲区仍在使用时释放它。这有多种用途:转换图像布局(似乎是 undef 到一般)、构建加速结构、复制缓冲区但不是每次都复制(例如,从暂存缓冲区到设备缓冲区,之后释放暂存缓冲区也会引发错误,因为它仍在使用中,副本尚未完成)...但对于其他用途,它可以正常工作。我目前无法确定一个共同点...

最后,由于呈现第一帧失败,程序崩溃,因为它的布局未定义 - 我认为这是由前面提到的一个或多个错误引起的。

自从我上次使用它后有什么变化吗?这是违规代码(endSingleTimeCommands):

    vkEndCommandBuffer(commandBuffer);

    VkSubmitInfo submitInfo{};
    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    submitInfo.commandBufferCount = 1;
    submitInfo.pCommandBuffers = &commandBuffer;

    vkQueueSubmit(graphicsQueue,1,&submitInfo,VK_NULL_HANDLE);
    switch (vkQueueWaitIdle(graphicsQueue)) {
        //debug output removed for brevity
    };

    vkFreeCommandBuffers(device,commandPool,&commandBuffer);

失败的地方之一是:

    //[fill the structs with info...]

    //function pointer grabbed via vkGetDeviceProcAddr
    vk::vkCmdBuildaccelerationStructuresKHR(cmd,&buildInfo,&buildOffset);

    //[call to the above code here]

但与扩展无关的代码也会失败(有时!),例如:

    VkCommandBuffer commandBuffer = beginSingleTimeCommands();

    VkBuffercopy copyRegion{};
    copyRegion.srcOffset = 0; // Optional
    copyRegion.dstOffset = 0; // Optional
    copyRegion.size = size;
    vkCmdcopyBuffer(commandBuffer,srcBuffer,dstBuffer,&copyRegion);

    endSingleTimeCommands(commandBuffer);

也许 beginSingleTimeCommands 也是相关的:

    VkCommandBufferAllocateInfo alLocinfo{};
    alLocinfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
    alLocinfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
    alLocinfo.commandPool = commandPool;
    alLocinfo.commandBufferCount = 1;

    VkCommandBuffer commandBuffer;
    if (vkAllocateCommandBuffers(device,&alLocinfo,&commandBuffer) != VK_SUCCESS) {
        std::cout << "beginSingleTimeCommands: Could not allocate command buffer!\n";
    }

    VkCommandBufferBeginInfo beginInfo{};
    beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;

    if (vkBeginCommandBuffer(commandBuffer,&beginInfo) != VK_SUCCESS) {
        std::cout << "beginSingleTimeCommands: Could not begin command buffer!\n";
    }

    return commandBuffer;

我想我收集了一些额外的信息: 我使用 nvidia 管道检查点系统在调用 vkCmdBuildaccelerationStructuresKHR 之前和之后添加一个检查点,并且两个检查点都在 TOP_OF_PIPE。第一次调用函数后,不再生成检查点输出,这让我相信对构建的第一次调用以某种方式破坏了一切。我想我会三重检查我的 AS 建筑,如果我发现任何东西,我会回复你。

解决方法

事实证明,实际错误可能发生在 vkQueueWaitIdle 返回 DEVICE_LOST 错误的命令缓冲区之前。在我的加速结构构建代码中,我已经并且继续存在各种错误。我无法轻松调试它,因为显然验证层没有显示提供给 vkCmdBuildAccelerationStructures 的结构中是否存在细微错误,而是进行了大量的反复试验。

我确信升级前验证层会发现一个值得注意的例子是忘记设置 VkAccelerationStructureBuildGeometryInfoKHR::scratchData 字段,这是我必须修复的最后一个错误,以最终让一切运行起来。

我的问题的答案是:不要看触发 DEVICE_LOST 的命令,看看你在该命令之前对队列做了什么,有可能出现错误,反而。事实上,一旦第一个 DEVICE_LOST 错误发生,(几乎?)所有进一步的 vkQueueWaitIdle 都失败并出现相同的错误(与 vkQueueSubmit 相同)。在诸如我的复制缓冲区代码第一个失败的情况下,错误总是在队列使用之前发现。

我无法发布我的问题的确切解决方案,因为 - 就像我所说的 - 原因不止一个,到目前为止我只修复了其中的一些,还有一些。我认为这些细节与将来遇到我的问题的人无关,但如果我可以添加任何内容来帮助其他人,请告诉我。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。