//******************************************************************************
//*
//* Copyright (C) 2015 The Android Open Source Project
//*
//* Licensed under the Apache License, Version 2.0 (the "License");
//* you may not use this file except in compliance with the License.
//* You may obtain a copy of the License at:
//*
//* http://www.apache.org/licenses/LICENSE-2.0
//*
//* Unless required by applicable law or agreed to in writing, software
//* distributed under the License is distributed on an "AS IS" BASIS,
//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//* See the License for the specific language governing permissions and
//* limitations under the License.
//*
//*****************************************************************************
//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
//*/

///**
//******************************************************************************
//*
//* @brief :Evaluate best intra 16x16 mode (among VERT, HORZ and DC )
//*                and do the prediction.
//*
//* @par Description
//*   This function evaluates  first three 16x16 modes and compute corresponding sad
//*   and return the buffer predicted with best mode.
//*
//* @param[in] pu1_src
//*  UWORD8 pointer to the source
//*
//** @param[in] pu1_ngbr_pels_i16
//*  UWORD8 pointer to neighbouring pels
//*
//* @param[out] pu1_dst
//*  UWORD8 pointer to the destination
//*
//* @param[in] src_strd
//*  integer source stride
//*
//* @param[in] dst_strd
//*  integer destination stride
//*
//* @param[in] u4_n_avblty
//* availability of neighbouring pixels
//*
//* @param[in] u4_intra_mode
//* Pointer to the variable in which best mode is returned
//*
//* @param[in] pu4_sadmin
//* Pointer to the variable in which minimum sad is returned
//*
//* @param[in] u4_valid_intra_modes
//* Says what all modes are valid
//*
//*
//* @return      none
//*
//******************************************************************************
//*/
//
//void ih264e_evaluate_intra16x16_modes(UWORD8 *pu1_src,
//                                      UWORD8 *pu1_ngbr_pels_i16,
//                                      UWORD8 *pu1_dst,
//                                      UWORD32 src_strd,
//                                      UWORD32 dst_strd,
//                                      WORD32 u4_n_avblty,
//                                      UWORD32 *u4_intra_mode,
//                                      WORD32 *pu4_sadmin,
//                                       UWORD32 u4_valid_intra_modes)
//
.text
.p2align 2
.include "ih264_neon_macros.s"

.global ih264e_evaluate_intra16x16_modes_av8

ih264e_evaluate_intra16x16_modes_av8:

//x0 = pu1_src,
//x1 = pu1_ngbr_pels_i16,
//x2 = pu1_dst,
//w3 = src_strd,
//w4 = dst_strd,
//w5 = u4_n_avblty,
//x6 = u4_intra_mode,
//x7 = pu4_sadmin



    // STMFD sp!, {x4-x12, x14}          //store register values to stack
    push_v_regs
    sxtw      x3, w3
    sxtw      x4, w4
    stp       x19, x20, [sp, #-16]!

    ldr       w16, [sp, #80]
    mov       x17, x4
    mov       x14, x6
    mov       x15, x7


    sub       v0.16b, v0.16b, v0.16b
    sub       v1.16b, v1.16b, v1.16b
    mov       w10, #0
    mov       w11 , #3

    ands      w6, w5, #0x01
    beq       top_available             //LEFT NOT AVAILABLE
    ld1       {v0.16b}, [x1]
    add       w10, w10, #8
    add       w11, w11, #1
top_available:
    ands      w6, w5, #0x04
    beq       none_available
    add       x6, x1, #17
    ld1       {v1.16b}, [x6]
    add       w10, w10, #8
    add       w11, w11, #1
    b         summation
none_available:
    cmp       w5, #0
    bne       summation
    mov       w6, #128
    dup       v30.16b, w6
    dup       v31.16b, w6
    b         sad_comp
summation:
    uaddl     v2.8h, v0.8b, v1.8b
    uaddl2    v3.8h, v0.16b, v1.16b
    dup       v10.8h, w10
    neg       w11, w11
    dup       v20.8h, w11
    add       v0.8h, v2.8h, v3.8h
    mov       v1.d[0], v0.d[1]
    add       v0.4h, v0.4h, v1.4h
    addp      v0.4h, v0.4h , v0.4h
    addp      v0.4h, v0.4h , v0.4h
    add       v0.4h, v0.4h, v10.4h
    uqshl     v0.8h, v0.8h, v20.8h
    sqxtun    v0.8b, v0.8h

    dup       v30.16b, v0.b[0]
    dup       v31.16b, v0.b[0]


sad_comp:
    ld1       { v0.2s, v1.2s }, [x0], x3 // source x0w 0

    ld1       { v2.2s, v3.2s}, [x0], x3 //row 1

    ld1       { v4.2s, v5.2s}, [x0], x3 //row 2

    ld1       { v6.2s, v7.2s}, [x0], x3 //row 3

    //---------------------

    //values for vertical prediction
    add       x6, x1, #17
    ld1       {v10.8b}, [x6], #8
    ld1       {v11.8b}, [x6], #8
    ld1       {v9.16b}, [x1]



    dup       v20.8b, v9.b[15]          ///HORIZONTAL VALUE ROW=0//
    dup       v21.8b, v9.b[15]          ///HORIZONTAL VALUE ROW=0//


///* computing SADs for all three modes*/
    ///vertical row 0@
    uabdl     v16.8h, v0.8b, v10.8b
    uabdl     v18.8h, v1.8b, v11.8b

    ///HORZ row 0@
    uabdl     v26.8h, v0.8b, v20.8b
    uabdl     v28.8h, v1.8b, v21.8b

    ///dc row 0@
    uabdl     v22.8h, v0.8b, v30.8b
    uabdl     v24.8h, v1.8b, v31.8b





    dup       v20.8b, v9.b[14]          ///HORIZONTAL VALUE ROW=1//
    dup       v21.8b, v9.b[14]


    ///vertical row 1@
    uabal     v16.8h, v2.8b, v10.8b
    uabal     v18.8h, v3.8b, v11.8b

    ld1       { v0.2s, v1.2s }, [x0], x3 //row 4
    ///HORZ row 1@
    uabal     v26.8h, v2.8b, v20.8b
    uabal     v28.8h, v3.8b, v21.8b

    ///dc row 1@
    uabal     v22.8h, v2.8b, v30.8b
    uabal     v24.8h, v3.8b, v31.8b

    dup       v20.8b, v9.b[13]          ///HORIZONTAL VALUE ROW=2//
    dup       v21.8b, v9.b[13]

    ///vertical row 2@
    uabal     v16.8h, v4.8b, v10.8b
    uabal     v18.8h, v5.8b, v11.8b

    ld1       { v2.2s, v3.2s}, [x0], x3 //row 5
    ///HORZ row 2@
    uabal     v26.8h, v4.8b, v20.8b
    uabal     v28.8h, v5.8b, v21.8b

    ///dc row 2@
    uabal     v22.8h, v4.8b, v30.8b
    uabal     v24.8h, v5.8b, v31.8b

    dup       v20.8b, v9.b[12]          ///HORIZONTAL VALUE ROW=3//
    dup       v21.8b, v9.b[12]

    ///vertical row 3@
    uabal     v16.8h, v6.8b, v10.8b
    uabal     v18.8h, v7.8b, v11.8b

    ld1       { v4.2s, v5.2s}, [x0], x3 //row 6
    ///HORZ row 3@
    uabal     v26.8h, v6.8b, v20.8b
    uabal     v28.8h, v7.8b, v21.8b

    ///dc row 3@
    uabal     v22.8h, v6.8b, v30.8b
    uabal     v24.8h, v7.8b, v31.8b
//----------------------------------------------------------------------------------------------

    dup       v20.8b, v9.b[11]          ///HORIZONTAL VALUE ROW=0//
    dup       v21.8b, v9.b[11]

    ///vertical row 0@
    uabal     v16.8h, v0.8b, v10.8b
    uabal     v18.8h, v1.8b, v11.8b

    ld1       {  v6.2s, v7.2s}, [x0], x3 //row 7
    ///HORZ row 0@
    uabal     v26.8h, v0.8b, v20.8b
    uabal     v28.8h, v1.8b, v21.8b

    ///dc row 0@
    uabal     v22.8h, v0.8b, v30.8b
    uabal     v24.8h, v1.8b, v31.8b

    dup       v20.8b, v9.b[10]          ///HORIZONTAL VALUE ROW=1//
    dup       v21.8b, v9.b[10]

    ///vertical row 1@
    uabal     v16.8h, v2.8b, v10.8b
    uabal     v18.8h, v3.8b, v11.8b

    ld1       { v0.2s, v1.2s }, [x0], x3 //row 8
    ///HORZ row 1@
    uabal     v26.8h, v2.8b, v20.8b
    uabal     v28.8h, v3.8b, v21.8b

    ///dc row 1@
    uabal     v22.8h, v2.8b, v30.8b
    uabal     v24.8h, v3.8b, v31.8b

    dup       v20.8b, v9.b[9]           ///HORIZONTAL VALUE ROW=2//
    dup       v21.8b, v9.b[9]

    ///vertical row 2@
    uabal     v16.8h, v4.8b, v10.8b
    uabal     v18.8h, v5.8b, v11.8b

    ld1       { v2.2s, v3.2s}, [x0], x3 //row 9

    ///HORZ row 2@
    uabal     v26.8h, v4.8b, v20.8b
    uabal     v28.8h, v5.8b, v21.8b

    ///dc row 2@
    uabal     v22.8h, v4.8b, v30.8b
    uabal     v24.8h, v5.8b, v31.8b

    dup       v20.8b, v9.b[8]           ///HORIZONTAL VALUE ROW=3//
    dup       v21.8b, v9.b[8]

    ///vertical row 3@
    uabal     v16.8h, v6.8b, v10.8b
    uabal     v18.8h, v7.8b, v11.8b

    ld1       { v4.2s, v5.2s}, [x0], x3 //row 10

    ///HORZ row 3@
    uabal     v26.8h, v6.8b, v20.8b
    uabal     v28.8h, v7.8b, v21.8b

    ///dc row 3@
    uabal     v22.8h, v6.8b, v30.8b
    uabal     v24.8h, v7.8b, v31.8b


//-------------------------------------------

    dup       v20.8b, v9.b[7]           ///HORIZONTAL VALUE ROW=0//
    dup       v21.8b, v9.b[7]

    ///vertical row 0@
    uabal     v16.8h, v0.8b, v10.8b
    uabal     v18.8h, v1.8b, v11.8b

    ld1       {  v6.2s, v7.2s}, [x0], x3 //row11

    ///HORZ row 0@
    uabal     v26.8h, v0.8b, v20.8b
    uabal     v28.8h, v1.8b, v21.8b

    ///dc row 0@
    uabal     v22.8h, v0.8b, v30.8b
    uabal     v24.8h, v1.8b, v31.8b

    dup       v20.8b, v9.b[6]           ///HORIZONTAL VALUE ROW=1//
    dup       v21.8b, v9.b[6]

    ///vertical row 1@
    uabal     v16.8h, v2.8b, v10.8b
    uabal     v18.8h, v3.8b, v11.8b

    ld1       { v0.2s, v1.2s }, [x0], x3 //row12

    ///HORZ row 1@
    uabal     v26.8h, v2.8b, v20.8b
    uabal     v28.8h, v3.8b, v21.8b

    ///dc row 1@
    uabal     v22.8h, v2.8b, v30.8b
    uabal     v24.8h, v3.8b, v31.8b

    dup       v20.8b, v9.b[5]           ///HORIZONTAL VALUE ROW=2//
    dup       v21.8b, v9.b[5]

    ///vertical row 2@
    uabal     v16.8h, v4.8b, v10.8b
    uabal     v18.8h, v5.8b, v11.8b

    ld1       { v2.2s, v3.2s}, [x0], x3 //row13

    ///HORZ row 2@
    uabal     v26.8h, v4.8b, v20.8b
    uabal     v28.8h, v5.8b, v21.8b

    ///dc row 2@
    uabal     v22.8h, v4.8b, v30.8b
    uabal     v24.8h, v5.8b, v31.8b

    dup       v20.8b, v9.b[4]           ///HORIZONTAL VALUE ROW=3//
    dup       v21.8b, v9.b[4]

    ///vertical row 3@
    uabal     v16.8h, v6.8b, v10.8b
    uabal     v18.8h, v7.8b, v11.8b

    ld1       { v4.2s, v5.2s}, [x0], x3 //row14

    ///HORZ row 3@
    uabal     v26.8h, v6.8b, v20.8b
    uabal     v28.8h, v7.8b, v21.8b

    ///dc row 3@
    uabal     v22.8h, v6.8b, v30.8b
    uabal     v24.8h, v7.8b, v31.8b
    //-----------------------------------------------------------------

    dup       v20.8b, v9.b[3]           ///HORIZONTAL VALUE ROW=0//
    dup       v21.8b, v9.b[3]

    ///vertical row 0@
    uabal     v16.8h, v0.8b, v10.8b
    uabal     v18.8h, v1.8b, v11.8b

    ld1       {  v6.2s, v7.2s}, [x0], x3 //row15

    ///HORZ row 0@
    uabal     v26.8h, v0.8b, v20.8b
    uabal     v28.8h, v1.8b, v21.8b

    ///dc row 0@
    uabal     v22.8h, v0.8b, v30.8b
    uabal     v24.8h, v1.8b, v31.8b

    dup       v20.8b, v9.b[2]           ///HORIZONTAL VALUE ROW=1//
    dup       v21.8b, v9.b[2]

    ///vertical row 1@
    uabal     v16.8h, v2.8b, v10.8b
    uabal     v18.8h, v3.8b, v11.8b

    ///HORZ row 1@
    uabal     v26.8h, v2.8b, v20.8b
    uabal     v28.8h, v3.8b, v21.8b

    ///dc row 1@
    uabal     v22.8h, v2.8b, v30.8b
    uabal     v24.8h, v3.8b, v31.8b

    dup       v20.8b, v9.b[1]           ///HORIZONTAL VALUE ROW=2//
    dup       v21.8b, v9.b[1]

    ///vertical row 2@
    uabal     v16.8h, v4.8b, v10.8b
    uabal     v18.8h, v5.8b, v11.8b

    ///HORZ row 2@
    uabal     v26.8h, v4.8b, v20.8b
    uabal     v28.8h, v5.8b, v21.8b

    ///dc row 2@
    uabal     v22.8h, v4.8b, v30.8b
    uabal     v24.8h, v5.8b, v31.8b

    dup       v20.8b, v9.b[0]           ///HORIZONTAL VALUE ROW=3//
    dup       v21.8b, v9.b[0]

    ///vertical row 3@
    uabal     v16.8h, v6.8b, v10.8b
    uabal     v18.8h, v7.8b, v11.8b

    ///HORZ row 3@
    uabal     v26.8h, v6.8b, v20.8b
    uabal     v28.8h, v7.8b, v21.8b

    ///dc row 3@
    uabal     v22.8h, v6.8b, v30.8b
    uabal     v24.8h, v7.8b, v31.8b
    //------------------------------------------------------------------------------


    //vert sum

    add       v16.8h, v16.8h , v18.8h
    mov       v18.d[0], v16.d[1]
    add       v16.4h, v16.4h , v18.4h
    uaddlp    v16.2s, v16.4h
    addp      v16.2s, v16.2s, v16.2s
    smov      x8, v16.s[0]              //dc


    //horz sum

    add       v26.8h, v26.8h , v28.8h
    mov       v28.d[0], v26.d[1]
    add       v26.4h, v26.4h , v28.4h
    uaddlp    v26.2s, v26.4h
    addp      v26.2s, v26.2s, v26.2s
    smov      x9, v26.s[0]

    //dc sum

    add       v24.8h, v22.8h , v24.8h   ///DC
    mov       v25.d[0], v24.d[1]
    add       v24.4h, v24.4h , v25.4h   ///DC
    uaddlp    v24.2s, v24.4h            ///DC
    addp      v24.2s, v24.2s, v24.2s    ///DC
    smov      x10, v24.s[0]             //dc


    //-----------------------
    mov       x11, #1
    lsl       x11, x11, #30

    mov       w0, w16
    //--------------------------------------------
    ands      w7, w0, #01               // vert mode valid????????????
    csel      x8, x11, x8, eq


    ands      w6, w0, #02               // horz mode valid????????????
    csel      x9, x11, x9, eq

    ands      w6, w0, #04               // dc mode valid????????????
    csel      x10, x11, x10, eq




//--------------------------------

    mov       x4, x17
    mov       x7, x15
    mov       x6, x14

    //---------------------------

    //--------------------------

    cmp       x8, x9
    bgt       not_vert
    cmp       x8, x10
    bgt       do_dc

    ///----------------------
    //DO VERTICAL PREDICTION
    str       w8 , [x7]                 //MIN SAD
    mov       w8, #0
    str       w8 , [x6]                 // MODE
    add       x6, x1, #17
    ld1       {v30.16b}, [x6]
    b         do_dc_vert
    //-----------------------------
not_vert: cmp x9, x10
    bgt       do_dc

    ///----------------------
    //DO HORIZONTAL
    str       w9 , [x7]                 //MIN SAD
    mov       w9, #1
    str       w9 , [x6]                 // MODE

    ld1       {v0.16b}, [x1]
    dup       v10.16b, v0.b[15]
    dup       v11.16b, v0.b[14]
    dup       v12.16b, v0.b[13]
    dup       v13.16b, v0.b[12]
    st1       {v10.16b}, [x2], x4
    dup       v14.16b, v0.b[11]
    st1       {v11.16b}, [x2], x4
    dup       v15.16b, v0.b[10]
    st1       {v12.16b}, [x2], x4
    dup       v16.16b, v0.b[9]
    st1       {v13.16b}, [x2], x4
    dup       v17.16b, v0.b[8]
    st1       {v14.16b}, [x2], x4
    dup       v18.16b, v0.b[7]
    st1       {v15.16b}, [x2], x4
    dup       v19.16b, v0.b[6]
    st1       {v16.16b}, [x2], x4
    dup       v20.16b, v0.b[5]
    st1       {v17.16b}, [x2], x4
    dup       v21.16b, v0.b[4]
    st1       {v18.16b}, [x2], x4
    dup       v22.16b, v0.b[3]
    st1       {v19.16b}, [x2], x4
    dup       v23.16b, v0.b[2]
    st1       {v20.16b}, [x2], x4
    dup       v24.16b, v0.b[1]
    st1       {v21.16b}, [x2], x4
    dup       v25.16b, v0.b[0]
    st1       {v22.16b}, [x2], x4
    st1       {v23.16b}, [x2], x4
    st1       {v24.16b}, [x2], x4
    st1       {v25.16b}, [x2], x4



    b         end_func


    ///-----------------------------

do_dc: ///---------------------------------
    //DO DC
    str       w10 , [x7]                //MIN SAD
    mov       w10, #2
    str       w10 , [x6]                // MODE
do_dc_vert:
    st1       {v30.4s}, [x2], x4        //0
    st1       {v30.4s}, [x2], x4        //1
    st1       {v30.4s}, [x2], x4        //2
    st1       {v30.4s}, [x2], x4        //3
    st1       {v30.4s}, [x2], x4        //4
    st1       {v30.4s}, [x2], x4        //5
    st1       {v30.4s}, [x2], x4        //6
    st1       {v30.4s}, [x2], x4        //7
    st1       {v30.4s}, [x2], x4        //8
    st1       {v30.4s}, [x2], x4        //9
    st1       {v30.4s}, [x2], x4        //10
    st1       {v30.4s}, [x2], x4        //11
    st1       {v30.4s}, [x2], x4        //12
    st1       {v30.4s}, [x2], x4        //13
    st1       {v30.4s}, [x2], x4        //14
    st1       {v30.4s}, [x2], x4        //15
    ///------------------
end_func:
    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack
    ldp       x19, x20, [sp], #16
    pop_v_regs
    ret