6

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

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

4

2 回答 2

11

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

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

于 2012-06-14T21:01:00.227 回答
4

如上一个答案:不,您根本不需要交换缓冲区。

但是,我不同意提出的答案。该函数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);

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

于 2014-02-24T09:47:27.940 回答