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.
三、参考链接
- http://stackmirror.cn/page/4ejhmgxan1w
- https://stackoverflow.com/questions/21765604/draw-image-from-vertex-buffer-object-generated-with-cuda-using-opengl
- https://stackoverflow.com/questions/19244191/cuda-opengl-interop-draw-to-opengl-texture-with-cuda?rq=1
- https://www.3dgep.com/opengl-interoperability-with-cuda/
OpenGL与CUDA互操作方式总结的更多相关文章
- [转]OpenGL与CUDA互操作方式总结
一.介绍 CUDA是Nvidia推出的一个通用GPU计算平台,对于提升并行任务的效率非常有帮助.本人主管的项目中采用了OpenGL做图像渲染,但是在数据处理方面比较慢,导致帧率一直上不来.于是就尝试把 ...
- OpenGL中的渲染方式—— GL_TRIANGLE_STRIP
OpenGL值绘制三角形的方式常用的有三种,分别是GL_TRIANGLES.GL_TRIANGLE_STRIP.GL_TRIANGLE_FAN,其效果如依次是: 从左起:第一个方式是GL_TRIANG ...
- CUDA和OpenGL互操作经典博文赏析和学习
1.使用cuda+opengl图形互操作性实现MPR.原学位论文学习:实时交互的医学图像可视化.在该论文的第5.1.1节. 2.cuda与opengl互操作之PBO 3.cuda与opengl互操作之 ...
- [转]CUDA和OpenGL互操作的实现及分析
CUDA和OpenGL互操作的实现及分析刘进锋.郭雷(西北工业大学 自动化学院,陕西西安710129) 1 CUDA与OpenGL概述 OpenGL是图形硬件的软件接口,它是在SGI等多家世界著名的计 ...
- CUDA编程
目录: 1.什么是CUDA 2.为什么要用到CUDA 3.CUDA环境搭建 4.第一个CUDA程序 5. CUDA编程 5.1. 基本概念 5.2. 线程层次结构 5.3. 存储器层次结构 5.4. ...
- CUDA与OpenGL互操作
当处理较大数据量的时候,往往会用GPU进行运算,比如OpenGL或者CUDA.在实际的操作中,往往CUDA实现并行计算会比OpenGL更加方便,而OpenGL在进行后期渲染更具有优势.由于CUDA中的 ...
- CUDA与OpenGL互操作实例
本文要解决的问题是如何实现CUDA和OpenGL的互操作,使得GPU能够将通用计算的运算结果交给OpenGL进行绘制. 本文的应用程序主要包括两个方面: 1. 使用CUDA核函数生成图像数据 ...
- OpenGL进行简单的通用计算实例
博主作为OpenGL新手,最近要用OpenGL进行并行的数据计算,突然发现这样的资料还是很少的,大部分资料和参考书都是讲用OpenGL进行渲染的.好不容易找到一本书<GPGPU编程技术,从Ope ...
- ubuntu安装nvidia驱动以及cuda教程
最近尝试在ubuntu中安装nvidia的显卡驱动以及cuda.花了近三天时间,真的如网上所说错误百出,期间甚至重装了一次ubuntu系统,搞到怀疑人生,整个都是泪- -.最终经过百般“磨难”总算安装 ...
随机推荐
- Tornado+MySQL模拟SQL注入
实验环境: python 3.6 + Tornado 4.5 + MySQL 5.7 实验目的: 简单模拟SQL注入,实现非法用户的成功登录 一.搭建环境 1.服务端的tornado主程序app.py ...
- servlet+jsp update修改页面的实现,整整搞了两个小时才搞定
package DAO; public class books { private int bid; private String bname; private int booksl; private ...
- ES6的转换器
---恢复内容开始--- ES6代码转为ES5代码的转换器 1.Babel 2.Traceur,Google公司出品 Babel是一个广泛使用的ES6转码器,可以将ES6代码转为ES5代码,从而在现有 ...
- 实现一个简单的Log框架
实际上算不上框架,只是自己对日志框架的一点理解. 核心接口:Logger,供调用者完成不同等级的日志输出 package com.lichmama.log.service; public interf ...
- VB6之HTTP服务器的实现
之前用VBS写过一个,效率和支持比较low,这次闲着没事用VB重写了一次. 当前的实现版本仅支持静态文件的访问(*.html之类),支持访问方式为GET,HTTP状态支持200和404. 两个文件,一 ...
- QC使用:
qc使用入门 qc使用安装篇:附链接http://www.cnblogs.com/alterhu/archive/2011/11/05/2237483.html qc使用配置篇:附链接http://w ...
- Postmessage运用-往飞信添加信息
1.定位窗口 fHwnd:=FindWindow(nil,'短信中心'); then begin showmessage('请先登录飞信2013短信中心'); exit; end; { applica ...
- React Native之APK文件签名及打包
生成apk签名文件 我们使用android studio的方式进行签名 AS工具栏找到并点击 build->gennrate signed apk 两种情况: 1.这里如果已经有签名文件了则直接 ...
- VS2010中的sln,suo分别是什么文件
相当于VC6里的.dsw和.dsp .Net解决方案下 .sln文件和.suo文件的解释: When a Web site is created, a solution file (.sln) and ...
- Java虚拟机:内存模型详解
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 我们都知道,当虚拟机执行Java代码的时候,首先要把字节码文件加载到内存,那么这些类的信息都存放在内存中的哪个区域呢?当我们创建一个对象实 ...