GLSL Vulkan 计算着色器可有效地从共享数组中删除零以生成压缩数组
GLSL Vulkan compute shader to efficiently prune zeros from a shared array to make a compressed array
我有一个 vulkan 计算着色器,在本地组内共享一个数组,我想执行以下转换:
基本上,我想 remove/prune 所有零。有没有快速或并行的方法来做到这一点?
我尝试按如下方式按顺序执行此操作
shared int arraySize;
shared int array[256];
shared int compressed_array[256];
/*... prepare array in parallel ... */
// run in series on 1st worker
if(gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0){
arraySize= 0; // initilize arraySize
for (int i = 0; i < 256; i++) {
if(array[i] > 0) // incrementally search for non-zeroes
{
compressed_array[arraySize] = array[i];
arraySize= arraySize + 1;
}
}
}
但是在我的 GPU 上使用数组的 256 个元素似乎需要 1-2[ms],有没有更快的方法来做到这一点?并行算法可能会更快,是否存在这样的算法?
是的。这个问题叫做 parallel stream compaction.
感谢 Yuri Kilochek 的回答,我能够通过并行找到解决方案 prefix-sums/scan
假设一个 'flag' 数组被添加到数据中,如果相应的数组单元格非零则为 1,否则为 0。然后标志数组上的“并行独占扫描”将产生 compressed_array 的索引,具有活动标志的调用应将其各自的 'array' 内容写入(分散操作)。
在 Vulkan 中,这可以使用 subgroups.
高效实现
但是,每个子组通常只能执行长达 32 (Nvidia) 或 64 (AMD) 个元素的扫描,而本地组可能大几倍。要对整个本地组执行扫描,需要采用 described here and coded here 的分层扫描方法。
我有一个 vulkan 计算着色器,在本地组内共享一个数组,我想执行以下转换:
shared int arraySize;
shared int array[256];
shared int compressed_array[256];
/*... prepare array in parallel ... */
// run in series on 1st worker
if(gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0){
arraySize= 0; // initilize arraySize
for (int i = 0; i < 256; i++) {
if(array[i] > 0) // incrementally search for non-zeroes
{
compressed_array[arraySize] = array[i];
arraySize= arraySize + 1;
}
}
}
但是在我的 GPU 上使用数组的 256 个元素似乎需要 1-2[ms],有没有更快的方法来做到这一点?并行算法可能会更快,是否存在这样的算法?
是的。这个问题叫做 parallel stream compaction.
感谢 Yuri Kilochek 的回答,我能够通过并行找到解决方案 prefix-sums/scan
假设一个 'flag' 数组被添加到数据中,如果相应的数组单元格非零则为 1,否则为 0。然后标志数组上的“并行独占扫描”将产生 compressed_array 的索引,具有活动标志的调用应将其各自的 'array' 内容写入(分散操作)。
在 Vulkan 中,这可以使用 subgroups.
高效实现但是,每个子组通常只能执行长达 32 (Nvidia) 或 64 (AMD) 个元素的扫描,而本地组可能大几倍。要对整个本地组执行扫描,需要采用 described here and coded here 的分层扫描方法。