#include "cl_viv_vx_ext.h"

_viv_uniform int input_width;
_viv_uniform int input_height;
_viv_uniform int input_channel;
_viv_uniform int output_channel;


__kernel __attribute__((reqd_work_group_size(8, 1, 1))) void vxcSignalFrame_width(
    image2d_array_t input,
    image2d_array_t output,
                int frame_length,
                int step,
                int pad_end,
                int pad,
                int axis)
{
    int gidx = get_global_id(0);
    int gidy = get_global_id(1);
    int gidz = get_global_id(2);
    int outChn = gidz * input_height + gidy;
    int4 coord = (int4)(0, gidy, gidz, 0);
    int4 coord_out = (int4)(0, 0, outChn, 0);

    int endcoord = (pad_end == 0) ? (input_width - frame_length + 1) : (input_width);
    int iter = frame_length / 8;
    int res = frame_length % 8;
    vxc_short8 src0;

    for(int i = 0; i < endcoord; i += step)
    {
        coord.x = i;
        for(int j = 0; j < iter; j++)
        {
            coord_out.x = j << 3;
            coord.x = i + (j << 3);
            VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
            VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
        }
        coord.x = i + (iter << 3);
        coord_out.x = (iter << 3);
        for(int j = 0; j < res; j++)
        {
            VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 0, 0, VXC_RM_TowardZero, 0));
            VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 0, 0, VXC_RM_TowardZero, 0));
            coord_out.x++;
            coord.x++;
        }

        coord_out.y++;
    }
}

__kernel __attribute__((reqd_work_group_size(8, 1, 1))) void vxcSignalFrame_height(
    image2d_array_t input,
    image2d_array_t output,
                int frame_length,
                int step,
                int pad_end,
                int pad,
                int axis)
{
    int gidx = get_global_id(0);
    int gidy = get_global_id(1);
    int gidz = get_global_id(2);
    int outChn = gidz * output_channel + (gidy / step);
    int4 coord = (int4)(gidx, gidy, gidz, 0);
    int4 coord_out = (int4)(gidx, 0, outChn, 0);
    vxc_short8 src0;

    for(int i = 0; i < frame_length; i++)
    {
        coord.y = gidy + i;
        coord_out.y = i;
        VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),\
            VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
        VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    }
}

__kernel __attribute__((reqd_work_group_size(8, 1, 1))) void vxcSignalFrame_channel(
    image2d_array_t input,
    image2d_array_t output,
                int frame_length,
                int step,
                int pad_end,
                int pad,
                int axis)
{
    int gidx = get_global_id(0);
    int gidy = get_global_id(1);
    int gidz = get_global_id(2);
    int outChn = (gidz / step) * frame_length;
    int4 coord = (int4)(gidx, gidy, gidz, 0);
    int4 coord_out = (int4)(gidx, gidy, outChn, 0);
    vxc_short8 src0;

    for(int i = 0; i < frame_length; i++)
    {
        coord.z = gidz + i;
        coord_out.z = outChn + i;
        if(coord.z < input_channel)
        {
            VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
        }
        else
        {
            src0 = (vxc_short8)(0);
        }
        VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    }
}

__kernel __attribute__((reqd_work_group_size(8, 1, 1))) void vxcSignalFrame_width_8bit(
    image2d_array_t input,
    image2d_array_t output,
                int frame_length,
                int step,
                int pad_end,
                int pad,
                int axis)
{
    int gidx = get_global_id(0);
    int gidy = get_global_id(1);
    int gidz = get_global_id(2);
    int outChn = gidz * input_height + gidy;
    int4 coord = (int4)(0, gidy, gidz, 0);
    int4 coord_out = (int4)(0, 0, outChn, 0);

    int endcoord = (pad_end == 0) ? (input_width - frame_length + 1) : (input_width);
    int iter = frame_length / 8;
    int res = frame_length % 8;
    vxc_char8 src0;

    for(int i = 0; i < endcoord; i += step)
    {
        coord.x = i;
        for(int j = 0; j < iter; j++)
        {
            coord_out.x = j << 3;
            coord.x = i + (j << 3);
            VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
            VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
        }
        coord.x = i + (iter << 3);
        coord_out.x = (iter << 3);
        for(int j = 0; j < res; j++)
        {
            VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 0, 0, VXC_RM_TowardZero, 0));
            VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 0, 0, VXC_RM_TowardZero, 0));
            coord_out.x++;
            coord.x++;
        }

        coord_out.y++;
    }
}

__kernel __attribute__((reqd_work_group_size(8, 1, 1))) void vxcSignalFrame_height_8bit(
    image2d_array_t input,
    image2d_array_t output,
                int frame_length,
                int step,
                int pad_end,
                int pad,
                int axis)
{
    int gidx = get_global_id(0);
    int gidy = get_global_id(1);
    int gidz = get_global_id(2);
    int outChn = gidz * output_channel + (gidy / step);
    int4 coord = (int4)(gidx, gidy, gidz, 0);
    int4 coord_out = (int4)(gidx, 0, outChn, 0);
    vxc_char8 src0;

    for(int i = 0; i < frame_length; i++)
    {
        coord.y = gidy + i;
        coord_out.y = i;
        VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),\
            VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
        VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    }
}

__kernel __attribute__((reqd_work_group_size(8, 1, 1))) void vxcSignalFrame_channel_8bit(
    image2d_array_t input,
    image2d_array_t output,
                int frame_length,
                int step,
                int pad_end,
                int pad,
                int axis)
{
    int gidx = get_global_id(0);
    int gidy = get_global_id(1);
    int gidz = get_global_id(2);
    int outChn = (gidz / step) * frame_length;
    int4 coord = (int4)(gidx, gidy, gidz, 0);
    int4 coord_out = (int4)(gidx, gidy, outChn, 0);
    vxc_char8 src0;

    for(int i = 0; i < frame_length; i++)
    {
        coord.z = gidz + i;
        coord_out.z = outChn + i;
        if(coord.z < input_channel)
        {
            VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
        }
        else
        {
            src0 = (vxc_char8)(0);
        }
        VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
    }
}

#if 0
__kernel __attribute__((reqd_work_group_size(16, 1, 1))) void vxcSignalFrame_tensor(
    image2d_array_t input,
    image2d_array_t output,
    image2d_array_t frame_length,
    image2d_array_t steps,
    image2d_array_t pad_end,
    image2d_array_t pad,
    image2d_array_t axis)
{
    int gidx = get_global_id(0);
    int gidy = get_global_id(1);
    int gidz = get_global_id(2);
    int outChn = gidz * input_height + gidy;
    int4 coord = (int4)(0, gidy, gidz, 0);
    int4 coord_out = (int4)(0, 0, outChn, 0);
    int4 coord_para = (int4)(0, 0, 0, 0);

    int4 size = read_imagei(frame_length, coord_para);
    int4 step = read_imagei(steps, coord_para);
    int4 pe = read_imagei(pad_end, coord_para);
    int4 pd = read_imagei(pad, coord_para);
    int len = input_width + (pe.x ? pd : 0);
    int endcoord = len - size.x + 1;
    int iter = size.x / 8;
    int res = size.x % 8;
    vxc_short8 src0;

    for(int i = 0; i < endcoord; i += step.x)
    {
        coord.x = i;
        for(int j = 0; j < iter; j++)
        {
            coord_out.x = j << 3;
            coord.x += (j << 3);
            VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
            VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 7, 0, VXC_RM_TowardZero, 0));
        }
        coord.x = i + (iter << 3);
        coord_out.x = (iter << 3);
        for(int j = 0; j < res; j++)
        {
            VXC_ReadImage2DArray(src0, input, coord, VXC_5BITOFFSET_XY(0, 0),
                VXC_MODIFIER(0, 0, 0, VXC_RM_TowardZero, 0));
            VXC_WriteImage2DArray(output, coord_out, src0, VXC_MODIFIER(0, 0, 0, VXC_RM_TowardZero, 0));
            coord_out.x++;
            coord.x++;
        }

        coord_out.y++;
    }
}
#endif
