#include "cl_viv_vx_ext.h"

_viv_uniform VXC_512Bits uniExtractR_2x8;
_viv_uniform VXC_512Bits uniExtractG_2x8;
_viv_uniform VXC_512Bits uniExtractB_2x8;
_viv_uniform float outputScale;
__kernel void ScaletoTensor_Fp16_copy
    (
    __read_only image2d_t        input,
    __write_only image2d_array_t output,
         global int              *xRatio,
         global int              *yRatio,
         global int              *xOffset,
         global int              *yOffset,
                float            rMean,
                float            gMean,
                float            bMean,
                float            f32Var
    )
{
    int2 coord      = (int2)(get_global_id(0) * 3, get_global_id(1));

    coord.xy += (int2) (*xOffset, *yOffset);
    vxc_uchar16 src0, src1;
    vxc_half8   dst;

    VXC_ReadImage(src0, input, coord.xy, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input, coord.xy, VXC_5BITOFFSET_XY(15, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));

    float4      paramData = (float4)(rMean * f32Var, gMean * f32Var, bMean * f32Var, f32Var);
    //convert U8 to FP16
    half4 paramData_f16;
    vxc_short8 tmp_dst;
    _viv_asm(CONV, paramData_f16, paramData);

    int4 coord_out = (int4)(get_global_id(0), get_global_id(1), 2, 0);
    //R
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_TowardZero, 0), uniExtractR_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 7, 0, VXC_RM_TowardZero, 0), uniExtractR_2x8);
    _viv_asm(COPY, tmp_dst, dst, 16);
    VXC_WriteImage2DArray(output, coord_out, tmp_dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));


    //G
    coord_out.z = 1;
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_TowardZero, 0), uniExtractG_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 7, 0, VXC_RM_TowardZero, 0), uniExtractG_2x8);
    _viv_asm(COPY, tmp_dst, dst, 16);
    VXC_WriteImage2DArray(output, coord_out, tmp_dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));

    //B
    coord_out.z = 0;
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_TowardZero, 0), uniExtractB_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 7, 0, VXC_RM_TowardZero, 0), uniExtractB_2x8);
    _viv_asm(COPY, tmp_dst, dst, 16);
    VXC_WriteImage2DArray(output, coord_out, tmp_dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
}

__kernel void ScaletoTensor_Int8_copy
    (
    __read_only image2d_t        input,
    __write_only image2d_array_t output,
         global int              *xRatio,
         global int              *yRatio,
         global int              *xOffset,
         global int              *yOffset,
                float            rMean,
                float            gMean,
                float            bMean,
                float            f32Var
    )
{
    int2 coord      = (int2)(get_global_id(0) * 3, get_global_id(1));

    coord.xy += (int2) (*xOffset, *yOffset);
    vxc_uchar16 src0, src1;
    vxc_char16   dst;

    VXC_ReadImage(src0, input, coord.xy, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input, coord.xy, VXC_5BITOFFSET_XY(15, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));

    f32Var *= outputScale;
    float4      paramData = (float4)(rMean * f32Var, gMean * f32Var, bMean * f32Var, f32Var);
    //convert U8 to FP16
    half4 paramData_f16;
    _viv_asm(CONV, paramData_f16, paramData);

    int4 coord_out = (int4)(get_global_id(0), get_global_id(1), 2, 0);
    //R
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_ToNearestEven, 1), uniExtractR_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 9, 0, VXC_RM_ToNearestEven, 1), uniExtractR_2x8);
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 9, 0, VXC_RM_TowardZero, 0));


    //G
    coord_out.z = 1;
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_ToNearestEven, 1), uniExtractG_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 9, 0, VXC_RM_ToNearestEven, 1), uniExtractG_2x8);
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 9, 0, VXC_RM_TowardZero, 0));

    //B
    coord_out.z = 0;
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_ToNearestEven, 1), uniExtractB_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 9, 0, VXC_RM_ToNearestEven, 1), uniExtractB_2x8);
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 9, 0, VXC_RM_TowardZero, 0));
}

__kernel void ScaletoTensor_Int16_copy
    (
    __read_only image2d_t        input,
    __write_only image2d_array_t output,
         global int              *xRatio,
         global int              *yRatio,
         global int              *xOffset,
         global int              *yOffset,
                float            rMean,
                float            gMean,
                float            bMean,
                float            f32Var
    )
{
    int2 coord      = (int2)(get_global_id(0) * 3, get_global_id(1));

    coord.xy += (int2) (*xOffset, *yOffset);
    vxc_uchar16 src0, src1;
    vxc_short8   dst;

    VXC_ReadImage(src0, input, coord.xy, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input, coord.xy, VXC_5BITOFFSET_XY(15, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));

    f32Var *= outputScale;
    float4      paramData = (float4)(rMean * f32Var, gMean * f32Var, bMean * f32Var, f32Var);
    //convert U8 to FP16
    half4 paramData_f16;
    _viv_asm(CONV, paramData_f16, paramData);

    int4 coord_out = (int4)(get_global_id(0), get_global_id(1), 2, 0);
    //R
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_ToNearestEven, 1), uniExtractR_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 7, 0, VXC_RM_ToNearestEven, 1), uniExtractR_2x8);
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));


    //G
    coord_out.z = 1;
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_ToNearestEven, 1), uniExtractG_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 7, 0, VXC_RM_ToNearestEven, 1), uniExtractG_2x8);
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));

    //B
    coord_out.z = 0;
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_ToNearestEven, 1), uniExtractB_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 7, 0, VXC_RM_ToNearestEven, 1), uniExtractB_2x8);
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
}

_viv_uniform float outputZP;
__kernel void ScaletoTensor_UInt8_copy
    (
    __read_only image2d_t        input,
    __write_only image2d_array_t output,
         global int              *xRatio,
         global int              *yRatio,
         global int              *xOffset,
         global int              *yOffset,
                float            rMean,
                float            gMean,
                float            bMean,
                float            f32Var
    )
{
    int2 coord      = (int2)(get_global_id(0) * 3, get_global_id(1));

    coord.xy += (int2) (*xOffset, *yOffset);
    vxc_uchar16 src0, src1;
    vxc_uchar16   dst;

    VXC_ReadImage(src0, input, coord.xy, VXC_5BITOFFSET_XY(0, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_ReadImage(src1, input, coord.xy, VXC_5BITOFFSET_XY(15, 0),\
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));

    f32Var *= outputScale;
    float4      paramData = (float4)(rMean * f32Var - outputZP,\
        gMean * f32Var - outputZP, bMean * f32Var - outputZP, f32Var);
    //convert U8 to FP16
    half4 paramData_f16;
    _viv_asm(CONV, paramData_f16, paramData);

    int4 coord_out = (int4)(get_global_id(0), get_global_id(1), 2, 0);
    //R
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_ToNearestEven, 1), uniExtractR_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 9, 0, VXC_RM_ToNearestEven, 1), uniExtractR_2x8);
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 9, 0, VXC_RM_TowardZero, 0));


    //G
    coord_out.z = 1;
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_ToNearestEven, 1), uniExtractG_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 9, 0, VXC_RM_ToNearestEven, 1), uniExtractG_2x8);
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 9, 0, VXC_RM_TowardZero, 0));

    //B
    coord_out.z = 0;
    VXC_DP2x8(dst, src0, paramData_f16, VXC_MODIFIER(0, 4, 0, VXC_RM_ToNearestEven, 1), uniExtractB_2x8);
    VXC_DP2x8(dst, src1, paramData_f16, VXC_MODIFIER(5, 9, 0, VXC_RM_ToNearestEven, 1), uniExtractB_2x8);
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 9, 0, VXC_RM_TowardZero, 0));
}
