cuda与opengl互操作之PBO

PBO(像素缓冲区对象)也可以映射到CUDA地址空间,CUDA的kernel函数可以讲计算结果直接写到PBO中,然后将 PBO的内容复制到texture,进行绘制。

具体使用步骤:

1、创建PBO

[cpp]  view plain  copy
  1. // Generate a buffer ID called a PBO (Pixel Buffer Object)  
  2. glGenBuffers(1,pbo);  
  3. // Make this the current UNPACK buffer (OpenGL is state-based)  
  4. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, *pbo);  
  5. // Allocate data for the buffer. 4-channel 8-bit image  
  6. glBufferData(GL_PIXEL_UNPACK_BUFFER, size_tex_data, NULL, GL_DYNAMIC_COPY);  

2、注册PBO

[cpp]  view plain  copy
  1. struct cudaGraphicsResource *cuda_pbo_resource;  
  2. cudaGraphicsGLRegisterBuffer(&cuda_pbo_resource, *pbo, cudaGraphicsMapFlagsWriteDiscard);  

3、映射PBO

[cpp]  view plain  copy
  1. cudaGraphicsMapResources(1, &cuda_pbo_resource, 0);  
[cpp]  view plain  copy
  1. cudaGraphicsResourceGetMappedPointer((void**)&d_output, &num_bytes, cuda_pbo_resource);  


4、使用

[cpp]  view plain  copy
  1. launch_kernel(d_output, window_width, window_height, w);  

5、解除映射

[cpp]  view plain  copy
  1. cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0);  

6、解除注册

[cpp]  view plain  copy
  1. cudaGraphicsUnregisterResource(cuda_pbo_resource);  

7、删除PBO

[cpp]  view plain  copy
  1. glBindBuffer(GL_ARRAY_BUFFER, *pbo);  
  2. glDeleteBuffers(1, pbo);  

8、绘制

[cpp]  view plain  copy
  1. glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);  
  2.   
  3. glBindTexture(GL_TEXTURE_2D, textureID);  
  4.   
  5. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 128, 128,/*window_width, window_height,*/   
  6.         GL_RGBA, GL_UNSIGNED_BYTE, NULL);  
  7.   
  8. glBegin(GL_QUADS);  
  9. glTexCoord2f(0.0f,1.0f); glVertex3f(0.0f,0.0f,0.0f);  
  10. glTexCoord2f(0.0f,0.0f); glVertex3f(0.0f,1.0f,0.0f);  
  11. glTexCoord2f(1.0f,0.0f); glVertex3f(1.0f,1.0f,0.0f);  
  12. glTexCoord2f(1.0f,1.0f); glVertex3f(1.0f,0.0f,0.0f);  
  13. glEnd();  

代码:

[cpp]  view plain  copy
  1. //myPBO.cpp  
  2.   
  3. #include <gl/glew.h>  
  4. #include <cuda_runtime.h>  
  5. #include <cutil_inline.h>  
  6. #include <cutil_gl_inline.h>  
  7. #include <cutil_gl_error.h>  
  8. #include <rendercheck_gl.h>  
  9. #include <sdkHelper.h>  
  10.   
  11. extern void initCuda(int argc, char **argv);  
  12. extern void runCuda();  
  13.   
  14.   
  15. unsigned int window_width = 500;  
  16. unsigned int window_height = 500;  
  17. unsigned int image_width = 128;//window_width;  
  18. unsigned int image_height = 128;//window_height;  
  19. unsigned int timer = 0;  
  20.   
  21. int animFlag = 1;   
  22. float animTime = 0.0f;  
  23. float animInc = 0.1f;  
  24.   
  25. GLuint pbo = NULL;  
  26. GLuint textureID = NULL;  
  27.   
  28. struct cudaGraphicsResource *cuda_pbo_resource;  
  29.   
  30. extern "C" void launch_kernel(uchar4* , unsigned int, unsigned intfloat);  
  31.   
  32. void createPBO(GLuint *pbo)  
  33. {  
  34.     if (pbo)  
  35.     {  
  36.         int num_texels = image_width * image_height;  
  37.         int num_values = num_texels * 4;  
  38.   
  39.         int size_tex_data = sizeof(GLubyte) * num_values;  
  40.   
  41.         glGenBuffers(1, pbo);  
  42.         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, *pbo);  
  43.         glBufferData(GL_PIXEL_UNPACK_BUFFER, size_tex_data, NULL, GL_DYNAMIC_COPY);  
  44.   
  45.         cudaGraphicsGLRegisterBuffer(&cuda_pbo_resource, *pbo, cudaGraphicsMapFlagsWriteDiscard);  
  46.     }  
  47. }  
  48.   
  49. void deletePBO(GLuint *pbo)  
  50. {  
  51.     if (pbo)  
  52.     {  
  53.         cudaGraphicsUnregisterResource(cuda_pbo_resource);  
  54.   
  55.         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, *pbo);  
  56.         glDeleteBuffers(1, pbo);  
  57.   
  58.         *pbo = NULL;  
  59.     }  
  60. }  
  61.   
  62. void createTexture(GLuint *textureID, unsigned int size_x, unsigned int size_y)  
  63. {  
  64.     glEnable(GL_TEXTURE_2D);  
  65.   
  66.     glGenTextures(1, textureID);  
  67.     glBindTexture(GL_TEXTURE_2D, *textureID);  
  68.   
  69.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);  
  70.   
  71.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
  72.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
  73. }  
  74.   
  75. void deleteTexture(GLuint *tex)  
  76. {  
  77.     glDeleteTextures(1, tex);  
  78.   
  79.     *tex = NULL;  
  80. }  
  81.   
  82. void cleanupCuda()  
  83. {  
  84.     if(pbo) deletePBO(&pbo);  
  85.     if(textureID) deleteTexture(&textureID);  
  86. }  
  87.   
  88. void runCuda()  
  89. {  
  90.     uchar4 *dptr = NULL;  
  91.     size_t num_bytes;  
  92.   
  93.     cudaGraphicsMapResources(1, &cuda_pbo_resource, 0);  
  94.     cudaGraphicsResourceGetMappedPointer((void**)&dptr, &num_bytes, cuda_pbo_resource);  
  95.   
  96.     launch_kernel(dptr, image_width, image_height, animTime);  
  97.   
  98.     cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0);  
  99.   
  100. }  
  101.   
  102. void initCuda(int argc, char **argv)  
  103. {  
  104.     if(cutCheckCmdLineFlag(argc, (const char**)argv, "device"))  
  105.         cutilGLDeviceInit(argc, argv);  
  106.     else  
  107.         cudaGLSetGLDevice(cutGetMaxGflopsDeviceId());  
  108.   
  109.     createPBO(&pbo);  
  110.     createTexture(&textureID, image_width, image_height);  
  111.   
  112.     atexit(cleanupCuda);  
  113.   
  114.     runCuda();  
  115. }  
  116.   
  117. void computeFPS()  
  118. {  
  119.     static int fpsCount = 0;  
  120.     static int fpsLimit = 100;  
  121.   
  122.     fpsCount++;  
  123.   
  124.     if(fpsCount == fpsLimit)  
  125.     {  
  126.         char fps[256];  
  127.         float ifps = 1.0f / (cutGetAverageTimerValue(timer) / 1000.0f);  
  128.         sprintf(fps, "Cuda GL Interop Wrapper: %3.1f fps", ifps);  
  129.   
  130.         glutSetWindowTitle(fps);  
  131.         fpsCount = 0;  
  132.   
  133.         cutilCheckError(cutResetTimer(timer));    
  134.     }  
  135. }  
  136.   
  137. void display()  
  138. {  
  139.     runCuda();  
  140.   
  141.     glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);  
  142.   
  143.     glBindTexture(GL_TEXTURE_2D, textureID);  
  144.   
  145.     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 128, 128,/*window_width, window_height,*/   
  146.         GL_RGBA, GL_UNSIGNED_BYTE, NULL);  
  147.   
  148.     glBegin(GL_QUADS);  
  149.     glTexCoord2f(0.0f,1.0f); glVertex3f(0.0f,0.0f,0.0f);  
  150.     glTexCoord2f(0.0f,0.0f); glVertex3f(0.0f,1.0f,0.0f);  
  151.     glTexCoord2f(1.0f,0.0f); glVertex3f(1.0f,1.0f,0.0f);  
  152.     glTexCoord2f(1.0f,1.0f); glVertex3f(1.0f,0.0f,0.0f);  
  153.     glEnd();  
  154.   
  155.   
  156.     glutSwapBuffers();  
  157.   
  158.     if(animFlag) {  
  159.         glutPostRedisplay();  
  160.         animTime += animInc;  
  161.     }  
  162. }  
  163.   
  164. void fpsDisplay()  
  165. {  
  166.     cutilCheckError(cutStartTimer(timer));  
  167.   
  168.     display();  
  169.   
  170.     cutilCheckError(cutStopTimer(timer));  
  171.   
  172.     computeFPS();  
  173. }  
  174.   
  175.   
  176. CUTBoolean initGL(int argc, char **argv)  
  177. {  
  178.     glutInit(&argc, argv);  
  179.     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);  
  180.     glutInitWindowSize(window_width, window_height);  
  181.     glutCreateWindow("Cuda GL Interop Demo (adapted from NVDIA's simpleGL)");  
  182.   
  183.     glutDisplayFunc(fpsDisplay);  
  184.   
  185.     glewInit();  
  186.     if(!glewIsSupported("GL_VERSION_2_0"))  
  187.     {  
  188.         fprintf(stderr, "ERROR: Support for necessary OpengGL extensions missing.");  
  189.         return CUTFalse;  
  190.     }  
  191.   
  192.     glViewport(0, 0, window_width, window_height);  
  193.   
  194.     glClearColor(0.0, 0.0, 0.0, 1.0);  
  195.     glDisable(GL_DEPTH_TEST);  
  196.   
  197.     glMatrixMode(GL_MODELVIEW);  
  198.     glLoadIdentity();  
  199.   
  200.     glMatrixMode(GL_PROJECTION);  
  201.     glLoadIdentity();  
  202.   
  203.     glOrtho(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);  
  204.   
  205.     return CUTTrue;  
  206. }  
  207.   
  208.   
  209.   
  210. int main(int argc, char **argv)  
  211. {  
  212.     cutilCheckError(cutCreateTimer(&timer));  
  213.   
  214.     if (CUTFalse == initGL(argc, argv))  
  215.         return CUTFalse;  
  216.   
  217.     initCuda(argc, argv);  
  218.     CUT_CHECK_ERROR_GL();  
  219.   
  220.     glutDisplayFunc(fpsDisplay);  
  221.   
  222.     glutMainLoop();  
  223.       
  224.     cudaThreadExit();           ///  
  225.     cutilExit(argc, argv);      //  
  226. }  


[cpp]  view plain  copy
  1. //kernelPBO.cu  
  2.   
  3. #include <stdio.h>  
  4.   
  5. float gain=0.75f;  
  6. float xStart=2.f;  
  7. float yStart=1.f;  
  8. float zOffset = 0.0f;  
  9. #define Z_PLANE 50.f  
  10.   
  11. __constant__ unsigned char c_perm[256];  
  12. __shared__ unsigned char s_perm[256]; // shared memory copy of permuation array  
  13. unsigned char* d_perm=NULL; // global memory copy of permutation array  
  14. // host version of permutation array  
  15. const static unsigned char h_perm[] = {151,160,137,91,90,15,  
  16. 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,  
  17. 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,  
  18. 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,  
  19. 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,  
  20. 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,  
  21. 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,  
  22. 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,  
  23. 223,183,170,213,119,248,152,2,44,154,163, 70,221,153,101,155,167, 43,172,9,  
  24. 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,  
  25. 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,  
  26. 49,192,214, 31,181,199,106,157,184,84,204,176,115,121,50,45,127, 4,150,254,  
  27. 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180  
  28. };  
  29.   
  30. __device__ inline int perm(int i) { return(s_perm[i&0xff]); }  
  31. __device__ inline float fade(float t) { return t * t * t * (t * (t * 6.f - 15.f) + 10.f); }  
  32. __device__ inline float lerpP(float t, float a, float b) { return a + t * (b - a); }  
  33. __device__ inline float grad(int hash, float x, float y, float z) {  
  34.     int h = hash & 15;                      // CONVERT LO 4 BITS OF HASH CODE  
  35.     float u = h<8 ? x : y,                 // INTO 12 GRADIENT DIRECTIONS.  
  36.         v = h<4 ? y : h==12||h==14 ? x : z;  
  37.     return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);  
  38. }  
  39.   
  40. __device__ float inoise(float x, float y, float z) {  
  41.     int X = ((int)floorf(x)) & 255, // FIND UNIT CUBE THAT  
  42.         Y = ((int)floorf(y)) & 255,   // CONTAINS POINT.  
  43.         Z = ((int)floorf(z)) & 255;  
  44.     x -= floorf(x);               // FIND RELATIVE X,Y,Z  
  45.     y -= floorf(y);               // OF POINT IN CUBE.  
  46.     z -= floorf(z);  
  47.     float u = fade(x),            // COMPUTE FADE CURVES  
  48.         v = fade(y),                // FOR EACH OF X,Y,Z.  
  49.         w = fade(z);  
  50.     int A = perm(X)+Y, AA = perm(A)+Z, AB = perm(A+1)+Z, // HASH COORDINATES OF  
  51.         B = perm(X+1)+Y, BA = perm(B)+Z, BB = perm(B+1)+Z; // THE 8 CUBE CORNERS,  
  52.   
  53.     return lerpP(w, lerpP(v, lerpP(u, grad(perm(AA), x  , y  , z   ), // AND ADD  
  54.         grad(perm(BA), x-1.f, y  , z   )),   // BLENDED  
  55.         lerpP(u, grad(perm(AB), x  , y-1.f, z   ),    // RESULTS  
  56.         grad(perm(BB), x-1.f, y-1.f, z   ))),     // FROM  8  
  57.         lerpP(v, lerpP(u, grad(perm(AA+1), x  , y  , z-1.f ),  // CORNERS  
  58.         grad(perm(BA+1), x-1.f, y  , z-1.f )),    // OF CUBE  
  59.         lerpP(u, grad(perm(AB+1), x  , y-1.f, z-1.f ),  
  60.         grad(perm(BB+1), x-1.f, y-1.f, z-1.f ))));  
  61. #ifdef ORIG  
  62.     return(perm(X));  
  63. #endif  
  64.   
  65. }  
  66.   
  67. __device__ inline float height2d(float x, float y, int octaves,  
  68.                                  float lacunarity = 2.0f, float gain = 0.5f)  
  69. {  
  70.     float freq = 1.0f, amp = 0.5f;  
  71.     float sum = 0.f;    
  72.     for(int i=0; i<octaves; i++) {  
  73.         sum += inoise(x*freq,y*freq, Z_PLANE)*amp;  
  74.         freq *= lacunarity;  
  75.         amp *= gain;  
  76.     }  
  77.     return sum;  
  78. }  
  79.   
  80. __device__ inline uchar4 colorElevation(float texHeight)  
  81. {  
  82.     uchar4 pos;  
  83.   
  84.     // color textel (r,g,b,a)  
  85.     if (texHeight < -1.000f) pos = make_uchar4(000, 000, 128, 255); //deeps  
  86.     else if (texHeight < -.2500f) pos = make_uchar4(000, 000, 255, 255); //shallow  
  87.     else if (texHeight < 0.0000f) pos = make_uchar4(000, 128, 255, 255); //shore  
  88.     else if (texHeight < 0.0625f) pos = make_uchar4(240, 240, 064, 255); //sand  
  89.     else if (texHeight < 0.1250f) pos = make_uchar4(032, 160, 000, 255); //grass  
  90.     else if (texHeight < 0.3750f) pos = make_uchar4(224, 224, 000, 255); //dirt  
  91.     else if (texHeight < 0.7500f) pos = make_uchar4(128, 128, 128, 255); //rock  
  92.     else                          pos = make_uchar4(255, 255, 255, 255); //snow  
  93.   
  94.     return(pos);  
  95. }  
  96.   
  97. void checkCUDAError(const char *msg) {  
  98.     cudaError_t err = cudaGetLastError();  
  99.     if( cudaSuccess != err) {  
  100.         fprintf(stderr, "Cuda error: %s: %s.\n", msg, cudaGetErrorString( err) );   
  101.         exit(EXIT_FAILURE);   
  102.     }  
  103. }   
  104.   
  105. //Simple kernel fills an array with perlin noise  
  106. __global__ void k_perlin(uchar4* pos, unsigned int width, unsigned int height,   
  107.                          float2 start, float2 delta, float gain, float zOffset,  
  108.                          unsigned char* d_perm)  
  109. {  
  110.     int idx = blockIdx.x * blockDim.x + threadIdx.x;  
  111.     float xCur = start.x + ((float) (idx%width)) * delta.x;  
  112.     float yCur = start.y + ((float) (idx/width)) * delta.y;  
  113.   
  114.     if(threadIdx.x < 256)  
  115.         // Optimization: this causes bank conflicts  
  116.         s_perm[threadIdx.x] = d_perm[threadIdx.x];  
  117.     // this synchronization can be important if there are more that 256 threads  
  118.     __syncthreads();  
  119.   
  120.   
  121.     // Each thread creates one pixel location in the texture (textel)  
  122.     if(idx < width*height) {  
  123.         float h = height2d(xCur, yCur, 4, 2.f, 0.75f) + zOffset;  
  124.   
  125.         pos[idx] = colorElevation(h);  
  126.     }  
  127. }  
  128.   
  129.   
  130. // Wrapper for the __global__ call that sets up the kernel call  
  131. extern "C" void launch_kernel(uchar4* pos, unsigned int image_width,   
  132.                               unsigned int image_height, float time)  
  133. {  
  134.     int nThreads=256; // must be equal or larger than 256! (see s_perm)  
  135.     int totalThreads = image_height * image_width;  
  136.     int nBlocks = totalThreads/nThreads;   
  137.     nBlocks += ((totalThreads%nThreads)>0)?1:0;  
  138.   
  139.     float xExtent = 10.f;  
  140.     float yExtent = 10.f;  
  141.     float xDelta = xExtent/(float)image_width;  
  142.     float yDelta = yExtent/(float)image_height;  
  143.   
  144.     if(!d_perm) { // for convenience allocate and copy d_perm here  
  145.         cudaMalloc((void**) &d_perm,sizeof(h_perm));  
  146.         cudaMemcpy(d_perm,h_perm,sizeof(h_perm),cudaMemcpyHostToDevice);  
  147.         checkCUDAError("d_perm malloc or copy failed!");  
  148.     }  
  149.   
  150.     k_perlin<<< nBlocks, nThreads>>>(pos, image_width, image_height,  
  151.         make_float2(xStart, yStart),  
  152.         make_float2(xDelta, yDelta),  
  153.         gain, zOffset, d_perm);  
  154.   
  155.     // make certain the kernel has completed   
  156.     cudaThreadSynchronize();  
  157.     checkCUDAError("kernel failed!");  
  158. }  


[cpp]  view plain  copy
  1. //another kernelPBO.cu  
  2.   
  3. #include <stdio.h>  
  4.   
  5. void checkCUDAError(const char *msg)  
  6. {  
  7.     cudaError_t err = cudaGetLastError();  
  8.   
  9.     if(cudaSuccess != err)  
  10.     {  
  11.         fprintf(stderr, "CUDA error: %s: %s. \n", msg, cudaGetErrorString(err));  
  12.         exit(EXIT_FAILURE);  
  13.     }  
  14. }  
  15.   
  16. __global__ void kernel(uchar4 *pos, unsigned int width, unsigned int height, float time)  
  17. {  
  18.     int index = blockIdx.x * blockDim.x + threadIdx.x;  
  19.   
  20.     unsigned int x = index % width;  
  21.     unsigned int y = index / width;  
  22.   
  23.     if (index < width *height)  
  24.     {  
  25.         unsigned char r = (x + (int)time) & 0xff;  
  26.         unsigned char g = (y + (int)time) & 0xff;  
  27.         unsigned char b = ((x+y) + (int)time) & 0xff;  
  28.   
  29.         pos[index].w = 0;  
  30.         pos[index].x = r;   
  31.         pos[index].y = g;  
  32.         pos[index].z = b;  
  33.   
  34.     }  
  35. }  
  36.   
  37. extern "C" void launch_kernel(uchar4* pos, unsigned int image_width, unsigned int image_height, float time)  
  38. {  
  39.     int nThreads = 256;  
  40.     int totalThreads = image_height * image_width;  
  41.     int nBlocks = totalThreads / nThreads;  
  42.     nBlocks += ((totalThreads%nThreads)>0)?1:0;  
  43.   
  44.     kernel<<<nBlocks, nThreads>>>(pos, image_width, image_height, time);  
  45.   
  46.     cudaThreadSynchronize();  
  47.   
  48.     checkCUDAError("kernel failed!");  
  49. }  


运行结果:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值