c++ - 升级到1.2.162.1后 : vkQueueWaitIdle == VK_ERROR_DEVICE_LOST

标签 c++ vulkan

我最近将光线追踪渲染器从 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, 1, &commandBuffer);

它失败的地方之一是:

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

    //function pointer grabbed via vkGetDeviceProcAddr
    vk::vkCmdBuildAccelerationStructuresKHR(cmd, 1, &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, 1, &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 相同)。在诸如我的复制缓冲区代码第一个失败的情况下,错误总是在该代码之前的队列使用中发现。

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

关于c++ - 升级到1.2.162.1后 : vkQueueWaitIdle == VK_ERROR_DEVICE_LOST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66198321/

相关文章:

c++ - 64 位 C++ 二进制文件消耗大量内存,即使二进制文件很大

c++ - 扑克代码清理修改从书...不太正确

c++ - 为什么 vulkan 在集成显卡和 GPU 的系统中报告单个设备?

multithreading - `vkCommandPool` 可以从主线程分配并移动到其他线程吗?

c++ - 当 C++ 全局变量未显式初始化时发出警告?

c++ - 拆分整数乘法

c++ - 带有 VK_NULL_HANDLE 的 Vulkan DestroyInstance/DestroyDevice

graphics - 为什么单个深度缓冲区足以满足这个 vulkan 交换链渲染循环?

c++ - 模板静态函数模板类类型推导

c++ - 使用 Vulkan 绘制到多个窗口