如何解决当我尝试在 vkQueueWaitIdle 之后重置 commandPool 时 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,©Info);
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 举报,一经查实,本站将立刻删除。