Fix opencl test broken on windows by r350643.

Windows doesn't allow common with alignment >32 bits, so these tests
were broken in windows mode.  This patch makes 'common' optional in
these cases.

Change-Id: I4d5fdd07ecdafc3570ef9b09cd816c2e5e4ed15e

git-svn-id: ffe668792ed300d6c2daa1f6eba2e0aa28d7ec6c@350645 91177308-0d34-0410-b5e6-96231b3b80d8

// RUN: %clang_cc1 %s -O0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,SPIR
// RUN: %clang_cc1 %s -O0 -DCL20 -cl-std=CL2.0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20SPIR
// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s
// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -DCL20 -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20AMDGCN
// RUN: %clang_cc1 %s -O0 -triple amdgcn-mesa-mesa3d -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s
// RUN: %clang_cc1 %s -O0 -triple r600-- -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s

// SPIR: %struct.S = type { i32, i32, i32* }
// CL20SPIR: %struct.S = type { i32, i32, i32 addrspace(4)* }
struct S {
  int x;
  int y;
  int *z;
};

// CL20-DAG: @g_extern_var = external {{(dso_local )?}}addrspace(1) global float
// CL20-DAG: @l_extern_var = external {{(dso_local )?}}addrspace(1) global float
// CL20-DAG: @test_static.l_static_var = internal addrspace(1) global float 0.000000e+00
// CL20-DAG: @g_static_var = internal addrspace(1) global float 0.000000e+00

#ifdef CL20
// CL20-DAG: @g_s = {{(common )?}}{{(dso_local )?}}addrspace(1) global %struct.S zeroinitializer
struct S g_s;
#endif

// SPIR: i32* %arg
// AMDGCN: i32 addrspace(5)* %arg
void f__p(__private int *arg) {}

// CHECK: i32 addrspace(1)* %arg
void f__g(__global int *arg) {}

// CHECK: i32 addrspace(3)* %arg
void f__l(__local int *arg) {}

// SPIR: i32 addrspace(2)* %arg
// AMDGCN: i32 addrspace(4)* %arg
void f__c(__constant int *arg) {}

// SPIR: i32* %arg
// AMDGCN: i32 addrspace(5)* %arg
void fp(private int *arg) {}

// CHECK: i32 addrspace(1)* %arg
void fg(global int *arg) {}

// CHECK: i32 addrspace(3)* %arg
void fl(local int *arg) {}

// SPIR: i32 addrspace(2)* %arg
// AMDGCN: i32 addrspace(4)* %arg
void fc(constant int *arg) {}

#ifdef CL20
int i;
// CL20-DAG: @i = common {{(dso_local )?}}addrspace(1) global i32 0
int *ptr;
// CL20SPIR-DAG: @ptr = {{(common )?}}{{(dso_local )?}}addrspace(1) global i32 addrspace(4)* null
// CL20AMDGCN-DAG: @ptr = common {{(dso_local )?}}addrspace(1) global i32* null
#endif

// SPIR: i32* %arg
// AMDGCN: i32 addrspace(5)* %arg
// CL20SPIR-DAG: i32 addrspace(4)* %arg
// CL20AMDGCN-DAG: i32* %arg
void f(int *arg) {

  int i;
// SPIR: %i = alloca i32,
// AMDGCN: %i = alloca i32{{.*}}addrspace(5)
// CL20SPIR-DAG: %i = alloca i32,
// CL20AMDGCN-DAG: %i = alloca i32{{.*}}addrspace(5)

#ifdef CL20
  static int ii;
// CL20-DAG: @f.ii = internal addrspace(1) global i32 0
#endif
}

typedef int int_td;
typedef int *intp_td;
// SPIR: define {{(dso_local )?}}void @test_typedef(i32 addrspace(1)* %x, i32 addrspace(2)* %y, i32* %z)
void test_typedef(global int_td *x, constant int_td *y, intp_td z) {
  *x = *y;
  *z = 0;
}

// SPIR: define {{(dso_local )?}}void @test_struct()
void test_struct() {
  // SPIR: %ps = alloca %struct.S*
  // CL20SPIR: %ps = alloca %struct.S addrspace(4)*
  struct S *ps;
  // SPIR: store i32 0, i32* %x
  // CL20SPIR: store i32 0, i32 addrspace(4)* %x
  ps->x = 0;
#ifdef CL20
  // CL20SPIR: store i32 0, i32 addrspace(1)* getelementptr inbounds (%struct.S, %struct.S addrspace(1)* @g_s, i32 0, i32 0)
  g_s.x = 0;
#endif
}

// SPIR-LABEL: define {{(dso_local )?}}void @test_void_par()
void test_void_par(void) {}

// On ppc64 returns signext i32.
// SPIR-LABEL: define{{.*}} i32 @test_func_return_type()
int test_func_return_type(void) {
  return 0;
}

#ifdef CL20
extern float g_extern_var;

// CL20-LABEL: define {{.*}}void @test_extern(
kernel void test_extern(global float *buf) {
  extern float l_extern_var;
  buf[0] += g_extern_var + l_extern_var;
}

static float g_static_var;

// CL20-LABEL: define {{.*}}void @test_static(
kernel void test_static(global float *buf) {
  static float l_static_var;
  buf[0] += g_static_var + l_static_var;
}

#endif

// RUN: %clang_cc1 %s -O0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,SPIR
// RUN: %clang_cc1 %s -O0 -DCL20 -cl-std=CL2.0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20SPIR
// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s
// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -DCL20 -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20AMDGCN
// RUN: %clang_cc1 %s -O0 -triple amdgcn-mesa-mesa3d -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s
// RUN: %clang_cc1 %s -O0 -triple r600-- -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s

// SPIR: %struct.S = type { i32, i32, i32* }
// CL20SPIR: %struct.S = type { i32, i32, i32 addrspace(4)* }
struct S {
  int x;
  int y;
  int *z;
};

// CL20-DAG: @g_extern_var = external {{(dso_local )?}}addrspace(1) global float
// CL20-DAG: @l_extern_var = external {{(dso_local )?}}addrspace(1) global float
// CL20-DAG: @test_static.l_static_var = internal addrspace(1) global float 0.000000e+00
// CL20-DAG: @g_static_var = internal addrspace(1) global float 0.000000e+00

#ifdef CL20
// CL20-DAG: @g_s = common {{(dso_local )?}}addrspace(1) global %struct.S zeroinitializer
struct S g_s;
#endif

// SPIR: i32* %arg
// AMDGCN: i32 addrspace(5)* %arg
void f__p(__private int *arg) {}

// CHECK: i32 addrspace(1)* %arg
void f__g(__global int *arg) {}

// CHECK: i32 addrspace(3)* %arg
void f__l(__local int *arg) {}

// SPIR: i32 addrspace(2)* %arg
// AMDGCN: i32 addrspace(4)* %arg
void f__c(__constant int *arg) {}

// SPIR: i32* %arg
// AMDGCN: i32 addrspace(5)* %arg
void fp(private int *arg) {}

// CHECK: i32 addrspace(1)* %arg
void fg(global int *arg) {}

// CHECK: i32 addrspace(3)* %arg
void fl(local int *arg) {}

// SPIR: i32 addrspace(2)* %arg
// AMDGCN: i32 addrspace(4)* %arg
void fc(constant int *arg) {}

#ifdef CL20
int i;
// CL20-DAG: @i = common {{(dso_local )?}}addrspace(1) global i32 0
int *ptr;
// CL20SPIR-DAG: @ptr = common {{(dso_local )?}}addrspace(1) global i32 addrspace(4)* null
// CL20AMDGCN-DAG: @ptr = common {{(dso_local )?}}addrspace(1) global i32* null
#endif

// SPIR: i32* %arg
// AMDGCN: i32 addrspace(5)* %arg
// CL20SPIR-DAG: i32 addrspace(4)* %arg
// CL20AMDGCN-DAG: i32* %arg
void f(int *arg) {

  int i;
// SPIR: %i = alloca i32,
// AMDGCN: %i = alloca i32{{.*}}addrspace(5)
// CL20SPIR-DAG: %i = alloca i32,
// CL20AMDGCN-DAG: %i = alloca i32{{.*}}addrspace(5)

#ifdef CL20
  static int ii;
// CL20-DAG: @f.ii = internal addrspace(1) global i32 0
#endif
}

typedef int int_td;
typedef int *intp_td;
// SPIR: define {{(dso_local )?}}void @test_typedef(i32 addrspace(1)* %x, i32 addrspace(2)* %y, i32* %z)
void test_typedef(global int_td *x, constant int_td *y, intp_td z) {
  *x = *y;
  *z = 0;
}

// SPIR: define {{(dso_local )?}}void @test_struct()
void test_struct() {
  // SPIR: %ps = alloca %struct.S*
  // CL20SPIR: %ps = alloca %struct.S addrspace(4)*
  struct S *ps;
  // SPIR: store i32 0, i32* %x
  // CL20SPIR: store i32 0, i32 addrspace(4)* %x
  ps->x = 0;
#ifdef CL20
  // CL20SPIR: store i32 0, i32 addrspace(1)* getelementptr inbounds (%struct.S, %struct.S addrspace(1)* @g_s, i32 0, i32 0)
  g_s.x = 0;
#endif
}

// SPIR-LABEL: define {{(dso_local )?}}void @test_void_par()
void test_void_par(void) {}

// On ppc64 returns signext i32.
// SPIR-LABEL: define{{.*}} i32 @test_func_return_type()
int test_func_return_type(void) {
  return 0;
}

#ifdef CL20
extern float g_extern_var;

// CL20-LABEL: define {{.*}}void @test_extern(
kernel void test_extern(global float *buf) {
  extern float l_extern_var;
  buf[0] += g_extern_var + l_extern_var;
}

static float g_static_var;

// CL20-LABEL: define {{.*}}void @test_static(
kernel void test_static(global float *buf) {
  static float l_static_var;
  buf[0] += g_static_var + l_static_var;
}

#endif


Update test without inbuilt `readFile` and `writeFile` methods

- Prepare for complete removal of the methods from core

include node-core

fs = require 'fs'

main = do
  err data <- IO (fs.readFile process.argv[2] 'utf8')
  maybeErr err (putLine err)
  err1 <- IO (fs.writeFile process.argv[3] data)
  maybeErr err1 (putLine err1)

include node-core
main = do
  data <- readFile process.argv[2]
  writeFile process.argv[3] data


lib/kernel/atomics.cl: fix atomic_xchg(float*, float)

the original code wasn't casting the return value of atomic_exchange_n()
(which was int) to float, therefore float->int conversion happened,
returning nonsense.

This adds result conversion and slighty simplifies the code
by using atomic_xchg(int*, int).

/* OpenCL built-in library: atomic operations

   Copyright (c) 2012 Universidad Rey Juan Carlos

   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.
*/

// Repeat the content of this file several times with different values
// for Q, T, and U:
#if !defined(Q)

#  define Q __global
#  include "atomics.cl"
#  undef Q

#  define Q __local
#  include "atomics.cl"
#  undef Q

#elif !defined(T)

#  define T int
#  define MIN __sync_fetch_and_min
#  define MAX __sync_fetch_and_max
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

#  define T uint
#  define MIN __sync_fetch_and_umin
#  define MAX __sync_fetch_and_umax
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

#ifdef cl_khr_int64
#  define T long
#  define MIN(a,b) (__builtin_trap(), 0L)
#  define MAX(a,b) (__builtin_trap(), 0L)
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

#  define T ulong
#  define MIN(a,b) (__builtin_trap(), 0UL)
#  define MAX(a,b) (__builtin_trap(), 0UL)
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX
#endif

// NOTE: Here and below we convert between an address-space qualified
// pointer and a regular pointer. To avoid internal errors in LLVM, we
// need to transform this via an intermediate int, since LLVM refuses
// to cast between different address spaces.

// On CPUs, we use -ffake-address-space-map to artifically introduce
// address spaces. They do not exist in the hardware. Thus, the
// bitwise casting between different address spaces is correct.

// On other devices this may not be correct. To handle this case
// correctly, LLVM would need to provide atomic builtins for different
// address spaces. These do not exist yet, so bitwise casting is our
// best hope anyway.

// xchg is also supported for float as a special case
__attribute__((overloadable))
float atomic_xchg(volatile Q float *p, float val)
{
  int retval = atomic_xchg ((volatile Q int *)p, as_int(val));
  return as_float(retval);
}

#else

// basic

// read, add, store
__attribute__((overloadable))
T atomic_add(volatile Q T *p, T val)
{
  return __sync_fetch_and_add(p, val, __ATOMIC_RELAXED);
}

// read, subtract, store
__attribute__((overloadable))
T atomic_sub(volatile Q T *p, T val)
{
  return __sync_fetch_and_sub(p, val, __ATOMIC_RELAXED);
}

// read, swap, store
__attribute__((overloadable))
T atomic_xchg(volatile Q T *p, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return __atomic_exchange_n(u2.p, val, __ATOMIC_RELAXED);
}

// read, increment, store
__attribute__((overloadable))
T atomic_inc(volatile Q T *p)
{
  return atomic_add(p, (T)1);
}

// read, decrement, store
__attribute__((overloadable))
T atomic_dec(volatile Q T *p)
{
  return atomic_sub(p, (T)1);
}

// read, store
__attribute__((overloadable))
T atomic_cmpxchg(volatile Q T *p, T cmp, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  __atomic_compare_exchange_n(u2.p, &cmp, val, false,
                              __ATOMIC_RELAXED, __ATOMIC_RELAXED);
  return cmp;
}

// extended

__attribute__((overloadable))
T atomic_min(volatile Q T *p, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return MIN(u2.p, val);
}

__attribute__((overloadable))
T atomic_max(volatile Q T *p, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return MAX(u2.p, val);
}

__attribute__((overloadable))
T atomic_and(volatile Q T *p, T val)
{
  return __sync_fetch_and_and(p, val, __ATOMIC_RELAXED);
}

__attribute__((overloadable))
T atomic_or(volatile Q T *p, T val)
{
  return __sync_fetch_and_or(p, val, __ATOMIC_RELAXED);
}

__attribute__((overloadable))
T atomic_xor(volatile Q T *p, T val)
{
  return __sync_fetch_and_xor(p, val, __ATOMIC_RELAXED);
}

#endif

/* OpenCL built-in library: atomic operations

   Copyright (c) 2012 Universidad Rey Juan Carlos

   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.
*/

// Repeat the content of this file several times with different values
// for Q, T, and U:
#if !defined(Q)

#  define Q __global
#  include "atomics.cl"
#  undef Q

#  define Q __local
#  include "atomics.cl"
#  undef Q

#elif !defined(T)

#  define T int
#  define MIN __sync_fetch_and_min
#  define MAX __sync_fetch_and_max
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

#  define T uint
#  define MIN __sync_fetch_and_umin
#  define MAX __sync_fetch_and_umax
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

#ifdef cl_khr_int64
#  define T long
#  define MIN(a,b) (__builtin_trap(), 0L)
#  define MAX(a,b) (__builtin_trap(), 0L)
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX

#  define T ulong
#  define MIN(a,b) (__builtin_trap(), 0UL)
#  define MAX(a,b) (__builtin_trap(), 0UL)
#  include "atomics.cl"
#  undef T
#  undef MIN
#  undef MAX
#endif

// NOTE: Here and below we convert between an address-space qualified
// pointer and a regular pointer. To avoid internal errors in LLVM, we
// need to transform this via an intermediate int, since LLVM refuses
// to cast between different address spaces.

// On CPUs, we use -ffake-address-space-map to artifically introduce
// address spaces. They do not exist in the hardware. Thus, the
// bitwise casting between different address spaces is correct.

// On other devices this may not be correct. To handle this case
// correctly, LLVM would need to provide atomic builtins for different
// address spaces. These do not exist yet, so bitwise casting is our
// best hope anyway.

// xchg is also supported for float as a special case
__attribute__((overloadable))
float atomic_xchg(volatile Q float *p, float val)
{
  // NOTE: We compare the float as int here...
  union { volatile Q float *p; intptr_t i; } u1;
  union { intptr_t i; volatile int *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return __atomic_exchange_n(u2.p, val, __ATOMIC_RELAXED);
}

#else

// basic

// read, add, store
__attribute__((overloadable))
T atomic_add(volatile Q T *p, T val)
{
  return __sync_fetch_and_add(p, val, __ATOMIC_RELAXED);
}

// read, subtract, store
__attribute__((overloadable))
T atomic_sub(volatile Q T *p, T val)
{
  return __sync_fetch_and_sub(p, val, __ATOMIC_RELAXED);
}

// read, swap, store
__attribute__((overloadable))
T atomic_xchg(volatile Q T *p, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return __atomic_exchange_n(u2.p, val, __ATOMIC_RELAXED);
}

// read, increment, store
__attribute__((overloadable))
T atomic_inc(volatile Q T *p)
{
  return atomic_add(p, (T)1);
}

// read, decrement, store
__attribute__((overloadable))
T atomic_dec(volatile Q T *p)
{
  return atomic_sub(p, (T)1);
}

// read, store
__attribute__((overloadable))
T atomic_cmpxchg(volatile Q T *p, T cmp, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  __atomic_compare_exchange_n(u2.p, &cmp, val, false,
                              __ATOMIC_RELAXED, __ATOMIC_RELAXED);
  return cmp;
}

// extended

__attribute__((overloadable))
T atomic_min(volatile Q T *p, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return MIN(u2.p, val);
}

__attribute__((overloadable))
T atomic_max(volatile Q T *p, T val)
{
  union { volatile Q T *p; intptr_t i; } u1;
  union { intptr_t i; volatile T *p; } u2;
  u1.p = p;
  u2.i = u1.i;
  return MAX(u2.p, val);
}

__attribute__((overloadable))
T atomic_and(volatile Q T *p, T val)
{
  return __sync_fetch_and_and(p, val, __ATOMIC_RELAXED);
}

__attribute__((overloadable))
T atomic_or(volatile Q T *p, T val)
{
  return __sync_fetch_and_or(p, val, __ATOMIC_RELAXED);
}

__attribute__((overloadable))
T atomic_xor(volatile Q T *p, T val)
{
  return __sync_fetch_and_xor(p, val, __ATOMIC_RELAXED);
}

#endif


fixed bug in forward-backward tracking for NCCand set movement to 0 if it is above the search size

__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;

float getPixelAsFloat(__read_only image2d_t image, int2 pos) {
    float value;
    int dataType = get_image_channel_data_type(image);
    if(dataType == CLK_FLOAT) {
        value = read_imagef(image, sampler, pos).x;
    } else if(dataType == CLK_UNSIGNED_INT8 || dataType == CLK_UNSIGNED_INT16) {
        value = read_imageui(image, sampler, pos).x;
    } else {
        value = read_imagei(image, sampler, pos).x;
    }
    return value;
}

float calculateMeanIntensity(__read_only image2d_t frame, int2 pos) {
    float mean = 0.0f;
    for(int y = pos.y - BLOCK_SIZE; y <= pos.y + BLOCK_SIZE; ++y) {
        for(int x = pos.x - BLOCK_SIZE; x <= pos.x + BLOCK_SIZE; ++x) {
            mean += getPixelAsFloat(frame, (int2)(x,y));
        }
    }

    return mean/((BLOCK_SIZE*2+1)*(BLOCK_SIZE*2+1));
}

inline float2 findSubpixelMovement(const float2 movement, const float b[GRID_SIZE][GRID_SIZE]) {
    const int index_x = (int)movement.x + SEARCH_SIZE+1;
    const int index_y = (int)movement.y + SEARCH_SIZE+1;
    // Subpixel parabolic fitting
    const float A =
            (b[index_x-1][index_y-1] - 2 * b[index_x][index_y-1] + b[index_x+1][index_y-1] + b[index_x-1][index_y] - 2 * b[index_x][index_y] + b[index_x+1][index_y] + b[index_x-1][index_y+1] - 2 * b[index_x][index_y+1] +
             b[index_x+1][index_y+1]) / 6.0;
    const float B = (b[index_x-1][index_y-1] - b[index_x+1][index_y-1] - b[index_x-1][index_y+1] + b[index_x+1][index_y+1]) / 4.0;
    const float C =
            (b[index_x-1][index_y-1] + b[index_x][index_y-1] + b[index_x+1][index_y-1] - 2 * b[index_x-1][index_y] - 2 * b[index_x][index_y] - 2 * b[index_x+1][index_y] + b[index_x-1][index_y+1] + b[index_x][index_y+1] +
             b[index_x+1][index_y+1]) / 6.0;
    const float D = (-b[index_x-1][index_y-1] + b[index_x+1][index_y-1] - b[index_x-1][index_y] + b[index_x+1][index_y] - b[index_x-1][index_y+1] + b[index_x+1][index_y+1]) / 6.0;
    const float E = (-b[index_x-1][index_y-1] - b[index_x][index_y-1] - b[index_x+1][index_y-1] + b[index_x-1][index_y+1] + b[index_x][index_y+1] + b[index_x+1][index_y+1]) / 6.0;
    const float F = (-b[index_x-1][index_y-1] + 2 * b[index_x][index_y-1] - b[index_x+1][index_y-1] + 2 * b[index_x-1][index_y] + 5 * b[index_x][index_y] + 2 * b[index_x+1][index_y] - b[index_x-1][index_y+1] +
                    2 * b[index_x][index_y+1] - b[index_x+1][index_y+1]) / 9.0;

    return (float2)(movement.x + (B * E - 2.0 * C * D) / (4.0 * A * C - B * B),
                    movement.y + (B * D - 2.0 * A * E) / (4.0 * A * C - B * B));
}

inline float2 findMovementNCC(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        const int2 pos,
        float targetMean
        ) {
    // Create grid for subpixel movement calculations
    float b[GRID_SIZE][GRID_SIZE];

    // For every possible block position
    float bestScore = -1.0f;
    float2 movement = {0, 0};
    for(int y = pos.y - SEARCH_SIZE - 1; y <= pos.y + SEARCH_SIZE + 1; ++y)  {
        for(int x = pos.x - SEARCH_SIZE - 1; x <= pos.x + SEARCH_SIZE + 1; ++x)  {
            // previousframe at pos x,y is the current candidate
            const float candidateMean = calculateMeanIntensity(previousFrame, (int2)(x, y));
            float upperPart = 0.0f;
            float lowerPart1 = 0.0f;
            float lowerPart2 = 0.0f;
            // Loop over target and candidate block
            for(int a = -BLOCK_SIZE; a <= BLOCK_SIZE; ++a) {
                for(int b = -BLOCK_SIZE; b <= BLOCK_SIZE; ++b) {
                    const float imagePart = getPixelAsFloat(previousFrame, (int2)(x+a, y+b)) - candidateMean;
                    const float targetPart = getPixelAsFloat(currentFrame, (int2)(pos.x+a, pos.y+b)) - targetMean;
                    upperPart += imagePart*targetPart;
                    lowerPart1 += imagePart*imagePart;
                    lowerPart2 += targetPart*targetPart;
                }
            }

            const float result = upperPart / sqrt(lowerPart1*lowerPart2);
            b[x- pos.x + SEARCH_SIZE + 1][y - pos.y + SEARCH_SIZE + 1] = result;
            if(result > bestScore && abs(x - pos.x) <= SEARCH_SIZE && abs(y - pos.y) <= SEARCH_SIZE) {
                bestScore = result;
                movement = (float2)(x - pos.x, y - pos.y); // Movement is the offset from pos.x, pos.y
            }
        }
    }

    float2 subpixel_movement = findSubpixelMovement(movement, b);
    return subpixel_movement;
}

__kernel void normalizedCrossCorrelation(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        __write_only image2d_t output,
        __private const float intensityThreshold,
        __private const float timeLag,
        __private const char forwardBackward
    ) {
    const int2 pos = {get_global_id(0), get_global_id(1)};

    // Template is what we are looking for (target), currentFrame at pos
    const float targetMean = calculateMeanIntensity(currentFrame, pos);
    if(targetMean < intensityThreshold) { // if target is all zero/black, just stop here
        write_imagef(output, pos, (float4)(0, 0, 0, 0));
        return;
    }

    float2 movement = findMovementNCC(previousFrame, currentFrame, pos, targetMean);
    if(forwardBackward == 1) {
      const float targetMean2 = calculateMeanIntensity(previousFrame, pos);
      movement = (movement - findMovementNCC(currentFrame, previousFrame, pos, targetMean2))*0.5f;
    }

    // If movement is larger than SEARCH_SIZE, zero it out
    if(length(movement) > SEARCH_SIZE + 1)
        movement = (float2)(0,0);

    write_imagef(output, pos, movement.xyyy / timeLag);
}

inline float2 findMovementSSD(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        const int2 pos,
        float minIntensity,
        float maxIntensity
        ) {
    // Create grid for subpixel movement calculations
    float b[GRID_SIZE][GRID_SIZE];

    // For every possible block position
    float bestScore = 0.0f;
    float2 movement = {0, 0};
    for(int y = pos.y - SEARCH_SIZE - 1; y <= pos.y + SEARCH_SIZE + 1; ++y)  {
        for(int x = pos.x - SEARCH_SIZE - 1; x <= pos.x + SEARCH_SIZE + 1; ++x)  {
            // previousframe at pos x,y is the current candidate
            float ssd = 0.0f;
            // Loop over target and candidate block
            for(int a = -BLOCK_SIZE; a <= BLOCK_SIZE; ++a) {
                for(int b = -BLOCK_SIZE; b <= BLOCK_SIZE; ++b) {
                    float val = (getPixelAsFloat(previousFrame, (int2)(x+a,y+b)) - minIntensity)/(maxIntensity - minIntensity) -
                            (getPixelAsFloat(currentFrame, (int2)(pos.x+a,pos.y+b)) - minIntensity)/(maxIntensity - minIntensity);
                    ssd += val*val;
                }
            }

            const float result = 1.0f - (ssd/((BLOCK_SIZE*2+1)*(BLOCK_SIZE*2+1))); // calculate average and invert

            b[x- pos.x + SEARCH_SIZE + 1][y - pos.y + SEARCH_SIZE + 1] = result;
            if(result > bestScore && abs(x - pos.x) <= SEARCH_SIZE && abs(y - pos.y) <= SEARCH_SIZE) {
                bestScore = result;
                movement = (float2)(x - pos.x, y - pos.y); // Movement is the offset from pos.x, pos.y
            }
        }
    }
    float2 subpixel_movement = findSubpixelMovement(movement, b);
    return subpixel_movement;
}

__kernel void sumOfSquaredDifferences(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        __write_only image2d_t output,
        __private const float intensityThreshold,
        __private const float timeLag,
        __private const char forwardBackward,
        __private const float minIntensity,
        __private const float maxIntensity
) {
    const int2 pos = {get_global_id(0), get_global_id(1)};

    // Template is what we are looking for (target), currentFrame at pos
    const float targetMean = calculateMeanIntensity(currentFrame, pos);
    if(targetMean < intensityThreshold) { // if target is all zero/black, just stop here
        write_imagef(output, pos, (float4)(0, 0, 0, 0));
        return;
    }

    float2 movement = findMovementSSD(previousFrame, currentFrame, pos, minIntensity, maxIntensity);
    if(forwardBackward == 1)
      movement = (movement - findMovementSSD(currentFrame, previousFrame, pos, minIntensity, maxIntensity))*0.5f;

    // If movement is larger than SEARCH_SIZE, zero it out
    if(length(movement) > SEARCH_SIZE + 1)
        movement = (float2)(0,0);

    write_imagef(output, pos, movement.xyyy / timeLag);
}

inline float2 findMovementSAD(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        const int2 pos,
        float minIntensity,
        float maxIntensity
        ) {
    // Create grid for subpixel movement calculations
    float b[GRID_SIZE][GRID_SIZE];

    // For every possible block position
    float bestScore = 0.0f;
    float2 movement = {0, 0};
    for(int y = pos.y - SEARCH_SIZE - 1; y <= pos.y + SEARCH_SIZE + 1; ++y)  {
        for(int x = pos.x - SEARCH_SIZE - 1; x <= pos.x + SEARCH_SIZE + 1; ++x)  {
            // previousframe at pos x,y is the current candidate
            float sad = 0.0f;
            // Loop over target and candidate block
            for(int a = -BLOCK_SIZE; a <= BLOCK_SIZE; ++a) {
                for(int b = -BLOCK_SIZE; b <= BLOCK_SIZE; ++b) {
                    sad += fabs((getPixelAsFloat(previousFrame, (int2)(x+a,y+b)) - minIntensity)/(maxIntensity - minIntensity) -
                            (getPixelAsFloat(currentFrame, (int2)(pos.x+a,pos.y+b)) - minIntensity)/(maxIntensity - minIntensity));
                }
            }

            const float result = 1.0f - (sad/((BLOCK_SIZE*2+1)*(BLOCK_SIZE*2+1))); // calculate average and invert

            b[x- pos.x + SEARCH_SIZE + 1][y - pos.y + SEARCH_SIZE + 1] = result;
            if(result > bestScore && abs(x - pos.x) <= SEARCH_SIZE && abs(y - pos.y) <= SEARCH_SIZE) {
                bestScore = result;
                movement = (float2)(x - pos.x, y - pos.y); // Movement is the offset from pos.x, pos.y
            }
        }
    }

    float2 subpixel_movement = findSubpixelMovement(movement, b);
    return subpixel_movement;
}

__kernel void sumOfAbsoluteDifferences(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        __write_only image2d_t output,
        __private const float intensityThreshold,
        __private const float timeLag,
        __private const char forwardBackward,
        __private const float minIntensity,
        __private const float maxIntensity
) {
    const int2 pos = {get_global_id(0), get_global_id(1)};

    // Template is what we are looking for (target), currentFrame at pos
    const float targetMean = calculateMeanIntensity(currentFrame, pos);
    if(targetMean < intensityThreshold) { // if target is all zero/black, just stop here
        write_imagef(output, pos, (float4)(0, 0, 0, 0));
        return;
    }

    float2 movement = findMovementSAD(previousFrame, currentFrame, pos, minIntensity, maxIntensity);
    if(forwardBackward == 1)
      movement = (movement - findMovementSAD(currentFrame, previousFrame, pos, minIntensity, maxIntensity))*0.5f;

    // If movement is larger than SEARCH_SIZE, zero it out
    if(length(movement) > SEARCH_SIZE + 1)
        movement = (float2)(0,0);

    write_imagef(output, pos, movement.xyyy / timeLag);
}

__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;

float getPixelAsFloat(__read_only image2d_t image, int2 pos) {
    float value;
    int dataType = get_image_channel_data_type(image);
    if(dataType == CLK_FLOAT) {
        value = read_imagef(image, sampler, pos).x;
    } else if(dataType == CLK_UNSIGNED_INT8 || dataType == CLK_UNSIGNED_INT16) {
        value = read_imageui(image, sampler, pos).x;
    } else {
        value = read_imagei(image, sampler, pos).x;
    }
    return value;
}

float calculateMeanIntensity(__read_only image2d_t frame, int2 pos) {
    float mean = 0.0f;
    for(int y = pos.y - BLOCK_SIZE; y <= pos.y + BLOCK_SIZE; ++y) {
        for(int x = pos.x - BLOCK_SIZE; x <= pos.x + BLOCK_SIZE; ++x) {
            mean += getPixelAsFloat(frame, (int2)(x,y));
        }
    }

    return mean/((BLOCK_SIZE*2+1)*(BLOCK_SIZE*2+1));
}

inline float2 findSubpixelMovement(const float2 movement, const float b[GRID_SIZE][GRID_SIZE]) {
    const int index_x = (int)movement.x + SEARCH_SIZE+1;
    const int index_y = (int)movement.y + SEARCH_SIZE+1;
    // Subpixel parabolic fitting
    const float A =
            (b[index_x-1][index_y-1] - 2 * b[index_x][index_y-1] + b[index_x+1][index_y-1] + b[index_x-1][index_y] - 2 * b[index_x][index_y] + b[index_x+1][index_y] + b[index_x-1][index_y+1] - 2 * b[index_x][index_y+1] +
             b[index_x+1][index_y+1]) / 6.0;
    const float B = (b[index_x-1][index_y-1] - b[index_x+1][index_y-1] - b[index_x-1][index_y+1] + b[index_x+1][index_y+1]) / 4.0;
    const float C =
            (b[index_x-1][index_y-1] + b[index_x][index_y-1] + b[index_x+1][index_y-1] - 2 * b[index_x-1][index_y] - 2 * b[index_x][index_y] - 2 * b[index_x+1][index_y] + b[index_x-1][index_y+1] + b[index_x][index_y+1] +
             b[index_x+1][index_y+1]) / 6.0;
    const float D = (-b[index_x-1][index_y-1] + b[index_x+1][index_y-1] - b[index_x-1][index_y] + b[index_x+1][index_y] - b[index_x-1][index_y+1] + b[index_x+1][index_y+1]) / 6.0;
    const float E = (-b[index_x-1][index_y-1] - b[index_x][index_y-1] - b[index_x+1][index_y-1] + b[index_x-1][index_y+1] + b[index_x][index_y+1] + b[index_x+1][index_y+1]) / 6.0;
    const float F = (-b[index_x-1][index_y-1] + 2 * b[index_x][index_y-1] - b[index_x+1][index_y-1] + 2 * b[index_x-1][index_y] + 5 * b[index_x][index_y] + 2 * b[index_x+1][index_y] - b[index_x-1][index_y+1] +
                    2 * b[index_x][index_y+1] - b[index_x+1][index_y+1]) / 9.0;

    return (float2)(movement.x + (B * E - 2.0 * C * D) / (4.0 * A * C - B * B),
                    movement.y + (B * D - 2.0 * A * E) / (4.0 * A * C - B * B));
}

inline float2 findMovementNCC(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        const int2 pos,
        float targetMean
        ) {
    // Create grid for subpixel movement calculations
    float b[GRID_SIZE][GRID_SIZE];

    // For every possible block position
    float bestScore = -1.0f;
    float2 movement = {0, 0};
    for(int y = pos.y - SEARCH_SIZE - 1; y <= pos.y + SEARCH_SIZE + 1; ++y)  {
        for(int x = pos.x - SEARCH_SIZE - 1; x <= pos.x + SEARCH_SIZE + 1; ++x)  {
            // previousframe at pos x,y is the current candidate
            const float candidateMean = calculateMeanIntensity(previousFrame, (int2)(x, y));
            float upperPart = 0.0f;
            float lowerPart1 = 0.0f;
            float lowerPart2 = 0.0f;
            // Loop over target and candidate block
            for(int a = -BLOCK_SIZE; a <= BLOCK_SIZE; ++a) {
                for(int b = -BLOCK_SIZE; b <= BLOCK_SIZE; ++b) {
                    const float imagePart = getPixelAsFloat(previousFrame, (int2)(x+a, y+b)) - candidateMean;
                    const float targetPart = getPixelAsFloat(currentFrame, (int2)(pos.x+a, pos.y+b)) - targetMean;
                    upperPart += imagePart*targetPart;
                    lowerPart1 += imagePart*imagePart;
                    lowerPart2 += targetPart*targetPart;
                }
            }

            const float result = upperPart / sqrt(lowerPart1*lowerPart2);
            b[x- pos.x + SEARCH_SIZE + 1][y - pos.y + SEARCH_SIZE + 1] = result;
            if(result > bestScore && abs(x - pos.x) <= SEARCH_SIZE && abs(y - pos.y) <= SEARCH_SIZE) {
                bestScore = result;
                movement = (float2)(x - pos.x, y - pos.y); // Movement is the offset from pos.x, pos.y
            }
        }
    }

    float2 subpixel_movement = findSubpixelMovement(movement, b);
    return subpixel_movement;
}

__kernel void normalizedCrossCorrelation(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        __write_only image2d_t output,
        __private const float intensityThreshold,
        __private const float timeLag,
        __private const char forwardBackward
    ) {
    const int2 pos = {get_global_id(0), get_global_id(1)};

    // Template is what we are looking for (target), currentFrame at pos
    const float targetMean = calculateMeanIntensity(currentFrame, pos);
    if(targetMean < intensityThreshold) { // if target is all zero/black, just stop here
        write_imagef(output, pos, (float4)(0, 0, 0, 0));
        return;
    }

    float2 movement = findMovementNCC(previousFrame, currentFrame, pos, targetMean);
    if(forwardBackward == 1)
      movement = (movement - findMovementNCC(currentFrame, previousFrame, pos, targetMean))*0.5f;

    /*
    // If movement is larger than SEARCH_SIZE, zero it out
    if(length(subpixel_movement) > SEARCH_SIZE + 1) {
        write_imagef(output, pos, (float4)(0, 0, 0, 0));
        return;
    }*/

    write_imagef(output, pos, movement.xyyy / timeLag);
}

inline float2 findMovementSSD(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        const int2 pos,
        float minIntensity,
        float maxIntensity
        ) {
    // Create grid for subpixel movement calculations
    float b[GRID_SIZE][GRID_SIZE];

    // For every possible block position
    float bestScore = 0.0f;
    float2 movement = {0, 0};
    for(int y = pos.y - SEARCH_SIZE - 1; y <= pos.y + SEARCH_SIZE + 1; ++y)  {
        for(int x = pos.x - SEARCH_SIZE - 1; x <= pos.x + SEARCH_SIZE + 1; ++x)  {
            // previousframe at pos x,y is the current candidate
            float ssd = 0.0f;
            // Loop over target and candidate block
            for(int a = -BLOCK_SIZE; a <= BLOCK_SIZE; ++a) {
                for(int b = -BLOCK_SIZE; b <= BLOCK_SIZE; ++b) {
                    float val = (getPixelAsFloat(previousFrame, (int2)(x+a,y+b)) - minIntensity)/(maxIntensity - minIntensity) -
                            (getPixelAsFloat(currentFrame, (int2)(pos.x+a,pos.y+b)) - minIntensity)/(maxIntensity - minIntensity);
                    ssd += val*val;
                }
            }

            const float result = 1.0f - (ssd/((BLOCK_SIZE*2+1)*(BLOCK_SIZE*2+1))); // calculate average and invert

            b[x- pos.x + SEARCH_SIZE + 1][y - pos.y + SEARCH_SIZE + 1] = result;
            if(result > bestScore && abs(x - pos.x) <= SEARCH_SIZE && abs(y - pos.y) <= SEARCH_SIZE) {
                bestScore = result;
                movement = (float2)(x - pos.x, y - pos.y); // Movement is the offset from pos.x, pos.y
            }
        }
    }
    float2 subpixel_movement = findSubpixelMovement(movement, b);
    return subpixel_movement;
}

__kernel void sumOfSquaredDifferences(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        __write_only image2d_t output,
        __private const float intensityThreshold,
        __private const float timeLag,
        __private const char forwardBackward,
        __private const float minIntensity,
        __private const float maxIntensity
) {
    const int2 pos = {get_global_id(0), get_global_id(1)};

    // Template is what we are looking for (target), currentFrame at pos
    const float targetMean = calculateMeanIntensity(currentFrame, pos);
    if(targetMean < intensityThreshold) { // if target is all zero/black, just stop here
        write_imagef(output, pos, (float4)(0, 0, 0, 0));
        return;
    }

    float2 movement = findMovementSSD(previousFrame, currentFrame, pos, minIntensity, maxIntensity);
    if(forwardBackward == 1)
      movement = (movement - findMovementSSD(currentFrame, previousFrame, pos, minIntensity, maxIntensity))*0.5f;

    /*
    // If movement is larger than SEARCH_SIZE, zero it out
    if(length(subpixel_movement) > SEARCH_SIZE + 1) {
        write_imagef(output, pos, (float4)(0, 0, 0, 0));
        return;
    }*/

    write_imagef(output, pos, movement.xyyy / timeLag);
}

inline float2 findMovementSAD(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        const int2 pos,
        float minIntensity,
        float maxIntensity
        ) {
    // Create grid for subpixel movement calculations
    float b[GRID_SIZE][GRID_SIZE];

    // For every possible block position
    float bestScore = 0.0f;
    float2 movement = {0, 0};
    for(int y = pos.y - SEARCH_SIZE - 1; y <= pos.y + SEARCH_SIZE + 1; ++y)  {
        for(int x = pos.x - SEARCH_SIZE - 1; x <= pos.x + SEARCH_SIZE + 1; ++x)  {
            // previousframe at pos x,y is the current candidate
            float sad = 0.0f;
            // Loop over target and candidate block
            for(int a = -BLOCK_SIZE; a <= BLOCK_SIZE; ++a) {
                for(int b = -BLOCK_SIZE; b <= BLOCK_SIZE; ++b) {
                    sad += fabs((getPixelAsFloat(previousFrame, (int2)(x+a,y+b)) - minIntensity)/(maxIntensity - minIntensity) -
                            (getPixelAsFloat(currentFrame, (int2)(pos.x+a,pos.y+b)) - minIntensity)/(maxIntensity - minIntensity));
                }
            }

            const float result = 1.0f - (sad/((BLOCK_SIZE*2+1)*(BLOCK_SIZE*2+1))); // calculate average and invert

            b[x- pos.x + SEARCH_SIZE + 1][y - pos.y + SEARCH_SIZE + 1] = result;
            if(result > bestScore && abs(x - pos.x) <= SEARCH_SIZE && abs(y - pos.y) <= SEARCH_SIZE) {
                bestScore = result;
                movement = (float2)(x - pos.x, y - pos.y); // Movement is the offset from pos.x, pos.y
            }
        }
    }

    float2 subpixel_movement = findSubpixelMovement(movement, b);
    return subpixel_movement;
}

__kernel void sumOfAbsoluteDifferences(
        __read_only image2d_t previousFrame,
        __read_only image2d_t currentFrame,
        __write_only image2d_t output,
        __private const float intensityThreshold,
        __private const float timeLag,
        __private const char forwardBackward,
        __private const float minIntensity,
        __private const float maxIntensity
) {
    const int2 pos = {get_global_id(0), get_global_id(1)};

    // Template is what we are looking for (target), currentFrame at pos
    const float targetMean = calculateMeanIntensity(currentFrame, pos);
    if(targetMean < intensityThreshold) { // if target is all zero/black, just stop here
        write_imagef(output, pos, (float4)(0, 0, 0, 0));
        return;
    }

    float2 movement = findMovementSAD(previousFrame, currentFrame, pos, minIntensity, maxIntensity);
    if(forwardBackward == 1)
      movement = (movement - findMovementSAD(currentFrame, previousFrame, pos, minIntensity, maxIntensity))*0.5f;

    /*
    // If movement is larger than SEARCH_SIZE, zero it out
    if(length(subpixel_movement) > SEARCH_SIZE + 1) {
        write_imagef(output, pos, (float4)(0, 0, 0, 0));
        return;
    }*/

    write_imagef(output, pos, movement.xyyy / timeLag);
}


fixing indentation

fixing indentation

/*
    When not passed as a command line
    option defaults are used
*/
#ifndef alpha
    #define alpha 1.5
    #define beta -0.5
    #define gamma 0.0
    #define radius 5
    #define masksize 0
#endif

/*
    Blur Mask as constant memory if it will fit in constant
    memory usally 64kb, else global.
*/
#if masksize <= 64000 // 64k
    #define mask_storage constant
#else
    #define mask_storage global
#endif

const sampler_t sampler = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;

kernel void unsharp_mask_pass_one(
    read_only image2d_t input,
    write_only image2d_t output,
    mask_storage float* hori
)
{
    const int x = get_global_id(0);
    const int y = get_global_id(1);

    float4 blurred = (float4)0.0f;

    for(int i = -radius, index = 0; i <= radius; ++i)
    {
        blurred += read_imagef(input, sampler, (int2)(x + i, y)) * (float4)hori[index++];
    }

    write_imagef(output, (int2)(x, y), blurred);
}

kernel void unsharp_mask_pass_two(
    read_only image2d_t image,
    read_only image2d_t input,
    write_only image2d_t output,
    mask_storage float* vert
)
{
    const int x = get_global_id(0);
    const int y = get_global_id(1);
    const float4 colour = read_imagef(image, sampler, (int2)(x, y));

    float4 blurred = (float4)0.0f;

    for(int i = -radius, index = 0; i <= radius; ++i)
    {
        blurred += read_imagef(input, sampler, (int2)(x, y + i)) * (float4)vert[index++];
    }

    const float4 sharp = (float4)(colour * alpha + blurred * beta + gamma);

    write_imagef(output, (int2)(x, y), radius == 0 ? colour : sharp);
}

kernel void unsharp_mask(
    read_only image2d_t in,
    write_only image2d_t out,
    mask_storage float* mask,
    const int2 px
)
{
    float4 blurred = (float4)0.0f;
    int index = 0;

    for(int y = -radius; y <= radius; ++y)
    {
        for(int x = -radius; x <= radius; ++x)
        {
            blurred += read_imagef(in, sampler, (int2)(px.x + x, px.y + y)) * mask[index++];
        }
     }

    const float4 colour = read_imagef(in, sampler, px);
    const float4 sharp = (float4)(colour * alpha + blurred * beta + gamma);

    write_imagef(out, px, radius == 0 ? colour : sharp);
}

kernel void unsharp_mask_sections(
    read_only image2d_t input,
    write_only image2d_t output,
    mask_storage float* mask,
    const int offsetX,
    const int offsetY
)
{
    const int x = get_global_id(0) + offsetX;
    const int y = get_global_id(1) + offsetY;

    unsharp_mask(input, output, mask, (int2)(x, y));
}

kernel void unsharp_mask_full(
    read_only image2d_t input,
    write_only image2d_t output,
    mask_storage float* mask
)
{
    const int x = get_global_id(0);
    const int y = get_global_id(1);

    unsharp_mask(input, output, mask, (int2)(x, y));
}


debug

debug

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

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

#define UNUSED __attribute__((__unused__))

#define MLO_NRN_GROUP_SZ2 1

#define MLO_NEURON_PASTHRU 0                       // x
#define MLO_NEURON_LOGISTIC MLO_NEURON_PASTHRU + 1 //	1 / (1 + e^-x)	//Sigmoid
#define MLO_NEURON_TANH MLO_NEURON_LOGISTIC + 1    //	a * tanh( b * x)
#define MLO_NEURON_RELU MLO_NEURON_TANH + 1        //	max(0, x)
#define MLO_NEURON_SOFTRELU \
    MLO_NEURON_RELU + 1                        //	log(1 + e^x)   // bonomial normal log likelihood
#define MLO_NEURON_ABS MLO_NEURON_SOFTRELU + 1 //	abs(x)
#define MLO_NEURON_POWER MLO_NEURON_ABS + 1    // (a + b * x ) ^power
//#define MLO_NEURON_BRELU		MLO_NEURON_POWER + 1		//	min(a, max(0, x))
//#define MLO_NEURON_SQUARE		BRELU + 1			//	x^2
//#define MLO_NEURON_SQR			MLO_NEURON_SQUARE + 1		//	sqr(x)
//#define MLO_NEURON_LINEAR		MLO_NEURON_SQR	+ 1			//	a + b * x
#define MLO_NEURON_TOTAL MLO_NEURON_POWER + 1

__attribute__((always_inline)) void ActivationFunction_PassThru(_FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < 4; i++)
    {
        res[i] = data[i];
    }
}

__attribute__((always_inline)) void
ActivationFunction_ReLU(int n, _FLOAT* res, const _FLOAT* data, _FLOAT slope)
{
    for(int i = 0; i < n; ++i)
    {
        res[i] = (data[i] > 0) ? data[i] : data[i] * slope;
    }
}

__attribute__((always_inline)) void
ActivationFunction_BReLU(int n, _FLOAT* res, const _FLOAT* data, _FLOAT alpha)
{

    for(int i = 0; i < n; ++i)
    {
        res[i] = fmin(alpha, fmax(data[i], 0));
    }
}

__attribute__((always_inline)) void
ActivationFunction_Sigmoid(int n, _FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < n; i++)
    {
        // 1/(1 + exp(-x))
        res[i] = 1.f / (1.f + exp(-data[i]));
    }
}

__attribute__((always_inline)) void
ActivationFunction_TanH(int n, _FLOAT* res, const _FLOAT* data, _FLOAT alpha, _FLOAT beta)
{
    for(int i = 0; i < n; i++)
    {
        // (exp(2x) -1) / (exp(2x) + 1)
        res[i] = alpha * tanh(beta * data[i]);
    }
}
__attribute__((always_inline)) void ActivationFunction_Abs(int n, _FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < n; i++)
    {
        res[i] = fabs(data[i]);
    }
}

__attribute__((always_inline)) void
ActivationFunction_Square(int n, _FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < n; i++)
    {

        res[i] = data[i] * data[i];
    }
}

__attribute__((always_inline)) void ActivationFunction_Sqrt(int n, _FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < n; i++)
    {

        res[i] = sqrt(data[i]);
    }
}

__attribute__((always_inline)) void
ActivationFunction_Linear(int n, _FLOAT* res, const _FLOAT* data, _FLOAT alpha, _FLOAT beta)
{
    for(int i = 0; i < n; i++)
    {
        // (exp(2x) -1) / (exp(2x) + 1)
        res[i] = alpha + beta * data[i];
    }
}

__attribute__((always_inline)) void ActivationFunction_Power(
    int n, _FLOAT* res, const _FLOAT* data, _FLOAT power, _FLOAT alpha, _FLOAT beta)
{
    for(int i = 0; i < n; i++)
    {
        // (shift + scale * x ) ^power
        _FLOAT arg     = alpha + data[i] * beta;
        _FLOAT run_arg = (arg == 0) ? 1 : arg;
        res[i]         = (arg == 0) ? 0 : pow(run_arg, power);
    }
}

__attribute__((always_inline)) void ActivationFunction_BNLL(int n, _FLOAT* res, const _FLOAT* data)

{
    for(int i = 0; i < n; i++)
    {
        //	log(1 + exp(x))
        res[i] = (data[i] > 0) ? data[i] + log(1.f + exp(-data[i])) : log(1.f + exp(data[i]));
    }
}

void ActivationFunction(
    int n, _FLOAT* res, const _FLOAT* data, _FLOAT power, _FLOAT alpha, _FLOAT beta)
{
    (void)power;
    (void)alpha;
    (void)beta;
#if MLO_NRN_OP_ID == MLO_NEURON_PASTHRU
    (void)n;
    ActivationFunction_PassThru(res, data);

#elif MLO_NRN_OP_ID == MLO_NEURON_LOGISTIC
    // 1/(1 + exp(-x))
    ActivationFunction_Sigmoid(n, res, data);

#elif MLO_NRN_OP_ID == MLO_NEURON_TANH
    // (exp(2x) -1) / (exp(2x) + 1)
    ActivationFunction_TanH(n, res, data, alpha, beta);

#elif MLO_NRN_OP_ID == MLO_NEURON_RELU
    ActivationFunction_ReLU(n, res, data, alpha);

//#elif	MLO_NRN_OP_ID==MLO_NEURON_BRELU
//	ActivationFunction_BReLU(n, res, data, alpha);

#elif MLO_NRN_OP_ID == MLO_NEURON_SOFTRELU
    //	log(1 + exp(x))
    ActivationFunction_BNLL(n, res, data);
#elif MLO_NRN_OP_ID == MLO_NEURON_ABS
    ActivationFunction_Abs(n, res, data);

//#elif	MLO_NRN_OP_ID==MLO_NEURON_SQUARE
//	ActivationFunction_Square(res, data);

//#elif	MLO_NRN_OP_ID==MLO_NEURON_SQR
//	ActivationFunction_Sqrt(n, res, data);

#elif MLO_NRN_OP_ID == MLO_NEURON_POWER
    // (shift + scale * x ) ^power

    ActivationFunction_Power(n, res, data, power, alpha, beta);

#endif
}

/******************************************************************************/
/*									DIFF */
/******************************************************************************/

static __constant _FLOAT kBNLL_THRESHOLD = 50.;

__attribute__((always_inline)) void ActivationFunction_ReLU_Diff(int n,
                                                                 _FLOAT* bot_diff,
                                                                 const _FLOAT* top_diff,
                                                                 const _FLOAT* bot_data,
                                                                 UNUSED _FLOAT negative_slope)
{

    for(int i = 0; i < n; ++i)
    {
        bot_diff[i] = top_diff[i] * (bot_data[i] > 0);
    }
}

__attribute__((always_inline)) void ActivationFunction_TanH_Diff(int n,
                                                                 _FLOAT* bot_diff,
                                                                 const _FLOAT* top_diff,
                                                                 const _FLOAT* top_data)
{
    for(int i = 0; i < n; i++)
    {
        // (exp(2x) -1) / (exp(2x) + 1)
        _FLOAT tanh_x = top_data[i];
        bot_diff[i]   = top_diff[i] * (1 - tanh_x * tanh_x);
    }
}

__attribute__((always_inline)) void ActivationFunction_Sigmoid_Diff(int n,
                                                                    _FLOAT* bot_diff,
                                                                    const _FLOAT* top_diff,
                                                                    const _FLOAT* top_data)
{
    for(int i = 0; i < n; i++)
    {
        // 1/(1 + exp(-x))
        _FLOAT sigmoid_x = top_data[i];
        bot_diff[i]      = top_diff[i] * sigmoid_x * (1.f - sigmoid_x);
    }
}

__attribute__((always_inline)) void
ActivationFunction_Abs_Diff(int n, _FLOAT* bot_diff, const _FLOAT* top_diff, const _FLOAT* bot_data)
{
    for(int i = 0; i < n; i++)
    {
        bot_diff[i] = top_diff[i] * ((bot_data != 0) ? 1 : -1);
    }
}

// Compute dy/dx = scale * power * (shift + scale * x)^(power - 1)
//               = diff_scale * y / (shift + scale * x)
__attribute__((always_inline)) void ActivationFunction_Power_Diff(int n,
                                                                  _FLOAT* bot_diff,
                                                                  UNUSED const _FLOAT* top_diff,
                                                                  const _FLOAT* top_data,
                                                                  const _FLOAT* bot_data,
                                                                  _FLOAT diff_scale,
                                                                  UNUSED _FLOAT power,
                                                                  _FLOAT scale,
                                                                  _FLOAT shift)
{

    for(int i = 0; i < n; i++)
    {
        _FLOAT arg  = shift + bot_data[i] * scale;
        bot_diff[i] = (arg == 0) ? 0 : diff_scale * top_data[i] / arg;
    }
}

__attribute__((always_inline)) void ActivationFunction_BNLL_Diff(int n,
                                                                 _FLOAT* bot_diff,
                                                                 const _FLOAT* top_diff,
                                                                 const _FLOAT* bot_data)
{
    for(int i = 0; i < n; i++)
    {
        //	(log(1 + exp(x)))' = 1/ (1 + exp(-x))
        _FLOAT expval = exp(fmin(bot_data[i], kBNLL_THRESHOLD));
        bot_diff[i]   = top_diff[i] * expval / (expval + 1.f);
    }
}

__attribute__((reqd_work_group_size(MLO_NRN_GROUP_SZ0, MLO_NRN_GROUP_SZ1, MLO_NRN_GROUP_SZ2)))
__kernel void
MIOpenNeuronFwd(const __global _FLOAT* bot,
                __global _FLOAT* top,
                _FLOAT power,
                _FLOAT scale,
                _FLOAT shift,
                const long xOffset,
                const long yOffset)
{
    int x = get_global_id(0); // channel x

    _FLOAT data[MLO_READ_UNIT];
    _FLOAT response[MLO_READ_UNIT];
#if MLO_N_PIXS_OFF > 0
    if(x == MLO_MAP_SZ_ALIGNED - 1)
    {
        int i = 0;
        for(; i < MLO_N_PIXS_OFF; ++i)
        {
            data[i] = bot[xOffset + x * MLO_READ_UNIT + i];
        }
        for(; i < MLO_READ_UNIT; ++i)
        {
            data[i] = 1.f;
        }
    }
    else
#endif
    {
        for(int i = 0; i < MLO_READ_UNIT; ++i)
        {
            data[i] = bot[xOffset + x * MLO_READ_UNIT + i];
        }
    }
    ActivationFunction(MLO_READ_UNIT, response, (const _FLOAT*)data, power, scale, shift);

#if MLO_N_PIXS_OFF > 0
    if(x == MLO_MAP_SZ_ALIGNED - 1)
    {
        int i = 0;
        for(; i < MLO_N_PIXS_OFF; ++i)
        {
            top[yOffset + x * MLO_READ_UNIT + i] = response[i];
        }
    }
    else
#endif
    {
        for(int i = 0; i < MLO_READ_UNIT; ++i)
        {
            top[yOffset + x * MLO_READ_UNIT + i] = response[i];
        }
    }
}

__attribute__((reqd_work_group_size(MLO_NRN_GROUP_SZ0, MLO_NRN_GROUP_SZ1, MLO_NRN_GROUP_SZ2)))
__kernel void
MIOpenNeuronBwd(__global _FLOAT* bot_diff,
                __global const _FLOAT* top_diff,
                __global const _FLOAT* bot_data,
                __global const _FLOAT* top_data,
                _FLOAT diff_scale,
                _FLOAT power,
                _FLOAT scale,
                _FLOAT shift,
                const long dxOffset,
                const long dyOffset,
                const long xOffset,
                const long yOffset)
{

    (void)diff_scale;
    (void)power;
    (void)scale;
    (void)shift;

    int x = get_global_id(0); // channel x

    _FLOAT bot_diff_dat[MLO_READ_UNIT];
    _FLOAT top_diff_dat[MLO_READ_UNIT];
    _FLOAT bot_dat[MLO_READ_UNIT];
    _FLOAT top_dat[MLO_READ_UNIT];
#if MLO_N_PIXS_OFF > 0
    if(x == MLO_MAP_SZ_ALIGNED - 1)
    {
        int i = 0;
        for(; i < MLO_N_PIXS_OFF; ++i)
        {
            top_diff_dat[i] = top_diff[dyOffset + x * MLO_READ_UNIT + i];
            bot_dat[i]      = bot_data[xOffset + x * MLO_READ_UNIT + i];
            top_dat[i]      = top_data[yOffset + x * MLO_READ_UNIT + i];
        }
        for(; i < MLO_READ_UNIT; ++i)
        {
            top_diff_dat[i] = 1.f;
            bot_dat[i]      = 1.f;
            top_dat[i]      = 1.f;
        }
    }
    else
#endif
    {
        for(int i = 0; i < MLO_READ_UNIT; ++i)
        {
            top_diff_dat[i] = top_diff[dyOffset + x * MLO_READ_UNIT + i];
            bot_dat[i]      = bot_data[xOffset + x * MLO_READ_UNIT + i];
            top_dat[i]      = top_data[yOffset + x * MLO_READ_UNIT + i];
        }
    }

#if MLO_NRN_OP_ID == MLO_NEURON_RELU
    {
        ActivationFunction_ReLU_Diff(MLO_READ_UNIT,
                                     bot_diff_dat,
                                     (const _FLOAT*)top_diff_dat,
                                     (const _FLOAT*)bot_dat,
                                     scale);
    }
#elif MLO_NRN_OP_ID == MLO_NEURON_LOGISTIC
    // 1/(1 + exp(-x))
    ActivationFunction_Sigmoid_Diff(
        MLO_READ_UNIT, bot_diff_dat, (const _FLOAT*)top_diff_dat, (const _FLOAT*)top_dat);
#elif MLO_NRN_OP_ID == MLO_NEURON_TANH
    // (exp(2x) -1) / (exp(2x) + 1)

    ActivationFunction_TanH_Diff(
        MLO_READ_UNIT, bot_diff_dat, (const _FLOAT*)top_diff_dat, (const _FLOAT*)top_dat);

#elif MLO_NRN_OP_ID == MLO_NEURON_ABS

    ActivationFunction_Abs_Diff(
        MLO_READ_UNIT, bot_diff_dat, (const _FLOAT*)top_diff_dat, (const _FLOAT*)bot_dat);
#elif MLO_NRN_OP_ID == MLO_NEURON_POWER
    // (shift + scale * x ) ^power

    ActivationFunction_Power_Diff(MLO_READ_UNIT,
                                  bot_diff_dat,
                                  (const _FLOAT*)top_diff_dat,
                                  (const _FLOAT*)top_dat,
                                  (const _FLOAT*)bot_dat,
                                  diff_scale,
                                  power,
                                  scale,
                                  shift);

#elif MLO_NRN_OP_ID == MLO_NEURON_SOFTRELU
    //	log(1 + exp(x))
    ActivationFunction_BNLL_Diff(
        MLO_READ_UNIT, bot_diff_dat, (const _FLOAT*)top_diff_dat, (const _FLOAT*)bot_dat);
#endif

#if MLO_N_PIXS_OFF > 0
    if(x == MLO_MAP_SZ_ALIGNED - 1)
    {
        int i = 0;
        for(; i < MLO_N_PIXS_OFF; ++i)
        {
            bot_diff[dxOffset + x * MLO_READ_UNIT + i] = bot_diff_dat[i];
        }
    }
    else
#endif
    {
        for(int i = 0; i < MLO_READ_UNIT; ++i)
        {
            bot_diff[dxOffset + x * MLO_READ_UNIT + i] = bot_diff_dat[i];
        }
    }
}

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

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

#define UNUSED __attribute__((__unused__))

#define MLO_NRN_GROUP_SZ2 1

#define MLO_NEURON_PASTHRU 0                       // x
#define MLO_NEURON_LOGISTIC MLO_NEURON_PASTHRU + 1 //	1 / (1 + e^-x)	//Sigmoid
#define MLO_NEURON_TANH MLO_NEURON_LOGISTIC + 1    //	a * tanh( b * x)
#define MLO_NEURON_RELU MLO_NEURON_TANH + 1        //	max(0, x)
#define MLO_NEURON_SOFTRELU \
    MLO_NEURON_RELU + 1                        //	log(1 + e^x)   // bonomial normal log likelihood
#define MLO_NEURON_ABS MLO_NEURON_SOFTRELU + 1 //	abs(x)
#define MLO_NEURON_POWER MLO_NEURON_ABS + 1    // (a + b * x ) ^power
//#define MLO_NEURON_BRELU		MLO_NEURON_POWER + 1		//	min(a, max(0, x))
//#define MLO_NEURON_SQUARE		BRELU + 1			//	x^2
//#define MLO_NEURON_SQR			MLO_NEURON_SQUARE + 1		//	sqr(x)
//#define MLO_NEURON_LINEAR		MLO_NEURON_SQR	+ 1			//	a + b * x
#define MLO_NEURON_TOTAL MLO_NEURON_POWER + 1

__attribute__((always_inline)) void ActivationFunction_PassThru(_FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < 4; i++)
    {
        res[i] = data[i];
    }
}

__attribute__((always_inline)) void
ActivationFunction_ReLU(int n, _FLOAT* res, const _FLOAT* data, _FLOAT slope)
{
    for(int i = 0; i < n; ++i)
    {
        res[i] = (data[i] > 0) ? data[i] : data[i] * slope;
    }
}

__attribute__((always_inline)) void
ActivationFunction_BReLU(int n, _FLOAT* res, const _FLOAT* data, _FLOAT alpha)
{

    for(int i = 0; i < n; ++i)
    {
        res[i] = fmin(alpha, fmax(data[i], 0));
    }
}

__attribute__((always_inline)) void
ActivationFunction_Sigmoid(int n, _FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < n; i++)
    {
        // 1/(1 + exp(-x))
        res[i] = 1.f / (1.f + exp(-data[i]));
    }
}

__attribute__((always_inline)) void
ActivationFunction_TanH(int n, _FLOAT* res, const _FLOAT* data, _FLOAT alpha, _FLOAT beta)
{
    for(int i = 0; i < n; i++)
    {
        // (exp(2x) -1) / (exp(2x) + 1)
        res[i] = alpha * tanh(beta * data[i]);
    }
}
__attribute__((always_inline)) void ActivationFunction_Abs(int n, _FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < n; i++)
    {
        res[i] = fabs(data[i]);
    }
}

__attribute__((always_inline)) void
ActivationFunction_Square(int n, _FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < n; i++)
    {

        res[i] = data[i] * data[i];
    }
}

__attribute__((always_inline)) void ActivationFunction_Sqrt(int n, _FLOAT* res, const _FLOAT* data)
{
    for(int i = 0; i < n; i++)
    {

        res[i] = sqrt(data[i]);
    }
}

__attribute__((always_inline)) void
ActivationFunction_Linear(int n, _FLOAT* res, const _FLOAT* data, _FLOAT alpha, _FLOAT beta)
{
    for(int i = 0; i < n; i++)
    {
        // (exp(2x) -1) / (exp(2x) + 1)
        res[i] = alpha + beta * data[i];
    }
}

__attribute__((always_inline)) void ActivationFunction_Power(
    int n, _FLOAT* res, const _FLOAT* data, _FLOAT power, _FLOAT alpha, _FLOAT beta)
{
    for(int i = 0; i < n; i++)
    {
        // (shift + scale * x ) ^power
        _FLOAT arg     = alpha + data[i] * beta;
        _FLOAT run_arg = (arg == 0) ? 1 : arg;
        res[i]         = (arg == 0) ? 0 : pow(run_arg, power);
    }
}

__attribute__((always_inline)) void ActivationFunction_BNLL(int n, _FLOAT* res, const _FLOAT* data)

{
    for(int i = 0; i < n; i++)
    {
        //	log(1 + exp(x))
        res[i] = (data[i] > 0) ? data[i] + log(1.f + exp(-data[i])) : log(1.f + exp(data[i]));
    }
}

void ActivationFunction(
    int n, _FLOAT* res, const _FLOAT* data, _FLOAT power, _FLOAT alpha, _FLOAT beta)
{
    (void)power;
    (void)alpha;
    (void)beta;
#if MLO_NRN_OP_ID == MLO_NEURON_PASTHRU
    (void)n;
    ActivationFunction_PassThru(res, data);

#elif MLO_NRN_OP_ID == MLO_NEURON_LOGISTIC
    // 1/(1 + exp(-x))
    ActivationFunction_Sigmoid(n, res, data);

#elif MLO_NRN_OP_ID == MLO_NEURON_TANH
    // (exp(2x) -1) / (exp(2x) + 1)
    ActivationFunction_TanH(n, res, data, alpha, beta);

#elif MLO_NRN_OP_ID == MLO_NEURON_RELU
    ActivationFunction_ReLU(n, res, data, alpha);

//#elif	MLO_NRN_OP_ID==MLO_NEURON_BRELU
//	ActivationFunction_BReLU(n, res, data, alpha);

#elif MLO_NRN_OP_ID == MLO_NEURON_SOFTRELU
    //	log(1 + exp(x))
    ActivationFunction_BNLL(n, res, data);
#elif MLO_NRN_OP_ID == MLO_NEURON_ABS
    ActivationFunction_Abs(n, res, data);

//#elif	MLO_NRN_OP_ID==MLO_NEURON_SQUARE
//	ActivationFunction_Square(res, data);

//#elif	MLO_NRN_OP_ID==MLO_NEURON_SQR
//	ActivationFunction_Sqrt(n, res, data);

#elif MLO_NRN_OP_ID == MLO_NEURON_POWER
    // (shift + scale * x ) ^power

    ActivationFunction_Power(n, res, data, power, alpha, beta);

#endif
}

/******************************************************************************/
/*									DIFF */
/******************************************************************************/

static __constant _FLOAT kBNLL_THRESHOLD = 50.;

__attribute__((always_inline)) void ActivationFunction_ReLU_Diff(int n,
                                                                 _FLOAT* bot_diff,
                                                                 const _FLOAT* top_diff,
                                                                 const _FLOAT* bot_data,
                                                                 UNUSED _FLOAT negative_slope)
{

    for(int i = 0; i < n; ++i)
    {
        bot_diff[i] = top_diff[i] * (bot_data[i] > 0);
    }
}

__attribute__((always_inline)) void ActivationFunction_TanH_Diff(int n,
                                                                 _FLOAT* bot_diff,
                                                                 const _FLOAT* top_diff,
                                                                 const _FLOAT* top_data)
{
    for(int i = 0; i < n; i++)
    {
        // (exp(2x) -1) / (exp(2x) + 1)
        _FLOAT tanh_x = top_data[i];
        bot_diff[i]   = top_diff[i] * (1 - tanh_x * tanh_x);
    }
}

__attribute__((always_inline)) void ActivationFunction_Sigmoid_Diff(int n,
                                                                    _FLOAT* bot_diff,
                                                                    const _FLOAT* top_diff,
                                                                    const _FLOAT* top_data)
{
    for(int i = 0; i < n; i++)
    {
        // 1/(1 + exp(-x))
        _FLOAT sigmoid_x = top_data[i];
        bot_diff[i]      = top_diff[i] * sigmoid_x * (1.f - sigmoid_x);
    }
}

__attribute__((always_inline)) void
ActivationFunction_Abs_Diff(int n, _FLOAT* bot_diff, const _FLOAT* top_diff, const _FLOAT* bot_data)
{
    for(int i = 0; i < n; i++)
    {
        bot_diff[i] = top_diff[i] * ((bot_data != 0) ? 1 : -1);
    }
}

// Compute dy/dx = scale * power * (shift + scale * x)^(power - 1)
//               = diff_scale * y / (shift + scale * x)
__attribute__((always_inline)) void ActivationFunction_Power_Diff(int n,
                                                                  _FLOAT* bot_diff,
                                                                  UNUSED const _FLOAT* top_diff,
                                                                  const _FLOAT* top_data,
                                                                  const _FLOAT* bot_data,
                                                                  _FLOAT diff_scale,
                                                                  UNUSED _FLOAT power,
                                                                  _FLOAT scale,
                                                                  _FLOAT shift)
{

    for(int i = 0; i < n; i++)
    {
        _FLOAT arg  = shift + bot_data[i] * scale;
        bot_diff[i] = (arg == 0) ? 0 : diff_scale * top_data[i] / arg;
    }
}

__attribute__((always_inline)) void ActivationFunction_BNLL_Diff(int n,
                                                                 _FLOAT* bot_diff,
                                                                 const _FLOAT* top_diff,
                                                                 const _FLOAT* bot_data)
{
    for(int i = 0; i < n; i++)
    {
        //	(log(1 + exp(x)))' = 1/ (1 + exp(-x))
        _FLOAT expval = exp(fmin(bot_data[i], kBNLL_THRESHOLD));
        bot_diff[i]   = top_diff[i] * expval / (expval + 1.f);
    }
}

__attribute__((reqd_work_group_size(MLO_NRN_GROUP_SZ0, MLO_NRN_GROUP_SZ1, MLO_NRN_GROUP_SZ2)))
__kernel void
MIOpenNeuronFwd(const __global _FLOAT* bot,
                __global _FLOAT* top,
                _FLOAT power,
                _FLOAT scale,
                _FLOAT shift,
                UNUSED const long xOffset,
                UNUSED const long yOffset)
{
    int x = get_global_id(0); // channel x

    _FLOAT data[MLO_READ_UNIT];
    _FLOAT response[MLO_READ_UNIT];
#if MLO_N_PIXS_OFF > 0
    if(x == MLO_MAP_SZ_ALIGNED - 1)
    {
        int i = 0;
        for(; i < MLO_N_PIXS_OFF; ++i)
        {
            data[i] = bot[xOffset + x * MLO_READ_UNIT + i];
        }
        for(; i < MLO_READ_UNIT; ++i)
        {
            data[i] = 1.f;
        }
    }
    else
#endif
    {
        for(int i = 0; i < MLO_READ_UNIT; ++i)
        {
            data[i] = bot[xOffset + x * MLO_READ_UNIT + i];
        }
    }
    ActivationFunction(MLO_READ_UNIT, response, (const _FLOAT*)data, power, scale, shift);

#if MLO_N_PIXS_OFF > 0
    if(x == MLO_MAP_SZ_ALIGNED - 1)
    {
        int i = 0;
        for(; i < MLO_N_PIXS_OFF; ++i)
        {
            top[yOffset + x * MLO_READ_UNIT + i] = response[i];
        }
    }
    else
#endif
    {
        for(int i = 0; i < MLO_READ_UNIT; ++i)
        {
            top[yOffset + x * MLO_READ_UNIT + i] = response[i];
        }
    }
}

__attribute__((reqd_work_group_size(MLO_NRN_GROUP_SZ0, MLO_NRN_GROUP_SZ1, MLO_NRN_GROUP_SZ2)))
__kernel void
MIOpenNeuronBwd(__global _FLOAT* bot_diff,
                __global const _FLOAT* top_diff,
                __global const _FLOAT* bot_data,
                __global const _FLOAT* top_data,
                _FLOAT diff_scale,
                _FLOAT power,
                _FLOAT scale,
                _FLOAT shift,
                UNUSED const long dxOffset
                UNUSED const long dyOffset,
                UNUSED const long xOffset,
                UNUSED const long yOffset)
{

    (void)diff_scale;
    (void)power;
    (void)scale;
    (void)shift;

    int x = get_global_id(0); // channel x

    _FLOAT bot_diff_dat[MLO_READ_UNIT];
    _FLOAT top_diff_dat[MLO_READ_UNIT];
    _FLOAT bot_dat[MLO_READ_UNIT];
    _FLOAT top_dat[MLO_READ_UNIT];
#if MLO_N_PIXS_OFF > 0
    if(x == MLO_MAP_SZ_ALIGNED - 1)
    {
        int i = 0;
        for(; i < MLO_N_PIXS_OFF; ++i)
        {
            top_diff_dat[i] = top_diff[dyOffset + x * MLO_READ_UNIT + i];
            bot_dat[i]      = bot_data[xOffset + x * MLO_READ_UNIT + i];
            top_dat[i]      = top_data[yOffset + x * MLO_READ_UNIT + i];
        }
        for(; i < MLO_READ_UNIT; ++i)
        {
            top_diff_dat[i] = 1.f;
            bot_dat[i]      = 1.f;
            top_dat[i]      = 1.f;
        }
    }
    else
#endif
    {
        for(int i = 0; i < MLO_READ_UNIT; ++i)
        {
            top_diff_dat[i] = top_diff[dyOffset + x * MLO_READ_UNIT + i];
            bot_dat[i]      = bot_data[xOffset + x * MLO_READ_UNIT + i];
            top_dat[i]      = top_data[yOffset + x * MLO_READ_UNIT + i];
        }
    }

#if MLO_NRN_OP_ID == MLO_NEURON_RELU
    {
        ActivationFunction_ReLU_Diff(MLO_READ_UNIT,
                                     bot_diff_dat,
                                     (const _FLOAT*)top_diff_dat,
                                     (const _FLOAT*)bot_dat,
                                     scale);
    }
#elif MLO_NRN_OP_ID == MLO_NEURON_LOGISTIC
    // 1/(1 + exp(-x))
    ActivationFunction_Sigmoid_Diff(
        MLO_READ_UNIT, bot_diff_dat, (const _FLOAT*)top_diff_dat, (const _FLOAT*)top_dat);
#elif MLO_NRN_OP_ID == MLO_NEURON_TANH
    // (exp(2x) -1) / (exp(2x) + 1)

    ActivationFunction_TanH_Diff(
        MLO_READ_UNIT, bot_diff_dat, (const _FLOAT*)top_diff_dat, (const _FLOAT*)top_dat);

#elif MLO_NRN_OP_ID == MLO_NEURON_ABS

    ActivationFunction_Abs_Diff(
        MLO_READ_UNIT, bot_diff_dat, (const _FLOAT*)top_diff_dat, (const _FLOAT*)bot_dat);
#elif MLO_NRN_OP_ID == MLO_NEURON_POWER
    // (shift + scale * x ) ^power

    ActivationFunction_Power_Diff(MLO_READ_UNIT,
                                  bot_diff_dat,
                                  (const _FLOAT*)top_diff_dat,
                                  (const _FLOAT*)top_dat,
                                  (const _FLOAT*)bot_dat,
                                  diff_scale,
                                  power,
                                  scale,
                                  shift);

#elif MLO_NRN_OP_ID == MLO_NEURON_SOFTRELU
    //	log(1 + exp(x))
    ActivationFunction_BNLL_Diff(
        MLO_READ_UNIT, bot_diff_dat, (const _FLOAT*)top_diff_dat, (const _FLOAT*)bot_dat);
#endif

#if MLO_N_PIXS_OFF > 0
    if(x == MLO_MAP_SZ_ALIGNED - 1)
    {
        int i = 0;
        for(; i < MLO_N_PIXS_OFF; ++i)
        {
            bot_diff[dxOffset + x * MLO_READ_UNIT + i] = bot_diff_dat[i];
        }
    }
    else
#endif
    {
        for(int i = 0; i < MLO_READ_UNIT; ++i)
        {
            bot_diff[dxOffset + x * MLO_READ_UNIT + i] = bot_diff_dat[i];
        }
    }
}


do RLC in main bit plane processing routine

/*  Copyright 2014 Aaron Boxer

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include "ocl_platform.cl"

/*

Bit Plane Coder
===============

A. Scan Pattern

Xx4 stripes

The stripes are scanned from top to bottom, and the columns within a
stripe are scanned from left to right.

*/

#define CODEBLOCKY_QUARTER 8

#define BOUNDARY 1
#define BOUNDARY_X2 2

#define CODEBLOCKY_X4 128

#define STATE_BUFFER_SIZE 1156
#define STATE_BOTTOM_BOUNDARY_OFFSET 1124

#define STATE_BUFFER_STRIDE 34
#define STATE_BUFFER_STRIDE_X2 68
#define STATE_BUFFER_STRIDE_X3 102
#define STATE_BUFFER_STRIDE_X4 136

#define LEFT_TOP -35
#define TOP  -34
#define RIGHT_TOP -33

#define LEFT   -1
#define RIGHT   1

#define LEFT_BOTTOM  33
#define BOTTOM  34
#define RIGHT_BOTTOM  35

// bit positions (0 based indices)
#define INPUT_SIGN_BITPOS  15

#define SIGMA_NEW_BITPOS   0x1
#define SIGMA_OLD_BITPOS   0x1
#define NBH_BITPOS         0x2
#define SIGMA_OLD_TO_NBH_SHIFT 0x1
#define RLC_BITPOS         0x4
#define PIXEL_START_BITPOS 0xA
#define PIXEL_END_BITPOS   0x18
#define SIGN_BITPOS        0x19

// bit flags
#define SIGMA_NEW_F			 0x1		  //position 0
#define SIGMA_OLD_F			 0x10		  //position  1
#define NBH_F				 0x20		  //position  2
#define RLC_F				 0x80		  //position  4
#define RLC_D_POSITION_F	 0x380        //positions 6-9
#define PIXEL_F				 0x7FFF0000   //positions 10-24
#define SIGN_F				 0x2000000    //position  25

#define NOT_SIGMA_NEW_F      0xFFFFFFFE   // ~SIGMA_NEW
#define SIGMA_OLD_AND_NEW_F  0x11

#define INPUT_TO_SIGN_SHIFT 10

CONSTANT sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE  | CLK_FILTER_NEAREST;

#define BIT(pix) (((pix)>>(bp))&1)
#define NBH(pix) ((pix) & NBH_F)
#define SIGMA_OLD(pix) ((pix) & SIGMA_OLD_F)
#define SIGMA_NEW(pix) ((pix) & SIGMA_NEW_F)
#define SIGMA_OLD_AND_NEW(pix) ((pix) & SIGMA_OLD_AND_NEW_F)
#define SIGN(pix) ((pix) & SIGN_F)

#define SET_SIGMA_NEW(pix) ( (pix) |= SIGMA_NEW_F )
#define CLEAR_SIGMA_NEW(pix) ( (pix) &= NOT_SIGMA_NEW_F )

/**

**/

void KERNEL run(read_only image2d_t channel) {

	// state buffer
	LOCAL int state[STATE_BUFFER_SIZE];
	LOCAL int cxd[STATE_BUFFER_SIZE];

	///////////////////////////////////////////////////////////////////////////////////
	//1. Calculate MSB

	LOCAL int msbScratch[CODEBLOCKX]; // between -1 and 31 - negative one value indicates that this code block is identically zero

	int maxSigBit;
	if (getLocalId(1) == 0) {

		int maxVal = 0;
		state[getLocalId(0)] = 0;   //top boundary
		LOCAL int* statePtr = state + (BOUNDARY + getLocalId(0));
		int2 posIn = (int2)(getGlobalId(0),  (getGlobalId(1) >> 3)*CODEBLOCKY);

		for (int i = 0; i < CODEBLOCKY; ++i) {
			int pixel = read_imagei(channel, sampler, posIn).x;
			int absPixel = abs(pixel);
			maxVal = max(maxVal, absPixel);
			pixel = (absPixel << PIXEL_START_BITPOS) | SIGN((pixel << INPUT_TO_SIGN_SHIFT));
			statePtr[0] = pixel;

			posIn.y++;
			statePtr += STATE_BUFFER_STRIDE;
		}
		state[ getLocalId(0) + STATE_BOTTOM_BOUNDARY_OFFSET] = 0;		//bottom boundary

		//initialize full left and right boundary columns
		if (getLocalId(0) == 0 || getLocalId(0) == CODEBLOCKX-1) {
			int delta = -1 + (getLocalId(0)/(CODEBLOCKX-1))*2; // -1 or +1
			statePtr = state + BOUNDARY + getLocalId(0) + delta;
			for (int i = 0; i < CODEBLOCKY+ BOUNDARY_X2; ++i) {
				 *statePtr = 0;
				 statePtr += STATE_BUFFER_STRIDE;
			}
		}

		// calculate column-msb
		maxSigBit = 31 - clz(maxVal);
		msbScratch[getLocalId(0)] =maxSigBit;
	}
	localMemoryFence();

	//calculate global msb
	if (!getLocalId(0) && !getLocalId(1) ) {
		int4 mx = (int4)(maxSigBit);

		LOCAL int* scratchPtr = msbScratch;
		for(int i=0; i < CODEBLOCKX; i+=4) {
			mx = max(mx,(int4)(msbScratch[i],msbScratch[i+1],msbScratch[i+2],msbScratch[i+3]));
		}
		maxSigBit = mx.x;
		maxSigBit = max(maxSigBit, mx.y);
		maxSigBit = max(maxSigBit, mx.z);
		maxSigBit = max(maxSigBit, mx.w);
		msbScratch[0] = maxSigBit;
	}
	localMemoryFence();

	if (msbScratch[0] == -1)
		return;

	int startIndex = (BOUNDARY + getLocalId(0)) + (BOUNDARY + getLocalId(1))*STATE_BUFFER_STRIDE_X4;

	////////////////////////////////////////////////////////////////////////////////////////////////
	// 2. CUP on MSB

	int bp = msbScratch[0] + PIXEL_START_BITPOS;

	// i) set sigma_new for strip column (sigma_old is zero)
	LOCAL int* statePtr = state + startIndex;
	for (int i = 0; i < 4; ++i) {
		int current = statePtr[0];
		current |= BIT(current);
		*statePtr = current;
		statePtr += STATE_BUFFER_STRIDE;

	}
	localMemoryFence();

	// ii) set nbh for strip column, and do CUP
	statePtr = state + startIndex;
	int current			= statePtr[0];
	int top				= statePtr[TOP];
	int leftTop			= statePtr[LEFT_TOP];
	int left			= statePtr[LEFT];
	int leftBottom		= statePtr[LEFT_BOTTOM];

	int rlcCount = 0;

	// first pixel in strip column
	int nbh =  SIGMA_NEW(top) | SIGMA_NEW(leftTop) | SIGMA_NEW(left) | SIGMA_NEW(leftBottom);
	bool doRLC = !nbh && !BIT(current);
	if (doRLC) {
		rlcCount++;
	} else {
		//ZC

		if (BIT(current)) {
		    //SC
		}
	}

	// next two pixels in strip column
	for (int i = 0; i < 2; ++i) {

		statePtr += STATE_BUFFER_STRIDE;
		top = current;
		current		= statePtr[0];
		leftTop		= left;
		left		= leftBottom;
		leftBottom	= statePtr[LEFT_BOTTOM];

		nbh =  SIGMA_NEW(top) | SIGMA_NEW(leftTop) | SIGMA_NEW(left) | SIGMA_NEW(leftBottom);
		doRLC = doRLC && !nbh && !BIT(current);
		if (doRLC) {

			rlcCount++;
		} else {
		   //ZC

		   if (BIT(current)) {
		       //SC
		   }
		}
	}

	// last pixel in strip column -
	// ignore leftBottom pixel, because it is in the next
	// stripe and it hasn't been processed yet
	statePtr += STATE_BUFFER_STRIDE;
	top			= current;
	current		= statePtr[0];
	leftTop		= left;
	left		= leftBottom;

	nbh =  SIGMA_NEW(top) | SIGMA_NEW(leftTop) | SIGMA_NEW(left);

	doRLC = doRLC && !nbh && !BIT(current);
	if (doRLC) {

		rlcCount++;
	} else {
		//ZC

		if (BIT(current)) {
		    //SC
		}
	}

	localMemoryFence();

	/////////////////////////////////////////////////////////////////////////////////////////////////
	// 3. Processs rest of bit planes
	bp--;
	LOCAL char blockVote;

	while (bp >= PIXEL_START_BITPOS) {
		blockVote = 0;

		/////////////////////////////
		// 4. pre-process bit plane

		// i) migrate sigma_new to sigma_old, and clear sigma new bit
		statePtr = state + startIndex;
		for (int i = 0; i < 4; ++i) {
		    int current = *statePtr;
			current |=  SIGMA_NEW(current) << SIGMA_OLD_BITPOS;
			CLEAR_SIGMA_NEW(current);

			*statePtr = current;
			statePtr += STATE_BUFFER_STRIDE;

		}
		localMemoryFence();

		// ii) update nbh
		statePtr = state + startIndex;

		int top			= statePtr[TOP];
		int leftTop		= statePtr[LEFT_TOP];
		int rightTop	= statePtr[RIGHT_TOP];
		int left		= statePtr[LEFT];
		int current		= statePtr[0];
		int right		= statePtr[RIGHT];
		int leftBottom  = statePtr[LEFT_BOTTOM];
		int bottom		= statePtr[BOTTOM];
		int rightBottom = statePtr[RIGHT_BOTTOM];

		current |=  (   SIGMA_OLD(leftTop) |
						SIGMA_OLD( top) |
						SIGMA_OLD( rightTop) |
						SIGMA_OLD( left) |
						SIGMA_OLD( right) |
						SIGMA_OLD( leftBottom) |
						SIGMA_OLD( bottom) |
						SIGMA_OLD( rightBottom)  ) << SIGMA_OLD_TO_NBH_SHIFT;

		if ( BIT(current) &&
				NBH(current) &&
					!SIGMA_OLD(current) ) {
			SET_SIGMA_NEW(current);
			blockVote = 1;

		}
		*statePtr = current;

		for (int i = 0; i < 3; ++i) {
			statePtr += STATE_BUFFER_STRIDE;

			top			 = current;
			leftTop		 = left;
			rightTop	 = right;
			left		 = leftBottom;
			current		 = statePtr[0];
			right		 = rightBottom;
			leftBottom   = statePtr[LEFT_BOTTOM];
			bottom		 = statePtr[BOTTOM];
			rightBottom  = statePtr[RIGHT_BOTTOM];

			current |=	   ( SIGMA_OLD(leftTop) |
							 SIGMA_OLD( top) |
							 SIGMA_OLD( rightTop) |
							 SIGMA_OLD( left) |
							 SIGMA_OLD( right) |
							 SIGMA_OLD( leftBottom) |
							 SIGMA_OLD( bottom) |
							 SIGMA_OLD( rightBottom)  ) << SIGMA_OLD_TO_NBH_SHIFT;

			if ( BIT(current) &&
					 NBH(current) &&
						 !SIGMA_OLD(current) ) {
			    SET_SIGMA_NEW(current);
				blockVote = 1;
			}
			*statePtr = current;

		}
		localMemoryFence();

		// iii) block vote on sigma new
		while (blockVote)
		{
		    blockVote = 0;
			localMemoryFence();

			statePtr = state + startIndex;

			//first pixel in strip column
			int top			= statePtr[TOP];
			int leftTop		= statePtr[LEFT_TOP];
			int left		= statePtr[LEFT];
			int current		= statePtr[0];
			int leftBottom  = statePtr[LEFT_BOTTOM];

			current  |= (   SIGMA_NEW(leftTop) |
							SIGMA_NEW( top) |
							SIGMA_NEW( left) |
							SIGMA_NEW( leftBottom) ) << NBH_BITPOS;

			if (  BIT(current) &&
				        !SIGMA_OLD(current) &&
						    NBH(current)  &&
							    !SIGMA_NEW(current)) {
				SET_SIGMA_NEW(current);
				blockVote = 1;

			}
			statePtr[0] = current;

			// next two pixels in strip column
			for (int i = 0; i < 2; ++i) {
				statePtr += STATE_BUFFER_STRIDE;

				top			= current;
				current		= statePtr[0];
				leftTop		= left;
				left		= leftBottom;
				leftBottom  = statePtr[LEFT_BOTTOM];

				current  |= (   SIGMA_NEW(leftTop) |
								SIGMA_NEW( top) |
								SIGMA_NEW( left) |
								SIGMA_NEW( leftBottom) ) << NBH_BITPOS;

				if (  BIT(current) &&
				          !SIGMA_OLD(current) &&
						      NBH(current)  &&
							     !SIGMA_NEW(current)) {
					SET_SIGMA_NEW(current);
					blockVote = 1;

				}
				statePtr[0] = current;
			}

			// last pixel in strip column -
			// ignore leftBottom pixel, because it is in the next
			// stripe and it hasn't been processed yet
			statePtr += STATE_BUFFER_STRIDE;

			top			= current;
			current		= statePtr[0];
			leftTop		= left;
			left		= leftBottom;

			current |= ( SIGMA_NEW(leftTop) |
						 SIGMA_NEW( top) |
						 SIGMA_NEW( left) ) << NBH_BITPOS;
			if (  BIT(current) &&
			        !SIGMA_OLD(current) &&
					    NBH(current)  &&
						    !SIGMA_NEW(current)) {
				SET_SIGMA_NEW(current);
				blockVote = 1;
			}
			statePtr[0] = current;

			localMemoryFence();

		}

		/////////////////////////
		// 5. bit plane processing
		statePtr = state + startIndex;

		top = statePtr[TOP];
		leftTop			= statePtr[LEFT_TOP];
		rightTop		= statePtr[RIGHT_TOP];
		left			= statePtr[LEFT];
		current			= statePtr[0];
		right			= statePtr[RIGHT];
		leftBottom		= statePtr[LEFT_BOTTOM];
		bottom			= statePtr[BOTTOM];
		rightBottom		= statePtr[RIGHT_BOTTOM];

		doRLC = false;
		rlcCount = 0;
		if (SIGMA_OLD(current)) {
			// MRC
		} else {
			int nbh = ( SIGMA_OLD_AND_NEW(leftTop) |
						SIGMA_OLD_AND_NEW( top) |
						SIGMA_OLD_AND_NEW( rightTop) |
						SIGMA_OLD_AND_NEW( left) |
						SIGMA_OLD_AND_NEW( right) |
						SIGMA_OLD_AND_NEW( leftBottom) |
						SIGMA_OLD_AND_NEW( bottom) |
						SIGMA_OLD_AND_NEW( rightBottom)  ) ;

			if (!nbh) {
				if ( !SIGMA_NEW(current) ) {
					doRLC = !BIT(current);
					if (doRLC) {
					   rlcCount++;
					}
				}
			}
			else  {
				// ZC
				if (BIT(current)) {
				    //SC
				}
			}
		}

		for (int i = 0; i < 3; ++i) {
			statePtr += STATE_BUFFER_STRIDE;

			top			= current;
			leftTop		= left;
			rightTop	= right;
			left		= leftBottom;
			current		= statePtr[0];
			right		= rightBottom;
			leftBottom  = statePtr[LEFT_BOTTOM];
			bottom		= statePtr[BOTTOM];
			rightBottom = statePtr[RIGHT_BOTTOM];

			if (SIGMA_OLD(current)) {
				// MRC
			} else {
				int nbh = ( SIGMA_OLD_AND_NEW(leftTop) |
							SIGMA_OLD_AND_NEW( top) |
							SIGMA_OLD_AND_NEW( rightTop) |
							SIGMA_OLD_AND_NEW( left) |
							SIGMA_OLD_AND_NEW( right) |
							SIGMA_OLD_AND_NEW( leftBottom) |
							SIGMA_OLD_AND_NEW( bottom) |
							SIGMA_OLD_AND_NEW( rightBottom)  ) ;

				if (!nbh) {
					if ( !SIGMA_NEW(current) ) {
						doRLC = doRLC && !BIT(current);
						if (!doRLC) {

							rlcCount++;

						}
					}
				}
				else  {
					// ZC
					if (BIT(current)) {
						//SC
					}
				}
			}
		}

		localMemoryFence();
		bp--;
	}
}

/*  Copyright 2014 Aaron Boxer

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include "ocl_platform.cl"

/*

Bit Plane Coder
===============

A. Scan Pattern

Xx4 stripes

The stripes are scanned from top to bottom, and the columns within a
stripe are scanned from left to right.

*/

#define CODEBLOCKY_QUARTER 8

#define BOUNDARY 1
#define BOUNDARY_X2 2

#define CODEBLOCKY_X4 128

#define STATE_BUFFER_SIZE 1156
#define STATE_BOTTOM_BOUNDARY_OFFSET 1124

#define STATE_BUFFER_STRIDE 34
#define STATE_BUFFER_STRIDE_X2 68
#define STATE_BUFFER_STRIDE_X3 102
#define STATE_BUFFER_STRIDE_X4 136

#define LEFT_TOP -35
#define TOP  -34
#define RIGHT_TOP -33

#define LEFT   -1
#define RIGHT   1

#define LEFT_BOTTOM  33
#define BOTTOM  34
#define RIGHT_BOTTOM  35

// bit positions (0 based indices)
#define INPUT_SIGN_BITPOS  15

#define SIGMA_NEW_BITPOS   0x1
#define SIGMA_OLD_BITPOS   0x1
#define NBH_BITPOS         0x2
#define SIGMA_OLD_TO_NBH_SHIFT 0x1
#define RLC_BITPOS         0x4
#define PIXEL_START_BITPOS 0xA
#define PIXEL_END_BITPOS   0x18
#define SIGN_BITPOS        0x19

// bit flags
#define SIGMA_NEW_F			 0x1		  //position 0
#define SIGMA_OLD_F			 0x10		  //position  1
#define NBH_F				 0x20		  //position  2
#define RLC_F				 0x80		  //position  4
#define RLC_D_POSITION_F	 0x380        //positions 6-9
#define PIXEL_F				 0x7FFF0000   //positions 10-24
#define SIGN_F				 0x2000000    //position  25

#define NOT_SIGMA_NEW_F      0xFFFFFFFE   // ~SIGMA_NEW
#define SIGMA_OLD_AND_NEW_F  0x11

#define INPUT_TO_SIGN_SHIFT 10

CONSTANT sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE  | CLK_FILTER_NEAREST;

#define BIT(pix) (((pix)>>(bp))&1)
#define NBH(pix) ((pix) & NBH_F)
#define SIGMA_OLD(pix) ((pix) & SIGMA_OLD_F)
#define SIGMA_NEW(pix) ((pix) & SIGMA_NEW_F)
#define SIGMA_OLD_AND_NEW(pix) ((pix) & SIGMA_OLD_AND_NEW_F)
#define SIGN(pix) ((pix) & SIGN_F)

#define SET_SIGMA_NEW(pix) ( (pix) |= SIGMA_NEW_F )
#define CLEAR_SIGMA_NEW(pix) ( (pix) &= NOT_SIGMA_NEW_F )

/**

**/

void KERNEL run(read_only image2d_t channel) {

	// state buffer
	LOCAL int state[STATE_BUFFER_SIZE];
	LOCAL int cxd[STATE_BUFFER_SIZE];

	///////////////////////////////////////////////////////////////////////////////////
	//1. Calculate MSB

	LOCAL int msbScratch[CODEBLOCKX]; // between -1 and 31 - negative one value indicates that this code block is identically zero

	int maxSigBit;
	if (getLocalId(1) == 0) {

		int maxVal = 0;
		state[getLocalId(0)] = 0;   //top boundary
		LOCAL int* statePtr = state + (BOUNDARY + getLocalId(0));
		int2 posIn = (int2)(getGlobalId(0),  (getGlobalId(1) >> 3)*CODEBLOCKY);

		for (int i = 0; i < CODEBLOCKY; ++i) {
			int pixel = read_imagei(channel, sampler, posIn).x;
			int absPixel = abs(pixel);
			maxVal = max(maxVal, absPixel);
			pixel = (absPixel << PIXEL_START_BITPOS) | SIGN((pixel << INPUT_TO_SIGN_SHIFT));
			statePtr[0] = pixel;

			posIn.y++;
			statePtr += STATE_BUFFER_STRIDE;
		}
		state[ getLocalId(0) + STATE_BOTTOM_BOUNDARY_OFFSET] = 0;		//bottom boundary

		//initialize full left and right boundary columns
		if (getLocalId(0) == 0 || getLocalId(0) == CODEBLOCKX-1) {
			int delta = -1 + (getLocalId(0)/(CODEBLOCKX-1))*2; // -1 or +1
			statePtr = state + BOUNDARY + getLocalId(0) + delta;
			for (int i = 0; i < CODEBLOCKY+ BOUNDARY_X2; ++i) {
				 *statePtr = 0;
				 statePtr += STATE_BUFFER_STRIDE;
			}
		}

		// calculate column-msb
		maxSigBit = 31 - clz(maxVal);
		msbScratch[getLocalId(0)] =maxSigBit;
	}
	localMemoryFence();

	//calculate global msb
	if (!getLocalId(0) && !getLocalId(1) ) {
		int4 mx = (int4)(maxSigBit);

		LOCAL int* scratchPtr = msbScratch;
		for(int i=0; i < CODEBLOCKX; i+=4) {
			mx = max(mx,(int4)(msbScratch[i],msbScratch[i+1],msbScratch[i+2],msbScratch[i+3]));
		}
		maxSigBit = mx.x;
		maxSigBit = max(maxSigBit, mx.y);
		maxSigBit = max(maxSigBit, mx.z);
		maxSigBit = max(maxSigBit, mx.w);
		msbScratch[0] = maxSigBit;
	}
	localMemoryFence();

	if (msbScratch[0] == -1)
		return;

	int startIndex = (BOUNDARY + getLocalId(0)) + (BOUNDARY + getLocalId(1))*STATE_BUFFER_STRIDE_X4;

	////////////////////////////////////////////////////////////////////////////////////////////////
	// 2. CUP on MSB

	int bp = msbScratch[0] + PIXEL_START_BITPOS;

	// i) set sigma_new for strip column (sigma_old is zero)
	LOCAL int* statePtr = state + startIndex;
	for (int i = 0; i < 4; ++i) {
		int current = statePtr[0];
		current |= BIT(current);
		*statePtr = current;
		statePtr += STATE_BUFFER_STRIDE;

	}
	localMemoryFence();

	// ii) set nbh for strip column, and do CUP
	statePtr = state + startIndex;
	int current			= statePtr[0];
	int top				= statePtr[TOP];
	int leftTop			= statePtr[LEFT_TOP];
	int left			= statePtr[LEFT];
	int leftBottom		= statePtr[LEFT_BOTTOM];

	int rlcCount = 0;

	// first pixel in strip column
	int nbh =  SIGMA_NEW(top) | SIGMA_NEW(leftTop) | SIGMA_NEW(left) | SIGMA_NEW(leftBottom);
	bool doRLC = !nbh && !BIT(current);
	if (doRLC) {
		rlcCount++;
	} else {
		//ZC

		if (BIT(current)) {
		    //SC
		}
	}

	// next two pixels in strip column
	for (int i = 0; i < 2; ++i) {

		statePtr += STATE_BUFFER_STRIDE;
		top = current;
		current		= statePtr[0];
		leftTop		= left;
		left		= leftBottom;
		leftBottom	= statePtr[LEFT_BOTTOM];

		nbh =  SIGMA_NEW(top) | SIGMA_NEW(leftTop) | SIGMA_NEW(left) | SIGMA_NEW(leftBottom);

		// toggle doRLC flag
		doRLC = doRLC && !nbh && !BIT(current);
		if (doRLC) {

			rlcCount++;
		} else {
		   //ZC

		   if (BIT(current)) {
		       //SC
		   }
		}
	}

	// last pixel in strip column -
	// ignore leftBottom pixel, because it is in the next
	// stripe and it hasn't been processed yet
	statePtr += STATE_BUFFER_STRIDE;
	top			= current;
	current		= statePtr[0];
	leftTop		= left;
	left		= leftBottom;

	nbh =  SIGMA_NEW(top) | SIGMA_NEW(leftTop) | SIGMA_NEW(left);

	doRLC = doRLC && !nbh && !BIT(current);
	if (doRLC) {

		rlcCount++;
	} else {
		//ZC

		if (BIT(current)) {
		    //SC
		}
	}

	localMemoryFence();

	/////////////////////////////////////////////////////////////////////////////////////////////////
	// 3. Processs rest of bit planes
	bp--;
	LOCAL char blockVote;

	while (bp >= PIXEL_START_BITPOS) {
		blockVote = 0;

		/////////////////////////////
		// 4. pre-process bit plane

		// i) migrate sigma_new to sigma_old, and clear sigma new bit
		statePtr = state + startIndex;
		for (int i = 0; i < 4; ++i) {
		    int current = *statePtr;
			current |=  SIGMA_NEW(current) << SIGMA_OLD_BITPOS;
			CLEAR_SIGMA_NEW(current);

			*statePtr = current;
			statePtr += STATE_BUFFER_STRIDE;

		}
		localMemoryFence();

		// ii) update nbh
		statePtr = state + startIndex;

		int top			= statePtr[TOP];
		int leftTop		= statePtr[LEFT_TOP];
		int rightTop	= statePtr[RIGHT_TOP];
		int left		= statePtr[LEFT];
		int current		= statePtr[0];
		int right		= statePtr[RIGHT];
		int leftBottom  = statePtr[LEFT_BOTTOM];
		int bottom		= statePtr[BOTTOM];
		int rightBottom = statePtr[RIGHT_BOTTOM];

		current |=  (   SIGMA_OLD(leftTop) |
						SIGMA_OLD( top) |
						SIGMA_OLD( rightTop) |
						SIGMA_OLD( left) |
						SIGMA_OLD( right) |
						SIGMA_OLD( leftBottom) |
						SIGMA_OLD( bottom) |
						SIGMA_OLD( rightBottom)  ) << SIGMA_OLD_TO_NBH_SHIFT;

		if ( BIT(current) &&
				NBH(current) &&
					!SIGMA_OLD(current) ) {
			SET_SIGMA_NEW(current);
			blockVote = 1;

		}
		*statePtr = current;

		for (int i = 0; i < 3; ++i) {
			statePtr += STATE_BUFFER_STRIDE;

			top			 = current;
			leftTop		 = left;
			rightTop	 = right;
			left		 = leftBottom;
			current		 = statePtr[0];
			right		 = rightBottom;
			leftBottom   = statePtr[LEFT_BOTTOM];
			bottom		 = statePtr[BOTTOM];
			rightBottom  = statePtr[RIGHT_BOTTOM];

			current |=	   ( SIGMA_OLD(leftTop) |
							 SIGMA_OLD( top) |
							 SIGMA_OLD( rightTop) |
							 SIGMA_OLD( left) |
							 SIGMA_OLD( right) |
							 SIGMA_OLD( leftBottom) |
							 SIGMA_OLD( bottom) |
							 SIGMA_OLD( rightBottom)  ) << SIGMA_OLD_TO_NBH_SHIFT;

			if ( BIT(current) &&
					 NBH(current) &&
						 !SIGMA_OLD(current) ) {
			    SET_SIGMA_NEW(current);
				blockVote = 1;
			}
			*statePtr = current;

		}
		localMemoryFence();

		// iii) block vote on sigma new
		while (blockVote)
		{
		    blockVote = 0;
			localMemoryFence();

			statePtr = state + startIndex;

			//first pixel in strip column
			int top			= statePtr[TOP];
			int leftTop		= statePtr[LEFT_TOP];
			int left		= statePtr[LEFT];
			int current		= statePtr[0];
			int leftBottom  = statePtr[LEFT_BOTTOM];

			current  |= (   SIGMA_NEW(leftTop) |
							SIGMA_NEW( top) |
							SIGMA_NEW( left) |
							SIGMA_NEW( leftBottom) ) << NBH_BITPOS;

			if (  BIT(current) &&
				        !SIGMA_OLD(current) &&
						    NBH(current)  &&
							    !SIGMA_NEW(current)) {
				SET_SIGMA_NEW(current);
				blockVote = 1;

			}
			statePtr[0] = current;

			// next two pixels in strip column
			for (int i = 0; i < 2; ++i) {
				statePtr += STATE_BUFFER_STRIDE;

				top			= current;
				current		= statePtr[0];
				leftTop		= left;
				left		= leftBottom;
				leftBottom  = statePtr[LEFT_BOTTOM];

				current  |= (   SIGMA_NEW(leftTop) |
								SIGMA_NEW( top) |
								SIGMA_NEW( left) |
								SIGMA_NEW( leftBottom) ) << NBH_BITPOS;

				if (  BIT(current) &&
				          !SIGMA_OLD(current) &&
						      NBH(current)  &&
							     !SIGMA_NEW(current)) {
					SET_SIGMA_NEW(current);
					blockVote = 1;

				}
				statePtr[0] = current;
			}

			// last pixel in strip column -
			// ignore leftBottom pixel, because it is in the next
			// stripe and it hasn't been processed yet
			statePtr += STATE_BUFFER_STRIDE;

			top			= current;
			current		= statePtr[0];
			leftTop		= left;
			left		= leftBottom;

			current |= ( SIGMA_NEW(leftTop) |
						 SIGMA_NEW( top) |
						 SIGMA_NEW( left) ) << NBH_BITPOS;
			if (  BIT(current) &&
			        !SIGMA_OLD(current) &&
					    NBH(current)  &&
						    !SIGMA_NEW(current)) {
				SET_SIGMA_NEW(current);
				blockVote = 1;
			}
			statePtr[0] = current;

			localMemoryFence();

		}

		/////////////////////////
		// 5. bit plane processing
		statePtr = state + startIndex;

		top = statePtr[TOP];
		leftTop			= statePtr[LEFT_TOP];
		rightTop		= statePtr[RIGHT_TOP];
		left			= statePtr[LEFT];
		current			= statePtr[0];
		right			= statePtr[RIGHT];
		leftBottom		= statePtr[LEFT_BOTTOM];
		bottom			= statePtr[BOTTOM];
		rightBottom		= statePtr[RIGHT_BOTTOM];

		if (SIGMA_OLD(current)) {
			// MRC
		} else {
			int nbh = ( SIGMA_OLD_AND_NEW(leftTop) |
						SIGMA_OLD_AND_NEW( top) |
						SIGMA_OLD_AND_NEW( rightTop) |
						SIGMA_OLD_AND_NEW( left) |
						SIGMA_OLD_AND_NEW( right) |
						SIGMA_OLD_AND_NEW( leftBottom) |
						SIGMA_OLD_AND_NEW( bottom) |
						SIGMA_OLD_AND_NEW( rightBottom)  ) ;

			if (!nbh) {
				if ( !SIGMA_NEW(current) ) {
					//RLC
				}
			}
			else  {
				// ZC
				if (BIT(current)) {
				    //SC
				}
			}
		}

		for (int i = 0; i < 3; ++i) {
			statePtr += STATE_BUFFER_STRIDE;

			top			= current;
			leftTop		= left;
			rightTop	= right;
			left		= leftBottom;
			current		= statePtr[0];
			right		= rightBottom;
			leftBottom  = statePtr[LEFT_BOTTOM];
			bottom		= statePtr[BOTTOM];
			rightBottom = statePtr[RIGHT_BOTTOM];

			if (SIGMA_OLD(current)) {
				// MRC
			} else {
				int nbh = ( SIGMA_OLD_AND_NEW(leftTop) |
							SIGMA_OLD_AND_NEW( top) |
							SIGMA_OLD_AND_NEW( rightTop) |
							SIGMA_OLD_AND_NEW( left) |
							SIGMA_OLD_AND_NEW( right) |
							SIGMA_OLD_AND_NEW( leftBottom) |
							SIGMA_OLD_AND_NEW( bottom) |
							SIGMA_OLD_AND_NEW( rightBottom)  ) ;

				if (!nbh) {
					if ( !SIGMA_NEW(current) ) {
						//RLC
					}
				}
				else  {
					// ZC
					if (BIT(current)) {
						//SC
					}
				}
			}
		}

		localMemoryFence();
		bp--;
	}
}