CUDA OPENGL互操作性:慢速映射

CUDA OPENGL互操作性:慢速映射,opengl,cuda,interop,pbo,Opengl,Cuda,Interop,Pbo,我的应用程序将从openGL获取渲染结果(深度贴图和渲染的2D图像信息) 到CUDA进行处理 我做的一种方法是通过glReadPixel(…,image\u array\u HOST/depth\u array\u HOST)*检索图像/深度贴图,然后将image\u HOST/depth\u HOST传递给CUDA 由cudaMemcpy(…,cudamemcpyhostodevice)编写。我已经完成了这一部分,尽管听起来有些多余。(从GPU>CPU>GPU)。 *图像数组主机/深度数组主机

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

我做的一种方法是通过glReadPixel(…,image\u array\u HOST/depth\u array\u HOST)*检索图像/深度贴图,然后将image\u HOST/depth\u HOST传递给CUDA 由cudaMemcpy(…,cudamemcpyhostodevice)编写。我已经完成了这一部分,尽管听起来有些多余。(从GPU>CPU>GPU)。 *图像数组主机/深度数组主机是我在主机上定义的数组

另一种方法是使用openGLcuda interpol。 第一步是在openGL中创建一个缓冲区,然后将图像/深度信息传递给该像素缓冲区。 还注册了一个cuda令牌并链接到该缓冲区。然后将CUDA上的矩阵链接到CUDA令牌。 (据我所知,似乎没有直接的方法将像素缓冲区链接到cuda矩阵,应该有一个cudatoken供openGL识别。如果我错了,请纠正我。)

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

然而,我从第二种方法得到的时间比第一种方法(GPU>CPU>GPU)还要长(略)。 那真让我困惑

我不确定我是否遗漏了任何部分,或者我没有以有效的方式完成

有一件事我也不确定,那就是glReadPixel(…,*数据)。 在我的理解中,如果*数据是指向主机上内存的指针,那么它将从GPU>CPU进行数据传输。 如果*data=0,并且绑定了一个缓冲区,那么数据将被传输到该缓冲区,它应该是GPU>GPU的东西

也许其他方法可以比glReadPixel(..,0)更有效地传递数据

希望有人能解释我的问题

以下是我的代码:

--

//openGL已经完成了渲染,数据都保存在openGL中。准备好了。
... 
//在cuda上声明一个指针和内存位置,供以后使用。
浮动*深度映射设备;
Cudamaloc((空白**)和深度映射设备,尺寸(浮动)*尺寸);
//初始化cudaopenGL
cudaGLSetGLDevice(0);
//生成一个缓冲区,并将cuda令牌链接到它——缓冲区cuda令牌
GLuint gl_pbo;
cudaGraphicsResource\u t cudaToken;
大小数据大小=大小(浮点)*数字数据;//数字_数据是预先定义的
void*data=malloc(数据大小);
glGenBuffers(1和gl_pbo);
glBindBuffer(GL_数组_BUFFER,GL_pbo);
glBufferData(GL\ U数组\ U缓冲区、大小、数据、GL\ U动态\ U绘图);
glBindBuffer(GL_数组_BUFFER,0);
cudaGraphicsGLRegisterBuffer(&cudaToken、gl_pbo、cudaGraphicsMapFlagsNone);//现在在gl_缓冲区和cudaResource之间有一个链接
免费(数据);
//现在它开始将缓冲区中的数据映射(链接)到cuda
glBindBuffer(GL_像素包缓冲区,GL_pbo);
glReadPixels(0,0,宽度,高度,GL_红色,GL_浮动,0);
//将渲染数据映射到缓冲区,因为它是glReadPixels(..,0),所以它应该还是快的?(GPU>GPU)
//宽度和高度预先定义。它可以是GL_DEPTH_组件,也可以是其他组件,这里只是一个示例。
glBindBuffer(GL_像素解包缓冲区,GL_pbo);
cudaGraphicsMapResources(1和cudaToken,0);//让具有gl_缓冲区链接的cufaResource连接到当前CUDA窗口
cudaGraphicsResourceGetMappedPointer((void**)和深度映射设备和数据大小,cudaToken);//传输数据
cudaGraphicsUnmapResources(1,&cudaToken,0);//为下一轮取消映射
//CUDA内核
我的内核(…,深度映射设备,…);

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

我将pbo绑定到浮点cuda(GPU)内存,但openGL原始图像渲染数据似乎是无符号字符格式(以下是我的假设),因此该数据需要转换为浮点,然后传递到cuda内存。我认为openGL所做的是使用CPU来进行这种格式转换,这就是为什么使用pbo和不使用pbo之间没有很大区别的原因

通过使用无符号字符(glreadpixel(..,GL_unsigned_BYTE,0)),使用pbo进行绑定比不使用pbo读取RGB数据更快。然后我让它做一个简单的cuda内核来做格式转换,这比openGL做的更有效。通过这样做,速度要快得多

但是,它不适用于深度缓冲区。 由于某些原因,glreadpixel读取深度贴图(无论是否使用pbo)的速度很慢。 然后,我发现了两个古老的讨论:

他们指出了格式问题,这正是我对RGB的发现。(无符号字符)。但我尝试了unsigned char/unsigned short和unsigned int,以及读取深度缓冲区的float,所有性能几乎都是相同的速度


因此,我在阅读深度方面仍然存在速度问题。

由于没有人回复,我再次在这里发表评论,希望有人能看到。对于深度,我会使用基于着色器的OpenGL,并自己将其写入第二个纹理附件。实际上Cuda6不支持深度通道互操作性。。他们“忘记”在文档中明确提到这一点。我在执行CUDAGraphicsMapPresources和cudaGraphicsSubResourceGetMappedArray时也表现不佳。你通过的纹理的大小是多少?我只使用了一个QVGA(320x240),在上面的两个通话中浪费了3毫秒。不可接受,因为数据已经在GPU上。
// 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,...);