vulkan - vulkan:VkImageMemoryBarrier
问题描述
我不太明白这里。: https ://github.com/SaschaWillems/Vulkan/blob/master/examples/computeshader/computeshader.cpp
void draw()
{
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
// Submit compute commands
// Use a fence to ensure that compute command buffer has finished executin before using it again
vkWaitForFences(device, 1, &compute.fence, VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &compute.fence);
VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo();
computeSubmitInfo.commandBufferCount = 1;
computeSubmitInfo.pCommandBuffers = &compute.commandBuffer;
VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, compute.fence));
}
drawCmdBuffers[currentBuffer] 在compute.commandBuffer 之前运行,但是消费者drawCmdBuffers[currentBuffer] 需要生产者compute.commandBuffer 生成的textureComputeTarget。
- 我不明白为什么在compute.commandBuffer 之前调用drawCmdBuffers[currentBuffer]。
在下面的代码中,只渲染了第一帧,而右图没有得到textureComputeTarget,所以渲染为蓝色背景。
void draw()
{
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
// Submit compute commands
// Use a fence to ensure that compute command buffer has finished executin before using it again
vkWaitForFences(device, 1, &compute.fence, VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &compute.fence);
VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo();
computeSubmitInfo.commandBufferCount = 1;
computeSubmitInfo.pCommandBuffers = &compute.commandBuffer;
VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, compute.fence));
sleep(1000) // <-------- Wait
}
调用时执行vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)
:
VkImageMemoryBarrier imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
// We won't be changing the layout of the image
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
imageMemoryBarrier.image = textureComputeTarget.image;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
drawCmdBuffers[i],
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_FLAGS_NONE,
0, nullptr,
0, nullptr,
1, &imageMemoryBarrier);
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
- 等待VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,但是这个阶段之前没有执行过,为什么管道没有卡住?是不是因为之前没有管道,所以不需要等待?
在第 6.6 节管道屏障中,vkCmdPipelineBarrier 是一个同步命令,它在提交到同一队列的命令之间或同一子通道中的命令之间插入依赖关系。
void draw()
{
printf("%p, %p\n", queue, compute.queue);
VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame();
// Submit compute commands
// Use a fence to ensure that compute command buffer has finished executin before using it again
vkWaitForFences(device, 1, &compute.fence, VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &compute.fence);
VkSubmitInfo computeSubmitInfo = vks::initializers::submitInfo();
computeSubmitInfo.commandBufferCount = 1;
computeSubmitInfo.pCommandBuffers = &compute.commandBuffer;
VK_CHECK_RESULT(vkQueueSubmit(compute.queue, 1, &computeSubmitInfo, compute.fence));
sleep(1000);
}
打印结果:0x6000039c4a20, 0x6000039c4a20 当前队列和compute.queue是同一个队列。但是上面的代码有可能生成不同的队列。
VkImageMemoryBarrier 可以在多个队列中同步吗?
vkCmdPipelineBarrier 是一个同步命令,它在提交到同一队列的命令之间或同一子通道中的命令之间插入依赖关系 。为什么使用“或”,为什么不使用 “和”?
解决方案
- 我不明白为什么在compute.commandBuffer 之前调用drawCmdBuffers[currentBuffer]。
不知道,这是一个例子。作者可能并不十分担心第一帧会发生什么。它只会以一帧延迟绘制。在绘制之前交换计算也应该付出一些努力。
- 等待
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
,但是这个阶段之前没有执行过,为什么管道没有卡住?是不是因为之前没有管道,所以不需要等待?
因为这不是管道和依赖项的工作方式。vkCmdPipelineBarrier
确保在屏障到达(并完成)之前队列中的任何命令\操作至少在到达之后记录的任何命令\操作之前的srcStage
阶段(即COMPUTE
)dstStage
。
即使之前没有记录任何命令,也满足这种依赖性。即根据“无”的定义,没有尚未达到COMPUTE
阶段的命令。
- 可以
VkImageMemoryBarrier
在多个队列中同步吗?
是的,在信号量的帮助下。
对于VK_SHARING_MODE_EXCLUSIVE
不同的队列族,它被称为队列族所有权转移(QFOT)。
否则,信号量已经执行了内存依赖,VkImageMemoryBarrier
不需要 a。
vkCmdPipelineBarrier
是一个同步命令,它在提交到同一队列的命令之间或同一子通道中的命令之间插入依赖关系。为什么使用“或”,为什么不使用“和”?
vkCmdPipelineBarrier
要么在子通道之外,然后它与队列中记录的前后命令形成依赖关系。
或者vkCmdPipelineBarrier
位于子通道内,在这种情况下,它称为“子通道自依赖”,其范围仅限于该子通道(以及其他限制)。
推荐阅读
- java - RandomAccessFile 没有从文件中读取任何内容
- laravel-lighthouse - 无法在 Laravel 8 全新安装上安装 Lighthouse
- flutter - 禁用时 Flutter FlutButton 样式不起作用
- powershell - 使用 PowerShell 将日志行从起始字符串提取到第一个时间戳
- python - 一个对象可以从一个类提升到另一个类吗?(从学徒到绝地大师)
- ruby-on-rails - 如何在 ERB(Rails)中注入 data-inject-svg?
- html - 在移动屏幕上看不到完整的幻灯片
- javascript - 如何在 Firebase 函数中实现模块化常量
- android - 在camerax中捕获没有音频的视频
- rust - Rust 不能返回引用局部变量的值