我的应用程序将从 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,...);