1

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

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

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

4

2 回答 2

3

这是一个起点。从这里您可以进行缓存预加载、循环展开等。当涉及更多 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
于 2013-10-29T01:51:24.003 回答
1

(促进我的评论回答)

在 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)

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

于 2013-10-29T05:09:34.893 回答