我想使用OpenCL加速渲染光线跟踪图像,但是我注意到Wikipedia页面声称Open CL中禁止递归。这是真的?由于我在光线跟踪时大量使用递归,因此需要大量的重新设计才能从速度上受益。阻止递归的基本限制是什么?有什么办法解决吗?
我想使用OpenCL加速渲染光线跟踪图像,但是我注意到Wikipedia页面声称Open CL中禁止递归。这是真的?由于我在光线跟踪时大量使用递归,因此需要大量的重新设计才能从速度上受益。阻止递归的基本限制是什么?有什么办法解决吗?
Answers:
实质上是因为并非所有的GPU都可以支持函数调用,并且即使支持,函数调用也可能非常慢或存在栈深度非常小的限制。
着色器代码和GPU计算代码似乎在各处都有函数调用,但是在正常情况下,编译器会将它们全部内联100%。GPU执行的机器代码包含分支和循环,但没有函数调用。但是,由于明显的原因,无法内联递归函数调用。(除非某些参数是编译时常量,否则编译器可以折叠它们并内联整个调用树。)
为了实现真正的函数调用,您需要一个堆栈。在大多数情况下,着色器代码根本不使用堆栈-GPU具有大型寄存器文件,并且着色器可以将所有数据始终保留在寄存器中。使堆栈难以工作是因为(a)您需要大量的堆栈空间才能同时提供所有可能发生的所有扭曲,并且(b)GPU内存系统经过优化可大量批处理内存事务以实现高吞吐量,但这是以等待时间为代价的,因此,我的猜测是,诸如保存/恢复本地变量的堆栈操作会非常慢。
从历史上看,硬件级别的函数调用在GPU上并不是太有用,因为在编译器中内联所有内容更为有意义。因此GPU架构师并没有专注于使其快速发展。如果将来对有效的硬件级调用有需求,可能会做出一些不同的权衡,但是(与工程中的所有内容一样)它将在其他地方产生成本。
就光线追踪而言,人们通常处理这种事情的方式是通过创建正在追踪过程中的光线队列。无需递归,而是将射线添加到队列中,并在高层的某个位置具有循环,该循环不断进行处理,直到所有队列都为空。但是,如果您从经典的递归raytracer开始,则确实需要对渲染代码进行大量重组。有关更多信息,请阅读Wavefront Path Tracing,这是一篇不错的文章。