我有一个使用两个计算着色器的应用程序。Shader #1
生成数据x
并将其存储在A
中,绑定为追加缓冲区。Shader #2
运行在A
的所有x
上,绑定为消费缓冲区。 我想通过添加Shader #3
来扩展它,它在A
中的所有x
上运行,将y
生成到新的缓冲区B
中 - 但我仍然希望Shader #2
像以前一样在x
上运行。
也就是说,我想对追加/消费缓冲区的所有元素运行操作,但不"消费"它们。
如果我理解正确,使用元素只会减少隐藏计数器,因此我应该能够通过在满时存储计数并在从中消耗的着色器调用之间重置它来多次使用缓冲区。
问题是我的平台 - Unity - 只有一种方法(SetCounterValue()
),这需要我传入新的计数器值。也就是说,我需要在重新设置之前获取 CPU 内存的计数器值,这将强制 GPU/CPU 之间同步并降低性能。
是否可以完全在 GPU 上设置消耗缓冲区的计数器值?
如果不是,是否可以在不使用消耗的情况下迭代消耗缓冲区?
(我曾想到只是将缓冲区绑定为常规 UAV 资源并以这种方式进行迭代,但文档对于是否支持此功能模棱两可。 例如,"这些资源不使用资源变量"是指资源本身还是视图?
执行此操作的正常方法(据我所知,我绝对不是 DirectCompute 专家!)是有两个缓冲区 - 您的数据缓冲区,在 Unity 中创建为缓冲区ComputeBufferType.Default
并在着色器中声明为RWStrucutedBuffer<YourStruct>
,以及索引缓冲区,在 Unity 中创建为ComputeBufferType.Append
,并在着色器中声明为ConsumeStrucutredBuffer<uint>
或AppendStructuredBuffer<uint>
。
索引缓冲区是对主缓冲区的索引引用列表,并指定哪些元素处于非活动状态。
您还需要在数据结构中添加一个名为"isAlive"或其他内容的 int。
然后,您将创建三个着色器:
- 您的模拟着色器,您可以在其中对主要数据执行所有工作,这与正常情况没有变化,只是您在完成大部分工作之前有类似
if(isAlive < 1) return
的东西。
索引 - 设置着色器,您可以在其中使用索引填充索引缓冲区(因此
indexBuffer[932] = 932
等(索引列表初始化为AppendStructuredBuffer<uint>
) - 您的发出着色器,您可以通过从可用索引列表中使用它们并设置
isAlive = true
来"创建"主要元素。(索引列表初始化为ConsumeStrucutredBuffer<uint>
。
您还可以在模拟着色器中将索引缓冲区声明为追加缓冲区,如果满足某些条件,则通过设置 isAlive = false 并将其索引附加到索引缓冲区来"终止"模拟索引。