我正在进行3D模拟(目前为2D),正在使用CUDA进行计算,并使用OpenGL进行渲染。我的问题与CUDA和OpenGL之间的互操作性有关。据我所知,有两种通用的方法可以做到这一点:
第一个是使用像素缓冲区对象(或顶点缓冲区对象),该对象将映射到CUDA全局内存,然后复制到OpenGL纹理。据说这是一种非常快速的方法。
第二个是将纹理对象直接复制到CUDA纹理存储器。从那时起我也可以使用所有的纹理记忆功能,例如纹理缓存等,这也将非常不错。
现在,有人可以向我解释这两种方法之间的一般区别是什么吗?每种情况下通常都在哪种情况下使用?
整个差异就像您说的那样,在纹理缓存中。因此,在这两种方法之间进行选择取决于您是否要在可视化中利用纹理缓存。让我们看一些常见的情况:
a)如果您要计算表面的变形方式(例如水的表面或某些弹性变形),并且需要了解该表面的多边形网格的新顶点,则通常应使用“缓冲区”(第一个),除非您不需要在此处复制到OpenGL纹理。实际上,这里没有涉及复制,您只需在CUDA中引用该缓冲区并将其用作gl缓冲区即可。
b)如果您有粒子模拟并且需要知道更新的粒子位置,则也可以像上述情况一样使用缓冲区。
c)如果您进行了有限元网格模拟,其中空间中的每个固定体积单元将获得一个新值,并且您需要通过体积渲染或等值面对其进行可视化,则在此处您将要使用纹理对象(2D或3D,具体取决于因为您要投射光线甚至生成流线时,几乎总是需要立即缓存相邻的纹理像素。而且您可以避免在此处进行任何复制,因为在上述方法中,您还可以直接从OpenGL中引用一些CUDA纹理内存(cudaArray)。您将使用以下调用来执行此操作:
cudaGraphicsGLRegisterImage( &myCudaGraphicsResource, textureNameFromGL, GL_TEXTURE_3D,...)
...
cudaGraphicsMapResources(1, myCudaGraphicsResource)
cudaGraphicsSubResourceGetMappedArray(&mycudaArray, myCudaGraphicsResource, 0, 0)
cudaGraphicsUnMapResources(1, myCudaGraphicsResource)
Run Code Online (Sandbox Code Playgroud)
因此,mycudaArray可以引用CUDA中的纹理数据,而TextureName可以引用OpenGL中的相同内存。
从缓冲区复制到纹理不是一个好主意,因为如果需要此数据进行纹理缓存,您将进行额外的复制。在支持纹理互操作之前,这在CUDA的早期版本中更为流行
您也可以在a)和b)用例中使用纹理。使用某些硬件,它甚至可能运行得更快,但这取决于硬件。还请记住,纹理读取还应用了缩小和放大滤镜,如果您要查找的只是存储在缓冲区中的精确值,这是额外的工作。
要与CUDA和OpenGL共享纹理资源,请参考此示例
https://github.com/nvpro-samples/gl_cuda_interop_pingpong_st