Pointers 矢量指针在openCL中的工作原理

Pointers 矢量指针在openCL中的工作原理,pointers,vector,opencl,Pointers,Vector,Opencl,我正在编写一个示例程序,将RGB图像转换为灰度图像。因此,图像作为一维数组从主机复制到设备,在我的代码中称为imgIn。由于imgIn是RGB图像,每个像素由3个无符号字符分量(R、G和B)组成。由于输出(imgOut)是灰度图像,因此它仅由一个通道(亮度)组成。守则如下: __kernel void rgbToGray(__global const uchar* restrict imgIn, __global uchar* restrict

我正在编写一个示例程序,将RGB图像转换为灰度图像。因此,图像作为一维数组从主机复制到设备,在我的代码中称为imgIn。由于imgIn是RGB图像,每个像素由3个无符号字符分量(R、G和B)组成。由于输出(imgOut)是灰度图像,因此它仅由一个通道(亮度)组成。守则如下:

__kernel void rgbToGray(__global const uchar* restrict imgIn, 
                        __global uchar* restrict imgOut) {
    //Get two indexes of the work item
    int x = get_global_id(0);
    int y = get_global_id(1);
    //rgb average is luminosity
    //uchar3 channels = *(((__global uchar3 *) imgIn) + (x+640*y));
    uchar3 channels = *((__global uchar3 *) (imgIn+3*(x+640*y)));
    channels = channels/(uchar3)(3);
    imgOut[x+640*y] = channels.s0 + channels.s1 + channels.s2;
}
我想理解为什么uchar3通道的注释声明与未注释声明不同。当我将uchar指针移到正确的像素,然后将其转换为uchar3指针时,channels变量具有正确的值,并且我的输出图像是完美的。但是,当我将指针投射到uchar3上,然后将指针移到右边的像素上时(假设),我的图像有一个奇怪的图案,如下图所示

A
uchar3
(实际上,任何三分量向量类型)与相应类型的四分量向量具有相同的对齐方式和大小。所以一个
uchar3
实际上只是一个
uchar4
,上面加了语法糖以防止您访问最后一个组件,它的大小仍然是4字节

那么你的第一句话呢

uchar3 channels = *(((__global uchar3 *) imgIn) + (x+640*y));
失败的原因是,当您使用
uchar3*
执行指针运算时,您最终会将4个字节增加到
(x+640*y)
,而您只想增加3个字节,因此每像素跳过一个字节,这会使您在屏幕截图中显示的结果失真

但是你的第二行

uchar3 channels = *((__global uchar3 *) (imgIn+3*(x+640*y)));
工作正常,因为您正在手动计算正确的偏移量,然后将偏移指针强制转换为
uchar3*
,这很好,可以获得正确的像素字节。然而,我认为如果
imgIn+3*(x+640*y)
没有与4字节边界对齐,那么它在技术上仍然是未定义的。如果我错了(这是很可能的),有人可以纠正我,但否则我建议要么一次将像素传递4个字节,并使用一个未使用的填充字节,要么手动将3个字节解压为
uchar3
,而无需通过指针重新解释转换(编辑:或者,更确切地说,按照prunge的建议,使用
vload3
,忘了那个)


我的建议是对作为内核输入和输出的三个组件向量说“不”。您可以在内核中使用它们,但将它们视为字面
uchar[3]
类型会让人感到困惑。

根据规范中的一节:

对于三分量矢量数据类型,数据类型的大小为4*sizeof(分量)。这意味着三分量矢量数据类型将与4*sizeof(分量)对齐vload3和vstore3内置函数可分别用于从压缩标量数据类型数组中读取和写入3分量矢量数据类型

如果您需要读取三分量向量值,请使用。此文档明确说明它将仅从内存中读取三个值:

vload3和vload_half3将x、y、z分量从地址(p+(偏移量*3))读入一个三分量向量

因此,类似这样的方法应该有效:

uchar3 channels = vload3(x + 640 * y, imgIn);

向上投票,忘记了
vload3
(如果您不介意的话,也将其添加到我的答案中)vload3仅在您的数据偏移量(字节)可被3整除时才起作用。