ARM Neon:添加相邻两次以平均四个相邻像素

ARM Neon: adding adjacent twice to average four adjacent pixels

我有 4 条车道 d0、d1、d2、d3,我想平均四个相邻的车道:

d0[0] = (d0[0] + d0[1] + d0[2] + d0[3]) / 4
d0[1] = (d0[4] + d0[5] + d0[6] + d0[7]) / 4
d0[2] = (d1[0] + d1[1] + d1[2] + d1[3]) / 4 
...

下面的 Neon 代码是否正确?

vpaddl.u8 d0, d0
vpaddl.u8 d1, d1

vpaddl.u8 d2, d2
vpaddl.u8 d3, d3

vpadd.u16 d0, d0, d2
vshrn.u16 d0, q0, #2

如果是,有没有更快的方法?

编辑 1

上面的代码不正确。我想到了以下内容:

vpaddl.u8 d0, d0
vpaddl.u8 d1, d1
vpaddl.u8 d2, d2
vpaddl.u8 d3, d3
vuzp.u16 q0, q1
vadd.u16 q0, q0, q1
vshrn.u16 d0, q0, #2

这是有效的。这与 'Notlikethat' 接受的答案的第二个建议非常相似,但优化程度较低。

经过一段时间的 playing around,我想说在给定的限制下,您的一般方法可能与您将要获得的一样好。由于要同时处理超过 4 个寄存器的数据,and/or 有机会在算法的其他地方吸收重新排列向量的成本,结论可能会有所不同,但除此之外,可行的选择非常有限。

但是,您在第二轮缩减中忘记了 d1d3,并且第一轮可以简化为两条指令,因为与 vpaddvpaddl 确实有一个 Q-register 表格。解决这些问题的结果是:

vpaddl.u8 q0, q0
vpaddl.u8 q1, q1
vpadd.u16 d0, d0, d1
vpadd.u16 d1, d2, d3
vshrn.u16 d0, q0, #2

就纯指令数而言,可以通过进行部分转置然后直接累加两个成对减少来降低,因此:

vuzp.16 q0, q1
vpaddl.u8 q0, q0
vpadal.u8 q0, q1
vshrn.u16 d0, q0, #2

但是 Q-form vuzp 真的 在我能找到的所有指令时序上都很昂贵,而且 vpadal 的累加也不是免费的,所以这几乎肯定最终会比更直接的版本表现更差。