【发布时间】:2017-05-11 03:21:55
【问题描述】:
我是 GPU 计算的新手,所以这可能是一个非常幼稚的问题。
我做了一些查找,似乎在 GPU 上计算积分图像是一个不错的主意。
但是,当我真正深入研究它时,我想知道它可能并不比 CPU 快,尤其是对于大图像。所以我只想知道您对此的想法,以及 GPU 是否真的更快的一些解释。
所以,假设我们有一个 MxN 图像,积分图像的 CPU 计算大约需要 3xMxN 加法,即 O(MxN)。
在 GPU 上,按照《OpenGL 超级圣经》第 6 版提供的代码,需要一些 KxMxNxlog2(N) + KxMxNxlog2(M) 操作,其中 K 是大量移位、乘法、补充...
GPU 可以并行工作,例如,一次 32 个像素,具体取决于设备,但仍然是 O(MxNxlog2(M))。
我认为即使在 640x480 的常见分辨率下,CPU 仍然更快。
我错了吗?
[编辑] 这是直接来自书的着色器代码,想法是使用 2 遍:计算行的积分,然后计算第 1 遍的结果的列的积分。此着色器代码用于 1 遍。
#version 430 core
layout (local_size_x = 1024) in;
shared float shared_data[gl_WorkGroupSize.x * 2];
layout (binding = 0, r32f) readonly uniform image2D input_image;
layout (binding = 1, r32f) writeonly uniform image2D output_image;
void main(void)
{
uint id = gl_LocalInvocationID.x;
uint rd_id;
uint wr_id;
uint mask;
ivec2 P = ivec2(id * 2, gl_WorkGroupID.x);
const uint steps = uint(log2(gl_WorkGroupSize.x)) + 1;
uint step = 0;
shared_data[id * 2] = imageLoad(input_image, P).r;
shared_data[id * 2 + 1] = imageLoad(input_image,
P + ivec2(1, 0)).r;
barrier();
memoryBarrierShared();
for (step = 0; step < steps; step++)
{
mask = (1 << step) - 1;
rd_id = ((id >> step) << (step + 1)) + mask;
wr_id = rd_id + 1 + (id & mask);
shared_data[wr_id] += shared_data[rd_id];
barrier();
memoryBarrierShared();
}
imageStore(output_image, P.yx, vec4(shared_data[id * 2]));
imageStore(output_image, P.yx + ivec2(0, 1),
vec4(shared_data[id * 2 + 1]));
}
【问题讨论】:
-
试试看就知道了。
-
@InternetAussie 是的,我现在正在尝试。只是网上的研究表明GPU比CPU快得多,这让我很惊讶。
-
缺少并行算法的描述,但规定的界限似乎很糟糕。这让我觉得使用了理论方法,您可以在 1x1、1x2、2x2、2x4、4x4 零件上工作。也就是说,您递归地在更大的范围内工作,但只有很小的增量步骤。在实际代码中,您可能一次从 16x16 块开始。您甚至可以忽略并行化下一步,因为 16x16 块已经比输入像素少 256 倍
-
@MSalters 我添加了书中的代码,想法是计算行的积分,然后计算结果的列的积分。
-
@MSalters 我想我会试试你关于 16x16 块的建议,或者计算一些适合我情况的其他数字。谢谢
标签: c++ performance opengl image-processing gpgpu