CUDA OPENGL互操作性:映射速度慢

时间:2013-04-12 12:26:02

标签: opengl cuda interop pbo

我的应用程序将从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是我在主机上定义的数组。

另一种方法是使用openGL<> cuda interpol。 第一步是在openGL中创建一个缓冲区,然后将图像/深度信息传递给该像素缓冲区。 还注册了一个cuda令牌并链接到该缓冲区。然后将CUDA上的矩阵链接到该cuda令牌。 (据我所知,似乎没有直接的方法将像素缓冲区链接到cuda矩阵,应该有一个cudatoken for 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,...);

1 个答案:

答案 0 :(得分:2)

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

我将pbo绑定到float cuda(GPU)内存,但似乎openGL原始图像渲染数据是unsigned char格式,(以下是我的假设)所以这个数据需要转换为float然后传递给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用于读取深度缓冲区,所有性能几乎都是相同的速度。

所以读取深度仍然存在速度问题。