/*==========================================================================*/
/*     TEXAS INSTRUMENTS, INC.                                              */
/*                                                                          */
/*     NAME                                                                 */
/*         vcop_sobelX, sobelX function for the VICP library.               */
/*                                                                          */
/*S    REVISION HISTORY                                                    S*/
/*S    5/10/2010.......initial Version.....................Kamath S.       S*/
/*                                                                          */
/*                                                                          */
/*     USAGE                                                                */
/*     This routine is C-callable and can be called as:                     */
/*                                                                          */
/*     void vcop_sobelX_uchar_char                                          */
/*     (                                                                    */
/*          __vptr_uint8 *in,                                               */
/*          __vptr_uint8 *inter,                                            */
/*          __vptr_uint8 *out,                                              */
/*          int   img_w,                                                    */
/*          int   img_h,                                                    */
/*          int   out_w,                                                    */
/*          int   out_h,                                                    */
/*          int   comp_w,                                                   */
/*          int   comp_h,                                                   */
/*          int   in_type,                                                  */
/*          int   inter_type,                                               */
/*          int   out_type,                                                 */
/*          int   round_shift                                               */
/*      );                                                                  */
/*                                                                          */
/*     *in        :  Pointer to an input array of "in_type".                */
/*     *inter     :  Pointer to intermediate array of "inter_type". This    */
/*                   array stores the results of the first loop.            */
/*     *out       :  Pointer to output array of "out_type".                 */
/*     img_w      :  Width of input image in pixels.                        */
/*     img_h      :  Height of the input image in pixels.                   */
/*     out_w      :  Width of the output image in pixels.                   */
/*     out_h      :  Height of the input image in pixels.                   */
/*     comp_w     :  The compute width over which sobelX is done.           */
/*     comp_h     :  The compute height for sobelX function.                */
/*     in_type    :  0 - BYTE,  1 - SHORT                                   */
/*     inter_type :  0 - BYTE,  1 - SHORT                                   */
/*     out_type   :  0 - UBYTE, 1 - BYTE, 2 - USHORT, 3 - SHORT             */
/*     round_shift:  Rounding and shifting amount. Rounding is enabled if   */
/*                   shift amount is non-zero.                              */
/*                                                                          */
/*     Returns :  None or void.                                             */
/*                                                                          */
/*     DESCRIPTION                                                          */
/*             This routine accepts Pointers to a input region "in", and    */
/*     sobelX it over M X N pixels of the image. The image is               */
/*     split into blocks of size M X N and filtered.                        */
/*                                                                          */
/*     ASSUMPTIONS                                                          */
/*     -- M and N are assumed to be multiples of 16.                        */
/*     -- Compute width must be a multiple of 16, compute height should be  */
/*        (out_h + 2)                                                       */
/*     -- M should be at least 32 pixels (image width assuming padding)     */
/*     -- Ensure RND_SHIFT == round_shift amount from the calling function. */
/*                                                                          */
/*     CYCLES/PERFORMANCE                                                   */
/*     SOBELX-                                                              */
/*     -------                                                              */
/*     Non-separable version : 5/16 cyc/pix                                 */
/*     Separable version :  5/16 cyc/pix                                    */
/*     Magnitude: 0.125                                                     */
/*                                                                          */
/*     SOBELY-                                                              */
/*     -------                                                              */
/*     Separable version : 2.25/8 + 2/16 = 0.4 cyc/pix                      */
/*     Non-separable version :  5/16 = 0.31 cyc/pix                         */
/*                                                                          */
/*     Magnitude: 0.125                                                     */
/*                                                                          */
/*==========================================================================*/
/*      Copyright (C) 2009-2012 Texas Instruments Incorporated.             */
/*                      All Rights Reserved                                 */
/*==========================================================================*/

#define ELEMSZ          sizeof(*inX)
#define VECTORSZ        (VCOP_SIMD_WIDTH * ELEMSZ)

#define ELEMSZ_IN       sizeof(*in)
#define VECTORSZ_IN     (VCOP_SIMD_WIDTH * ELEMSZ_IN)

#define ELEMSZ_OUT      sizeof(*out)
#define VECTORSZ_OUT    ((VCOP_SIMD_WIDTH) * ELEMSZ_OUT)

#define ELEMSZ_INTER    sizeof(*inter)
#define ELEMSZ_COEF     sizeof(*coef)

#define WORD_SIZE       4
#define ELEMS_PER_WORD  (WORD_SIZE/ELEMSZ_IN)

#define SAT_LO          (-128)
#define SAT_HI          (127)
#define RND_SHIFT         3

#define VCOP_SIMD_WIDTH_X_2   (VCOP_SIMD_WIDTH * 2)

/*-----------------------------------------------------------------------*/
/* This is the separable version of the sobel X function.                */
/*-----------------------------------------------------------------------*/

void vcop_sobelX_3x3_uchar_char
(
     __vptr_uint8  in, 
     __vptr_int16  inter,
     __vptr_int8   out,
     int img_w,
     int img_h,
     int out_w,
     int out_h,
     int comp_w, 
     int comp_h,
     int in_type,
     int inter_type,	
     int out_type,
     int round_shift
)
{
    __vector Vin, Vin0_plus2, Vin1_plus2, Vout0, Vout1;
    __vector Vin0, Vin1, Vin2, Vin3, Vin4, Vin5;
    __vector Vsum0, Vsum1;

    /*-------------------------------------------------------------------*/
    /* This is the first loop where we implement 1-D horizontal filtering*/
    /* by applying [1 0 -1] to the image data.                           */
    /* Cycles: 2/16                                                      */
    /*-------------------------------------------------------------------*/

    for (int I1 = 0; I1 < comp_h; I1++)
    {
        for ( int I2 = 0; I2 < comp_w/VCOP_SIMD_WIDTH_X_2; I2++)   
        {
            __agen outAddr;
            __agen inAddr;
            
            inAddr = (I1 * img_w * ELEMSZ_IN) + (I2 * VCOP_SIMD_WIDTH_X_2 * ELEMSZ_IN);
            outAddr = (I1 * comp_w * ELEMSZ_INTER) + (I2 * VCOP_SIMD_WIDTH_X_2 * ELEMSZ_INTER);
                 
            (Vin0, Vin1)  =   in[inAddr].deinterleave();
            (Vin0_plus2, Vin1_plus2)   =   (in + (2 * ELEMSZ_IN))[inAddr].deinterleave();
      
            Vsum0 = Vin0 - Vin0_plus2;
            Vsum1 = Vin1 - Vin1_plus2;

           inter[outAddr].interleave() = (Vsum0, Vsum1);
        }
    }

    /*-------------------------------------------------------------------*/
    /* This is the second loop where we implement 1-D vertical filtering */
    /* by applying [1 2 1]' to the intermediate data.                    */
    /* Cycles: 3/16 cyc/pix (Memory access bound)                        */
    /*-------------------------------------------------------------------*/
   
    for (int I1 = 0; I1 < comp_h - 2; I1++)
    {
        
        /*---------------------------------------------------------------*/
        /* As we do deinterleaved loads, we can load 2 * VCOP_SIMD_WIDTH */
        /* amount of data at a time.                                     */
        /*---------------------------------------------------------------*/

        for ( int I2 = 0; I2 < comp_w/(2 * VCOP_SIMD_WIDTH); I2++)
        {
            __agen Addr0;
            __agen Addr1;

            Addr0 = (I1 * comp_w * ELEMSZ_INTER) + (I2 * 2 * VCOP_SIMD_WIDTH * ELEMSZ_INTER);
            Addr1 = (I1 * out_w * ELEMSZ_OUT) + (I2 * 2 * VCOP_SIMD_WIDTH * ELEMSZ_OUT);
           
            (Vin0, Vin1) = inter[Addr0].deinterleave();
            (Vin2, Vin3) = (inter + (comp_w * ELEMSZ_INTER))[Addr0].deinterleave();
            (Vin4, Vin5) = (inter + (2 * comp_w * ELEMSZ_INTER))[Addr0].deinterleave();
 
            Vout0 = Vin0 + Vin2; 
            Vout1 = Vin1 + Vin3; 

            Vout0 += Vin2 + Vin4;
            Vout1 += Vin3 + Vin5;

            out[Addr1].interleave() = (Vout0, Vout1).round( RND_SHIFT).saturate( SAT_LO, SAT_HI );
        }
    }
}




/*-----------------------------------------------------------------------*/
/* This is the separable version of the sobel function.                  */
/*-----------------------------------------------------------------------*/

void vcop_sobelY_3x3_uchar_char
(
     __vptr_uint8  in, 
     __vptr_int16  inter,
     __vptr_int8   out,
     int img_w,
     int img_h,
     int out_w,
     int out_h,
     int comp_w, 
     int comp_h,
     int in_type,
     int inter_type,
     int out_type,
     int round_shift
)
{
    __vector Vin,  Vin_plus1,  Vin_plus2, Vsum, Vtmp1, Vtmp2, Vout0, Vout1;
    __vector Vtmp, Vin_minus1, Vin_minus2;
    __vector Vin0, Vin1, Vin2, Vin3, V_2, Vctr;

    /*-------------------------------------------------------------------*/
    /* This is the first loop where we implement 1-D horizontal filtering*/
    /* by applying [1 2 1] to the image data.                            */
    /*-------------------------------------------------------------------*/

    for (int I1 = 0; I1 < comp_h; I1++)
    {
        for ( int I2 = 0; I2 < comp_w/VCOP_SIMD_WIDTH; I2++)
        {
            __agen outAddr;
            __agen inAddr;
            
            inAddr  = (I1 * img_w * ELEMSZ_IN) + (I2 * VCOP_SIMD_WIDTH * ELEMSZ_IN);
            outAddr = (I1 * comp_w * ELEMSZ_INTER) + (I2 * VCOP_SIMD_WIDTH * ELEMSZ_INTER);              
                 
            Vin         =   in[inAddr].npt();
            Vin_plus1   =   (in + ELEMSZ_IN)[inAddr].npt();
            Vin_plus2   =   (in + (2 * ELEMSZ_IN))[inAddr].npt();
      
            Vtmp1 = Vin       + Vin_plus1;
            Vtmp2 = Vin_plus1 + Vin_plus2;
            Vsum  = Vtmp1     + Vtmp2;
    
           inter[outAddr] = Vsum;

        }
    }

    /*-------------------------------------------------------------------*/
    /* This is the second loop where we implement 1-D vertical filtering */
    /* by applying [1 0 -1]' to the intermediate data.                   */
    /*-------------------------------------------------------------------*/
  
    for (int I1 = 0; I1 < comp_h - 2; I1++)
    {

        for ( int I2 = 0; I2 < comp_w/(2 * VCOP_SIMD_WIDTH); I2++)
        {
            __agen Addr0;
            __agen Addr1;

            Addr0   = (I1 * comp_w * ELEMSZ_INTER) + (I2 * 2 * VCOP_SIMD_WIDTH * ELEMSZ_INTER);
            Addr1   = (I1 * out_w * ELEMSZ_OUT) + (I2 * 2 * VCOP_SIMD_WIDTH * ELEMSZ_OUT);
           
            (Vin0, Vin1) = inter[Addr0].deinterleave();
            (Vin2, Vin3) = (inter + (2 * comp_w * ELEMSZ_INTER))[Addr0].deinterleave();
            
            Vout0 = Vin0 - Vin2; 
            Vout1 = Vin1 - Vin3; 

            out[Addr1].interleave() = (Vout0, Vout1).round(RND_SHIFT).saturate(SAT_LO, SAT_HI);

        }
    }
}

void vcop_sobel_magnitude
(
   __vptr_int8 inX,                // input image data
   __vptr_int8 inY,                // input image data
   __vptr_uint8 out,                // output image data
   unsigned short blk_w,            // image width
   unsigned short blk_h,            // image height
   unsigned short out_w
)
{
    __vector Vin1,   Vin2,   Vin3,     Vin4;
    __vector Vout_o,  Vout_e;
    __vector Vzero, Vone, Vsc, VT, V128, V255;

    Vzero =   0;
    Vsc   =   2;
    VT    =  20;
    V128  = 128;
    V255  = 255;
   

    for (int I1 = 0; I1 < blk_h; I1++)
    {
        for (int I2 = 0; I2 < blk_w/(2 * VCOP_SIMD_WIDTH); I2++)
        {
            __agen Addr_in;
            __agen Addr_ou;
      
            /* ----------------------------------------------------------- */
            /* Input and Output Address Increments                         */
            /* ----------------------------------------------------------- */
           
            Addr_in         = I2 * 2 * VECTORSZ + I1 * 2 * blk_w * ELEMSZ; 
            Addr_ou         = I2 * VECTORSZ + I1 * out_w * ELEMSZ; 

            (Vin1, Vin2)    = (inX + 2)[Addr_in].deinterleave();
            (Vin3, Vin4)    = (inY + 2)[Addr_in].deinterleave();

            Vout_e = abs(Vin1);
            Vout_o = abs(Vin2);

            Vout_e += abs(Vin3 - Vzero);
            Vout_o += abs(Vin4 - Vzero);

            /*-----------------------------------------------------------*/
            /* Here we use the sub-abs instruction to save a cycle.      */
            /* The subtracting if zero is a redundant step in order to   */
            /* save a cycle!                                             */
            /*-----------------------------------------------------------*/

            Vout_e += Vout_o;

        //    Vout_e = round(Vout_e, Vtwo);

       //     Vout_o = (Vout_e > VT);
            Vout_e *= Vsc;

            out[Addr_ou].npt() = Vout_e;

        }
    }
}
