clear extra memset

clear extra memset

int blake2b( uchar *out, uchar *in );

// The kernel that grinds nonces until it finds a hash below the target
__kernel void nonceGrind(__global uchar *headerIn, __global uchar *hashOut, __global uchar *targ, __global uchar *nonceOut) {
	private uchar header[256] = {0};
	private uchar headerHash[32];
	private uchar target[32];
	headerHash[0] = 255;

	int i;
#pragma unroll
	for (i = 0; i < 32; i++) {
		target[i] = targ[i];
		header[i] = headerIn[i];
	}
#pragma unroll
	for (i = 32; i < 80; i++) {
		header[i] = headerIn[i];
	}

	// Set nonce
	private int id = get_global_id(0);
	// Support global work sizes of up to 256^4 - 1
	header[32] = id / (256 * 256 * 256);
	header[33] = id / (256 * 256);
	header[34] = id / 256;
	header[35] = id % 256;

	// Hash the header
	blake2b(headerHash, header);

	// Compare header to target
	int z = 0;
	while (target[z] == headerHash[z]) {
		z++;
	}
	if (headerHash[z] < target[z]) {
		// Transfer the output to global space.
		for (i = 0; i < 8; i++) {
			nonceOut[i] = header[i + 32];
		}
		for (i = 0; i < 32; i++) {
			hashOut[i] = headerHash[i];
		}
		return;
	}
}

// Implementations of clmemset and memcopy
void *clmemset( __private void *s, __private int c, __private size_t n) {
	uchar *p = s;
	while(n--) {
		*p++ = (uchar)c;
	}
	return s;
}

void clmemcpy( __private void *dest, __private const void *src, __private size_t num) {
	int i = 0 ;
	char *dest8 = (char*)dest;
	char *src8 = (char*)src;
#pragma unroll
	for (int i = 0; i < num; i++) {
		dest8[i] = src8[i];
	}
}

#if defined(_MSC_VER)
#define ALIGN(x) __declspec(align(x))
#else
#define ALIGN(x) __attribute__((aligned(x)))
#endif

  typedef struct __blake2b_state
  {
	ulong h[8];
	ulong t[2];
	ulong f[2];
	uchar  buf[256];
	uchar  last_node;
  } blake2b_state;

static inline ulong load64( __private const void *src )
{
  return *( ulong * )( src );
}

static inline void store64( __private void *dst, __private ulong w )
{
  *( ulong * )( dst ) = w;
}

static inline ulong rotr64( __private const ulong w, __private const unsigned c )
{
  return ( w >> c ) | ( w << ( 64 - c ) );
}

// blake2b-ref.c
__constant ulong blake2b_IV[8] =
{
	0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
	0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
	0x510e527fade682d1, 0x9b05688c2b3e6c1f,
	0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
};

__constant uchar blake2b_sigma[12][16] =
{
	{	0,	1,	2,	3,	4,	5,	6,	7,	8,	9, 10, 11, 12, 13, 14, 15 } ,
	{ 14, 10,	4,	8,	9, 15, 13,	6,	1, 12,	0,	2, 11,	7,	5,	3 } ,
	{ 11,	8, 12,	0,	5,	2, 15, 13, 10, 14,	3,	6,	7,	1,	9,	4 } ,
	{	7,	9,	3,	1, 13, 12, 11, 14,	2,	6,	5, 10,	4,	0, 15,	8 } ,
	{	9,	0,	5,	7,	2,	4, 10, 15, 14,	1, 11, 12,	6,	8,	3, 13 } ,
	{	2, 12,	6, 10,	0, 11,	8,	3,	4, 13,	7,	5, 15, 14,	1,	9 } ,
	{ 12,	5,	1, 15, 14, 13,	4, 10,	0,	7,	6,	3,	9,	2,	8, 11 } ,
	{ 13, 11,	7, 14, 12,	1,	3,	9,	5,	0, 15,	4,	8,	6,	2, 10 } ,
	{	6, 15, 14,	9, 11,	3,	0,	8, 12,	2, 13,	7,	1,	4, 10,	5 } ,
	{ 10,	2,	8,	4,	7,	6,	1,	5, 15, 11,	9, 14,	3, 12, 13 , 0 } ,
	{	0,	1,	2,	3,	4,	5,	6,	7,	8,	9, 10, 11, 12, 13, 14, 15 } ,
	{ 14, 10,	4,	8,	9, 15, 13,	6,	1, 12,	0,	2, 11,	7,	5,	3 }
};

static int blake2b_compress( __private blake2b_state *S, __private const uchar block[128] )
{
	return 0;
}

int blake2b( __private uchar *out, __private uchar *in )
{
	// Initialize a state.
	private blake2b_state S[1];
	clmemset( S, 0, sizeof( blake2b_state ) );
	for( int i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
	S->h[0] ^= 0x0000000001010020UL;

	S->t[0] += 80;
	S->f[0] = ~((ulong)0);

	ulong m[16];
	ulong v[16];
	int i;

	for( i = 0; i < 16; ++i )
		m[i] = load64( in + i * sizeof( m[i] ) );

	for( i = 0; i < 8; ++i )
		v[i] = S->h[i];

	v[ 8] = blake2b_IV[0];
	v[ 9] = blake2b_IV[1];
	v[10] = blake2b_IV[2];
	v[11] = blake2b_IV[3];
	v[12] = S->t[0] ^ blake2b_IV[4];
	v[13] = S->t[1] ^ blake2b_IV[5];
	v[14] = S->f[0] ^ blake2b_IV[6];
	v[15] = S->f[1] ^ blake2b_IV[7];
#define G(r,i,a,b,c,d) \
	do { \
		a = a + b + m[blake2b_sigma[r][2*i+0]]; \
		d = rotr64(d ^ a, 32); \
		c = c + d; \
		b = rotr64(b ^ c, 24); \
		a = a + b + m[blake2b_sigma[r][2*i+1]]; \
		d = rotr64(d ^ a, 16); \
		c = c + d; \
		b = rotr64(b ^ c, 63); \
	} while(0)
#define ROUND(r)	\
	do { \
		G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
		G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
		G(r,2,v[ 2],v[ 6],v[10],v[14]); \
		G(r,3,v[ 3],v[ 7],v[11],v[15]); \
		G(r,4,v[ 0],v[ 5],v[10],v[15]); \
		G(r,5,v[ 1],v[ 6],v[11],v[12]); \
		G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
		G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
	} while(0)
	ROUND( 0 );
	ROUND( 1 );
	ROUND( 2 );
	ROUND( 3 );
	ROUND( 4 );
	ROUND( 5 );
	ROUND( 6 );
	ROUND( 7 );
	ROUND( 8 );
	ROUND( 9 );
	ROUND( 10 );
	ROUND( 11 );

	for( i = 0; i < 8; ++i )
		S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];

#undef G
#undef ROUND

	uchar buffer[64];
	for( int i = 0; i < 8; ++i ) // Output full hash to temp buffer
		store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );

	clmemcpy( out, buffer, 32 );

	return 0;
}

int blake2b( uchar *out, uchar *in );

// The kernel that grinds nonces until it finds a hash below the target
__kernel void nonceGrind(__global uchar *headerIn, __global uchar *hashOut, __global uchar *targ, __global uchar *nonceOut) {
	private uchar header[256];
	private uchar headerHash[32];
	private uchar target[32];
	headerHash[0] = 255;

	int i;
#pragma unroll
	for (i = 0; i < 32; i++) {
		target[i] = targ[i];
		header[i] = headerIn[i];
	}
#pragma unroll
	for (i = 32; i < 80; i++) {
		header[i] = headerIn[i];
	}

	// Set nonce
	private int id = get_global_id(0);
	// Support global work sizes of up to 256^4 - 1
	header[32] = id / (256 * 256 * 256);
	header[33] = id / (256 * 256);
	header[34] = id / 256;
	header[35] = id % 256;

	// Hash the header
	blake2b(headerHash, header);

	// Compare header to target
	int z = 0;
	while (target[z] == headerHash[z]) {
		z++;
	}
	if (headerHash[z] < target[z]) {
		// Transfer the output to global space.
		for (i = 0; i < 8; i++) {
			nonceOut[i] = header[i + 32];
		}
		for (i = 0; i < 32; i++) {
			hashOut[i] = headerHash[i];
		}
		return;
	}
}

// Implementations of clmemset and memcopy
void *clmemset( __private void *s, __private int c, __private size_t n) {
	uchar *p = s;
	while(n--) {
		*p++ = (uchar)c;
	}
	return s;
}

void clmemcpy( __private void *dest, __private const void *src, __private size_t num) {
	int i = 0 ;
	char *dest8 = (char*)dest;
	char *src8 = (char*)src;
#pragma unroll
	for (int i = 0; i < num; i++) {
		dest8[i] = src8[i];
	}
}

#if defined(_MSC_VER)
#define ALIGN(x) __declspec(align(x))
#else
#define ALIGN(x) __attribute__((aligned(x)))
#endif

  typedef struct __blake2b_state
  {
	ulong h[8];
	ulong t[2];
	ulong f[2];
	uchar  buf[256];
	uchar  last_node;
  } blake2b_state;

static inline ulong load64( __private const void *src )
{
  return *( ulong * )( src );
}

static inline void store64( __private void *dst, __private ulong w )
{
  *( ulong * )( dst ) = w;
}

static inline ulong rotr64( __private const ulong w, __private const unsigned c )
{
  return ( w >> c ) | ( w << ( 64 - c ) );
}

// blake2b-ref.c
__constant ulong blake2b_IV[8] =
{
	0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
	0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
	0x510e527fade682d1, 0x9b05688c2b3e6c1f,
	0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
};

__constant uchar blake2b_sigma[12][16] =
{
	{	0,	1,	2,	3,	4,	5,	6,	7,	8,	9, 10, 11, 12, 13, 14, 15 } ,
	{ 14, 10,	4,	8,	9, 15, 13,	6,	1, 12,	0,	2, 11,	7,	5,	3 } ,
	{ 11,	8, 12,	0,	5,	2, 15, 13, 10, 14,	3,	6,	7,	1,	9,	4 } ,
	{	7,	9,	3,	1, 13, 12, 11, 14,	2,	6,	5, 10,	4,	0, 15,	8 } ,
	{	9,	0,	5,	7,	2,	4, 10, 15, 14,	1, 11, 12,	6,	8,	3, 13 } ,
	{	2, 12,	6, 10,	0, 11,	8,	3,	4, 13,	7,	5, 15, 14,	1,	9 } ,
	{ 12,	5,	1, 15, 14, 13,	4, 10,	0,	7,	6,	3,	9,	2,	8, 11 } ,
	{ 13, 11,	7, 14, 12,	1,	3,	9,	5,	0, 15,	4,	8,	6,	2, 10 } ,
	{	6, 15, 14,	9, 11,	3,	0,	8, 12,	2, 13,	7,	1,	4, 10,	5 } ,
	{ 10,	2,	8,	4,	7,	6,	1,	5, 15, 11,	9, 14,	3, 12, 13 , 0 } ,
	{	0,	1,	2,	3,	4,	5,	6,	7,	8,	9, 10, 11, 12, 13, 14, 15 } ,
	{ 14, 10,	4,	8,	9, 15, 13,	6,	1, 12,	0,	2, 11,	7,	5,	3 }
};

static int blake2b_compress( __private blake2b_state *S, __private const uchar block[128] )
{
	return 0;
}

int blake2b( __private uchar *out, __private uchar *in )
{
	// Initialize a state.
	private blake2b_state S[1];
	clmemset( S, 0, sizeof( blake2b_state ) );
	for( int i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
	S->h[0] ^= 0x0000000001010020UL;

	S->t[0] += 80;
	S->f[0] = ~((ulong)0);
	clmemset( in + 80, 0, 2 * 128 - 80 ); // Padding

	ulong m[16];
	ulong v[16];
	int i;

	for( i = 0; i < 16; ++i )
		m[i] = load64( in + i * sizeof( m[i] ) );

	for( i = 0; i < 8; ++i )
		v[i] = S->h[i];

	v[ 8] = blake2b_IV[0];
	v[ 9] = blake2b_IV[1];
	v[10] = blake2b_IV[2];
	v[11] = blake2b_IV[3];
	v[12] = S->t[0] ^ blake2b_IV[4];
	v[13] = S->t[1] ^ blake2b_IV[5];
	v[14] = S->f[0] ^ blake2b_IV[6];
	v[15] = S->f[1] ^ blake2b_IV[7];
#define G(r,i,a,b,c,d) \
	do { \
		a = a + b + m[blake2b_sigma[r][2*i+0]]; \
		d = rotr64(d ^ a, 32); \
		c = c + d; \
		b = rotr64(b ^ c, 24); \
		a = a + b + m[blake2b_sigma[r][2*i+1]]; \
		d = rotr64(d ^ a, 16); \
		c = c + d; \
		b = rotr64(b ^ c, 63); \
	} while(0)
#define ROUND(r)	\
	do { \
		G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
		G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
		G(r,2,v[ 2],v[ 6],v[10],v[14]); \
		G(r,3,v[ 3],v[ 7],v[11],v[15]); \
		G(r,4,v[ 0],v[ 5],v[10],v[15]); \
		G(r,5,v[ 1],v[ 6],v[11],v[12]); \
		G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
		G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
	} while(0)
	ROUND( 0 );
	ROUND( 1 );
	ROUND( 2 );
	ROUND( 3 );
	ROUND( 4 );
	ROUND( 5 );
	ROUND( 6 );
	ROUND( 7 );
	ROUND( 8 );
	ROUND( 9 );
	ROUND( 10 );
	ROUND( 11 );

	for( i = 0; i < 8; ++i )
		S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];

#undef G
#undef ROUND

	uchar buffer[64];
	for( int i = 0; i < 8; ++i ) // Output full hash to temp buffer
		store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );

	clmemcpy( out, buffer, 32 );

	return 0;
}


Update image.cl

Update image.cl

__constant sampler_t sampler =
  CLK_NORMALIZED_COORDS_FALSE
| CLK_ADDRESS_CLAMP_TO_EDGE
| CLK_FILTER_NEAREST;

__kernel void Filter (
    __read_only image2d_t a,
    __read_only image2d_t b,
    __write_only image2d_t output)
{

    const int2 pos = {get_global_id(0), get_global_id(1)};

    float4 sum = read_imagef(a, sampler, pos) + read_imagef(b, sampler, pos);

    write_imagef (output, pos, sum);
}

__kernel void imageAdd(__read_only image2d_t input,
                    __write_only image2d_t output)
{
   int2 x2;
   x2.x = get_global_id(0);
   x2.y = 0;
   float4 inp = read_imagef(input, x2);
   write_imagef(output, x2, inp);
}


Also record the work being done..

Also record the work being done..

kernel void label_with_id(global int *data, int w, int h) {
  int x = get_global_id(0);
  int y = get_global_id(1);
  if (x >= w || y >= h) {
    return;
  }

  int loc = w * y + x;
  if (data[loc] == 1) {
    data[loc] = loc + 2;
  }
}

kernel void neighbour_propagate(global int *data, int w, int h,
                                global char *changed) {
  int x = get_global_id(0);
  int y = get_global_id(1);
  if (x >= w || y >= h) {
    return;
  }

  int oldlabel = data[w * y + x];
  int curlabel = oldlabel;
  int otherlabel = 0;

  if (curlabel == 0) {
    return;
  }

  if (y + 1 < h) {
    otherlabel = data[w * (y + 1) + (x)];
    if (otherlabel && otherlabel < curlabel) {
      curlabel = otherlabel;
    }
  }
  if (y - 1 >= 0) {
    otherlabel = data[w * (y - 1) + (x)];
    if (otherlabel && otherlabel < curlabel) {
      curlabel = otherlabel;
    }
  }
  if (x + 1 < w) {
    otherlabel = data[w * (y) + (x + 1)];
    if (otherlabel && otherlabel < curlabel) {
      curlabel = otherlabel;
    }
  }
  if (x - 1 >= 0) {
    otherlabel = data[w * (y) + (x - 1)];
    if (otherlabel && otherlabel < curlabel) {
      curlabel = otherlabel;
    }
  }

  if (curlabel < oldlabel) {
    *changed = 1;
    data[w * y + x] = curlabel;
  }
}

kernel void plus_propagate(global int *data, int w, int h,
                           global char *changed) {
  int x = get_global_id(0);
  int y = get_global_id(1);
  if (x >= w || y >= h) {
    return;
  }

  int oldlabel = data[w * y + x];
  int curlabel = oldlabel;
  int otherlabel = 0;
  int diff;

  if (curlabel == 0) {
    return;
  }

  diff = 1;
  while (true) {
    if (y + diff < 0 || y + diff >= h) {
      break;
    }
    otherlabel = data[w * (y + diff) + (x)];
    if (otherlabel == 0) {
      break;
    }
    if (otherlabel < curlabel) {
      curlabel = otherlabel;
    }
    ++diff;
  }
  diff = 1;
  while (true) {
    if (y - diff < 0 || y - diff >= h) {
      break;
    }
    otherlabel = data[w * (y - diff) + (x)];
    if (otherlabel == 0) {
      break;
    }
    if (otherlabel < curlabel) {
      curlabel = otherlabel;
    }
    ++diff;
  }
  diff = 1;
  while (true) {
    if (x + diff < 0 || x + diff >= w) {
      break;
    }
    otherlabel = data[w * y + (x + diff)];
    if (otherlabel == 0) {
      break;
    }
    if (otherlabel < curlabel) {
      curlabel = otherlabel;
    }
    ++diff;
  }
  diff = 1;
  while (true) {
    if (x - diff < 0 || x - diff >= w) {
      break;
    }
    otherlabel = data[w * y + (x - diff)];
    if (otherlabel == 0) {
      break;
    }
    if (otherlabel < curlabel) {
      curlabel = otherlabel;
    }
    ++diff;
  }

  if (curlabel < oldlabel) {
    *changed = 1;
    data[w * y + x] = curlabel;
  }
}

int find_set(global int *data, int loc) {
  // All loc of found elements should be in range.
  // Also assuming there are no cycles in the links.
  while (loc != data[loc] - 2) {
    loc = data[loc] - 2;
  }

  // +2 is the correct LABEL of root at LOCATION loc
  return loc + 2;
}

kernel void union_find(global int *data, int w, int h, global char *changed) {
  int x = get_global_id(0);
  int y = get_global_id(1);
  if (x >= w || y >= h) {
    return;
  }

  int oldlabel = data[w * y + x];
  int lowest = oldlabel;

  if (oldlabel == 0) {
    return;
  }

  bool ok_N = y - 1 >= 0 && data[w * (y - 1) + (x)];
  bool ok_E = x + 1 < w && data[w * (y) + (x + 1)];
  bool ok_S = y + 1 < h && data[w * (y + 1) + (x)];
  bool ok_W = x - 1 >= 0 && data[w * (y) + (x - 1)];
  int root_N = 1 << 30;
  int root_E = 1 << 30;
  int root_S = 1 << 30;
  int root_W = 1 << 30;

  if (ok_N) {
    root_N = find_set(data, w * (y - 1) + (x));
  }
  if (ok_E) {
    root_E = find_set(data, w * (y) + (x + 1));
  }
  if (ok_S) {
    root_S = find_set(data, w * (y + 1) + (x));
  }
  if (ok_W) {
    root_W = find_set(data, w * (y) + (x - 1));
  }

  if (root_N < lowest) {
    lowest = root_N;
  }
  if (root_E < lowest) {
    lowest = root_E;
  }
  if (root_S < lowest) {
    lowest = root_S;
  }
  if (root_W < lowest) {
    lowest = root_W;
  }

  if (lowest < oldlabel) {
    *changed = 1;
    data[w * y + x] = lowest;
    if (ok_N && root_N > lowest) {
      data[root_N - 2] = lowest;
    }
    if (ok_E && root_E > lowest) {
      data[root_E - 2] = lowest;
    }
    if (ok_S && root_S > lowest) {
      data[root_S - 2] = lowest;
    }
    if (ok_W && root_W > lowest) {
      data[root_W - 2] = lowest;
    }
  }
}

kernel void lineedit_right(global int *data, int w, int h,
                           global char *changed) {
  int x = 0;
  int y = get_global_id(0);
  int lowest = 1 << 30;

  while (x < w) {
    int curlabel = data[w * y + x];

    if (curlabel == 0) {
      lowest = 1 << 30;
    } else {
      if (curlabel < lowest) {
        lowest = curlabel;
      } else if (curlabel > lowest) {
        data[w * y + x] = lowest;
        *changed = 1;
      }
    }

    ++x;
  }
}

kernel void lineedit_left(global int *data, int w, int h,
                          global char *changed) {
  int x = w - 1;
  int y = get_global_id(0);
  int lowest = 1 << 30;

  while (x >= 0) {
    int curlabel = data[w * y + x];

    if (curlabel == 0) {
      lowest = 1 << 30;
    } else {
      if (curlabel < lowest) {
        lowest = curlabel;
      } else if (curlabel > lowest) {
        data[w * y + x] = lowest;
        *changed = 1;
      }
    }

    --x;
  }
}

kernel void lineedit_up(global int *data, int w, int h, global char *changed) {
  int x = get_global_id(0);
  int y = 0;
  int lowest = 1 << 30;

  while (y < h) {
    int curlabel = data[w * y + x];

    if (curlabel == 0) {
      lowest = 1 << 30;
    } else {
      if (curlabel < lowest) {
        lowest = curlabel;
      } else if (curlabel > lowest) {
        data[w * y + x] = lowest;
        *changed = 1;
      }
    }

    ++y;
  }
}

kernel void lineedit_down(global int *data, int w, int h,
                          global char *changed) {
  int x = get_global_id(0);
  int y = h - 1;
  int lowest = 1 << 30;

  while (y >= 0) {
    int curlabel = data[w * y + x];

    if (curlabel == 0) {
      lowest = 1 << 30;
    } else {
      if (curlabel < lowest) {
        lowest = curlabel;
      } else if (curlabel > lowest) {
        data[w * y + x] = lowest;
        *changed = 1;
      }
    }

    --y;
  }
}

kernel void lines_up(global int *data, int w, int h, global char *changed) {
  int x = get_global_id(0);
  int y = 0;
  char localchanged = 0;

  while (y < h) {
    if (!data[w * y + x]) {
      ++y;
      continue;
    }
    int i = y;
    int min = data[w * y + x];
    int tmpmin = min;

    while (i < h && (tmpmin = data[w * i + x])) {
      if (tmpmin != min) {
        localchanged = 1; // Not all equal, i.e. will have change
      }
      if (tmpmin < min) {
        min = tmpmin;
      }
      ++i;
    }

    while (y != i) {
      data[w * y + x] = min;
      ++y;
    }
  }

  if (localchanged) {
    *changed = localchanged;
  }
}

kernel void lines_right(global int *data, int w, int h, global char *changed) {
  int x = 0;
  int y = get_global_id(0);
  char localchanged = 0;

  while (x < w) {
    if (!data[w * y + x]) {
      ++x;
      continue;
    }
    int i = x;
    int min = data[w * y + x];
    int tmpmin = min;

    while (i < w && (tmpmin = data[w * y + i])) {
      if (tmpmin != min) {
        localchanged = 1; // Not all equal, i.e. will have change
      }
      if (tmpmin < min) {
        min = tmpmin;
      }
      ++i;
    }

    while (x != i) {
      data[w * y + x] = min;
      ++x;
    }
  }

  if (localchanged) {
    *changed = localchanged;
  }
}

kernel void id_accessor(global int *data, int w) {
  unsigned int x = get_global_id(0);
  unsigned int y = get_global_id(1);

  int loc = w * y + x;
  data[loc] = data[loc];
}

// Can't allocate if not known at compile-time anyway
#define lw 32
#define lh 4

kernel void solve_locally_nprop(global int *data, int w, int h) {
  int lx = get_local_id(0);
  int ly = get_local_id(1);
  int x = get_global_id(0);
  int y = get_global_id(1);

  char valid = 1;
  local int buffer[lw * lh];
  local char changed;

  if (y >= h || x >= w) {
    valid = 0;
  }
  buffer[lw * ly + lx] = valid ? data[w * y + x] : 0;
  changed = 1;

  while (changed) {
    barrier(CLK_LOCAL_MEM_FENCE);
    changed = 0;
    barrier(CLK_LOCAL_MEM_FENCE);

    if (valid) {
      int min = 1 << 30;
      int tmp;
      if (lx > 0) {
        tmp = buffer[lw * (ly) + (lx - 1)];
        if (tmp && tmp < min) {
          min = tmp;
        }
      }
      if (lx < lw - 1) {
        tmp = buffer[lw * (ly) + (lx + 1)];
        if (tmp && tmp < min) {
          min = tmp;
        }
      }
      if (ly > 0) {
        tmp = buffer[lw * (ly - 1) + (lx)];
        if (tmp && tmp < min) {
          min = tmp;
        }
      }
      if (ly < lh - 1) {
        tmp = buffer[lw * (ly + 1) + (lx)];
        if (tmp && tmp < min) {
          min = tmp;
        }
      }
      if (min < buffer[lw * ly + lx]) {
        changed = 1;
        buffer[lw * ly + lx] = min;
      }
    }

    barrier(CLK_LOCAL_MEM_FENCE);
  }

  if (valid) {
    data[w * y + x] = buffer[lw * ly + lx];
  }
}

kernel void label_with_id(global int *data, int w, int h) {
  int x = get_global_id(0);
  int y = get_global_id(1);
  if (x >= w || y >= h) {
    return;
  }

  int loc = w * y + x;
  if (data[loc] == 1) {
    data[loc] = loc + 2;
  }
}

kernel void neighbour_propagate(global int *data, int w, int h,
                                global char *changed) {
  int x = get_global_id(0);
  int y = get_global_id(1);
  if (x >= w || y >= h) {
    return;
  }

  int oldlabel = data[w * y + x];
  int curlabel = oldlabel;
  int otherlabel = 0;

  if (curlabel == 0) {
    return;
  }

  if (y + 1 < h) {
    otherlabel = data[w * (y + 1) + (x)];
    if (otherlabel && otherlabel < curlabel) {
      curlabel = otherlabel;
    }
  }
  if (y - 1 >= 0) {
    otherlabel = data[w * (y - 1) + (x)];
    if (otherlabel && otherlabel < curlabel) {
      curlabel = otherlabel;
    }
  }
  if (x + 1 < w) {
    otherlabel = data[w * (y) + (x + 1)];
    if (otherlabel && otherlabel < curlabel) {
      curlabel = otherlabel;
    }
  }
  if (x - 1 >= 0) {
    otherlabel = data[w * (y) + (x - 1)];
    if (otherlabel && otherlabel < curlabel) {
      curlabel = otherlabel;
    }
  }

  if (curlabel < oldlabel) {
    *changed = 1;
    data[w * y + x] = curlabel;
  }
}

kernel void plus_propagate(global int *data, int w, int h,
                           global char *changed) {
  int x = get_global_id(0);
  int y = get_global_id(1);
  if (x >= w || y >= h) {
    return;
  }

  int oldlabel = data[w * y + x];
  int curlabel = oldlabel;
  int otherlabel = 0;
  int diff;

  if (curlabel == 0) {
    return;
  }

  diff = 1;
  while (true) {
    if (y + diff < 0 || y + diff >= h) {
      break;
    }
    otherlabel = data[w * (y + diff) + (x)];
    if (otherlabel == 0) {
      break;
    }
    if (otherlabel < curlabel) {
      curlabel = otherlabel;
    }
    ++diff;
  }
  diff = 1;
  while (true) {
    if (y - diff < 0 || y - diff >= h) {
      break;
    }
    otherlabel = data[w * (y - diff) + (x)];
    if (otherlabel == 0) {
      break;
    }
    if (otherlabel < curlabel) {
      curlabel = otherlabel;
    }
    ++diff;
  }
  diff = 1;
  while (true) {
    if (x + diff < 0 || x + diff >= w) {
      break;
    }
    otherlabel = data[w * y + (x + diff)];
    if (otherlabel == 0) {
      break;
    }
    if (otherlabel < curlabel) {
      curlabel = otherlabel;
    }
    ++diff;
  }
  diff = 1;
  while (true) {
    if (x - diff < 0 || x - diff >= w) {
      break;
    }
    otherlabel = data[w * y + (x - diff)];
    if (otherlabel == 0) {
      break;
    }
    if (otherlabel < curlabel) {
      curlabel = otherlabel;
    }
    ++diff;
  }

  if (curlabel < oldlabel) {
    *changed = 1;
    data[w * y + x] = curlabel;
  }
}

int find_set(global int *data, int loc) {
  // All loc of found elements should be in range.
  // Also assuming there are no cycles in the links.
  while (loc != data[loc] - 2) {
    loc = data[loc] - 2;
  }

  // +2 is the correct LABEL of root at LOCATION loc
  return loc + 2;
}

kernel void union_find(global int *data, int w, int h, global char *changed) {
  int x = get_global_id(0);
  int y = get_global_id(1);
  if (x >= w || y >= h) {
    return;
  }

  int oldlabel = data[w * y + x];
  int lowest = oldlabel;

  if (oldlabel == 0) {
    return;
  }

  bool ok_N = y - 1 >= 0 && data[w * (y - 1) + (x)];
  bool ok_E = x + 1 < w && data[w * (y) + (x + 1)];
  bool ok_S = y + 1 < h && data[w * (y + 1) + (x)];
  bool ok_W = x - 1 >= 0 && data[w * (y) + (x - 1)];
  int root_N = 1 << 30;
  int root_E = 1 << 30;
  int root_S = 1 << 30;
  int root_W = 1 << 30;

  if (ok_N) {
    root_N = find_set(data, w * (y - 1) + (x));
  }
  if (ok_E) {
    root_E = find_set(data, w * (y) + (x + 1));
  }
  if (ok_S) {
    root_S = find_set(data, w * (y + 1) + (x));
  }
  if (ok_W) {
    root_W = find_set(data, w * (y) + (x - 1));
  }

  if (root_N < lowest) {
    lowest = root_N;
  }
  if (root_E < lowest) {
    lowest = root_E;
  }
  if (root_S < lowest) {
    lowest = root_S;
  }
  if (root_W < lowest) {
    lowest = root_W;
  }

  if (lowest < oldlabel) {
    *changed = 1;
    data[w * y + x] = lowest;
    if (ok_N && root_N > lowest) {
      data[root_N - 2] = lowest;
    }
    if (ok_E && root_E > lowest) {
      data[root_E - 2] = lowest;
    }
    if (ok_S && root_S > lowest) {
      data[root_S - 2] = lowest;
    }
    if (ok_W && root_W > lowest) {
      data[root_W - 2] = lowest;
    }
  }
}

kernel void lineedit_right(global int *data, int w, int h,
                           global char *changed) {
  int x = 0;
  int y = get_global_id(0);
  int lowest = 1 << 30;

  while (x < w) {
    int curlabel = data[w * y + x];

    if (curlabel == 0) {
      lowest = 1 << 30;
    } else {
      if (curlabel < lowest) {
        lowest = curlabel;
      } else if (curlabel > lowest) {
        data[w * y + x] = lowest;
        *changed = 1;
      }
    }

    ++x;
  }
}

kernel void lineedit_left(global int *data, int w, int h,
                          global char *changed) {
  int x = w - 1;
  int y = get_global_id(0);
  int lowest = 1 << 30;

  while (x >= 0) {
    int curlabel = data[w * y + x];

    if (curlabel == 0) {
      lowest = 1 << 30;
    } else {
      if (curlabel < lowest) {
        lowest = curlabel;
      } else if (curlabel > lowest) {
        data[w * y + x] = lowest;
        *changed = 1;
      }
    }

    --x;
  }
}

kernel void lineedit_up(global int *data, int w, int h, global char *changed) {
  int x = get_global_id(0);
  int y = 0;
  int lowest = 1 << 30;

  while (y < h) {
    int curlabel = data[w * y + x];

    if (curlabel == 0) {
      lowest = 1 << 30;
    } else {
      if (curlabel < lowest) {
        lowest = curlabel;
      } else if (curlabel > lowest) {
        data[w * y + x] = lowest;
        *changed = 1;
      }
    }

    ++y;
  }
}

kernel void lineedit_down(global int *data, int w, int h,
                          global char *changed) {
  int x = get_global_id(0);
  int y = h - 1;
  int lowest = 1 << 30;

  while (y >= 0) {
    int curlabel = data[w * y + x];

    if (curlabel == 0) {
      lowest = 1 << 30;
    } else {
      if (curlabel < lowest) {
        lowest = curlabel;
      } else if (curlabel > lowest) {
        data[w * y + x] = lowest;
        *changed = 1;
      }
    }

    --y;
  }
}

kernel void lines_up(global int *data, int w, int h, global char *changed) {
  int x = get_global_id(0);
  int y = 0;
  char localchanged = 0;

  while (y < h) {
    if (!data[w * y + x]) {
      ++y;
      continue;
    }
    int i = y;
    int min = data[w * y + x];
    int tmpmin = min;

    while (i < h && (tmpmin = data[w * i + x])) {
      if (tmpmin != min) {
        localchanged = 1; // Not all equal, i.e. will have change
      }
      if (tmpmin < min) {
        min = tmpmin;
      }
      ++i;
    }

    while (y != i) {
      data[w * y + x] = min;
      ++y;
    }
  }

  if (localchanged) {
    *changed = localchanged;
  }
}

kernel void lines_right(global int *data, int w, int h, global char *changed) {
  int x = 0;
  int y = get_global_id(0);
  char localchanged = 0;

  while (x < w) {
    if (!data[w * y + x]) {
      ++x;
      continue;
    }
    int i = x;
    int min = data[w * y + x];
    int tmpmin = min;

    while (i < w && (tmpmin = data[w * y + i])) {
      if (tmpmin != min) {
        localchanged = 1; // Not all equal, i.e. will have change
      }
      if (tmpmin < min) {
        min = tmpmin;
      }
      ++i;
    }

    while (x != i) {
      data[w * y + x] = min;
      ++x;
    }
  }

  if (localchanged) {
    *changed = localchanged;
  }
}

kernel void id_accessor(global int *data, int w) {
  unsigned int x = get_global_id(0);
  unsigned int y = get_global_id(1);

  int loc = w * y + x;
  data[loc] = data[loc];
}

// Can't allocate if not known at compile-time anyway
#define lw 32
#define lh 4

kernel void solve_locally_nprop(global int *data, int w, int h) {
  int lx = get_local_id(0);
  int ly = get_local_id(1);
  int x = get_global_id(0);
  int y = get_global_id(1);

  char valid = 1;
  local int buffer[lw * lh];
  local char changed;

  if (y >= h || x >= w) {
    valid = 0;
  }
  buffer[lw * ly + lx] = valid ? data[w * y + x] : 0;
  changed = 1;

  while (changed) {
    barrier(CLK_LOCAL_MEM_FENCE);
    changed = 0;
    barrier(CLK_LOCAL_MEM_FENCE);

    if (valid) {
      int min = 1 << 30;
      int tmp;
      if (lx > 0) {
        tmp = buffer[lw * (ly) + (lx - 1)];
        if (tmp < min) {
          min = tmp;
        }
      }
      if (lx < lw - 1) {
        tmp = buffer[lw * (ly) + (lx + 1)];
        if (tmp < min) {
          min = tmp;
        }
      }
      if (ly > 0) {
        tmp = buffer[lw * (ly - 1) + (lx)];
        if (tmp < min) {
          min = tmp;
        }
      }
      if (ly < lh - 1) {
        tmp = buffer[lw * (ly + 1) + (lx)];
        if (tmp < min) {
          min = tmp;
        }
      }
      if (min < buffer[lw * ly + lx]) {
        changed = 1;
        buffer[lw * ly + lx] = min;
      }
    }

    barrier(CLK_LOCAL_MEM_FENCE);
  }
}


Fix 2-level intersector

Fix 2-level intersector

/**********************************************************************
Copyright (c) 2016 Advanced Micro Devices, Inc. All rights reserved.

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.
********************************************************************/
/**
    \file intersect_2level_skiplinkscl
    \author Dmitry Kozlov
    \version 1.0
    \brief Intersector implementation based on 2-level BVH with skip links.

    IntersectorSkipLinks implementation is based on the modification of the following paper:
    "Efficiency Issues for Ray Tracing" Brian Smits
    http://www.cse.chalmers.se/edu/year/2016/course/course/TDA361/EfficiencyIssuesForRayTracing.pdf

    Intersector is using binary BVH with a single bounding box per node. BVH layout guarantees
    that left child of an internal node lies right next to it in memory. Each BVH node has a
    skip link to the node traversed next. Intersector builds its own BVH for each scene object
    and then top level BVH across all bottom level BVHs. Top level leafs keep object transforms and
    might reference other leafs making instancing possible.

    Pros:
        -Simple and efficient kernel with low VGPR pressure.
        -Can traverse trees of arbitrary depth.
        -Supports motion blur.
        -Supports instancing.
        -Fast to refit.
    Cons:
        -Travesal order is fixed, so poor algorithmic characteristics.
        -Does not benefit from BVH quality optimizations.
 */

/*************************************************************************
INCLUDES
**************************************************************************/
#include <../RadeonRays/src/kernels/CL/common.cl>

/*************************************************************************
EXTENSIONS
**************************************************************************/

/*************************************************************************
DEFINES
**************************************************************************/
#define PI 3.14159265358979323846f
#define STARTIDX(x)     (((int)(x.pmin.w)) >> 4)
#define SHAPEIDX(x)     (((int)(x.pmin.w)) >> 4)
#define LEAFNODE(x)     (((x).pmin.w) != -1.f)
#define NEXT(x)     ((int)((x).pmax.w))

/*************************************************************************
TYPE DEFINITIONS
**************************************************************************/

typedef bbox bvh_node;

typedef struct
{
    // Shape ID
    int id;
    // Shape BVH index (bottom level)
    int bvh_idx;
    // Shape mask
    int mask;
    int padding1;
    // Transform
    float4 m0;
    float4 m1;
    float4 m2;
    float4 m3;
    // Motion blur params
    float4 velocity_linear;
    float4 velocity_angular;
} Shape;

typedef struct
{
    // Vertex indices
    int idx[3];
    // Shape maks
    int shape_mask;
    // Shape ID
    int shape_id;
    // Primitive ID
    int prim_id;
} Face;

INLINE float3 transform_point(float3 p, float4 m0, float4 m1, float4 m2, float4 m3)
{
    float3 res;
    res.x = m0.s0 * p.x + m0.s1 * p.y + m0.s2 * p.z + m0.s3;
    res.y = m1.s0 * p.x + m1.s1 * p.y + m1.s2 * p.z + m1.s3;
    res.z = m2.s0 * p.x + m2.s1 * p.y + m2.s2 * p.z + m2.s3;
    return res;
}

INLINE float3 transform_vector(float3 p, float4 m0, float4 m1, float4 m2, float4 m3)
{
    float3 res;
    res.x = m0.s0 * p.x + m0.s1 * p.y + m0.s2 * p.z;
    res.y = m1.s0 * p.x + m1.s1 * p.y + m1.s2 * p.z;
    res.z = m2.s0 * p.x + m2.s1 * p.y + m2.s2 * p.z;
    return res;
}

INLINE ray transform_ray(ray r, float4 m0, float4 m1, float4 m2, float4 m3)
{
    ray res;
    res.o.xyz = transform_point(r.o.xyz, m0, m1, m2, m3);
    res.d.xyz = transform_vector(r.d.xyz, m0, m1, m2, m3);
    res.o.w = r.o.w;
    res.d.w = r.d.w;
    return res;
}

__attribute__((reqd_work_group_size(64, 1, 1)))
KERNEL void intersect_main(
    // BVH nodes
    GLOBAL bvh_node const* restrict nodes,
    // Vertices
    GLOBAL float3 const* restrict vertices,
    // Faces
    GLOBAL Face const* restrict faces,
    // Shapes
    GLOBAL Shape const* restrict shapes,
    // BVH root index
    int root_idx,
    // Rays
    GLOBAL ray const* restrict rays,
    // Number of rays in ray buffer
    GLOBAL int const* restrict num_rays,
    // Hits
    GLOBAL Intersection* hits
)
{
    int global_id = get_global_id(0);

    // Handle only working subset
    if (global_id < *num_rays)
    {
        // Fetch ray
        ray r = rays[global_id];

        if (ray_is_active(&r))
        {
            // Precompute invdir for bbox testing
            float3 invdir = native_recip(r.d.xyz);
            float3 invdirtop = invdir;
            float t_max = r.o.w;

            // We need to keep original ray around for returns from bottom hierarchy
            ray top_ray = r;

            // Fetch top level BVH index
            int addr = root_idx;
            // Set top index
            int top_addr = INVALID_IDX;
            // Current shape ID
            int shape_id = INVALID_IDX;
            // Closest shape ID
            int closest_shape_id = INVALID_IDX;
            int closest_prim_id = INVALID_IDX;
            float2 closest_barycentrics;

            while (addr != INVALID_IDX)
            {
                // Fetch next node
                bvh_node node = nodes[addr];
                // Intersect against bbox
                float2 s = fast_intersect_bbox1(node, invdir, -r.o.xyz * invdir, t_max);

                if (s.x <= s.y)
                {
                    if (LEAFNODE(node))
                    {
                        // If this is the leaf it can be either a leaf containing primitives (bottom hierarchy)
                        // or containing another BVH (top level hierarhcy)
                        if (top_addr != INVALID_IDX)
                        {
                            // Intersect leaf here
                            //
                            int const face_idx = STARTIDX(node);
                            Face const face = faces[face_idx];
                            float3 const v1 = vertices[face.idx[0]];
                            float3 const v2 = vertices[face.idx[1]];
                            float3 const v3 = vertices[face.idx[2]];

                            // Intersect triangle
                            float const f = fast_intersect_triangle(r, v1, v2, v3, t_max);
                            // If hit update closest hit distance and index
                            if (f < t_max)
                            {
                                t_max = f;
                                closest_prim_id = face.prim_id;
                                closest_shape_id = shape_id;

                                float3 const p = r.o.xyz + r.d.xyz * t_max;
                                // Calculte barycentric coordinates
                                closest_barycentrics = triangle_calculate_barycentrics(p, v1, v2, v3);
                            }

                            // And goto next node
                            addr = NEXT(node);
                        }
                        else
                        {
                            // This is top level hierarchy leaf
                            // Save top node index for return
                            top_addr = addr;
                            // Get shape descrition struct index
                            int shape_idx = SHAPEIDX(node);
                            // Get shape mask
                            int shape_mask = shapes[shape_idx].mask;
                            // Drill into 2nd level BVH only if the geometry is not masked vs current ray
                            // otherwise skip the subtree
                            //if (ray_get_mask(&r) && shape_mask)
                            {
                                // Fetch bottom level BVH index
                                addr = shapes[shape_idx].bvh_idx;
                                shape_id = shapes[shape_idx].id;

                                // Fetch BVH transform
                                float4 wmi0 = shapes[shape_idx].m0;
                                float4 wmi1 = shapes[shape_idx].m1;
                                float4 wmi2 = shapes[shape_idx].m2;
                                float4 wmi3 = shapes[shape_idx].m3;

                                r = transform_ray(r, wmi0, wmi1, wmi2, wmi3);
                                // Recalc invdir
                                invdir = native_recip(r.d.xyz);
                                // And continue traversal of the bottom level BVH
                                continue;
                            }
                            /*else
                            {
                                addr = INVALID_IDX;
                            }*/
                        }
                    }
                    // Traverse child nodes otherwise.
                    else
                    {
                        // This is an internal node, proceed to left child (it is at current + 1 index)
                        addr = addr + 1;
                    }
                }
                else
                {
                    // We missed the node, goto next one
                    addr = NEXT(node);
                }

                // Here check if we ended up traversing bottom level BVH
                // in this case idx = -1 and topidx has valid value
                if (addr == INVALID_IDX && top_addr != INVALID_IDX)
                {
                    //  Proceed to next top level node
                    addr = NEXT(nodes[top_addr]);
                    // Set topidx
                    top_addr = INVALID_IDX;
                    // Restore ray here
                    r = top_ray;
                    // Restore invdir
                    invdir = invdirtop;
                }
            }

            // Check if we have found an intersection
            if (closest_shape_id != INVALID_IDX)
            {
                // Update hit information
                hits[global_id].shape_id = closest_shape_id;
                hits[global_id].prim_id = closest_prim_id;
                hits[global_id].uvwt = make_float4(closest_barycentrics.x, closest_barycentrics.y, 0.f, t_max);
            }
            else
            {
                // Miss here
                hits[global_id].shape_id = MISS_MARKER;
                hits[global_id].prim_id = MISS_MARKER;
            }
        }
    }
}

__attribute__((reqd_work_group_size(64, 1, 1)))
KERNEL void occluded_main(
    // BVH nodes
    GLOBAL bvh_node const* restrict nodes,
    // Vertices
    GLOBAL float3 const* restrict vertices,
    // Faces
    GLOBAL Face const* restrict faces,
    // Shapes
    GLOBAL Shape const* restrict shapes,
    // BVH root index
    int root_idx,
    // Rays
    GLOBAL ray const* restrict rays,
    // Number of rays in ray buffer
    GLOBAL int const* restrict num_rays,
    // Hits
    GLOBAL int* hits
)
{
    int global_id = get_global_id(0);

    // Handle only working subset
    if (global_id < *num_rays)
    {
        // Fetch ray
        ray r = rays[global_id];

        if (ray_is_active(&r))
        {
            // Precompute invdir for bbox testing
            float3 invdir = native_recip(r.d.xyz);
            float3 invdirtop = invdir;
            float const t_max = r.o.w;

            // We need to keep original ray around for returns from bottom hierarchy
            ray top_ray = r;

            // Fetch top level BVH index
            int addr = root_idx;
            // Set top index
            int top_addr = INVALID_IDX;

            while (addr != INVALID_IDX)
            {
                // Fetch next node
                bvh_node node = nodes[addr];
                // Intersect against bbox
                float2 s = fast_intersect_bbox1(node, invdir, -r.o.xyz * invdir, t_max);

                if (s.x <= s.y)
                {
                    if (LEAFNODE(node))
                    {
                        // If this is the leaf it can be either a leaf containing primitives (bottom hierarchy)
                        // or containing another BVH (top level hierarhcy)
                        if (top_addr != INVALID_IDX)
                        {
                            // Intersect leaf here
                            //
                            int const face_idx = STARTIDX(node);
                            Face const face = faces[face_idx];
                            float3 const v1 = vertices[face.idx[0]];
                            float3 const v2 = vertices[face.idx[1]];
                            float3 const v3 = vertices[face.idx[2]];

                            // Intersect triangle
                            float const f = fast_intersect_triangle(r, v1, v2, v3, t_max);
                            // If hit update closest hit distance and index
                            if (f < t_max)
                            {
                                hits[global_id] = HIT_MARKER;
                                return;
                            }

                            // And goto next node
                            addr = NEXT(node);
                        }
                        else
                        {
                            // This is top level hierarchy leaf
                            // Save top node index for return
                            top_addr = addr;
                            // Get shape descrition struct index
                            int shape_idx = SHAPEIDX(node);
                            // Get shape mask
                            int shape_mask = shapes[shape_idx].mask;
                            // Drill into 2nd level BVH only if the geometry is not masked vs current ray
                            // otherwise skip the subtree
                            if (ray_get_mask(&r) && shape_mask)
                            {
                                // Fetch bottom level BVH index
                                addr = shapes[shape_idx].bvh_idx;

                                // Fetch BVH transform
                                float4 wmi0 = shapes[shape_idx].m0;
                                float4 wmi1 = shapes[shape_idx].m1;
                                float4 wmi2 = shapes[shape_idx].m2;
                                float4 wmi3 = shapes[shape_idx].m3;

                                r = transform_ray(r, wmi0, wmi1, wmi2, wmi3);
                                // Recalc invdir
                                invdir = native_recip(r.d.xyz);
                                // And continue traversal of the bottom level BVH
                                continue;
                            }
                            else
                            {
                                addr = INVALID_IDX;
                            }
                        }
                    }
                    // Traverse child nodes otherwise.
                    else
                    {
                        // This is an internal node, proceed to left child (it is at current + 1 index)
                        addr = addr + 1;
                    }
                }
                else
                {
                    // We missed the node, goto next one
                    addr = NEXT(node);
                }

                // Here check if we ended up traversing bottom level BVH
                // in this case idx = -1 and topidx has valid value
                if (addr == INVALID_IDX && top_addr != INVALID_IDX)
                {
                    //  Proceed to next top level node
                    addr = NEXT(nodes[top_addr]);
                    // Set topidx
                    top_addr = INVALID_IDX;
                    // Restore ray here
                    r = top_ray;
                    // Restore invdir
                    invdir = invdirtop;
                }
            }

            hits[global_id] = MISS_MARKER;
        }
    }
}

/**********************************************************************
Copyright (c) 2016 Advanced Micro Devices, Inc. All rights reserved.

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.
********************************************************************/
/**
    \file intersect_2level_skiplinkscl
    \author Dmitry Kozlov
    \version 1.0
    \brief Intersector implementation based on 2-level BVH with skip links.

    IntersectorSkipLinks implementation is based on the modification of the following paper:
    "Efficiency Issues for Ray Tracing" Brian Smits
    http://www.cse.chalmers.se/edu/year/2016/course/course/TDA361/EfficiencyIssuesForRayTracing.pdf

    Intersector is using binary BVH with a single bounding box per node. BVH layout guarantees
    that left child of an internal node lies right next to it in memory. Each BVH node has a
    skip link to the node traversed next. Intersector builds its own BVH for each scene object
    and then top level BVH across all bottom level BVHs. Top level leafs keep object transforms and
    might reference other leafs making instancing possible.

    Pros:
        -Simple and efficient kernel with low VGPR pressure.
        -Can traverse trees of arbitrary depth.
        -Supports motion blur.
        -Supports instancing.
        -Fast to refit.
    Cons:
        -Travesal order is fixed, so poor algorithmic characteristics.
        -Does not benefit from BVH quality optimizations.
 */

/*************************************************************************
INCLUDES
**************************************************************************/
#include <../RadeonRays/src/kernels/CL/common.cl>

/*************************************************************************
EXTENSIONS
**************************************************************************/

/*************************************************************************
DEFINES
**************************************************************************/
#define PI 3.14159265358979323846f
#define STARTIDX(x)     (((int)(x.pmin.w)))
#define SHAPEIDX(x)     (((int)(x.pmin.w)))
#define LEAFNODE(x)     (((x).pmin.w) != -1.f)
#define NEXT(x)     ((int)((x).pmax.w))

/*************************************************************************
TYPE DEFINITIONS
**************************************************************************/

typedef bbox bvh_node;

typedef struct
{
    // Shape ID
    int id;
    // Shape BVH index (bottom level)
    int bvh_idx;
    // Shape mask
    int mask;
    int padding1;
    // Transform
    float4 m0;
    float4 m1;
    float4 m2;
    float4 m3;
    // Motion blur params
    float4 velocity_linear;
    float4 velocity_angular;
} Shape;

typedef struct
{
    // Vertex indices
    int idx[3];
    // Shape maks
    int shape_mask;
    // Shape ID
    int shape_id;
    // Primitive ID
    int prim_id;
} Face;

INLINE float3 transform_point(float3 p, float4 m0, float4 m1, float4 m2, float4 m3)
{
    float3 res;
    res.x = m0.s0 * p.x + m0.s1 * p.y + m0.s2 * p.z + m0.s3;
    res.y = m1.s0 * p.x + m1.s1 * p.y + m1.s2 * p.z + m1.s3;
    res.z = m2.s0 * p.x + m2.s1 * p.y + m2.s2 * p.z + m2.s3;
    return res;
}

INLINE float3 transform_vector(float3 p, float4 m0, float4 m1, float4 m2, float4 m3)
{
    float3 res;
    res.x = m0.s0 * p.x + m0.s1 * p.y + m0.s2 * p.z;
    res.y = m1.s0 * p.x + m1.s1 * p.y + m1.s2 * p.z;
    res.z = m2.s0 * p.x + m2.s1 * p.y + m2.s2 * p.z;
    return res;
}

INLINE ray transform_ray(ray r, float4 m0, float4 m1, float4 m2, float4 m3)
{
    ray res;
    res.o.xyz = transform_point(r.o.xyz, m0, m1, m2, m3);
    res.d.xyz = transform_vector(r.d.xyz, m0, m1, m2, m3);
    res.o.w = r.o.w;
    res.d.w = r.d.w;
    return res;
}

__attribute__((reqd_work_group_size(64, 1, 1)))
KERNEL void intersect_main(
    // BVH nodes
    GLOBAL bvh_node const* restrict nodes,
    // Vertices
    GLOBAL float3 const* restrict vertices,
    // Faces
    GLOBAL Face const* restrict faces,
    // Shapes
    GLOBAL Shape const* restrict shapes,
    // BVH root index
    int root_idx,
    // Rays
    GLOBAL ray const* restrict rays,
    // Number of rays in ray buffer
    GLOBAL int const* restrict num_rays,
    // Hits
    GLOBAL Intersection* hits
)
{
    int global_id = get_global_id(0);

    // Handle only working subset
    if (global_id < *num_rays)
    {
        // Fetch ray
        ray r = rays[global_id];

        if (ray_is_active(&r))
        {
            // Precompute invdir for bbox testing
            float3 invdir = native_recip(r.d.xyz);
            float3 invdirtop = invdir;
            float t_max = r.o.w;

            // We need to keep original ray around for returns from bottom hierarchy
            ray top_ray = r;

            // Fetch top level BVH index
            int addr = root_idx;
            // Set top index
            int top_addr = INVALID_IDX;
            // Current shape ID
            int shape_id = INVALID_IDX;
            // Closest shape ID
            int closest_shape_id = INVALID_IDX;
            int closest_prim_id = INVALID_IDX;
            float2 closest_barycentrics;

            while (addr != INVALID_IDX)
            {
                // Fetch next node
                bvh_node node = nodes[addr];
                // Intersect against bbox
                float2 s = fast_intersect_bbox1(node, invdir, -r.o.xyz * invdir, t_max);

                if (s.x <= s.y)
                {
                    if (LEAFNODE(node))
                    {
                        // If this is the leaf it can be either a leaf containing primitives (bottom hierarchy)
                        // or containing another BVH (top level hierarhcy)
                        if (top_addr != INVALID_IDX)
                        {
                            // Intersect leaf here
                            //
                            int const face_idx = STARTIDX(node);
                            Face const face = faces[face_idx];
                            float3 const v1 = vertices[face.idx[0]];
                            float3 const v2 = vertices[face.idx[1]];
                            float3 const v3 = vertices[face.idx[2]];

                            // Intersect triangle
                            float const f = fast_intersect_triangle(r, v1, v2, v3, t_max);
                            // If hit update closest hit distance and index
                            if (f < t_max)
                            {
                                t_max = f;
                                closest_prim_id = face.prim_id;
                                closest_shape_id = shape_id;

                                float3 const p = r.o.xyz + r.d.xyz * t_max;
                                // Calculte barycentric coordinates
                                closest_barycentrics = triangle_calculate_barycentrics(p, v1, v2, v3);
                            }

                            // And goto next node
                            addr = NEXT(node);
                        }
                        else
                        {
                            // This is top level hierarchy leaf
                            // Save top node index for return
                            top_addr = addr;
                            // Get shape descrition struct index
                            int shape_idx = SHAPEIDX(node);
                            // Get shape mask
                            int shape_mask = shapes[shape_idx].mask;
                            // Drill into 2nd level BVH only if the geometry is not masked vs current ray
                            // otherwise skip the subtree
                            if (ray_get_mask(&r) && shape_mask)
                            {
                                // Fetch bottom level BVH index
                                addr = shapes[shape_idx].bvh_idx;
                                shape_id = shapes[shape_idx].id;

                                // Fetch BVH transform
                                float4 wmi0 = shapes[shape_idx].m0;
                                float4 wmi1 = shapes[shape_idx].m1;
                                float4 wmi2 = shapes[shape_idx].m2;
                                float4 wmi3 = shapes[shape_idx].m3;

                                r = transform_ray(r, wmi0, wmi1, wmi2, wmi3);
                                // Recalc invdir
                                invdir = native_recip(r.d.xyz);
                                // And continue traversal of the bottom level BVH
                                continue;
                            }
                            else
                            {
                                addr = INVALID_IDX;
                            }
                        }
                    }
                    // Traverse child nodes otherwise.
                    else
                    {
                        // This is an internal node, proceed to left child (it is at current + 1 index)
                        addr = addr + 1;
                    }
                }
                else
                {
                    // We missed the node, goto next one
                    addr = NEXT(node);
                }

                // Here check if we ended up traversing bottom level BVH
                // in this case idx = -1 and topidx has valid value
                if (addr == INVALID_IDX && top_addr != INVALID_IDX)
                {
                    //  Proceed to next top level node
                    addr = NEXT(nodes[top_addr]);
                    // Set topidx
                    top_addr = INVALID_IDX;
                    // Restore ray here
                    r = top_ray;
                    // Restore invdir
                    invdir = invdirtop;
                }
            }

            // Check if we have found an intersection
            if (closest_shape_id != INVALID_IDX)
            {
                // Update hit information
                hits[global_id].shape_id = closest_shape_id;
                hits[global_id].prim_id = closest_prim_id;
                hits[global_id].uvwt = make_float4(closest_barycentrics.x, closest_barycentrics.y, 0.f, t_max);
            }
            else
            {
                // Miss here
                hits[global_id].shape_id = MISS_MARKER;
                hits[global_id].prim_id = MISS_MARKER;
            }
        }
    }
}

__attribute__((reqd_work_group_size(64, 1, 1)))
KERNEL void occluded_main(
    // BVH nodes
    GLOBAL bvh_node const* restrict nodes,
    // Vertices
    GLOBAL float3 const* restrict vertices,
    // Faces
    GLOBAL Face const* restrict faces,
    // Shapes
    GLOBAL Shape const* restrict shapes,
    // BVH root index
    int root_idx,
    // Rays
    GLOBAL ray const* restrict rays,
    // Number of rays in ray buffer
    GLOBAL int const* restrict num_rays,
    // Hits
    GLOBAL int* hits
)
{
    int global_id = get_global_id(0);

    // Handle only working subset
    if (global_id < *num_rays)
    {
        // Fetch ray
        ray r = rays[global_id];

        if (ray_is_active(&r))
        {
            // Precompute invdir for bbox testing
            float3 invdir = native_recip(r.d.xyz);
            float3 invdirtop = invdir;
            float const t_max = r.o.w;

            // We need to keep original ray around for returns from bottom hierarchy
            ray top_ray = r;

            // Fetch top level BVH index
            int addr = root_idx;
            // Set top index
            int top_addr = INVALID_IDX;

            while (addr != INVALID_IDX)
            {
                // Fetch next node
                bvh_node node = nodes[addr];
                // Intersect against bbox
                float2 s = fast_intersect_bbox1(node, invdir, -r.o.xyz * invdir, t_max);

                if (s.x <= s.y)
                {
                    if (LEAFNODE(node))
                    {
                        // If this is the leaf it can be either a leaf containing primitives (bottom hierarchy)
                        // or containing another BVH (top level hierarhcy)
                        if (top_addr != INVALID_IDX)
                        {
                            // Intersect leaf here
                            //
                            int const face_idx = STARTIDX(node);
                            Face const face = faces[face_idx];
                            float3 const v1 = vertices[face.idx[0]];
                            float3 const v2 = vertices[face.idx[1]];
                            float3 const v3 = vertices[face.idx[2]];

                            // Intersect triangle
                            float const f = fast_intersect_triangle(r, v1, v2, v3, t_max);
                            // If hit update closest hit distance and index
                            if (f < t_max)
                            {
                                hits[global_id] = HIT_MARKER;
                                return;
                            }

                            // And goto next node
                            addr = NEXT(node);
                        }
                        else
                        {
                            // This is top level hierarchy leaf
                            // Save top node index for return
                            top_addr = addr;
                            // Get shape descrition struct index
                            int shape_idx = SHAPEIDX(node);
                            // Get shape mask
                            int shape_mask = shapes[shape_idx].mask;
                            // Drill into 2nd level BVH only if the geometry is not masked vs current ray
                            // otherwise skip the subtree
                            if (ray_get_mask(&r) && shape_mask)
                            {
                                // Fetch bottom level BVH index
                                addr = shapes[shape_idx].bvh_idx;

                                // Fetch BVH transform
                                float4 wmi0 = shapes[shape_idx].m0;
                                float4 wmi1 = shapes[shape_idx].m1;
                                float4 wmi2 = shapes[shape_idx].m2;
                                float4 wmi3 = shapes[shape_idx].m3;

                                r = transform_ray(r, wmi0, wmi1, wmi2, wmi3);
                                // Recalc invdir
                                invdir = native_recip(r.d.xyz);
                                // And continue traversal of the bottom level BVH
                                continue;
                            }
                            else
                            {
                                addr = INVALID_IDX;
                            }
                        }
                    }
                    // Traverse child nodes otherwise.
                    else
                    {
                        // This is an internal node, proceed to left child (it is at current + 1 index)
                        addr = addr + 1;
                    }
                }
                else
                {
                    // We missed the node, goto next one
                    addr = NEXT(node);
                }

                // Here check if we ended up traversing bottom level BVH
                // in this case idx = -1 and topidx has valid value
                if (addr == INVALID_IDX && top_addr != INVALID_IDX)
                {
                    //  Proceed to next top level node
                    addr = NEXT(nodes[top_addr]);
                    // Set topidx
                    top_addr = INVALID_IDX;
                    // Restore ray here
                    r = top_ray;
                    // Restore invdir
                    invdir = invdirtop;
                }
            }

            hits[global_id] = MISS_MARKER;
        }
    }
}


Remove unnecessary license text from the HOG implementation -- part 1

/* ---------------------------------------------------------------------
* Copyright Realeyes OU 2014-2015
*
* All rights reserved. Realeyes OU PROPRIETARY/CONFIDENTIAL.
* No part of this computer programs(s) may be used, reproduced,
* stored in any retrieval system, or transmitted, in any form or
* by any means, electronic, mechanical, photocopying,
* recording, or otherwise without prior written permission of
* Realeyes OU. Use is subject to license terms.
* ---------------------------------------------------------------------
*/

#ifndef NUMBER_OF_CELLS
#error NUMBER_OF_CELLS not defined
#endif
#ifndef NUMBER_OF_BINS
#error NUMBER_OF_BINS not defined
#endif
#ifndef GAUSSIAN_WEIGHTS
#error GAUSSIAN_WEIGHTS not defined
#endif
#ifndef SPARTIAL_WEIGHTS
#error SPARTIAL_WEIGHTS not defined
#endif
#ifndef SIGNED_HOG
#error SIGNED_HOG not defined
#endif
#ifndef STATIC_BLOCK_SIZE
#error STATIC_BLOCK_SIZE not defined
#endif
#if (USE_GLOBAL + USE_LOCAL + USE_PRIVATE != 1)
#error define one of one of USE_PRIVATE, USE_LOCAL, USE_GLOBAL to 1 to store intermediate histogram data in private, local, or global memory
#endif

#if VECTOR_SIZE == 16
    #define VLOADN     vload16
    #define VSTOREN    vstore16
    #define FLOATN     float16
    #define WG_REDUCEN wg_reduce16
#elif VECTOR_SIZE == 8
    #define VLOADN     vload8
    #define VSTOREN    vstore8
    #define FLOATN     float8
    #define WG_REDUCEN wg_reduce8
#elif VECTOR_SIZE == 4
    #define VLOADN     vload4
    #define VSTOREN    vstore4
    #define FLOATN     float4
    #define WG_REDUCEN wg_reduce4
#elif VECTOR_SIZE == 2
    #define VLOADN     vload2
    #define VSTOREN    vstore2
    #define FLOATN     float2
    #define WG_REDUCEN wg_reduce2
#elif VECTOR_SIZE == 1
    #define VLOADN(x, y)     (y)[x]
    #define VSTOREN(x, y, z) (z)[y] = (x)
    #define FLOATN           float
    #define WG_REDUCEN       wg_reduce
#else
    #error Unsupported vector size!
#endif

#define TOTAL_NUMBER_OF_BINS (NUMBER_OF_CELLS * NUMBER_OF_CELLS * NUMBER_OF_BINS)
#define BIN_INDEX(cellx, celly, bin) ((cellx) * NUMBER_OF_CELLS * NUMBER_OF_BINS + (celly) * NUMBER_OF_BINS + bin)
#define ROUND_DOWN_TO_VECTOR_SIZE(VAL) (VAL & ~(VECTOR_SIZE-1))

//Find the largest 2^n where (2^n) < v
uint lower_power_of_two(uint v)
{
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v++;
    return v >> 1;
}

//Returns the sum of 'value' among all workitems within this workgroup
//Overwrites temp, so add barriers before calling this function when necessary
//Provides functionality similar to OpenCL 2.0's work_group_reduce_add
#define DEFINE_REDUCE(name, datatype)                                            \
datatype name(             datatype                  value                       \
             , local       datatype * const restrict temp                        \
             ,       const size_t                    thread_id                   \
             ,       const size_t                    array_size                  \
             )                                                                   \
{                                                                                \
    /* Store partial sum to temp */                                              \
    if (thread_id < array_size) {                                                \
        temp[thread_id] = value;                                                 \
    }                                                                            \
    barrier(CLK_LOCAL_MEM_FENCE);                                                \
                                                                                \
    /* Do a reduction on temp */                                                 \
    for ( size_t offset = lower_power_of_two(array_size)                         \
        ; offset > 0                                                             \
        ; offset >>= 1                                                           \
        ) {                                                                      \
        bool check = (thread_id < offset) && (thread_id + offset < array_size ); \
        if (check) {                                                             \
            value += temp[thread_id + offset];                                   \
            temp[thread_id] = value;                                             \
        }                                                                        \
        barrier(CLK_LOCAL_MEM_FENCE);                                            \
    }                                                                            \
    return temp[0];                                                              \
}

DEFINE_REDUCE(wg_reduce  , float  )
DEFINE_REDUCE(wg_reduce2 , float2 )
DEFINE_REDUCE(wg_reduce3 , float3 )
DEFINE_REDUCE(wg_reduce4 , float4 )
DEFINE_REDUCE(wg_reduce8 , float8 )
DEFINE_REDUCE(wg_reduce16, float16)
#undef DEFINE_REDUCE

#if USE_PRIVATE
void atomic_add_float(volatile private float* source, float operand) {
    *source += operand;
}
#else
#if USE_GLOBAL
    #define LOCAL global
#elif USE_LOCAL
    #define LOCAL local
#endif
void atomic_add_float(volatile LOCAL float* source, float operand) {
    volatile LOCAL int* sourceAsInt = (volatile LOCAL int*)source;
    int oldVal;
    int oldVal_2 = 0;
    do {
        oldVal = oldVal_2;
        float newVal = as_float(oldVal) + operand;
        oldVal_2 = atomic_cmpxchg(sourceAsInt, oldVal, as_int(newVal));
    } while (oldVal_2 != oldVal);
}
#undef LOCAL
#endif

kernel void FUNCTIONNAME(        const          int2                    img_size
                        ,        const unsigned int                     step_
                        , global const unsigned char   * const restrict image
                        ,        const unsigned int                     num_locations
                        , global const          float2 * const restrict location_global     //num_locations elements
#if STATIC_BLOCK_SIZE
                        ,        const          float                   blck_size           //Note: static block size: float
#else
                        , global const          float2 * const restrict blocksize_global    //Note: dynamic block size: float2 array, num_locations elements
#endif
                        , global                float  *       restrict hist_global         //num_locations * NUMBER_OF_CELLS * NUMBER_OF_CELLS * NUMBER_OF_BINS elements
#if defined(USE_LOCAL)
                        ,  local                float  *       restrict hist_local          //get_local_size(2) * NUMBER_OF_CELLS * NUMBER_OF_CELLS * NUMBER_OF_BINS elements
#elif defined(USE_PRIVATE)
                        ,  local                float  *       restrict temp                //get_local_size(2) * get_local_size(0) * get_local_size(1) * VECTOR_SIZE elements
#endif
                        )
{
    //get_global_id(0): x coordinate
    //get_global_id(1): y coordinate
    //get_global_id(2): per location

    const size_t location_global_idx = get_global_id(2);
    hist_global += TOTAL_NUMBER_OF_BINS * location_global_idx;
#if USE_PRIVATE
    float hist_private[TOTAL_NUMBER_OF_BINS] = { 0 };
    #define hist_temp hist_private
#else
#if USE_GLOBAL
    #define hist_temp hist_global
#elif USE_LOCAL
    hist_local += TOTAL_NUMBER_OF_BINS * get_local_id(2);
    #define hist_temp hist_local
#endif

    //Clear hist_temp
    if (location_global_idx < num_locations) {
        const size_t threadId = get_local_id(0) + get_local_size(0) * get_local_id(1);
        const size_t groupSize = get_local_size(0) * get_local_size(1);
        size_t i = threadId * VECTOR_SIZE;
        for(; i < ROUND_DOWN_TO_VECTOR_SIZE(TOTAL_NUMBER_OF_BINS); i += groupSize * VECTOR_SIZE) {
            VSTOREN(0.0f, 0, &hist_temp[i]);
        }
#if (TOTAL_NUMBER_OF_BINS % VECTOR_SIZE > 0)
        for(; i < TOTAL_NUMBER_OF_BINS; i += groupSize) {
            hist_temp[i] = 0.0f;
        }
#endif
    }
#if USE_GLOBAL
    barrier(CLK_GLOBAL_MEM_FENCE);
#elif USE_LOCAL
    barrier(CLK_LOCAL_MEM_FENCE);
#endif
#endif

    if (location_global_idx < num_locations) {
        float2 location = location_global[location_global_idx];
#if !STATIC_BLOCK_SIZE
        float2 blck_size = blocksize_global[location_global_idx];
#endif
        float2 minloc = location - blck_size * 0.5f;
        float2 maxloc = location + blck_size * 0.5f;

        //Not converting to uint before min/max, because without saturation it can underflow, and saturation is expensive (if we could saturate to 1 to img_size-2..)
        uint2 mini = convert_uint2(clamp(convert_int2_rtp(minloc), 1, img_size - 2));
        uint2 maxi = convert_uint2(clamp(convert_int2_rtn(maxloc), 1, img_size - 2));

        for (uint pointy = mini.y + (uint)get_local_id(1); pointy <= maxi.y; pointy += (uint)get_local_size(1)) {
            for (uint pointx = mini.x + (uint)get_local_id(0); pointx <= maxi.x; pointx += (uint)get_local_size(0)) {
                float2 point_f = (float2)(pointx, pointy);
                //Read the image

                uint point_idx = mad24(pointy, step_, pointx);
                uchar3 row_pixels = vload3(0, &image[point_idx-1]);
                uchar  top_pixel  = image[point_idx+step_];
                uchar  bot_pixel  = image[point_idx-step_];

                if (top_pixel == bot_pixel && row_pixels.s2 == row_pixels.s0) continue; //If the pixels have the same value, no contribution. Both faster, and correct ( atan2pi(0,0) is undefined ).

                float mdx = row_pixels.s2 - row_pixels.s0;
                float mdy = top_pixel     - bot_pixel;

                //calculate the magnitude
                float magnitude = hypot(mdx, mdy);

                //calculate the orientation
#if SIGNED_HOG
                float orientation = atan2pi(mdy, mdx) * 0.5f;
#else
                float orientation = atan2pi(mdy, mdx) + 0.5f;
#endif

#if GAUSSIAN_WEIGHTS
                {
                    float2 m1p2sigmaSq = -2.0f / (blck_size * blck_size);
                    float2 distance = point_f - location;
                    float2 distanceSq = distance*distance;
                    magnitude *= exp(dot(distanceSq, m1p2sigmaSq));
                }
#endif
                float relative_orientation = orientation * NUMBER_OF_BINS - 0.5f;

                int   bin0        = convert_int_rtn(relative_orientation);
                float bin_weight1 = relative_orientation - convert_float(bin0);

                int   bin1        = 1    + bin0;
                float bin_weight0 = 1.0f - bin_weight1;

                int2   bin        = ((int2)(bin0, bin1) + NUMBER_OF_BINS) % NUMBER_OF_BINS;
                float2 bin_weight = magnitude * (float2)(bin_weight0, bin_weight1);

#if NUMBER_OF_CELLS == 1
                atomic_add_float( &(hist_temp[bin.s0]), bin_weight.s0);
                atomic_add_float( &(hist_temp[bin.s1]), bin_weight.s1);
#elif SPARTIAL_WEIGHTS
                float2 relative_pos = (point_f - minloc) * NUMBER_OF_CELLS / blck_size - 0.5f;
                int2 celli = convert_int2_rtn(relative_pos);

                const float2 scale1 = relative_pos - convert_float2(celli);
                const float2 scale0 = 1.0f - scale1;
                const float4 scale  = (float4)(scale0, scale1);
                const float4 nearly_scaled_bin_weight = scale.s0022 * bin_weight.s0101;

                if (celli.y >= 0) {
                    const float4 scaled_bin_weight = scale.s1 * nearly_scaled_bin_weight;
                    if (celli.x >= 0) {
                        atomic_add_float( &(hist_temp[BIN_INDEX(celli.y  , celli.x  , bin.s0)]), scaled_bin_weight.s0);
                        atomic_add_float( &(hist_temp[BIN_INDEX(celli.y  , celli.x  , bin.s1)]), scaled_bin_weight.s1);
                    }
                    if (celli.x < NUMBER_OF_CELLS - 1) {
                        atomic_add_float( &(hist_temp[BIN_INDEX(celli.y  , celli.x+1, bin.s0)]), scaled_bin_weight.s2);
                        atomic_add_float( &(hist_temp[BIN_INDEX(celli.y  , celli.x+1, bin.s1)]), scaled_bin_weight.s3);
                    }
                }
                if (celli.y < NUMBER_OF_CELLS - 1) {
                    const float4 scaled_bin_weight = scale.s3 * nearly_scaled_bin_weight;
                    if (celli.x >= 0) {
                        atomic_add_float( &(hist_temp[BIN_INDEX(celli.y+1, celli.x  , bin.s0)]), scaled_bin_weight.s0);
                        atomic_add_float( &(hist_temp[BIN_INDEX(celli.y+1, celli.x  , bin.s1)]), scaled_bin_weight.s1);
                    }
                    if (celli.x < NUMBER_OF_CELLS - 1) {
                        atomic_add_float( &(hist_temp[BIN_INDEX(celli.y+1, celli.x+1, bin.s0)]), scaled_bin_weight.s2);
                        atomic_add_float( &(hist_temp[BIN_INDEX(celli.y+1, celli.x+1, bin.s1)]), scaled_bin_weight.s3);
                    }
                }
#else
                int2 celli = convert_int2_rtn((point_f - minloc) * NUMBER_OF_CELLS / blck_size);

                atomic_add_float( &(hist_temp[BIN_INDEX(celli.y, celli.x, bin.s0)]), bin_weight.s0);
                atomic_add_float( &(hist_temp[BIN_INDEX(celli.y, celli.x, bin.s1)]), bin_weight.s1);
#endif
            }
        }
    }
    #undef hist_temp
#if USE_LOCAL
    barrier(CLK_LOCAL_MEM_FENCE);

    if (location_global_idx < num_locations) {
        //Add local version to global
        const size_t threadId = get_local_id(0) + get_local_size(0) * get_local_id(1);
        const size_t groupSize = get_local_size(0) * get_local_size(1);
        size_t i = threadId * VECTOR_SIZE;
        for(; i < ROUND_DOWN_TO_VECTOR_SIZE(TOTAL_NUMBER_OF_BINS); i += groupSize * VECTOR_SIZE) {
            VSTOREN(VLOADN(0, &hist_local[i]), 0, &hist_global[i]);
        }
#if (TOTAL_NUMBER_OF_BINS % VECTOR_SIZE > 0)
        for(; i < TOTAL_NUMBER_OF_BINS; i += groupSize) {
            hist_global[i] = hist_local[i];
        }
#endif
    }
#elif defined(USE_PRIVATE)
    //Use lock-step reduction and store result to hist_global
    const size_t threadId = get_local_id(0) + get_local_size(0) * get_local_id(1);
    const size_t groupSize = get_local_size(0) * get_local_size(1);
    temp += get_local_id(2) * groupSize * VECTOR_SIZE;

    int i = 0;
    for(; i < ROUND_DOWN_TO_VECTOR_SIZE(TOTAL_NUMBER_OF_BINS); i += VECTOR_SIZE) {
        barrier(CLK_LOCAL_MEM_FENCE);
        FLOATN value = WG_REDUCEN(VLOADN(0, &hist_private[i]), (local FLOATN *)temp, threadId, groupSize);
        if (0 == threadId && location_global_idx < num_locations) {
            VSTOREN(value, 0, &hist_global[i]);
        }
    }
#if (TOTAL_NUMBER_OF_BINS % VECTOR_SIZE > 0)
    for(; i < TOTAL_NUMBER_OF_BINS; ++i) {
        barrier(CLK_LOCAL_MEM_FENCE);
        float value = wg_reduce(hist_private[i], temp, threadId, groupSize);
        if (0 == threadId && location_global_idx < num_locations) {
            hist_global[i] = value;
        }
    }
#endif
#endif
}


r1795: *** empty log message ***

r1795: *** empty log message ***

;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          tester-clsql.cl
;;;; Purpose:       Automated test of CLSQL using ACL's tester
;;;; Programmer:    Kevin M. Rosenberg
;;;; Date Started:  Mar 2002
;;;;
;;;; $Id: tester-clsql.cl,v 1.7 2002/04/24 16:10:55 kevin Exp $
;;;;
;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
;;;;
;;;; CLSQL users are granted the rights to distribute and use this software
;;;; as governed by the terms of the Lisp Lesser GNU Public License
;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
;;;; *************************************************************************

;;; This test suite looks for a configuration file named "test.config"
;;; This file contains a single a-list that specifies the connection
;;; specs for each database type to be tested. For example, to test all
;;; platforms, a sample "test.config" may look like:
;;;
;;; ((:mysql ("localhost" "a-mysql-db" "user1" "secret"))
;;;  (:aodbc ("my-dsn" "a-user" "pass"))
;;;  (:postgresql ("localhost" "another-db" "user2" "dont-tell"))
;;;  (:postgresql-socket ("pg-server" "a-db-name" "user" "secret-password")))

(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0)))
(in-package :cl-user)

(unless (find-package :util.test)
  (load (make-pathname :name "acl-compat-tester" :type "cl"
		       :defaults *load-truename*)))

(in-package :clsql-user)
(use-package :util.test)

(defvar *config-pathname* (make-pathname :name "test"
					 :type "config"
					 :defaults *load-truename*))

(defclass conn-specs ()
  ((aodbc-spec :accessor aodbc-spec)
   (mysql-spec :accessor mysql-spec)
   (pgsql-spec :accessor pgsql-spec)
   (pgsql-socket-spec :accessor pgsql-socket-spec))
  (:documentation "Test fixture for CLSQL testing"))

(defun read-specs (&optional (path *config-pathname*))
  (if (probe-file path)
      (with-open-file (stream path :direction :input)
	(let ((config (read stream))
	      (specs (make-instance 'conn-specs)))
	  (setf (aodbc-spec specs) (cadr (assoc :aodbc config)))
	  (setf (mysql-spec specs) (cadr (assoc :mysql config)))
	  (setf (pgsql-spec specs) (cadr (assoc :postgresql config)))
	  (setf (pgsql-socket-spec specs)
		(cadr (assoc :postgresql-socket config)))
	  specs))
      (error "CLSQL tester config file ~S not found" path)))

(defmethod mysql-table-test ((test conn-specs))
  (test-table (mysql-spec test) :mysql))

(defmethod aodbc-table-test ((test conn-specs))
  (test-table (aodbc-spec test) :aodbc))

(defmethod pgsql-table-test ((test conn-specs))
  (test-table (pgsql-spec test) :postgresql))

(defmethod pgsql-socket-table-test ((test conn-specs))
  (test-table (pgsql-socket-spec test) :postgresql-socket))

(defmethod test-table (spec type)
  (when spec
    (let ((db (clsql:connect spec :database-type type :if-exists :new)))
      (unwind-protect
	   (progn
	     (create-test-table db)
	     (dolist (row (query "select * from test_clsql" :database db :types :auto))
	       (test-table-row row :auto type))
	     (dolist (row (query "select * from test_clsql" :database db :types nil))
	       (test-table-row row nil type))
	     (loop for row across (map-query 'vector #'list "select * from test_clsql"
					     :database db :types :auto)
		   do (test-table-row row :auto type))
	     (loop for row across (map-query 'vector #'list "select * from test_clsql"
					     :database db :types nil)
		   do (test-table-row row nil type))
	     (loop for row in (map-query 'list #'list "select * from test_clsql"
					 :database db :types nil)
		   do (test-table-row row nil type))
	     (loop for row in (map-query 'list #'list "select * from test_clsql"
					 :database db :types :auto)
		 do (test-table-row row :auto type))
	     (test (map-query nil #'list "select * from test_clsql"
			      :database db :types :auto)
		   nil
		   :fail-info "Expected NIL result from map-query nil")
	     (do-query ((int float bigint str) "select * from test_clsql")
	       (test-table-row (list int float bigint str) nil type))
	     (do-query ((int float bigint str) "select * from test_clsql" :types :auto)
	       (test-table-row (list int float bigint str) :auto type))
	     (drop-test-table db)
	     )
	(disconnect :database db)))))

(defmethod mysql-low-level ((test conn-specs))
  (let ((spec (mysql-spec test)))
    (when spec
      (let ((db (clsql-mysql::database-connect spec :mysql)))
	(clsql-mysql::database-execute-command "DROP TABLE IF EXISTS test_clsql" db)
	(clsql-mysql::database-execute-command
	 "CREATE TABLE test_clsql (i integer, sqrt double, sqrt_str CHAR(20))" db)
	(dotimes (i 10)
	  (clsql-mysql::database-execute-command
	   (format nil "INSERT INTO test_clsql VALUES (~d,~d,'~a')"
		   i (number-to-sql-string (sqrt i))
		   (number-to-sql-string (sqrt i)))
	   db))
	(let ((res (clsql-mysql::database-query-result-set "select * from test_clsql" db :full-set t :types nil)))
	  (test (mysql:mysql-num-rows
		 (clsql-mysql::mysql-result-set-res-ptr res))
		10
		:test #'eql
		:fail-info "Error calling mysql-num-rows")
	  (clsql-mysql::database-dump-result-set res db))
	(clsql-mysql::database-execute-command "DROP TABLE test_clsql" db)
	(clsql-mysql::database-disconnect db)))))

;;;; Testing functions

(defun transform-float-1 (i)
  (coerce (* i (abs (/ i 2)) (expt 10 (* 2 i))) 'double-float))

(defun transform-bigint-1 (i)
  (* i (expt 10 (* 3 (abs i)))))

(defun create-test-table (db)
  (ignore-errors
    (clsql:execute-command
     "DROP TABLE test_clsql" :database db))
  (clsql:execute-command
   "CREATE TABLE test_clsql (t_int integer, t_float float, t_bigint BIGINT, t_str CHAR(30))"
   :database db)
  (dotimes (i 11)
    (let* ((test-int (- i 5))
	   (test-flt (transform-float-1 test-int)))
      (clsql:execute-command
       (format nil "INSERT INTO test_clsql VALUES (~a,~a,~a,'~a')"
	       test-int
	       (number-to-sql-string test-flt)
	       (transform-bigint-1 test-int)
	       (number-to-sql-string test-flt)
	       )
       :database db))))

(defun parse-double (num-str)
  (let ((*read-default-float-format* 'double-float))
    (coerce (read-from-string num-str) 'double-float)))

(defun test-table-row (row types db-type)
  (test (and (listp row)
	     (= 4 (length row)))
	t
	:fail-info
	(format nil "Row ~S is incorrect format" row))
  (destructuring-bind (int float bigint str) row
    (cond
      ((eq types :auto)
       (test (and (integerp int)
		  (typep float 'double-float)
		  (or (eq db-type :aodbc) ;; aodbc doesn't handle bigint conversions
		      (integerp bigint))
		  (stringp str))
	     t
	     :fail-info
	     (format nil "Incorrect field type for row ~S (types :auto)" row)))
       ((null types)
	(test (and (stringp int)
		     (stringp float)
		     (stringp bigint)
		     (stringp str))
	      t
	      :fail-info
	      (format nil "Incorrect field type for row ~S (types nil)" row))
	(setq int (parse-integer int))
	(setq bigint (parse-integer bigint))
	(setq float (parse-double float)))
       ((listp types)
	(error "NYI")
	)
       (t
	(test t nil
	      :fail-info
	      (format nil "Invalid types field (~S) passed to test-table-row" types))))
    (test (transform-float-1 int)
	  float
	  :test #'eql
	  :fail-info
	  (format nil "Wrong float value ~A for int ~A (row ~S)" float int row))
    (test float
	  (parse-double str)
	  :test #'double-float-equal
	  :fail-info (format nil "Wrong string value ~A for double ~A~%Row: ~S"
			     str float row))))

(defun double-float-equal (a b)
  (if (zerop a)
      (if (zerop b)
	  t
	  nil)
      (let ((diff (abs (/ (- a b) a))))
	(if (> diff (* 10 double-float-epsilon))
	    nil
	    t))))

(defun drop-test-table (db)
  (clsql:execute-command "DROP TABLE test_clsql"))

(defun do-test ()
    (let ((specs (read-specs)))
      (with-tests (:name "CLSQL")
	(mysql-low-level specs)
	(mysql-table-test specs)
	(pgsql-table-test specs)
	(pgsql-socket-table-test specs)
	(aodbc-table-test specs)
      )))

(do-test)

;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          tester-clsql.cl
;;;; Purpose:       Automated test of CLSQL using ACL's tester
;;;; Programmer:    Kevin M. Rosenberg
;;;; Date Started:  Mar 2002
;;;;
;;;; $Id: tester-clsql.cl,v 1.6 2002/04/23 18:28:02 kevin Exp $
;;;;
;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg
;;;;
;;;; CLSQL users are granted the rights to distribute and use this software
;;;; as governed by the terms of the Lisp Lesser GNU Public License
;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
;;;; *************************************************************************

;;; This test suite looks for a configuration file named "test.config"
;;; This file contains a single a-list that specifies the connection
;;; specs for each database type to be tested. For example, to test all
;;; platforms, a sample "test.config" may look like:
;;;
;;; ((:mysql ("localhost" "a-mysql-db" "user1" "secret"))
;;;  (:aodbc ("my-dsn" "a-user" "pass"))
;;;  (:postgresql ("localhost" "another-db" "user2" "dont-tell"))
;;;  (:postgresql-socket ("pg-server" "a-db-name" "user" "secret-password")))

(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0)))
(in-package :cl-user)

(unless (find-package :util.test)
  (load (make-pathname :name "acl-compat-tester" :type "cl"
		       :defaults *load-truename*)))

(in-package :clsql-user)
(use-package :util.test)

(defvar *config-pathname* (make-pathname :name "test"
					 :type "config"
					 :defaults *load-truename*))

(defclass conn-specs ()
  ((aodbc-spec :accessor aodbc-spec)
   (mysql-spec :accessor mysql-spec)
   (pgsql-spec :accessor pgsql-spec)
   (pgsql-socket-spec :accessor pgsql-socket-spec))
  (:documentation "Test fixture for CLSQL testing"))

(defun read-specs (&optional (path *config-pathname*))
  (if (probe-file path)
      (with-open-file (stream path :direction :input)
	(let ((config (read stream))
	      (specs (make-instance 'conn-specs)))
	  (setf (aodbc-spec specs) (cadr (assoc :aodbc config)))
	  (setf (mysql-spec specs) (cadr (assoc :mysql config)))
	  (setf (pgsql-spec specs) (cadr (assoc :postgresql config)))
	  (setf (pgsql-socket-spec specs)
		(cadr (assoc :postgresql-socket config)))
	  specs))
      (error "CLSQL tester config file ~S not found" path)))

(defmethod mysql-table-test ((test conn-specs))
  (test-table (mysql-spec test) :mysql))

(defmethod aodbc-table-test ((test conn-specs))
  (test-table (aodbc-spec test) :aodbc))

(defmethod pgsql-table-test ((test conn-specs))
  (test-table (pgsql-spec test) :postgresql))

(defmethod pgsql-socket-table-test ((test conn-specs))
  (test-table (pgsql-socket-spec test) :postgresql-socket))

(defmethod test-table (spec type)
  (when spec
    (let ((db (clsql:connect spec :database-type type :if-exists :new)))
      (unwind-protect
	   (progn
	     (create-test-table db)
	     (dolist (row (query "select * from test_clsql" :database db :types :auto))
	       (test-table-row row :auto type))
	     (dolist (row (query "select * from test_clsql" :database db :types nil))
	       (test-table-row row nil type))
	     (loop for row across (map-query 'vector #'list "select * from test_clsql"
					     :database db :types :auto)
		   do (test-table-row row :auto type))
	     (loop for row across (map-query 'vector #'list "select * from test_clsql"
					     :database db :types nil)
		   do (test-table-row row nil type))
	     (loop for row in (map-query 'list #'list "select * from test_clsql"
					 :database db :types nil)
		   do (test-table-row row nil type))
	     (loop for row in (map-query 'list #'list "select * from test_clsql"
					 :database db :types :auto)
		 do (test-table-row row :auto type))
	     (test (map-query nil #'list "select * from test_clsql"
			      :database db :types :auto)
		   nil
		   :fail-info "Expected NIL result from map-query nil")
	     (do-query ((int float bigint str) "select * from test_clsql")
	       (test-table-row (list int float bigint str) nil type))
	     (do-query ((int float bigint str) "select * from test_clsql" :types :auto)
	       (test-table-row (list int float bigint str) :auto type))
	     (drop-test-table db)
	     )
	(disconnect :database db)))))

(defmethod mysql-low-level ((test conn-specs))
  (let ((spec (mysql-spec test)))
    (when spec
      (let ((db (clsql-mysql::database-connect spec :mysql)))
	(clsql-mysql::database-execute-command "DROP TABLE IF EXISTS test_clsql" db)
	(clsql-mysql::database-execute-command
	 "CREATE TABLE test_clsql (i integer, sqrt double, sqrt_str CHAR(20))" db)
	(dotimes (i 10)
	  (clsql-mysql::database-execute-command
	   (format nil "INSERT INTO test_clsql VALUES (~d,~d,'~a')"
		   i (number-to-sql-string (sqrt i))
		   (number-to-sql-string (sqrt i)))
	   db))
	(let ((res (clsql-mysql::database-query-result-set "select * from test_clsql" db :full-set t :types nil)))
	  (test (mysql:mysql-num-rows
		 (clsql-mysql::mysql-result-set-res-ptr res))
		10
		:test #'eql
		:fail-info "Error calling mysql-num-rows")
	  (clsql-mysql::database-dump-result-set res db))
	(clsql-mysql::database-execute-command "DROP TABLE test_clsql" db)
	(clsql-mysql::database-disconnect db)))))

;;;; Testing functions

(defun transform-float-1 (i)
  (coerce (* i (abs (/ i 2)) (expt 10 (* 2 i))) 'double-float))

(defun transform-bigint-1 (i)
  (* i (expt 10 (* 3 (abs i)))))

(defun create-test-table (db)
  (ignore-errors
    (clsql:execute-command
     "DROP TABLE test_clsql" :database db))
  (clsql:execute-command
   "CREATE TABLE test_clsql (t_int integer, t_float float, t_bigint BIGINT, t_str CHAR(30))"
   :database db)
  (dotimes (i 11)
    (let* ((test-int (- i 5))
	   (test-flt (transform-float-1 test-int)))
      (clsql:execute-command
       (format nil "INSERT INTO test_clsql VALUES (~a,~a,~a,'~a')"
	       test-int
	       (number-to-sql-string test-flt)
	       (transform-bigint-1 test-int)
	       (number-to-sql-string test-flt)
	       )
       :database db))))

(defun parse-double (num-str)
  (let ((*read-default-float-format* 'double-float))
    (coerce (read-from-string num-str) 'double-float)))

(defun test-table-row (row types db-type)
  (test (and (listp row)
	     (= 4 (length row)))
	t
	:fail-info
	(format nil "Row ~S is incorrect format" row))
  (destructuring-bind (int float bigint str) row
    (cond
      ((eq types :auto)
       (test (and (integerp int)
		  (typep float 'double-float)
		  (or (eq db-type :aodbc) ;; aodbc doesn't handle bigint conversions
		      (integerp bigint))
		  (stringp str))
	     t
	     :fail-info
	     (format nil "Incorrect field type for row ~S (types :auto)" row)))
       ((null types)
	(test (and (stringp int)
		     (stringp float)
		     (stringp bigint)
		     (stringp str))
	      t
	      :fail-info
	      (format nil "Incorrect field type for row ~S (types nil)" row))
	(setq int (parse-integer int))
	(setq bigint (parse-integer bigint))
	(setq float (parse-double float)))
       ((listp types)
	(error "NYI")
	)
       (t
	(test t nil
	      :fail-info
	      (format nil "Invalid types field (~S) passed to test-table-row" types))))
    (test (transform-float-1 int)
	  float
	  :test #'eql
	  :fail-info
	  (format nil "Wrong float value ~A for int ~A (row ~S)" float int row))
    (test (parse-double str)
	  float
	  :test #'eql
	  :fail-info (format nil "Wrong string value ~A for double ~A (row ~S)"
			     float str row))))

(defun drop-test-table (db)
  (clsql:execute-command "DROP TABLE test_clsql"))

(defun do-test ()
    (let ((specs (read-specs)))
      (with-tests (:name "CLSQL")
	(mysql-low-level specs)
	(mysql-table-test specs)
	(pgsql-table-test specs)
	(pgsql-socket-table-test specs)
	(aodbc-table-test specs)
      )))

(do-test)