VkSubpassDependency 与信号量的使用?
Use of VkSubpassDependency vs semaphore?
我正在学习这个 vulkan 教程:https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation
我目前在 subpass 依赖项部分。作者在其中说,由于图像布局转换可能发生在我们从交换链获取图像之前,因此我们需要使用如下所示的 VkSubpassDependency,以便 renderpass 将在片段着色器输出阶段等待。
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
不过笔者之前也有这段代码
vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = { imageAvailableSemaphore };
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
VkSemaphore signalSemaphores[] = { renderFinishedSemaphore };
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
throw std::runtime_error("failed to submit command buffer");
}
这段代码的作用是,在我们能够从交换链实际获取图像之前,片段着色器阶段不会开始(imageAvailableSemaphore 确保了这一点)。对我来说,这两段代码在做同样的事情,即确保在我们能够获取图像之前片段着色器阶段不会开始。这是为什么?
PS:我也很难理解stagemask和access mask。
subpass 依赖表示从 initialLayout
到第一个布局的转换发生在各自同步范围的 srcStageMask
和 dstStageMask
之间。
带有 pWaitDstStageMask
的信号量等待表示信号量将不迟于该阶段等待(并且根据信号量等待的性质,将阻止任何后续执行,直到等待完成。
您不能跳过信号量,因为 vkAcquireNextImageKHR
不是队列操作,并且信号量(或栅栏)是知道表示引擎不再需要图像的唯一方法。
并且你不能跳过subpass依赖,因为跳过它等同于提供srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
。这意味着布局转换(可以是写访问)可以在任何时候执行。如果您的 pWaitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
,这意味着演示引擎可能仍在读取图像,而您的工作已经尝试更改图像布局。
您可以使用 pWaitDstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
(相应 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
)而不使用 barrier\dependency。但这意味着 "wait on the semaphore first thing",然后会阻止所有内容。包括甚至不需要交换链图像的部分(如顶点处理)。这在某些平台上可能不是最佳选择,没有理由这样做。
我应该补充一点,同步命令实际上并没有经过流水线阶段。它们只定义它们的同步范围之间的依赖关系。在信号量等待和 Subpass 依赖之间发生的是一个 执行依赖链 。信号量定义了 PE 和 COLOR
阶段之间的依赖关系。 Subpass Dependency 定义了 COLOR
阶段和布局转换之间的依赖关系。因此选择的阶段 do 在这两个同步原语之间形成一个 执行依赖链 。并且这样的链形成了一个传递属性;即它充当 PE 和布局转换之间的单一依赖项。
我正在学习这个 vulkan 教程:https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation 我目前在 subpass 依赖项部分。作者在其中说,由于图像布局转换可能发生在我们从交换链获取图像之前,因此我们需要使用如下所示的 VkSubpassDependency,以便 renderpass 将在片段着色器输出阶段等待。
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
不过笔者之前也有这段代码
vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = { imageAvailableSemaphore };
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
VkSemaphore signalSemaphores[] = { renderFinishedSemaphore };
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
throw std::runtime_error("failed to submit command buffer");
}
这段代码的作用是,在我们能够从交换链实际获取图像之前,片段着色器阶段不会开始(imageAvailableSemaphore 确保了这一点)。对我来说,这两段代码在做同样的事情,即确保在我们能够获取图像之前片段着色器阶段不会开始。这是为什么?
PS:我也很难理解stagemask和access mask。
subpass 依赖表示从 initialLayout
到第一个布局的转换发生在各自同步范围的 srcStageMask
和 dstStageMask
之间。
带有 pWaitDstStageMask
的信号量等待表示信号量将不迟于该阶段等待(并且根据信号量等待的性质,将阻止任何后续执行,直到等待完成。
您不能跳过信号量,因为 vkAcquireNextImageKHR
不是队列操作,并且信号量(或栅栏)是知道表示引擎不再需要图像的唯一方法。
并且你不能跳过subpass依赖,因为跳过它等同于提供srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
。这意味着布局转换(可以是写访问)可以在任何时候执行。如果您的 pWaitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
,这意味着演示引擎可能仍在读取图像,而您的工作已经尝试更改图像布局。
您可以使用 pWaitDstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
(相应 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
)而不使用 barrier\dependency。但这意味着 "wait on the semaphore first thing",然后会阻止所有内容。包括甚至不需要交换链图像的部分(如顶点处理)。这在某些平台上可能不是最佳选择,没有理由这样做。
我应该补充一点,同步命令实际上并没有经过流水线阶段。它们只定义它们的同步范围之间的依赖关系。在信号量等待和 Subpass 依赖之间发生的是一个 执行依赖链 。信号量定义了 PE 和 COLOR
阶段之间的依赖关系。 Subpass Dependency 定义了 COLOR
阶段和布局转换之间的依赖关系。因此选择的阶段 do 在这两个同步原语之间形成一个 执行依赖链 。并且这样的链形成了一个传递属性;即它充当 PE 和布局转换之间的单一依赖项。