pixel_avg2_w20_neon x264像素宽度为20的均值计算

一 C语言实现

static inline void pixel_avg2_w20_altivec(uint8_t *dst, intptr_t i_dst,

uint8_t *src1, intptr_t i_src1,

uint8_t *src2, int i_height)

{

    pixel_avg2_w16_altivec(dst, idst, src1, i_src1, src2, i_height); //前面16列

    pixel_avg2_w4_altivec(dst + 16, i_dst, src1 + 16, i_src1, src2 + 16, i_height); //后面4列

}  

static inline void pixel_avg2_w16_altivec(uint8_t *dst, intptr_t i_dst,

uint8_t *src1, intptr_t i_src1, 

uint8_t *src2, int i_height)

{

    vec_u8_t src1v, src2v;

    for (int y = 0; y < i_height; y++)

    {

        src1v = vec_vsx_ld(0, src1);

        src2v = vec_vsx_ld(0, src2);

        src1v = vec_avg(src1v, srcv2);

        vec_st(src1v, 0, dst);

        dst += i_dst;

        src1 += i_src1;

        src2 += i_src1; 

    }

}

static inline void pixel_avg2_w4_altivec(uint8_t *dst, intptr_t i_dst,

uint8_t *src1, intptr_t i_src1,

uint8_t *src2, int i_height)

{

    for (int y = 0; y < i_height; y++)

    {

        for (int x = 0; x < 4; x++)

            dst[x] = (src1[x] + src2[x] + 1) >> 1;

        dst += i_dst;

        src1 += i_src1;

        src2 += i_src1;

     }

}

二 汇编实现

function pixel_avg2_w20_neon

    ldr ip, [sp, #4]

    push {lr}

    sub r1, r1, #16

    ldr lr, [sp, #4]

i_height

src2

sp开始的位置,sp + 4就是i_height

push {lr}

lr寄存器在此,sp + 4 就是 src2

function pixel_avg2_w20_neon

    ldr         ip,  [sp, #4] //取参数 height 到 ip

    push        {lr} //push lr到栈上,sp寄存器,也减小了 - 4

    sub         r1,  r1,  #16 //r1 = r1 - 16

    ldr         lr,  [sp, #4] //src2 载入到 lr寄存器 

avg2_w20_loop:

    subs        ip,  ip,  #2 //ip = ip - 2

    vld1.64     {d0-d2},  [r2], r3 //先从r2(src1)处加载 24字节   d0 d1 d2

    vld1.64     {d4-d6},  [lr], r3 //先从lr(dst)处加载 24字节   d4 d5 d6

    vrhadd.u8   q0,  q0,  q2  //q0 = (q0 + q2 + 1) >> 1  这里 q0 = d0 d1  q2 = d4 d4

    //因此上面这句话的意思是, d0 = d0 + d4 , d1 = d1 + d5  这里计算了128也就是16字节

    vrhadd.u8   d2,  d2,  d6  //d2 = (d2 + d6 + 1) >> 1

    //上面这句话,是末尾还有8个字节的计算。 d2 = d2 + d6

    vld1.64     {d4-d6},  [r2], r3 //载入数据 d4 d5 d6 再次读入数据

    vld1.64     {d16-d18},[lr], r3 //载入数据 d16 d17 d18 再次读入数据

    vrhadd.u8   q2,  q2,  q8 //q2 = (q2 + q8 + 1) >> 1

    //和上面操作类似, q2 = d4 d5, q8 = d16 d17 16个字节相加

    vst1.64     {d0-d1},  [r0,:128]! //d0 d1 -> 存储到 r0, 128bits  存储回去128bits

    vrhadd.u8   d6,  d6,  d18 // d6 = (d6 + d18 + 1) >> 1 剩余的8字节相加 

    vst1.32     {d2[0]},  [r0,:32], r1 //vst1.32 {d2[0]}, [r0,:32], r1 指令表示将寄存器  存储回去

    //d2 中的数据的低 32 位存储到内存地址 [r0 + r1] 处。这里的 r0 是存储地址的基址,r1 是偏移量,表示存储地址的偏移量

    //vst1.32 {d2[1]}, [r0,:32], r1 的意思是将寄存器 d2 中的数据的高 32 位存储到内存地址 

    // [r0 + r1] 处。这里的 r0 是存储地址的基址,r1 是偏移量,表示存储地址的偏移量。

    vst1.64     {d4-d5},  [r0,:128]! //d4 d5 ->存储到 r0 刚才后面一组的计算结果 d4 d5存储回去

    vst1.32     {d6[0]},  [r0,:32], r1 //d6[0] 低 32位 存储到 r0的位置 最后计算的结果d6存储回去 

    //以上一次计算了2行的数据,所以 ip = ip - 2,每次减少两行,再循环

    bgt         avg2_w20_loop

    pop         {pc} //弹出 lr到pc上。

endfunc