fixed an index that caused reading from slice 0 always

/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

__kernel void ckDAS(
  __global float* dSource, // input image
  __global float* dDest, // output buffer
  __global unsigned short* usedLines,
  __global unsigned short* delays,
  __constant float* apodArray,
  unsigned short apodArraySize,
  unsigned int inputL,
  unsigned int inputS,
  unsigned int Slices,
  unsigned int outputL,
  unsigned int outputS  // parameters
)
{
  // get thread identifier
  unsigned int globalPosX = get_global_id(0);
  unsigned int globalPosY = get_global_id(1);
  unsigned int globalPosZ = get_global_id(2);

  // terminate non-valid threads
  if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices )
  {
    float l_i = (float)globalPosX / (float)outputL * (float)inputL;

    unsigned short curUsedLines = usedLines[globalPosY * 3 * outputL + 3 * globalPosX];
    unsigned short minLine = usedLines[globalPosY * 3 * outputL + 3 * globalPosX + 1];
    unsigned short maxLine = usedLines[globalPosY * 3 *outputL + 3 * globalPosX + 2];

    float apod_mult = (float)apodArraySize / (float)curUsedLines;

    unsigned short Delay = 0;

    float output = 0;
    float mult = 0;

    for (short l_s = minLine; l_s < maxLine; ++l_s)
    {
      Delay = delays[globalPosY * (outputL / 2) + (int)(fabs(l_s - l_i)/(float)inputL * (float)outputL)];
      if (Delay < inputS && Delay >= 0) {
        output += apodArray[(int)((l_s - minLine)*apod_mult)] * dSource[(int)(globalPosZ * inputL * inputS + Delay * inputL + l_s)];
      }
      else
        --curUsedLines;
    }

    dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / (float)curUsedLines;
  }
}

__kernel void ckDAS_g(
  __global float* dSource, // input image
  __global float* dDest, // output buffer
  __global float* elementHeights,
  __global float* elementPositions,
  __constant float* apodArray,
  unsigned short apodArraySize,
  unsigned int inputL,
  unsigned int inputS,
  int Slices,
  int outputL,
  int outputS,
  float totalSamples_i,
  float horizontalExtent,
  float mult,
  char isPAImage,
  __global unsigned short* usedLines // parameters
)
{
  // get thread identifier
  int globalPosX = get_global_id(0);
  int globalPosY = get_global_id(1);
  int globalPosZ = get_global_id(2);

  // terminate non-valid threads
  if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices )
  {
    int AddSample = 0;
    float l_p = 0;
    float s_i = 0;

    float apod_mult = 1;

    float output = 0;

    l_p = (float)globalPosX / outputL * horizontalExtent;
    s_i = (float)globalPosY / outputS * totalSamples_i;

    unsigned short curUsedLines = usedLines[globalPosY * 3 * outputL + 3 * globalPosX];
    unsigned short minLine = usedLines[globalPosY * 3 * outputL + 3 * globalPosX + 1];
    unsigned short maxLine = usedLines[globalPosY * 3 *outputL + 3 * globalPosX + 2];

    apod_mult = (float)apodArraySize / curUsedLines;

    for (int l_s = minLine; l_s < maxLine; ++l_s)
    {
      AddSample = (int)sqrt(
        pow(s_i-elementHeights[l_s]*mult, 2)
        +
        pow(mult * (l_p - elementPositions[l_s]), 2)
      ) + (1 - isPAImage)*s_i;
      if (AddSample < inputS && AddSample >= 0)
        output += dSource[(int)(globalPosZ * inputL * inputS + l_s + AddSample*inputL)] * apodArray[(int)((l_s - minLine)*apod_mult)];
      else
        --curUsedLines;
    }
    dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / curUsedLines;
  }
}

/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

__kernel void ckDAS(
  __global float* dSource, // input image
  __global float* dDest, // output buffer
  __global unsigned short* usedLines,
  __global unsigned short* delays,
  __constant float* apodArray,
  unsigned short apodArraySize,
  unsigned int inputL,
  unsigned int inputS,
  unsigned int Slices,
  unsigned int outputL,
  unsigned int outputS  // parameters
)
{
  // get thread identifier
  unsigned int globalPosX = get_global_id(0);
  unsigned int globalPosY = get_global_id(1);
  unsigned int globalPosZ = get_global_id(2);

  // terminate non-valid threads
  if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices )
  {
    float l_i = (float)globalPosX / (float)outputL * (float)inputL;

    unsigned short curUsedLines = usedLines[globalPosY * 3 * outputL + 3 * globalPosX];
    unsigned short minLine = usedLines[globalPosY * 3 * outputL + 3 * globalPosX + 1];
    unsigned short maxLine = usedLines[globalPosY * 3 *outputL + 3 * globalPosX + 2];

    float apod_mult = (float)apodArraySize / (float)curUsedLines;

    unsigned short Delay = 0;

    float output = 0;
    float mult = 0;

    for (short l_s = minLine; l_s < maxLine; ++l_s)
    {
      Delay = delays[globalPosY * (outputL / 2) + (int)(fabs(l_s - l_i)/(float)inputL * (float)outputL)];
      if (Delay < inputS && Delay >= 0) {
        output += apodArray[(int)((l_s - minLine)*apod_mult)] * dSource[(int)(globalPosZ * inputL * inputS + Delay * inputL + l_s)];
      }
      else
        --curUsedLines;
    }

    dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / (float)curUsedLines;
  }
}

__kernel void ckDAS_g(
  __global float* dSource, // input image
  __global float* dDest, // output buffer
  __global float* elementHeights,
  __global float* elementPositions,
  __constant float* apodArray,
  unsigned short apodArraySize,
  unsigned int inputL,
  unsigned int inputS,
  int Slices,
  int outputL,
  int outputS,
  float totalSamples_i,
  float horizontalExtent,
  float mult,
  char isPAImage,
  __global unsigned short* usedLines // parameters
)
{
  // get thread identifier
  int globalPosX = get_global_id(0);
  int globalPosY = get_global_id(1);
  int globalPosZ = get_global_id(2);

  // terminate non-valid threads
  if ( globalPosX < outputL && globalPosY < outputS && globalPosZ < Slices )
  {
    int AddSample = 0;
    float l_p = 0;
    float s_i = 0;

    float apod_mult = 1;

    float output = 0;

    l_p = (float)globalPosX / outputL * horizontalExtent;
    s_i = (float)globalPosY / outputS * totalSamples_i;

    unsigned short curUsedLines = usedLines[globalPosY * 3 * outputL + 3 * globalPosX];
    unsigned short minLine = usedLines[globalPosY * 3 * outputL + 3 * globalPosX + 1];
    unsigned short maxLine = usedLines[globalPosY * 3 *outputL + 3 * globalPosX + 2];

    apod_mult = (float)apodArraySize / curUsedLines;

    for (int l_s = minLine; l_s < maxLine; ++l_s)
    {
      AddSample = (int)sqrt(
        pow(s_i-elementHeights[l_s]*mult, 2)
        +
        pow(mult * (l_p - elementPositions[l_s]), 2)
      ) + (1 - isPAImage)*s_i;
      if (AddSample < inputS && AddSample >= 0)
        output += dSource[l_s + AddSample*inputL] *
        apodArray[(int)((l_s - minLine)*apod_mult)];
      else
        --curUsedLines;
    }
    dDest[ globalPosZ * outputL * outputS + globalPosY * outputL + globalPosX ] = output / curUsedLines;
  }
}


Signed-off-by: Francesco Furiani <francesco@furio.me>

//------------------------------------------------------------
// Purpose :
// ---------
// Prefix sum or prefix scan is an operation where each output element contains the sum of all input elements preceding it.
//
// Algorithm :
// -----------
// The parallel prefix sum has two principal parts, the reduce phase (also known as the up-sweep phase) and the down-sweep phase.
//
// In the up-sweep reduction phase we traverse the computation tree from bottom to top, computing partial sums.
// After this phase, the last element of the array contains the total sum.
//
// During the down-sweep phase, we traverse the tree from the root and use the partial sums to build the scan in place.
//
// Because the scan pictured is an exclusive sum, a zero is inserted into the last element before the start of the down-sweep phase.
// This zero is then propagated back to the first element.
//
// In our implementation, each compute unit loads and sums up two elements (for the deepest depth). Each subsequent depth during the up-sweep
// phase is processed by half of the compute units from the deeper level and the other way around for the down-sweep phase.
//
// In order to be able to scan large arrays, i.e. arrays that have many more elements than the maximum size of a work-group, the prefix sum has to be decomposed.
// Each work-group computes the prefix scan of its sub-range and outputs a single number representing the sum of all elements in its sub-range.
// The workgroup sums are scanned using exactly the same algorithm.
// When the number of work-group results reaches the size of a work-group, the process is reversed and the work-group sums are
// propagated to the sub-ranges, where each work-group adds the incoming sum to all its elements, thus producing the final scanned array.
//
// References :
// ------------
// http://graphics.idav.ucdavis.edu/publications/print_pub?pub_id=1041
//
// To read :
// http://developer.apple.com/library/mac/#samplecode/OpenCL_Parallel_Prefix_Sum_Example/Listings/scan_kernel_cl.html#//apple_ref/doc/uid/DTS40008183-scan_kernel_cl-DontLinkElementID_5
// http://developer.apple.com/library/mac/#samplecode/OpenCL_Parallel_Reduction_Example/Listings/reduce_int4_kernel_cl.html
//------------------------------------------------------------

// #pragma OPENCL EXTENSION cl_amd_printf : enable

#define T int
#define OPERATOR_APPLY(A,B) A+B
#define OPERATOR_IDENTITY 0

//#define VOLATILE volatile
#define VOLATILE

//------------------------------------------------------------
// kernel__scanInter
//
// Purpose : do a scan on a chunck of data.
//------------------------------------------------------------

inline T scan_simt_exclusive(__local VOLATILE T* input, size_t idx, const uint lane)
{
	if (lane > 0 ) input[idx] = OPERATOR_APPLY(input[idx - 1] , input[idx]);
	if (lane > 1 ) input[idx] = OPERATOR_APPLY(input[idx - 2] , input[idx]);
	if (lane > 3 ) input[idx] = OPERATOR_APPLY(input[idx - 4] , input[idx]);
	if (lane > 7 ) input[idx] = OPERATOR_APPLY(input[idx - 8] , input[idx]);
	if (lane > 15) input[idx] = OPERATOR_APPLY(input[idx - 16], input[idx]);

	return (lane > 0) ? input[idx-1] : OPERATOR_IDENTITY;
}

inline T scan_simt_inclusive(__local VOLATILE T* input, size_t idx, const uint lane)
{
	if (lane > 0 ) input[idx] = OPERATOR_APPLY(input[idx - 1] , input[idx]);
	if (lane > 1 ) input[idx] = OPERATOR_APPLY(input[idx - 2] , input[idx]);
	if (lane > 3 ) input[idx] = OPERATOR_APPLY(input[idx - 4] , input[idx]);
	if (lane > 7 ) input[idx] = OPERATOR_APPLY(input[idx - 8] , input[idx]);
	if (lane > 15) input[idx] = OPERATOR_APPLY(input[idx - 16], input[idx]);

	return input[idx];
}

inline T scan_workgroup_exclusive(__local T* localBuf, const uint idx, const uint lane, const uint simt_bid)
{
	// Step 1: Intra-warp scan in each warp
	T val = scan_simt_exclusive(localBuf, idx, lane);
	barrier(CLK_LOCAL_MEM_FENCE);

	// Step 2: Collect per-warp partial results (the sum)
	if (lane > 30) localBuf[simt_bid] = localBuf[idx];
	barrier(CLK_LOCAL_MEM_FENCE);

	// Step 3: Use 1st warp to scan per-warp results
	if (simt_bid < 1) scan_simt_inclusive(localBuf, idx, lane);
	barrier(CLK_LOCAL_MEM_FENCE);

	// Step 4: Accumulate results from Steps 1 and 3
	if (simt_bid > 0) val = OPERATOR_APPLY(localBuf[simt_bid-1], val);
	barrier(CLK_LOCAL_MEM_FENCE);

	// Step 5: Write and return the final result
	localBuf[idx] = val;
	barrier(CLK_LOCAL_MEM_FENCE);

	return val;
}

__kernel
void kernel__scan_block_anylength(
	__local T* localBuf,
	__global T* dataSet,
	const uint B,
	uint size,
	const uint passesCount
)
{
	size_t idx = get_local_id(0);
	const uint bidx = get_group_id(0);
	const uint TC = get_local_size(0);

	const uint lane = idx & 31;
	const uint simt_bid = idx >> 5;

	T reduceValue = OPERATOR_IDENTITY;

	//#pragma unroll 4
	for(uint i = 0; i < passesCount; ++i)
	{
		const uint offset = i * TC + (bidx * B);
		const uint offsetIdx = offset + idx;

		if (offsetIdx > size-1) return;

		// Step 1: Read TC elements from global (off-chip) memory to local memory (on-chip)
		T input = localBuf[idx] = dataSet[offsetIdx];

		barrier(CLK_LOCAL_MEM_FENCE);

		// Step 2: Perform scan on TC elements
		T val = scan_workgroup_exclusive(localBuf, idx, lane, simt_bid);

		// Step 3: Propagate reduced result from previous block of TC elements
		val = OPERATOR_APPLY(val, reduceValue);

		// Step 4: Write out data to global memory
		dataSet[offsetIdx] = val;

		// Step 5: Choose reduced value for next iteration
		if (idx == (TC-1))
		{
			//localBuf[idx] = (Kind == exclusive) ? OPERATOR_APPLY(input, val) : val;
			localBuf[idx] = OPERATOR_APPLY(input, val);
		}
		barrier(CLK_LOCAL_MEM_FENCE);

		reduceValue = localBuf[TC-1];
		barrier(CLK_LOCAL_MEM_FENCE);
	}
}

//------------------------------------------------------------
// Purpose :
// ---------
// Prefix sum or prefix scan is an operation where each output element contains the sum of all input elements preceding it.
//
// Algorithm :
// -----------
// The parallel prefix sum has two principal parts, the reduce phase (also known as the up-sweep phase) and the down-sweep phase.
//
// In the up-sweep reduction phase we traverse the computation tree from bottom to top, computing partial sums.
// After this phase, the last element of the array contains the total sum.
//
// During the down-sweep phase, we traverse the tree from the root and use the partial sums to build the scan in place.
//
// Because the scan pictured is an exclusive sum, a zero is inserted into the last element before the start of the down-sweep phase.
// This zero is then propagated back to the first element.
//
// In our implementation, each compute unit loads and sums up two elements (for the deepest depth). Each subsequent depth during the up-sweep
// phase is processed by half of the compute units from the deeper level and the other way around for the down-sweep phase.
//
// In order to be able to scan large arrays, i.e. arrays that have many more elements than the maximum size of a work-group, the prefix sum has to be decomposed.
// Each work-group computes the prefix scan of its sub-range and outputs a single number representing the sum of all elements in its sub-range.
// The workgroup sums are scanned using exactly the same algorithm.
// When the number of work-group results reaches the size of a work-group, the process is reversed and the work-group sums are
// propagated to the sub-ranges, where each work-group adds the incoming sum to all its elements, thus producing the final scanned array.
//
// References :
// ------------
// http://graphics.idav.ucdavis.edu/publications/print_pub?pub_id=1041
//
// To read :
// http://developer.apple.com/library/mac/#samplecode/OpenCL_Parallel_Prefix_Sum_Example/Listings/scan_kernel_cl.html#//apple_ref/doc/uid/DTS40008183-scan_kernel_cl-DontLinkElementID_5
// http://developer.apple.com/library/mac/#samplecode/OpenCL_Parallel_Reduction_Example/Listings/reduce_int4_kernel_cl.html
//------------------------------------------------------------

// #pragma OPENCL EXTENSION cl_amd_printf : enable

#define T int
#define OPERATOR_APPLY(A,B) A+B
#define OPERATOR_IDENTITY 0

//#define VOLATILE volatile
#define VOLATILE

//------------------------------------------------------------
// kernel__scanInter
//
// Purpose : do a scan on a chunck of data.
//------------------------------------------------------------

inline T scan_simt_exclusive(__local VOLATILE T* input, size_t idx, const uint lane)
{
	if (lane > 0 ) input[idx] = OPERATOR_APPLY(input[idx - 1] , input[idx]);
	if (lane > 1 ) input[idx] = OPERATOR_APPLY(input[idx - 2] , input[idx]);
	if (lane > 3 ) input[idx] = OPERATOR_APPLY(input[idx - 4] , input[idx]);
	if (lane > 7 ) input[idx] = OPERATOR_APPLY(input[idx - 8] , input[idx]);
	if (lane > 15) input[idx] = OPERATOR_APPLY(input[idx - 16], input[idx]);

	return (lane > 0) ? input[idx-1] : OPERATOR_IDENTITY;
}

inline T scan_simt_inclusive(__local VOLATILE T* input, size_t idx, const uint lane)
{
	if (lane > 0 ) input[idx] = OPERATOR_APPLY(input[idx - 1] , input[idx]);
	if (lane > 1 ) input[idx] = OPERATOR_APPLY(input[idx - 2] , input[idx]);
	if (lane > 3 ) input[idx] = OPERATOR_APPLY(input[idx - 4] , input[idx]);
	if (lane > 7 ) input[idx] = OPERATOR_APPLY(input[idx - 8] , input[idx]);
	if (lane > 15) input[idx] = OPERATOR_APPLY(input[idx - 16], input[idx]);

	return input[idx];
}

inline T scan_workgroup_exclusive(__local T* localBuf, const uint idx, const uint lane, const uint simt_bid)
{
	// Step 1: Intra-warp scan in each warp
	T val = scan_simt_exclusive(localBuf, idx, lane);
	barrier(CLK_LOCAL_MEM_FENCE);

	// Step 2: Collect per-warp partial results (the sum)
	if (lane > 30) localBuf[simt_bid] = localBuf[idx];
	barrier(CLK_LOCAL_MEM_FENCE);

	// Step 3: Use 1st warp to scan per-warp results
	if (simt_bid < 1) scan_simt_inclusive(localBuf, idx, lane);
	barrier(CLK_LOCAL_MEM_FENCE);

	// Step 4: Accumulate results from Steps 1 and 3
	if (simt_bid > 0) val = OPERATOR_APPLY(localBuf[simt_bid-1], val);
	barrier(CLK_LOCAL_MEM_FENCE);

	// Step 5: Write and return the final result
	localBuf[idx] = val;
	barrier(CLK_LOCAL_MEM_FENCE);

	return val;
}

__kernel
void kernel__scan_block_anylength(
	__local T* localBuf,
	__global T* dataSet,
	const uint B,
	uint size,
	const uint passesCount
)
{
	size_t idx = get_local_id(0);
	const uint bidx = get_group_id(0);
	const uint TC = get_local_size(0);

	const uint lane = idx & 31;
	const uint simt_bid = idx >> 5;

	T reduceValue = OPERATOR_IDENTITY;

	//#pragma unroll 4
	for(uint i = 0; i < passesCount; ++i)
	{
		const uint offset = i * TC + (bidx * B);
		const uint offsetIdx = offset + idx;

		if (offsetIdx > size-1) return;

		// Step 1: Read TC elements from global (off-chip) memory to local memory (on-chip)
		T input = localBuf[idx] = dataSet[offsetIdx];

		/*
		// This version try to avoid bank conflicts and improve memory access serializations !
		if (lane < 1)
		{
			__global T* currentOffset = inputDatas + offsetIdx;
			vstore16(vload16(0, currentOffset),  0, localBuf);
			vstore16(vload16(0, currentOffset + 16), 16, localBuf);
		}
		barrier(CLK_LOCAL_MEM_FENCE);
		T input = localBuf[idx];
		*/

		barrier(CLK_LOCAL_MEM_FENCE);

		// Step 2: Perform scan on TC elements
		T val = scan_workgroup_exclusive(localBuf, idx, lane, simt_bid);

		// Step 3: Propagate reduced result from previous block of TC elements
		val = OPERATOR_APPLY(val, reduceValue);

		// Step 4: Write out data to global memory
		dataSet[offsetIdx] = val;

		// Step 5: Choose reduced value for next iteration
		if (idx == (TC-1))
		{
			//localBuf[idx] = (Kind == exclusive) ? OPERATOR_APPLY(input, val) : val;
			localBuf[idx] = OPERATOR_APPLY(input, val);
		}
		barrier(CLK_LOCAL_MEM_FENCE);

		reduceValue = localBuf[TC-1];
		barrier(CLK_LOCAL_MEM_FENCE);
	}
}


Add clamping for y dimension.

Add clamping for y dimension.

/*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, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Peng Xiao, pengxiao@multicorewareinc.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 oclMaterials 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*/

#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable

#ifdef L2GRAD
inline float calc(int x, int y)
{
    return sqrt((float)(x * x + y * y));
}
#else
inline float calc(int x, int y)
{
    return (float)abs(x) + abs(y);
}
#endif //

// Smoothing perpendicular to the derivative direction with a triangle filter
// only support 3x3 Sobel kernel
// h (-1) =  1, h (0) =  2, h (1) =  1
// h'(-1) = -1, h'(0) =  0, h'(1) =  1
// thus sobel 2D operator can be calculated as:
// h'(x, y) = h'(x)h(y) for x direction
//
// src		input 8bit single channel image data
// dx_buf	output dx buffer
// dy_buf	output dy buffer
__kernel
void
__attribute__((reqd_work_group_size(16,16,1)))
calcSobelRowPass
(
    __global const uchar * src,
    __global int * dx_buf,
    __global int * dy_buf,
    int rows,
    int cols,
    int src_step,
    int src_offset,
    int dx_buf_step,
    int dx_buf_offset,
    int dy_buf_step,
    int dy_buf_offset
)
{
    dx_buf_step   /= sizeof(*dx_buf);
    dx_buf_offset /= sizeof(*dx_buf);
    dy_buf_step   /= sizeof(*dy_buf);
    dy_buf_offset /= sizeof(*dy_buf);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    __local int smem[16][18];

    smem[lidy][lidx + 1] =
        src[gidx + min(gidy, rows - 1) * src_step + src_offset];
    if(lidx == 0)
    {
        smem[lidy][0]  =
            src[max(gidx - 1,  0)        + min(gidy, rows - 1) * src_step + src_offset];
        smem[lidy][17] =
            src[min(gidx + 16, cols - 1) + min(gidy, rows - 1) * src_step + src_offset];
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    if(gidy < rows && gidx < cols)
    {
        dx_buf[gidx + gidy * dx_buf_step + dx_buf_offset] =
            -smem[lidy][lidx] + smem[lidy][lidx + 2];
        dy_buf[gidx + gidy * dy_buf_step + dy_buf_offset] =
            smem[lidy][lidx] + 2 * smem[lidy][lidx + 1] + smem[lidy][lidx + 2];
    }
}

// calculate the magnitude of the filter pass combining both x and y directions
// This is the buffered version(3x3 sobel)
//
// dx_buf		dx buffer, calculated from calcSobelRowPass
// dy_buf		dy buffer, calculated from calcSobelRowPass
// dx			direvitive in x direction output
// dy			direvitive in y direction output
// mag			magnitude direvitive of xy output
__kernel
void
__attribute__((reqd_work_group_size(16,16,1)))
calcMagnitude_buf
(
    __global const int * dx_buf,
    __global const int * dy_buf,
    __global int * dx,
    __global int * dy,
    __global float * mag,
    int rows,
    int cols,
    int dx_buf_step,
    int dx_buf_offset,
    int dy_buf_step,
    int dy_buf_offset,
    int dx_step,
    int dx_offset,
    int dy_step,
    int dy_offset,
    int mag_step,
    int mag_offset
)
{
    dx_buf_step    /= sizeof(*dx_buf);
    dx_buf_offset  /= sizeof(*dx_buf);
    dy_buf_step    /= sizeof(*dy_buf);
    dy_buf_offset  /= sizeof(*dy_buf);
    dx_step    /= sizeof(*dx);
    dx_offset  /= sizeof(*dx);
    dy_step    /= sizeof(*dy);
    dy_offset  /= sizeof(*dy);
    mag_step   /= sizeof(*mag);
    mag_offset /= sizeof(*mag);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    __local int sdx[18][16];
    __local int sdy[18][16];

    sdx[lidy + 1][lidx] =
        dx_buf[gidx + min(gidy, rows - 1) * dx_buf_step + dx_buf_offset];
    sdy[lidy + 1][lidx] =
        dy_buf[gidx + min(gidy, rows - 1) * dy_buf_step + dy_buf_offset];
    if(lidy == 0)
    {
        sdx[0][lidx]  =
            dx_buf[gidx + min(max(gidy-1,0),rows-1) * dx_buf_step + dx_buf_offset];
        sdx[17][lidx] =
            dx_buf[gidx + min(gidy + 16, rows - 1)  * dx_buf_step + dx_buf_offset];

        sdy[0][lidx]  =
            dy_buf[gidx + min(max(gidy-1,0),rows-1) * dy_buf_step + dy_buf_offset];
        sdy[17][lidx] =
            dy_buf[gidx + min(gidy + 16, rows - 1)  * dy_buf_step + dy_buf_offset];
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    if(gidx < cols && gidy < rows)
    {
        int x =  sdx[lidy][lidx] + 2 * sdx[lidy + 1][lidx] + sdx[lidy + 2][lidx];
        int y = -sdy[lidy][lidx] + sdy[lidy + 2][lidx];

        dx[gidx + gidy * dx_step + dx_offset] = x;
        dy[gidx + gidy * dy_step + dy_offset] = y;

        mag[(gidx + 1) + (gidy + 1) * mag_step + mag_offset] = calc(x, y);
    }
}

// calculate the magnitude of the filter pass combining both x and y directions
// This is the non-buffered version(non-3x3 sobel)
//
// dx_buf		dx buffer, calculated from calcSobelRowPass
// dy_buf		dy buffer, calculated from calcSobelRowPass
// dx			direvitive in x direction output
// dy			direvitive in y direction output
// mag			magnitude direvitive of xy output
__kernel
void calcMagnitude
(
    __global const int * dx,
    __global const int * dy,
    __global float * mag,
    int rows,
    int cols,
    int dx_step,
    int dx_offset,
    int dy_step,
    int dy_offset,
    int mag_step,
    int mag_offset
)
{
    dx_step    /= sizeof(*dx);
    dx_offset  /= sizeof(*dx);
    dy_step    /= sizeof(*dy);
    dy_offset  /= sizeof(*dy);
    mag_step   /= sizeof(*mag);
    mag_offset /= sizeof(*mag);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    if(gidy < rows && gidx < cols)
    {
        mag[(gidx + 1) + (gidy + 1) * mag_step + mag_offset] =
            calc(
                dx[gidx + gidy * dx_step + dx_offset],
                dy[gidx + gidy * dy_step + dy_offset]
            );
    }
}

//////////////////////////////////////////////////////////////////////////////////////////
// 0.4142135623730950488016887242097 is tan(22.5)
#define CANNY_SHIFT 15
#define TG22        (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5)

//First pass of edge detection and non-maximum suppression
// edgetype is set to for each pixel:
// 0 - below low thres, not an edge
// 1 - maybe an edge
// 2 - is an edge, either magnitude is greater than high thres, or
//     Given estimates of the image gradients, a search is then carried out
//     to determine if the gradient magnitude assumes a local maximum in the gradient direction.
//     if the rounded gradient angle is zero degrees (i.e. the edge is in the north-south direction) the point will be considered to be on the edge if its gradient magnitude is greater than the magnitudes in the west and east directions,
//     if the rounded gradient angle is 90 degrees (i.e. the edge is in the east-west direction) the point will be considered to be on the edge if its gradient magnitude is greater than the magnitudes in the north and south directions,
//     if the rounded gradient angle is 135 degrees (i.e. the edge is in the north east-south west direction) the point will be considered to be on the edge if its gradient magnitude is greater than the magnitudes in the north west and south east directions,
//     if the rounded gradient angle is 45 degrees (i.e. the edge is in the north west-south east direction)the point will be considered to be on the edge if its gradient magnitude is greater than the magnitudes in the north east and south west directions.
//
// dx, dy		direvitives of x and y direction
// mag			magnitudes calculated from calcMagnitude function
// map			output containing raw edge types
__kernel
void
__attribute__((reqd_work_group_size(16,16,1)))
calcMap
(
    __global const int * dx,
    __global const int * dy,
    __global const float * mag,
    __global int * map,
    int rows,
    int cols,
    float low_thresh,
    float high_thresh,
    int dx_step,
    int dx_offset,
    int dy_step,
    int dy_offset,
    int mag_step,
    int mag_offset,
    int map_step,
    int map_offset
)
{
    dx_step    /= sizeof(*dx);
    dx_offset  /= sizeof(*dx);
    dy_step    /= sizeof(*dy);
    dy_offset  /= sizeof(*dy);
    mag_step   /= sizeof(*mag);
    mag_offset /= sizeof(*mag);
    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);

    __local float smem[18][18];

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    int grp_idx = get_global_id(0) & 0xFFFFF0;
    int grp_idy = get_global_id(1) & 0xFFFFF0;

    int tid = lidx + lidy * 16;
    int lx = tid % 18;
    int ly = tid / 18;
    if(ly < 14)
    {
        smem[ly][lx] =
            mag[grp_idx + lx + min(grp_idy + ly, rows - 1) * mag_step];
    }
    if(ly < 4 && grp_idy + ly + 14 <= rows && grp_idx + lx <= cols)
    {
        smem[ly + 14][lx] =
            mag[grp_idx + lx + min(grp_idy + ly + 14, rows -1) * mag_step];
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    if(gidy < rows && gidx < cols)
    {
        int x = dx[gidx + gidy * dx_step];
        int y = dy[gidx + gidy * dy_step];
        const int s = (x ^ y) < 0 ? -1 : 1;
        const float m = smem[lidy + 1][lidx + 1];
        x = abs(x);
        y = abs(y);

        // 0 - the pixel can not belong to an edge
        // 1 - the pixel might belong to an edge
        // 2 - the pixel does belong to an edge
        int edge_type = 0;
        if(m > low_thresh)
        {
            const int tg22x = x * TG22;
            const int tg67x = tg22x + (x << (1 + CANNY_SHIFT));
            y <<= CANNY_SHIFT;
            if(y < tg22x)
            {
                if(m > smem[lidy + 1][lidx] && m >= smem[lidy + 1][lidx + 2])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
            else if (y > tg67x)
            {
                if(m > smem[lidy][lidx + 1]&& m >= smem[lidy + 2][lidx + 1])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
            else
            {
                if(m > smem[lidy][lidx + 1 - s]&& m > smem[lidy + 2][lidx + 1 + s])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
        }
        map[gidx + 1 + (gidy + 1) * map_step] = edge_type;
    }
}

#undef CANNY_SHIFT
#undef TG22

//////////////////////////////////////////////////////////////////////////////////////////
// do Hysteresis for pixel whose edge type is 1
//
// If candidate pixel (edge type is 1) has a neighbour pixel (in 3x3 area) with type 2, it is believed to be part of an edge and
// marked as edge. Each thread will iterate for 16 times to connect local edges.
// Candidate pixel being identified as edge will then be tested if there is nearby potiential edge points. If there is, counter will
// be incremented by 1 and the point location is stored. These potiential candidates will be processed further in next kernel.
//
// map		raw edge type results calculated from calcMap.
// st		the potiential edge points found in this kernel call
// counter	the number of potiential edge points
__kernel
void
__attribute__((reqd_work_group_size(16,16,1)))
edgesHysteresisLocal
(
    __global int * map,
    __global ushort2 * st,
    volatile __global unsigned int * counter,
    int rows,
    int cols,
    int map_step,
    int map_offset
)
{
    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);

    __local int smem[18][18];

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    int grp_idx = get_global_id(0) & 0xFFFFF0;
    int grp_idy = get_global_id(1) & 0xFFFFF0;

    int tid = lidx + lidy * 16;
    int lx = tid % 18;
    int ly = tid / 18;
    if(ly < 14)
    {
        smem[ly][lx] =
            map[grp_idx + lx + min(grp_idy + ly, rows - 1) * map_step + map_offset];
    }
    if(ly < 4 && grp_idy + ly + 14 <= rows && grp_idx + lx <= cols)
    {
        smem[ly + 14][lx] =
            map[grp_idx + lx + min(grp_idy + ly + 14, rows - 1) * map_step + map_offset];
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    if(gidy < rows && gidx < cols)
    {
        int n;

        #pragma unroll
        for (int k = 0; k < 16; ++k)
        {
            n = 0;

            if (smem[lidy + 1][lidx + 1] == 1)
            {
                n += smem[lidy    ][lidx    ] == 2;
                n += smem[lidy    ][lidx + 1] == 2;
                n += smem[lidy    ][lidx + 2] == 2;

                n += smem[lidy + 1][lidx    ] == 2;
                n += smem[lidy + 1][lidx + 2] == 2;

                n += smem[lidy + 2][lidx    ] == 2;
                n += smem[lidy + 2][lidx + 1] == 2;
                n += smem[lidy + 2][lidx + 2] == 2;
            }

            if (n > 0)
                smem[lidy + 1][lidx + 1] = 2;
        }

        const int e = smem[lidy + 1][lidx + 1];
        map[gidx + 1 + (gidy + 1) * map_step] = e;

        n = 0;
        if(e == 2)
        {
            n += smem[lidy    ][lidx    ] == 1;
            n += smem[lidy    ][lidx + 1] == 1;
            n += smem[lidy    ][lidx + 2] == 1;

            n += smem[lidy + 1][lidx    ] == 1;
            n += smem[lidy + 1][lidx + 2] == 1;

            n += smem[lidy + 2][lidx    ] == 1;
            n += smem[lidy + 2][lidx + 1] == 1;
            n += smem[lidy + 2][lidx + 2] == 1;
        }

        if(n > 0)
        {
            unsigned int ind = atomic_inc(counter);
            st[ind] = (ushort2)(gidx + 1, gidy + 1);
        }
    }
}

__constant int c_dx[8] = {-1,  0,  1, -1, 1, -1, 0, 1};
__constant int c_dy[8] = {-1, -1, -1,  0, 0,  1, 1, 1};

#define stack_size 512
__kernel
void edgesHysteresisGlobal
(
    __global int * map,
    __global ushort2 * st1,
    __global ushort2 * st2,
    volatile __global int * counter,
    int rows,
    int cols,
    int count,
    int map_step,
    int map_offset
)
{

    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    int grp_idx = get_group_id(0);
    int grp_idy = get_group_id(1);

    volatile __local unsigned int s_counter;
    __local unsigned int s_ind;

    __local ushort2 s_st[stack_size];

    if(lidx == 0)
    {
        s_counter = 0;
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    int ind = mad24(grp_idy, (int)get_local_size(0), grp_idx);

    if(ind < count)
    {
        ushort2 pos = st1[ind];
        if (pos.x > 0 && pos.x <= cols && pos.y > 0 && pos.y <= rows)
        {
            if (lidx < 8)
            {
                pos.x += c_dx[lidx];
                pos.y += c_dy[lidx];

                if (map[pos.x + pos.y * map_step] == 1)
                {
                    map[pos.x + pos.y * map_step] = 2;

                    ind = atomic_inc(&s_counter);

                    s_st[ind] = pos;
                }
            }
            barrier(CLK_LOCAL_MEM_FENCE);

            while (s_counter > 0 && s_counter <= stack_size - get_local_size(0))
            {
                const int subTaskIdx = lidx >> 3;
                const int portion = min(s_counter, (uint)(get_local_size(0)>> 3));

                pos.x = pos.y = 0;

                if (subTaskIdx < portion)
                    pos = s_st[s_counter - 1 - subTaskIdx];
                barrier(CLK_LOCAL_MEM_FENCE);

                if (lidx == 0)
                    s_counter -= portion;
                barrier(CLK_LOCAL_MEM_FENCE);

                if (pos.x > 0 && pos.x <= cols && pos.y > 0 && pos.y <= rows)
                {
                    pos.x += c_dx[lidx & 7];
                    pos.y += c_dy[lidx & 7];

                    if (map[pos.x + map_offset + pos.y * map_step] == 1)
                    {
                        map[pos.x + map_offset + pos.y * map_step] = 2;

                        ind = atomic_inc(&s_counter);

                        s_st[ind] = pos;
                    }
                }
                barrier(CLK_LOCAL_MEM_FENCE);
            }

            if (s_counter > 0)
            {
                if (lidx == 0)
                {
                    ind = atomic_add(counter, s_counter);
                    s_ind = ind - s_counter;
                }
                barrier(CLK_LOCAL_MEM_FENCE);

                ind = s_ind;

                for (int i = lidx; i < s_counter; i += get_local_size(0))
                {
                    st2[ind + i] = s_st[i];
                }
            }
        }
    }
}
#undef stack_size

//Get the edge result. egde type of value 2 will be marked as an edge point and set to 255. Otherwise 0.
// map		edge type mappings
// dst		edge output
__kernel
void getEdges
(
    __global const int * map,
    __global uchar * dst,
    int rows,
    int cols,
    int map_step,
    int map_offset,
    int dst_step,
    int dst_offset
)
{
    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    if(gidy < rows && gidx < cols)
    {
        dst[gidx + gidy * dst_step] = (uchar)(-(map[gidx + 1 + (gidy + 1) * map_step] >> 1));
    }
}

/*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, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Peng Xiao, pengxiao@multicorewareinc.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 oclMaterials 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*/

#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable

#ifdef L2GRAD
inline float calc(int x, int y)
{
    return sqrt((float)(x * x + y * y));
}
#else
inline float calc(int x, int y)
{
    return (float)abs(x) + abs(y);
}
#endif //

// Smoothing perpendicular to the derivative direction with a triangle filter
// only support 3x3 Sobel kernel
// h (-1) =  1, h (0) =  2, h (1) =  1
// h'(-1) = -1, h'(0) =  0, h'(1) =  1
// thus sobel 2D operator can be calculated as:
// h'(x, y) = h'(x)h(y) for x direction
//
// src		input 8bit single channel image data
// dx_buf	output dx buffer
// dy_buf	output dy buffer
__kernel
    void calcSobelRowPass
    (
    __global const uchar * src,
    __global int * dx_buf,
    __global int * dy_buf,
    int rows,
    int cols,
    int src_step,
    int src_offset,
    int dx_buf_step,
    int dx_buf_offset,
    int dy_buf_step,
    int dy_buf_offset
    )
{
    //src_step   /= sizeof(*src);
    //src_offset /= sizeof(*src);
    dx_buf_step   /= sizeof(*dx_buf);
    dx_buf_offset /= sizeof(*dx_buf);
    dy_buf_step   /= sizeof(*dy_buf);
    dy_buf_offset /= sizeof(*dy_buf);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    __local int smem[16][18];

    smem[lidy][lidx + 1] = src[gidx + gidy * src_step + src_offset];
    if(lidx == 0)
    {
        smem[lidy][0]  = src[max(gidx - 1,  0)        + gidy * src_step + src_offset];
        smem[lidy][17] = src[min(gidx + 16, cols - 1) + gidy * src_step + src_offset];
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    if(gidy < rows)
    {

        if(gidx < cols)
        {
            dx_buf[gidx + gidy * dx_buf_step + dx_buf_offset] =
                -smem[lidy][lidx] + smem[lidy][lidx + 2];
            dy_buf[gidx + gidy * dy_buf_step + dy_buf_offset] =
                smem[lidy][lidx] + 2 * smem[lidy][lidx + 1] + smem[lidy][lidx + 2];
        }
    }
}

// calculate the magnitude of the filter pass combining both x and y directions
// This is the buffered version(3x3 sobel)
//
// dx_buf		dx buffer, calculated from calcSobelRowPass
// dy_buf		dy buffer, calculated from calcSobelRowPass
// dx			direvitive in x direction output
// dy			direvitive in y direction output
// mag			magnitude direvitive of xy output
__kernel
    void calcMagnitude_buf
    (
    __global const int * dx_buf,
    __global const int * dy_buf,
    __global int * dx,
    __global int * dy,
    __global float * mag,
    int rows,
    int cols,
    int dx_buf_step,
    int dx_buf_offset,
    int dy_buf_step,
    int dy_buf_offset,
    int dx_step,
    int dx_offset,
    int dy_step,
    int dy_offset,
    int mag_step,
    int mag_offset
    )
{
    dx_buf_step    /= sizeof(*dx_buf);
    dx_buf_offset  /= sizeof(*dx_buf);
    dy_buf_step    /= sizeof(*dy_buf);
    dy_buf_offset  /= sizeof(*dy_buf);
    dx_step    /= sizeof(*dx);
    dx_offset  /= sizeof(*dx);
    dy_step    /= sizeof(*dy);
    dy_offset  /= sizeof(*dy);
    mag_step   /= sizeof(*mag);
    mag_offset /= sizeof(*mag);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    __local int sdx[18][16];
    __local int sdy[18][16];

    sdx[lidy + 1][lidx] = dx_buf[gidx + gidy * dx_buf_step + dx_buf_offset];
    sdy[lidy + 1][lidx] = dy_buf[gidx + gidy * dy_buf_step + dy_buf_offset];
    if(lidy == 0)
    {
        sdx[0][lidx]  = dx_buf[gidx + max(gidy - 1,  0)        * dx_buf_step + dx_buf_offset];
        sdx[17][lidx] = dx_buf[gidx + min(gidy + 16, rows - 1) * dx_buf_step + dx_buf_offset];

        sdy[0][lidx]  = dy_buf[gidx + max(gidy - 1,  0)        * dy_buf_step + dy_buf_offset];
        sdy[17][lidx] = dy_buf[gidx + min(gidy + 16, rows - 1) * dy_buf_step + dy_buf_offset];
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    if(gidx < cols)
    {
        if(gidy < rows)
        {
            int x =  sdx[lidy][lidx] + 2 * sdx[lidy + 1][lidx] + sdx[lidy + 2][lidx];
            int y = -sdy[lidy][lidx] + sdy[lidy + 2][lidx];

            dx[gidx + gidy * dx_step + dx_offset] = x;
            dy[gidx + gidy * dy_step + dy_offset] = y;

            mag[(gidx + 1) + (gidy + 1) * mag_step + mag_offset] = calc(x, y);
        }
    }
}

// calculate the magnitude of the filter pass combining both x and y directions
// This is the non-buffered version(non-3x3 sobel)
//
// dx_buf		dx buffer, calculated from calcSobelRowPass
// dy_buf		dy buffer, calculated from calcSobelRowPass
// dx			direvitive in x direction output
// dy			direvitive in y direction output
// mag			magnitude direvitive of xy output
__kernel
    void calcMagnitude
    (
    __global const int * dx,
    __global const int * dy,
    __global float * mag,
    int rows,
    int cols,
    int dx_step,
    int dx_offset,
    int dy_step,
    int dy_offset,
    int mag_step,
    int mag_offset
    )
{
    dx_step    /= sizeof(*dx);
    dx_offset  /= sizeof(*dx);
    dy_step    /= sizeof(*dy);
    dy_offset  /= sizeof(*dy);
    mag_step   /= sizeof(*mag);
    mag_offset /= sizeof(*mag);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    if(gidy < rows && gidx < cols)
    {
        mag[(gidx + 1) + (gidy + 1) * mag_step + mag_offset] =
            calc(
            dx[gidx + gidy * dx_step + dx_offset],
            dy[gidx + gidy * dy_step + dy_offset]
        );
    }
}

//////////////////////////////////////////////////////////////////////////////////////////
// 0.4142135623730950488016887242097 is tan(22.5)
#define CANNY_SHIFT 15
#define TG22        (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5)

//First pass of edge detection and non-maximum suppression
// edgetype is set to for each pixel:
// 0 - below low thres, not an edge
// 1 - maybe an edge
// 2 - is an edge, either magnitude is greater than high thres, or
//     Given estimates of the image gradients, a search is then carried out
//     to determine if the gradient magnitude assumes a local maximum in the gradient direction.
//     if the rounded gradient angle is zero degrees (i.e. the edge is in the north-south direction) the point will be considered to be on the edge if its gradient magnitude is greater than the magnitudes in the west and east directions,
//     if the rounded gradient angle is 90 degrees (i.e. the edge is in the east-west direction) the point will be considered to be on the edge if its gradient magnitude is greater than the magnitudes in the north and south directions,
//     if the rounded gradient angle is 135 degrees (i.e. the edge is in the north east-south west direction) the point will be considered to be on the edge if its gradient magnitude is greater than the magnitudes in the north west and south east directions,
//     if the rounded gradient angle is 45 degrees (i.e. the edge is in the north west-south east direction)the point will be considered to be on the edge if its gradient magnitude is greater than the magnitudes in the north east and south west directions.
//
// dx, dy		direvitives of x and y direction
// mag			magnitudes calculated from calcMagnitude function
// map			output containing raw edge types
__kernel
    void calcMap
    (
    __global const int * dx,
    __global const int * dy,
    __global const float * mag,
    __global int * map,
    int rows,
    int cols,
    float low_thresh,
    float high_thresh,
    int dx_step,
    int dx_offset,
    int dy_step,
    int dy_offset,
    int mag_step,
    int mag_offset,
    int map_step,
    int map_offset
    )
{
    dx_step    /= sizeof(*dx);
    dx_offset  /= sizeof(*dx);
    dy_step    /= sizeof(*dy);
    dy_offset  /= sizeof(*dy);
    mag_step   /= sizeof(*mag);
    mag_offset /= sizeof(*mag);
    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);

    __local float smem[18][18];

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    int grp_idx = get_global_id(0) & 0xFFFFF0;
    int grp_idy = get_global_id(1) & 0xFFFFF0;

    int tid = lidx + lidy * 16;
    int lx = tid % 18;
    int ly = tid / 18;
    if(ly < 14)
    {
        smem[ly][lx] = mag[grp_idx + lx + (grp_idy + ly) * mag_step];
    }
    if(ly < 4 && grp_idy + ly + 14 <= rows && grp_idx + lx <= cols)
    {
        smem[ly + 14][lx] = mag[grp_idx + lx + (grp_idy + ly + 14) * mag_step];
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    if(gidy < rows && gidx < cols)
    {
        int x = dx[gidx + gidy * dx_step];
        int y = dy[gidx + gidy * dy_step];
        const int s = (x ^ y) < 0 ? -1 : 1;
        const float m = smem[lidy + 1][lidx + 1];
        x = abs(x);
        y = abs(y);

        // 0 - the pixel can not belong to an edge
        // 1 - the pixel might belong to an edge
        // 2 - the pixel does belong to an edge
        int edge_type = 0;
        if(m > low_thresh)
        {
            const int tg22x = x * TG22;
            const int tg67x = tg22x + (x << (1 + CANNY_SHIFT));
            y <<= CANNY_SHIFT;
            if(y < tg22x)
            {
                if(m > smem[lidy + 1][lidx] && m >= smem[lidy + 1][lidx + 2])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
            else if (y > tg67x)
            {
                if(m > smem[lidy][lidx + 1]&& m >= smem[lidy + 2][lidx + 1])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
            else
            {
                if(m > smem[lidy][lidx + 1 - s]&& m > smem[lidy + 2][lidx + 1 + s])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
        }
        map[gidx + 1 + (gidy + 1) * map_step] = edge_type;
    }
}

// non local memory version
__kernel
    void calcMap_2
    (
    __global const int * dx,
    __global const int * dy,
    __global const float * mag,
    __global int * map,
    int rows,
    int cols,
    float low_thresh,
    float high_thresh,
    int dx_step,
    int dx_offset,
    int dy_step,
    int dy_offset,
    int mag_step,
    int mag_offset,
    int map_step,
    int map_offset
    )
{
    dx_step    /= sizeof(*dx);
    dx_offset  /= sizeof(*dx);
    dy_step    /= sizeof(*dy);
    dy_offset  /= sizeof(*dy);
    mag_step   /= sizeof(*mag);
    mag_offset /= sizeof(*mag);
    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    if(gidy < rows && gidx < cols)
    {
        int x = dx[gidx + gidy * dx_step];
        int y = dy[gidx + gidy * dy_step];
        const int s = (x ^ y) < 0 ? -1 : 1;
        const float m = mag[gidx + 1 + (gidy + 1) * mag_step];
        x = abs(x);
        y = abs(y);

        // 0 - the pixel can not belong to an edge
        // 1 - the pixel might belong to an edge
        // 2 - the pixel does belong to an edge
        int edge_type = 0;
        if(m > low_thresh)
        {
            const int tg22x = x * TG22;
            const int tg67x = tg22x + (x << (1 + CANNY_SHIFT));
            y <<= CANNY_SHIFT;
            if(y < tg22x)
            {
                if(m > mag[gidx + (gidy + 1) * mag_step] && m >= mag[gidx + 2 + (gidy + 1) * mag_step])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
            else if (y > tg67x)
            {
                if(m > mag[gidx + 1 + gidy* mag_step] && m >= mag[gidx + 1 + (gidy + 2) * mag_step])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
            else
            {
                if(m > mag[gidx + 1 - s + gidy * mag_step] && m > mag[gidx + 1 + s + (gidy + 2) * mag_step])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
        }
        map[gidx + 1 + (gidy + 1) * map_step] = edge_type;
    }
}

// [256, 1, 1] threaded, local memory version
__kernel
    void calcMap_3
    (
    __global const int * dx,
    __global const int * dy,
    __global const float * mag,
    __global int * map,
    int rows,
    int cols,
    float low_thresh,
    float high_thresh,
    int dx_step,
    int dx_offset,
    int dy_step,
    int dy_offset,
    int mag_step,
    int mag_offset,
    int map_step,
    int map_offset
    )
{
    dx_step    /= sizeof(*dx);
    dx_offset  /= sizeof(*dx);
    dy_step    /= sizeof(*dy);
    dy_offset  /= sizeof(*dy);
    mag_step   /= sizeof(*mag);
    mag_offset /= sizeof(*mag);
    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);

    __local float smem[18][18];

    int lidx = get_local_id(0) % 16;
    int lidy = get_local_id(0) / 16;

    int grp_pix = get_global_id(0); // identifies which pixel is processing currently in the target block
    int grp_ind = get_global_id(1); // identifies which block of pixels is currently processing

    int grp_idx = (grp_ind % (cols/16)) * 16;
    int grp_idy = (grp_ind / (cols/16)) * 16; //(grp_ind / (cols/16)) * 16

    int gidx = grp_idx + lidx;
    int gidy = grp_idy + lidy;

    int tid = get_global_id(0) % 256;
    int lx = tid % 18;
    int ly = tid / 18;
    if(ly < 14)
    {
        smem[ly][lx] = mag[grp_idx + lx + (grp_idy + ly) * mag_step];
    }
    if(ly < 4 && grp_idy + ly + 14 <= rows && grp_idx + lx <= cols)
    {
        smem[ly + 14][lx] = mag[grp_idx + lx + (grp_idy + ly + 14) * mag_step];
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    if(gidy < rows && gidx < cols)
    {
        int x = dx[gidx + gidy * dx_step];
        int y = dy[gidx + gidy * dy_step];
        const int s = (x ^ y) < 0 ? -1 : 1;
        const float m = smem[lidy + 1][lidx + 1];
        x = abs(x);
        y = abs(y);

        // 0 - the pixel can not belong to an edge
        // 1 - the pixel might belong to an edge
        // 2 - the pixel does belong to an edge
        int edge_type = 0;
        if(m > low_thresh)
        {
            const int tg22x = x * TG22;
            const int tg67x = tg22x + (x << (1 + CANNY_SHIFT));
            y <<= CANNY_SHIFT;
            if(y < tg22x)
            {
                if(m > smem[lidy + 1][lidx] && m >= smem[lidy + 1][lidx + 2])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
            else if (y > tg67x)
            {
                if(m > smem[lidy][lidx + 1]&& m >= smem[lidy + 2][lidx + 1])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
            else
            {
                if(m > smem[lidy][lidx + 1 - s]&& m > smem[lidy + 2][lidx + 1 + s])
                {
                    edge_type = 1 + (int)(m > high_thresh);
                }
            }
        }
        map[gidx + 1 + (gidy + 1) * map_step] = edge_type;
    }
}

#undef CANNY_SHIFT
#undef TG22

//////////////////////////////////////////////////////////////////////////////////////////
// do Hysteresis for pixel whose edge type is 1
//
// If candidate pixel (edge type is 1) has a neighbour pixel (in 3x3 area) with type 2, it is believed to be part of an edge and
// marked as edge. Each thread will iterate for 16 times to connect local edges.
// Candidate pixel being identified as edge will then be tested if there is nearby potiential edge points. If there is, counter will
// be incremented by 1 and the point location is stored. These potiential candidates will be processed further in next kernel.
//
// map		raw edge type results calculated from calcMap.
// st		the potiential edge points found in this kernel call
// counter	the number of potiential edge points
__kernel
    void edgesHysteresisLocal
    (
    __global int * map,
    __global ushort2 * st,
    volatile __global unsigned int * counter,
    int rows,
    int cols,
    int map_step,
    int map_offset
    )
{
    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);

    __local int smem[18][18];

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    int grp_idx = get_global_id(0) & 0xFFFFF0;
    int grp_idy = get_global_id(1) & 0xFFFFF0;

    int tid = lidx + lidy * 16;
    int lx = tid % 18;
    int ly = tid / 18;
    if(ly < 14)
    {
        smem[ly][lx] = map[grp_idx + lx + (grp_idy + ly) * map_step + map_offset];
    }
    if(ly < 4 && grp_idy + ly + 14 <= rows && grp_idx + lx <= cols)
    {
        smem[ly + 14][lx] = map[grp_idx + lx + (grp_idy + ly + 14) * map_step + map_offset];
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    if(gidy < rows && gidx < cols)
    {
        int n;

        #pragma unroll
        for (int k = 0; k < 16; ++k)
        {
            n = 0;

            if (smem[lidy + 1][lidx + 1] == 1)
            {
                n += smem[lidy    ][lidx    ] == 2;
                n += smem[lidy    ][lidx + 1] == 2;
                n += smem[lidy    ][lidx + 2] == 2;

                n += smem[lidy + 1][lidx    ] == 2;
                n += smem[lidy + 1][lidx + 2] == 2;

                n += smem[lidy + 2][lidx    ] == 2;
                n += smem[lidy + 2][lidx + 1] == 2;
                n += smem[lidy + 2][lidx + 2] == 2;
            }

            if (n > 0)
                smem[lidy + 1][lidx + 1] = 2;
        }

        const int e = smem[lidy + 1][lidx + 1];
        map[gidx + 1 + (gidy + 1) * map_step] = e;

        n = 0;
        if(e == 2)
        {
            n += smem[lidy    ][lidx    ] == 1;
            n += smem[lidy    ][lidx + 1] == 1;
            n += smem[lidy    ][lidx + 2] == 1;

            n += smem[lidy + 1][lidx    ] == 1;
            n += smem[lidy + 1][lidx + 2] == 1;

            n += smem[lidy + 2][lidx    ] == 1;
            n += smem[lidy + 2][lidx + 1] == 1;
            n += smem[lidy + 2][lidx + 2] == 1;
        }

        if(n > 0)
        {
            unsigned int ind = atomic_inc(counter);
            st[ind] = (ushort2)(gidx + 1, gidy + 1);
        }
    }
}

__constant int c_dx[8] = {-1,  0,  1, -1, 1, -1, 0, 1};
__constant int c_dy[8] = {-1, -1, -1,  0, 0,  1, 1, 1};

#define stack_size 512
__kernel
    void edgesHysteresisGlobal
    (
    __global int * map,
    __global ushort2 * st1,
    __global ushort2 * st2,
    volatile __global int * counter,
    int rows,
    int cols,
    int count,
    int map_step,
    int map_offset
    )
{

    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    int lidx = get_local_id(0);
    int lidy = get_local_id(1);

    int grp_idx = get_group_id(0);
    int grp_idy = get_group_id(1);

    volatile __local unsigned int s_counter;
    __local unsigned int s_ind;

    __local ushort2 s_st[stack_size];

    if(lidx == 0)
    {
        s_counter = 0;
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    int ind = mad24(grp_idy, (int)get_local_size(0), grp_idx);

    if(ind < count)
    {
        ushort2 pos = st1[ind];
        if (pos.x > 0 && pos.x <= cols && pos.y > 0 && pos.y <= rows)
        {
            if (lidx < 8)
            {
                pos.x += c_dx[lidx];
                pos.y += c_dy[lidx];

                if (map[pos.x + pos.y * map_step] == 1)
                {
                    map[pos.x + pos.y * map_step] = 2;

                    ind = atomic_inc(&s_counter);

                    s_st[ind] = pos;
                }
            }
            barrier(CLK_LOCAL_MEM_FENCE);

            while (s_counter > 0 && s_counter <= stack_size - get_local_size(0))
            {
                const int subTaskIdx = lidx >> 3;
                const int portion = min(s_counter, get_local_size(0)>> 3);

                pos.x = pos.y = 0;

                if (subTaskIdx < portion)
                    pos = s_st[s_counter - 1 - subTaskIdx];
                barrier(CLK_LOCAL_MEM_FENCE);

                if (lidx == 0)
                    s_counter -= portion;
                barrier(CLK_LOCAL_MEM_FENCE);

                if (pos.x > 0 && pos.x <= cols && pos.y > 0 && pos.y <= rows)
                {
                    pos.x += c_dx[lidx & 7];
                    pos.y += c_dy[lidx & 7];

                    if (map[pos.x + map_offset + pos.y * map_step] == 1)
                    {
                        map[pos.x + map_offset + pos.y * map_step] = 2;

                        ind = atomic_inc(&s_counter);

                        s_st[ind] = pos;
                    }
                }
                barrier(CLK_LOCAL_MEM_FENCE);
            }

            if (s_counter > 0)
            {
                if (lidx == 0)
                {
                    ind = atomic_add(counter, s_counter);
                    s_ind = ind - s_counter;
                }
                barrier(CLK_LOCAL_MEM_FENCE);

                ind = s_ind;

                for (int i = lidx; i < s_counter; i += get_local_size(0))
                {
                    st2[ind + i] = s_st[i];
                }
            }
        }
    }
}
#undef stack_size

//Get the edge result. egde type of value 2 will be marked as an edge point and set to 255. Otherwise 0.
// map		edge type mappings
// dst		edge output
__kernel
    void getEdges
    (
    __global const int * map,
    __global uchar * dst,
    int rows,
    int cols,
    int map_step,
    int map_offset,
    int dst_step,
    int dst_offset
    )
{
    map_step   /= sizeof(*map);
    map_offset /= sizeof(*map);
    //dst_step   /= sizeof(*dst);
    //dst_offset /= sizeof(*dst);

    int gidx = get_global_id(0);
    int gidy = get_global_id(1);

    if(gidy < rows && gidx < cols)
    {
        //dst[gidx + gidy * dst_step] = map[gidx + 1 + (gidy + 1) * map_step] == 2 ? 255: 0;
        dst[gidx + gidy * dst_step] = (uchar)(-(map[gidx + 1 + (gidy + 1) * map_step] / 2));
    }
}


cl compilration issue

cl compilration issue

/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#define _FLOAT float
#define _FLOAT2 float2
#define _FLOAT4 float4
#define _FLOAT8 float8
#define _INT_MASK_GLOBAL uchar
#define _INT_MASK_LOCAL uchar

#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F /* max value */
#endif

#define UNUSED __attribute__((__unused__))

#define MLO_POOLING_OP_AVE 0
#define MLO_POOLING_OP_MAX 1
#define MLO_POOLING_OP_STC 2

#define MLO_POOLING_GROUP_SZ2 1

#ifndef MLO_POOLING_OP_ID
#define MLO_POOLING_OP_ID 0
#endif
// max
#if MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
#define MLO_POOLING_OP(A, B) fmax(A, B);
#elif MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
#define MLO_POOLING_OP(A, B) (A + B);
#endif

/*********************************************************************************

**********************************************************************************/

#define MLO_BOT_DATA_SZ0 \
    (MLO_POOLING_N_HORIZ_OUT_PIX * MLO_POOLING_STRIDE0 + MLO_POOLING_KERNEL_SZ0 - 1)
#define MLO_BOT_DATA_SZ1 \
    (MLO_POOLING_N_VERT_OUT_PIX * MLO_POOLING_STRIDE1 + MLO_POOLING_KERNEL_SZ1 - 1)

__attribute__((reqd_work_group_size(MLO_POOLING_GROUP_SZ0,
                                    MLO_POOLING_GROUP_SZ1,
                                    MLO_POOLING_GROUP_SZ2))) __kernel void
mloPoolingG(const __global _FLOAT* bot,
            __global _FLOAT* top,
#if !defined(MLO_POOLING_DO_BACKWARD) || MLO_POOLING_OP_ID != MLO_POOLING_OP_MAX
            UNUSED
#endif
                __global _INT_MASK_GLOBAL* mask)
{

    uint x       = get_group_id(0) * MLO_POOLING_GROUP_SZ0 * MLO_POOLING_N_HORIZ_OUT_PIX;
    uint y       = get_group_id(1) * MLO_POOLING_GROUP_SZ1 * MLO_POOLING_N_VERT_OUT_PIX;
    uint lcl_id0 = get_local_id(0);
    uint lcl_id1 = get_local_id(1);
    //		int lcl_id = (lcl_id1 << MLO_POOLING_GROUP_LG2SZ0) + lcl_id0;
    uint ob      = get_global_id(2); // output * batch_sz
    uint b       = ob / MLO_POOLING_N_OUTPUTS;
    uint o       = ob - b * MLO_POOLING_N_OUTPUTS;
    uint bot_x   = (x + lcl_id0 * MLO_POOLING_N_HORIZ_OUT_PIX) * MLO_POOLING_STRIDE0;
    uint bot_y   = (y + lcl_id1 * MLO_POOLING_N_VERT_OUT_PIX) * MLO_POOLING_STRIDE1;
    uint bot_off = b * MLO_POOLING_BOT_BATCH_STRIDE + o * MLO_POOLING_BOT_CHANNEL_STRIDE;

    _FLOAT bot_data[MLO_BOT_DATA_SZ1][MLO_BOT_DATA_SZ0];
    _FLOAT res[MLO_POOLING_N_VERT_OUT_PIX][MLO_POOLING_N_HORIZ_OUT_PIX];
#if defined(MLO_POOLING_DO_BACKWARD) && MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
    _INT_MASK_LOCAL mask_private[MLO_POOLING_N_VERT_OUT_PIX][MLO_POOLING_N_HORIZ_OUT_PIX];
#endif
    for(int k = 0; k < MLO_POOLING_N_VERT_OUT_PIX; k++)
    {
        for(int l = 0; l < MLO_POOLING_N_HORIZ_OUT_PIX; l++)
        {
#if MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
            res[k][l] = -FLT_MAX;
#elif MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
            res[k][l]         = 0;
#endif
        }
    }

    for(uint j = 0; j < MLO_BOT_DATA_SZ1; ++j)
    {
        int run_y = (int)bot_y + j - MLO_POOLING_PAD1;

        for(uint i = 0; i < MLO_BOT_DATA_SZ0; ++i)
        {
            int run_x        = (int)bot_x + i - MLO_POOLING_PAD0;
            uint bot_gbl_off = bot_off + (uint)run_y * MLO_POOLING_BOT_STRIDE + (uint)run_x;
            bool vis         = ((run_y >= 0 && run_y < MLO_POOLING_BOT_HEIGHT) &&
                        (run_x >= 0 && run_x < MLO_POOLING_BOT_WIDTH))
                           ? true
                           : false;
            bot_data[j][i] = (vis) ? bot[bot_gbl_off] : 0;
        }
    }

    for(uint k = 0; k < MLO_POOLING_N_VERT_OUT_PIX; k++)
    {
#if MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
        uint y_dst  = y + lcl_id1 * MLO_POOLING_N_VERT_OUT_PIX + k;
        uint hstart = y_dst * MLO_POOLING_STRIDE1 - MLO_POOLING_PAD1;
        uint hend   = min((uint)(hstart + MLO_POOLING_KERNEL_SZ1),
                        (uint)(MLO_POOLING_BOT_HEIGHT + MLO_POOLING_PAD1));
#endif
        for(uint l = 0; l < MLO_POOLING_N_HORIZ_OUT_PIX; l++)
        {

#if MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
            uint x_dst  = x + lcl_id0 * MLO_POOLING_N_HORIZ_OUT_PIX + l;
            uint wstart = x_dst * MLO_POOLING_STRIDE0 - MLO_POOLING_PAD0;
            uint wend   = min((uint)(wstart + MLO_POOLING_KERNEL_SZ0),
                            (uint)(MLO_POOLING_BOT_WIDTH + MLO_POOLING_PAD0));
            uint pool_size = (hend - hstart) * (wend - wstart);
#endif
#if defined(MLO_POOLING_DO_BACKWARD) && MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
            mask_private[k][l] = 0xFF;
#endif

            for(uint j = 0; j < MLO_POOLING_KERNEL_SZ1; j++)
            {
                for(uint i = 0; i < MLO_POOLING_KERNEL_SZ0; i++)
                {

                    _FLOAT bot_val =
                        bot_data[j + k * MLO_POOLING_STRIDE1][i + l * MLO_POOLING_STRIDE0];
#if 0
						if (y_dst == 0 && x_dst == 6)
						{

							printf("k: %d %f %f\n",
								lcl_off + (k * MLO_POOLING_STRIDE1+j)*MLO_POOLING_LCL_DATA_WIDTH + (l * MLO_POOLING_STRIDE0+i),
								res[k][l],
								bot_val
								);
						}
#endif
#if defined(MLO_POOLING_DO_BACKWARD) && MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
                    if(bot_val > res[k][l])
                    {
                        res[k][l]          = bot_val;
                        mask_private[k][l] = i + MLO_POOLING_KERNEL_SZ0 * j;
                    }
#else
                    res[k][l] = MLO_POOLING_OP(res[k][l], bot_val);
#endif
                }
            }

#if MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
            res[k][l] *= (_FLOAT)1.f / (_FLOAT)pool_size;
#endif
        }
    }

    uint top_y   = (y + lcl_id1 * MLO_POOLING_N_VERT_OUT_PIX);
    uint top_x   = (x + lcl_id0 * MLO_POOLING_N_HORIZ_OUT_PIX);
    uint top_off = b * MLO_POOLING_TOP_BATCH_STRIDE + o * MLO_POOLING_TOP_CHANNEL_STRIDE +
                   top_y * MLO_POOLING_TOP_STRIDE + top_x;
    for(uint k = 0; k < MLO_POOLING_N_VERT_OUT_PIX; k++)
    {
        for(uint l = 0; l < MLO_POOLING_N_HORIZ_OUT_PIX; l++)
        {
            if(top_y + k < MLO_POOLING_TOP_HEIGHT && top_x + l < MLO_POOLING_TOP_WIDTH)
            {
                top[top_off + k * MLO_POOLING_TOP_STRIDE + l] = res[k][l];
#if defined(MLO_POOLING_DO_BACKWARD) && MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
                mask[top_off + k * MLO_POOLING_TOP_STRIDE + l] = mask_private[k][l];
#endif
            }
        }
    }
}

/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#define _FLOAT float
#define _FLOAT2 float2
#define _FLOAT4 float4
#define _FLOAT8 float8
#define _INT_MASK_GLOBAL uchar
#define _INT_MASK_LOCAL uchar

#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F /* max value */
#endif

#define UNUSED __attribute__((__unused__))

#define MLO_POOLING_OP_AVE 0
#define MLO_POOLING_OP_MAX 1
#define MLO_POOLING_OP_STC 2

#define MLO_POOLING_GROUP_SZ2 1

#ifndef MLO_POOLING_OP_ID
#define MLO_POOLING_OP_ID 0
#endif
// max
#if MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
#define MLO_POOLING_OP(A, B) fmax(A, B);
#elif MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
#define MLO_POOLING_OP(A, B) (A + B);
#endif

/*********************************************************************************

**********************************************************************************/

#define MLO_BOT_DATA_SZ0 \
    (MLO_POOLING_N_HORIZ_OUT_PIX * MLO_POOLING_STRIDE0 + MLO_POOLING_KERNEL_SZ0 - 1)
#define MLO_BOT_DATA_SZ1 \
    (MLO_POOLING_N_VERT_OUT_PIX * MLO_POOLING_STRIDE1 + MLO_POOLING_KERNEL_SZ1 - 1)

__attribute__((reqd_work_group_size(MLO_POOLING_GROUP_SZ0,
                                    MLO_POOLING_GROUP_SZ1,
                                    MLO_POOLING_GROUP_SZ2))) __kernel void
mloPoolingG(const __global _FLOAT* bot,
            __global _FLOAT* top,
#if !defined(MLO_POOLING_DO_BACKWARD) || MLO_POOLING_OP_ID != MLO_POOLING_OP_MAX
            UNUSED
#endif
                __global _INT_MASK_GLOBAL* mask)
{

    uint x       = get_group_id(0) * MLO_POOLING_GROUP_SZ0 * MLO_POOLING_N_HORIZ_OUT_PIX;
    uint y       = get_group_id(1) * MLO_POOLING_GROUP_SZ1 * MLO_POOLING_N_VERT_OUT_PIX;
    uint lcl_id0 = get_local_id(0);
    uint lcl_id1 = get_local_id(1);
    //		int lcl_id = (lcl_id1 << MLO_POOLING_GROUP_LG2SZ0) + lcl_id0;
    uint ob      = get_global_id(2); // output * batch_sz
    uint b       = ob / MLO_POOLING_N_OUTPUTS;
    uint o       = ob - b * MLO_POOLING_N_OUTPUTS;
    uint bot_x   = (x + lcl_id0 * MLO_POOLING_N_HORIZ_OUT_PIX) * MLO_POOLING_STRIDE0;
    uint bot_y   = (y + lcl_id1 * MLO_POOLING_N_VERT_OUT_PIX) * MLO_POOLING_STRIDE1;
    uint bot_off = b * MLO_POOLING_BOT_BATCH_STRIDE + o * MLO_POOLING_BOT_CHANNEL_STRIDE;

    _FLOAT bot_data[MLO_BOT_DATA_SZ1][MLO_BOT_DATA_SZ0];
    _FLOAT res[MLO_POOLING_N_VERT_OUT_PIX][MLO_POOLING_N_HORIZ_OUT_PIX];
#if defined(MLO_POOLING_DO_BACKWARD) && MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
    _INT_MASK_LOCAL mask_private[MLO_POOLING_N_VERT_OUT_PIX][MLO_POOLING_N_HORIZ_OUT_PIX];
#endif
    for(int k = 0; k < MLO_POOLING_N_VERT_OUT_PIX; k++)
    {
        for(int l = 0; l < MLO_POOLING_N_HORIZ_OUT_PIX; l++)
        {
#if MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
            res[k][l] = -FLT_MAX;
#elif MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
            res[k][l]         = 0;
#endif
        }
    }

    for(uint j = 0; j < MLO_BOT_DATA_SZ1; ++j)
    {
        int run_y = (int)bot_y + j - MLO_POOLING_PAD1;

        for(uint i = 0; i < MLO_BOT_DATA_SZ0; ++i)
        {
            int run_x        = (int)bot_x + i - MLO_POOLING_PAD0;
            uint bot_gbl_off = bot_off + (uint)run_y * MLO_POOLING_BOT_STRIDE + (uint)run_x;
            bool vis         = ((run_y >= 0 && run_y < MLO_POOLING_BOT_HEIGHT) &&
                        (run_x >= 0 && run_x < MLO_POOLING_BOT_WIDTH))
                           ? true
                           : false;
            bot_data[j][i] = (vis) ? bot[bot_gbl_off] : 0;
        }
    }

    for(uint k = 0; k < MLO_POOLING_N_VERT_OUT_PIX; k++)
    {
#if MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
        uint y_dst  = y + lcl_id1 * MLO_POOLING_N_VERT_OUT_PIX + k;
        uint hstart = y_dst * MLO_POOLING_STRIDE1 - MLO_POOLING_PAD1;
        uint hend = min(hstart + MLO_POOLING_KERNEL_SZ1, MLO_POOLING_BOT_HEIGHT + MLO_POOLING_PAD1);
#endif
        for(uint l = 0; l < MLO_POOLING_N_HORIZ_OUT_PIX; l++)
        {

#if MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
            uint x_dst  = x + lcl_id0 * MLO_POOLING_N_HORIZ_OUT_PIX + l;
            uint wstart = x_dst * MLO_POOLING_STRIDE0 - MLO_POOLING_PAD0;
            uint wend =
                min(wstart + MLO_POOLING_KERNEL_SZ0, MLO_POOLING_BOT_WIDTH + MLO_POOLING_PAD0);
            uint pool_size = (hend - hstart) * (wend - wstart);
#endif
#if defined(MLO_POOLING_DO_BACKWARD) && MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
            mask_private[k][l] = 0xFF;
#endif

            for(uint j = 0; j < MLO_POOLING_KERNEL_SZ1; j++)
            {
                for(uint i = 0; i < MLO_POOLING_KERNEL_SZ0; i++)
                {

                    _FLOAT bot_val =
                        bot_data[j + k * MLO_POOLING_STRIDE1][i + l * MLO_POOLING_STRIDE0];
#if 0
						if (y_dst == 0 && x_dst == 6)
						{

							printf("k: %d %f %f\n",
								lcl_off + (k * MLO_POOLING_STRIDE1+j)*MLO_POOLING_LCL_DATA_WIDTH + (l * MLO_POOLING_STRIDE0+i),
								res[k][l],
								bot_val
								);
						}
#endif
#if defined(MLO_POOLING_DO_BACKWARD) && MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
                    if(bot_val > res[k][l])
                    {
                        res[k][l]          = bot_val;
                        mask_private[k][l] = i + MLO_POOLING_KERNEL_SZ0 * j;
                    }
#else
                    res[k][l] = MLO_POOLING_OP(res[k][l], bot_val);
#endif
                }
            }

#if MLO_POOLING_OP_ID == MLO_POOLING_OP_AVE
            res[k][l] *= (_FLOAT)1.f / (_FLOAT)pool_size;
#endif
        }
    }

    uint top_y   = (y + lcl_id1 * MLO_POOLING_N_VERT_OUT_PIX);
    uint top_x   = (x + lcl_id0 * MLO_POOLING_N_HORIZ_OUT_PIX);
    uint top_off = b * MLO_POOLING_TOP_BATCH_STRIDE + o * MLO_POOLING_TOP_CHANNEL_STRIDE +
                   top_y * MLO_POOLING_TOP_STRIDE + top_x;
    for(uint k = 0; k < MLO_POOLING_N_VERT_OUT_PIX; k++)
    {
        for(uint l = 0; l < MLO_POOLING_N_HORIZ_OUT_PIX; l++)
        {
            if(top_y + k < MLO_POOLING_TOP_HEIGHT && top_x + l < MLO_POOLING_TOP_WIDTH)
            {
                top[top_off + k * MLO_POOLING_TOP_STRIDE + l] = res[k][l];
#if defined(MLO_POOLING_DO_BACKWARD) && MLO_POOLING_OP_ID == MLO_POOLING_OP_MAX
                mask[top_off + k * MLO_POOLING_TOP_STRIDE + l] = mask_private[k][l];
#endif
            }
        }
    }
}


Support for custom magnetic field sources / CL

Electron trajectory and velocities can be calculated numerically from
the magnetic field data.

//__author__ = "Konstantin Klementiev, Roman Chernikov"
//__date__ = "10 Apr 2015"

#ifdef cl_khr_fp64
#if __OPENCL_VERSION__<120
#pragma OPENCL EXTENSION cl_khr_fp64: enable
#endif
#endif

__kernel void undulator(const float alpha,
                    const float Kx,
                    const float Ky,
                    const float phase,
                    const int jend,
                    __global float* gamma,
                    __global float* wu,
                    __global float* w,
                    __global float* ww1,
                    __global float* ddphi,
                    __global float* ddpsi,
                    __global float* tg,
                    __global float* ag,
                    __global float2* Is_gl,
                    __global float2* Ip_gl)
{
        unsigned int ii = get_global_id(0);
        int j;

        float2 beta;
        float2 eucos;
        float ucos, sinucos, cosucos, sintg, costg, sintgph, costgph;
        float2 zero2 = (float2)(0,0);
        float2 Is = zero2;
        float2 Ip = zero2;
        float wgwu = w[ii] / gamma[ii] / wu[ii];
        float Kx2 = Kx * Kx;
        float Ky2 = Ky * Ky;
        for(j=0; j<jend; j++)
          {
            sintg = sincos(tg[j], &costg);
            sintgph = sincos(tg[j] + phase, &costgph);
            ucos = (float)(ww1[ii]) * tg[j] + wgwu *
               (-Ky * ddphi[ii] * sintg + Kx * ddpsi[ii] * sintgph +
                0.125/gamma[ii] * (Ky2*2*sintg*costg + Kx2*2*sintgph*costgph));

            sinucos = sincos(ucos, &cosucos);
            eucos.x = sinucos;
            eucos.y = cosucos;

            beta.x = -Ky / gamma[ii] * costg;
            beta.y = Kx / gamma[ii] * costgph;

            Is += (ag[j] * (ddphi[ii] + beta.x)) * eucos;
            Ip += (ag[j] * (ddpsi[ii] + beta.y)) * eucos;

          }
        mem_fence(CLK_LOCAL_MEM_FENCE);
        Is_gl[ii] = Is;
        Ip_gl[ii] = Ip;
}

__kernel void undulator_taper(const float alpha,
                    const float Kx,
                    const float Ky,
                    const float phase,
                    const int jend,
                    __global float* gamma,
                    __global float* wu,
                    __global float* w,
                    __global float* ww1,
                    __global float* ddtheta,
                    __global float* ddpsi,
                    __global float* tg,
                    __global float* ag,
                    __global float2* Is_gl,
                    __global float2* Ip_gl)
{
        const float E2W = 1.51926751475e15;
        const float C = 2.99792458e11;
        unsigned int ii = get_global_id(0);
        int j;

        float2 eucos, beta;
        float ucos, sintg, sin2tg, costg;
        float2 zero2 = (float2)(0,0);
        float2 Is = zero2;
        float2 Ip = zero2;
        float Kx2 = Kx * Kx;
        float Ky2 = Ky * Ky;
        float alphaS = alpha * C / wu[ii] / E2W;
        float wgwu = w[ii] / gamma[ii] / wu[ii];
        for(j=0; j<jend; j++)
          {
            sintg = sin(tg[j]);
            sin2tg = sin(2 * tg[j]);
            costg = cos(tg[j]);
            ucos = ww1[ii] * tg[j] + wgwu *
                (-Ky * ddtheta[ii] *(sintg + alphaS *
                                      (1 - costg - tg[j] * sintg)) +
                  Kx * ddpsi[ii] * sin(tg[j] + phase) +
                  0.125 / gamma[ii] *
                  (Ky2 * (sin2tg - 2 * alphaS *
                    (tg[j] * tg[j] + costg * costg + tg[j] * sin2tg)) +
                   Kx2 * sin(2. * (tg[j] + phase))));

            eucos.x = cos(ucos);
            eucos.y = sin(ucos);

            beta.x = -Ky / gamma[ii] * costg;
            beta.y = Kx / gamma[ii] * cos(tg[j] + phase);

            Is += ag[j] * (ddtheta[ii] + beta.x *
                (1 - alphaS * tg[j])) * eucos;
            Ip += ag[j] * (ddpsi[ii] + beta.y) * eucos;
          }
        mem_fence(CLK_LOCAL_MEM_FENCE);
        Is_gl[ii] = Is;
        Ip_gl[ii] = Ip;
}

__kernel void undulator_nf(const float R0,
                    const float Kx,
                    const float Ky,
                    const float phase,
                    const int jend,
                    __global float* gamma,
                    __global float* wu,
                    __global float* w,
                    __global float* ddphi,
                    __global float* ddpsi,
                    __global float* tg,
                    __global float* ag,
                    __global float2* Is_gl,
                    __global float2* Ip_gl)
{
        const float E2W = 1.51926751475e15;
        const float C = 2.99792458e11;

        unsigned int ii = get_global_id(0);
        int j;

        float2 eucos;
        float ucos;
        float2 zero2 = (float2)(0,0);
        float2 Is = zero2;
        float2 Ip = zero2;
        float3 r, r0;
        float2 beta;
        float Kx2 = Kx * Kx;
        float Ky2 = Ky * Ky;
        float gamma2 = gamma[ii] * gamma[ii];
        float betam = 1 - (1 + 0.5 * Kx2 + 0.5 * Ky2) / 2. / gamma2;

        float wR0 = R0 / C * E2W;
        r0.x = wR0 * tan(-ddphi[ii]);
        r0.y = wR0 * tan(ddpsi[ii]);
        r0.z = wR0 * cos(sqrt(ddphi[ii]*ddphi[ii] + ddpsi[ii]*ddpsi[ii]));

        for(j=0; j<jend; j++)
          {

          r.x = Ky / wu[ii] / gamma[ii] * sin(tg[j]);
          r.y = -Kx / wu[ii] / gamma[ii] * sin(tg[j] + phase);
          r.z = betam * tg[j] / wu[ii] - 0.125 / wu[ii] / gamma2 *
                (Ky2 * sin(2 * tg[j]) + Kx2 * sin(2 * (tg[j] + phase)));

          ucos = w[ii] * (tg[j] / wu[ii] + length(r0 - r));

          eucos.x = cos(ucos);
          eucos.y = sin(ucos);

          beta.x = -Ky / gamma[ii] * cos(tg[j]);
          beta.y = Kx / gamma[ii] * cos(tg[j] + phase);

          Is += ag[j] * (-ddphi[ii] + beta.x) * eucos;
          Ip += ag[j] * (ddpsi[ii] + beta.y) * eucos;
          }
        mem_fence(CLK_LOCAL_MEM_FENCE);

        Is_gl[ii] = Is;
        Ip_gl[ii] = Ip;
}

double2 f_beta(double Bx, double By, double Bz,
               double emcg,
               double2 beta)
    {
    return emcg*(double2)(beta.y * Bz - By,
                          Bx - beta.x * Bz);
    }

double3 f_traj(double gamma, double2 beta)
    {
    return (double3)(beta.x,
                     beta.y,
                     sqrt(1. - 1./gamma/gamma - beta.x*beta.x - beta.y*beta.y));
    }

__kernel void undulator_custom(const double Kx,
                    const double Ky,
                    const double phase,
                    const int jend,
                    const int nwt,
                    const double lUnd,
                    __global double* gamma,
                    __global double* wu,
                    __global double* w,
                    __global float* ww1,
                    __global double* ddphi,
                    __global double* ddpsi,
                    __global double* tg,
                    __global double* ag,
                    __global double* Bx,
                    __global double* By,
                    __global double* Bz,
                    __global double2* Is_gl,
                    __global double2* Ip_gl)
{
        const double E2W = 1.51926751475e15;
        const double C = 2.99792458e11;
        const double SIE0 = 1.602176565e-19;
        const double SIM0 = 9.10938291e-31;
        //const double PI = 3.1415926535897932384626433832795;
        const double PI2 = 6.283185307179586476925286766559;

        unsigned int ii = get_global_id(0);
        int j, k;
        double emcg = lUnd * SIE0 / SIM0 / C / gamma[ii] / PI2;

        double2 eucos;
        double ucos, dir;
        double  sintg, costg, sintgph, costgph, sinucos, cosucos, ucos_ref;
        double2 eucos_ref;
        double2 zero2 = (double2)(0,0);
        double2 Is = zero2;
        double2 Ip = zero2;
        double3 r, traj, traj2, n, k1Traj, k2Traj, k3Traj, k4Traj, traj_min, traj_max;
        double2 beta_ref, beta, k1Beta, k2Beta, k3Beta, k4Beta, beta_min, beta_max;

        int iBase, iZeroStep, iHalfStep, iFullStep;
        double rkStep;
	   //double tg2r = 1. / wu[ii]; // lUnd / PI2 * E2W / C;
        n.x = ddphi[ii];
        n.y = ddpsi[ii];
        n.z = 1. - 0.5*(n.x*n.x + n.y*n.y);
        double Kx2 = Kx * Kx;
        double Ky2 = Ky * Ky;
        double gamma2 = gamma[ii] * gamma[ii];
        double revgamma = 1. - 1./gamma2;
        double betam = 1. - (1. + 0.5 * Kx2 + 0.5 * Ky2) / 2. / gamma2;
        double wgwu = w[ii] / gamma[ii] / wu[ii];
        double wu_int;

        beta_max = (double2)(-1e20, -1e20);
        beta_min = (double2)(1e20, 1e20);
        beta = zero2;
        double betam_int=0;

        for (j=1; j<jend; j++)
            {

            iBase = (j-1)*2*nwt;
            rkStep = (tg[j] - tg[j-1]) / nwt;
            for (k=0; k<nwt; k++)
                {
                iZeroStep  = iBase + 2*k;
                iHalfStep = iBase + 2*k + 1;
                iFullStep = iBase + 2*(k + 1);

                k1Beta = rkStep * f_beta(Bx[iZeroStep],
                                         By[iZeroStep],
                                         Bz[iZeroStep],
                                         emcg, beta);
                k2Beta = rkStep * f_beta(Bx[iHalfStep],
                                         By[iHalfStep],
                                         Bz[iHalfStep],
                                         emcg, beta + 0.5*k1Beta);
                k3Beta = rkStep * f_beta(Bx[iHalfStep],
                                         By[iHalfStep],
                                         Bz[iHalfStep],
                                         emcg, beta + 0.5*k2Beta);
                k4Beta = rkStep * f_beta(Bx[iFullStep],
                                         By[iFullStep],
                                         Bz[iFullStep],
                                         emcg, beta + k3Beta);
                beta += (k1Beta + 2.*k2Beta + 2.*k3Beta + k4Beta)/6.;

                if (beta.x > beta_max.x) beta_max.x = beta.x;
                if (beta.y > beta_max.y) beta_max.y = beta.y;
                if (beta.x < beta_min.x) beta_min.x = beta.x;
                if (beta.y < beta_min.y) beta_min.y = beta.y;
                }
			}
        mem_fence(CLK_LOCAL_MEM_FENCE);
	   beta = -0.5*(beta_max + beta_min);

        traj_max = (double3)(-1.0e20, -1.0e20, -1.0e20);
        traj_min = (double3)(1.0e20, 1.0e20, 1.0e20);
        traj = (double3)(0., 0., 0.);

        for (j=1; j<jend; j++)
            {
            iBase = (j-1)*2*nwt;
            rkStep = (tg[j] - tg[j-1]) / nwt;
            for (k=0; k<nwt; k++)
                {
                iZeroStep  = iBase + 2*k;
                iHalfStep = iBase + 2*k + 1;
                iFullStep = iBase + 2*(k + 1);

                k1Beta = rkStep * f_beta(Bx[iZeroStep],
                                         By[iZeroStep],
                                         Bz[iZeroStep],
                                         emcg, beta);
                k1Traj = rkStep * f_traj(gamma[ii], beta);

                k2Beta = rkStep * f_beta(Bx[iHalfStep],
                                         By[iHalfStep],
                                         Bz[iHalfStep],
                                         emcg, beta + 0.5*k1Beta);
                k2Traj = rkStep * f_traj(gamma[ii], beta + 0.5*k1Beta);

                k3Beta = rkStep * f_beta(Bx[iHalfStep],
                                         By[iHalfStep],
                                         Bz[iHalfStep],
                                         emcg, beta + 0.5*k2Beta);
                k3Traj = rkStep * f_traj(gamma[ii], beta + 0.5*k2Beta);

                k4Beta = rkStep * f_beta(Bx[iFullStep],
                                         By[iFullStep],
                                         Bz[iFullStep],
                                         emcg, beta + k3Beta);
                k4Traj = rkStep * f_traj(gamma[ii], beta + k3Beta);

                beta += (k1Beta + 2.*k2Beta + 2.*k3Beta + k4Beta)/6.;
                traj += (k1Traj + 2.*k2Traj + 2.*k3Traj + k4Traj)/6.;
                betam_int += rkStep*sqrt(revgamma - beta.x*beta.x - beta.y*beta.y);

				if (traj.x > traj_max.x) traj_max.x = traj.x;
				if (traj.y > traj_max.y) traj_max.y = traj.y;
				if (traj.z > traj_max.z) traj_max.z = traj.z;
				if (traj.x < traj_min.x) traj_min.x = traj.x;
				if (traj.y < traj_min.y) traj_min.y = traj.y;
				if (traj.z < traj_min.z) traj_min.z = traj.z;
                }
			}
          mem_fence(CLK_LOCAL_MEM_FENCE);
		beta = -0.5*(beta_max + beta_min);
		traj = -0.5*(traj_max + traj_min);
          betam_int /= tg[jend-1] - tg[0];
          wu_int = PI2 * C * betam_int / lUnd / E2W;
          //printf("wu=%2.8e, wu_int=%2.8e\n",wu[ii], wu_int);
        //printf("1-betam: %2.8e, 1-betam_int=%2.8e\n", 1.-betam, 1.-betam_int/(tg[jend-1]-tg[0]));

        for (j=1; j<jend; j++)
            {
            iBase = (j-1)*2*nwt;
            rkStep = (tg[j] - tg[j-1]) / nwt;
            for (k=0; k<nwt; k++)
                {
                iZeroStep  = iBase + 2*k;
                iHalfStep = iBase + 2*k + 1;
                iFullStep = iBase + 2*(k + 1);

                k1Beta = rkStep * f_beta(Bx[iZeroStep],
                                         By[iZeroStep],
                                         Bz[iZeroStep],
                                         emcg, beta);
                k1Traj = rkStep * f_traj(gamma[ii], beta);

                k2Beta = rkStep * f_beta(Bx[iHalfStep],
                                         By[iHalfStep],
                                         Bz[iHalfStep],
                                         emcg, beta + 0.5*k1Beta);
                k2Traj = rkStep * f_traj(gamma[ii], beta + 0.5*k1Beta);

                k3Beta = rkStep * f_beta(Bx[iHalfStep],
                                         By[iHalfStep],
                                         Bz[iHalfStep],
                                         emcg, beta + 0.5*k2Beta);
                k3Traj = rkStep * f_traj(gamma[ii], beta + 0.5*k2Beta);

                k4Beta = rkStep * f_beta(Bx[iFullStep],
                                         By[iFullStep],
                                         Bz[iFullStep],
                                         emcg, beta + k3Beta);
                k4Traj = rkStep * f_traj(gamma[ii], beta + k3Beta);

                beta += (k1Beta + 2.*k2Beta + 2.*k3Beta + k4Beta)/6.;
                traj += (k1Traj + 2.*k2Traj + 2.*k3Traj + k4Traj)/6.;
                }
            mem_fence(CLK_LOCAL_MEM_FENCE);
    		  //traj2 =  tg2r * traj;
    		  dir = dot(n, traj);
            //ucos = w[ii] / wu_int * (tg[j]  - dir);
            ucos = w[ii] / wu[ii] * (tg[j]  - dir);
            //eucos.x = cos(ucos);
            //eucos.y = sin(ucos);
/*
            sintg = sincos(tg[j], &costg);
            sintgph = sincos(tg[j] + phase, &costgph);
            ucos_ref = (double)(ww1[ii]) * tg[j] + wgwu *
               (-Ky * ddphi[ii] * sintg + Kx * ddpsi[ii] * sintgph +
                0.125/gamma[ii] * (Ky2*2*sintg*costg + Kx2*2*sintgph*costgph));

            sinucos = sincos(ucos_ref, &cosucos);
            eucos_ref.x = sinucos;
            eucos_ref.y = cosucos;

		  r.x = Ky / wu[ii] / gamma[ii] * sin(tg[j]);
            r.y = -Kx / wu[ii] / gamma[ii] * sin(tg[j] + phase);
            r.z = betam * tg[j] / wu[ii] - 0.125 / wu[ii] / gamma2 *
                  (Ky2 * sin(2 * tg[j]) + Kx2 * sin(2 * (tg[j] + phase)));

            beta_ref.x = Ky / gamma[ii] * cos(tg[j]);
            beta_ref.y = -Kx / gamma[ii] * cos(tg[j] + phase);

    		  //dir = dot(n, r);

            ucos_ref = w[ii] * (tg[j] / wu[ii] - dot(n, r));

			if (ii==0)
                {
                //printf("n: %2.12v3e\n", n);
			 //printf("[%i] r(int): %2.8v3e\n", j, traj2);
			 printf("[%i] r(int) %2.8v3e\n", j, traj2);
                printf("[%i] r(ref) %2.8v3e\n", j, r);
                //printf("[%i] dr %2.8v3e\n", j, traj2-r);
                printf("dir: %2.8e, dir_ref: %2.8e\n", dir, dot(n, r));
                //printf("1 - betam = %2.16e\n", 1. - betam);
                printf("ucos: %2.8e, ucos_ref: %2.8e, delta_ucos: %2.8e\n", ucos, ucos_ref, ucos-ucos_ref);
                //printf("1st: %2.8e, 1st_ref: %2.8e\n", w[ii] / wu[ii] * (1. - n.z*betam), ww1[ii]);
                //printf("2nd: %2.8e, 2nd_ref: %2.8e\n", betam * tg[j] / wu[ii],  wgwu * Ky * ddphi[ii] * sintg);

                printf("[%i] beta_int: %2.8v2e\n", j, beta);
                printf("[%i] beta_ref: %2.8v2e\n", j, beta_ref);
                }

*/
            eucos.x = cos(ucos);
            eucos.y = sin(ucos);
            Is += ag[j] * (ddphi[ii] - beta.x) * eucos;
            Ip += ag[j] * (ddpsi[ii] - beta.y) * eucos;
        }

        mem_fence(CLK_LOCAL_MEM_FENCE);

        Is_gl[ii] = Is;
        Ip_gl[ii] = Ip;
}


Does not work. kuku~

Does not work. kuku~

__kernel void histogram(__global unsigned int *rst, __constant unsigned int *img, unsigned int sz) {
	unsigned int idx;
	__global unsigned int *tmp = rst;

	for (idx = 0; idx < sz; idx += 3)
		tmp[img[idx]]++;

	tmp += 256;
	for (idx = 1; idx < sz; idx += 3)
		tmp[img[idx]]++;

	tmp += 256;
	for (idx = 2; idx < sz; idx += 3)
		tmp[img[idx]]++;
}

__kernel void histogram(unsigned int *rst, unsigned int *img, unsigned int sz) {
	unsigned int idx, *tmp;
	tmp = rst;

	for (idx = 0; idx < sz; idx += 3)
		tmp[img[idx]]++;

	tmp += 256;
	for (idx = 1; idx < sz; idx += 3)
		tmp[img[idx]]++;

	tmp += 256;
	for (idx = 2; idx < sz; idx += 3)
		tmp[img[idx]]++;
}