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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM