#include "cl_viv_vx_ext.h"

_viv_uniform float outputScale;
_viv_uniform float outputZP;
_viv_uniform int r_order;
_viv_uniform int b_order;
_viv_uniform VXC_512Bits uniExtractRtoF32_part0_4x4;
_viv_uniform VXC_512Bits uniExtractRtoF32_part1_4x4;
_viv_uniform VXC_512Bits uniExtractRtoF32_part2_4x4;
_viv_uniform VXC_512Bits uniExtractRtoF32_part3_4x4;
_viv_uniform VXC_512Bits uniExtractGtoF32_part0_4x4;
_viv_uniform VXC_512Bits uniExtractGtoF32_part1_4x4;
_viv_uniform VXC_512Bits uniExtractGtoF32_part2_4x4;
_viv_uniform VXC_512Bits uniExtractGtoF32_part3_4x4;
_viv_uniform VXC_512Bits uniExtractBtoF32_part0_4x4;
_viv_uniform VXC_512Bits uniExtractBtoF32_part1_4x4;
_viv_uniform VXC_512Bits uniExtractBtoF32_part2_4x4;
_viv_uniform VXC_512Bits uniExtractBtoF32_part3_4x4;
_viv_uniform VXC_512Bits uniExtract8Data_2x8;

#define IMAGE_PRE_PROCESS_COPY_16BITS(dst_name, dst_type, copy_type, convert_type) \
__kernel void pre_process_rgb_copy_U8to##dst_name \
    ( \
    __read_only image2d_array_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, \
                int              reverse_channel, \
                int              trans \
    ) \
{ \
    int2 coord      = (int2)(get_global_id(0) * 3, get_global_id(1)); \
 \
    coord.xy = coord.xy + (int2) (*xOffset * 3 + 16, *yOffset); \
    vxc_uchar16 src0, src1; \
    dst_type   dst0; \
    copy_type   dst; \
 \
    VXC_ReadImage(src0, input, coord.xy, VXC_5BITOFFSET_XY(-16, 0), \
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0)); \
    VXC_ReadImage(src1, input, coord.xy, VXC_5BITOFFSET_XY(0, 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); \
 \
    int4 coord_out = (int4)(get_global_id(0), get_global_id(1), r_order, 0); \
    float4 tmp0, tmp1; \
    convert_type result0, result1; \
 \
    VXC_DP4x4(tmp0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractRtoF32_part0_4x4); \
    VXC_DP4x4(tmp1, src0, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractRtoF32_part1_4x4); \
    tmp0 = tmp0 * paramData.w - paramData.x; \
    tmp1 = tmp1 * paramData.w - paramData.x; \
    _viv_asm(CONV_RTE, result0, tmp0); \
    _viv_asm(CONV_RTE, result1, tmp1); \
    VXC_DP2x8(dst0, result0, result1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniExtract8Data_2x8); \
    _viv_asm(COPY, dst, dst0, 16); \
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0)); \
 \
    coord_out.z = 1; \
    VXC_DP4x4(tmp0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractGtoF32_part0_4x4); \
    VXC_DP4x4(tmp1, src0, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractGtoF32_part1_4x4); \
    tmp0 = tmp0 * paramData.w - paramData.y; \
    tmp1 = tmp1 * paramData.w - paramData.y; \
    _viv_asm(CONV_RTE, result0, tmp0); \
    _viv_asm(CONV_RTE, result1, tmp1); \
    VXC_DP2x8(dst0, result0, result1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniExtract8Data_2x8); \
    _viv_asm(COPY, dst, dst0, 16); \
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0)); \
 \
    coord_out.z = b_order; \
    VXC_DP4x4(tmp0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractBtoF32_part0_4x4); \
    VXC_DP4x4(tmp1, src0, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractBtoF32_part1_4x4); \
    tmp0 = tmp0 * paramData.w - paramData.z; \
    tmp1 = tmp1 * paramData.w - paramData.z; \
    _viv_asm(CONV_RTE, result0, tmp0); \
    _viv_asm(CONV_RTE, result1, tmp1); \
    VXC_DP2x8(dst0, result0, result1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniExtract8Data_2x8); \
    _viv_asm(COPY, dst, dst0, 16); \
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0)); \
}
IMAGE_PRE_PROCESS_COPY_16BITS(I16, vxc_short8, vxc_short8, int4)
IMAGE_PRE_PROCESS_COPY_16BITS(F16, vxc_half8,  vxc_short8, half4)

#define IMAGE_PRE_PROCESS_COPY_8BITS(dst_name, dst_type) \
__kernel void pre_process_rgb_copy_U8to##dst_name \
    ( \
    __read_only image2d_array_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, \
                int              reverse_channel, \
                int              trans \
    ) \
{ \
    int2 coord      = (int2)(get_global_id(0) * 3, get_global_id(1)); \
    coord.xy = coord.xy + (int2) (*xOffset * 3 + 16, *yOffset); \
    vxc_uchar16 src0, src1, src2; \
    dst_type dst; \
 \
    VXC_ReadImage(src0, input, coord.xy, VXC_5BITOFFSET_XY(-16, 0), \
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0)); \
    VXC_ReadImage(src1, input, coord.xy, VXC_5BITOFFSET_XY(0, 0), \
        VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0)); \
        coord.x += 16; \
    VXC_ReadImage(src2, input, coord.xy, VXC_5BITOFFSET_XY(0, 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); \
 \
    int4 coord_out = (int4)(get_global_id(0), get_global_id(1), r_order, 0); \
    float4 tmp0, tmp1; \
    int4 result0, result1; \
 \
    VXC_DP4x4(tmp0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractRtoF32_part0_4x4); \
    VXC_DP4x4(tmp1, src0, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractRtoF32_part1_4x4); \
    tmp0 = tmp0 * paramData.w - paramData.x; \
    tmp1 = tmp1 * paramData.w - paramData.x; \
    result0 = convert_int4_rte(tmp0); \
    result1 = convert_int4_rte(tmp1); \
    VXC_DP2x8(dst, result0, result1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniExtract8Data_2x8); \
    VXC_DP4x4(tmp0, src1, src2, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractRtoF32_part2_4x4); \
    VXC_DP4x4(tmp1, src1, src2, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractRtoF32_part3_4x4); \
    tmp0 = tmp0 * paramData.w - paramData.x; \
    tmp1 = tmp1 * paramData.w - paramData.x; \
    result0 = convert_int4_rte(tmp0); \
    result1 = convert_int4_rte(tmp1); \
    VXC_DP2x8(dst, result0, result1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniExtract8Data_2x8); \
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0)); \
 \
    coord_out.z = 1; \
    VXC_DP4x4(tmp0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractGtoF32_part0_4x4); \
    VXC_DP4x4(tmp1, src0, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractGtoF32_part1_4x4); \
    tmp0 = tmp0 * paramData.w - paramData.y; \
    tmp1 = tmp1 * paramData.w - paramData.y; \
    result0 = convert_int4_rte(tmp0); \
    result1 = convert_int4_rte(tmp1); \
    VXC_DP2x8(dst, result0, result1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniExtract8Data_2x8); \
    VXC_DP4x4(tmp0, src1, src2, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractGtoF32_part2_4x4); \
    VXC_DP4x4(tmp1, src1, src2, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractGtoF32_part3_4x4); \
    tmp0 = tmp0 * paramData.w - paramData.y; \
    tmp1 = tmp1 * paramData.w - paramData.y; \
    result0 = convert_int4_rte(tmp0); \
    result1 = convert_int4_rte(tmp1); \
    VXC_DP2x8(dst, result0, result1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniExtract8Data_2x8); \
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0)); \
 \
    coord_out.z = b_order; \
    VXC_DP4x4(tmp0, src0, src0, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractBtoF32_part0_4x4); \
    VXC_DP4x4(tmp1, src0, src1, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractBtoF32_part1_4x4); \
    tmp0 = tmp0 * paramData.w - paramData.z; \
    tmp1 = tmp1 * paramData.w - paramData.z; \
    result0 = convert_int4_rte(tmp0); \
    result1 = convert_int4_rte(tmp1); \
    VXC_DP2x8(dst, result0, result1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniExtract8Data_2x8); \
    VXC_DP4x4(tmp0, src1, src2, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractBtoF32_part2_4x4); \
    VXC_DP4x4(tmp1, src1, src2, VXC_MODIFIER(0, 3, 0, VXC_RM_TowardZero, 0), uniExtractBtoF32_part3_4x4); \
    tmp0 = tmp0 * paramData.w - paramData.z; \
    tmp1 = tmp1 * paramData.w - paramData.z; \
    result0 = convert_int4_rte(tmp0); \
    result1 = convert_int4_rte(tmp1); \
    VXC_DP2x8(dst, result0, result1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniExtract8Data_2x8); \
    VXC_WriteImage2DArray(output, coord_out, dst, VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0)); \
}
IMAGE_PRE_PROCESS_COPY_8BITS(U8, vxc_uchar16)
IMAGE_PRE_PROCESS_COPY_8BITS(I8, vxc_char16)
