【发布时间】:2019-03-18 09:22:51
【问题描述】:
当多个帧在运行时,在 Vulkan 中同步访问单个缓冲区的最佳方法是什么?
我是 Vulkan 的新手,但我发现同步是最难理解的部分。我浏览了 Vulkan 规范、同步示例 (https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples)、Vulkan 教程 (https://vulkan-tutorial.com/) 以及一堆 Stack Overflow 帖子。不过,我仍然不确定我是否真的“明白”了。
为了帮助我学习,我正在尝试编写以下代码:
- 如 Vulkan 教程 (https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation#page_Frames_in_flight) 中所述,拥有多个正在运行的帧。
- 从单个存储缓冲区读取顶点着色器。
- 通过主机本地和主机一致的“暂存缓冲区”,每帧使用新数据更新部分存储缓冲区。
- 将有多个暂存缓冲区 - 一个用于每个正在运行的帧。
我认为第 N 帧的命令缓冲区(0
// Many parameters omitted for brevity
vkCmdCopyBuffer(commandBuffer[N], stagingBuffer[N], storageBuffer, ...);
VkMemoryBarrier barrier = {0};
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
commandBuffer[N],
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
0,
1,
&barrier,
...
);
// begin render pass
// drawing commands
// end render pass
vkCmdPipelineBarrier(
commandBuffer[N],
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0,
NULL,
...
);
我认为需要第一个管道屏障来防止 GPU 允许顶点着色器在存储缓冲区更新时读取它。
我认为需要第二个管道屏障来防止执行下一帧的vkCmdCopyBuffers 命令,直到前一帧的顶点着色器完成读取存储缓冲区。我的理解是这里不需要内存屏障,因为这是一个“战争危险”(https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples#first-draw-samples-a-texture-in-the-fragment-shader-second-draw-writes-to-that-texture-as-a-color-attachment)。
我的建议正确吗?还是我误解了什么?
注意:我知道我在上面采用的方法(即使正确)可能不是最好的 - 例如或许为每个运行中的帧提供 N 个存储缓冲区会提供更好的性能。不过,我希望在继续之前先了解同步。
感谢 Vulkan 大师提供的任何帮助!
【问题讨论】:
标签: c graphics synchronization rendering vulkan