一、介绍

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中的使用

  1. // 初始化Buffer Object
  2. //vertex array object
  3. glGenVertexArrays(1, &this->VAO);
  4. //Create vertex buffer object
  5. glGenBuffers(2, this->VBO);
  6. //Create Element Buffer Objects
  7. glGenBuffers(1, &this->EBO);
  8.  
  9. //Bind the Vertex Array Object first, then bind and set vertex buffer(s) and attribute pointer(s).
  10. glBindVertexArray(this->VAO);
  11.  
  12. // 绑定VBO后即在CUDA中注册Buffer Object
  13. glBindBuffer(GL_ARRAY_BUFFER, this->VBO[0]);
  14. glBufferData(GL_ARRAY_BUFFER, sizeof(*this->malla)*this->numPoints, this->malla, GL_DYNAMIC_COPY);
  15. cudaGraphicsGLRegisterBuffer(&this->cudaResourceBuf[0], this->VBO[0], cudaGraphicsRegisterFlagsNone);
  16.  
  17. glBindBuffer(GL_ARRAY_BUFFER, this->VBO[1]);
  18. glBufferData(GL_ARRAY_BUFFER, sizeof(*this->malla)*this->numPoints, this->malla, GL_DYNAMIC_COPY);
  19. cudaGraphicsGLRegisterBuffer(&this->cudaResourceBuf[1], this->VBO[1], cudaGraphicsRegisterFlagsNone);
  20.  
  21. // 在CUDA中映射资源,锁定资源
  22. cudaGraphicsMapResources(1, &this->cudaResourceBuf[0], 0);
  23. cudaGraphicsMapResources(1, &this->cudaResourceBuf[1], 0);
  24.  
  25. point *devicePoints1;
  26. point *devicePoints2;
  27. size_t size = sizeof(*this->malla)*this->numPoints;
  28. // 获取操作资源的指针,以便在CUDA核函数中使用
  29. cudaGraphicsResourceGetMappedPointer((void **)&devicePoints1, &size, this->cudaResourceBuf[0]);
  30. cudaGraphicsResourceGetMappedPointer((void **)&devicePoints2, &size, this->cudaResourceBuf[1]);
  31. // execute kernel
  32. dim3 dimGrid(20, 20, 1);
  33. dim3 dimBlock(this->X/dimGrid.x, this->Y/dimGrid.y, 1);
  34. modifyVertices<<<dimGrid, dimBlock>>>(devicePoints1, devicePoints2,this->X, this->Y);
  35. modifyVertices<<<dimGrid, dimBlock>>>(devicePoints2, devicePoints1,this->X, this->Y);
  36.  
  37. // 处理完了即可解除资源锁定,OpenGL可以开始利用处理结果了。
  38. // 注意在CUDA处理过程中,OpenGL如果访问这些锁定的资源会出错。
  39. cudaGraphicsUnmapResources(1, &this->cudaResourceBuf[0], 0);
  40. cudaGraphicsUnmapResources(1, &this->cudaResourceBuf[1], 0);

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

  1. cudaGraphicsGLRegisterBuffer();
  2. cudaGraphicsResourceGetMappedPointer();

(2)OpenGL Texture在CUDA中的使用

  1. // 初始化两个Texture并绑定
  2. cudaGraphicsResource_t cudaResources[2];
  3. GLuint textureID[2];
  4. glEnable(GL_TEXTURE_2D);
  5. glGenTextures(2, textureID);
  6. glBindTexture(GL_TEXTURE_2D, textureID[0]);
  7. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  8. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  9. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1000, 1000, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  10.  
  11. glBindTexture(GL_TEXTURE_2D, textureID[1]);
  12. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  13. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  14. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1000, 1000, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  15. // 在CUDA中注册这两个Texture
  16. cudaError_t err = cudaGraphicsGLRegisterImage(&cudaResources[0], textureID[0], GL_TEXTURE_2D, cudaGraphicsRegisterFlagsWriteDiscard);
  17. if (err != cudaSuccess)
  18. {
  19. std::cout << "cudaGraphicsGLRegisterImage: " << err << "Line: " << __LINE__;
  20. return -1;
  21. }
  22. err = cudaGraphicsGLRegisterImage(&cudaResources[1], textureID[1], GL_TEXTURE_2D, cudaGraphicsRegisterFlagsWriteDiscard);
  23. if (err != cudaSuccess)
  24. {
  25. std::cout << "cudaGraphicsGLRegisterImage: " << err << "Line: " << __LINE__;
  26. return -1;
  27. }
  28. // 在CUDA中锁定资源,获得操作Texture的指针,这里是CudaArray*类型
  29. cudaError_t err = cudaGraphicsMapResources(2, cudaResource, 0);
  30. err = cudaGraphicsSubResourceGetMappedArray(&this->cuArrayL, cudaResource[0], 0, 0);
  31. err = cudaGraphicsSubResourceGetMappedArray(&this->cuArrayR, cudaResource[1], 0, 0);
  32.  
  33. // 数据拷贝至CudaArray。这里因为得到的是CudaArray,处理时不方便操作,于是先在设备内存中
  34. // 分配缓冲区处理,处理完后再把结果存到CudaArray中,仅仅是GPU内存中的操作。
  35. cudaMemcpyToArray(cuArrayL, 0, 0, pHostDataL, imgWidth*imgHeight * sizeof(uchar4), cudaMemcpyDeviceToDevice);
  36. cudaMemcpyToArray(cuArrayR, 0, 0, pHostDataR, imgWidth*imgHeight * sizeof(uchar4), cudaMemcpyDeviceToDevice);
  37. // 处理完后即解除资源锁定,OpenGL可以利用得到的Texture对象进行纹理贴图操作了。
  38. cudaGraphicsUnmapResources(1, &cudaResource[0], 0);
  39. cudaGraphicsUnmapResources(1, &cudaResource[1], 0);

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

  1. cudaGraphicsGLRegisterImage();
  2. 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.

三、参考链接

OpenGL与CUDA互操作方式总结的更多相关文章

  1. [转]OpenGL与CUDA互操作方式总结

    一.介绍 CUDA是Nvidia推出的一个通用GPU计算平台,对于提升并行任务的效率非常有帮助.本人主管的项目中采用了OpenGL做图像渲染,但是在数据处理方面比较慢,导致帧率一直上不来.于是就尝试把 ...

  2. OpenGL中的渲染方式—— GL_TRIANGLE_STRIP

    OpenGL值绘制三角形的方式常用的有三种,分别是GL_TRIANGLES.GL_TRIANGLE_STRIP.GL_TRIANGLE_FAN,其效果如依次是: 从左起:第一个方式是GL_TRIANG ...

  3. CUDA和OpenGL互操作经典博文赏析和学习

    1.使用cuda+opengl图形互操作性实现MPR.原学位论文学习:实时交互的医学图像可视化.在该论文的第5.1.1节. 2.cuda与opengl互操作之PBO 3.cuda与opengl互操作之 ...

  4. [转]CUDA和OpenGL互操作的实现及分析

    CUDA和OpenGL互操作的实现及分析刘进锋.郭雷(西北工业大学 自动化学院,陕西西安710129) 1 CUDA与OpenGL概述 OpenGL是图形硬件的软件接口,它是在SGI等多家世界著名的计 ...

  5. CUDA编程

    目录: 1.什么是CUDA 2.为什么要用到CUDA 3.CUDA环境搭建 4.第一个CUDA程序 5. CUDA编程 5.1. 基本概念 5.2. 线程层次结构 5.3. 存储器层次结构 5.4. ...

  6. CUDA与OpenGL互操作

    当处理较大数据量的时候,往往会用GPU进行运算,比如OpenGL或者CUDA.在实际的操作中,往往CUDA实现并行计算会比OpenGL更加方便,而OpenGL在进行后期渲染更具有优势.由于CUDA中的 ...

  7. CUDA与OpenGL互操作实例

    本文要解决的问题是如何实现CUDA和OpenGL的互操作,使得GPU能够将通用计算的运算结果交给OpenGL进行绘制. 本文的应用程序主要包括两个方面: 1.      使用CUDA核函数生成图像数据 ...

  8. OpenGL进行简单的通用计算实例

    博主作为OpenGL新手,最近要用OpenGL进行并行的数据计算,突然发现这样的资料还是很少的,大部分资料和参考书都是讲用OpenGL进行渲染的.好不容易找到一本书<GPGPU编程技术,从Ope ...

  9. ubuntu安装nvidia驱动以及cuda教程

    最近尝试在ubuntu中安装nvidia的显卡驱动以及cuda.花了近三天时间,真的如网上所说错误百出,期间甚至重装了一次ubuntu系统,搞到怀疑人生,整个都是泪- -.最终经过百般“磨难”总算安装 ...

随机推荐

  1. Python库:序列化和反序列化模块pickle介绍

    1 前言 在“通过简单示例来理解什么是机器学习”这篇文章里提到了pickle库的使用,本文来做进一步的阐述. 通过简单示例来理解什么是机器学习 pickle是python语言的一个标准模块,安装pyt ...

  2. 详解react/redux的服务端渲染:页面性能与SEO

        亟待解决的疑问 为什么服务端渲染首屏渲染快?(对比客户端首屏渲染)   react客户端渲染的一大痛点就是首屏渲染速度慢问题,因为react是一个单页面应用,大多数的资源需要在首次渲染前就加载 ...

  3. 使用freemarker模板生成word文档

    项目中最近用到这个东西,做下记录. 如下图,先准备好一个(office2003)word文档当做模板.文档中图片.姓名.性别和生日已经使用占位符代替,生成过程中将会根据实际情况进行替换. 然后将wor ...

  4. 第二章:2.9 总结一下 Django

    1. URLconf(URL configuration ) : 这个模块包含URL模式(正则表达式)到视图函数(view.py)的简单映射. 2. python 正则表达式: 解释: 通配符:r : ...

  5. python编程快速上手之第9章实践项目参考答案

    本章介介绍了shutil,zipfile模块的使用,我们先来认识一下这2个模块吧. 一.shutil模块 shutil模块主要用于对文件或文件夹进行处理,包括:复制,移动,改名和删除文件,在shuti ...

  6. 利用powershell反弹shell到metasploit

    一.使用msfvenom生成PS1文件: msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST= -f psh-reflection >.p ...

  7. OpenStack(企业私有云)万里长征第四步——DevStack整体安装规划及使用

    一.前言 前期成功通过DevStack安装OpenStack,现将从机房规划到虚拟机搭建的整个过程总结如下,以供日后查阅或有需之人参考. 二.机房规划 这个整个安装过程的重点,能不能成功就看规划的如何 ...

  8. 在react.js上使用antd-design没有样式

    两种解决方法: 第一种: 在.babelrc中加入 { "presets": ["es2015", "react"], "plug ...

  9. Java基础语法<九> 接口与内部类

    1 接口  interface implement 接口的所有方法自动地属于public.因此,在接口中声明方法时,不必提供关键字public.   接口可以包含多个方法,接口中可以定义常量.接口中的 ...

  10. HashMap TreeMap ConcurrentHashMap 源码

    1 HashMap java se 1.6 1.1 父类 java.lang.Object 继承者 java.util.AbstractMap<K,V> 继承者 java.util.Has ...