3

我的应用程序将从 openGL(深度图和渲染的 2D 图像信息)获取渲染结果到 CUDA 进行处理。

我做的一种方法是通过 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 中创建一个缓冲区,然后将图像/深度信息传递给该像素缓冲区。还注册了一个 cuda 令牌并将其链接到该缓冲区。然后将 CUDA 上的矩阵链接到该 cuda 令牌。(据我所知,似乎没有直接的方法将像素缓冲区链接到 cuda 矩阵,应该有一个 cudatoken 供 openGL 识别。如果我错了,请纠正我。)

这部分我也做过。它认为这应该是相当有效的,因为 CUDA 正在处理的数据没有传输到任何地方,而只是传输到它在 openGL 上的位置。它是设备(GPU)内部的数据处理。

但是,我从第二种方法获得的花费时间甚至(略)长于第一种方法(GPU>CPU>GPU)。这真的让我很困惑。

我不确定我是否错过了任何部分,或者我没有以有效的方式做到这一点。

我也不确定的一件事是 glReadPixel(...,*data)。在我的理解中,如果 *data 是一个指向 HOST 上内存的指针,那么它将执行从 GPU>CPU 传输的数据。如果 *data=0,并且绑定了一个缓冲区,那么数据将被传输到该缓冲区,它应该是 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 绑定到浮点 cuda (GPU) 内存,但似乎 openGL 原始图像渲染数据是无符号字符格式,(以下是我的假设)因此需要将这些数据转换为浮点数,然后传递到 cuda 内存。我认为openGL所做的就是使用CPU来进行这种格式转换,这就是为什么使用pbo和不使用pbo没有太大区别的原因。

通过使用 unsigned char (glreadpixel(..,GL_UNSIGNED_BYTE,0)),与 pbo 绑定比不使用 pbo 读取 RGB 数据更快。然后我通过它做一个简单的 cuda 内核来做格式转换,这比 openGL 做的效率更高。通过这样做,速度会快得多。

但是,它不适用于深度缓冲区。出于某种原因,通过 glreadpixel 读取深度图(无论是否使用 pbo)都很慢。然后,我发现了两个旧讨论: 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 回答