OpenCL粒子系统内存布局

时间:2013-01-21 16:19:36

标签: opencl

我需要一些关于OpenCL代码的建议。我在OpenCL中编写一个粒子系统,直接从OpenCL绘制到gpu上,因此不需要复制到CPU。这一切都很好,但我有创建新粒子的问题。

我在GPU上分配了一个包含所有粒子数据的大内存区域。粒子的一个参数称为isAlive,并决定其活动的天气。当我想创建一个新的粒子然后找到一个不活着的粒子,在将它设置为isAlive true之前将其位置修改为其起始位置。这个过程非常昂贵,因为我必须遍历所有粒子才能找到那些不活跃的粒子,同时我必须确保几个线程不会同时创建相同的粒子(所以我不会最后有更多的粒子然后我问)。 是否有任何好的考虑因素,算法或策略可以更优雅,更快速地解决这个问题?

1 个答案:

答案 0 :(得分:2)

这是我尝试的一种方法:将isAlive的标志与数据结构的其余部分分开。这看起来像是经常阅读但几乎不写的数据。使用单个uint来跟踪32个粒子的状态。使用零表示活动,使用1表示死亡 - 基本上创建一个isDead列表。我假设你会有更多活着的粒子而不是死粒子。

当您需要时,可以将值(一次32个)读取到本地内存中。这允许您创建一个快速迭代数据的内核,寻找非零值。这里的大性能提升伴随着密集数据,从而减少了存储和加载标志的内存开销。这使得检查其中一个值的操作便宜得多,允许您更快地迭代它们。更改32位值时需要小心,以免损坏共享相同uint的其他数据(隔行扫描有助于此)。当您需要缩小1位的确切位置时,指令clz和popcount将非常有用。 opencl 1.2 refcard

可能的优化#1: 如果需要,您可以尝试隔行扫描值,以便第一个uint跟踪索引0,32,64,96,...,992,第二个uint代表1,33,65,97,...,993和等等。这可能允许通常在特定粒子上工作的工作项读取32个连续的isDead状态。这可能会比它的价值更多,但这取决于你的应用程序。

可能的优化#2: 如果死粒子真的很稀疏,那么跟踪更高级别的isDead列表可能是值得的。使用相同的技术,很容易将isDead bit / uint列表再次减少32倍。第2级的每个位代表相应的uint的状态。即:如果设置了uint N中的任何位,则也将设置该列表的位N.仅在数据中需要大量零时才有用,但这一额外步骤可以节省大量周期,搜索数据中罕见的“开”位。包括原始isDead数据在内的总内存开销将达到:memBits = ceil(particleCount / 32)+ ceil(particleCount / 32 ^ 2),或者每2 ^ 20个粒子大约128kb + 4kb。

使用上面的代码,可以编写一个内核,它将返回给定范围内的死粒子数,并快速找到下一个可用的死粒子之一。