graphics - Order of action commands using subpass dependency?
问题描述
From what I have read so far, commands in a single command buffer can be out of order without explicit synchronization. Here is what the vulkan spec says (https://vulkan.lunarg.com/doc/view/1.0.26.0/linux/vkspec.chunked/ch02s02.html#fundamentals-queueoperation-commandorder)
"The work involved in performing action commands is often allowed to overlap or to be reordered, but doing so must not alter the state to be used by each action command. In general, action commands are those commands that alter framebuffer attachments, read/write buffer or image memory, or write to query pools."
Edit: At first I thought that set state commands would act as some kind of barrier to ensure that draw commands are in order. I have already been explained that this is wrong. So I look at this example of bloom effect in 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]);
Here are the 2 subpass dependencies used by both render passes
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;
My understanding then becomes that these 2 subpass dependencies are responsible for the execution ordering of the render pass but I'm not sure how yet since I'm still fuzzy about subpass dependency. If I'm correct in my understanding can you explain to me why the subpass dependency helps order the draw command? If I'm wrong then what is ensuring the draw command order?
解决方案
所以发生的事情是某些东西被渲染到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
\ after之前的东西vkCmdEndRenderPass
是同步范围的一部分。
了解同步系统需要时间,我无法在此正确介绍。在Using pipeline barrier instead of semaphores上,我对障碍有更多的扩展答案,否则互联网上也充满了资源。
推荐阅读
- c# - 控制器参数将 DateTime 反序列化为 UTC
- c# - 我正在使用 VEctor2 进行破折号移动,但它不会移动角色
- node.js - 我们如何使用通过 axios 将请求接收到的数据放在 mern 堆栈的客户端?
- ruby-on-rails - before_action 具有相同的回调但不同的条件不起作用
- python - Tkinter:单击按钮时如何将按钮的文本作为参数传递给函数
- html - 居中 div 元素
- php - Pimcore 管理侧边栏修改
- pandas - 尝试将 csv 转换为 HDF5 并使用 vaex 读取它
- java - 如何从 Java 的任意字节数组中派生 AES 256 位密钥?
- accessibility-insights - 从 ClassName 为 Chrome_RenderWidgetHostHWND 的元素初始化 UIautomation 树。可访问性见解