我有点难以理解统一缓冲区和推送常量之间的概念差异。通过阅读规范可以了解到,主要区别在于:


统一缓冲区可以比推常量大得多。
UBO使用std140,PC使用std430。< brUBU可以随时通过vkCmdUpdateBuffer(或主机映射)进行更新,并保留其值,否则,每次渲染过程都必须重新推送PC。 (这使我感到惊讶-基于名称。我认为我会在字面上就地更新管道中的常量,并且使这些更改持续存在)

在我的场景中,我大约有200个字节的值我希望大部分数据保持不变。也就是说,我将很少更改它们。即使我必须在每个命令缓冲区中重新发送推送常量,(假设大小允许)使用推送常量会更好吗?还是使用200字节的UBO并仅使用vkCmdUpdatebuffer很少更新它会更好?

也。如果我有例如我每次运行着色器时都会更新的一个float random_seed吗?假设我已经有一个UBO,最好将它混入UBO中,即使UBO的其余部分是恒定的,还是我可以通过专门针对此变量使用推常量来受益,所以我可以避免每次渲染通过之前vkCmdUpdateBuffer吗?

评论

欢迎来到计算机图形堆栈交换网站!我不熟悉Vulkan,但在您的情况下使用UBO似乎会更有效(您可以尝试在示例程序中比较这两种方法的性能)。您熟悉哪些图形API?另外,您可能对此GDC 2012演示文稿感兴趣:不要一味扔掉:高效的缓冲区管理

根据Vulkan文档:虽然UBO在GPU上分配了一块视频内存(您可以稍后再更新),但Push Constant不使用视频内存(这就是为什么在每次绘图/计算调用时都必须提供视频内存的原因,否则着色器将不知道使用哪个值)。我想它存储在GPU上的另一个短期,快速存储区域中,尽管详细信息可能取决于您的GPU供应商。

#1 楼


可以使用vkCmdUpdateBuffer随时更新UBO。


根据规范:“仅允许在渲染过程之外使用vkCmdUpdateBuffer。”因此,“随时”都不是。

即使在渲染过程中允许使用它,它仍然是传输操作。这意味着您需要将内存传输与使用它的命令进行同步。这会降低性能。

对于一般的“推常数”还是“均匀”,请使用您的判断力。通过“判断”,我的意思是只看它们如何工作。推常量使您可以随时更改其数据,而无需执行繁重的过程,如内存操作,同步或更改描述符状态。显然,它们用于频繁更改的数据。 “频率”多久一次?好吧,这是一个判断电话。

如果失败,请分析性能差异。

#2 楼


我有大约200字节的数据,我希望它们基本上是恒定的。也就是说,我将很少更改它们。


如果数据很少更改,则可以使用特殊化常数。它们是在创建管道时设置的,如果需要更改值,则必须创建新的管道。对于不常发生的事件(例如调整窗口大小),这可能是可以接受的费用。


如果我有例如每次运行着色器时都会更新的float random_seed吗?


这是Push Constants的完美用例。您可以将所有其他数据保留在UBO(或专业化常量)中,并使用VkCmdPushConstants更改此值。