专栏首页24K纯开源OpenGL与CUDA互操作方式总结

OpenGL与CUDA互操作方式总结

一、介绍

CUDA是Nvidia推出的一个通用GPU计算平台,对于提升并行任务的效率非常有帮助。本人主管的项目中采用了OpenGL做图像渲染,但是在数据处理方面比较慢,导致帧率一直上不来。于是就尝试把计算工作分解成小的任务,使用核函数在CUDA中加速计算。对于CUDA和OpenGL如何交互以前从来没有接触过,这次在实施时趟了不少的坑。在这里记录下OpenGL与CUDA的互操作的两种方式。

二、基本操作流程

OpenGL与CUDA互操作可以分成两种,一种是OpenGL将Buffer对象注册到CUDA中去,供CUDA读写操作,然后再在OpenGL中使用。一般这种情况下注册的是VBO和PBO,VBO一般用于存储顶点坐标、索引等数据;PBO则一般用于存储图像数据,因此称作Pixel Buffer Object。另一种是OpenGL将Texture对象注册到CUDA中去,经CUDA处理后得到纹理内容,然后在OpenGL中渲染出来。不过不管是哪一种互操作类型,其操作流程是一致的:

  • 在OpenGL里面初始化Buffer Object
  • 在CUDA中注册OpenGL中的Buffer Object
  • CUDA锁定资源,获取操作资源的指针,在CUDA核函数中进行处理
  • CUDA释放资源,在OpenGL中使用Buffer Object

下面就以代码为例,讲讲两种方式的异同:

(1)OpenGL PBO/VBO在CUDA中的使用

// 初始化Buffer Object
//vertex array object
glGenVertexArrays(1, &this->VAO);
//Create vertex buffer object
glGenBuffers(2, this->VBO);
//Create Element Buffer Objects
glGenBuffers(1, &this->EBO);

//Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).
glBindVertexArray(this->VAO);

// 绑定VBO后即在CUDA中注册Buffer Object
glBindBuffer(GL_ARRAY_BUFFER, this->VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(*this->malla)*this->numPoints, this->malla, GL_DYNAMIC_COPY);
cudaGraphicsGLRegisterBuffer(&this->cudaResourceBuf[0], this->VBO[0], cudaGraphicsRegisterFlagsNone);

glBindBuffer(GL_ARRAY_BUFFER, this->VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(*this->malla)*this->numPoints, this->malla, GL_DYNAMIC_COPY);
cudaGraphicsGLRegisterBuffer(&this->cudaResourceBuf[1], this->VBO[1], cudaGraphicsRegisterFlagsNone);

// 在CUDA中映射资源,锁定资源
cudaGraphicsMapResources(1, &this->cudaResourceBuf[0], 0);
cudaGraphicsMapResources(1, &this->cudaResourceBuf[1], 0);

point *devicePoints1;
point *devicePoints2;
size_t size = sizeof(*this->malla)*this->numPoints;
// 获取操作资源的指针,以便在CUDA核函数中使用
cudaGraphicsResourceGetMappedPointer((void **)&devicePoints1, &size, this->cudaResourceBuf[0]);
cudaGraphicsResourceGetMappedPointer((void **)&devicePoints2, &size, this->cudaResourceBuf[1]);
// execute kernel
dim3 dimGrid(20, 20, 1);
dim3 dimBlock(this->X/dimGrid.x, this->Y/dimGrid.y, 1);
modifyVertices<<<dimGrid, dimBlock>>>(devicePoints1, devicePoints2,this->X, this->Y);
modifyVertices<<<dimGrid, dimBlock>>>(devicePoints2, devicePoints1,this->X, this->Y);

// 处理完了即可解除资源锁定,OpenGL可以开始利用处理结果了。
// 注意在CUDA处理过程中,OpenGL如果访问这些锁定的资源会出错。
cudaGraphicsUnmapResources(1, &this->cudaResourceBuf[0], 0);
cudaGraphicsUnmapResources(1, &this->cudaResourceBuf[1], 0);

  值得注意的是,由于这里绑定的是VBO,属于Buffer对象,因此调用的CUDA API是这两个:

cudaGraphicsGLRegisterBuffer();
cudaGraphicsResourceGetMappedPointer();

(2)OpenGL Texture在CUDA中的使用

// 初始化两个Texture并绑定
cudaGraphicsResource_t cudaResources[2];
GLuint textureID[2];
glEnable(GL_TEXTURE_2D);
glGenTextures(2, textureID);
glBindTexture(GL_TEXTURE_2D, textureID[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1000, 1000, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

glBindTexture(GL_TEXTURE_2D, textureID[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1000, 1000, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
// 在CUDA中注册这两个Texture
cudaError_t err = cudaGraphicsGLRegisterImage(&cudaResources[0], textureID[0], GL_TEXTURE_2D, cudaGraphicsRegisterFlagsWriteDiscard);
if (err != cudaSuccess)
{
    std::cout << "cudaGraphicsGLRegisterImage: " << err << "Line: " << __LINE__;
    return -1;
}
err = cudaGraphicsGLRegisterImage(&cudaResources[1], textureID[1], GL_TEXTURE_2D, cudaGraphicsRegisterFlagsWriteDiscard);
if (err != cudaSuccess)
{
    std::cout << "cudaGraphicsGLRegisterImage: " << err << "Line: " << __LINE__;
    return -1;
}
// 在CUDA中锁定资源,获得操作Texture的指针,这里是CudaArray*类型
cudaError_t err = cudaGraphicsMapResources(2, cudaResource, 0);	
err = cudaGraphicsSubResourceGetMappedArray(&this->cuArrayL, cudaResource[0], 0, 0);
err = cudaGraphicsSubResourceGetMappedArray(&this->cuArrayR, cudaResource[1], 0, 0);

// 数据拷贝至CudaArray。这里因为得到的是CudaArray,处理时不方便操作,于是先在设备内存中
// 分配缓冲区处理,处理完后再把结果存到CudaArray中,仅仅是GPU内存中的操作。
cudaMemcpyToArray(cuArrayL, 0, 0, pHostDataL, imgWidth*imgHeight * sizeof(uchar4), cudaMemcpyDeviceToDevice);
cudaMemcpyToArray(cuArrayR, 0, 0, pHostDataR, imgWidth*imgHeight * sizeof(uchar4), cudaMemcpyDeviceToDevice);
// 处理完后即解除资源锁定,OpenGL可以利用得到的Texture对象进行纹理贴图操作了。
cudaGraphicsUnmapResources(1, &cudaResource[0], 0);
cudaGraphicsUnmapResources(1, &cudaResource[1], 0);

      注意这里因为使用的是Texture对象,因此使用了不同的API:

cudaGraphicsGLRegisterImage();
cudaGraphicsSubResourceGetMappedArray();

  VBO/PBO是属于OpenGL Buffer对象,而OpenGL Texture则是另一种对象。因此,两种类型的处理需要区别对待。在这个地方耽搁了很久,就是因为没有看文档说明。下面一段话正是对这种情况的说明:

From the CUDA Reference Guide entry for `cudaGraphicsResourceGetMappedPointer()`: > If resource is not a buffer then it cannot be accessed via a pointer and cudaErrorUnknown is returned. From the CUDA Reference Guide entry for `cudaGraphicsSubResourceGetMappedArray()`: > If resource is not a texture then it cannot be accessed via an array and cudaErrorUnknown is returned. In other words, use **GetMappedPointer** for mapped buffer objects. Use **GetMappedArray** for mapped texture objects.

三、参考链接

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用VS2010开发Qt程序的一点经验

    导读      相比于Qt Creator,我更喜欢用VS2010来进行开发。虽然启动时间相对较慢,但是VS下强大的快捷键和丰富的插件,以及使用多年的经验,都让...

    24K纯开源
  • CMake结合Visual Studio中开发Qt应用程序注意事项

    24K纯开源
  • 用Qt写软件系列三:一个简单的系统工具之界面美化

    前言      在上一篇中,我们基本上完成了主要功能的实现,剩下的一些导出、进程子模块信息等功能,留到后面再来慢慢实现。这一篇来讲述如何对主界面进行个性化的定制...

    24K纯开源
  • Spring Cloud Zuul重试机制探秘

    作者:李刚 原文:http://www.spring4all.com/article/208 简介 本文章对应spring cloud的版本为(Dalston....

    程序猿DD
  • 在 Cocos Creator 里画个炫酷的雷达图

    是以从同一点开始的轴上表示的三个或更多个定量变量的二维图表的形式显示多元数据的图形方法。

    陈皮皮
  • 关于Form.Close跟Form.Dispose

    我们在Winform开发的时候,使用From.Show来显示窗口,使用Form.Close来关闭窗口。熟悉Winform开发的想必对这些非常熟悉。但是Form类...

    kklldog
  • 无埋点实现监测的真相——革新还是噱头?

    小编提示:   本文是宋星老师独家为iCDO供稿。对于想要了解无埋点这一监测方法的朋友,是非常深入浅出,详尽清楚的一篇高质量文章。   这篇文章介绍了: 1. ...

    iCDO互联网数据官
  • JavaScript 设计模式学习第五篇-继承与原型链

    JavaScript 是一种灵活的语言,兼容并包含面向对象风格、函数式风格等编程风格。我们知道面向对象风格有三大特性和六大原则,三大特性是封装、继承、多态,六大...

    越陌度阡
  • 浅谈对机器学习的理解

    在网上看到关于一篇ML的文章,很不错,转载过来共勉.(http://www.36dsj.com/archives/21024).

    红色石头
  • 机器学习算法经验总结

    算算时间,从开始到现在,做机器学习算法也将近八个月了。虽然还没有达到融会贯通的地步,但至少在熟悉了算法的流程后,我在算法的选择和创造能力上有了不小的提升。实话...

    机器学习AI算法工程

扫码关注云+社区

领取腾讯云代金券