如何有效地交换OpenCL内存缓冲区?

时间:2012-06-14 20:45:53

标签: buffer opencl swap

正如标题所示,我正在寻找如何有效地交换两个OpenCL缓冲区。我的内核使用两个gloabl缓冲区,一个作为输入,一个作为输出。但是,我在具有相同NDRange的for循环中调用我的内核,每次设置内核参数,使内核入队,并交换缓冲区,因为前一个输出缓冲区将是下一次迭代的输入缓冲区种子。

交换这两个缓冲区的适当方法是什么?我想将缓冲区复制回主机到一个已经malloc的数组并使用clEnqueueWriteBuffer()clEnqueueReadBuffer()将其复制到下一个输入缓冲区是一种低效的方法。否则我只是使用临时cl_mem变量来进行交换。

2 个答案:

答案 0 :(得分:10)

您不需要,只需在第二次排入内核之前使用clSetKernelArg设置正确的内核args(使用clEnqueueNDRangeKernel)。缓冲区将保留在设备上,不会将任何内容复制回主机。

当然,在这种情况下,您的缓冲区必须使用CL_MEM_READ_WRITE创建。

答案 1 :(得分:1)

如前所述:不,您根本不需要交换缓冲区。

但是,我不同意建议的答案。函数clSetKernelArg() 不是线程安全的,并且不能在操作循环中调用。

正确的解决方案是创建使用相同程序和源创建的2个内核。这种方法更符合OpenCL编程理念“一个任务的一个内核”。拥有许多具有相同代码但不同参数的内核是可行的方法。

第一个内核将具有:

kernel1 = clCreateKernel(program, "mykernel", NULL);
clSetKernelArg(kernel1, 0, &buff1);
clSetKernelArg(kernel1, 1, &buff2);

另一个将是:

kernel2 = clCreateKernel(program, "mykernel", NULL);
clSetKernelArg(kernel2, 0, &buff2);
clSetKernelArg(kernel2, 1, &buff1);

这样,您不需要每次迭代都停止执行。你可以简单地运行:

for(int it=0; it<iter; it++){
    clEnqueueNDRangeKernel(it%2 ? kernel1 : kernel2, ....);
}
clFinish(command);

这种方法肯定比更改内核args更好,更有效,更少API调用。此外,在某些系统上,由于API实施不佳,clSetKernelArgs()可能是阻塞调用。所以最好尽量避免使用它们。