Vulkan:管道衍生品的创造和收益

Vulkan: Creating and benefit of pipeline derivatives

在 Vulkan 中,您可以使用 vkCreateGraphicsPipelinevkCreateComputePipeline 创建 pipeline derivates,并使用 VkGraphicsPipelineCreateInfobasePipelineHandlebasePipelineIndex 成员/VkComputePipelineCreateInfo。文档指出此功能出于性能原因可用:

The goal of derivative pipelines is that they be cheaper to create using the parent as a starting point, and that it be more efficient (on either host or device) to switch/bind between children of the same parent.

这给我提出了很多问题:

  1. 有没有办法指示父子管道之间共享哪个状态,或者实现决定?
  2. 有什么方法可以知道实现是否真的从使用派生管道(除了分析)中获得任何好处?
  3. 需要使用 VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT 创建父管道。始终使用此标志是否有缺点(例如,以防您将来可能从该标志创建派生管道)?

Is there a way to indicate which state is shared between parent and child pipelines

否;管道创建 API 无法告诉它什么状态会改变。这个想法是,由于实现可以看到 parent 的状态,并且它可以看到你对 child 的状态的要求,所以它可以分辨出有什么不同。

此外,如果有这样的方法,那也只是一种让您不小心误导实施的方法。最好让实施找出变化。

Is there any way to know whether the implementation is actually getting any benefit from using derived pipelines (other than profiling)?

没有

The parent pipeline needs to be created with VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT. Is there a downside to always using this flag (eg. in case you may create a derived pipeline from this one in the future)?

可能吧。由于#1,实现需要至少存储某种形式的 parent 管道状态,以便它可以将其与 child 管道状态进行比较。并且它必须以易于阅读的形式存储此状态,这可能与要复制到命令流中的 GPU 内存和令牌的形式不同。因此,parent 管道很有可能会为此类数据分配额外的内存。尽管它们在 binding/command 执行时间变慢的可能性很低。

您可以通过将分配器传递给管道创建函数来轻松地进行测试。如果它分配了与没有标志相同的内存量,那么它可能没有存储任何东西。

我不是计算机图形学专家,但我的理解(部分包括直觉)如下:

Is there a way to indicate which state is shared between parent and child pipelines, or does the implementation decide?

管道的某些方面在渲染时未指定(因此是固定的),例如要使用的着色器。我的推测是派生自和派生管道可能共享这些 "read-only" 信息(或者用 C 术语来说,它们指向同一个对象)。这就是创建派生管道更快的原因。

这些管道之间的切换也会更快,因为在更改管道时不需要更改资源,因为一些资源是共享的并且是相同的。

The parent pipeline needs to be created with VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT. Is there a downside to always using this flag (eg. in case you may create a derived pipeline from this one in the future)?

这很可能取决于实现。我的推测是,当您允许派生时,您就启用了资源(例如着色器)共享,这意味着实现可能会对这些资源进行引用计数。如果不共享资源,那将是不必要的成本。此外,在更改管道时,驱动程序无需检查每个资源是否共享且可以保留在 GPU 上,或者不是且需要更改。如果没有共享,所有资源都会改变,并且没有检查开销。 None 其中的开销很大,所以要么 Vulkan 安全起见,要么还有其他我不知道的原因。

我来到这个问题是为了调查管道衍生品是否能带来好处。以下是我从供应商处找到的一些资源:

Tips and Tricks: Vulkan Dos and Don’ts,英伟达,2019 年 6 月 6 日

Don’t expect speedup from Pipeline Derivatives.

Vulkan Usage Recommendations、三星

Pipeline derivatives let applications express "child" pipelines as incremental state changes from a similar "parent"; on some architectures, this can reduce the cost of switching between similar states. Many mobile GPUs gain performance primarily through pipeline caches, so pipeline derivatives often provide no benefit to portable mobile applications.

Recommendations

  • Create pipelines early in application execution. Avoid pipeline creation at draw time.
  • Use a single pipeline cache for all pipeline creation.
  • Write the pipeline cache to a file between application runs.
  • Avoid pipeline derivatives.

Vulkan Best Practice for Mobile Developers - Pipeline Management,Arm 软件,2019 年 7 月 11 日

Don't

  • Create pipelines at draw time without a pipeline cache (introduces performance stutters).
  • Use pipeline derivatives as they are not supported.

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?

明确指定它