有没有办法将运行在GPU上的着色器的结果返回到CPU上运行的程序?
我想基于GPU上的计算成本高的算法从简单的体素数据生成多边形网格,但我需要在CPU上进行物理计算的结果。
答案 0 :(得分:24)
定义“结果”?
通常,如果您使用OpenGL进行GPGPU样式的计算,则需要根据渲染系统的需要构建着色器。渲染系统设计为单向:数据进入它们并生成图像。向后看,让渲染系统产生数据,通常不是渲染系统的结构。
这并不意味着你当然不能这样做。但是你需要围绕OpenGL的局限来构建一切。
OpenGL提供了许多钩子,您可以从某些着色器阶段写入数据。其中大多数都需要专门的硬件
任何能够使用片段着色器的硬件显然都允许您写入正在渲染的当前帧缓冲区。通过使用framebuffer objects和带有浮点或整数image formats的纹理,您可以将所需的任何数据写入各种图像。进入纹理后,您只需调用glGetTexImage
即可获取渲染的像素数据。或者,如果FBO仍然受约束,您可以glReadPixels
来获取它。无论哪种方式都有效。
此方法的主要限制是:
您可以附加到帧缓冲区的图像数量;这限制了您可以写入的数据量。在GL-x之前的硬件上,FBO通常仅限于4个图像加上深度/模板缓冲区。在3.x和更好的硬件中,您可以预期至少8张图像。
您呈现的事实。这意味着您需要设置顶点数据以将三角形准确定位在您希望修改数据的位置。这不是一项微不足道的事。获取有用的输入数据也很困难,因为您通常希望每个纹素都完全独立于另一个。围绕这些限制构建片段着色器很困难。在许多情况下并非不可能,但并非不重要。
此OpenGL 3.0功能允许在一个或多个缓冲区对象中捕获来自OpenGL Vertex Processing阶段(顶点着色器和可选几何着色器)的输出。
这对于捕获要播放或再次渲染的顶点数据更为自然。在您的情况下,您需要在呈现后重新阅读,或者通过glGetBufferSubData
调用,或使用glMapBufferRange
进行阅读。
这里的限制是你通常只能捕获4个输出值,其中每个值都是vec4。还有一些严格的布局限制。一些OpenGL 3.x和4.x硬件提供了将数据写入多个反馈流的能力,这些反馈流都可以写入不同的缓冲区。
这个GL 4.2特性代表了写作的巅峰:你可以绑定一个图像(缓冲区纹理,如果你想写入一个缓冲区),然后写入它。您需要在memory ordering constraints内工作。
它非常灵活,但非常复杂。除了正确使用它的困难之外,还有许多限制。您可以写入的图像数量相当有限,可能大约8个左右。并且实现可能具有总写入限制,因此要写入的8个图像可能必须由片段着色器的输出共享。
更重要的是,图像输出仅保证片段着色器(和4.3的计算着色器)。也就是说,允许硬件禁止您在非FS / CS着色器阶段使用图像加载/存储。