高效的霓虹灯实现剪辑

iaj*_*jnr 2 arm simd neon

在一个循环中,我必须实现一种裁剪

if ( isLast )
{
    val = ( val < 0 ) ? 0 : val;
    val = ( val > 255 ) ? 255 : val;        
}
Run Code Online (Sandbox Code Playgroud)

然而,这种"剪辑"几乎占用了霓虹灯循环执行时间的一半.这就是整个循环的样子 -

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;
   }

}
Run Code Online (Sandbox Code Playgroud)

这就是在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:  
Run Code Online (Sandbox Code Playgroud)

这是变量到寄存器的映射 -

isLast-    %10
maxVal-    %11
Run Code Online (Sandbox Code Playgroud)

有什么建议让它更快?谢谢

编辑-

剪辑现在看起来喜欢-

     "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
Run Code Online (Sandbox Code Playgroud)

这部分代码消耗的时间从223ms减少到18ms

Nil*_*nck 8

使用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);
  }
} 
Run Code Online (Sandbox Code Playgroud)

警告:此代码假定numElements始终是2的倍数,我还没有测试过它.

如果使用vminq/vmaxq指令一次处理四个元素并且每次迭代加载/存储四个整数,您甚至可以加快速度.

  • 很高兴你发布了基准测试结果.:-) (3认同)
  • 那么这将开销从200ms减少到18ms.谢谢! (2认同)