运行长度编码 - SIMD

时间:2013-02-16 13:00:04

标签: arm jpeg simd neon run-length-encoding

我正在尝试优化游程编码。我在考虑在SIMD中实现它。我花了几个小时在算法上工作,但不能继续下去。是否值得一试?我正在做霓虹灯。

感谢。

1 个答案:

答案 0 :(得分:7)

我假设你的问题是在用JPEG编码的AC块系数中使用RLE。

在JPEG中使用的RLE变体是非常具体的。每个8×8像素的块用DCT变换并量化。然后,针对第一DC系数和63个AC系数分离DCT输出(64个系数)。使用Zig-Zag模式将8x8块AC coefs转换为线性阵列,然后使用RLE编码

ZigZag from wikimedia (File:JPEG_ZigZag.svg, by Alex Khristov, PD)

ZigZag通常与RLE运行相结合,因此我们使用非线性内存访问的RLE,并且应该优化这两种功能。

警告! JPEG中的RLE仅用于零元素!,请检查F.1.2.2.3标准的F.1.2.2.1,Figure F.2ISO/IEC 10918-1 : 1993

一些实现:

2010年至2011年,Linaro为ARM提供libjpeg-tubro(主页为libjpeg-turbo.org),其中一些分支是optimized

此fork中有list of optimizations

  
      
  • 10 - 对'forward_DCT'中的量化代码进行ARM NEON优化(用浮点乘法替换整数除法... ...此优化函数现在几乎比原始C变量快3倍 - jcdctmgr.c - Siarhei Siamashka 2010-11- 10
  •   
  • 9 - 针对'encode_one_block'的ARM程序集优化(针对'encode_one_block'的ARM程序集优化。比原始C变体快近2倍。) - jchuff.c - Siarhei Siamashka 2010-11-10 < / LI>   
  • 8 - ARM NEON优化版'rgb_ycc_convert' - Siarhei Siamashka 2010-11-10
  •   
  • 7 - ARM NEON优化版'ycc_rgb_convert' - Siarhei Siamashka 2010-11-10
  •   
  • 6 - 'convsamp'的小型ARM NEON优化 - Siarhei Siamashka 2010-11-10
  •   
  • 5 - ARM NEON优化版'jpeg_fdct_ifast' - Siarhei Siamashka 2010-11-10
  •   
  • 4 - ARM NEON优化版'jpeg_idct_ifast' - Siarhei Siamashka 2010-11-10
  •   
  • 3 - ARM NEON优化版'jpeg_idct_4x4' - Siarhei Siamashka 2010-11-10
  •   

Revision 9jchuff.c文件的ARM优化,用于函数encode_one_block,它对块的AC和DC组件进行编码;但它没有使用NEON

/* Encode a single block's worth of coefficients */
LOCAL(boolean)   encode_one_block 

事实上,RLE并未优化;但是ZigZag和last zero coef检测是在find_last_nonzero_index辅助函数的ARM程序集中实现的。 (它是使用ruby generator)或in linaro git生成的。它被安排用于双重问题Cortex-A8:

* Find last nonzero coefficient and produce output in natural order,
* instructions are scheduled to make use of ARM Cortex-A8 dual-issue
* capability

这是函数的相应C代码:

LOCAL(int)
find_last_nonzero_index (JCOEFPTR block, JCOEFPTR out)
{
  int tmp, i, n = 0;
  for (i = 1; i < DCTSIZE2; i++) {
    if ((tmp = block[jpeg_natural_order[i]]) != 0)
      n = i;
    out[i] = tmp;
}
return n;

这里有RLE本身的ARM或NEON优化,但我认为这个asm代码有助于RLE,将其转换为线性内存访问版本(encode_one_block下的ifdef __arm__):

  for (k = 2; k <= last_nonzero_index; k += 2) {
      innerloop(k);
  }
r宏中使用的

innerloop是RLE计数器。

这种带有手动编码ZigZag(用于Cortex-A8)的线性RLE应该比原始C版本更快,即使对于Cortex-A9也是如此。感谢Siarhei Siamashka!

PS:当前版本的libjpeg-turbo在此RLE中没有arm优化:encode_one_block, Line 454 of jchuff.c, rev929 - innerloop被略微改写为kloop,但RLE仍以非线性方式完成;之字形没有与它分开。

关于NEON的一些想法

NEON有32个寄存器,每个64位宽(D0..D31;根据Anderson @ ELC 2011,page 5),理论上可以用来存储64位16位系数和实现ZigZag + RLE。仍在寻找实施......

在MPEG标准中有类似的Zig-zag + RLE,并且为x86和arm做了一些SIMD实现的努力。有blog post in x264dev;使用SSSE3为x86实现了8x8 zigzag x264_zigzag_scan_8x8_frame。但对于ARM,x264中只有4x4 NEON zigzag

PS:只为我和任何不了解Jpeg内幕的人。在Cardiff CM0340 lecture slides中有一些简短易懂的JPEG编码介绍。

PPS(2013年2月18日更新,13:30):为了优化RLE编码,我们可以在AC系数中间进行预扫描搜索零,然后使用这个预先计算的数据。我们甚至可以将它保存为半字节或一些NEON寄存器中的位

更新2月18日:补丁作者说,对提交9的评论是不准确的。当这个代码与jpeg6b进行比较时,有2倍的改进,而不是libjpeg-turbo。他说,展开63(如在libjpeg-tubro中)与这个asm解决方案的速度几乎相同(在某些测试中,它在其他情况下略胜一筹)。