fixed ocl::warpPerspective

fixed ocl::warpPerspective

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Zhang Ying, zhangying913@gmail.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

//wrapPerspective kernel
//support data types: CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4, and three interpolation methods: NN, Linear, Cubic.

#if defined (DOUBLE_SUPPORT)
#ifdef cl_khr_fp64
#pragma OPENCL EXTENSION cl_khr_fp64:enable
#elif defined (cl_amd_fp64)
#pragma OPENCL EXTENSION cl_amd_fp64:enable
#endif
typedef double F;
typedef double4 F4;
#define convert_F4 convert_double4
#else
typedef float F;
typedef float4 F4;
#define convert_F4 convert_float4
#endif

#define INTER_BITS 5
#define INTER_TAB_SIZE (1 << INTER_BITS)
#define INTER_SCALE 1.f/INTER_TAB_SIZE
#define AB_BITS max(10, (int)INTER_BITS)
#define AB_SCALE (1 << AB_BITS)
#define INTER_REMAP_COEF_BITS 15
#define INTER_REMAP_COEF_SCALE (1 << INTER_REMAP_COEF_BITS)

inline void interpolateCubic( float x, float* coeffs )
{
    const float A = -0.75f;

    coeffs[0] = ((A*(x + 1.f) - 5.0f*A)*(x + 1.f) + 8.0f*A)*(x + 1.f) - 4.0f*A;
    coeffs[1] = ((A + 2.f)*x - (A + 3.f))*x*x + 1.f;
    coeffs[2] = ((A + 2.f)*(1.f - x) - (A + 3.f))*(1.f - x)*(1.f - x) + 1.f;
    coeffs[3] = 1.f - coeffs[0] - coeffs[1] - coeffs[2];
}

/**********************************************8UC1*********************************************
***********************************************************************************************/
__kernel void warpPerspectiveNN_C1_D0(__global uchar const * restrict src, __global uchar * dst, int src_cols, int src_rows,
                                      int dst_cols, int dst_rows, int srcStep, int dstStep,
                                      int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        dx = (dx<<2) - (dst_offset&3);

        F4 DX = (F4)(dx, dx+1, dx+2, dx+3);
        F4 X0 = M[0]*DX + M[1]*dy + M[2];
        F4 Y0 = M[3]*DX + M[4]*dy + M[5];
        F4 W = M[6]*DX + M[7]*dy + M[8],one=1,zero=0;
        W = (W!=zero) ? one/W : zero;
        short4 X = convert_short4_sat_rte(X0*W);
        short4 Y = convert_short4_sat_rte(Y0*W);
        int4 sx = convert_int4(X);
        int4 sy = convert_int4(Y);

        int4 DXD = (int4)(dx, dx+1, dx+2, dx+3);
        __global uchar4 * d = (__global uchar4 *)(dst+dst_offset+dy*dstStep+dx);
        uchar4 dval = *d;
        int4 dcon = DXD >= 0 && DXD < dst_cols && dy >= 0 && dy < dst_rows;
        int4 scon = sx >= 0 && sx < src_cols && sy >= 0 && sy < src_rows;
        int4 spos = src_offset + sy * srcStep + sx;
        uchar4 sval;
        sval.s0 = scon.s0 ? src[spos.s0] : 0;
        sval.s1 = scon.s1 ? src[spos.s1] : 0;
        sval.s2 = scon.s2 ? src[spos.s2] : 0;
        sval.s3 = scon.s3 ? src[spos.s3] : 0;
        dval = convert_uchar4(dcon) != (uchar4)(0,0,0,0) ? sval : dval;
        *d = dval;
    }
}

__kernel void warpPerspectiveLinear_C1_D0(__global const uchar * restrict src, __global uchar * dst,
        int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
        int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        int sx = convert_short_sat(X >> INTER_BITS);
        int sy = convert_short_sat(Y >> INTER_BITS);
        int ay = (short)(Y & (INTER_TAB_SIZE-1));
        int ax = (short)(X & (INTER_TAB_SIZE-1));

        uchar v[4];
        int i;
#pragma unroll 4
        for(i=0; i<4;  i++)
            v[i] = (sx+(i&1) >= 0 && sx+(i&1) < src_cols && sy+(i>>1) >= 0 && sy+(i>>1) < src_rows) ? src[src_offset + (sy+(i>>1)) * srcStep + (sx+(i&1))] : (uchar)0;

        short itab[4];
        float tab1y[2], tab1x[2];
        tab1y[0] = 1.0 - 1.f/INTER_TAB_SIZE*ay;
        tab1y[1] = 1.f/INTER_TAB_SIZE*ay;
        tab1x[0] = 1.0 - 1.f/INTER_TAB_SIZE*ax;
        tab1x[1] = 1.f/INTER_TAB_SIZE*ax;

#pragma unroll 4
        for(i=0; i<4;  i++)
        {
            float v = tab1y[(i>>1)] * tab1x[(i&1)];
            itab[i] = convert_short_sat_rte( v * INTER_REMAP_COEF_SCALE );
        }
        if(dx >=0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            int sum = 0;
            for ( i =0; i<4; i++ )
            {
                sum += v[i] * itab[i] ;
            }
            dst[dst_offset+dy*dstStep+dx] = convert_uchar_sat ( (sum + (1 << (INTER_REMAP_COEF_BITS-1))) >> INTER_REMAP_COEF_BITS ) ;
        }
    }
}

__kernel void warpPerspectiveCubic_C1_D0(__global uchar * src, __global uchar * dst, int src_cols, int src_rows,
        int dst_cols, int dst_rows, int srcStep, int dstStep,
        int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = convert_short_sat(X >> INTER_BITS) - 1;
        short sy = convert_short_sat(Y >> INTER_BITS) - 1;
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        uchar v[16];
        int i, j;

#pragma unroll 4
        for(i=0; i<4;  i++)
            for(j=0; j<4;  j++)
            {
                v[i*4+j] = (sx+j >= 0 && sx+j < src_cols && sy+i >= 0 && sy+i < src_rows) ? src[src_offset+(sy+i) * srcStep + (sx+j)] : (uchar)0;
            }

        short itab[16];
        float tab1y[4], tab1x[4];
        float axx, ayy;

        ayy = 1.f/INTER_TAB_SIZE * ay;
        axx = 1.f/INTER_TAB_SIZE * ax;
        interpolateCubic(ayy, tab1y);
        interpolateCubic(axx, tab1x);

        int isum = 0;
#pragma unroll 16
        for( i=0; i<16; i++ )
        {
            F v = tab1y[(i>>2)] * tab1x[(i&3)];
            isum += itab[i] = convert_short_sat( rint( v * INTER_REMAP_COEF_SCALE ) );
        }
        if( isum != INTER_REMAP_COEF_SCALE )
        {
            int k1, k2;
            int diff = isum - INTER_REMAP_COEF_SCALE;
            int Mk1=2, Mk2=2, mk1=2, mk2=2;
            for( k1 = 2; k1 < 4; k1++ )
                for( k2 = 2; k2 < 4; k2++ )
                {
                    if( itab[(k1<<2)+k2] < itab[(mk1<<2)+mk2] )
                        mk1 = k1, mk2 = k2;
                    else if( itab[(k1<<2)+k2] > itab[(Mk1<<2)+Mk2] )
                        Mk1 = k1, Mk2 = k2;
                }
            diff<0 ? (itab[(Mk1<<2)+Mk2]=(short)(itab[(Mk1<<2)+Mk2]-diff)) : (itab[(mk1<<2)+mk2]=(short)(itab[(mk1<<2)+mk2]-diff));
        }

        if( dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            int sum=0;
            for ( i =0; i<16; i++ )
            {
                sum += v[i] * itab[i] ;
            }
            dst[dst_offset+dy*dstStep+dx] = convert_uchar_sat( (sum + (1 << (INTER_REMAP_COEF_BITS-1))) >> INTER_REMAP_COEF_BITS ) ;
        }
    }
}

/**********************************************8UC4*********************************************
***********************************************************************************************/

__kernel void warpPerspectiveNN_C4_D0(__global uchar4 const * restrict src, __global uchar4 * dst,
                                      int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
                                      int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? 1./W : 0.0;
        short sx = convert_short_sat_rte(X0*W);
        short sy = convert_short_sat_rte(Y0*W);

        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>2)+dy*(dstStep>>2)+dx]= (sx>=0 && sx<src_cols && sy>=0 && sy<src_rows) ? src[(src_offset>>2)+sy*(srcStep>>2)+sx] : (uchar4)0;
    }
}

__kernel void warpPerspectiveLinear_C4_D0(__global uchar4 const * restrict src, __global uchar4 * dst,
        int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
        int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>2);
        srcStep = (srcStep>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = convert_short_sat(X >> INTER_BITS);
        short sy = convert_short_sat(Y >> INTER_BITS);
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        int4 v0, v1, v2, v3;

        v0 = (sx >= 0 && sx < src_cols && sy >= 0 && sy < src_rows) ? convert_int4(src[src_offset+sy * srcStep + sx]) : (int4)0;
        v1 = (sx+1 >= 0 && sx+1 < src_cols && sy >= 0 && sy < src_rows) ? convert_int4(src[src_offset+sy * srcStep + sx+1]) : (int4)0;
        v2 = (sx >= 0 && sx < src_cols && sy+1 >= 0 && sy+1 < src_rows) ? convert_int4(src[src_offset+(sy+1) * srcStep + sx]) : (int4)0;
        v3 = (sx+1 >= 0 && sx+1 < src_cols && sy+1 >= 0 && sy+1 < src_rows) ? convert_int4(src[src_offset+(sy+1) * srcStep + sx+1]) : (int4)0;

        int itab0, itab1, itab2, itab3;
        float taby, tabx;
        taby = 1.f/INTER_TAB_SIZE*ay;
        tabx = 1.f/INTER_TAB_SIZE*ax;

        itab0 = convert_short_sat(rint( (1.0f-taby)*(1.0f-tabx) * INTER_REMAP_COEF_SCALE ));
        itab1 = convert_short_sat(rint( (1.0f-taby)*tabx * INTER_REMAP_COEF_SCALE ));
        itab2 = convert_short_sat(rint( taby*(1.0f-tabx) * INTER_REMAP_COEF_SCALE ));
        itab3 = convert_short_sat(rint( taby*tabx * INTER_REMAP_COEF_SCALE ));

        int4 val;
        val = v0 * itab0 +  v1 * itab1 + v2 * itab2 + v3 * itab3;

        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>2)+dy*(dstStep>>2)+dx] =  convert_uchar4_sat ( (val + (1 << (INTER_REMAP_COEF_BITS-1))) >> INTER_REMAP_COEF_BITS ) ;
    }
}

__kernel void warpPerspectiveCubic_C4_D0(__global uchar4 const * restrict src, __global uchar4 * dst,
        int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
        int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>2);
        srcStep = (srcStep>>2);
        dst_offset = (dst_offset>>2);
        dstStep = (dstStep>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = convert_short_sat(X >> INTER_BITS) - 1;
        short sy = convert_short_sat(Y >> INTER_BITS) - 1;
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        uchar4 v[16];
        int i,j;
#pragma unroll 4
        for(i=0; i<4; i++)
            for(j=0; j<4; j++)
            {
                v[i*4+j] = (sx+j >= 0 && sx+j < src_cols && sy+i >= 0 && sy+i < src_rows) ? (src[src_offset+(sy+i) * srcStep + (sx+j)])  : (uchar4)0;
            }
        int itab[16];
        float tab1y[4], tab1x[4];
        float axx, ayy;

        ayy = INTER_SCALE * ay;
        axx = INTER_SCALE * ax;
        interpolateCubic(ayy, tab1y);
        interpolateCubic(axx, tab1x);
        int isum = 0;

#pragma unroll 16
        for( i=0; i<16; i++ )
        {
            float tmp;
            tmp = tab1y[(i>>2)] * tab1x[(i&3)] * INTER_REMAP_COEF_SCALE;
            itab[i] = rint(tmp);
            isum += itab[i];
        }

        if( isum != INTER_REMAP_COEF_SCALE )
        {
            int k1, k2;
            int diff = isum - INTER_REMAP_COEF_SCALE;
            int Mk1=2, Mk2=2, mk1=2, mk2=2;

            for( k1 = 2; k1 < 4; k1++ )
                for( k2 = 2; k2 < 4; k2++ )
                {

                    if( itab[(k1<<2)+k2] < itab[(mk1<<2)+mk2] )
                        mk1 = k1, mk2 = k2;
                    else if( itab[(k1<<2)+k2] > itab[(Mk1<<2)+Mk2] )
                        Mk1 = k1, Mk2 = k2;
                }

            diff<0 ? (itab[(Mk1<<2)+Mk2]=(short)(itab[(Mk1<<2)+Mk2]-diff)) : (itab[(mk1<<2)+mk2]=(short)(itab[(mk1<<2)+mk2]-diff));
        }

        if( dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            int4 sum=0;
            for ( i =0; i<16; i++ )
            {
                sum += convert_int4(v[i]) * itab[i];
            }
            dst[dst_offset+dy*dstStep+dx] = convert_uchar4_sat( (sum + (1 << (INTER_REMAP_COEF_BITS-1))) >> INTER_REMAP_COEF_BITS ) ;
        }
    }
}

/**********************************************32FC1********************************************
***********************************************************************************************/

__kernel void warpPerspectiveNN_C1_D5(__global float * src, __global float * dst, int src_cols, int src_rows,
                                      int dst_cols, int dst_rows, int srcStep, int dstStep,
                                      int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? 1./W : 0.0;
        short sx = convert_short_sat_rte(X0*W);
        short sy = convert_short_sat_rte(Y0*W);

        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>2)+dy*dstStep+dx]= (sx>=0 && sx<src_cols && sy>=0 && sy<src_rows) ? src[(src_offset>>2)+sy*srcStep+sx] : 0;
    }
}

__kernel void warpPerspectiveLinear_C1_D5(__global float * src, __global float * dst, int src_cols, int src_rows,
        int dst_cols, int dst_rows, int srcStep, int dstStep,
        int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = convert_short_sat(X >> INTER_BITS);
        short sy = convert_short_sat(Y >> INTER_BITS);
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        float v0, v1, v2, v3;

        v0 = (sx >= 0 && sx < src_cols && sy >= 0 && sy < src_rows) ? src[src_offset+sy * srcStep + sx] : (float)0;
        v1 = (sx+1 >= 0 && sx+1 < src_cols && sy >= 0 && sy < src_rows) ? src[src_offset+sy * srcStep + sx+1] : (float)0;
        v2 = (sx >= 0 && sx < src_cols && sy+1 >= 0 && sy+1 < src_rows) ? src[src_offset+(sy+1) * srcStep + sx] : (float)0;
        v3 = (sx+1 >= 0 && sx+1 < src_cols && sy+1 >= 0 && sy+1 < src_rows) ? src[src_offset+(sy+1) * srcStep + sx+1] : (float)0;

        float tab[4];
        float taby[2], tabx[2];
        taby[0] = 1.0 - 1.f/INTER_TAB_SIZE*ay;
        taby[1] = 1.f/INTER_TAB_SIZE*ay;
        tabx[0] = 1.0 - 1.f/INTER_TAB_SIZE*ax;
        tabx[1] = 1.f/INTER_TAB_SIZE*ax;

        tab[0] = taby[0] * tabx[0];
        tab[1] = taby[0] * tabx[1];
        tab[2] = taby[1] * tabx[0];
        tab[3] = taby[1] * tabx[1];

        float sum = 0;
        sum += v0 * tab[0] +  v1 * tab[1] +  v2 * tab[2] +  v3 * tab[3];
        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>2)+dy*dstStep+dx] = sum;
    }
}

__kernel void warpPerspectiveCubic_C1_D5(__global float * src, __global float * dst, int src_cols, int src_rows,
        int dst_cols, int dst_rows, int srcStep, int dstStep,
        int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>2);
        dst_offset = (dst_offset>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = convert_short_sat(X >> INTER_BITS) - 1;
        short sy = convert_short_sat(Y >> INTER_BITS) - 1;
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        float v[16];
        int i;

        for(i=0; i<16;  i++)
            v[i] = (sx+(i&3) >= 0 && sx+(i&3) < src_cols && sy+(i>>2) >= 0 && sy+(i>>2) < src_rows) ? src[src_offset+(sy+(i>>2)) * srcStep + (sx+(i&3))] : (float)0;

        float tab[16];
        float tab1y[4], tab1x[4];
        float axx, ayy;

        ayy = 1.f/INTER_TAB_SIZE * ay;
        axx = 1.f/INTER_TAB_SIZE * ax;
        interpolateCubic(ayy, tab1y);
        interpolateCubic(axx, tab1x);

#pragma unroll 4
        for( i=0; i<16; i++ )
        {
            tab[i] = tab1y[(i>>2)] * tab1x[(i&3)];
        }

        if( dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            float sum = 0;
#pragma unroll 4
            for ( i =0; i<16; i++ )
            {
                sum += v[i] * tab[i];
            }
            dst[dst_offset+dy*dstStep+dx] = sum;

        }
    }
}

/**********************************************32FC4********************************************
***********************************************************************************************/

__kernel void warpPerspectiveNN_C4_D5(__global float4 * src, __global float4 * dst, int src_cols, int src_rows,
                                      int dst_cols, int dst_rows, int srcStep, int dstStep,
                                      int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W =(W != 0.0)? 1./W : 0.0;
        short sx = convert_short_sat_rte(X0*W);
        short sy = convert_short_sat_rte(Y0*W);

        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>4)+dy*(dstStep>>2)+dx]= (sx>=0 && sx<src_cols && sy>=0 && sy<src_rows) ? src[(src_offset>>4)+sy*(srcStep>>2)+sx] : (float)0;
    }
}

__kernel void warpPerspectiveLinear_C4_D5(__global float4 * src, __global float4 * dst, int src_cols, int src_rows,
        int dst_cols, int dst_rows, int srcStep, int dstStep,
        int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>4);
        dst_offset = (dst_offset>>4);
        srcStep = (srcStep>>2);
        dstStep = (dstStep>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx0 = convert_short_sat(X >> INTER_BITS);
        short sy0 = convert_short_sat(Y >> INTER_BITS);
        short ay0 = (short)(Y & (INTER_TAB_SIZE-1));
        short ax0 = (short)(X & (INTER_TAB_SIZE-1));

        float4 v0, v1, v2, v3;

        v0 = (sx0 >= 0 && sx0 < src_cols && sy0 >= 0 && sy0 < src_rows) ? src[src_offset+sy0 * srcStep + sx0] : (float4)0;
        v1 = (sx0+1 >= 0 && sx0+1 < src_cols && sy0 >= 0 && sy0 < src_rows) ? src[src_offset+sy0 * srcStep + sx0+1] : (float4)0;
        v2 = (sx0 >= 0 && sx0 < src_cols && sy0+1 >= 0 && sy0+1 < src_rows) ? src[src_offset+(sy0+1) * srcStep + sx0] : (float4)0;
        v3 = (sx0+1 >= 0 && sx0+1 < src_cols && sy0+1 >= 0 && sy0+1 < src_rows) ? src[src_offset+(sy0+1) * srcStep + sx0+1] : (float4)0;

        float tab[4];
        float taby[2], tabx[2];
        taby[0] = 1.0 - 1.f/INTER_TAB_SIZE*ay0;
        taby[1] = 1.f/INTER_TAB_SIZE*ay0;
        tabx[0] = 1.0 - 1.f/INTER_TAB_SIZE*ax0;
        tabx[1] = 1.f/INTER_TAB_SIZE*ax0;

        tab[0] = taby[0] * tabx[0];
        tab[1] = taby[0] * tabx[1];
        tab[2] = taby[1] * tabx[0];
        tab[3] = taby[1] * tabx[1];

        float4 sum = 0;
        sum += v0 * tab[0] +  v1 * tab[1] +  v2 * tab[2] +  v3 * tab[3];
        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[dst_offset+dy*dstStep+dx] = sum;
    }
}

__kernel void warpPerspectiveCubic_C4_D5(__global float4 * src, __global float4 * dst,
        int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
        int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows )
    {
        src_offset = (src_offset>>4);
        dst_offset = (dst_offset>>4);
        srcStep = (srcStep>>2);
        dstStep = (dstStep>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = convert_short_sat(X >> INTER_BITS)-1;
        short sy = convert_short_sat(Y >> INTER_BITS)-1;
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        float4 v[16];
        int i;

        for(i=0; i<16;  i++)
            v[i] = (sx+(i&3) >= 0 && sx+(i&3) < src_cols && sy+(i>>2) >= 0 && sy+(i>>2) < src_rows) ? src[src_offset+(sy+(i>>2)) * srcStep + (sx+(i&3))] : (float4)0;

        float tab[16];
        float tab1y[4], tab1x[4];
        float axx, ayy;

        ayy = 1.f/INTER_TAB_SIZE * ay;
        axx = 1.f/INTER_TAB_SIZE * ax;
        interpolateCubic(ayy, tab1y);
        interpolateCubic(axx, tab1x);

#pragma unroll 4
        for( i=0; i<16; i++ )
        {
            tab[i] = tab1y[(i>>2)] * tab1x[(i&3)];
        }

        if( dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            float4 sum = 0;
#pragma unroll 4
            for ( i =0; i<16; i++ )
            {
                sum += v[i] * tab[i];
            }
            dst[dst_offset+dy*dstStep+dx] = sum;

        }
    }
}

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Zhang Ying, zhangying913@gmail.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

//wrapPerspective kernel
//support data types: CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4, and three interpolation methods: NN, Linear, Cubic.

#if defined (DOUBLE_SUPPORT)
#ifdef cl_khr_fp64
#pragma OPENCL EXTENSION cl_khr_fp64:enable
#elif defined (cl_amd_fp64)
#pragma OPENCL EXTENSION cl_amd_fp64:enable
#endif
typedef double F;
typedef double4 F4;
#define convert_F4 convert_double4
#else
typedef float F;
typedef float4 F4;
#define convert_F4 convert_float4
#endif

#define INTER_BITS 5
#define INTER_TAB_SIZE (1 << INTER_BITS)
#define INTER_SCALE 1.f/INTER_TAB_SIZE
#define AB_BITS max(10, (int)INTER_BITS)
#define AB_SCALE (1 << AB_BITS)
#define INTER_REMAP_COEF_BITS 15
#define INTER_REMAP_COEF_SCALE (1 << INTER_REMAP_COEF_BITS)

inline void interpolateCubic( float x, float* coeffs )
{
    const float A = -0.75f;

    coeffs[0] = ((A*(x + 1.f) - 5.0f*A)*(x + 1.f) + 8.0f*A)*(x + 1.f) - 4.0f*A;
    coeffs[1] = ((A + 2.f)*x - (A + 3.f))*x*x + 1.f;
    coeffs[2] = ((A + 2.f)*(1.f - x) - (A + 3.f))*(1.f - x)*(1.f - x) + 1.f;
    coeffs[3] = 1.f - coeffs[0] - coeffs[1] - coeffs[2];
}

/**********************************************8UC1*********************************************
***********************************************************************************************/
__kernel void warpPerspectiveNN_C1_D0(__global uchar const * restrict src, __global uchar * dst, int src_cols, int src_rows,
                                      int dst_cols, int dst_rows, int srcStep, int dstStep,
                                      int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        dx = (dx<<2) - (dst_offset&3);

        F4 DX = (F4)(dx, dx+1, dx+2, dx+3);
        F4 X0 = M[0]*DX + M[1]*dy + M[2];
        F4 Y0 = M[3]*DX + M[4]*dy + M[5];
        F4 W = M[6]*DX + M[7]*dy + M[8],one=1,zero=0;
        W = (W!=zero) ? one/W : zero;
        short4 X = convert_short4(rint(X0*W));
        short4 Y = convert_short4(rint(Y0*W));
        int4 sx = convert_int4(X);
        int4 sy = convert_int4(Y);

        int4 DXD = (int4)(dx, dx+1, dx+2, dx+3);
        __global uchar4 * d = (__global uchar4 *)(dst+dst_offset+dy*dstStep+dx);
        uchar4 dval = *d;
        int4 dcon = DXD >= 0 && DXD < dst_cols && dy >= 0 && dy < dst_rows;
        int4 scon = sx >= 0 && sx < src_cols && sy >= 0 && sy < src_rows;
        int4 spos = src_offset + sy * srcStep + sx;
        uchar4 sval;
        sval.s0 = scon.s0 ? src[spos.s0] : 0;
        sval.s1 = scon.s1 ? src[spos.s1] : 0;
        sval.s2 = scon.s2 ? src[spos.s2] : 0;
        sval.s3 = scon.s3 ? src[spos.s3] : 0;
        dval = convert_uchar4(dcon) != (uchar4)(0,0,0,0) ? sval : dval;
        *d = dval;
    }
}

__kernel void warpPerspectiveLinear_C1_D0(__global const uchar * restrict src, __global uchar * dst,
        int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
        int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        int sx = (short)(X >> INTER_BITS);
        int sy = (short)(Y >> INTER_BITS);
        int ay = (short)(Y & (INTER_TAB_SIZE-1));
        int ax = (short)(X & (INTER_TAB_SIZE-1));

        uchar v[4];
        int i;
#pragma unroll 4
        for(i=0; i<4;  i++)
            v[i] = (sx+(i&1) >= 0 && sx+(i&1) < src_cols && sy+(i>>1) >= 0 && sy+(i>>1) < src_rows) ? src[src_offset + (sy+(i>>1)) * srcStep + (sx+(i&1))] : (uchar)0;

        short itab[4];
        float tab1y[2], tab1x[2];
        tab1y[0] = 1.0 - 1.f/INTER_TAB_SIZE*ay;
        tab1y[1] = 1.f/INTER_TAB_SIZE*ay;
        tab1x[0] = 1.0 - 1.f/INTER_TAB_SIZE*ax;
        tab1x[1] = 1.f/INTER_TAB_SIZE*ax;

#pragma unroll 4
        for(i=0; i<4;  i++)
        {
            float v = tab1y[(i>>1)] * tab1x[(i&1)];
            itab[i] = convert_short_sat(rint( v * INTER_REMAP_COEF_SCALE ));
        }
        if(dx >=0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            int sum = 0;
            for ( i =0; i<4; i++ )
            {
                sum += v[i] * itab[i] ;
            }
            dst[dst_offset+dy*dstStep+dx] = convert_uchar_sat ( (sum + (1 << (INTER_REMAP_COEF_BITS-1))) >> INTER_REMAP_COEF_BITS ) ;
        }
    }
}

__kernel void warpPerspectiveCubic_C1_D0(__global uchar * src, __global uchar * dst, int src_cols, int src_rows,
        int dst_cols, int dst_rows, int srcStep, int dstStep,
        int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = (short)(X >> INTER_BITS) - 1;
        short sy = (short)(Y >> INTER_BITS) - 1;
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        uchar v[16];
        int i, j;

#pragma unroll 4
        for(i=0; i<4;  i++)
            for(j=0; j<4;  j++)
            {
                v[i*4+j] = (sx+j >= 0 && sx+j < src_cols && sy+i >= 0 && sy+i < src_rows) ? src[src_offset+(sy+i) * srcStep + (sx+j)] : (uchar)0;
            }

        short itab[16];
        float tab1y[4], tab1x[4];
        float axx, ayy;

        ayy = 1.f/INTER_TAB_SIZE * ay;
        axx = 1.f/INTER_TAB_SIZE * ax;
        interpolateCubic(ayy, tab1y);
        interpolateCubic(axx, tab1x);

        int isum = 0;
#pragma unroll 16
        for( i=0; i<16; i++ )
        {
            F v = tab1y[(i>>2)] * tab1x[(i&3)];
            isum += itab[i] = convert_short_sat( rint( v * INTER_REMAP_COEF_SCALE ) );
        }
        if( isum != INTER_REMAP_COEF_SCALE )
        {
            int k1, k2;
            int diff = isum - INTER_REMAP_COEF_SCALE;
            int Mk1=2, Mk2=2, mk1=2, mk2=2;
            for( k1 = 2; k1 < 4; k1++ )
                for( k2 = 2; k2 < 4; k2++ )
                {
                    if( itab[(k1<<2)+k2] < itab[(mk1<<2)+mk2] )
                        mk1 = k1, mk2 = k2;
                    else if( itab[(k1<<2)+k2] > itab[(Mk1<<2)+Mk2] )
                        Mk1 = k1, Mk2 = k2;
                }
            diff<0 ? (itab[(Mk1<<2)+Mk2]=(short)(itab[(Mk1<<2)+Mk2]-diff)) : (itab[(mk1<<2)+mk2]=(short)(itab[(mk1<<2)+mk2]-diff));
        }

        if( dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            int sum=0;
            for ( i =0; i<16; i++ )
            {
                sum += v[i] * itab[i] ;
            }
            dst[dst_offset+dy*dstStep+dx] = convert_uchar_sat( (sum + (1 << (INTER_REMAP_COEF_BITS-1))) >> INTER_REMAP_COEF_BITS ) ;
        }
    }
}

/**********************************************8UC4*********************************************
***********************************************************************************************/

__kernel void warpPerspectiveNN_C4_D0(__global uchar4 const * restrict src, __global uchar4 * dst,
                                      int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
                                      int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? 1./W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);
        short sx = (short)X;
        short sy = (short)Y;

        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>2)+dy*(dstStep>>2)+dx]= (sx>=0 && sx<src_cols && sy>=0 && sy<src_rows) ? src[(src_offset>>2)+sy*(srcStep>>2)+sx] : (uchar4)0;
    }
}

__kernel void warpPerspectiveLinear_C4_D0(__global uchar4 const * restrict src, __global uchar4 * dst,
        int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
        int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>2);
        srcStep = (srcStep>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = (short)(X >> INTER_BITS);
        short sy = (short)(Y >> INTER_BITS);
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        int4 v0, v1, v2, v3;

        v0 = (sx >= 0 && sx < src_cols && sy >= 0 && sy < src_rows) ? convert_int4(src[src_offset+sy * srcStep + sx]) : (int4)0;
        v1 = (sx+1 >= 0 && sx+1 < src_cols && sy >= 0 && sy < src_rows) ? convert_int4(src[src_offset+sy * srcStep + sx+1]) : (int4)0;
        v2 = (sx >= 0 && sx < src_cols && sy+1 >= 0 && sy+1 < src_rows) ? convert_int4(src[src_offset+(sy+1) * srcStep + sx]) : (int4)0;
        v3 = (sx+1 >= 0 && sx+1 < src_cols && sy+1 >= 0 && sy+1 < src_rows) ? convert_int4(src[src_offset+(sy+1) * srcStep + sx+1]) : (int4)0;

        int itab0, itab1, itab2, itab3;
        float taby, tabx;
        taby = 1.f/INTER_TAB_SIZE*ay;
        tabx = 1.f/INTER_TAB_SIZE*ax;

        itab0 = convert_short_sat(rint( (1.0f-taby)*(1.0f-tabx) * INTER_REMAP_COEF_SCALE ));
        itab1 = convert_short_sat(rint( (1.0f-taby)*tabx * INTER_REMAP_COEF_SCALE ));
        itab2 = convert_short_sat(rint( taby*(1.0f-tabx) * INTER_REMAP_COEF_SCALE ));
        itab3 = convert_short_sat(rint( taby*tabx * INTER_REMAP_COEF_SCALE ));

        int4 val;
        val = v0 * itab0 +  v1 * itab1 + v2 * itab2 + v3 * itab3;

        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>2)+dy*(dstStep>>2)+dx] =  convert_uchar4_sat ( (val + (1 << (INTER_REMAP_COEF_BITS-1))) >> INTER_REMAP_COEF_BITS ) ;
    }
}

__kernel void warpPerspectiveCubic_C4_D0(__global uchar4 const * restrict src, __global uchar4 * dst,
        int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
        int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>2);
        srcStep = (srcStep>>2);
        dst_offset = (dst_offset>>2);
        dstStep = (dstStep>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = (short)(X >> INTER_BITS) - 1;
        short sy = (short)(Y >> INTER_BITS) - 1;
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        uchar4 v[16];
        int i,j;
#pragma unroll 4
        for(i=0; i<4; i++)
            for(j=0; j<4; j++)
            {
                v[i*4+j] = (sx+j >= 0 && sx+j < src_cols && sy+i >= 0 && sy+i < src_rows) ? (src[src_offset+(sy+i) * srcStep + (sx+j)])  : (uchar4)0;
            }
        int itab[16];
        float tab1y[4], tab1x[4];
        float axx, ayy;

        ayy = INTER_SCALE * ay;
        axx = INTER_SCALE * ax;
        interpolateCubic(ayy, tab1y);
        interpolateCubic(axx, tab1x);
        int isum = 0;

#pragma unroll 16
        for( i=0; i<16; i++ )
        {
            float tmp;
            tmp = tab1y[(i>>2)] * tab1x[(i&3)] * INTER_REMAP_COEF_SCALE;
            itab[i] = rint(tmp);
            isum += itab[i];
        }

        if( isum != INTER_REMAP_COEF_SCALE )
        {
            int k1, k2;
            int diff = isum - INTER_REMAP_COEF_SCALE;
            int Mk1=2, Mk2=2, mk1=2, mk2=2;

            for( k1 = 2; k1 < 4; k1++ )
                for( k2 = 2; k2 < 4; k2++ )
                {

                    if( itab[(k1<<2)+k2] < itab[(mk1<<2)+mk2] )
                        mk1 = k1, mk2 = k2;
                    else if( itab[(k1<<2)+k2] > itab[(Mk1<<2)+Mk2] )
                        Mk1 = k1, Mk2 = k2;
                }

            diff<0 ? (itab[(Mk1<<2)+Mk2]=(short)(itab[(Mk1<<2)+Mk2]-diff)) : (itab[(mk1<<2)+mk2]=(short)(itab[(mk1<<2)+mk2]-diff));
        }

        if( dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            int4 sum=0;
            for ( i =0; i<16; i++ )
            {
                sum += convert_int4(v[i]) * itab[i];
            }
            dst[dst_offset+dy*dstStep+dx] = convert_uchar4_sat( (sum + (1 << (INTER_REMAP_COEF_BITS-1))) >> INTER_REMAP_COEF_BITS ) ;
        }
    }
}

/**********************************************32FC1********************************************
***********************************************************************************************/

__kernel void warpPerspectiveNN_C1_D5(__global float * src, __global float * dst, int src_cols, int src_rows,
                                      int dst_cols, int dst_rows, int srcStep, int dstStep,
                                      int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? 1./W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);
        short sx = (short)X;
        short sy = (short)Y;

        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>2)+dy*dstStep+dx]= (sx>=0 && sx<src_cols && sy>=0 && sy<src_rows) ? src[(src_offset>>2)+sy*srcStep+sx] : 0;
    }
}

__kernel void warpPerspectiveLinear_C1_D5(__global float * src, __global float * dst, int src_cols, int src_rows,
        int dst_cols, int dst_rows, int srcStep, int dstStep,
        int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = (short)(X >> INTER_BITS);
        short sy = (short)(Y >> INTER_BITS);
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        float v0, v1, v2, v3;

        v0 = (sx >= 0 && sx < src_cols && sy >= 0 && sy < src_rows) ? src[src_offset+sy * srcStep + sx] : (float)0;
        v1 = (sx+1 >= 0 && sx+1 < src_cols && sy >= 0 && sy < src_rows) ? src[src_offset+sy * srcStep + sx+1] : (float)0;
        v2 = (sx >= 0 && sx < src_cols && sy+1 >= 0 && sy+1 < src_rows) ? src[src_offset+(sy+1) * srcStep + sx] : (float)0;
        v3 = (sx+1 >= 0 && sx+1 < src_cols && sy+1 >= 0 && sy+1 < src_rows) ? src[src_offset+(sy+1) * srcStep + sx+1] : (float)0;

        float tab[4];
        float taby[2], tabx[2];
        taby[0] = 1.0 - 1.f/INTER_TAB_SIZE*ay;
        taby[1] = 1.f/INTER_TAB_SIZE*ay;
        tabx[0] = 1.0 - 1.f/INTER_TAB_SIZE*ax;
        tabx[1] = 1.f/INTER_TAB_SIZE*ax;

        tab[0] = taby[0] * tabx[0];
        tab[1] = taby[0] * tabx[1];
        tab[2] = taby[1] * tabx[0];
        tab[3] = taby[1] * tabx[1];

        float sum = 0;
        sum += v0 * tab[0] +  v1 * tab[1] +  v2 * tab[2] +  v3 * tab[3];
        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>2)+dy*dstStep+dx] = sum;
    }
}

__kernel void warpPerspectiveCubic_C1_D5(__global float * src, __global float * dst, int src_cols, int src_rows,
        int dst_cols, int dst_rows, int srcStep, int dstStep,
        int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>2);
        dst_offset = (dst_offset>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = (short)(X >> INTER_BITS) - 1;
        short sy = (short)(Y >> INTER_BITS) - 1;
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        float v[16];
        int i;

        for(i=0; i<16;  i++)
            v[i] = (sx+(i&3) >= 0 && sx+(i&3) < src_cols && sy+(i>>2) >= 0 && sy+(i>>2) < src_rows) ? src[src_offset+(sy+(i>>2)) * srcStep + (sx+(i&3))] : (float)0;

        float tab[16];
        float tab1y[4], tab1x[4];
        float axx, ayy;

        ayy = 1.f/INTER_TAB_SIZE * ay;
        axx = 1.f/INTER_TAB_SIZE * ax;
        interpolateCubic(ayy, tab1y);
        interpolateCubic(axx, tab1x);

#pragma unroll 4
        for( i=0; i<16; i++ )
        {
            tab[i] = tab1y[(i>>2)] * tab1x[(i&3)];
        }

        if( dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            float sum = 0;
#pragma unroll 4
            for ( i =0; i<16; i++ )
            {
                sum += v[i] * tab[i];
            }
            dst[dst_offset+dy*dstStep+dx] = sum;

        }
    }
}

/**********************************************32FC4********************************************
***********************************************************************************************/

__kernel void warpPerspectiveNN_C4_D5(__global float4 * src, __global float4 * dst, int src_cols, int src_rows,
                                      int dst_cols, int dst_rows, int srcStep, int dstStep,
                                      int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W =(W != 0.0)? 1./W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);
        short sx = (short)X;
        short sy = (short)Y;

        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[(dst_offset>>4)+dy*(dstStep>>2)+dx]= (sx>=0 && sx<src_cols && sy>=0 && sy<src_rows) ? src[(src_offset>>4)+sy*(srcStep>>2)+sx] : (float)0;
    }
}

__kernel void warpPerspectiveLinear_C4_D5(__global float4 * src, __global float4 * dst, int src_cols, int src_rows,
        int dst_cols, int dst_rows, int srcStep, int dstStep,
        int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows)
    {
        src_offset = (src_offset>>4);
        dst_offset = (dst_offset>>4);
        srcStep = (srcStep>>2);
        dstStep = (dstStep>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx0 = (short)(X >> INTER_BITS);
        short sy0 = (short)(Y >> INTER_BITS);
        short ay0 = (short)(Y & (INTER_TAB_SIZE-1));
        short ax0 = (short)(X & (INTER_TAB_SIZE-1));

        float4 v0, v1, v2, v3;

        v0 = (sx0 >= 0 && sx0 < src_cols && sy0 >= 0 && sy0 < src_rows) ? src[src_offset+sy0 * srcStep + sx0] : (float4)0;
        v1 = (sx0+1 >= 0 && sx0+1 < src_cols && sy0 >= 0 && sy0 < src_rows) ? src[src_offset+sy0 * srcStep + sx0+1] : (float4)0;
        v2 = (sx0 >= 0 && sx0 < src_cols && sy0+1 >= 0 && sy0+1 < src_rows) ? src[src_offset+(sy0+1) * srcStep + sx0] : (float4)0;
        v3 = (sx0+1 >= 0 && sx0+1 < src_cols && sy0+1 >= 0 && sy0+1 < src_rows) ? src[src_offset+(sy0+1) * srcStep + sx0+1] : (float4)0;

        float tab[4];
        float taby[2], tabx[2];
        taby[0] = 1.0 - 1.f/INTER_TAB_SIZE*ay0;
        taby[1] = 1.f/INTER_TAB_SIZE*ay0;
        tabx[0] = 1.0 - 1.f/INTER_TAB_SIZE*ax0;
        tabx[1] = 1.f/INTER_TAB_SIZE*ax0;

        tab[0] = taby[0] * tabx[0];
        tab[1] = taby[0] * tabx[1];
        tab[2] = taby[1] * tabx[0];
        tab[3] = taby[1] * tabx[1];

        float4 sum = 0;
        sum += v0 * tab[0] +  v1 * tab[1] +  v2 * tab[2] +  v3 * tab[3];
        if(dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
            dst[dst_offset+dy*dstStep+dx] = sum;
    }
}

__kernel void warpPerspectiveCubic_C4_D5(__global float4 * src, __global float4 * dst,
        int src_cols, int src_rows, int dst_cols, int dst_rows, int srcStep,
        int dstStep, int src_offset, int dst_offset,  __constant F * M, int threadCols )
{
    int dx = get_global_id(0);
    int dy = get_global_id(1);

    if( dx < threadCols && dy < dst_rows )
    {
        src_offset = (src_offset>>4);
        dst_offset = (dst_offset>>4);
        srcStep = (srcStep>>2);
        dstStep = (dstStep>>2);

        F X0 = M[0]*dx + M[1]*dy + M[2];
        F Y0 = M[3]*dx + M[4]*dy + M[5];
        F W = M[6]*dx + M[7]*dy + M[8];
        W = (W != 0.0) ? INTER_TAB_SIZE/W : 0.0;
        int X = rint(X0*W);
        int Y = rint(Y0*W);

        short sx = (short)(X >> INTER_BITS)-1;
        short sy = (short)(Y >> INTER_BITS)-1;
        short ay = (short)(Y & (INTER_TAB_SIZE-1));
        short ax = (short)(X & (INTER_TAB_SIZE-1));

        float4 v[16];
        int i;

        for(i=0; i<16;  i++)
            v[i] = (sx+(i&3) >= 0 && sx+(i&3) < src_cols && sy+(i>>2) >= 0 && sy+(i>>2) < src_rows) ? src[src_offset+(sy+(i>>2)) * srcStep + (sx+(i&3))] : (float4)0;

        float tab[16];
        float tab1y[4], tab1x[4];
        float axx, ayy;

        ayy = 1.f/INTER_TAB_SIZE * ay;
        axx = 1.f/INTER_TAB_SIZE * ax;
        interpolateCubic(ayy, tab1y);
        interpolateCubic(axx, tab1x);

#pragma unroll 4
        for( i=0; i<16; i++ )
        {
            tab[i] = tab1y[(i>>2)] * tab1x[(i&3)];
        }

        if( dx >= 0 && dx < dst_cols && dy >= 0 && dy < dst_rows)
        {
            float4 sum = 0;
#pragma unroll 4
            for ( i =0; i<16; i++ )
            {
                sum += v[i] * tab[i];
            }
            dst[dst_offset+dy*dstStep+dx] = sum;

        }
    }
}


Fix comment

Fix comment

#ifndef __ga_utils__
#define __ga_utils__

#include "Noise.cl"

/**
 * prints the value of chromosomes. We can also use this function to print a
 * single chromome with 1 value of num_of_chromosomes.
 * @param *chromosomes (global) the reference of chromosomes array
 * @param size_of_chromosome the size of a single chromesome
 * @param num_of_chromosomes the number of chromosomes in this array.
 * @param *fitnesses (global) the fitness array of all chromosomes. The size of
 *        this array is num_of_chromosomes.
 */
void print_chromosomes(global int* chromosomes, int size_of_chromosome,
                       int num_of_chromosomes, global float* fitnesses)
{
  int idx = get_global_id(0);
  if (idx > 0) {
    // We use this function to dump all of chromosomes. In most of the cases,
    // we shouldn't let all threads to print result because it may give us too
    // many information. So, the first thread is the only one can dump infos.
    return;
  }
  for (int c = 0; c < num_of_chromosomes; c++) {
    int start = c * size_of_chromosome;
    printf("Chromosome[%d]/dist[%f]:", c, fitnesses[c]);
    for (int i = 0; i < size_of_chromosome; i++) {
        printf("->(%d)", chromosomes[start+i]);
    }
    printf("\n");
  }
  printf("\n");
}

/**
 * rand generates a random number between 0 to max value of uint.
 * NOTE : Since we cannot create a real random number in kernel,
 *        By passing in a random value from python, and storing the last
 *        random value generated from table, we could simulate a pesudo random
 *        number in kernel.
 * @param *holder a pointer of uint for storing the last rand value.
 * @return a random uint value.
 */
uint rand(uint* holder)
{
  uint b = ParallelRNG(holder[0]);
  uint c = ParallelRNG2(b, holder[0]);
  uint d = ParallelRNG3(c, b, holder[0]);
  holder[0] = c;
  return d;
}

/**
 * rand_range generates a random number between 0 <= return_vlue < range.
 * @param *holder a pointer of uint for storing the last rand value.
 * @param range the max value of random number.
 * @return a random uint value in the range.
 */
uint rand_range(uint* holder, uint range)
{
  uint r = rand(holder) % range;
  return r;
}

/**
 * rand_range_exclude generates a random number between 0 < return_vlue < range.
 * But the value aExcluded is excluded.
 * @param *holder a pointer of uint for storing the last rand value.
 * @param range the max value of random number.
 * @param aExclude the excluded value
 * @return a random uint value in the range except aExcluded.
 */
uint rand_range_exclude(uint* holder, uint range, uint aExcluded)
{
  uint r = rand(holder) % (range - 1);
  return r == aExcluded ? range - 1 : r;
}

/**
 * rand_prob generates a random number between 0 < return_vlue < 1 in float.
 * @param *holder a pointer of uint for storing the last rand value.
 * @return a random float value.
 */
float rand_prob(uint* holder)
{
  uint r = rand(holder);
  float p = r / (float)UINT_MAX;
  return p;
}

/**
 * initialze the random seed.
 * @param seed the reandom seed.
 * @param *holder a pointer of uint for storing the last rand value.
 */
void init_rand(int seed, uint* holder)
{
  holder[0] = ParallelRNG(seed);
}

/**
 * random choose a chromosome based on the ratio. For GA, we need to choose a
 * chromosome for crossover based on fitnesses. If a chromosome with better
 * fitness, the probability is higher. The ratio is an array with population in
 * size. The value in ratio array is the uniform[0, 1] distribution value. The
 * accumulated value of the whole array is 1.
 * @param *ratio (global) the probability array for each chromosomes.
 * @param *holder a pointer of uint for storing the last rand value.
 * @param num_of_chromosomes the size of ratio.
 */
int random_choose_by_ratio(global float* ratio, uint* holder,
                           int num_of_chromosomes)
{

  // generate a random number from between 0 and 1
  float rand_choose = rand_prob(holder);
  float accumulated = 0.0;
  int i;
  // random choose a chromosome based on probability of each chromosome.
  for (i = 0; i < num_of_chromosomes; i++) {
    accumulated += ratio[i];
    if (accumulated > rand_choose) {
      return i;
    }
  }
  return num_of_chromosomes - 1;
}

/**
 * calc_min_max_fitness find the max and min value among all fitness values.
 * @param *fitnesses (global) the fitness value array of all chromosomes
 * @param num_of_chromosomes the number of chromosomes
 * @param *min (out) for returing the min fitness value
 * @param *max (out) for returning the max fitness value
 */
void calc_min_max_fitness(global float* fitnesses, int num_of_chromosomes,
                          float* min, float* max)
{
  for (int i = 0; i < num_of_chromosomes; i++) {
    max[0] = fmax(fitnesses[i], max[0]);
    min[0] = fmin(fitnesses[i], min[0]);
  }
}

/**
 * utils_calc_ratio find the best, worst, avg fitnesses among all chromosomes.
 * It also calculates the probability for each chromosomes based on their
 * fitness value. The best and worst definition is based on the initial options
 * of OpenCLGA.
 * @param *fitness (global) the fitness value array of all chromosomes
 * @param *ratio (global, out) the probability array of each chromosomes
 * @param num_of_chromosomes the number of chromosomes.
 */
void utils_calc_ratio(global float* fitness,
                      global float* ratio,
                      int num_of_chromosomes)
{
  float local_min = INT_MAX;
  float local_max = 0;
  // OPTIMIZATION_FOR_MAX is set at ocl_ga.py
  float best;
  float worst;
#if OPTIMIZATION_FOR_MAX
  calc_min_max_fitness(fitness, num_of_chromosomes, &local_max, &local_min);
  best = local_max;
  worst = local_min;
#else
  calc_min_max_fitness(fitness, num_of_chromosomes, &local_min, &local_max);
  best = local_min;
  worst = local_max;
#endif

  float temp_worst = worst;
  float diffTotal = 0;
  int i;
  // we use total and diff to calculate the probability for each chromosome
  for (i = 0; i < num_of_chromosomes; i++) {
    // to have a significant different between better and worst, we use square
    // of diff to calculate the probability.
    diffTotal += (temp_worst - fitness[i]) * (temp_worst - fitness[i]);
  }
  // calculate probability for each one
  for (i = 0; i < num_of_chromosomes; i++) {
    ratio[i] = (temp_worst - fitness[i]) * (temp_worst - fitness[i]) /
               diffTotal;
  }
}

#endif

#ifndef __ga_utils__
#define __ga_utils__

#include "Noise.cl"

/**
 * prints the value of chromosomes. We can also use this function to print a
 * single chromome with 1 value of num_of_chromosomes.
 * @param *chromosomes (global) the reference of chromosomes array
 * @param size_of_chromosome the size of a single chromesome
 * @param num_of_chromosomes the number of chromosomes in this array.
 * @param *fitnesses (global) the fitness array of all chromosomes. The size of
 *        this array is num_of_chromosomes.
 */
void print_chromosomes(global int* chromosomes, int size_of_chromosome,
                       int num_of_chromosomes, global float* fitnesses)
{
  int idx = get_global_id(0);
  if (idx > 0) {
    // We use this function to dump all of chromosomes. In most of the cases,
    // we shouldn't let all threads to print result because it may give us too
    // many information. So, the first thread is the only one can dump infos.
    return;
  }
  for (int c = 0; c < num_of_chromosomes; c++) {
    int start = c * size_of_chromosome;
    printf("Chromosome[%d]/dist[%f]:", c, fitnesses[c]);
    for (int i = 0; i < size_of_chromosome; i++) {
        printf("->(%d)", chromosomes[start+i]);
    }
    printf("\n");
  }
  printf("\n");
}

/**
 * rand generates a random number between 0 to max value of uint.
 * NOTE : Since we cannot create a real random number in kernel,
 *        By passing in a random value from python, and storing the last
 *        random value generated from table, we could simulate a pesudo random
 *        number in kernel.
 * @param *holder a pointer of uint for storing the last rand value.
 * @return a random uint value.
 */
uint rand(uint* holder)
{
  uint b = ParallelRNG(holder[0]);
  uint c = ParallelRNG2(b, holder[0]);
  uint d = ParallelRNG3(c, b, holder[0]);
  holder[0] = c;
  return d;
}

/**
 * rand_range generates a random number between 0 < return_vlue < range.
 * @param *holder a pointer of uint for storing the last rand value.
 * @param range the max value of random number.
 * @return a random uint value in the range.
 */
uint rand_range(uint* holder, uint range)
{
  uint r = rand(holder) % range;
  return r;
}

/**
 * rand_range_exclude generates a random number between 0 < return_vlue < range.
 * But the value aExcluded is excluded.
 * @param *holder a pointer of uint for storing the last rand value.
 * @param range the max value of random number.
 * @param aExclude the excluded value
 * @return a random uint value in the range except aExcluded.
 */
uint rand_range_exclude(uint* holder, uint range, uint aExcluded)
{
  uint r = rand(holder) % (range - 1);
  return r == aExcluded ? range - 1 : r;
}

/**
 * rand_prob generates a random number between 0 < return_vlue < 1 in float.
 * @param *holder a pointer of uint for storing the last rand value.
 * @return a random float value.
 */
float rand_prob(uint* holder)
{
  uint r = rand(holder);
  float p = r / (float)UINT_MAX;
  return p;
}

/**
 * initialze the random seed.
 * @param seed the reandom seed.
 * @param *holder a pointer of uint for storing the last rand value.
 */
void init_rand(int seed, uint* holder)
{
  holder[0] = ParallelRNG(seed);
}

/**
 * random choose a chromosome based on the ratio. For GA, we need to choose a
 * chromosome for crossover based on fitnesses. If a chromosome with better
 * fitness, the probability is higher. The ratio is an array with population in
 * size. The value in ratio array is the uniform[0, 1] distribution value. The
 * accumulated value of the whole array is 1.
 * @param *ratio (global) the probability array for each chromosomes.
 * @param *holder a pointer of uint for storing the last rand value.
 * @param num_of_chromosomes the size of ratio.
 */
int random_choose_by_ratio(global float* ratio, uint* holder,
                           int num_of_chromosomes)
{

  // generate a random number from between 0 and 1
  float rand_choose = rand_prob(holder);
  float accumulated = 0.0;
  int i;
  // random choose a chromosome based on probability of each chromosome.
  for (i = 0; i < num_of_chromosomes; i++) {
    accumulated += ratio[i];
    if (accumulated > rand_choose) {
      return i;
    }
  }
  return num_of_chromosomes - 1;
}

/**
 * calc_min_max_fitness find the max and min value among all fitness values.
 * @param *fitnesses (global) the fitness value array of all chromosomes
 * @param num_of_chromosomes the number of chromosomes
 * @param *min (out) for returing the min fitness value
 * @param *max (out) for returning the max fitness value
 */
void calc_min_max_fitness(global float* fitnesses, int num_of_chromosomes,
                          float* min, float* max)
{
  for (int i = 0; i < num_of_chromosomes; i++) {
    max[0] = fmax(fitnesses[i], max[0]);
    min[0] = fmin(fitnesses[i], min[0]);
  }
}

/**
 * utils_calc_ratio find the best, worst, avg fitnesses among all chromosomes.
 * It also calculates the probability for each chromosomes based on their
 * fitness value. The best and worst definition is based on the initial options
 * of OpenCLGA.
 * @param *fitness (global) the fitness value array of all chromosomes
 * @param *ratio (global, out) the probability array of each chromosomes
 * @param num_of_chromosomes the number of chromosomes.
 */
void utils_calc_ratio(global float* fitness,
                      global float* ratio,
                      int num_of_chromosomes)
{
  float local_min = INT_MAX;
  float local_max = 0;
  // OPTIMIZATION_FOR_MAX is set at ocl_ga.py
  float best;
  float worst;
#if OPTIMIZATION_FOR_MAX
  calc_min_max_fitness(fitness, num_of_chromosomes, &local_max, &local_min);
  best = local_max;
  worst = local_min;
#else
  calc_min_max_fitness(fitness, num_of_chromosomes, &local_min, &local_max);
  best = local_min;
  worst = local_max;
#endif

  float temp_worst = worst;
  float diffTotal = 0;
  int i;
  // we use total and diff to calculate the probability for each chromosome
  for (i = 0; i < num_of_chromosomes; i++) {
    // to have a significant different between better and worst, we use square
    // of diff to calculate the probability.
    diffTotal += (temp_worst - fitness[i]) * (temp_worst - fitness[i]);
  }
  // calculate probability for each one
  for (i = 0; i < num_of_chromosomes; i++) {
    ratio[i] = (temp_worst - fitness[i]) * (temp_worst - fitness[i]) /
               diffTotal;
  }
}

#endif


Fix incorrect edge case in color_conversion.cl

__kernel void rgba_to_uint8_rgba_buffer(read_only image2d_t src_image,
                                        __global uchar* const buf) {
	int2 coords = (int2)(get_global_id(0), get_global_id(1));
	int w = get_image_width(src_image);

	float4 pixel = read_imagef(src_image, coords) * 255.0f;

	int base = (coords.y * w + coords.x) * 4;
	buf[base] = round(pixel.x);
	buf[base + 1] = round(pixel.y);
	buf[base + 2] = round(pixel.z);
	buf[base + 3] = round(pixel.w);
}

__kernel void rgb_to_yuv444_601_limited(read_only image2d_t src_image,
                                        __private uint const Y_stride,
                                        __private uint const U_stride,
                                        __private uint const V_stride,
                                        __global uchar* const Y_buf,
                                        __global uchar* const U_buf,
                                        __global uchar* const V_buf) {
	int2 coords = (int2)(get_global_id(0), get_global_id(1));

	float4 pixel = read_imagef(src_image, coords);
	float Y = 16 + pixel.x * 65.481 + pixel.y * 128.553 + pixel.z * 24.966;
	float U = 128 - pixel.x * 37.797 - pixel.y * 74.203 + pixel.z * 112.0;
	float V = 128 + pixel.x * 112.0 - pixel.y * 93.786 - pixel.z * 18.214;

	// FFMpeg frames are flipped.
	coords.y = get_image_height(src_image) - coords.y - 1;

	Y_buf[coords.y * Y_stride + coords.x] = round(Y);
	U_buf[coords.y * U_stride + coords.x] = round(U);
	V_buf[coords.y * V_stride + coords.x] = round(V);
}

__kernel void rgb_to_yuv420_601_limited(read_only image2d_t src_image,
                                        __private uint const Y_stride,
                                        __private uint const U_stride,
                                        __private uint const V_stride,
                                        __global uchar* const Y_buf,
                                        __global uchar* const U_buf,
                                        __global uchar* const V_buf) {
	int2 coords = (int2)(get_global_id(0), get_global_id(1));
	int h = get_image_height(src_image);

	float4 pixel = read_imagef(src_image, coords);

	float Y = 16 + pixel.x * 65.481 + pixel.y * 128.553 + pixel.z * 24.966;
	Y_buf[(h - coords.y - 1) * Y_stride + coords.x] = round(Y);

	if ((coords.x & 1) == 0 && (coords.y & 1) == 0) {
		// Average the 4 pixel values for better results.
		int w = get_image_width(src_image);
		float4 top_right, bottom_left, bottom_right;

		if (coords.x + 1 < w) {
			top_right = read_imagef(src_image, coords + (int2)(1, 0));
		} else {
			top_right = pixel;
		}

		if (coords.y + 1 < h) {
			bottom_left = read_imagef(src_image, coords + (int2)(0, 1));
		} else {
			bottom_left = pixel;
		}

		if (coords.x + 1 < w && coords.y + 1 < h) {
			bottom_right = read_imagef(src_image, coords + (int2)(1, 1));
		} else {
			if (coords.x + 1 < w) {
				bottom_right = top_right;
			} else if (coords.y + 1 < h) {
				bottom_right = bottom_left;
			} else {
				bottom_right = pixel;
			}
		}

		pixel = (pixel + top_right + bottom_left + bottom_right) / (float4)(4.0, 4.0, 4.0, 4.0);

		coords.x >>= 1;
		coords.y >>= 1;

		coords.y = (h >> 1) - coords.y - 1;

		float U = 128 - pixel.x * 37.797 - pixel.y * 74.203 + pixel.z * 112.0;
		float V = 128 + pixel.x * 112.0 - pixel.y * 93.786 - pixel.z * 18.214;

		U_buf[coords.y * U_stride + coords.x] = round(U);
		V_buf[coords.y * V_stride + coords.x] = round(V);
	}
}

__kernel void rgba_to_uint8_rgba_buffer(read_only image2d_t src_image,
                                        __global uchar* const buf) {
	int2 coords = (int2)(get_global_id(0), get_global_id(1));
	int w = get_image_width(src_image);

	float4 pixel = read_imagef(src_image, coords) * 255.0f;

	int base = (coords.y * w + coords.x) * 4;
	buf[base] = round(pixel.x);
	buf[base + 1] = round(pixel.y);
	buf[base + 2] = round(pixel.z);
	buf[base + 3] = round(pixel.w);
}

__kernel void rgb_to_yuv444_601_limited(read_only image2d_t src_image,
                                        __private uint const Y_stride,
                                        __private uint const U_stride,
                                        __private uint const V_stride,
                                        __global uchar* const Y_buf,
                                        __global uchar* const U_buf,
                                        __global uchar* const V_buf) {
	int2 coords = (int2)(get_global_id(0), get_global_id(1));

	float4 pixel = read_imagef(src_image, coords);
	float Y = 16 + pixel.x * 65.481 + pixel.y * 128.553 + pixel.z * 24.966;
	float U = 128 - pixel.x * 37.797 - pixel.y * 74.203 + pixel.z * 112.0;
	float V = 128 + pixel.x * 112.0 - pixel.y * 93.786 - pixel.z * 18.214;

	// FFMpeg frames are flipped.
	coords.y = get_image_height(src_image) - coords.y - 1;

	Y_buf[coords.y * Y_stride + coords.x] = round(Y);
	U_buf[coords.y * U_stride + coords.x] = round(U);
	V_buf[coords.y * V_stride + coords.x] = round(V);
}

__kernel void rgb_to_yuv420_601_limited(read_only image2d_t src_image,
                                        __private uint const Y_stride,
                                        __private uint const U_stride,
                                        __private uint const V_stride,
                                        __global uchar* const Y_buf,
                                        __global uchar* const U_buf,
                                        __global uchar* const V_buf) {
	int2 coords = (int2)(get_global_id(0), get_global_id(1));
	int h = get_image_height(src_image);

	float4 pixel = read_imagef(src_image, coords);

	float Y = 16 + pixel.x * 65.481 + pixel.y * 128.553 + pixel.z * 24.966;
	Y_buf[(h - coords.y - 1) * Y_stride + coords.x] = round(Y);

	if ((coords.x & 1) == 0 && (coords.y & 1) == 0) {
		// Average the 4 pixel values for better results.
		int w = get_image_width(src_image);
		float4 top_right, bottom_left, bottom_right;

		if (coords.x + 1 < w) {
			top_right = read_imagef(src_image, coords + (int2)(1, 0));
		} else {
			top_right = pixel;
		}

		if (coords.y + 1 < h) {
			bottom_left = read_imagef(src_image, coords + (int2)(0, 1));
		} else {
			bottom_left = pixel;
		}

		if (coords.x + 1 < w && coords.y + 1 < h) {
			bottom_right = read_imagef(src_image, coords + (int2)(1, 1));
		} else {
			bottom_right = pixel;
		}

		pixel = (pixel + top_right + bottom_left + bottom_right) / (float4)(4.0, 4.0, 4.0, 4.0);

		coords.x >>= 1;
		coords.y >>= 1;

		coords.y = (h >> 1) - coords.y - 1;

		float U = 128 - pixel.x * 37.797 - pixel.y * 74.203 + pixel.z * 112.0;
		float V = 128 + pixel.x * 112.0 - pixel.y * 93.786 - pixel.z * 18.214;

		U_buf[coords.y * U_stride + coords.x] = round(U);
		V_buf[coords.y * V_stride + coords.x] = round(V);
	}
}


moved a two-line macro to a single line

moved a two-line macro to a single line

// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
//   Cedric Nugteren <www.cedricnugteren.nl>
//
// This file contains two optimized matrix-multiplication kernels:
// - Kernel 0: inspired by the paper by Matsumoto et al. and the tutorial on
//   http://www.cedricnugteren.nl/tutorial.php
// - Kernel 1: inspired by a Qualcomm optimized GPU kernel with 2D register tiling
//   https://developer.qualcomm.com/blog/matrix-multiply-adreno-gpus-part-2-host-code-and-kernel
// Both are fully configurable (and tunable!) using many parameters. Both kernels support
// different data-types (SGEMM/DGEMM/CGEMM/ZGEMM/HGEMM) through a pre-processor define.
//
// For kernel 0 matrices are accessed as follows:
// A: [k*M + m], with 'k' ranging from 0:K and 'm' from 0:M (m,k,m)
// B: [k*N + n], with 'k' ranging from 0:K and 'n' from 0:N (n,k,n)
// C: [n*M + m], with 'n' ranging from 0:N and 'm' from 0:M (m,n,m)
// For kernel 1, both A and C are transposed w.r.t. the above
//
// Or as an image (assuming column-major)
//       K
//    o-------o
//    |       |
//  N | [B^T] |
//    |       |
//    o-------o
//        K               N
//    o-------o        o-----o
//  M |  [A]  |      M | [C] |
//    |       |        |     |
//    o-------o        o-----o
//
//
// This kernel is separated into multiple files. This is part 1 out of 4.
//
// =================================================================================================

// Enables loading of this file using the C++ pre-processor's #include (C++11 standard raw string
// literal). Comment-out this line for syntax-highlighting when developing.
R"(

// =================================================================================================

// Parameters set by the tuner or by the database. Here they are given a basic default value in case
// this kernel file is used outside of the CLBlast library.
#ifndef GEMMK
  #define GEMMK 0    // Kernel to choose: 0 regular, 1 with 2D register tiling
#endif
#ifndef MWG
  #define MWG 8      // Tile-size in dimension M (e.g. 64, 128)
#endif
#ifndef NWG
  #define NWG 8      // Tile-size in dimension N (e.g. 64, 128)
#endif
#ifndef KWG
  #define KWG 8      // Tile-size in dimension K (e.g. 8, 16)
#endif
#ifndef MDIMC
  #define MDIMC 8    // Threads per workgroup in M-dimension (e.g. 8, 16, 32)
#endif
#ifndef NDIMC
  #define NDIMC 8    // Threads per workgroup in N-dimension (e.g. 8, 16, 32)
#endif
#ifndef MDIMA
  #define MDIMA 8    // Re-shaped tile dimension of matrix A: KDIMA * MDIMA (kernel 0 only)
#endif
#ifndef NDIMB
  #define NDIMB 8    // Re-shaped tile dimension of matrix B: KDIMB * NDIMB (kernel 0 only)
#endif
#ifndef KWI
  #define KWI 1      // Unroll factor of the KWG loop (smaller or equal than KWG)
#endif
#ifndef VWM
  #define VWM 1      // Vector width of matrices A and C
#endif
#ifndef VWN
  #define VWN 1      // Vector width of matrix B
#endif
#ifndef STRM
  #define STRM 0     // Use strided access within a thread in the M-dimension (1) or not (0) (kernel 0 only)
#endif
#ifndef STRN
  #define STRN 0     // Use strided access within a thread in the N-dimension (1) or not (0) (kernel 0 only)
#endif
#ifndef SA
  #define SA 0       // Use local/shared memory to cache matrix A (1) or not (0) (kernel 0 only)
#endif
#ifndef SB
  #define SB 0       // Use local/shared memory to cache matrix B (1) or not (0) (kernel 0 only)
#endif
#ifndef KREG
  #define KREG 1     // Amount of register tiling in second dimension, multiple of VWN (kernel 1 only)
#endif

// Helper parameters based on the above tuning parameters
#define MWI (MWG/MDIMC)               // Work per work-item (M-dimension)
#define NWI (NWG/NDIMC)               // Work per work-item (N-dimension)
#define KDIMA ((MDIMC*NDIMC)/(MDIMA)) // Re-shaped tile dimension of matrix A: KDIMA * MDIMA
#define KDIMB ((MDIMC*NDIMC)/(NDIMB)) // Re-shaped tile dimension of matrix B: KDIMB * NDIMB
#define MWA (MWG/MDIMA)               // Amount of loads-per-thread for matrix A (M-dimension)
#define KWA (KWG/KDIMA)               // Amount of loads-per-thread for matrix A (K-dimension)
#define KWB (KWG/KDIMB)               // Amount of loads-per-thread for matrix B (K-dimension)
#define NWB (NWG/NDIMB)               // Amount of loads-per-thread for matrix B (N-dimension)

// Settings
#ifndef USE_VECTOR_MAD
  #define USE_VECTOR_MAD 0      // Unroll (0) or don't (1) unroll the vector MAD manually
#endif
#ifndef GLOBAL_MEM_FENCE
  #define GLOBAL_MEM_FENCE 0    // Global synchronisation barrier for potential better performance
#endif

#ifndef SUBGROUP_SHUFFLING_NVIDIA_PRE_VOLTA
  #define SUBGROUP_SHUFFLING_NVIDIA_PRE_VOLTA 0
#endif
#ifndef SUBGROUP_SHUFFLING_NVIDIA_POST_VOLTA
  #define SUBGROUP_SHUFFLING_NVIDIA_POST_VOLTA 0
#endif
#ifndef SUBGROUP_SHUFFLING_INTEL
  #define SUBGROUP_SHUFFLING_INTEL 0
#endif
#ifndef USE_SUBGROUP_SHUFFLING
  #define USE_SUBGROUP_SHUFFLING 0     // Optionally enables subgroup shuffling for Intel GPUs
#endif

// Intel subgroups (https://www.khronos.org/registry/OpenCL/extensions/intel/cl_intel_subgroups.txt)
#if USE_SUBGROUP_SHUFFLING == 1 && SUBGROUP_SHUFFLING_INTEL
  #define SUBGROUP_SIZE 8              // Assumes subgroup size is always 8 on Intel GPUs
#endif

// NVIDIA warps as subgroups using inline PTX (https://docs.nvidia.com/cuda/inline-ptx-assembly/index.html)
#if USE_SUBGROUP_SHUFFLING == 1 && (SUBGROUP_SHUFFLING_NVIDIA_PRE_VOLTA || SUBGROUP_SHUFFLING_NVIDIA_POST_VOLTA)
  #define SUBGROUP_SIZE 32              // Assumes subgroup size is always 32 on NVIDIA GPUs
#endif

#if NWI != SUBGROUP_SIZE || MDIMC < SUBGROUP_SIZE
  #undef USE_SUBGROUP_SHUFFLING
  #define USE_SUBGROUP_SHUFFLING 0     // Disables subgroups in case the assumptions don't hold
#endif

// =================================================================================================

// Data-widths in dimension M
#if VWM == 1
    typedef real realM;
#elif VWM == 2
    typedef real2 realM;
#elif VWM == 4
    typedef real4 realM;
#elif VWM == 8
    typedef real8 realM;
#elif VWM == 16
    typedef real16 realM;
#endif

// Data-widths in dimension N
#if VWN == 1
    typedef real realN;
#elif VWN == 2
    typedef real2 realN;
#elif VWN == 4
    typedef real4 realN;
#elif VWN == 8
    typedef real8 realN;
#elif VWN == 16
    typedef real16 realN;
#endif

// =================================================================================================

// Initializes the accumulation registers to zero
INLINE_FUNC realM InitAccRegisters() {
  realM result;
  #if VWM == 1
    SetToZero(result);
  #elif VWM == 2
    SetToZero(result.x);
    SetToZero(result.y);
  #elif VWM == 4
    SetToZero(result.x);
    SetToZero(result.y);
    SetToZero(result.z);
    SetToZero(result.w);
  #elif VWM == 8
    SetToZero(result.s0);
    SetToZero(result.s1);
    SetToZero(result.s2);
    SetToZero(result.s3);
    SetToZero(result.s4);
    SetToZero(result.s5);
    SetToZero(result.s6);
    SetToZero(result.s7);
  #elif VWM == 16
    SetToZero(result.s0);
    SetToZero(result.s1);
    SetToZero(result.s2);
    SetToZero(result.s3);
    SetToZero(result.s4);
    SetToZero(result.s5);
    SetToZero(result.s6);
    SetToZero(result.s7);
    SetToZero(result.s8);
    SetToZero(result.s9);
    SetToZero(result.sA);
    SetToZero(result.sB);
    SetToZero(result.sC);
    SetToZero(result.sD);
    SetToZero(result.sE);
    SetToZero(result.sF);
  #endif
  return result;
}

// =================================================================================================

// Caches global off-chip memory into local (shared) memory on-chip. This function is specific for
// caching the A input matrix.
#if SA == 1
INLINE_FUNC void GlobalToLocalA(const __global realM* restrict agm, LOCAL_PTR realM* alm,
                                const int kSizeM, const int tid, const int kwg) {
  const int la0 = tid % MDIMA;
  const int la1 = tid / MDIMA;
  #pragma unroll
  for (int _mia = 0; _mia < MWA/VWM; _mia += 1) {
    #pragma unroll
    for (int _kia = 0; _kia < KWA; _kia += 1) {

      // Computes the indices based on strided/non-strided access
      #if STRM == 0
        int mg = _mia + la0*(MWA/VWM);
      #elif STRM == 1
        int mg = la0 + _mia*MDIMA;
      #endif

      // Computes the indices for the global memory
      int kg = _kia + la1*KWA;
      int idm = mg + GetGroupID0() * (MWG/VWM);
      int idk = kg + kwg;

      // Loads the data from global memory (not transposed) into the local memory
      alm[kg*(MWG/VWM) + mg] = agm[idk*(kSizeM/VWM) + idm];
    }
  }
}
#endif

// Same as above, but now for the B input matrix
#if SB == 1
INLINE_FUNC void GlobalToLocalB(const __global realN* restrict bgm, LOCAL_PTR realN* blm,
                                const int kSizeN, const int tid, const int kwg) {
  const int lb0 = tid % NDIMB;
  const int lb1 = tid / NDIMB;
  #pragma unroll
  for (int _kib = 0; _kib < KWB; _kib += 1) {
    #pragma unroll
    for (int _nib = 0; _nib < NWB/VWN; _nib += 1) {

      // Computes the indices based on strided/non-strided access
      #if STRN == 0
        int ng = _nib + lb0*(NWB/VWN);
      #elif STRN == 1
        int ng = lb0 + _nib*NDIMB;
      #endif

      // Computes the indices for the global memory
      int kg = _kib + lb1*KWB;
      int idn = ng + GetGroupID1() * (NWG/VWN);
      int idk = kg + kwg;

      // Loads the data from global memory (transposed) into the local memory
      blm[kg*(NWG/VWN) + ng] = bgm[idk*(kSizeN/VWN) + idn];
    }
  }
}
#endif

// =================================================================================================

// Caches global off-chip memory directly into per-thread private memory (registers). This function
// is specific for caching the A input matrix.
#if SA == 0 && GEMMK == 0
INLINE_FUNC realM GlobalToPrivateA(const __global realM* restrict agm, const int _mi,
                                   const int kSizeM, const int idk, const int kwg) {
  // Computes the indices based on strided/non-strided access
  #if STRM == 0
    int mg = _mi + get_local_id(0)*(MWI/VWM);
  #elif STRM == 1
    int mg = get_local_id(0) + _mi*MDIMC;
  #endif

  // Computes the indices for the global memory
  int idm = mg + GetGroupID0() * (MWG/VWM);

  // Loads the data from global memory (not transposed) and stores into registers
  return agm[idk*(kSizeM/VWM) + idm];
}
#endif

// Same as above, but now for the B input matrix
#if SB == 0 && GEMMK == 0
INLINE_FUNC realN GlobalToPrivateB(const __global realN* restrict bgm, const int _ni,
                                   const int kSizeN, const int idk) {
  // Computes the indices based on strided/non-strided access
  #if STRN == 0
    int ng = _ni + get_local_id(1)*(NWI/VWN);
  #elif STRN == 1
    int ng = get_local_id(1) + _ni*NDIMC;
  #endif

  // Computes the indices for the global memory
  int idn = ng + GetGroupID1() * (NWG/VWN);

  // Loads the data from global memory (transposed) and stores into registers
  return bgm[idk*(kSizeN/VWN) + idn];
}
#endif

// =================================================================================================
#if GEMMK == 1

// Caches global off-chip memory directly into per-thread private memory (registers). This function
// is specific for caching the A input matrix for kernel 1.
INLINE_FUNC realN GlobalToPrivateA2D(const __global real* restrict a_ptr, const int tid_y, const int _ni,
                                     const int kSizeK, const int idk, const int _ki) {
  #if PRECISION == 3232 || PRECISION == 6464
    const int a_index = (tid_y * NWI + _ni) * (kSizeK / VWN) + idk / VWN + _ki;
    const __global realN* restrict agm = (const __global realN* restrict) a_ptr;
    return agm[a_index];
  #else
    const int a_index = (tid_y * NWI + _ni) * kSizeK + idk + _ki * VWN;
    #if VWN == 1
      return a_ptr[a_index];
    #elif VWN == 2
      return vload2(0, a_ptr + a_index);
    #elif VWN == 4
      return vload4(0, a_ptr + a_index);
    #elif VWN == 8
      return vload8(0, a_ptr + a_index);
    #elif VWN == 16
      return vload16(0, a_ptr + a_index);
    #endif
  #endif
}

// Same as above, but now for the B input matrix
INLINE_FUNC realM GlobalToPrivateB2D(const __global real* restrict b_ptr, const int tid_x, const int _mi,
                                     const int kSizeN, const int idk, const int _ki) {
  #if PRECISION == 3232 || PRECISION == 6464
    const int b_index = (idk + _ki) * (kSizeN / VWM) + tid_x * (MWI / VWM) + _mi;
    const __global realM* restrict bgm = (const __global realM* restrict) b_ptr;
    return bgm[b_index];
  #else
    const int b_index = (idk + _ki) * kSizeN + tid_x * MWI + _mi * VWM;
    #if VWM == 1
      return b_ptr[b_index];
    #elif VWM == 2
      return vload2(0, b_ptr + b_index);
    #elif VWM == 4
      return vload4(0, b_ptr + b_index);
    #elif VWM == 8
      return vload8(0, b_ptr + b_index);
    #elif VWM == 16
      return vload16(0, b_ptr + b_index);
    #endif
  #endif
}

#endif
// =================================================================================================

// Caches on-chip local memory into per-thread private memory (registers). This function is specific
// for caching the A input matrix.
#if SA == 1
INLINE_FUNC realM LocalToPrivateA(LOCAL_PTR realM* alm, const int _mi, const int kg) {
  #if STRM == 0
    int mg = _mi + get_local_id(0)*(MWI/VWM);
  #elif STRM == 1
    int mg = get_local_id(0) + _mi*MDIMC;
  #endif
  return alm[kg*(MWG/VWM) + mg];
}
#endif

// Same as above, but now for the B input matrix
#if SB == 1
INLINE_FUNC realN LocalToPrivateB(LOCAL_PTR realN* blm, const int _ni, const int kg) {
  #if STRN == 0
    int ng = _ni + get_local_id(1)*(NWI/VWN);
  #elif STRN == 1
    int ng = get_local_id(1) + _ni*NDIMC;
  #endif
  return blm[kg*(NWG/VWN) + ng];
}
#endif

// =================================================================================================

// End of the C++11 raw string literal
)"

// =================================================================================================

// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
//   Cedric Nugteren <www.cedricnugteren.nl>
//
// This file contains two optimized matrix-multiplication kernels:
// - Kernel 0: inspired by the paper by Matsumoto et al. and the tutorial on
//   http://www.cedricnugteren.nl/tutorial.php
// - Kernel 1: inspired by a Qualcomm optimized GPU kernel with 2D register tiling
//   https://developer.qualcomm.com/blog/matrix-multiply-adreno-gpus-part-2-host-code-and-kernel
// Both are fully configurable (and tunable!) using many parameters. Both kernels support
// different data-types (SGEMM/DGEMM/CGEMM/ZGEMM/HGEMM) through a pre-processor define.
//
// For kernel 0 matrices are accessed as follows:
// A: [k*M + m], with 'k' ranging from 0:K and 'm' from 0:M (m,k,m)
// B: [k*N + n], with 'k' ranging from 0:K and 'n' from 0:N (n,k,n)
// C: [n*M + m], with 'n' ranging from 0:N and 'm' from 0:M (m,n,m)
// For kernel 1, both A and C are transposed w.r.t. the above
//
// Or as an image (assuming column-major)
//       K
//    o-------o
//    |       |
//  N | [B^T] |
//    |       |
//    o-------o
//        K               N
//    o-------o        o-----o
//  M |  [A]  |      M | [C] |
//    |       |        |     |
//    o-------o        o-----o
//
//
// This kernel is separated into multiple files. This is part 1 out of 4.
//
// =================================================================================================

// Enables loading of this file using the C++ pre-processor's #include (C++11 standard raw string
// literal). Comment-out this line for syntax-highlighting when developing.
R"(

// =================================================================================================

// Parameters set by the tuner or by the database. Here they are given a basic default value in case
// this kernel file is used outside of the CLBlast library.
#ifndef GEMMK
  #define GEMMK 0    // Kernel to choose: 0 regular, 1 with 2D register tiling
#endif
#ifndef MWG
  #define MWG 8      // Tile-size in dimension M (e.g. 64, 128)
#endif
#ifndef NWG
  #define NWG 8      // Tile-size in dimension N (e.g. 64, 128)
#endif
#ifndef KWG
  #define KWG 8      // Tile-size in dimension K (e.g. 8, 16)
#endif
#ifndef MDIMC
  #define MDIMC 8    // Threads per workgroup in M-dimension (e.g. 8, 16, 32)
#endif
#ifndef NDIMC
  #define NDIMC 8    // Threads per workgroup in N-dimension (e.g. 8, 16, 32)
#endif
#ifndef MDIMA
  #define MDIMA 8    // Re-shaped tile dimension of matrix A: KDIMA * MDIMA (kernel 0 only)
#endif
#ifndef NDIMB
  #define NDIMB 8    // Re-shaped tile dimension of matrix B: KDIMB * NDIMB (kernel 0 only)
#endif
#ifndef KWI
  #define KWI 1      // Unroll factor of the KWG loop (smaller or equal than KWG)
#endif
#ifndef VWM
  #define VWM 1      // Vector width of matrices A and C
#endif
#ifndef VWN
  #define VWN 1      // Vector width of matrix B
#endif
#ifndef STRM
  #define STRM 0     // Use strided access within a thread in the M-dimension (1) or not (0) (kernel 0 only)
#endif
#ifndef STRN
  #define STRN 0     // Use strided access within a thread in the N-dimension (1) or not (0) (kernel 0 only)
#endif
#ifndef SA
  #define SA 0       // Use local/shared memory to cache matrix A (1) or not (0) (kernel 0 only)
#endif
#ifndef SB
  #define SB 0       // Use local/shared memory to cache matrix B (1) or not (0) (kernel 0 only)
#endif
#ifndef KREG
  #define KREG 1     // Amount of register tiling in second dimension, multiple of VWN (kernel 1 only)
#endif

// Helper parameters based on the above tuning parameters
#define MWI (MWG/MDIMC)               // Work per work-item (M-dimension)
#define NWI (NWG/NDIMC)               // Work per work-item (N-dimension)
#define KDIMA ((MDIMC*NDIMC)/(MDIMA)) // Re-shaped tile dimension of matrix A: KDIMA * MDIMA
#define KDIMB ((MDIMC*NDIMC)/(NDIMB)) // Re-shaped tile dimension of matrix B: KDIMB * NDIMB
#define MWA (MWG/MDIMA)               // Amount of loads-per-thread for matrix A (M-dimension)
#define KWA (KWG/KDIMA)               // Amount of loads-per-thread for matrix A (K-dimension)
#define KWB (KWG/KDIMB)               // Amount of loads-per-thread for matrix B (K-dimension)
#define NWB (NWG/NDIMB)               // Amount of loads-per-thread for matrix B (N-dimension)

// Settings
#ifndef USE_VECTOR_MAD
  #define USE_VECTOR_MAD 0      // Unroll (0) or don't (1) unroll the vector MAD manually
#endif
#ifndef GLOBAL_MEM_FENCE
  #define GLOBAL_MEM_FENCE 0    // Global synchronisation barrier for potential better performance
#endif

#ifndef SUBGROUP_SHUFFLING_NVIDIA_PRE_VOLTA
  #define SUBGROUP_SHUFFLING_NVIDIA_PRE_VOLTA 0
#endif
#ifndef SUBGROUP_SHUFFLING_NVIDIA_POST_VOLTA
  #define SUBGROUP_SHUFFLING_NVIDIA_POST_VOLTA 0
#endif
#ifndef SUBGROUP_SHUFFLING_INTEL
  #define SUBGROUP_SHUFFLING_INTEL 0
#endif
#ifndef USE_SUBGROUP_SHUFFLING
  #define USE_SUBGROUP_SHUFFLING 0     // Optionally enables subgroup shuffling for Intel GPUs
#endif

// Intel subgroups (https://www.khronos.org/registry/OpenCL/extensions/intel/cl_intel_subgroups.txt)
#if USE_SUBGROUP_SHUFFLING == 1 && SUBGROUP_SHUFFLING_INTEL
  #define SUBGROUP_SIZE 8              // Assumes subgroup size is always 8 on Intel GPUs
#endif

// NVIDIA warps as subgroups using inline PTX (https://docs.nvidia.com/cuda/inline-ptx-assembly/index.html)
#if USE_SUBGROUP_SHUFFLING == 1 && (SUBGROUP_SHUFFLING_NVIDIA_PRE_VOLTA || \
                                    SUBGROUP_SHUFFLING_NVIDIA_POST_VOLTA)
  #define SUBGROUP_SIZE 32              // Assumes subgroup size is always 32 on NVIDIA GPUs
#endif

#if NWI != SUBGROUP_SIZE || MDIMC < SUBGROUP_SIZE
  #undef USE_SUBGROUP_SHUFFLING
  #define USE_SUBGROUP_SHUFFLING 0     // Disables subgroups in case the assumptions don't hold
#endif

// =================================================================================================

// Data-widths in dimension M
#if VWM == 1
    typedef real realM;
#elif VWM == 2
    typedef real2 realM;
#elif VWM == 4
    typedef real4 realM;
#elif VWM == 8
    typedef real8 realM;
#elif VWM == 16
    typedef real16 realM;
#endif

// Data-widths in dimension N
#if VWN == 1
    typedef real realN;
#elif VWN == 2
    typedef real2 realN;
#elif VWN == 4
    typedef real4 realN;
#elif VWN == 8
    typedef real8 realN;
#elif VWN == 16
    typedef real16 realN;
#endif

// =================================================================================================

// Initializes the accumulation registers to zero
INLINE_FUNC realM InitAccRegisters() {
  realM result;
  #if VWM == 1
    SetToZero(result);
  #elif VWM == 2
    SetToZero(result.x);
    SetToZero(result.y);
  #elif VWM == 4
    SetToZero(result.x);
    SetToZero(result.y);
    SetToZero(result.z);
    SetToZero(result.w);
  #elif VWM == 8
    SetToZero(result.s0);
    SetToZero(result.s1);
    SetToZero(result.s2);
    SetToZero(result.s3);
    SetToZero(result.s4);
    SetToZero(result.s5);
    SetToZero(result.s6);
    SetToZero(result.s7);
  #elif VWM == 16
    SetToZero(result.s0);
    SetToZero(result.s1);
    SetToZero(result.s2);
    SetToZero(result.s3);
    SetToZero(result.s4);
    SetToZero(result.s5);
    SetToZero(result.s6);
    SetToZero(result.s7);
    SetToZero(result.s8);
    SetToZero(result.s9);
    SetToZero(result.sA);
    SetToZero(result.sB);
    SetToZero(result.sC);
    SetToZero(result.sD);
    SetToZero(result.sE);
    SetToZero(result.sF);
  #endif
  return result;
}

// =================================================================================================

// Caches global off-chip memory into local (shared) memory on-chip. This function is specific for
// caching the A input matrix.
#if SA == 1
INLINE_FUNC void GlobalToLocalA(const __global realM* restrict agm, LOCAL_PTR realM* alm,
                                const int kSizeM, const int tid, const int kwg) {
  const int la0 = tid % MDIMA;
  const int la1 = tid / MDIMA;
  #pragma unroll
  for (int _mia = 0; _mia < MWA/VWM; _mia += 1) {
    #pragma unroll
    for (int _kia = 0; _kia < KWA; _kia += 1) {

      // Computes the indices based on strided/non-strided access
      #if STRM == 0
        int mg = _mia + la0*(MWA/VWM);
      #elif STRM == 1
        int mg = la0 + _mia*MDIMA;
      #endif

      // Computes the indices for the global memory
      int kg = _kia + la1*KWA;
      int idm = mg + GetGroupID0() * (MWG/VWM);
      int idk = kg + kwg;

      // Loads the data from global memory (not transposed) into the local memory
      alm[kg*(MWG/VWM) + mg] = agm[idk*(kSizeM/VWM) + idm];
    }
  }
}
#endif

// Same as above, but now for the B input matrix
#if SB == 1
INLINE_FUNC void GlobalToLocalB(const __global realN* restrict bgm, LOCAL_PTR realN* blm,
                                const int kSizeN, const int tid, const int kwg) {
  const int lb0 = tid % NDIMB;
  const int lb1 = tid / NDIMB;
  #pragma unroll
  for (int _kib = 0; _kib < KWB; _kib += 1) {
    #pragma unroll
    for (int _nib = 0; _nib < NWB/VWN; _nib += 1) {

      // Computes the indices based on strided/non-strided access
      #if STRN == 0
        int ng = _nib + lb0*(NWB/VWN);
      #elif STRN == 1
        int ng = lb0 + _nib*NDIMB;
      #endif

      // Computes the indices for the global memory
      int kg = _kib + lb1*KWB;
      int idn = ng + GetGroupID1() * (NWG/VWN);
      int idk = kg + kwg;

      // Loads the data from global memory (transposed) into the local memory
      blm[kg*(NWG/VWN) + ng] = bgm[idk*(kSizeN/VWN) + idn];
    }
  }
}
#endif

// =================================================================================================

// Caches global off-chip memory directly into per-thread private memory (registers). This function
// is specific for caching the A input matrix.
#if SA == 0 && GEMMK == 0
INLINE_FUNC realM GlobalToPrivateA(const __global realM* restrict agm, const int _mi,
                                   const int kSizeM, const int idk, const int kwg) {
  // Computes the indices based on strided/non-strided access
  #if STRM == 0
    int mg = _mi + get_local_id(0)*(MWI/VWM);
  #elif STRM == 1
    int mg = get_local_id(0) + _mi*MDIMC;
  #endif

  // Computes the indices for the global memory
  int idm = mg + GetGroupID0() * (MWG/VWM);

  // Loads the data from global memory (not transposed) and stores into registers
  return agm[idk*(kSizeM/VWM) + idm];
}
#endif

// Same as above, but now for the B input matrix
#if SB == 0 && GEMMK == 0
INLINE_FUNC realN GlobalToPrivateB(const __global realN* restrict bgm, const int _ni,
                                   const int kSizeN, const int idk) {
  // Computes the indices based on strided/non-strided access
  #if STRN == 0
    int ng = _ni + get_local_id(1)*(NWI/VWN);
  #elif STRN == 1
    int ng = get_local_id(1) + _ni*NDIMC;
  #endif

  // Computes the indices for the global memory
  int idn = ng + GetGroupID1() * (NWG/VWN);

  // Loads the data from global memory (transposed) and stores into registers
  return bgm[idk*(kSizeN/VWN) + idn];
}
#endif

// =================================================================================================
#if GEMMK == 1

// Caches global off-chip memory directly into per-thread private memory (registers). This function
// is specific for caching the A input matrix for kernel 1.
INLINE_FUNC realN GlobalToPrivateA2D(const __global real* restrict a_ptr, const int tid_y, const int _ni,
                                     const int kSizeK, const int idk, const int _ki) {
  #if PRECISION == 3232 || PRECISION == 6464
    const int a_index = (tid_y * NWI + _ni) * (kSizeK / VWN) + idk / VWN + _ki;
    const __global realN* restrict agm = (const __global realN* restrict) a_ptr;
    return agm[a_index];
  #else
    const int a_index = (tid_y * NWI + _ni) * kSizeK + idk + _ki * VWN;
    #if VWN == 1
      return a_ptr[a_index];
    #elif VWN == 2
      return vload2(0, a_ptr + a_index);
    #elif VWN == 4
      return vload4(0, a_ptr + a_index);
    #elif VWN == 8
      return vload8(0, a_ptr + a_index);
    #elif VWN == 16
      return vload16(0, a_ptr + a_index);
    #endif
  #endif
}

// Same as above, but now for the B input matrix
INLINE_FUNC realM GlobalToPrivateB2D(const __global real* restrict b_ptr, const int tid_x, const int _mi,
                                     const int kSizeN, const int idk, const int _ki) {
  #if PRECISION == 3232 || PRECISION == 6464
    const int b_index = (idk + _ki) * (kSizeN / VWM) + tid_x * (MWI / VWM) + _mi;
    const __global realM* restrict bgm = (const __global realM* restrict) b_ptr;
    return bgm[b_index];
  #else
    const int b_index = (idk + _ki) * kSizeN + tid_x * MWI + _mi * VWM;
    #if VWM == 1
      return b_ptr[b_index];
    #elif VWM == 2
      return vload2(0, b_ptr + b_index);
    #elif VWM == 4
      return vload4(0, b_ptr + b_index);
    #elif VWM == 8
      return vload8(0, b_ptr + b_index);
    #elif VWM == 16
      return vload16(0, b_ptr + b_index);
    #endif
  #endif
}

#endif
// =================================================================================================

// Caches on-chip local memory into per-thread private memory (registers). This function is specific
// for caching the A input matrix.
#if SA == 1
INLINE_FUNC realM LocalToPrivateA(LOCAL_PTR realM* alm, const int _mi, const int kg) {
  #if STRM == 0
    int mg = _mi + get_local_id(0)*(MWI/VWM);
  #elif STRM == 1
    int mg = get_local_id(0) + _mi*MDIMC;
  #endif
  return alm[kg*(MWG/VWM) + mg];
}
#endif

// Same as above, but now for the B input matrix
#if SB == 1
INLINE_FUNC realN LocalToPrivateB(LOCAL_PTR realN* blm, const int _ni, const int kg) {
  #if STRN == 0
    int ng = _ni + get_local_id(1)*(NWI/VWN);
  #elif STRN == 1
    int ng = get_local_id(1) + _ni*NDIMC;
  #endif
  return blm[kg*(NWG/VWN) + ng];
}
#endif

// =================================================================================================

// End of the C++11 raw string literal
)"

// =================================================================================================