有效地矢量化图像块处理?
Posted
技术标签:
【中文标题】有效地矢量化图像块处理?【英文标题】:Vectorise image block processing efficiently? 【发布时间】:2016-10-10 19:49:54 【问题描述】:我很好奇当我逐块处理图像时最有效的方法是什么。
那时,我应用了一些矢量化技术,例如从 8x8 块中读取一行像素(每行 8 个像素,每个 8 位深度)。但由于现代处理器支持 128/256 位矢量运算,我认为从图像块中加载两行像素可以提高代码速度。
但问题是,内存中的图像(例如 16x16 图像,包含 4 个 8x8 块)从第一个像素到最后一个像素连续存储。 1行8像素的加载很简单,但是应该如何操作指针或者对齐图片数据才能一起加载2行呢?
我觉得这个图可以清楚地说明我的问题: pixels' address in a image
因此,当我们一起加载 8 个像素(一行)时,我们只需通过 1 条指令从初始指针位置加载 8 字节数据。当我们加载第二行时,我们只需将 9 添加到指针并加载第二行。
那么,问题是,有没有什么方法可以从初始指针位置加载这两行(16 像素)?
谢谢!
【问题讨论】:
当您说 "load" 时,您的意思是从文件中读取吗?还是从 RAM 中放入 CPU 寄存器? 我的意思是把数据从 RAM 放到 CPU 寄存器中 【参考方案1】:要使每行对齐,您可以填充每行的末尾。编写代码以支持比行间距更短的图像宽度,让您的算法可以处理图像的子集。
此外,您实际上并不需要对齐所有内容才能使 SIMD 正常工作。连续就足够了。大多数 SIMD 指令集(SSE、NEON 等)都有未对齐的加载指令。根据具体的实现,可能不会有太多的惩罚。
您不会将两个不同的行加载到同一个 SIMD 向量中。例如,要使用 AVX2 VPSADBW 进行 8x8 SAD(绝对差之和),每个 32 字节加载将从四个不同 8x8 块的一行中获取数据。但这很好,您只需使用它来并行生成四个 8x8 SAD 结果,而不是浪费大量时间改组来执行单个 8x8 SAD。
例如,Intel's MPSADBW tutorial 展示了如何使用 C 和 Intel 的 SSE 内在函数实现对 4x4、8x8 和 16x16 块的详尽运动搜索。显然,实际的 MPSADBW 指令实际上并不值得在实践中使用,因为它比 PSADBW 慢,并且您可以通过 x264 使用的顺序消除穷举搜索更快地获得相同的结果(x264 开发人员在this forum thread about 中提到过) SSE4.1 是否会帮助 x264。)
Dark Shikari 博客档案中的一些 SIMD 编程博客文章:Diary Of An x264 Developer:
Cacheline splits, take two:使用 ALIGNR 或其他技术为运动搜索设置未对齐的输入 A curious SIMD assembly challenge: the zigzag【讨论】:
但是即使我们在每一行的末尾填充零,我也不明白如何将两行一起加载到一个块中?我猜未对齐的加载指令无助于在一条指令中加载两行? 你想设置编译器为你向量化它的代码吗?还是自己辛苦?如果编译器获得相同的结果,并且如果/当您使用新的 AVX 或其他架构时,则后面没有任何优势,那么您需要再次“手动执行”。所有 #pragma 的东西通常可以让编译器对其进行排序,这取决于它如何处理指针和连续访问。 @drinking:您从多个块加载同一行,并并行处理多个块,因此您不需要这样做。请参阅我的更新答案。 @PeterCordes:是的。更新对我来说很有意义。在您的更新中,我们并行计算左侧 8x8 块和右侧 8x8 块。 @PeterCordes:很抱歉上次的评论,我没有完成它,提交后似乎无法编辑它......感谢您的回答。更新对我来说很有意义。但是如果图像处理中的搜索窗口没有那么大呢?例如,在 14x14 图像搜索窗口中搜索 8x8 块在实践中很常见。 14x14 的搜索窗口甚至不允许我们从 2 个块中加载同一行。以上是关于有效地矢量化图像块处理?的主要内容,如果未能解决你的问题,请参考以下文章