CUDA与OpenGL互操作实例

本文要解决的问题是如何实现CUDA和OpenGL的互操作,使得GPU能够将通用计算的运算结果交给OpenGL进行绘制。

本文的应用程序主要包括两个方面:

1.      使用CUDA核函数生成图像数据

2.      将数据传递给OpenGL驱动程序并进行渲染

实现这个功能需要按如下四个步骤:

Step1: 申明两个全局变量,保存指向同一个缓冲区的不同句柄,指向要在OpenGL和CUDA之间共享的数据;

Step2: 选择运行应用程序的CUDA设备(cudaChooseDevice),告诉cuda运行时使用哪个设备来执行CUDA和OpenGL (cudaGLSetGLDevice);

Step3:在OpenGL中创建像素缓冲区对象;

Step4: 通知CUDA运行时将像素缓冲区对象bufferObj注册为图形资源,实现缓冲区共享。

然后就可以按照一般的CUDA程序调用核函数进行计算。运行结果如下:

/********************************************************************
*  SharedBuffer.cu
*  interact between CUDA and OpenGL
*********************************************************************/  

#include <stdio.h>
#include <stdlib.h>
#include "GL\glut.h"
#include "GL\glext.h"
#include <cuda_runtime.h>
#include <cutil_inline.h>
#include <cuda.h>
#include <cuda_gl_interop.h>  

#define GET_PROC_ADDRESS(str) wglGetProcAddress(str)
#define DIM 512  

PFNGLBINDBUFFERARBPROC    glBindBuffer     = NULL;
PFNGLDELETEBUFFERSARBPROC glDeleteBuffers  = NULL;
PFNGLGENBUFFERSARBPROC    glGenBuffers     = NULL;
PFNGLBUFFERDATAARBPROC    glBufferData     = NULL;  

// step one:
GLuint bufferObj;
cudaGraphicsResource *resource;  

__global__ void cudaGLKernel(uchar4 *ptr)
{
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;  

    float fx = x/(float)DIM - 0.5f;
    float fy = y/(float)DIM - 0.5f;  

    unsigned char green = 128 + 127 * sin(abs(fx*100) - abs(fy*100));  

    ptr[offset].x = 0;
    ptr[offset].y = green;
    ptr[offset].z = 0;
    ptr[offset].w = 255;  

}  

 void drawFunc(void)
{
    glDrawPixels(DIM, DIM, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glutSwapBuffers();
}  

static void keyFunc(unsigned char key, int x, int y)
{
    switch(key){
        case 27:
            cutilSafeCall(cudaGraphicsUnregisterResource(resource));
            glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
            glDeleteBuffers(1, &bufferObj);
            exit(0);
    }
}  

int main(int argc, char* argv[])
{
    // step 2:
    cudaDeviceProp prop;
    int dev;  

    memset(&prop, 0, sizeof(cudaDeviceProp));
    prop.major = 1;
    prop.minor = 0;
    cutilSafeCall(cudaChooseDevice(&dev, &prop));
    cutilSafeCall(cudaGLSetGLDevice(dev));  

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowSize(DIM, DIM);
    glutCreateWindow("CUDA interact with OpenGL");  

    // step 3:
    glBindBuffer    = (PFNGLBINDBUFFERARBPROC)GET_PROC_ADDRESS("glBindBuffer");
    glDeleteBuffers = (PFNGLDELETEBUFFERSARBPROC)GET_PROC_ADDRESS("glDeleteBuffers");
    glGenBuffers    = (PFNGLGENBUFFERSARBPROC)GET_PROC_ADDRESS("glGenBuffers");
    glBufferData    = (PFNGLBUFFERDATAARBPROC)GET_PROC_ADDRESS("glBufferData");  

    glGenBuffers(1, &bufferObj);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, bufferObj);
    glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, DIM*DIM*4, NULL, GL_DYNAMIC_DRAW_ARB);  

    // step 4:
    cutilSafeCall(cudaGraphicsGLRegisterBuffer(&resource, bufferObj, cudaGraphicsMapFlagsNone));  

    uchar4* devPtr;
    size_t size;
    cutilSafeCall(cudaGraphicsMapResources(1, &resource, NULL));
    cutilSafeCall(cudaGraphicsResourceGetMappedPointer((void**)&devPtr, &size, resource));  

    dim3 grids(DIM/16, DIM/16);
    dim3 threads(16, 16);
    cudaGLKernel<<<grids, threads>>>(devPtr);  

    cutilSafeCall(cudaGraphicsUnmapResources(1, &resource, NULL));
    glutKeyboardFunc(keyFunc);
    glutDisplayFunc(drawFunc);
    glutMainLoop();
    return 0;
}  

程序编译的时候貌似要注意头文件glut.h和glext.h的顺序,否则会报错~

参考资源:

1、Jason Sanders, Edward Kandrot, CUDA By Example: An Introduction toGeneral-Purpose GPU Programming (2011).

2、[菜鸟每天来段CUDA_C]CUDA与OpenGL互操作

3、CUDA与OpenGL交互开发

4、cuda与opengl互操作之PBO

时间: 2024-07-30 17:27:57

CUDA与OpenGL互操作实例的相关文章

CUDA与OpenGL互操作

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

C#中父窗口和子窗口之间控件互操作实例

本文实例讲述了C#中父窗口和子窗口之间控件互操作的方法.分享给大家供大家参考.具体分析如下: 很多人都苦恼于如何在子窗体中操作主窗体上的控件,或者在主窗体中操作子窗体上的控件.相比较而言,后面稍微简单一些,只要在主窗体中创建子窗体的时候,保留所创建子窗体对象即可. 下面重点介绍前一种,目前常见的有两种方法,基本上大同小异: 第一种,在主窗体类中定义一个静态成员,来保存当前主窗体对象,例如: 代码如下: public static yourMainWindow pCurrentWin = null

OpenGL完整实例

结合上一节的内容,分享完整代码. 先画一个cube,然后通过OnGestureListener去触发onFling使它旋转起来. OnGestureListener相关的方法我已经都加了注释,可以参考注释去了解有关的方法是干什么的. 旋转相关随便复制了一个,主要说明OnGestureListener. 简单的触摸操作会用一些OnTouchListener复杂的还是需要用到OnGestureListener. Acivity & Render: import javax.microedition.

cuda+ffmpeg+opengl解码rtsp h264码流多路

Cuda 解码 全尺寸 解码 .全尺寸窗口绘制测试( 分别 测试 视频 文件和 IP 相机 实时视频 ) 1080 p 视屏 文件 全尺寸 解码 全尺寸 显示 72 0p IP 相机 全尺寸 解码 全尺寸 显示 (最多只能获取 6路)

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.

OpenGL与CUDA互操作方式总结

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

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

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

第一篇 CUDA基础

基本概念 主机: CPU+内存的组合: 设备: GPU+显存的组合: 运行时API: "CUDA运行时API"是在"驱动API"的基础上封装而成的,简化CUDA的开发: 驱动API: "CUDA驱动API",相比于"运行时API"更接近于设备,可灵活运用设备的特性开发CUDA,可实现运行时API无法实现的功能: warp:多处理器激活.管理.调度和执行并行任务的单位.计算能力2.x的设备warp为32个线程.未来的设备可能不同

OpenCV 为啥勾搭上 OpenGL

OpenCV 为啥勾搭上 OpenGL? Vinjn张静· 2 年前 如果读者留意 OpenCV 2.3 之后的版本,那么会发现 cv::ogl namespace,ogl 自然是 OpenGL了.一个三维计算机图形库为何出现在计算机视觉中,传统的 CV 开发者是否需要学习它,这些问题待我一一来回答. 问题一:为何引入 OpenGL? 在 2.3 之前 OpenCV 的渲染部分都是由 CPU 来实现的,不论是画线还是把图片显示到屏幕上.这有两个问题,速度慢,同时没法画三维物体.引入 OpenGL