Sorting Pixels from opengl using CUDA and Thrust

前端 未结 1 1119

I rendered a scene with opengl (I can also render it to a texture)

I want to use CUDA / Thrust to sort this rendered image

How do I link the texture I made f

相关标签:
1条回答
  • 2021-01-17 07:37

    I'm not sure it makes sense to try and use textures directly with thrust. However using an ordinary GL pixel buffer can be made to work directly with thrust.

    The following example creates an openGL pixel buffer with a particular green/black pattern, and then displays it. When you press the space bar, the pixel buffer will be made available to CUDA via CUDA/OpenGL interop, and then a thrust sort (in-place) function is called. After the sort, the sorted pixel data is displayed again. The pixel data never leaves the GPU.

    Here's the sample code:

    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    #include <GL/gl.h> 
    #include <GL/glut.h> 
    #include <cuda_gl_interop.h> 
    #include <GL/glext.h> 
    #include <GL/glx.h> 
    #include <thrust/device_ptr.h>
    #include <thrust/sort.h>
    #define GET_PROC_ADDRESS( str ) glXGetProcAddress( (const GLubyte *)str ) 
    
    static void HandleError( cudaError_t err, const char *file,  int line ) { 
        if (err != cudaSuccess) { 
                printf( "%s in %s at line %d\n", cudaGetErrorString( err ),  file, line ); 
                exit( EXIT_FAILURE ); 
        } 
    } 
    #define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ )) 
    
    
    
    PFNGLBINDBUFFERARBPROC    glBindBuffer     = NULL; 
    PFNGLDELETEBUFFERSARBPROC glDeleteBuffers  = NULL; 
    PFNGLGENBUFFERSARBPROC    glGenBuffers     = NULL; 
    PFNGLBUFFERDATAARBPROC    glBufferData     = NULL; 
    
    #define     DIM    512 
    
    GLuint  bufferObj; 
    cudaGraphicsResource *resource; 
    
    struct sort_functor
    {
      __host__ __device__
        bool operator()(uchar4 left, uchar4 right) const
        {
          return (left.y < right.y);
        }
    };
    
    
    
    // create a green/black pattern
    __global__ void kernel( uchar4 *ptr ) { 
    // map from threadIdx/BlockIdx to pixel position 
      int x = threadIdx.x + blockIdx.x * blockDim.x; 
      int y = threadIdx.y + blockIdx.y * blockDim.y; 
      int offset = x + y * blockDim.x * gridDim.x; 
    
    // now calculate the value at that position 
      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) ); 
    
    // accessing uchar4 vs unsigned char* 
      ptr[offset].x = 0; 
      ptr[offset].y = green; 
      ptr[offset].z = 0; 
      ptr[offset].w = 255; 
    } 
    
    static void draw_func( void ) { 
    
      glDrawPixels( DIM, DIM, GL_RGBA, GL_UNSIGNED_BYTE, 0 ); 
      glutSwapBuffers(); 
    }
    static void sort_pixels(){
      cudaGraphicsMapResources( 1, &resource, NULL ); 
      uchar4* devPtr; 
      size_t  size; 
    
      cudaGraphicsResourceGetMappedPointer( (void**)&devPtr, &size, resource); 
    
      thrust::device_ptr<uchar4> tptr = thrust::device_pointer_cast(devPtr);
      thrust::sort(tptr, tptr+(DIM*DIM), sort_functor());
      cudaGraphicsUnmapResources( 1, &resource, NULL ); 
      draw_func();
    }
    
    static void key_func( unsigned char key, int x, int y ) { 
      switch (key) { 
        case 27: 
            HANDLE_ERROR( cudaGraphicsUnregisterResource( resource ) ); 
            glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0 ); 
            glDeleteBuffers( 1, &bufferObj ); 
            exit(0); 
            break;
        case 32:
            sort_pixels();
            break;
        default:
            break;
      } 
    } 
    
    
    
    int main(int argc, char *argv[]) { 
    
      cudaGLSetGLDevice( 0 ); 
    
      glutInit( &argc, argv ); 
      glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA ); 
      glutInitWindowSize( DIM, DIM ); 
      glutCreateWindow( "sort test" ); 
    
      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 ); 
    
    
      cudaGraphicsGLRegisterBuffer( &resource, bufferObj, cudaGraphicsMapFlagsNone ); 
    
    
      cudaGraphicsMapResources( 1, &resource, NULL ); 
      uchar4* devPtr; 
      size_t  size; 
    
      cudaGraphicsResourceGetMappedPointer( (void**)&devPtr, &size, resource); 
    
      dim3    grid(DIM/16,DIM/16); 
      dim3    threads(16,16); 
      kernel<<<grid,threads>>>( devPtr ); 
      cudaGraphicsUnmapResources( 1, &resource, NULL ); 
    
    // set up GLUT and kick off main loop 
      glutKeyboardFunc( key_func ); 
      glutDisplayFunc( draw_func ); 
      glutMainLoop(); 
    } 
    

    compile like this:

    nvcc -arch=sm_20 -o ogltest ogltest.cu -lglut
    

    Here's what the display window looks like before sorting:

    display before sorting

    Here's what the display window looks like after sorting (after you press the space bar):

    display after sorting

    Note that we are sorting pixels based on the green component in this example.

    You can press the ESC key to exit the app.

    There are some updated versions of this sample code here.

    0 讨论(0)
提交回复
热议问题