温馨提示:本文翻译自stackoverflow.com,查看原文请点击:graphics - Order of action commands using subpass dependency?
graphics vulkan

graphics - 使用子传递依赖项的操作命令顺序?

发布于 2020-05-02 08:13:41

到目前为止,根据我的读物,单个命令缓冲区中的命令可能会混乱,而无需显式同步。这是vulkan规范所说的内容(https://vulkan.lunarg.com/doc/view/1.0.26.0/linux/vkspec.chunked/ch02s02.html#fundamentals-queueoperation-commandorder

“执行动作命令所涉及的工作通常被允许重叠或重新排序,但是这样做一定不能改变每个动作命令要使用的状态。通常,动作命令是那些会更改帧缓冲区附件(读/写)的命令缓冲区或图像内存,或写入查询池。”

编辑:起初,我认为设置状态命令将充当某种障碍,以确保绘制命令井然有序。我已经被解释说这是错误的。所以我看一下Vulkan中的绽放效果示例 https://github.com/SaschaWillems/Vulkan/blob/master/examples/bloom/bloom.cpp

/*First render pass: Render glow parts of the model (separate mesh) to an offscreen frame buffer*/

vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.scene, 0, 1, &descriptorSets.scene, 0, NULL);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.glowPass);
VkDeviceSize offsets[1] = { 0 };
vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.ufoGlow.vertices.buffer, offsets);
vkCmdBindIndexBuffer(drawCmdBuffers[i], models.ufoGlow.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(drawCmdBuffers[i], models.ufoGlow.indexCount, 1, 0, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]);

/*Second render pass: Vertical blur
Render contents of the first pass into a second framebuffer and apply a vertical blur
This is the first blur pass, the horizontal blur is applied when rendering on top of the scene*/

renderPassBeginInfo.framebuffer = offscreenPass.framebuffers[1].framebuffer;
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.blur, 0, 1, &descriptorSets.blurVert, 0, NULL);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.blurVert);
vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]);

这是两个渲染过程都使用的2个子过程依赖项

dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

然后,我的理解是这两个子通道依赖关系负责渲染过程的执行顺序,但是由于我仍然对子通道依赖关系尚不清楚,因此我不确定如何执行。如果我的理解是正确的,您可以向我解释为什么子传递依赖项有助于命令draw命令吗?如果我错了,那么确保draw命令顺序的是什么?

查看更多

提问者
Henry Wise
被浏览
20
krOoze 2020-02-09 00:54

因此,正在发生的事情是渲染了某种东西img1(作为颜色附件)。然后 img1进行采样,然后将内容写入img2(作为颜色附件)。然后img2被采样并写入交换链映像。

dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;

dependencies[0].dstSubpass = 0;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;

对于第一个和第二个渲染遍历实例,这可能会阻止对资源的某些先前采样。可能来自前一帧。假设后续帧之间没有其他同步。

dependencies[1].srcSubpass = 0;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;

dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;

现在已经写入了颜色附件VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,更重要的是(又方便),存储操作在同一阶段进行颜色附件。VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT无论是STORE还是都不总是无关紧要的DONT_CARE

VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT并且VK_ACCESS_SHADER_READ_BIT再次非常适合图像采样(在片段着色器中)。

因此,这意味着img1在第二个渲染过程实例对它进行采样之前,它已从第一个渲染过程实例完全渲染并存储。

而且这也意味着img2在第二个渲染过程实例对它进行采样之前,它已从第二个渲染过程实例中完全渲染并存储。


这是一个高级示例,希望您已经了解同步。

状态命令不受同步限制。它们仅在引入后续动作命令后立即更改它们的上下文,并且通常持续到命令缓冲区结束或状态再次更改为止。

子传递依赖关系和障碍以这种方式定义了依赖关系:src同步作用域在dst同步作用域开始执行之前完成执行。

子通道的依赖性和障碍几乎相同。屏障通常在渲染过程之外使用,而子过程依赖于它。子通道彼此无序,因此子通道依赖项还具有*Subpass参数,并且同步作用域仅限于所述子通道。VK_SUBPASS_EXTERNAL表示vkCmdBeginRenderPass\之后的内容vkCmdEndRenderPass是同步范围的一部分。

了解同步系统需要花费一些时间,因此我无法在此处进行适当介绍。使用管道壁垒而不是信号灯时我对壁垒有更多扩展的答案,否则互联网上也将充满资源。