【问题标题】:Neon optimization of interlaced YUYV to gray隔行扫描 YUYV 到灰度的霓虹灯优化
【发布时间】:2013-10-28 19:30:28
【问题描述】:

我有以下将隔行扫描网络摄像头 YUYV 转换为灰色的 C 代码:

void convert_yuyv_to_y(const void *src, char *dest) {
    int x, y;
    char *Y, *gray;
    //get only Y component for grayscale from (Y1)(U1,2)(Y2)(V1,2)
    for (y = 0; y < CAM_HEIGHT; y++) {
        Y = src + (CAM_WIDTH * 2 * y);
        gray = dest + (CAM_WIDTH * y);
        for (x=0; x < CAM_WIDTH; x += 2) {
            gray[x] = *Y;
            Y += 2;
            gray[x + 1] = *Y;
            Y += 2;
        }
    }
}

有没有办法通过一些霓虹灯指令来优化这样的功能?

【问题讨论】:

  • 您是否有一个基准框架,以便您可以衡量任何更改的好处?
  • 基本方法:一次交错读取2个寄存器,只存储一个:vld2.8 { d0, d1}, [r0]!; vst1.8 d0, [r1]!;高级的东西:对齐到 16 个字节,使用多个单独的路径,确保这些路径不会从相同的缓存行竞争,使用多个线程。
  • @Aki Suihkonen:您能否总结一下您的基本方法的答案,包括一些代码?
  • 你也可以通过 gcc 使用 "-Wall -mfpu=neon -ftree-vectorize -ftree-vectorizer-verbose=8 -O2 -c" 来编译它。
  • 我还将删除code.google.com/p/libyuv 作为另一个参考。

标签: c image-processing arm neon


【解决方案1】:

这是一个起点。从这里您可以进行缓存预加载、循环展开等。当涉及更多 NEON 寄存器以防止数据停顿时,性能最佳。

 .equ CAM_HEIGHT, 480 @ fill in the correct values
 .equ CAM_WIDTH,  640

@
@ Call from C as convert_yuyv_to_y(const void *src, char *dest);
@
convert_yuyv_to_y:
  mov r2,#CAM_HEIGHT  
cvtyuyv_top_y:
  mov r3,#CAM_WIDTH
cvtyuyv_top_x:
  vld2.8 {d0,d1},[r0]!   @ assumes source width is a multiple of 8
  vst1.8 {d0},[r1]!      @ work with 8 pixels at a time
  subs r3,r3,#8          @ x+=8
  bgt cvtyuyv_top_x
  subs r2,r2,#1          @ y++
  bgt cvtyuyv_top_y
  bx lr

【讨论】:

  • (+1) 我认为应该是“subs r2,r2,#2”,OP 提到 interlaced 并且 Y 计算为 (CAM_WIDTH * 2 * y).
  • subs r2,r2,#1 是正确的。它正在读取 16 字节的 YUYV 并存储 8 字节的 Y。在垂直轴(r2 计数器)中,没有隔行扫描。
【解决方案2】:

(促进我的评论回答)

NEON 架构中对数据进行解交织的最少指令可通过以下顺序实现:

vld2.8 { d0, d1 }, [r0]!
vst1.8 { d0 }, [r1]!

这里r0是源指针,每次前进16,r1是目的指针,每次前进8。

循环展开、检索多达 4 个寄存器并将寄存器偏移 2 的能力可以提供稍大的最大吞吐量。再加上16字节对齐:

start:
vld4.8 { d0, d1, d2, d3 }, [r0:256]
subs r3, r3, #1
vld4.8 { d4, d5, d6, d7 }, [r1:256]
add r0, r0, #64
add r1, r0, #64
vst2.8 { d0, d2 }, [r2:256]!
vst2.8 { d4, d6 }, [r2:128]!
bgt start

(我不记得vstx.y {regs}, [rx, ro] 的格式是否存在——这里的 ro 是偏移寄存器,后递增 rx)

虽然内存传输优化很有用,但最好还是考虑一下,如果它可以一起跳过,或者与一些计算合并。这也是考虑平面像素格式的地方,可以完全避免复制任务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-01
    • 2016-01-30
    • 2014-07-30
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    • 2015-02-14
    相关资源
    最近更新 更多