
#pragma OPENCL EXTENSION cl_viv_vx_extension : enable

typedef struct Image
{
    __global uchar *ptr;
    int             stride_x;
    int             stride_y;
} Image;

inline uchar* get_image_ptr_from_coord(Image img, int2 coord)
{
    return img.ptr + coord.x * img.stride_x + coord.y * img.stride_y;
}

inline Image create_image_from_image2d(image2d_t input, int stride_x)
{
    int stride_y;
#if (USE_40BITS_VA==0)
    int8 desc;
#else
    int8 desc;
    _viv_asm(GET_IMAGE_STRIDE, stride_y, input);
#endif
    _viv_asm(COPY, desc, input, sizeof(desc));
    uint address = as_uint(desc.s0);

#if (USE_40BITS_VA==0)
    stride_y = desc.s1;
#endif

    Image img =
    {
        .ptr                           = (uchar*)(uintptr_t)address,
        .stride_x                      = stride_x,
        .stride_y                      = stride_y
    };

    return img;
}

typedef struct Tensor
{
    __global uchar *ptr;
    int             stride_x;
    int             stride_y;
    int             stride_z;
} Tensor;

inline uchar* get_tensor_ptr_from_coord(Tensor t, int4 coord)
{
    return t.ptr + coord.x * t.stride_x + coord.y * t.stride_y + coord.z * t.stride_z;
}

inline Tensor create_tensor_from_image2d_array(image2d_array_t input, int stride_x)
{
    int8 desc;
    int2 strides;
    _viv_asm(COPY, desc, input, sizeof(desc));
#if (USE_40BITS_VA==0)
    strides.x = desc.s1;
    strides.y = desc.s4;
#else
    _viv_asm(GET_IMAGE_STRIDE, strides, input);
#endif
    uint address = as_uint(desc.s0);

    Tensor t =
    {
        .ptr                           = (uchar*)(uintptr_t)address,
        .stride_x                      = stride_x,
        .stride_y                      = strides.x,
        .stride_z                      = strides.y
    };

    return t;
}

#if (VX_VERSION==1)
#define VXC_DP2x8_b_(dst, src0, src1, src2, info, uniform)\
do\
{\
    _viv_asm(COPY, dst, src0, 16); \
} while (0)

#define VXC_VertMin3_Integer(dst, src0, src1, src2, info)\
do\
{\
    typeof (dst) tmp; \
    tmp  = min(src0, src1);\
    dst  = min(src2, tmp);\
} while (0)

#define VXC_VertMin3_Half(dst, src0, src1, src2, info)\
do\
{\
    vxc_short8 val0_ver1, val1_ver1, val2_ver1, minVal_ver1, maxVal_ver1;\
    _viv_asm(COPY, val0_ver1, src0, 16);\
    _viv_asm(COPY, val1_ver1, src1, 16);\
    _viv_asm(COPY, val2_ver1, src2, 16);\
    maxVal_ver1 = max(val0_ver1, val1_ver1);\
    minVal_ver1 = min(val0_ver1, val1_ver1);\
    minVal_ver1 = maxVal_ver1 < 0 ? maxVal_ver1 : minVal_ver1; \
    maxVal_ver1 = max(val2_ver1, minVal_ver1);\
    minVal_ver1 = min(val2_ver1, minVal_ver1);\
    minVal_ver1 = maxVal_ver1 < 0 ? maxVal_ver1 : minVal_ver1; \
    _viv_asm(COPY, dst, minVal_ver1, 16); \
} while (0)

#define VXC_VertMax3_Integer(dst, src0, src1, src2, info)\
do\
{\
    constant int startBin     = (info & VXC_START_BIN_BITMASK) >> 12;\
    constant int endBin       = (info & VXC_END_BIN_BITMASK) >> 8;\
    constant int sourceBin    = (info & VXC_SOURCE_BIN_BITMASK) >> 4;\
    constant int mod1 = VXC_MODIFIER_CLAMP(startBin, endBin, sourceBin, 0);\
    typeof (dst) tmp;\
    tmp = max(src0, src1);\
    tmp = max(src2, tmp);\
    VXC_Clamp(dst, tmp, tmp, tmp, mod1);\
} while (0)

#define VXC_VertMax3_Half(dst, src0, src1, src2, info)\
 do\
 {\
     vxc_short8 val0_ver1, val1_ver1, val2_ver1, minVal_ver1, maxVal_ver1;\
     _viv_asm(COPY, val0_ver1, src0, 16);\
     _viv_asm(COPY, val1_ver1, src1, 16);\
     _viv_asm(COPY, val2_ver1, src2, 16);\
     maxVal_ver1 = max(val0_ver1, val1_ver1);\
     maxVal_ver1 = max(val2_ver1, maxVal_ver1);\
     minVal_ver1 = min(val0_ver1, val1_ver1);\
     minVal_ver1 = min(val2_ver1, minVal_ver1);\
     maxVal_ver1 = maxVal_ver1 >= 0 ? maxVal_ver1 : minVal_ver1;\
     _viv_asm(COPY, dst, maxVal_ver1, 16); \
 } while (0)

#define VXC_HorzMax3_Integer(dst, src0, info)\
do\
{\
    constant int startBin     = (info & VXC_START_BIN_BITMASK) >> 12;\
    constant int endBin       = (info & VXC_END_BIN_BITMASK) >> 8;\
    constant int sourceBin    = (info & VXC_SOURCE_BIN_BITMASK) >> 4;\
    constant int clamp        = (info & VXC_CLAMP_BITMASK) >> 22;\
    int mod1 = VXC_MODIFIER_FILTER(startBin, endBin, sourceBin, VXC_FM_Max, clamp);\
    VXC_OP4(filter, dst, src0, src0, src0, mod1);\
} while (0)

#define VXC_HorzMax3_Half(dst, src0, info)\
do\
{\
    constant int startBin    = (info & VXC_START_BIN_BITMASK) >> 12;\
    constant int endBin      = (info & VXC_END_BIN_BITMASK) >> 8;\
    constant int sourceBin   = (info & VXC_SOURCE_BIN_BITMASK) >> 4;\
    constant int clamp       = (info & VXC_CLAMP_BITMASK) >> 22;\
    constant int mod1 = VXC_MODIFIER_FILTER(startBin, endBin, sourceBin, VXC_FM_Max, clamp);\
    constant int mod2 = VXC_MODIFIER_FILTER(startBin, endBin, sourceBin, VXC_FM_Min, clamp);\
    vxc_short8 val0, minVal, maxVal;\
    _viv_asm(COPY, val0, src0, 16);\
    VXC_OP4(filter, maxVal, val0, val0, val0, mod1);\
    VXC_OP4(filter, minVal, val0, val0, val0, mod2);\
    maxVal = maxVal >= 0 ? maxVal : minVal;\
    _viv_asm(COPY, dst, maxVal, 16);\
} while (0)

#define VXC_HorzMin3_Integer(dst, src0, info)\
do\
{\
    constant int startBin     = (info & VXC_START_BIN_BITMASK) >> 12;\
    constant int endBin       = (info & VXC_END_BIN_BITMASK) >> 8;\
    constant int sourceBin    = (info & VXC_SOURCE_BIN_BITMASK) >> 4;\
    constant int clamp        = (info & VXC_CLAMP_BITMASK) >> 22;\
    constant int mod1 = VXC_MODIFIER_FILTER(startBin, endBin, sourceBin, VXC_FM_Min, clamp);\
    VXC_OP4(filter, dst, src0, src0, src0, mod1);\
} while (0)

#define VXC_HorzMin3_Half(dst, src0, info)\
do\
{\
    constant int startBin     = (info & VXC_START_BIN_BITMASK) >> 12;\
    constant int endBin       = (info & VXC_END_BIN_BITMASK) >> 8;\
    constant int sourceBin    = (info & VXC_SOURCE_BIN_BITMASK) >> 4;\
    constant int clamp        = (info & VXC_CLAMP_BITMASK) >> 22;\
    constant int mod1 = VXC_MODIFIER_FILTER(startBin, endBin, sourceBin, VXC_FM_Max, clamp);\
    constant int mod2 = VXC_MODIFIER_FILTER(startBin, endBin, sourceBin, VXC_FM_Min, clamp);\
    constant int mod3 = VXC_MODIFIER_FILTER(startBin, endBin, sourceBin, VXC_FM_Median, clamp);\
    vxc_short8 val0, minVal, maxVal, midVal;\
    _viv_asm(COPY, val0, src0, 16);\
    VXC_OP4(filter, maxVal, val0, val0, val0, mod1);\
    VXC_OP4(filter, minVal, val0, val0, val0, mod2);\
    VXC_OP4(filter, midVal, val0, val0, val0, mod3);\
    minVal = midVal  < 0 ? midVal : minVal;\
    minVal = maxVal  < 0 ? maxVal : minVal;\
    _viv_asm(COPY, dst, minVal, 16);\
} while (0)

#define VXC_Clamp_Half(dst, src0, src1, src2, info)\
do\
{\
    typeof (dst) tmp;\
    VXC_VertMax3_Half(tmp, src0, src0, src1, info);\
    VXC_VertMin3_Half(dst, tmp, tmp, src2, info);\
} while (0)

#else
#define VXC_DP2x8_b_(dst, src0, src1, src2, info, uniform)\
do\
{\
    VXC_DP2x8_b(dst, src0, src1, src2, info, uniform); \
} while (0)

#define VXC_VertMin3_Integer(dst, src0, src1, src2, info)\
 do\
 {\
    VXC_VertMin3(dst, src0, src1, src2, info);\
 } while (0)

#define VXC_VertMin3_Half(dst, src0, src1, src2, info)\
 do\
 {\
    VXC_VertMin3(dst, src0, src1, src2, info);\
 } while (0)

#define VXC_VertMax3_Integer(dst, src0, src1, src2, info)\
do\
{\
    VXC_VertMax3(dst, src0, src1, src2, info);\
} while (0)

#define VXC_VertMax3_Half(dst, src0, src1, src2, info)\
do\
{\
    VXC_VertMax3(dst, src0, src1, src2, info);\
} while (0)

#define VXC_HorzMax3_Integer(dst, src0, info)\
do\
{\
    VXC_HorzMax3(dst, src0, info);\
} while (0)

#define VXC_HorzMax3_Half(dst, src0, info)\
do\
{\
    VXC_HorzMax3(dst, src0, info);\
} while (0)

#define VXC_HorzMin3_Integer(dst, src0, info)\
do\
{\
    VXC_HorzMin3(dst, src0, info);\
} while (0)

#define VXC_HorzMin3_Half(dst, src0, info)\
do\
{\
    VXC_HorzMin3(dst, src0, info);\
} while (0)

#define VXC_Clamp_Half(dst, src0, src1, src2, info)\
do\
{\
    VXC_Clamp(dst, src0, src1, src2, info);\
} while (0)
#endif
