FFmpeg H.265解碼器亮度四分之一像素插值ARM NEON代碼閱讀

//預取pld , load做8次, 但是實際pld的使用不應該如此頻繁,因爲文檔裏說pld的作用是從內存裏提前預取數據,提前多久呢,in the near future(如此隱晦又美好)
//每次的vld1.8    {d16}, [r2], r3  代表從r2寄存器(裏面是src),load出8個8位的數到d16裏,然後r2尋址到r2+r3 (r3 is srcstride)
.macro loadin8
        pld       [r2]
        vld1.8    {d16}, [r2], r3
        pld       [r2]
        vld1.8    {d17}, [r2], r3
        pld       [r2]
        vld1.8    {d18}, [r2], r3
        pld       [r2]
        vld1.8    {d19}, [r2], r3
        pld       [r2]
        vld1.8    {d20}, [r2], r3
        pld       [r2]
        vld1.8    {d21}, [r2], r3
        pld       [r2]
        vld1.8    {d22}, [r2], r3
        pld       [r2]
        vld1.8    {d23}, [r2], r3
.endm
//水平差值,vext指令是個很雞賊的指令
.macro vextin8
        pld       [r2]
        vld1.8    {q11}, [r2], r3
        vext.8    d16, d22, d23, #1
        vext.8    d17, d22, d23, #2
        vext.8    d18, d22, d23, #3
        vext.8    d19, d22, d23, #4
        vext.8    d20, d22, d23, #5
        vext.8    d21, d22, d23, #6
        vext.8    d22, d22, d23, #7
.endm

具體到像素,就是左邊的像素在d22的低位

注意;第一個0每次的vext都取不到,所以,sub r2, #4 (亮度插值的範圍是從當前正像素開始的 -3到4)

d16 d17 d18 d19 d20 d21 d22 d23裏面對應存了插值所用的整像素。

.macro  hevc_put_qpel_uw_vX_neon_8 filter
        push   {r4-r10} //寄存器入棧,等着被用
        ldr    r5, [sp, #28] // width 傳入參數的順序決定了每個變量的偏移量
        ldr    r4, [sp, #32] // height
        ldr    r8, [sp, #36] // src2
        ldr    r9, [sp, #40] // src2stride
        vpush {d8-d15}
        sub       r2, r2, r3, lsl #1
        sub       r2, r3 // r2 move up 3 lines to ensure the result of first MC result.
        mov       r12, r4
        mov       r6, r0
        mov       r7, r2
        cmp       r8, #0 //看看src2是不是0來判斷是不是bi模式預測
        bne       .Lbi\@
0:      loadin8          //load進來8個8bit像素到d16-d
        cmp       r5, #4
        beq       4f
8:      subs r4, #1      // height-1
        \filter           // filtering and store the result in q7
        vqrshrun.s16   d0, q7, #6   // when bitdepth = 8,a shift=6 process need to be applied to the filtered target.
        vst1.8    d0, [r0], r1 // store d0 to r0 with r1 stride (r0->dst)
        regshuffle_d8  // ==shuffle d16-d23. ???==相當於處理完當前像素後,處理下一個像素前,倒騰下寄存器,爲下一個像素的插值濾波做準備
        vld1.8    {d23}, [r2], r3 // load r2的下一個
        bne 8b // 處理了前8列的插值
        subs  r5, #8  // 處理後8列
        beq       99f  // 如果爲0代表已經處理完畢,結束。否則重新初始化 r4:height; r6:由src的地址跳8,r0重新指向沒有處理的新位置 ;
        // r7指向 向上偏移3行 再向右偏移8個像素位置
        mov r4, r12
        add r6, #8
        mov r0, r6
        add r7, #8
        mov r2, r7
        b     0b
4:      subs r4, #1
        \filter
        vqrshrun.s16   d0, q7, #6
        vst1.32    d0[0], [r0], r1 //如果還剩4列,則之用D寄存器的低地址,
        regshuffle_d8
        vld1.32    {d23[0]}, [r2], r3
        bne 4b
        b   99f
.Lbi\@: lsl       r9, #1
        mov       r10, r8
0:      loadin8
        cmp       r5, #4
        beq       4f
8:      subs r4, #1
        \filter
        vld1.16        {q0}, [r8], r9
        vqadd.s16      q0, q7
        vqrshrun.s16   d0, q0, #7
        vst1.8         d0, [r0], r1
        regshuffle_d8
        vld1.8    {d23}, [r2], r3
        bne 8b
        subs  r5, #8
        beq       99f
        mov r4, r12
        add r6, #8
        mov r0, r6
        add r10, #16
        mov r8, r10
        add r7, #8
        mov r2, r7
        b     0b
4:      subs r4, #1
        \filter
        vld1.16      d0, [r8], r9
        vqadd.s16    d0, d14
        vqrshrun.s16 d0, q0, #7
        vst1.32      d0[0], [r0], r1
        regshuffle_d8
        vld1.32    {d23[0]}, [r2], r3
        bne 4b
99:     vpop {d8-d15}
        pop {r4-r10}
        bx lr
.endm



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章