裁剪的高效霓虹灯实现

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;
   


这就是 ClippingNeon

中的实现方式
     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 的回答更加灵活和完整。

以上是关于裁剪的高效霓虹灯实现的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 小技巧之霓虹灯文本的「故障」效果的实现

七彩霓虹灯能够实现两种效果(更新版本号2)

组装armv7霓虹灯电源功能

iOS SceneKit 霓虹灯

小5聊使用js+css+div布局方式画一棵圣诞树,带闪烁霓虹灯效果

前端例程20220818:边框跑马霓虹灯效按钮