#include "cl_viv_vx_ext.h"

_viv_uniform VXC_512Bits uniResize2xUp_0_4x8;
_viv_uniform VXC_512Bits uniResize2xUp_1_4x8;
_viv_uniform int out_height;

__kernel void resize_bilinear_U8toU8_SAME_2x_upsample_half_pixel_centers
    (
    __read_only  image2d_array_t   input,
    __write_only image2d_array_t   output,
                             int   align_corners,
                             int   half_pixel_centers
    )
{
    int4 coord_out  =  (int4)(get_global_id(0), 0, get_global_id(1), 0);
    int4 coord_in   = (int4)(get_global_id(0), -1, get_global_id(1), 0);
    coord_in.x = (coord_out.x * 2 - 1) >> 2;
    coord_in.x  = coord_out.x == 0 ? -1 : coord_in.x;

    vxc_uchar16 in0, in1, tmp, result;

    int8 input_desc;
    _viv_asm(COPY, input_desc, input, sizeof(input_desc));
    int baseAddr = (int)coord_in.z * input_desc.s4 + input_desc.s0;
    _viv_asm(MOV, coord_in.w, baseAddr);
    VXC_OP4(img_load_3d, in0, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 0),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_OP4(img_load_3d, in1, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 1),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));

    int8 output_desc;
    _viv_asm(COPY, output_desc, output, sizeof(output_desc));
    baseAddr = (int)coord_out.z * output_desc.s4 + output_desc.s0;
    _viv_asm(MOV, coord_out.w, baseAddr);

    while (coord_out.y < out_height)
    {
        VXC_DP4x8(result, in0, in1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniResize2xUp_0_4x8);
        VXC_DP4x8(result, in0, in1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize2xUp_1_4x8);
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, result,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_OP4(img_load_3d, in0, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 2),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
        VXC_DP4x8(result, in0, in1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniResize2xUp_0_4x8);
        VXC_DP4x8(result, in0, in1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize2xUp_1_4x8);
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, result,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_DP4x8(result, in1, in0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniResize2xUp_0_4x8);
        VXC_DP4x8(result, in1, in0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize2xUp_1_4x8);
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, result,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        VXC_OP4(img_load_3d, in1, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 3),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_DP4x8(result, in1, in0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniResize2xUp_0_4x8);
        VXC_DP4x8(result, in1, in0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize2xUp_1_4x8);
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, result,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_in.y += 2;
        coord_out.y++;
    }
}

_viv_uniform VXC_512Bits uniResize4xUp_l00_4x8;
_viv_uniform VXC_512Bits uniResize4xUp_l01_4x8;
_viv_uniform VXC_512Bits uniResize4xUp_l10_4x8;
_viv_uniform VXC_512Bits uniResize4xUp_l11_4x8;
__kernel void resize_bilinear_U8toU8_SAME_4x_upsample_half_pixel_centers
    (
    __read_only  image2d_array_t   input,
    __write_only image2d_array_t   output,
                             int   align_corners,
                             int   half_pixel_centers
    )
{
    int4 coord_out  =  (int4)(get_global_id(0), 0, get_global_id(1), 0);
    int4 coord_in   = (int4)(get_global_id(0), -1, get_global_id(1), 0);
    coord_in.x = (coord_out.x * 2 - 3) >> 3;
    coord_in.x  = coord_out.x == 0 ? -1 : coord_in.x;

    vxc_uchar16 in0, in1, tmp, dst0, dst1;

    int8 input_desc;
    _viv_asm(COPY, input_desc, input, sizeof(input_desc));
    int baseAddr = (int)coord_in.z * input_desc.s4 + input_desc.s0;
    _viv_asm(MOV, coord_in.w, baseAddr);
    VXC_OP4(img_load_3d, in0, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 0),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_OP4(img_load_3d, in1, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 1),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));

    int8 output_desc;
    _viv_asm(COPY, output_desc, output, sizeof(output_desc));
    baseAddr = (int)coord_out.z * output_desc.s4 + output_desc.s0;
    _viv_asm(MOV, coord_out.w, baseAddr);

    while (coord_out.y < out_height)
    {
        VXC_DP4x8(dst0, in0, in1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l00_4x8);
        VXC_DP4x8(dst0, in0, in1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l01_4x8);
        VXC_DP4x8(dst1, in0, in1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l10_4x8);
        VXC_DP4x8(dst1, in0, in1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l11_4x8);
        VXC_OP4(img_load_3d, in0, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 2),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst0,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst1,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_DP4x8(dst0, in0, in1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l10_4x8);
        VXC_DP4x8(dst0, in0, in1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l11_4x8);
        VXC_DP4x8(dst1, in0, in1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),  uniResize4xUp_l00_4x8);
        VXC_DP4x8(dst1, in0, in1, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l01_4x8);
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst0,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst1,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_DP4x8(dst0, in1, in0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),  uniResize4xUp_l00_4x8);
        VXC_DP4x8(dst0, in1, in0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l01_4x8);
        VXC_DP4x8(dst1, in1, in0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),  uniResize4xUp_l10_4x8);
        VXC_DP4x8(dst1, in1, in0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l11_4x8);
        VXC_OP4(img_load_3d, in1, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 3),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst0,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst1,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_DP4x8(dst0, in1, in0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),  uniResize4xUp_l10_4x8);
        VXC_DP4x8(dst0, in1, in0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l11_4x8);
        VXC_DP4x8(dst1, in1, in0, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),  uniResize4xUp_l00_4x8);
        VXC_DP4x8(dst1, in1, in0, VXC_MODIFIER(8, 15, 0, VXC_RM_ToNearestEven, 1), uniResize4xUp_l01_4x8);
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst0,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_out.y++;
        VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst1,
            VXC_MODIFIER(0, 15, 0,VXC_RM_TowardZero, 0));
        coord_in.y += 2;
        coord_out.y++;
    }
}

_viv_uniform VXC_512Bits uniResize3xUp_l00_2x8;
_viv_uniform VXC_512Bits uniResize3xUp_l01_2x8;
_viv_uniform VXC_512Bits uniResize3xUp_l10_4x4;
_viv_uniform VXC_512Bits uniResize3xUp_l11_4x4;
_viv_uniform VXC_512Bits uniResize3xUp_l12_4x4;
_viv_uniform VXC_512Bits uniResize3xUp_l13_4x4;
__kernel void resize_bilinear_U8toU8_SAME_3x_upsample_half_pixel_centers
    (
    __read_only  image2d_array_t   input,
    __write_only image2d_array_t   output,
                             int   align_corners,
                             int   half_pixel_centers
    )
{
    int4 coord_out  =  (int4)(get_global_id(0), get_global_id(1), get_global_id(2), 0);
    int4 coord_in   = (int4)(get_global_id(0), get_global_id(1), get_global_id(2), 0);
    coord_in.x = (short)(coord_out.x * 2 - 1) / (short)6;
    coord_in.x  = coord_out.x == 0 ? -1 : coord_in.x;
    coord_in.y = (short)(coord_out.y * 2 - 1) / (short)6;
    coord_in.y  = coord_out.y == 0 ? -1 : coord_in.y;

    vxc_uchar16 in0, in1, in2, in3, tmp, dst0, dst1, dst2;

    int8 input_desc;
    _viv_asm(COPY, input_desc, input, sizeof(input_desc));
    int baseAddr = (int)coord_in.z * input_desc.s4 + input_desc.s0;
    _viv_asm(MOV, coord_in.w, baseAddr);
    VXC_OP4(img_load_3d, in0, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 0),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_OP4(img_load_3d, in1, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 1),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_OP4(img_load_3d, in2, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 2),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));
    VXC_OP4(img_load_3d, in3, input, coord_in.xywz, VXC_5BITOFFSET_XY(0, 3),
            VXC_MODIFIER(0, 15, 0, VXC_RM_TowardZero, 0));

    int8 output_desc;
    _viv_asm(COPY, output_desc, output, sizeof(output_desc));
    baseAddr = (int)coord_out.z * output_desc.s4 + output_desc.s0;
    _viv_asm(MOV, coord_out.w, baseAddr);

    VXC_DP4x4(dst2, in1, in0, VXC_MODIFIER(0, 3, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l10_4x4);
    VXC_DP4x4(dst2, in1, in0, VXC_MODIFIER(4, 7, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l11_4x4);
    VXC_DP4x4(dst2, in1, in0, VXC_MODIFIER(8, 11, 0, VXC_RM_ToNearestEven, 1),  uniResize3xUp_l12_4x4);
    VXC_DP4x4(dst2, in1, in0, VXC_MODIFIER(12, 14, 0, VXC_RM_ToNearestEven, 1), uniResize3xUp_l13_4x4);
    VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst2,
        VXC_MODIFIER(0, 14, 0,VXC_RM_TowardZero, 0));
    coord_out.y++;

    VXC_DP2x8(dst0, in1, in1, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l00_2x8);
    VXC_DP2x8(dst0, in1, in1, VXC_MODIFIER(8, 14, 0, VXC_RM_ToNearestEven, 1),  uniResize3xUp_l01_2x8);
    VXC_DP4x4(dst1, in1, in2, VXC_MODIFIER(0, 3, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l10_4x4);
    VXC_DP4x4(dst1, in1, in2, VXC_MODIFIER(4, 7, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l11_4x4);
    VXC_DP4x4(dst1, in1, in2, VXC_MODIFIER(8, 11, 0, VXC_RM_ToNearestEven, 1),  uniResize3xUp_l12_4x4);
    VXC_DP4x4(dst1, in1, in2, VXC_MODIFIER(12, 14, 0, VXC_RM_ToNearestEven, 1), uniResize3xUp_l13_4x4);
    VXC_DP4x4(dst2, in2, in1, VXC_MODIFIER(0, 3, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l10_4x4);
    VXC_DP4x4(dst2, in2, in1, VXC_MODIFIER(4, 7, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l11_4x4);
    VXC_DP4x4(dst2, in2, in1, VXC_MODIFIER(8, 11, 0, VXC_RM_ToNearestEven, 1),  uniResize3xUp_l12_4x4);
    VXC_DP4x4(dst2, in2, in1, VXC_MODIFIER(12, 14, 0, VXC_RM_ToNearestEven, 1), uniResize3xUp_l13_4x4);
    VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst0,
        VXC_MODIFIER(0, 14, 0,VXC_RM_TowardZero, 0));
    coord_out.y++;
    VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst1,
        VXC_MODIFIER(0, 14, 0,VXC_RM_TowardZero, 0));
    coord_out.y++;
    VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst2,
        VXC_MODIFIER(0, 14, 0,VXC_RM_TowardZero, 0));
    coord_out.y++;

    VXC_DP2x8(dst0, in2, in2, VXC_MODIFIER(0, 7, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l00_2x8);
    VXC_DP2x8(dst0, in2, in2, VXC_MODIFIER(8, 14, 0, VXC_RM_ToNearestEven, 1),  uniResize3xUp_l01_2x8);
    VXC_DP4x4(dst1, in2, in3, VXC_MODIFIER(0, 3, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l10_4x4);
    VXC_DP4x4(dst1, in2, in3, VXC_MODIFIER(4, 7, 0, VXC_RM_ToNearestEven, 1),   uniResize3xUp_l11_4x4);
    VXC_DP4x4(dst1, in2, in3, VXC_MODIFIER(8, 11, 0, VXC_RM_ToNearestEven, 1),  uniResize3xUp_l12_4x4);
    VXC_DP4x4(dst1, in2, in3, VXC_MODIFIER(12, 14, 0, VXC_RM_ToNearestEven, 1), uniResize3xUp_l13_4x4);
    VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst0,
        VXC_MODIFIER(0, 14, 0,VXC_RM_TowardZero, 0));
    coord_out.y++;
    VXC_OP4_NoDest(img_store_3d, output, coord_out.xywz, dst1,
        VXC_MODIFIER(0, 14, 0,VXC_RM_TowardZero, 0));
}
