OpenCL:如何正确链接内核

时间:2016-05-27 17:30:45

标签: opencl

好的,所以我有两个内核,它们都接受输入和输出图像并做一些有意义的操作:

#pragma OPENCL EXTENSION cl_khr_3d_image_writes : enable

kernel void Kernel1(read_only image3d_t input, write_only output)
{
    //read voxel and some surrounding voxels
    //perform some operation
    //write voxel
}


#pragma OPENCL EXTENSION cl_khr_3d_image_writes : enable

kernel void Kernel2(read_only image3d_t input, write_only output)
{
    //read voxel and some surrounding voxels
    //perform some other operation
    //write voxel
}


#pragma OPENCL EXTENSION cl_khr_3d_image_writes : enable

kernel void KernelCombined(read_only image3d_t input, write_only output)
{
    //read voxel and some surrounding voxels

    //...
    //perform operation of both kernels (without read, write)
    //...
    //write voxel
}

现在我想在某些情况下链接内核,所以我能做的就是首先调用Kernel 1然后调用Kernel2。但这意味着,我有不必要的写入和读取。我也可以写第三个内核同时执行这两个操作,但是维护复制粘贴代码似乎很烦人。根据我的知识,我无法将每个内核的内容放在单独的函数中,因为我无法传递image3d_t输入。

问题:有没有聪明的方法来链接这两个内核?也许OpenCL做了一些我不知道的聪明事情?

修改:添加了我想要实现的内容的示例。

3 个答案:

答案 0 :(得分:1)

据我所知,你不应该做任何特别的事情,即使使用OpenCL 1.2也行不通。

OpenCL命令队列默认为IN ORDER,不需要在内核调用之间传输数据。

只需将数据保留在设备上(不要执行map / unmap和Read / Write),将两个内核排入队列并等待它们完成。以下是它的外观代码摘要:

// Enqueue first kernel
clSetKernelArg(kernel1, 0, sizeof(cl_mem), in);
clSetKernelArg(kernel1, 1, sizeof(cl_mem), out);
clEnqueueNDRange(..., kernel1, ...);

// Enqueue second kernel
clSetKernelArg(kernel2, 0, sizeof(cl_mem), in);
clSetKernelArg(kernel2, 1, sizeof(cl_mem), out);
clEnqueueNDRange(..., kernel2, ...);

// Flush the queue and wait for the results
clFlush(...);  // Start the execution
clWait(...);   // Wait until all operations in the queue are done

当使用OOO(OUT OF ORDER)队列时,可以使用事件(参见clEnqueueNDRangeKernel中的最后3个参数)来指定内核之间的依赖关系,并在管道的末尾执行clWaitForEvents。 / p>

答案 1 :(得分:1)

我理解您的要求 - 您希望删除内核之间的图像写入/读取周期。使用您描述的内核,这不会有效。在现有的内核中,你“读取体素和一些周围的体素” - 让我们说这意味着读取7个体素。如果在内核2和3中执行相同的读取模式,则总共有21次读取(和3次写入)。如果以某种方式将这三个内核链接到编写单个输出体素的单个内核中,则需要从更多源体素中读取以获得相同的结果(因为每个读取步骤都添加了半径)。

内核写入/读取链接有用的场景将是单入/单出内核,例如图像处理,其中颜色独立于其邻居进行修改。为此,您需要更高级别的内核描述,以及可根据您的操作生成所需内核的内容。

答案 2 :(得分:0)

如果您使用的是支持opencl 2.0的设备,则可以使用此功能。 enqueue_kernel允许内核对另一个内核进行排队,就像主机上的EnqueueNDRange一样。

如果你正在使用opencl 1.2 - 可能都是1.x,你需要返回主机并调用下一个内核(或让下一个内核已经排队)。你不需要将缓冲区复制回内核之间的主机,所以至少你不需要多次支付转账费用。