图像如何在opencl内核中运行?

Dr.*_*all 3 c c++ gpgpu opencl

我正在尝试找到在opencl中从主机到设备复制多维数组的方法,并认为一种方法是使用图像......可以是1,2或3维对象.但是我很困惑,因为当从数组中读取像素时,它们使用的是矢量数据类型.通常我会想到双指针,但听起来不像是矢量数据类型的含义.无论如何这里是我的问题:

1)矢量数据类型实际上是什么意思,为什么我们不能在表示像素坐标时指定2或3个索引?它看起来像一个单独的值,如float2用于表示坐标,但这对我没有意义.我正在看函数read_imageui和read_image.

2)输入图像可以只是整个图像的子集,而采样器是输入图像的子集吗?我不明白这里是如何实际指定坐标的,因为read_image()只接缝为输入采用单个值而采样器采用单个值.

3)如果做线性代数,我应该咬紧牙关并将缓冲区中的1-D数组数据转换为opencl中的多维数组吗?

4)我仍然对图像感兴趣,所以即使我想做的事情不是最适合图像,你还能解释问题1和2吗?

谢谢!

编辑 我想改进我的问题并询问,在下面的khronos文档中他们定义...

 int4 read_imagei (
    image2d_t image,
    sampler_t sampler,
    int2 coord)
Run Code Online (Sandbox Code Playgroud)

但是我无处可以找到image2d_t的定义或结构.sampler_t和int2 coord的相同内容.它们似乎是对我的结构或指向结构的指针,因为opencl应该基于ansi c,但是这些结构的字段是什么,或者我如何注意看起来像scala的坐标?!我已经看过符号(int2)(x,y),但这不是ansi c,看起来像scala,哈哈.事情似乎与我相互矛盾.再次感谢!

Tho*_*mas 8

通常,您可以通过三种不同的方式从图像中读取:

  1. 直接像素访问,无采样

  2. 采样,归一化坐标

  3. 采样,整数坐标

第一个是你想要的,也就是说,你传递整数像素坐标,如(10,43),它将返回该点的图像内容,没有任何过滤,就好像它是一个内存缓冲区.您可以使用read_image*()不带sampler_t参数的函数族.

第二个是大多数人想要的图像,你指定0到1之间的标准化图像坐标,返回值是指定点的插值图像颜色(所以如果你的坐标指定像素之间的点,颜色是插值的基于周围的像素颜色).插值和处理越界坐标的方式由sampler_t传递给函数的参数的配置定义.

第三个与第二个相同,除了纹理坐标没有标准化,并且需要相应地配置采样器.在某种意义上,第三种方式更接近第一种方式,它提供的唯一附加功能是能够处理越界像素坐标(例如,通过包裹或夹紧它们),而不是手动操作.

最后,不同版本的每个功能,例如read_imagef,read_imagei,read_imageui,根据您的图像的像素格式使用.如果它包含浮点数(在每个通道中),请使用read_imagef,如果它包含有符号整数(在每个通道中),请使用read_imagei等...

另一方面,写入图像很简单,有一些write_image{f,i,ui}()函数可以获取图像对象,整数像素坐标和像素颜色,这一切都非常简单.

请注意,您无法在同一内核中读取和写入同一图像!(我不知道最近的OpenCL版本是否已经改变了).一般情况下,如果您不打算将图像用作实际图像(即您采样的输入纹理或输出在内核末端只写一次的纹理),我建议使用缓冲区.


关于image2d_t,sampler_t类型,它们是OpenCL"伪对象",您可以从C传递到内核(它们是保留类型).您将图像或采样器从C端发送到clSetKernelArg,并且内核在内核的参数列表中返回sampler_t或image2d_t(就像传入缓冲区对象并获取指针一样).对象本身不能在内核中进行有意义的操作,它们只是可以发送到read_image/write_image函数的句柄,以及其他一些函数.


至于图像和缓冲区之间的"实际"低级别差异,GPU通常具有专门保留的纹理存储器,该存储器针对"经常读取,一次写入"访问模式进行了高度优化,具有特殊纹理采样硬件和纹理缓存以优化分散读取, mipmap等.

在CPU上,图像和缓冲区之间可能没有底层差异,并且您的运行时可能在实施图像语义时同时实现为内存阵列.