3

私のアプリケーションは、openGL からレンダリングされた結果 (深度マップとレンダリングされた 2D イメージ情報の両方) を CUDA に渡して処理します。

私が行った 1 つの方法は、glReadPixel(..., image_array_HOST/depth_array_Host)* でイメージ/深度マップを取得し、cudaMemcpy(..., cudaMemcpyHostToDevice) で image_HOST/depth_HOST を CUDA に渡すことです。冗長に聞こえますが、この部分は実行しました。(GPU>CPU>GPU から)。*image_array_HOST/depth_array_Host は、ホストで定義する配列です。

別の方法は、openGL<>cuda interpol を使用することです。最初のステップは、openGL で 1 つのバッファーを作成し、そのピクセル バッファーに画像/深度情報を渡すことです。また、1 つの cuda トークンが登録され、そのバッファーにリンクされます。次に、CUDA のマトリックスをその cuda トークンにリンクします。(私が知る限り、ピクセル バッファを cuda マトリックスにリンクする直接的な方法はないようです。openGL が認識する cudatoken が必要です。間違っている場合は修正してください。)

この部分もやりました。CUDA が処理しているデータはどこにも転送されず、openGL 上のどこにでも転送されるため、かなり効率的であると考えられました。デバイス(GPU)内部のデータ処理です​​。

ただし、2 番目の方法で得た所要時間は、最初の方法よりも (わずかに) 長くなります (GPU>CPU>GPU)。それは本当に私を混乱させます。

見逃した部分があるのか​​、それとも効率的な方法でやらなかったのかはわかりません。

私もよくわからないことの1つは、glReadPixel(...、* data)です。私の理解では、*data が HOST 上のメモリにリンクするポインタである場合、GPU>CPU からのデータ転送を行います。*data=0 で 1 つのバッファーがバインドされている場合、データはそのバッファーに転送され、GPU>GPU のようになります。

おそらく、glReadPixel(..,0) よりも効率的にデータを渡すことができる他の方法があります。

何人かが私の質問を説明してくれることを願っています。

以下は私のコードです:

--

// openGL has finished its rendering, and the data are all save in the openGL. It is ready to go.
... 


// declare one pointer and memory location on cuda for later use.
float *depth_map_Device;
cudaMalloc((void**) &depth_map_Device, sizeof(float) * size); 


// inititate cuda<>openGL
cudaGLSetGLDevice(0);   


// generate a buffer, and link the cuda token to it -- buffer <>cuda token
GLuint gl_pbo;
cudaGraphicsResource_t cudaToken;   
size_t data_size = sizeof(float)*number_data;                               // number_data is defined beforehand
void *data = malloc(data_size);
glGenBuffers(1, &gl_pbo);
glBindBuffer(GL_ARRAY_BUFFER, gl_pbo);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_DYNAMIC_DRAW); 
glBindBuffer(GL_ARRAY_BUFFER, 0);
cudaGraphicsGLRegisterBuffer(&cudaToken, gl_pbo, cudaGraphicsMapFlagsNone); // now there is a link between gl_buffer and cudaResource
free(data);

// now it start to map(link) the data on buffer to cuda 
glBindBuffer(GL_PIXEL_PACK_BUFFER, gl_pbo);                     
glReadPixels(0, 0, width, height, GL_RED, GL_FLOAT, 0);         
// map the rendered data to buffer, since it is glReadPixels(..,0), it should be still fast? (GPU>GPU)
// width & height are defined beforehand. It can be GL_DEPTH_COMPONENT or others as well, just an example here.
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo);                       
cudaGraphicsMapResources(1, &cudaToken, 0);                     // let cufaResource which has a link to gl_buffer to the the current CUDA windows
cudaGraphicsResourceGetMappedPointer((void **)&depth_map_Device,  &data_size, cudaToken);   // transfer data
cudaGraphicsUnmapResources(1, &cudaToken, 0);           // unmap it, for the next round

// CUDA kernel
my_kernel       <<<block_number, thread_number>>> (...,depth_map_Device,...);
4

1 に答える 1

3

私の質問に部分的に答えることができると思います。一部の人にとって役立つことを願っています。

pbo を float cuda (GPU) メモリにバインドしていましたが、openGL の raw 画像レンダリング データは unsigned char 形式のようです (以下は私の推測です)。そのため、このデータを float に変換してから cuda メモリに渡す必要があります。openGL が行ったのは、CPU を使用してこのフォーマット変換を行うことだと思います。そのため、pbo を使用する場合と使用しない場合で大きな違いはありません。

unsigned char (glreadpixel(..,GL_UNSIGNED_BYTE,0)) を使用すると、RGB データの読み取りに pbo を使用しない場合よりも、pbo とのバインドが高速になります。そして、フォーマット変換を行う単純な cuda カーネルを渡します。これは、openGL が行ったものよりも効率的です。これを行うことで、速度ははるかに速くなります。

ただし、深度バッファでは機能しません。何らかの理由で、glreadpixel による深度マップの読み取り (pbo の有無に関係なく) が遅くなります。そして、2 つの古い議論を見つけました: http://www.opengl.org/discussion_boards/showthread.php/153121-Reading-the-Depth-Buffer-Why-so-slow

http://www.opengl.org/discussion_boards/showthread.php/173205-Saving-Restoring-Depth-Buffer-to-from-PBO

彼らはフォーマットの質問を指摘しましたが、それはまさに私が RGB について見つけたものです。(符号なし文字)。しかし、unsigned char/unsigned short と unsigned int を試してみました。深度バッファーを読み取るために float を試しましたが、すべてのパフォーマンスはほぼ同じ速度でした。

だから私はまだ深さを読むための速度の問題を抱えています。

于 2013-04-25T15:06:38.910 に答える