CUDA和和OpenGL互操作的实现及分析互操作的实现及分析
CUDA和OpenGL互操作的基本方式是使用CUDA生成数据,再利用OpenGL在屏幕上绘制出数据所表示的图
形。两者的结合可以通过使用OpenGL的PBO(像素缓冲区对象)或VBO(顶点缓冲区对象)两种方式来实现。描述
了CUDA和OpenGL互操作的步骤并展示了一个使用PBO的实例。该实例运行结果表明,互操作的方式比单纯使
用OpenGL方式快了7~8倍。
摘摘 要:要:
关键词:关键词: CUDA;OpenGL;像素缓冲区对象;顶点缓冲区对象
1 CUDA与与OpenGL概述概述
OpenGL是图形硬件的
OpenGL不是一种编程语言,而是一种API(应用程序编程接口)。程序员可以使用某种编程语言(如C或C++)编写绘图软
件,其中调用了一个或多个OpenGL库函数。作为一种API,OpenGL遵循C语言的调用约定。OpenGL开发资料可参考文献[1]
和参考文献[2]。
图形处理器(GPU)原本是处理计算机图形的专用设备,近十年来,由于高清晰度复杂图形实时处理的需求,GPU发展成为高
并行度、多线程、多核的处理器。目前,主流GPU的运算能力已超过主流通用CPU,从发展趋势上来看将来差距会越拉越
大。为了合理地利用GPU 资源,CUDA(统一计算设备架构)应运而生。CUDA是一种由NVIDIA推出的通用并行计算架构[3],
该架构使GPU能够解决复杂的计算问题,并且由于CUDA编程语言基于标准的C语言,从而大大提高了可编程性。
CUDA和OpenGL互操作的基本方式是使用CUDA生成数据,然后使用OpenGL在屏幕上绘制出数据所表示的图形。两者的结
合可以通过两种方式来实现:
(1)使用OpenGL的PBO(像素缓冲区对象)。在该方式下,CUDA直接生成像素数据,OpenGL显示这些像素;
(2)使用OpenGL的VBO(顶点缓冲区对象)。在该方式下,CUDA生成顶点网格数据,OpenGL可以根据需要绘制出平滑的表
面图或线框图或一系列顶点。
这两种方式的核心都是利用cudaGLMapBufferObject函数将OpenGL的缓冲区映射到CUDA的内存空间上,这样,程序员就可
以充分利用CUDA的优点写出性能高的程序在该内存空间上生成数据,这些数据不需要传送,OpenGL可以直接使用。如果不
使用CUDA,这些数据需要由CPU来计算产生。一方面,CPU的计算速度通常比GPU慢;另一方面,这些数据需要传送到
GPU上以供OpenGL显示使用。鉴于此,当数据量很大时,CUDA和OpenGL的混合使用效果明显。
2 CUDA和和OpenGL互操作的过程互操作的过程[4]
CUDA和OpenGL互操作具体步骤如下:
(1)创建窗口及OpenGL运行环境。
(2)设置OpenGL视口和坐标系。要根据绘制的图形是2D还是3D等具体情况设置。(1)和(2)是所有OpenGL程序必需的,这里
也没什么特殊之处,需要注意的是,后面的一些功能需要OpenGL 2.0及以上版本支持,所以在这里需要进行版本检查。
(3)创建CUDA环境。可以使用cuGLCtxCreate或cudaGLSetGLDevice来设置CUDA环境。该设置一定要放在其他CUDA的
API调用之前。
(4)产生一个或多个OpenGL缓冲区用以和CUDA共享。使用PBO和使用VBO差不多,只是有些函数调用参数不同。以下是
具体过程。
GLuint bufferID;
glGenBuffers(1,&bufferID);//产生一个buffer ID
glBindBuffer(parameter1,bufferID);
//将其设置为当前非压缩缓冲区,如果是PBO方式,parameter1设置为GL_PIXEL_UNPACK_BUFFER,如果
是VBO方式,parameter1设置为GL_ARRAY_BUFFER
glBufferData(parameter1,parameter2,NULL,GL_DYNAMIC _COPY);
//给该缓冲区分配数据,PBO方式下,parameter1设置为GL_PIXEL_UNPACK_BUFFER,parameter1设置为图像的长度*
宽度*4。VBO方式下,parameter1设置为GL_ARRAY_BUFFER,parameter2设置为顶点数*16,因为每个顶点包含3个浮点
坐标(x,y,z)和4个颜色字节(RGBA),这样一个顶点包含16 B
(5)用CUDA登记缓冲区。登记可以使用cuGLRegisterBufferObject或cudaGLRegisterBufferObject,该命令告诉OpenGL和
CUDA 驱动程序该缓冲区为二者共同使用。
(6)将OpenGL缓冲区映射到CUDA内存。可以使用cuGLMapBufferObject或cudaGLMapBufferObject,它实际是将CUDA内
存的指针指向OpenGL的缓冲区,这样如果只有一个GPU,就不需要数据传递。当映射完成后,OpenGL不能再使用该缓冲
区。
(7)使用CUDA往该映射的内存写图像数据。前面的准备工作在这里真正发挥作用了,此时可以调用CUDA的kernel,像使用
全局内存一样使用映射了的缓冲区,向其中写数据。
(8)取消OpenGL缓冲区映射。要等前面CUDA的活动完成以后,使用cuGLUnmapBufferObject或
cudaGLUnmapBufferObject函数取消映射。
(9)前面的步骤完成以后就可以真正开始绘图了, OpenGL的PBO和VBO的绘图方式不同,分别为以下两个过程。
①如果只是绘制平面图形,需要使用OpenGL的PBO及纹理。
glEnable(GL_TEXTURE_2D); //使纹理可用
glGenTextures(1,&textureID); //生成一个textureID
glBindTexture(GL_TEXTURE_2D,textureID);
//使该纹理成为当前可用纹理
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,Width,
Height,0,GL_BGRA,GL_UNSIGNED_BYTE,NULL);
//分配纹理内存。最后的参数设置数据来源,这里设置为NULL,表示数据来自PBO,不是来自主机内存
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN _FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_ FILTER,GL_LINEAR);//必须设置滤波模式,GL_LINEAR
允许图形伸缩时线性差值。如果不需要线性差值,可以用GL_TEXTURE_RECTANGLE_ARB代替GL_TEXTURE_2D以提高
评论1
最新资源