OpenCL图像直方图

OpenCL图像直方图,opencl,gpgpu,gpu,Opencl,Gpgpu,Gpu,我试图在OpenCL中编写一个直方图内核,以计算RGBA32F输入图像的256位R、G和B直方图。我的内核如下所示: const sampler_t mSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP| CLK_FILTER_NEAREST; __kernel void computeHistogram(read_onl

我试图在OpenCL中编写一个直方图内核,以计算RGBA32F输入图像的256位R、G和B直方图。我的内核如下所示:

const sampler_t mSampler = CLK_NORMALIZED_COORDS_FALSE |
                           CLK_ADDRESS_CLAMP|
                           CLK_FILTER_NEAREST;


__kernel void computeHistogram(read_only image2d_t input, __global int* rOutput,
                               __global int* gOutput, __global int* bOutput)
{

    int2 coords = {get_global_id(0), get_global_id(1)};

    float4 sample = read_imagef(input, mSampler, coords);

    uchar rbin = floor(sample.x * 255.0f);
    uchar gbin = floor(sample.y * 255.0f);
    uchar bbin = floor(sample.z * 255.0f);

    rOutput[rbin]++;
    gOutput[gbin]++;
    bOutput[bbin]++;


}
当我在2100 x 894图像(1877400像素)上运行它时,当我汇总每个通道的直方图值时,我倾向于只看到1870000个或大约1870000个总值。每次都是不同的数字。我确实预料到了这一点,因为偶尔两个内核可能会从输出数组中获取相同的值并对其进行递增,从而有效地取消了一个递增操作(我假设?)

1870000输出用于{1,1}工作组大小(如果我没有另外指定,这似乎是默认设置的)。如果我强制一个更大的工作组大小,比如{10,6},我在柱状图中得到的总数就会大大减少(与工作组大小的变化成比例)。这对我来说似乎很奇怪,但我猜发生的是,组中的所有工作项同时递增输出数组值,所以它只算作一个增量

无论如何,我在规范中读到OpenCL没有全局内存同步,只有使用本地内存的本地工作组内的同步。nVidia的直方图示例将直方图工作负载分解为一系列特定大小的子问题,计算它们的部分直方图,然后将结果合并为单个直方图。这似乎对任意大小的图像都不太管用。我想我可以用虚拟值填充图像数据

作为OpenCL的新手,我想我想知道是否有更直接的方法来实现这一点(因为它似乎应该是一个相对简单的GPU问题)


谢谢

是的,您正在同时从多个工作项写入共享内存,因此如果不以安全的方式进行更新(或者更糟,就是不这样做),您将丢失元素。组大小的增加实际上提高了计算设备的利用率,这反过来又增加了冲突的可能性。所以你最终会丢失更多的更新

但是,您似乎混淆了同步(排序线程执行顺序)和共享内存更新(通常需要原子操作或代码同步和内存屏障,以确保其他同步线程可以看到内存更新)

synchronization+屏障对您的情况不是特别有用(正如您所指出的,全局同步无论如何都不可用。原因是,两个线程组可能永远不会同时运行,因此尝试同步它们是毫无意义的)。通常在所有线程开始生成公共数据集,然后所有线程都开始使用不同的访问模式使用该数据集时使用


在您的情况下,您可以使用原子操作(例如atom_inc,请参阅)。但是,请注意,更新高度竞争的内存地址(例如,因为有数千个线程试图全部写入256个整数)可能会产生较差的性能。所有典型的直方图代码都在那里,以减少直方图数据的争用

如前所述,您将非同步且非原子地写入共享内存。这会导致错误。如果图片足够大,我有一个建议:

将您的工作组拆分为一个用于列或行的一维工作组。使用每个内核对列或列的直方图求和,然后使用atomic atom_inc.对其进行全局求和。这样可以在私有内存中进行最多的求和,速度更快,并减少原子运算

如果你在两个维度上工作,你可以在图片的一部分上完成

[编辑:]

我想,我有一个更好的答案:;-)

看看:

它们有一个有趣的实现…

您可以查看

  • 直方图示例来自
  • OpenCL编程指南(ISBN-13:978-0-321-74964-2)第14章-图像直方图