在Vulkan中,您可以使用vkCreateGraphicsPipeline
或vkCreateComputePipeline
创建pipeline derivates,basePipelineHandle
或basePipelineIndex
成员VkGraphicsPipelineCreateInfo
/ { {1}}。该文档声明此功能可用于性能原因:
派生管道的目标是使用父项作为起点创建它们更便宜,并且在同一父项的子项之间切换/绑定更有效(在主机或设备上)。
这为我提出了很多问题:
VkComputePipelineCreateInfo
创建父管道。总是使用这个标志是否有缺点(例如,如果您将来可以从这个创建派生管道)?答案 0 :(得分:5)
有没有办法表明父管道和子管道之间共享的状态
没有;管道创建API无法告诉它将改变什么状态。这个想法是,由于实施可以看到父母的状态,并且它可以看到你对孩子的状态的要求,它可以告诉你的不同之处。
此外,如果有这样的方式,它只会代表一种方式让你不小心误导实施改变了什么。最好让实施计算出变化。
有没有办法知道实现是否实际上从使用派生管道(分析除外)中获得了任何好处?
没有
需要使用
VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT
创建父管道。总是使用这个标志是否有缺点(例如,如果您将来可以从这个创建派生管道)?
可能。由于#1,实现需要存储至少某种形式的父管道状态,以便它可以将其与子管道的状态进行比较。并且它必须以易于阅读的形式存储此状态,这可能与GPU内存和要复制到命令流中的令牌的形式不同。因此,父流水线很可能会为这些数据分配额外的内存。虽然它们在绑定/命令执行时间较慢的可能性很低。
您可以通过将分配器传递给管道创建功能来轻松地测试它。如果它分配的内存量与没有标志的内存相同,那么它可能不会存储任何内容。
答案 1 :(得分:1)
我问这个问题,调查管道衍生工具是否会带来好处。这是我从供应商处找到的一些资源:
Tips and Tricks: Vulkan Dos and Don’ts,Nvidia,2019年6月6日
不要期望管道衍生工具会加速。
Vulkan Usage Recommendations,三星
管道派生使应用程序可以随着类似的“父”状态的增量状态变化来表达“子”管道;在某些架构上,这可以减少在相似状态之间切换的成本。许多移动GPU主要通过管道缓存来获得性能,因此管道派生通常无法为便携式移动应用程序带来任何好处。
建议
- 在应用程序执行的早期创建管道。避免在绘制时创建管道。
- 使用单个管道缓存进行所有管道创建。
- 在应用程序运行之间将管道缓存写入文件。
- 避免使用管道衍生工具。
Vulkan Best Practice for Mobile Developers - Pipeline Management,Arm Software,2019年7月11日
不要
- 在绘制时创建管道而没有管道缓存(会导致性能停顿)。
- 使用不受支持的管道衍生工具。
Vulkan样本,LunarG,API-Samples/pipeline_derivative/pipeline_derivative.cpp
/*
VULKAN_SAMPLE_SHORT_DESCRIPTION
This sample creates pipeline derivative and draws with it.
Pipeline derivatives should allow for faster creation of pipelines.
In this sample, we'll create the default pipeline, but then modify
it slightly and create a derivative. The derivatve will be used to
render a simple cube.
We may later find that the pipeline is too simple to show any speedup,
or that replacing the fragment shader is too expensive, so this sample
can be updated then.
*/
似乎没有任何供应商实际上建议使用管道派生工具,只是可能会加快管道创建。
对我来说,这在理论上似乎是个好主意,但在实践中并没有多大作用。
此外,如果应该使驱动程序受益于多个管道的公共父级,则它应该完全能够自动执行该祖先检测。可以基于提供最佳加速的任何特定公共管道状态来合成“公共祖先”。为什么要通过API明确指定?
答案 2 :(得分:0)
我不是计算机图形学专家,但我的理解(部分包括直觉)如下:
有没有办法说明父管道和子管道之间共享哪个状态,还是实现决定?
管道的某些方面未在渲染时指定(因此是固定的),例如要使用的着色器。我的推测是派生的和派生的管道可能共享这些“只读”信息(或者用C语言,它们指向同一个对象)。这就是为什么派生管道的创建更快。
在这些管道之间切换也会更快,因为在更改管道时更改资源的需求更少,因为某些资源是共享的并且相同。
需要使用VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT创建父管道。总是使用这个标志是否有缺点(例如,如果您将来可以从这个创建派生管道)?
这很可能取决于实现。我的推测是,当你允许派生时,你启用资源(例如着色器)共享,这意味着实现可能会对这些资源进行引用计数。如果不分享资源,这将是不必要的成本。此外,在更改管道时,驱动程序不需要检查每个资源是否共享并且可以保留在GPU上,还是不需要更改。如果没有共享,则所有资源都将被更改,并且没有检查的开销。这些都不是开销,所以要么Vulkan保持安全,要么还有另一个我不知道的原因。