提交单次 CommandBuffer 后 Vulkan Device Lost
Vulkan Device Lost after submitting single-time CommandBuffer
我编写了一个基本的 Vulkan 渲染器有一段时间了,它运行良好。然后它坏了(电源问题),我将 Vulkan 驱动程序重新安装到版本 1.0.42.0,从那时起,它在提交 CommandBuffer 供一次性使用(加载纹理等)时给我错误 VK_ERROR_DEVICE_LOST。我已经在具有不同 GPU 的不同设备上尝试了代码,并且它工作得很好。具体破解代码:
vkEndCommandBuffer(commandBuffer);
VkSubmitInfo submitInfo =
init::SubmitInfo();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(context->transferQueue, 1, &submitInfo, VK_NULL_HANDLE);
//works fine until now
vkQueueWaitIdle(context->transferQueue);
//This gives me VK_ERROR_DEVICE_LOST
vkFreeCommandBuffers(context->device, context->cmdTempPool, 1, &commandBuffer);
//Also doesn't work since commandbuffer is still in queue
它似乎也只在初始化期间发生,因为它在运行时(实际渲染代码)没有给我任何错误,但它们在清理期间再次发生(删除纹理和缓冲区)
是否有针对此问题的任何报告或解决方法?
确切的验证层输出是:
ParameterValidation: vkQueueWaitIdle: returned VK_ERROR_DEVICE_LOST,
indicating that the logical device has been lost
DS: Attempt to free command buffer (0x000002D18AAF1A90) which is in use. For
more information refer to Vulkan Spec Section '5.3. Command Buffer
Allocation and Management' which states 'All elements of pCommandBuffers
must not be in the pending state'
(https://www.khronos.org/registry/vulkan/specs/1.0-
extensions/html/vkspec.html#vkFreeCommandBuffers)
ParameterValidation: vkQueueSubmit: returned VK_ERROR_DEVICE_LOST,
indicating that the logical device has been lost
编辑:
因为它似乎只在转换图像布局时发生,这里是代码:
void util::transitionImageLayout(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout)
{
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
else {
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
if (oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
else {
throw std::invalid_argument("unsupported layout transition!");
}
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
endSingleTimeCommands(commandBuffer);
}
如评论中所述,您需要跟踪图像所有权,尤其是。如果您使用不同的队列系列。
因此,如果您使用 VK_SHARING_MODE_CONCURRENT
,请确保指定在创建时访问图像的所有队列系列索引(VkImageCreateInfo.pQueueFamilyIndices
和 VkImageCreateInfo.queueFamilyIndexCount
)。如果您不需要对图像进行并发队列访问,您也可以使用 VK_SHARING_MODE_EXCLUSIVE
而无需指定队列系列索引。
在处理不同的队列系列索引(例如图形和计算)时,通过它们的 srcQueueFamilyIndex
和 dstQueueFamilyIndex
成员在两个方向上在您的屏障中进行适当的队列系列所有权转移也很重要。
我编写了一个基本的 Vulkan 渲染器有一段时间了,它运行良好。然后它坏了(电源问题),我将 Vulkan 驱动程序重新安装到版本 1.0.42.0,从那时起,它在提交 CommandBuffer 供一次性使用(加载纹理等)时给我错误 VK_ERROR_DEVICE_LOST。我已经在具有不同 GPU 的不同设备上尝试了代码,并且它工作得很好。具体破解代码:
vkEndCommandBuffer(commandBuffer);
VkSubmitInfo submitInfo =
init::SubmitInfo();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(context->transferQueue, 1, &submitInfo, VK_NULL_HANDLE);
//works fine until now
vkQueueWaitIdle(context->transferQueue);
//This gives me VK_ERROR_DEVICE_LOST
vkFreeCommandBuffers(context->device, context->cmdTempPool, 1, &commandBuffer);
//Also doesn't work since commandbuffer is still in queue
它似乎也只在初始化期间发生,因为它在运行时(实际渲染代码)没有给我任何错误,但它们在清理期间再次发生(删除纹理和缓冲区) 是否有针对此问题的任何报告或解决方法?
确切的验证层输出是:
ParameterValidation: vkQueueWaitIdle: returned VK_ERROR_DEVICE_LOST,
indicating that the logical device has been lost
DS: Attempt to free command buffer (0x000002D18AAF1A90) which is in use. For
more information refer to Vulkan Spec Section '5.3. Command Buffer
Allocation and Management' which states 'All elements of pCommandBuffers
must not be in the pending state'
(https://www.khronos.org/registry/vulkan/specs/1.0-
extensions/html/vkspec.html#vkFreeCommandBuffers)
ParameterValidation: vkQueueSubmit: returned VK_ERROR_DEVICE_LOST,
indicating that the logical device has been lost
编辑: 因为它似乎只在转换图像布局时发生,这里是代码:
void util::transitionImageLayout(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout)
{
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
else {
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
if (oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
else {
throw std::invalid_argument("unsupported layout transition!");
}
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
endSingleTimeCommands(commandBuffer);
}
如评论中所述,您需要跟踪图像所有权,尤其是。如果您使用不同的队列系列。
因此,如果您使用 VK_SHARING_MODE_CONCURRENT
,请确保指定在创建时访问图像的所有队列系列索引(VkImageCreateInfo.pQueueFamilyIndices
和 VkImageCreateInfo.queueFamilyIndexCount
)。如果您不需要对图像进行并发队列访问,您也可以使用 VK_SHARING_MODE_EXCLUSIVE
而无需指定队列系列索引。
在处理不同的队列系列索引(例如图形和计算)时,通过它们的 srcQueueFamilyIndex
和 dstQueueFamilyIndex
成员在两个方向上在您的屏障中进行适当的队列系列所有权转移也很重要。