Fixed bug in cl_random_state by using int constants rather than longs and returning correct variable.

git-svn-id: 602a26e73ae9f2a14e2bb95676f2e137fcc39919@3090 7c0444ca-5550-0410-9008-faecdbe78eb5

/* rng/taus.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*
 * The following adapted from rng/taus.c by Craig Rasmussen, 12/27/2010
 * for OpenCL.  Also converted (hopefully) to use 32 bit integers.
 *
 * It uses a uint4 to store state and a result:
 *    state.s0 => random number
 *    state.s1 => state s1 value
 *    state.s2 => state s2 value
 *    state.s3 => state s3 value
 */

#include "../arch/opencl/pv_opencl.h"

#define cl_random_state(s) (cl_taus_get(s))

static inline uint4
cl_taus_get(uint4 state)
{
#define TAUSWORTHE(s,a,b,c,d) (((s &c) <<d)) ^ ((((s <<a))^s) >>b)

  state.s1 = TAUSWORTHE (state.s1, 13, 19, 4294967294, 12);
  state.s2 = TAUSWORTHE (state.s2,  2, 25, 4294967288, 4);
  state.s3 = TAUSWORTHE (state.s3,  3, 11, 4294967280, 17);

  state.s0 = (state.s1 ^ state.s2 ^ state.s3);

  return state;
}

static inline float cl_random_prob(uint4 state)
{
   return (float) ((double) state.s0 / (double) 4294967296.0);
}

/* rng/taus.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*
 * The following adapted from rng/taus.c by Craig Rasmussen, 12/27/2010
 * for OpenCL.  Also converted (hopefully) to use 32 bit integers.
 *
 * It uses a uint4 to store state and a result:
 *    state.s0 => random number
 *    state.s1 => state s1 value
 *    state.s2 => state s2 value
 *    state.s3 => state s3 value
 */

#include "../arch/opencl/pv_opencl.h"

#define cl_random_state(s) (cl_taus_get(s))

static inline uint4
cl_taus_get(uint4 state)
{
   uint4 result;

#define TAUSWORTHE(s,a,b,c,d) (((s &c) <<d)) ^ ((((s <<a))^s) >>b)

  result.s1 = TAUSWORTHE (state.s1, 13, 19, 4294967294UL, 12);
  result.s2 = TAUSWORTHE (state.s2,  2, 25, 4294967288UL, 4);
  result.s3 = TAUSWORTHE (state.s3,  3, 11, 4294967280UL, 17);

  result.s0 = (state.s1 ^ state.s2 ^ state.s3);

  return result;
}

static inline float cl_random_prob(uint4 state)
{
   return (float) ((double) state.s0 / (double) 4294967296.0);
}


minor 1x1 update

minor 1x1 update

/*
 * Copyright (c) 2016 AMD Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and/or associated documentation files (the
 * "Materials"), to deal in the Materials without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Materials, and to
 * permit persons to whom the Materials are 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 Materials.
 *
 * THE MATERIALS ARE 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
 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
 */

#define _FLOAT					float
#define _FLOAT2					float2
#define _FLOAT4					float4
#define _FLOAT8					float8

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

/*
Layout:

*/

__kernel void MLOpenConv1x1(
       const __global _FLOAT * restrict in_ptr,
       const __global _FLOAT * restrict wei_ptr,
#if MLO_CONV_BIAS
       const __global _FLOAT * bias,
#endif
 	  __global _FLOAT *out_ptr,
	   _FLOAT dummy_val // nothing
	   )
{
// KERNEL
// private buffers
	__private _FLOAT4 in_stage[MLO_N_LCL_BATCHS][MLO_N_LCL_IN_MAPS];
	__private _FLOAT wei_stage[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];
	__private _FLOAT4 out_tiles[MLO_N_LCL_BATCHS][MLO_N_LCL_OUT_MAPS];
#if MLO_N_MAPS_PERGROUP > 1
	__local _FLOAT4 lcl_in_stage[MLO_GRP_SZ0];

#endif

	int lcl_id0 = get_local_id(0);
	int in_map_id = 0; // map
	int pix_id = get_global_id(0);  // inside map
	in_map_id = pix_id / MLO_MAP_SZ4; // mad id inside group
	int out_grp_block = get_group_id(1); // block of outputs for the entire group
	int out_block = out_grp_block;
	int batch_block = get_group_id(2); // block of batchs
// multipe maps per group
//#if MLO_N_MAPS_PERGROUP > 1
	pix_id = (pix_id - in_map_id * MLO_MAP_SZ4);  // pixel inside map
	out_block = out_grp_block * MLO_N_MAPS_PERGROUP + in_map_id;
//#endif

	int in_off = batch_block * MLO_N_LCL_BATCHS * MLO_IN_BATCH_STRIDE
		+ in_map_id * MLO_IN_CHANNEL_STRIDE
				+ pix_id * 4;

	int wei_off = out_block * MLO_N_LCL_OUT_MAPS * MLO_WEI_BSTRIDE;
	for (int j = 0; j < MLO_N_LCL_BATCHS; ++j)
	{
		for (int i = 0; i < MLO_N_LCL_OUT_MAPS; ++i)
		{
			out_tiles[j][i] = 0;
		}
	}
// over all input maps; with step == MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP; MLO_IN_LOOP
	for (int c = 0; c < MLO_IN_LOOP; ++c,
		in_off += MLO_IN_CHANNEL_STRIDE*MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP,
		wei_off += MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP * MLO_WEI_CHANNEL_STRIDE
//#if MLO_DIR_FORWARD==0
//			* MLO_N_OUTPUTS
//#endif
		)
	{
// read data
// over all local batchs
		int in_off1 = in_off;
		for (int ib = 0; ib < MLO_N_LCL_BATCHS
#if MLO_BATCH_ALIGNED == 0
			&& (batch_block*MLO_N_LCL_BATCHS + ib < MLO_BATCH_SZ)
#endif
			; ++ib, in_off1 += MLO_IN_BATCH_STRIDE)
		{
			int in_off2 = in_off1;
// lcl in maps (in data tiles) is has the stride = MLO_N_MAPS_PERGROUP
			for (int ilc = 0; ilc < MLO_N_LCL_IN_MAPS; ++ilc, in_off2 += MLO_IN_CHANNEL_STRIDE * MLO_N_MAPS_PERGROUP)
			{
				// read data
				//				in_stage[ib][ilc] = 0;
				//				if (c*MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP + in_map_id + ilc* MLO_N_MAPS_PERGROUP < MLO_N_INPUTS)
				{

					in_stage[ib][ilc] = *(_FLOAT4*)&in_ptr[in_off2];
					in_stage[ib][ilc] = (c*MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP + in_map_id + ilc* MLO_N_MAPS_PERGROUP < MLO_N_INPUTS) ? in_stage[ib][ilc] : 0;
#if !MLO_DIVBY4

					// if the last one
					if (pix_id == MLO_MAP_SZ4 - 1)
					{
						for (int j = 3; j >= MLO_C1x1_PIXLEFT; --j)
						{
							((_FLOAT*)&in_stage[ib][ilc])[j] = 0;
						}
					}

#endif
				}
				/*
				if(c*MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP + in_map_id + ilc* MLO_N_MAPS_PERGROUP >= MLO_N_INPUTS)
				{
					in_stage[ib][ilc] = 0;
				}
				*/

			}
		}

// convolve
		int wei_off1 = wei_off + in_map_id * MLO_WEI_CHANNEL_STRIDE;
		for (int olc = 0; olc < MLO_N_LCL_OUT_MAPS; ++olc, wei_off1 += MLO_WEI_BSTRIDE)
		{
			int wei_off2 = wei_off1;
			// lcl in maps (in data tiles) is has the stride = MLO_N_MAPS_PERGROUP, weights are mapped accordingly

			for (int ilc = 0; ilc < MLO_N_LCL_IN_MAPS; ++ilc, wei_off2 += MLO_WEI_CHANNEL_STRIDE * MLO_N_MAPS_PERGROUP)
			{
				// read weights
				wei_stage[olc][ilc] = wei_ptr[wei_off2];
				for (int ib = 0; ib < MLO_N_LCL_BATCHS;  ++ib)
				{
					out_tiles[ib][olc] += in_stage[ib][ilc] * (_FLOAT4)wei_stage[olc][ilc];
#if 0
					if (get_group_id(0) == 312 && get_group_id(1) == 0 && in_map_id == 0 && pix_id == 80065 && olc == 0)
					{
						printf("k:c: 0 %d %d %d %d  %11.10f %11.10f %f %f\n",
							wei_off2,
							get_local_id(0),
							olc,
							ilc,
							out_tiles[ib][olc].s2,
							in_stage[ib][ilc].s2 * wei_stage[olc][ilc],
							in_stage[ib][ilc].s2,
							wei_stage[olc][ilc]
							);
					}
#endif

				}
			}
		}

#if MLO_N_MAPS_PERGROUP > 1
// exchange inputs with other MLO_N_MAPS_PERGROUP - 1 maps
		for (int im = 1; im < MLO_N_MAPS_PERGROUP; ++im)
		{

// mov to different output block
			// exchange data
//			if(pix_id < MLO_MAP_SZ4)
			{
				for(int ib = 0; ib < MLO_N_LCL_BATCHS; ++ib)
				{
					for(int ilc = 0; ilc < MLO_N_LCL_IN_MAPS; ++ilc)
					{
						barrier(CLK_LOCAL_MEM_FENCE);
						lcl_in_stage[lcl_id0] = in_stage[ib][ilc];
						int lcl_off = lcl_id0 + MLO_MAP_SZ4;
						lcl_off = (lcl_off >= MLO_N_MAPS_PERGROUP * MLO_MAP_SZ4) ? lcl_off - MLO_N_MAPS_PERGROUP * MLO_MAP_SZ4 : lcl_off;
						barrier(CLK_LOCAL_MEM_FENCE);
						in_stage[ib][ilc] = lcl_in_stage[lcl_off];
					}
				}
			}
			int imp = in_map_id + im;
			imp = (imp >= MLO_N_MAPS_PERGROUP) ? imp - MLO_N_MAPS_PERGROUP :  imp;
			// convolve
			int wei_off1 = wei_off + imp * MLO_WEI_CHANNEL_STRIDE;
			for (int olc = 0; olc < MLO_N_LCL_OUT_MAPS; ++olc, wei_off1 += MLO_WEI_BSTRIDE)
			{
				int wei_off2 = wei_off1;
				for (int ilc = 0; ilc < MLO_N_LCL_IN_MAPS; ++ilc, wei_off2 += MLO_WEI_CHANNEL_STRIDE * MLO_N_MAPS_PERGROUP)
				{
					// read weights
					wei_stage[olc][ilc] = wei_ptr[wei_off2];
					for (int ib = 0; ib < MLO_N_LCL_BATCHS;++ib)
					{
						out_tiles[ib][olc] += in_stage[ib][ilc] * (_FLOAT4)wei_stage[olc][ilc];
#if 0
						if (get_group_id(0) == 0 && get_group_id(1) == 0 && in_map_id == 4 && pix_id == 27 && olc == 1 )
						{
							printf("k:c: %d %d %d %d %d  %11.10f %11.10f %f %f\n",
								im,
								wei_off2,
								get_local_id(0),
								olc,
								ilc,
								out_tiles[ib][olc].s1,
								in_stage[ib][ilc].s1*wei_stage[olc][ilc],
								in_stage[ib][ilc].s1,
								wei_stage[olc][ilc]
								);
					}
#endif

					}
				}
			}

		}

#endif

	}

	if (in_map_id >= MLO_N_MAPS_PERGROUP || in_map_id*MLO_N_LCL_IN_MAPS >= MLO_N_INPUTS)
	{
		return;
	}

	out_block = out_grp_block * MLO_N_MAPS_PERGROUP + in_map_id;
	int out_off = batch_block * MLO_N_LCL_BATCHS * MLO_OUT_BATCH_STRIDE
		+ out_block * MLO_N_LCL_OUT_MAPS * MLO_OUT_CHANNEL_STRIDE
		+ pix_id * 4;

	int out_off1 = out_off;
	for (int ib = 0; ib < MLO_N_LCL_BATCHS
#if MLO_BATCH_ALIGNED == 0
		&& (batch_block*MLO_N_LCL_BATCHS + ib < MLO_BATCH_SZ)
#endif
		; ++ib, out_off1 += MLO_OUT_BATCH_STRIDE)
	{

		int out_off2 = out_off1;
		for (int olc = 0; olc < MLO_N_LCL_OUT_MAPS
#if MLO_OUTPUTS_ALIGNED == 0
			&& out_block* MLO_N_LCL_OUT_MAPS + olc < MLO_N_OUTPUTS
#endif
			; ++olc, out_off2 += MLO_OUT_CHANNEL_STRIDE)
		{

			_FLOAT  bias_val = 0;
#if MLO_CONV_BIAS
			bias_val = bias[out_block* MLO_N_LCL_OUT_MAPS + olc];
#endif
#if !MLO_DIVBY4

			// if the last one
			if (pix_id == MLO_MAP_SZ4 - 1)
			{
				for (int j = 0; j < MLO_C1x1_PIXLEFT; ++j)
				{
					out_ptr[out_off2 + j] = ((_FLOAT*)&out_tiles[ib][olc])[j] + bias_val;

				}

			}
			else
#endif
			{

				*((_FLOAT4*)&out_ptr[out_off2]) = (out_tiles[ib][olc] + (_FLOAT4)bias_val);
			}

#if 0
			if (out_block* MLO_N_LCL_OUT_MAPS + olc == 0 && pix_id == (444*720 +582) / 4)
			{
				printf("k:o: %d %d %d %d %d %d   %11.10f %f %11.10f\n",
					out_off2 + 2,
					get_group_id(0),
					get_group_id(1),
					in_map_id,
					pix_id,
					olc,
					out_ptr[out_off2 + 2],
					((_FLOAT*)&out_tiles[ib][olc])[2],
					bias_val
					);
			}
#endif

		}

	}

}

/*
 * Copyright (c) 2016 AMD Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and/or associated documentation files (the
 * "Materials"), to deal in the Materials without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Materials, and to
 * permit persons to whom the Materials are 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 Materials.
 *
 * THE MATERIALS ARE 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
 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
 */

#define _FLOAT					float
#define _FLOAT2					float2
#define _FLOAT4					float4
#define _FLOAT8					float8

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

/*
Layout:

*/

__kernel void MLOpenConv1x1(
       const __global _FLOAT * restrict in_ptr,
       const __global _FLOAT * restrict wei_ptr,
#if MLO_CONV_BIAS
       const __global _FLOAT * bias,
#endif
 	  __global _FLOAT *out_ptr,
	   _FLOAT dummy_val // nothing
	   )
{
// KERNEL
// private buffers
	__private _FLOAT4 in_stage[MLO_N_LCL_BATCHS][MLO_N_LCL_IN_MAPS];
	__private _FLOAT wei_stage[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];
	__private _FLOAT4 out_tiles[MLO_N_LCL_BATCHS][MLO_N_LCL_OUT_MAPS];
#if MLO_N_MAPS_PERGROUP > 1
	__local _FLOAT4 lcl_in_stage[MLO_GRP_SZ0];

#endif

	int lcl_id0 = get_local_id(0);
	int in_map_id = 0; // map
	int pix_id = get_global_id(0);  // inside map
	in_map_id = pix_id / MLO_MAP_SZ4; // mad id inside group
	int out_grp_block = get_group_id(1); // block of outputs for the entire group
	int out_block = out_grp_block;
	int batch_block = get_group_id(2); // block of batchs
// multipe maps per group
//#if MLO_N_MAPS_PERGROUP > 1
	pix_id = (pix_id - in_map_id * MLO_MAP_SZ4);  // pixel inside map
	out_block = out_grp_block * MLO_N_MAPS_PERGROUP + in_map_id;
//#endif

	int in_off = batch_block * MLO_N_LCL_BATCHS * MLO_IN_BATCH_STRIDE
		+ in_map_id * MLO_IN_CHANNEL_STRIDE
				+ pix_id * 4;

	int wei_off = out_block * MLO_N_LCL_OUT_MAPS * MLO_WEI_BSTRIDE;
	for (int j = 0; j < MLO_N_LCL_BATCHS; ++j)
	{
		for (int i = 0; i < MLO_N_LCL_OUT_MAPS; ++i)
		{
			out_tiles[j][i] = 0;
		}
	}
// over all input maps; with step == MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP; MLO_IN_LOOP
	for (int c = 0; c < MLO_IN_LOOP; ++c,
		in_off += MLO_IN_CHANNEL_STRIDE*MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP,
		wei_off += MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP * MLO_WEI_CHANNEL_STRIDE
//#if MLO_DIR_FORWARD==0
//			* MLO_N_OUTPUTS
//#endif
		)
	{
// read data
// over all local batchs
		int in_off1 = in_off;
		for (int ib = 0; ib < MLO_N_LCL_BATCHS
#if MLO_BATCH_ALIGNED == 0
			&& (batch_block*MLO_N_LCL_BATCHS + ib < MLO_BATCH_SZ)
#endif
			; ++ib, in_off1 += MLO_IN_BATCH_STRIDE)
		{
			int in_off2 = in_off1;
// lcl in maps (in data tiles) is has the stride = MLO_N_MAPS_PERGROUP
			for (int ilc = 0; ilc < MLO_N_LCL_IN_MAPS; ++ilc, in_off2 += MLO_IN_CHANNEL_STRIDE * MLO_N_MAPS_PERGROUP)
			{
				// read data
				in_stage[ib][ilc] = 0;
				if (c*MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP + in_map_id + ilc* MLO_N_MAPS_PERGROUP < MLO_N_INPUTS)
				{

					in_stage[ib][ilc] = *(_FLOAT4*)&in_ptr[in_off2];

#if !MLO_DIVBY4

					// if the last one
					if (pix_id == MLO_MAP_SZ4 - 1)
					{
						for (int j = 3; j >= MLO_C1x1_PIXLEFT; --j)
						{
							((_FLOAT*)&in_stage[ib][ilc])[j] = 0;
						}
					}

#endif
				}
				/*
				if(c*MLO_N_LCL_IN_MAPS * MLO_N_MAPS_PERGROUP + in_map_id + ilc* MLO_N_MAPS_PERGROUP >= MLO_N_INPUTS)
				{
					in_stage[ib][ilc] = 0;
				}
				*/

			}
		}

// convolve
		int wei_off1 = wei_off + in_map_id * MLO_WEI_CHANNEL_STRIDE;
		for (int olc = 0; olc < MLO_N_LCL_OUT_MAPS; ++olc, wei_off1 += MLO_WEI_BSTRIDE)
		{
			int wei_off2 = wei_off1;
			// lcl in maps (in data tiles) is has the stride = MLO_N_MAPS_PERGROUP, weights are mapped accordingly

			for (int ilc = 0; ilc < MLO_N_LCL_IN_MAPS; ++ilc, wei_off2 += MLO_WEI_CHANNEL_STRIDE * MLO_N_MAPS_PERGROUP)
			{
				// read weights
				wei_stage[olc][ilc] = wei_ptr[wei_off2];
				for (int ib = 0; ib < MLO_N_LCL_BATCHS;  ++ib)
				{
					out_tiles[ib][olc] += in_stage[ib][ilc] * (_FLOAT4)wei_stage[olc][ilc];
#if 0
					if (get_group_id(0) == 312 && get_group_id(1) == 0 && in_map_id == 0 && pix_id == 80065 && olc == 0)
					{
						printf("k:c: 0 %d %d %d %d  %11.10f %11.10f %f %f\n",
							wei_off2,
							get_local_id(0),
							olc,
							ilc,
							out_tiles[ib][olc].s2,
							in_stage[ib][ilc].s2 * wei_stage[olc][ilc],
							in_stage[ib][ilc].s2,
							wei_stage[olc][ilc]
							);
					}
#endif

				}
			}
		}

#if MLO_N_MAPS_PERGROUP > 1
// exchange inputs with other MLO_N_MAPS_PERGROUP - 1 maps
		for (int im = 1; im < MLO_N_MAPS_PERGROUP; ++im)
		{

// mov to different output block
			// exchange data
//			if(pix_id < MLO_MAP_SZ4)
			{
				for(int ib = 0; ib < MLO_N_LCL_BATCHS; ++ib)
				{
					for(int ilc = 0; ilc < MLO_N_LCL_IN_MAPS; ++ilc)
					{
						barrier(CLK_LOCAL_MEM_FENCE);
						lcl_in_stage[lcl_id0] = in_stage[ib][ilc];
						int lcl_off = lcl_id0 + MLO_MAP_SZ4;
						lcl_off = (lcl_off >= MLO_N_MAPS_PERGROUP * MLO_MAP_SZ4) ? lcl_off - MLO_N_MAPS_PERGROUP * MLO_MAP_SZ4 : lcl_off;
						barrier(CLK_LOCAL_MEM_FENCE);
						in_stage[ib][ilc] = lcl_in_stage[lcl_off];
					}
				}
			}
			int imp = in_map_id + im;
			imp = (imp >= MLO_N_MAPS_PERGROUP) ? imp - MLO_N_MAPS_PERGROUP :  imp;
			// convolve
			int wei_off1 = wei_off + imp * MLO_WEI_CHANNEL_STRIDE;
			for (int olc = 0; olc < MLO_N_LCL_OUT_MAPS; ++olc, wei_off1 += MLO_WEI_BSTRIDE)
			{
				int wei_off2 = wei_off1;
				for (int ilc = 0; ilc < MLO_N_LCL_IN_MAPS; ++ilc, wei_off2 += MLO_WEI_CHANNEL_STRIDE * MLO_N_MAPS_PERGROUP)
				{
					// read weights
					wei_stage[olc][ilc] = wei_ptr[wei_off2];
					for (int ib = 0; ib < MLO_N_LCL_BATCHS;++ib)
					{
						out_tiles[ib][olc] += in_stage[ib][ilc] * (_FLOAT4)wei_stage[olc][ilc];
#if 0
						if (get_group_id(0) == 0 && get_group_id(1) == 0 && in_map_id == 4 && pix_id == 27 && olc == 1 )
						{
							printf("k:c: %d %d %d %d %d  %11.10f %11.10f %f %f\n",
								im,
								wei_off2,
								get_local_id(0),
								olc,
								ilc,
								out_tiles[ib][olc].s1,
								in_stage[ib][ilc].s1*wei_stage[olc][ilc],
								in_stage[ib][ilc].s1,
								wei_stage[olc][ilc]
								);
					}
#endif

					}
				}
			}

		}

#endif

	}

	if (in_map_id >= MLO_N_MAPS_PERGROUP || in_map_id*MLO_N_LCL_IN_MAPS >= MLO_N_INPUTS)
	{
		return;
	}

	out_block = out_grp_block * MLO_N_MAPS_PERGROUP + in_map_id;
	int out_off = batch_block * MLO_N_LCL_BATCHS * MLO_OUT_BATCH_STRIDE
		+ out_block * MLO_N_LCL_OUT_MAPS * MLO_OUT_CHANNEL_STRIDE
		+ pix_id * 4;

	int out_off1 = out_off;
	for (int ib = 0; ib < MLO_N_LCL_BATCHS
#if MLO_BATCH_ALIGNED == 0
		&& (batch_block*MLO_N_LCL_BATCHS + ib < MLO_BATCH_SZ)
#endif
		; ++ib, out_off1 += MLO_OUT_BATCH_STRIDE)
	{

		int out_off2 = out_off1;
		for (int olc = 0; olc < MLO_N_LCL_OUT_MAPS
#if MLO_OUTPUTS_ALIGNED == 0
			&& out_block* MLO_N_LCL_OUT_MAPS + olc < MLO_N_OUTPUTS
#endif
			; ++olc, out_off2 += MLO_OUT_CHANNEL_STRIDE)
		{

			_FLOAT  bias_val = 0;
#if MLO_CONV_BIAS
			bias_val = bias[out_block* MLO_N_LCL_OUT_MAPS + olc];
#endif
#if !MLO_DIVBY4

			// if the last one
			if (pix_id == MLO_MAP_SZ4 - 1)
			{
				for (int j = 0; j < MLO_C1x1_PIXLEFT; ++j)
				{
					out_ptr[out_off2 + j] = ((_FLOAT*)&out_tiles[ib][olc])[j] + bias_val;

				}

			}
			else
#endif
			{

				*((_FLOAT4*)&out_ptr[out_off2]) = (out_tiles[ib][olc] + (_FLOAT4)bias_val);
			}

#if 0
			if (out_block* MLO_N_LCL_OUT_MAPS + olc == 0 && pix_id == (444*720 +582) / 4)
			{
				printf("k:o: %d %d %d %d %d %d   %11.10f %f %11.10f\n",
					out_off2 + 2,
					get_group_id(0),
					get_group_id(1),
					in_map_id,
					pix_id,
					olc,
					out_ptr[out_off2 + 2],
					((_FLOAT*)&out_tiles[ib][olc])[2],
					bias_val
					);
			}
#endif

		}

	}

}


Add multiplication functionality

Add multiplication functionality

;; Add two polynomials together
(defun poly+ (poly1 poly2)
  (add-terms (append poly1 poly2)))

;; Subtract one polynomial from another
(defun poly- (poly1 poly2)
  (add-terms (append poly1 (flip-multipliers poly2))))

;; Multiply polynomials together
(defun poly* (poly1 poly2)
  (clear-zero (add-terms (multiply-terms poly1 poly2))))

;; Returns the variable component of a singular polynomial
(defun variable-symbol (single-poly)
  (car (car single-poly)))

;; Returns the exponent component of a singular polynomial
(defun exponent (single-poly)
  (car (cdr (car single-poly))))

;; Returns the multiplier component of a singular polynomial
(defun multiplier (single-poly)
  (car (cdr single-poly)))

;; Returns a polynomial with all the multipliers multiplied by -1
(defun flip-multipliers (poly)
  (map 'list #'(lambda (x)
                 (list (list (variable-symbol x) (exponent x))
                       (* (multiplier x) -1))) poly))

;; Returns an added term if the addition is succesful, nil otherwise
(defun term-addition (term1 term2)
  (if (and (equal (variable-symbol term1) (variable-symbol term2))
           (equal (exponent term1) (exponent term2)))
    (list (list (variable-symbol term1) (exponent term1))
          (+ (multiplier term1) (multiplier term2)))
    nil))

;; Returns the failed term if the addition fails, nil otherwise
(defun term-failure (term1 term2)
  (if (and (equal (variable-symbol term1) (variable-symbol term2))
           (equal (exponent term1) (exponent term2)))
    nil
    term2))

;; Returns true if a polynomial contains only unique terms
(defun poly-unique-terms? (poly)
  (cond ((equal poly nil) T)
  (T (if (some #'(lambda (x) (and (equal (flatten
                                                  (variable-symbol x))
                                                (flatten
                                                  (variable-symbol
                                                    (car poly))))
                              (equal (flatten (exponent x))
                                     (flatten (exponent (car poly))))))
               (cdr poly))
    nil
    (poly-unique-terms? (cdr poly))))))

;; Functional flatten from Rosetta Code:
;; http://rosettacode.org/wiki/Flatten_a_list#Common_Lisp
(defun flatten (x &optional stack out)
  (cond ((consp x) (flatten (rest x) (cons (first x) stack) out))
        (x         (flatten (first stack) (rest stack) (cons x out)))
        (stack     (flatten (first stack) (rest stack) out))
        (t out)))

;; This function replaces a full list of nils with the replace-term, otherwise
;; returns the list
(defun useful-replace-nil (addition-seq replace-term)
  (if (equal (remove nil addition-seq) nil)
    (list replace-term)
    addition-seq))

;; Removes all zeroes from the polynomial
(defun clear-zero (poly)
  (remove nil (map 'list #'(lambda (x)
                 (if (or (equal (multiplier x) 0) (equal (exponent x) 0)) nil x))
                   poly)))

;; Recursively adds all the terms in the list
(defun add-terms (poly)
  (cond
    ((poly-unique-terms? poly) (clear-zero poly))
    (T (add-terms (remove nil (append (map 'list #'(lambda (x)
                                     (term-failure (car poly) x))
                           (cdr poly))
        (useful-replace-nil (map 'list #'(lambda (y)
                       (term-addition (car poly) y))
             (cdr poly)) (car poly))))))))

(defun map-onto-poly (single-poly poly)
  (map 'list #'(lambda (x) (multiply-singles single-poly x)) poly))

(defun multiply-singles (single-poly1 single-poly2)
  (cond
    ((equal (variable-symbol single-poly1) (variable-symbol single-poly2))
     (list (list (variable-symbol single-poly1)
                 (if (typep (exponent single-poly1) 'list)
                   (map 'list #'+ (exponent single-poly1)
                        (exponent single-poly2))
                   (+ (exponent single-poly1) (exponent single-poly2))))
           (* (multiplier single-poly1) (multiplier single-poly2)))
    )
    (T
      (list (list (list (variable-symbol single-poly1)
                        (variable-symbol single-poly2))
                  (list (exponent single-poly1)
                        (exponent single-poly2)))
            (* (multiplier single-poly1) (multiplier single-poly2))))))

(defun multiply-terms (map-poly poly)
  (cond
    ((equal map-poly nil) nil)
    (T (remove nil (append (map-onto-poly (car map-poly) poly)
               (multiply-terms (cdr map-poly) poly))))))

; (poly+ '(((x 2) 3)) '(((y 2) 4)))
; (poly+ '(((x 2) 3) ((y 2) 3)) '(((y 2) 4)))

;; Add two polynomials together
(defun poly+ (poly1 poly2)
  (add-terms (append poly1 poly2)))

;; Subtract one polynomial from another
(defun poly- (poly1 poly2)
  (add-terms (append poly1 (flip-multipliers poly2))))

;; Returns the variable component of a singular polynomial
(defun variable-symbol (single-poly)
  (car (car single-poly)))

;; Returns the exponent component of a singular polynomial
(defun exponent (single-poly)
  (car (cdr (car single-poly))))

;; Returns the multiplier component of a singular polynomial
(defun multiplier (single-poly)
  (car (cdr single-poly)))

;; Returns a polynomial with all the multipliers multiplied by -1
(defun flip-multipliers (poly)
  (map 'list #'(lambda (x)
                 (list (list (variable-symbol x) (exponent x))
                       (* (multiplier x) -1))) poly))

;; Returns an added term if the addition is succesful, nil otherwise
(defun term-addition (term1 term2)
  (if (and (equal (variable-symbol term1) (variable-symbol term2))
           (equal (exponent term1) (exponent term2)))
    (list (list (variable-symbol term1) (exponent term1))
          (+ (multiplier term1) (multiplier term2)))
    nil))

;; Returns the failed term if the addition fails, nil otherwise
(defun term-failure (term1 term2)
  (if (and (equal (variable-symbol term1) (variable-symbol term2))
           (equal (exponent term1) (exponent term2)))
    nil
    term2))

;; Returns true if a polynomial contains only unique terms
(defun poly-unique-terms? (poly)
  (cond ((equal poly nil) T)
  (T (if (some #'(lambda (x) (equal (car x) (car (car poly)))) (cdr poly))
    nil
    (poly-unique-terms? (cdr poly))))))

;; This function replaces a full list of nils with the replace-term, otherwise
;; returns the list
(defun useful-replace-nil (addition-seq replace-term)
  (if (equal (remove nil addition-seq) nil)
    (list replace-term)
    addition-seq))

;; Removes all zeroes from the polynomial
(defun clear-zero (poly)
  (remove nil (map 'list #'(lambda (x)
                 (if (equal (multiplier x) 0) nil x)) poly)))

;; Recursively adds all the terms in the list
(defun add-terms (poly)
  (cond
    ((poly-unique-terms? poly) (clear-zero poly))
    (T (add-terms (remove nil (append (map 'list #'(lambda (x)
                                     (term-failure (car poly) x))
                           (cdr poly))
        (useful-replace-nil (map 'list #'(lambda (y)
                       (term-addition (car poly) y))
             (cdr poly)) (car poly))))))))

; (poly+ '(((x 2) 3)) '(((y 2) 4)))
; (poly+ '(((x 2) 3) ((y 2) 3)) '(((y 2) 4)))


defining M_PI to fix some compiler errors on OSX 10.8

fixes #44

//
//     Copyright (C) Pixar. All rights reserved.
//
//     This license governs use of the accompanying software. If you
//     use the software, you accept this license. If you do not accept
//     the license, do not use the software.
//
//     1. Definitions
//     The terms "reproduce," "reproduction," "derivative works," and
//     "distribution" have the same meaning here as under U.S.
//     copyright law.  A "contribution" is the original software, or
//     any additions or changes to the software.
//     A "contributor" is any person or entity that distributes its
//     contribution under this license.
//     "Licensed patents" are a contributor's patent claims that read
//     directly on its contribution.
//
//     2. Grant of Rights
//     (A) Copyright Grant- Subject to the terms of this license,
//     including the license conditions and limitations in section 3,
//     each contributor grants you a non-exclusive, worldwide,
//     royalty-free copyright license to reproduce its contribution,
//     prepare derivative works of its contribution, and distribute
//     its contribution or any derivative works that you create.
//     (B) Patent Grant- Subject to the terms of this license,
//     including the license conditions and limitations in section 3,
//     each contributor grants you a non-exclusive, worldwide,
//     royalty-free license under its licensed patents to make, have
//     made, use, sell, offer for sale, import, and/or otherwise
//     dispose of its contribution in the software or derivative works
//     of the contribution in the software.
//
//     3. Conditions and Limitations
//     (A) No Trademark License- This license does not grant you
//     rights to use any contributor's name, logo, or trademarks.
//     (B) If you bring a patent claim against any contributor over
//     patents that you claim are infringed by the software, your
//     patent license from such contributor to the software ends
//     automatically.
//     (C) If you distribute any portion of the software, you must
//     retain all copyright, patent, trademark, and attribution
//     notices that are present in the software.
//     (D) If you distribute any portion of the software in source
//     code form, you may do so only under this license by including a
//     complete copy of this license with your distribution. If you
//     distribute any portion of the software in compiled or object
//     code form, you may only do so under a license that complies
//     with this license.
//     (E) The software is licensed "as-is." You bear the risk of
//     using it. The contributors give no express warranties,
//     guarantees or conditions. You may have additional consumer
//     rights under your local laws which this license cannot change.
//     To the extent permitted under your local laws, the contributors
//     exclude the implied warranties of merchantability, fitness for
//     a particular purpose and non-infringement.
//

#ifndef M_PI
    #define M_PI 3.14159265358979323846  // fix for OSX 10.8 (M_PI is in the Khronos standard...)
#endif

struct Vertex
{
    float v[NUM_VERTEX_ELEMENTS];
};

struct Varying
{
    float v[NUM_VARYING_ELEMENTS];
};

__global void clearVertex(struct Vertex *vertex) {

    for (int i = 0; i < NUM_VERTEX_ELEMENTS; i++) {
        vertex->v[i] = 0;
    }
}
__global void clearVarying(struct Varying *varying) {

    for (int i = 0; i < NUM_VARYING_ELEMENTS; i++) {
        varying->v[i] = 0;
    }
}

__global void addWithWeight(struct Vertex *dst, __global struct Vertex *src, float weight) {

    for (int i = 0; i < NUM_VERTEX_ELEMENTS; i++) {
        dst->v[i] += src->v[i] * weight;
    }
}

__global void addVaryingWithWeight(struct Varying *dst, __global struct Varying *src, float weight) {

    for (int i = 0; i < NUM_VARYING_ELEMENTS; i++) {
        dst->v[i] += src->v[i] * weight;
    }
}

__kernel void computeBilinearEdge(__global struct Vertex *vertex,
                                   __global struct Varying *varying,
                                   __global int *E_IT,
                                   int ofs_E_IT,
                                   int offset, int start, int end) {
    E_IT += ofs_E_IT;

    int i = start + get_global_id(0);
    int eidx0 = E_IT[2*i+0];
    int eidx1 = E_IT[2*i+1];

    struct Vertex dst;
    struct Varying dstVarying;
    clearVertex(&dst);
    clearVarying(&dstVarying);

    addWithWeight(&dst, &vertex[eidx0], 0.5f);
    addWithWeight(&dst, &vertex[eidx1], 0.5f);

    vertex[i+offset] = dst;

    if (varying) {
        addVaryingWithWeight(&dstVarying, &varying[eidx0], 0.5f);
        addVaryingWithWeight(&dstVarying, &varying[eidx1], 0.5f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void computeBilinearVertex(__global struct Vertex *vertex,
                                     __global struct Varying *varying,
                                     __global int *V_ITa,
                                     int ofs_V_ITa,
                                     int offset, int start, int end) {

    V_ITa += ofs_V_ITa;

    int i = start + get_global_id(0);

    int p = V_ITa[i];

    struct Vertex dst;
    clearVertex(&dst);
    addWithWeight(&dst, &vertex[p], 1.0f);

    vertex[i+offset] = dst;

    if (varying) {
        struct Varying dstVarying;
        clearVarying(&dstVarying);
        addVaryingWithWeight(&dstVarying, &varying[p], 1.0f);
        varying[i+offset] = dstVarying;
    }
}

// ----------------------------------------------------------------------------------------

__kernel void computeFace(__global struct Vertex *vertex,
                          __global struct Varying *varying,
                          __global int *F_IT,
                          __global int *F_ITa,
                          int ofs_F_IT, int ofs_F_ITa,
                          int offset, int start, int end) {

    F_IT += ofs_F_IT;
    F_ITa += ofs_F_ITa;

    int i = start + get_global_id(0);
    int h = F_ITa[2*i];
    int n = F_ITa[2*i+1];

    float weight = 1.0f/n;

    struct Vertex dst;
    struct Varying dstVarying;
    clearVertex(&dst);
    clearVarying(&dstVarying);
    for (int j=0; j<n; ++j) {
        int index = F_IT[h+j];
        addWithWeight(&dst, &vertex[index], weight);
        if(varying) addVaryingWithWeight(&dstVarying, &varying[index], weight);
    }
    vertex[i+offset] = dst;
    if(varying) varying[i+offset] = dstVarying;
}

__kernel void computeEdge(__global struct Vertex *vertex,
                          __global struct Varying *varying,
                          __global int *E_IT,
                          __global float *E_W,
                          int ofs_E_IT, int ofs_E_W,
                          int offset, int start, int end) {

    E_IT += ofs_E_IT;
    E_W += ofs_E_W;

    int i = start + get_global_id(0);
    int eidx0 = E_IT[4*i+0];
    int eidx1 = E_IT[4*i+1];
    int eidx2 = E_IT[4*i+2];
    int eidx3 = E_IT[4*i+3];

    float vertWeight = E_W[i*2+0];

    // Fully sharp edge : vertWeight = 0.5f;
    struct Vertex dst;
    struct Varying dstVarying;
    clearVertex(&dst);
    clearVarying(&dstVarying);

    addWithWeight(&dst, &vertex[eidx0], vertWeight);
    addWithWeight(&dst, &vertex[eidx1], vertWeight);

    if (eidx2 > -1) {
        float faceWeight = E_W[i*2+1];

        addWithWeight(&dst, &vertex[eidx2], faceWeight);
        addWithWeight(&dst, &vertex[eidx3], faceWeight);
    }

    vertex[i+offset] = dst;

    if (varying) {
        addVaryingWithWeight(&dstVarying, &varying[eidx0], 0.5f);
        addVaryingWithWeight(&dstVarying, &varying[eidx1], 0.5f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void computeVertexA(__global struct Vertex *vertex,
                             __global struct Varying *varying,
                             __global int *V_ITa,
                             __global float *V_W,
                             int ofs_V_ITa, int ofs_V_W,
                             int offset, int start, int end, int pass) {
    V_ITa += ofs_V_ITa;
    V_W += ofs_V_W;

    int i = start + get_global_id(0);
    int n     = V_ITa[5*i+1];
    int p     = V_ITa[5*i+2];
    int eidx0 = V_ITa[5*i+3];
    int eidx1 = V_ITa[5*i+4];

    float weight = (pass==1) ? V_W[i] : 1.0f - V_W[i];

    // In the case of fractional weight, the weight must be inverted since
    // the value is shared with the k_Smooth kernel (statistically the
    // k_Smooth kernel runs much more often than this one)
    if (weight>0.0f && weight<1.0f && n > 0)
        weight=1.0f-weight;

    struct Vertex dst;
    if (! pass)
        clearVertex(&dst);
    else
        dst = vertex[i+offset];

    if (eidx0==-1 || (pass==0 && (n==-1)) ) {
        addWithWeight(&dst, &vertex[p], weight);
    } else {
        addWithWeight(&dst, &vertex[p], weight * 0.75f);
        addWithWeight(&dst, &vertex[eidx0], weight * 0.125f);
        addWithWeight(&dst, &vertex[eidx1], weight * 0.125f);
    }
    vertex[i+offset] = dst;

    if (! pass && varying) {
        struct Varying dstVarying;
        clearVarying(&dstVarying);
        addVaryingWithWeight(&dstVarying, &varying[p], 1.0f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void computeVertexB(__global struct Vertex *vertex,
                             __global struct Varying *varying,
                             __global int *V_ITa,
                             __global int *V_IT,
                             __global float *V_W,
                             int ofs_V_ITa, int ofs_V_IT, int ofs_V_W,
                             int offset, int start, int end) {
    V_ITa += ofs_V_ITa;
    V_IT += ofs_V_IT;
    V_W += ofs_V_W;

    int i = start + get_global_id(0);
    int h = V_ITa[5*i];
    int n = V_ITa[5*i+1];
    int p = V_ITa[5*i+2];

    float weight = V_W[i];
    float wp = 1.0f/(float)(n*n);
    float wv = (n-2.0f) * n * wp;

    struct Vertex dst;
    clearVertex(&dst);

    addWithWeight(&dst, &vertex[p], weight * wv);

    for (int j = 0; j < n; ++j) {
        addWithWeight(&dst, &vertex[V_IT[h+j*2]], weight * wp);
        addWithWeight(&dst, &vertex[V_IT[h+j*2+1]], weight * wp);
    }
    vertex[i+offset] = dst;

    if (varying) {
        struct Varying dstVarying;
        clearVarying(&dstVarying);
        addVaryingWithWeight(&dstVarying, &varying[p], 1.0f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void computeLoopVertexB(__global struct Vertex *vertex,
                                 __global struct Varying *varying,
                                 __global int *V_ITa,
                                 __global int *V_IT,
                                 __global float *V_W,
                                 int ofs_V_ITa, int ofs_V_IT, int ofs_V_W,
                                 int offset, int start, int end) {

    V_ITa += ofs_V_ITa;
    V_IT += ofs_V_IT;
    V_W += ofs_V_W;

    int i = start + get_global_id(0);
    int h = V_ITa[5*i];
    int n = V_ITa[5*i+1];
    int p = V_ITa[5*i+2];

    float weight = V_W[i];
    float wp = 1.0f/(float)(n);
    float beta = 0.25f * cos((float)(M_PI) * 2.0f * wp) + 0.375f;
    beta = beta * beta;
    beta = (0.625f - beta) * wp;

    struct Vertex dst;
    clearVertex(&dst);
    addWithWeight(&dst, &vertex[p], weight * (1.0f - (beta * n)));

    for (int j = 0; j < n; ++j) {
        addWithWeight(&dst, &vertex[V_IT[h+j]], weight * beta);
    }
    vertex[i+offset] = dst;

    if (varying) {
        struct Varying dstVarying;
        clearVarying(&dstVarying);
        addVaryingWithWeight(&dstVarying, &varying[p], 1.0f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void editVertexAdd(__global struct Vertex *vertex,
                            __global int *editIndices,
                            __global float *editValues,
                            int ofs_editIndices,
                            int ofs_editValues,
                            int primVarOffset,
                            int primVarWidth) {

    editIndices += ofs_editIndices;
    editValues += ofs_editValues;

    int i = get_global_id(0);
    int v = editIndices[i];
    struct Vertex dst = vertex[v];

    for (int j = 0; j < primVarWidth; ++j) {
        dst.v[j+primVarOffset] += editValues[j];
    }
    vertex[v] = dst;
}

//
//     Copyright (C) Pixar. All rights reserved.
//
//     This license governs use of the accompanying software. If you
//     use the software, you accept this license. If you do not accept
//     the license, do not use the software.
//
//     1. Definitions
//     The terms "reproduce," "reproduction," "derivative works," and
//     "distribution" have the same meaning here as under U.S.
//     copyright law.  A "contribution" is the original software, or
//     any additions or changes to the software.
//     A "contributor" is any person or entity that distributes its
//     contribution under this license.
//     "Licensed patents" are a contributor's patent claims that read
//     directly on its contribution.
//
//     2. Grant of Rights
//     (A) Copyright Grant- Subject to the terms of this license,
//     including the license conditions and limitations in section 3,
//     each contributor grants you a non-exclusive, worldwide,
//     royalty-free copyright license to reproduce its contribution,
//     prepare derivative works of its contribution, and distribute
//     its contribution or any derivative works that you create.
//     (B) Patent Grant- Subject to the terms of this license,
//     including the license conditions and limitations in section 3,
//     each contributor grants you a non-exclusive, worldwide,
//     royalty-free license under its licensed patents to make, have
//     made, use, sell, offer for sale, import, and/or otherwise
//     dispose of its contribution in the software or derivative works
//     of the contribution in the software.
//
//     3. Conditions and Limitations
//     (A) No Trademark License- This license does not grant you
//     rights to use any contributor's name, logo, or trademarks.
//     (B) If you bring a patent claim against any contributor over
//     patents that you claim are infringed by the software, your
//     patent license from such contributor to the software ends
//     automatically.
//     (C) If you distribute any portion of the software, you must
//     retain all copyright, patent, trademark, and attribution
//     notices that are present in the software.
//     (D) If you distribute any portion of the software in source
//     code form, you may do so only under this license by including a
//     complete copy of this license with your distribution. If you
//     distribute any portion of the software in compiled or object
//     code form, you may only do so under a license that complies
//     with this license.
//     (E) The software is licensed "as-is." You bear the risk of
//     using it. The contributors give no express warranties,
//     guarantees or conditions. You may have additional consumer
//     rights under your local laws which this license cannot change.
//     To the extent permitted under your local laws, the contributors
//     exclude the implied warranties of merchantability, fitness for
//     a particular purpose and non-infringement.
//

struct Vertex
{
    float v[NUM_VERTEX_ELEMENTS];
};

struct Varying
{
    float v[NUM_VARYING_ELEMENTS];
};

__global void clearVertex(struct Vertex *vertex) {

    for (int i = 0; i < NUM_VERTEX_ELEMENTS; i++) {
        vertex->v[i] = 0;
    }
}
__global void clearVarying(struct Varying *varying) {

    for (int i = 0; i < NUM_VARYING_ELEMENTS; i++) {
        varying->v[i] = 0;
    }
}

__global void addWithWeight(struct Vertex *dst, __global struct Vertex *src, float weight) {

    for (int i = 0; i < NUM_VERTEX_ELEMENTS; i++) {
        dst->v[i] += src->v[i] * weight;
    }
}

__global void addVaryingWithWeight(struct Varying *dst, __global struct Varying *src, float weight) {

    for (int i = 0; i < NUM_VARYING_ELEMENTS; i++) {
        dst->v[i] += src->v[i] * weight;
    }
}

__kernel void computeBilinearEdge(__global struct Vertex *vertex,
                                   __global struct Varying *varying,
                                   __global int *E_IT,
                                   int ofs_E_IT,
                                   int offset, int start, int end) {
    E_IT += ofs_E_IT;

    int i = start + get_global_id(0);
    int eidx0 = E_IT[2*i+0];
    int eidx1 = E_IT[2*i+1];

    struct Vertex dst;
    struct Varying dstVarying;
    clearVertex(&dst);
    clearVarying(&dstVarying);

    addWithWeight(&dst, &vertex[eidx0], 0.5f);
    addWithWeight(&dst, &vertex[eidx1], 0.5f);

    vertex[i+offset] = dst;

    if (varying) {
        addVaryingWithWeight(&dstVarying, &varying[eidx0], 0.5f);
        addVaryingWithWeight(&dstVarying, &varying[eidx1], 0.5f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void computeBilinearVertex(__global struct Vertex *vertex,
                                     __global struct Varying *varying,
                                     __global int *V_ITa,
                                     int ofs_V_ITa,
                                     int offset, int start, int end) {

    V_ITa += ofs_V_ITa;

    int i = start + get_global_id(0);

    int p = V_ITa[i];

    struct Vertex dst;
    clearVertex(&dst);
    addWithWeight(&dst, &vertex[p], 1.0f);

    vertex[i+offset] = dst;

    if (varying) {
        struct Varying dstVarying;
        clearVarying(&dstVarying);
        addVaryingWithWeight(&dstVarying, &varying[p], 1.0f);
        varying[i+offset] = dstVarying;
    }
}

// ----------------------------------------------------------------------------------------

__kernel void computeFace(__global struct Vertex *vertex,
                          __global struct Varying *varying,
                          __global int *F_IT,
                          __global int *F_ITa,
                          int ofs_F_IT, int ofs_F_ITa,
                          int offset, int start, int end) {

    F_IT += ofs_F_IT;
    F_ITa += ofs_F_ITa;

    int i = start + get_global_id(0);
    int h = F_ITa[2*i];
    int n = F_ITa[2*i+1];

    float weight = 1.0f/n;

    struct Vertex dst;
    struct Varying dstVarying;
    clearVertex(&dst);
    clearVarying(&dstVarying);
    for (int j=0; j<n; ++j) {
        int index = F_IT[h+j];
        addWithWeight(&dst, &vertex[index], weight);
        if(varying) addVaryingWithWeight(&dstVarying, &varying[index], weight);
    }
    vertex[i+offset] = dst;
    if(varying) varying[i+offset] = dstVarying;
}

__kernel void computeEdge(__global struct Vertex *vertex,
                          __global struct Varying *varying,
                          __global int *E_IT,
                          __global float *E_W,
                          int ofs_E_IT, int ofs_E_W,
                          int offset, int start, int end) {

    E_IT += ofs_E_IT;
    E_W += ofs_E_W;

    int i = start + get_global_id(0);
    int eidx0 = E_IT[4*i+0];
    int eidx1 = E_IT[4*i+1];
    int eidx2 = E_IT[4*i+2];
    int eidx3 = E_IT[4*i+3];

    float vertWeight = E_W[i*2+0];

    // Fully sharp edge : vertWeight = 0.5f;
    struct Vertex dst;
    struct Varying dstVarying;
    clearVertex(&dst);
    clearVarying(&dstVarying);

    addWithWeight(&dst, &vertex[eidx0], vertWeight);
    addWithWeight(&dst, &vertex[eidx1], vertWeight);

    if (eidx2 > -1) {
        float faceWeight = E_W[i*2+1];

        addWithWeight(&dst, &vertex[eidx2], faceWeight);
        addWithWeight(&dst, &vertex[eidx3], faceWeight);
    }

    vertex[i+offset] = dst;

    if (varying) {
        addVaryingWithWeight(&dstVarying, &varying[eidx0], 0.5f);
        addVaryingWithWeight(&dstVarying, &varying[eidx1], 0.5f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void computeVertexA(__global struct Vertex *vertex,
                             __global struct Varying *varying,
                             __global int *V_ITa,
                             __global float *V_W,
                             int ofs_V_ITa, int ofs_V_W,
                             int offset, int start, int end, int pass) {
    V_ITa += ofs_V_ITa;
    V_W += ofs_V_W;

    int i = start + get_global_id(0);
    int n     = V_ITa[5*i+1];
    int p     = V_ITa[5*i+2];
    int eidx0 = V_ITa[5*i+3];
    int eidx1 = V_ITa[5*i+4];

    float weight = (pass==1) ? V_W[i] : 1.0f - V_W[i];

    // In the case of fractional weight, the weight must be inverted since
    // the value is shared with the k_Smooth kernel (statistically the
    // k_Smooth kernel runs much more often than this one)
    if (weight>0.0f && weight<1.0f && n > 0)
        weight=1.0f-weight;

    struct Vertex dst;
    if (! pass)
        clearVertex(&dst);
    else
        dst = vertex[i+offset];

    if (eidx0==-1 || (pass==0 && (n==-1)) ) {
        addWithWeight(&dst, &vertex[p], weight);
    } else {
        addWithWeight(&dst, &vertex[p], weight * 0.75f);
        addWithWeight(&dst, &vertex[eidx0], weight * 0.125f);
        addWithWeight(&dst, &vertex[eidx1], weight * 0.125f);
    }
    vertex[i+offset] = dst;

    if (! pass && varying) {
        struct Varying dstVarying;
        clearVarying(&dstVarying);
        addVaryingWithWeight(&dstVarying, &varying[p], 1.0f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void computeVertexB(__global struct Vertex *vertex,
                             __global struct Varying *varying,
                             __global int *V_ITa,
                             __global int *V_IT,
                             __global float *V_W,
                             int ofs_V_ITa, int ofs_V_IT, int ofs_V_W,
                             int offset, int start, int end) {
    V_ITa += ofs_V_ITa;
    V_IT += ofs_V_IT;
    V_W += ofs_V_W;

    int i = start + get_global_id(0);
    int h = V_ITa[5*i];
    int n = V_ITa[5*i+1];
    int p = V_ITa[5*i+2];

    float weight = V_W[i];
    float wp = 1.0f/(float)(n*n);
    float wv = (n-2.0f) * n * wp;

    struct Vertex dst;
    clearVertex(&dst);

    addWithWeight(&dst, &vertex[p], weight * wv);

    for (int j = 0; j < n; ++j) {
        addWithWeight(&dst, &vertex[V_IT[h+j*2]], weight * wp);
        addWithWeight(&dst, &vertex[V_IT[h+j*2+1]], weight * wp);
    }
    vertex[i+offset] = dst;

    if (varying) {
        struct Varying dstVarying;
        clearVarying(&dstVarying);
        addVaryingWithWeight(&dstVarying, &varying[p], 1.0f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void computeLoopVertexB(__global struct Vertex *vertex,
                                 __global struct Varying *varying,
                                 __global int *V_ITa,
                                 __global int *V_IT,
                                 __global float *V_W,
                                 int ofs_V_ITa, int ofs_V_IT, int ofs_V_W,
                                 int offset, int start, int end) {

    V_ITa += ofs_V_ITa;
    V_IT += ofs_V_IT;
    V_W += ofs_V_W;

    int i = start + get_global_id(0);
    int h = V_ITa[5*i];
    int n = V_ITa[5*i+1];
    int p = V_ITa[5*i+2];

    float weight = V_W[i];
    float wp = 1.0f/(float)(n);
    float beta = 0.25f * cos((float)(M_PI) * 2.0f * wp) + 0.375f;
    beta = beta * beta;
    beta = (0.625f - beta) * wp;

    struct Vertex dst;
    clearVertex(&dst);
    addWithWeight(&dst, &vertex[p], weight * (1.0f - (beta * n)));

    for (int j = 0; j < n; ++j) {
        addWithWeight(&dst, &vertex[V_IT[h+j]], weight * beta);
    }
    vertex[i+offset] = dst;

    if (varying) {
        struct Varying dstVarying;
        clearVarying(&dstVarying);
        addVaryingWithWeight(&dstVarying, &varying[p], 1.0f);
        varying[i+offset] = dstVarying;
    }
}

__kernel void editVertexAdd(__global struct Vertex *vertex,
                            __global int *editIndices,
                            __global float *editValues,
                            int ofs_editIndices,
                            int ofs_editValues,
                            int primVarOffset,
                            int primVarWidth) {

    editIndices += ofs_editIndices;
    editValues += ofs_editValues;

    int i = get_global_id(0);
    int v = editIndices[i];
    struct Vertex dst = vertex[v];

    for (int j = 0; j < primVarWidth; ++j) {
        dst.v[j+primVarOffset] += editValues[j];
    }
    vertex[v] = dst;
}