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

当我尝试在 vkQueueWaitIdle 之后重置 commandPool 时 Vulkan 验证错误

如何解决当我尝试在 vkQueueWaitIdle 之后重置 commandPool 时 Vulkan 验证错误

我有一个小的 Vulkan 程序,它循环运行计算着色器。

只有一个 commandBuffer 是从我唯一的 commandPool 分配的。

commandBuffer 构建完成后,我将其提交到队列中,等待它完成 vkQueueWaitIddle。我确实在那行代码中等待了一段时间。之后,我调用 vkResetCommandPool,它应该重置所有分配给该池的 commandBuffer(反正只有一个)。

...

vkEndCommandBuffer(commandBuffer);
        
{
    VkSubmitInfo info = {};
    info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    info.commandBufferCount = 1;
    info.pCommandBuffers = &commandBuffer;
    vkQueueSubmit(queue,1,&info,VK_NULL_HANDLE);
}
vkQueueWaitIdle(queue);

vkResetCommandPool(device,commandPool,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);

当它尝试重置 commandPool 时,验证会给我以下错误

VUID-vkResetCommandPool-commandPool-00040(ERROR / SPEC): msgNum: -1254218959
- Validation Error: [ VUID-vkResetCommandPool-commandPool-00040 ]
Object 0: handle = 0x20d2ce0b718,type = VK_OBJECT_TYPE_COMMAND_BUFFER; |
MessageID = 0xb53e2331 |
Attempt to reset command pool with VkCommandBuffer 0x20d2ce0b718[] which is in use.
The Vulkan spec states: All VkCommandBuffer objects allocated from commandPool must not be in the pending state
(https://vulkan.lunarg.com/doc/view/1.2.176.1/windows/1.2-extensions/vkspec.html#VUID-vkResetCommandPool-commandPool-00040)
    Objects: 1
        [0] 0x20d2ce0b718,type: 6,name: NULL

但我不明白为什么,因为我已经在等待 vkQueueWaitIdle。根据 documentation,一旦 commandBuffer 执行完毕,它应该进入 invalid 状态,我应该能够重置它。

这是相关的周围代码

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

for (i64 i = 0; i < numIterations; i++)
{
    vkBeginCommandBuffer(commandBuffer,&beginInfo);

    vkCmdBindPipeline(commandBuffer,VK_PIPELINE_BIND_POINT_COmpuTE,pipeline);
    vkCmdBindDescriptorSets(commandBuffer,pipelineLayout,2,descriptorSets,nullptr);

    uniforms.start = i * numThreads;
    vkCmdUpdateBuffer(commandBuffer,unifsBuffer,sizeof(uniforms),&uniforms);
    vkCmdPipelineBarrier(commandBuffer,VK_PIPELINE_STAGE_TRANSFER_BIT,VK_PIPELINE_STAGE_COmpuTE_SHADER_BIT,nullptr,&memBarriers[0],nullptr);

    vkCmddispatch(commandBuffer,numThreads,1);

    vkCmdPipelineBarrier(commandBuffer,&memBarriers[1],nullptr);

    VkBuffercopy copyInfo = {};
    copyInfo.srcOffset = 0;
    copyInfo.dstOffset = 0;
    copyInfo.size = sizeof(i64) * numThreads;
    vkCmdcopyBuffer(commandBuffer,buffer,stagingBuffer,&copyInfo);

    vkEndCommandBuffer(commandBuffer);
        
    {
        VkSubmitInfo info = {};
        info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
        info.commandBufferCount = 1;
        info.pCommandBuffers = &commandBuffer;
        vkQueueSubmit(queue,VK_NULL_HANDLE);
    }
    vkQueueWaitIdle(queue);
    vkResetCommandPool(device,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);

    i64* result;
    vkMapMemory(device,stagingBufferMem,sizeof(i64) * numThreads,(void**)&result);

    for (int i = 0; i < numThreads; i++)
    {
        if (result[i]) {
            auto res = result[i];
            vkUnmapMemory(device,stagingBufferMem);
            return res;
        }
    }
    vkUnmapMemory(device,stagingBufferMem);
}

解决方法

我发现了我的问题。在 vkCmdDispatch 中,我认为参数指定了全局大小(计算着色器调用的数量),但实际上是工作组的数量。因此,我调度的线程比我预期的要多,而且我的缓冲区不够大,所以线程写出越界。 我相信验证层并没有给我正确的提示。

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