【问题标题】:CUDA OPENGL Interoperability: slow mappingCUDA OPENGL 互操作性:慢映射
【发布时间】:2013-04-04 23:35:02
【问题描述】:

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

我做的一种方法是通过 glReadPixel(..., image_array_HOST/depth_array_Host)* 检索图像/深度图,然后将 image_HOST/depth_HOST 传递给 CUDA 通过 cudaMemcpy(..., cudaMemcpyHostToDevice)。我已经完成了这部分,虽然这听起来是多余的。 (从 GPU>CPU>GPU)。 *image_array_HOST/depth_array_Host 是我在主机上定义的数组。

另一种方法是使用openGLcuda 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,...);

【问题讨论】:

  • 由于没有人回复,我再次来到这里,希望有人能看到。非常感谢

标签: opengl cuda interop pbo


【解决方案1】:

我想我现在可以部分回答我的问题,希望它对某些人有用。

我将 pbo 绑定到浮点 cuda (GPU) 内存,但似乎 openGL 原始图像渲染数据是无符号字符格式,(以下是我的假设)因此需要将这些数据转换为浮点数,然后传递给 cuda 内存.我认为openGL所做的就是使用CPU进行这种格式转换,这就是为什么使用和不使用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 用于读取深度缓冲区,所有性能几乎相同的速度。

所以我仍然有阅读深度的速度问题。

【讨论】:

  • 对于深度,我会使用基于着色器的 OpenGL 并自己将其写入第二个纹理附件。实际上,Cuda6 不支持深度通道互操作性。他们“忘记”在文档中明确提及这一点。在执行 cudaGraphicsMapResourcescudaGraphicsSubResourceGetMappedArray 时,我的表现也很缓慢。你通过的纹理大小是多少?我只使用 QVGA (320x240),我在上面的两个调用上浪费了 3ms。考虑到数据已经在 GPU 上,这是不可接受的。
猜你喜欢
  • 2011-12-03
  • 1970-01-01
  • 2011-09-22
  • 2015-08-03
  • 1970-01-01
  • 2013-10-15
  • 2013-04-30
  • 2016-12-04
  • 2016-01-25
相关资源
最近更新 更多