裁剪的高效霓虹灯实现
Posted
技术标签:
【中文标题】裁剪的高效霓虹灯实现【英文标题】:Efficient Neon Implementation Of Clipping 【发布时间】:2012-07-17 06:12:53 【问题描述】:在一个循环中,我必须实现一种 剪辑
if ( isLast )
val = ( val < 0 ) ? 0 : val;
val = ( val > 255 ) ? 255 : val;
但是,这种“剪辑”几乎占用了 Neon 中循环的 一半执行时间。 这就是整个循环的样子-
for (row = 0; row < height; row++)
for (col = 0; col < width; col++)
Int sum;
//...Calculate the sum
Short val = ( sum + offset ) >> shift;
if ( isLast )
val = ( val < 0 ) ? 0 : val;
val = ( val > 255 ) ? 255 : val;
dst[col] = val;
这就是 Clipping 在 Neon
中的实现方式 cmp %10,#1 //if(isLast)
bne 3f
vmov.i32 %4, d4[0] //put val in %4
cmp %4,#0 //if( val < 0 )
blt 4f
b 5f
4:
mov %4,#0
vmov.i32 d4[0],%4
5:
cmp %4,%11 //if( val > maxVal )
bgt 6f
b 3f
6:
mov %4,%11
vmov.i32 d4[0],%4
3:
这是变量到寄存器的映射-
isLast- %10
maxVal- %11
有什么建议可以让它更快吗? 谢谢
编辑-
现在剪辑看起来像-
"cmp %10,#1 \n\t"//if(isLast)
"bne 3f \n\t"
"vmin.s32 d4,d4,d13 \n\t"
"vmax.s32 d4,d4,d12 \n\t"
"3: \n\t"
//d13 contains maxVal(255)
//d12 contains 0
这部分代码消耗的时间从 223ms 减少到 18ms
【问题讨论】:
您可以考虑消除循环中的条件分支。例如,如果“isLast”在循环中没有改变,您可以总是剪辑到 (lo,hi),其中 (lo,hi) 是预先设置的 - (0,255) 当 isLast 时,并且(-0x80000000,0x7FFFFFFF) 否则。 【参考方案1】:对 NEON 使用普通比较几乎总是一个坏主意,因为它会将 NEON 寄存器的内容强制写入通用 ARM 寄存器,这会花费很多周期。
您可以使用 vmin 和 vmax NEON 指令。这是一个将整数数组限制为任何最小值/最大值的小示例。
void clampArray (int minimum,
int maximum,
int * input,
int * output,
int numElements)
// get two NEON values with your minimum and maximum in each lane:
int32x2_t lower = vdup_n_s32 (minimum);
int32x2_t higher = vdup_n_s32 (maximum);
int i;
for (i=0; i<numElements; i+=2)
// load two integers
int32x2_t x = vld1_s32 (&input[i]);
// clamp against maximum:
x = vmin_s32 (x, higher);
// clamp against minimum
x = vmax_s32 (x, lower);
// store two integers
vst1_s32 (&output[i], x);
警告:此代码假定 numElements 始终是 2 的倍数,我尚未对其进行测试。
如果您使用 vminq / vmaxq 指令一次处理四个元素并在每次迭代中加载/存储四个整数,您甚至可以加快速度。
【讨论】:
嗯,这将开销从 200 毫秒减少到 18 毫秒。谢谢!【参考方案2】:如果 maxVal 是 UCHAR_MAX、CHAR_MAX、SHORT_MAX 或 USHORT_MAX,您可以简单地使用 neon 通过饱和转换将 int 转换为所需的数据类型。
举例
// Will convert four int32 values to signed short values, with saturation.
int16x4_t vqmovn_s32 (int32x4_t)
// Converts signed short to unsgigned char, with saturation
uint8x8_t vqmovun_s16 (int16x8_t)
如果您不想使用多数据功能,您仍然可以使用这些指令,只需加载和读取其中一条通道即可。
【讨论】:
好的解决方案 - 另见vmax(q)_xxx
/vmin(q)_xxx
。
maxVal 是 255。我们能以某种方式使用 vqshrn 吗?
您可以链接两个强制转换操作:vqmovun_s16(vqmovn_s32( ... ))。但 Nils 的回答更加灵活和完整。以上是关于裁剪的高效霓虹灯实现的主要内容,如果未能解决你的问题,请参考以下文章