1

我最近一直在摆弄 OpenCL,我遇到了一个严重的限制:你不能将指针数组传递给内核。这使得将任意大小的图像列表传递给内核变得很困难。我对此有一些想法,我想知道是否有人可以确定他们是否会工作,或者提供更好的建议。

假设您有 x 个想要传递给内核的图像对象。如果它们都是 2D 的,一种解决方案可能是将它们全部打包成 3D 图像,然后只索引切片。这样做的问题是,如果图像大小不同,则会浪费空间,因为 3D 图像必须具有最宽图像的宽度、最高图像的高度,而深度将是图像的数量。

但是,我也在想,当您将缓冲区对象传递给内核时,它会作为指针出现在内核中。如果您有一个内核采用任意数据缓冲区,并且指定一个缓冲区仅用于存储指针,然后将指向第一个缓冲区的指针附加到第二个缓冲区的末尾,(当然前提是有足够的分配空间)那么也许您可以保留指向设备上其他缓冲区的指针缓冲区。然后可以将此缓冲区传递给其他内核,然后通过一些有趣的转换,这些内核将能够访问设备上的这些任意缓冲区。唯一的问题是给定的缓冲区指针在缓冲区的整个生命周期中是否保持不变。此外,当您传递图像时,您会得到一个结构作为参数。现在,这个结构实际上在设备内存中有一个家吗?或者它是否足够长以传递给内核?这些事情很重要,因为它们将确定指针缓冲区技巧是否也适用于图像,假设它完全可以工作。

有人知道缓冲技巧是否有效吗?有没有其他人可以想到将任意大小的列表传递给内核的方法?

编辑:缓冲技巧不起作用。我已经测试过了。我不确定为什么,但设备上的指针似乎从一次调用到另一次调用并不相同。

4

2 回答 2

1

将指针数组传递给内核没有意义,因为指针将指向主机内存,而 OpenCL 设备对此一无所知。您必须将数据传输到设备缓冲区,然后将缓冲区指针传递给内核。(映射/固定内存有一些更复杂的选项,尤其是在 APU 的情况下,但它们不会改变主要事实,即主机指针在设备上无效)。

我可以建议一种方法,尽管我自己从未真正使用过它。如果您预先分配了一个大的设备缓冲区,您可以用主机背靠背的图像填充它。然后使用缓冲区和偏移列表作为参数调用内核。

于 2012-08-21T19:30:13.553 回答
0

这很容易,我已经做到了。您不使用指针,而是使用引用,并且您这样做。在您的内核中,您可以提供两个参数:

kernel void(
   global float *rowoffsets,
   global float *data
) {

现在,在您的主机中,您只需获取 2d 数据,将其复制到 1d 数组中,然后将每行开头的索引放入rowoffsets

对于最后一行,您添加了一个额外的行偏移,指向数据末尾之后的一个。

然后在您的内核中,要从一行中读取数据,您可以执行以下操作:

kernel void(
   global float *rowoffsets,
   global float *data,
   const int N
) {
    for( int n = 0; n < N; n++ ) {
        const int rowoffset = rowoffsets[n];
        const int rowlen = rowoffsets[n+1] - rowoffset;
        for( int col = 0; col < rowlen; col++ ) {
            // do stuff with data[rowoffset + col] here
        }
    }
}

显然,如何将数据实际分配给每个工作项取决于您,因此无论您是使用实际循环,还是为每个工作项提供单行和列,都是您自己的应用程序设计的一部分。

于 2013-01-23T02:58:17.513 回答