[转]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.

三、参考链接

原文链接:OpenGL与CUDA互操作方式总结

原文地址:https://www.cnblogs.com/rainbow70626/p/8428788.html

时间: 2024-07-30 17:28:03

[转]OpenGL与CUDA互操作方式总结的相关文章

OpenGL与CUDA互操作方式总结

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

OpenGL几种绘制方式

OpenGL几种绘制方式 OpenGL 绘制 本文介绍了OpenGL的几种绘制方式及各自特点.绘制方式如下: 立即模式 显示列表 顶点数组 VBO 1.立即模式 最直接的方式,传统的使用glBegin...glEnd绘制的方式,如下所示: glBegin( GL_TRIANGLES ); glVertex3f(-1.0f, -0.5f, -4.0f); glVertex3f( 1.0f, -0.5f, -4.0f); glVertex3f( 0.0f, 0.5f, -4.0f); glEnd()

CUDA编程

目录: 1.什么是CUDA 2.为什么要用到CUDA 3.CUDA环境搭建 4.第一个CUDA程序 5. CUDA编程 5.1. 基本概念 5.2. 线程层次结构 5.3. 存储器层次结构 5.4. 运行时API 5.4.1. 初始化 5.4.2. 设备管理 5.4.3. 存储器管理 5.4.3.1. 共享存储器 5.4.3.2. 常量存储器 5.4.3.3. 线性存储器 5.4.3.4. CUDA数组 5.4.4. 流管理 5.4.5. 事件管理 5.4.6. 纹理参考管理 5.4.6.1.

CUDA与OpenGL互操作

当处理较大数据量的时候,往往会用GPU进行运算,比如OpenGL或者CUDA.在实际的操作中,往往CUDA实现并行计算会比OpenGL更加方便,而OpenGL在进行后期渲染更具有优势.由于CUDA中的运算结果存储在GPU中,如果将数据download到CPU,然后再将CPU中的数据上传到GPU,使用OpenGL进行渲染,中间的GPU与CPU的交互会很耗时,毕竟使用GPU的目的就是为了加速,这样的数据传输会降低效率. 接下来简要说一下如何使CUDA和OpenGL互操作来实现GPU中数据的交互传输,

CUDA与OpenGL互操作实例

本文要解决的问题是如何实现CUDA和OpenGL的互操作,使得GPU能够将通用计算的运算结果交给OpenGL进行绘制. 本文的应用程序主要包括两个方面: 1.      使用CUDA核函数生成图像数据 2.      将数据传递给OpenGL驱动程序并进行渲染 实现这个功能需要按如下四个步骤: Step1: 申明两个全局变量,保存指向同一个缓冲区的不同句柄,指向要在OpenGL和CUDA之间共享的数据: Step2: 选择运行应用程序的CUDA设备(cudaChooseDevice),告诉cud

图形互操作源码分析

项目打包下载 1 /* 2 * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. 3 * 4 * NVIDIA Corporation and its licensors retain all intellectual property and 5 * proprietary rights in and to this software and related documentation. 6 * Any use, repr

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

博主作为OpenGL新手,最近要用OpenGL进行并行的数据计算,突然发现这样的资料还是很少的,大部分资料和参考书都是讲用OpenGL进行渲染的.好不容易找到一本书<GPGPU编程技术,从OpenGL.CUDA到OpenCL>,里面对并行处理的发展进行了系统性的介绍,还是很不错的.小白博主很兴奋,看完书中第三章后恍然大悟了很多,就贴出书中代码3-3的例子,实现一番,并用一副图片数据做了实现. 实现环境:Window7 32bit, VS2013+OpenGL3.3+GLEW+GLFW. Ope

opengl两种投影类型

openGL两种投影方式 from http://hi.baidu.com/fcqian/blog/item/cc5794ec76807a3f27979131.html 投影变换是一种很关键的图形变换,OpenGL中只提供了两种投影方式,一种是正射投影,另一种是透视投影.不管是调用哪种投影函数,为了避免不必要的变换,其前面必须加上以下两句: glMAtrixMode(GL_PROJECTION); glLoadIdentity(); 事实上,投影变换的目的就是定义一个视景体,使得视景体外多余的部

Mali GPU OpenGL ES 应用性能优化--测试+定位+优化流程

1. 使用DS-5 Streamline定位瓶颈 DS-5 Streamline要求GPU驱动启用性能测试,在Mali GPU驱动中激活性能测试对性能影响微不足道. 1.1 DS-5 Streamline简介 可使用DS-5 Streamline从CPU和Mali GPU中实时收集性能计数器,然后以图形方式显示这些计数器,其主要功能如下:     ? 收集计数器--从CPU和Mali GPU中     ? 保存收集到的计数器数据以供回放     ? 查看显示GPU活动.GPU活动和Framebu