cleanups

cleanups

#include "cl/mwc64x/cl/mwc64x.cl"

// Doesn't return 0 so that rays can bounce without bumping.
float sphere_toi(
  const float3 eye,
  const float3 look,

  const float3 center,
  const float radius)
{
  // quadratic coefficients
  float a = dot(look, look);
  float b = 2 * dot(eye - center, look);
  float3 to_center = eye - center;
  float c = dot(to_center, to_center) - radius*radius;

  // discriminant
  float d = b*b - 4*a*c;

  if (d < 0) {
    return HUGE_VALF;
  }

  float s1 = (sqrt(d) - b) / (2 * a);
  if (s1 <= 0) {
    s1 = HUGE_VALF;
  }

  float s2 = (-sqrt(d) - b) / (2 * a);
  if (s1 < s2 || s2 <= 0) {
    return s1;
  }

  return s2;
}

typedef struct {
  float4 row1;
  float4 row2;
  float4 row3;
  float4 row4;
} mat4;

float4 vmult(mat4 m, float4 v) {
  return
    (float4)(
      dot(m.row1, v),
      dot(m.row2, v),
      dot(m.row3, v),
      dot(m.row4, v)
    );
}

mat4 screen_to_view(uint w, uint h, float fovy) {
  float aspect = (float)w / (float)h;

  float b = tan(fovy / 2);
  float a = 2 * b / h;
  b = -b;

  mat4 r;
  // We divide both x and y by h, to take aspect ratio into account.
  // An increase in image width will cause wider rays to be shot.
  r.row1 = (float4)(a, 0, 0, b * aspect);
  r.row2 = (float4)(0, a, 0, b);
  r.row3 = (float4)(0, 0, 1, 0);
  r.row4 = (float4)(0, 0, 0, 1);

  return r;
}

mat4 view_to_world(float3 eye, float3 look, float3 up) {
  float4 x = (float4)(cross(look, up), 0);
  float4 y = (float4)(up, 0);
  float4 z = (float4)(look, 0);
  float4 w = (float4)(eye, 1);

  // Change of basis

  mat4 r;
  r.row1.x = x.x;
  r.row2.x = x.y;
  r.row3.x = x.z;
  r.row4.x = x.w;

  r.row1.y = y.x;
  r.row2.y = y.y;
  r.row3.y = y.z;
  r.row4.y = y.w;

  r.row1.z = z.x;
  r.row2.z = z.y;
  r.row3.z = z.z;
  r.row4.z = z.w;

  r.row1.w = w.x;
  r.row2.w = w.y;
  r.row3.w = w.z;
  r.row4.w = w.w;

  return r;
}

typedef struct {
  float r;
  float g;
  float b;
} RGB;

RGB rgb(float3 xyz) {
  RGB r;
  r.r = xyz.x;
  r.g = xyz.y;
  r.b = xyz.z;
  return r;
}

typedef struct { float x, y, z } float3_parse;

#define MAKE_OBJECT(f3)  \
  struct {               \
    f3 center;           \
    float radius;        \
    f3 color;            \
    float diffuseness;   \
    float emittance;     \
    float reflectance;   \
    float transmittance; \
  }

typedef MAKE_OBJECT(float3) Object;
typedef MAKE_OBJECT(float3_parse) Object_parse;

float parse_float(__global const float** data) {
  float r = **data;
  ++*data;
  return r;
}

float3 parse_float3(__global const float** data) {
  float3 r;
  r.x = parse_float(data);
  r.y = parse_float(data);
  r.z = parse_float(data);
  return r;
}

Object parse_object(__global const float* data) {
  Object r;
  r.center        = parse_float3(&data);
  r.radius        = parse_float(&data);
  r.color         = parse_float3(&data);
  r.diffuseness   = parse_float(&data);
  r.emittance     = parse_float(&data);
  r.reflectance   = parse_float(&data);
  r.transmittance = parse_float(&data);
  return r;
}

typedef struct {
  float3 origin;
  float3 direction;
} Ray;

void raycast(
  Ray ray,

  __global const float* objects,
  const uint num_objects,

  float* toi,
  Object* collision
) {
  *toi = HUGE_VALF;

  for (uint i = 0; i < num_objects; ++i) {
    Object object = parse_object((Object_parse*)objects + i);
    float this_toi = sphere_toi(ray.origin, ray.direction, object.center, object.radius);

    if (this_toi >= *toi) {
      continue;
    }

    *toi = this_toi;
    *collision = object;
  }
}

float rand(mwc64x_state_t* rand_state) {
  return (float)MWC64X_NextUint(rand_state) / (float)UINT_MAX;
}

float3 perturb_frame(mwc64x_state_t* rand_state, const float max_angle, const float3* x, const float3* y, const float3* z) {
  float3 coeffs;
  const float c = cos(max_angle);
  coeffs.y = rand(rand_state) * (1 - c) + c;
  const float xz = sqrt(1 - coeffs.y * coeffs.y);
  const float azimuth = rand(rand_state) * 2 * 3.14;
  coeffs.x = cos(azimuth);
  coeffs.z = sin(azimuth);
  coeffs.x *= xz;
  coeffs.z *= xz;
  return coeffs.x * *x + coeffs.y * *y + coeffs.z * *z;
}

float3 perturb(mwc64x_state_t* rand_state, const float3* unperturbed, const float3* normal, const float max_angle) {
  const float3* y = unperturbed;
  // TODO: find z/x better when normal ~= unperturbed
  const float3 z = normalize(cross(*normal, *y));
  const float3 x = normalize(cross(z, *y));

  for (int i = 0; i < 8; ++i) {
    const float3 r = perturb_frame(rand_state, max_angle, &x, y, &z);
    if (dot(r, *normal) >= 0) {
      return r;
    }
  }

  // If we failed several times, we're probably almost perpendicular to the normal.
  // I think that's a pretty small area, so we can just forget the perturb here.
  return *unperturbed;
}

// If the ray is absorbed (i.e. there is no next path), this returns false.
bool pick_next_path(
  mwc64x_state_t* const rand_state,
  const Ray* const ray,
  const float3* const collision_point,
  const float3* const normal,
  const Object* const collided_object,
  float3* const new_direction,
  float3* const new_normal
) {
  float r = rand(rand_state);

  r -= collided_object->transmittance;
  if (r <= 0) {
    *new_direction = ray->direction;
    *new_normal = -*normal;
    return true;
  }

  r -= collided_object->reflectance;
  if (r <= 0) {
    const float cos_theta = dot(ray->direction, *normal);
    *new_direction = ray->direction - 2 * cos_theta * *normal;
    *new_normal = *normal;
    return true;
  }

  return false;
}

float3 pathtrace(
  Ray ray,
  const uint max_depth,
  mwc64x_state_t* rand_state,
  __global const float* objects,
  const uint num_objects
) {
  float3 pixel_color = (float3)(0, 0, 0);
  float3 attenuation = (float3)(1, 1, 1);

  for (int i = 0; i < max_depth; ++i) {
    float toi;
    Object collided_object;

    raycast(ray, objects, num_objects, &toi, &collided_object);

    if (toi == HUGE_VALF) {
      break;
    }

    attenuation *= collided_object.color;

    pixel_color += attenuation * (float3)(collided_object.emittance);

    const float3 collision_point = ray.origin + toi*ray.direction;
    const float3 normal = (collision_point - collided_object.center) / collided_object.radius;

    float3 new_direction;
    float3 new_normal;
    if (!pick_next_path(rand_state, &ray, &collision_point, &normal, &collided_object, &new_direction, &new_normal)) {
      // Ray is absorbed.
      break;
    }

    const float max_scatter_angle = 3.14 * collided_object.diffuseness;

    // TODO: maybe instead of a max_scatter_angle, we could describe a probability distribution over the scatter angle.
    ray.direction = perturb(rand_state, &new_direction, &new_normal, max_scatter_angle);
    ray.origin = collision_point + 0.1f * ray.direction;
  }

  return pixel_color;
}

mwc64x_state_t init_rand_state(ulong random_seed) {
  mwc64x_state_t rand_state;
  rand_state.x = (uint)(random_seed & 0xFFFFFFFF);
  rand_state.c = (random_seed & 0xFFFFFFFF00000000) >> 32;
  return rand_state;
}

__kernel void render(
  const uint image_width,
  const uint image_height,

  const float fovy,
  float3 eye,
  const float3 look,
  const float3 up,

  ulong random_seed,

  __global const float* objects,
  const uint num_objects,

  __global RGB * output)
{
  const int id = get_global_id(0);

  const int x_pix = id % image_width;
  const int y_pix = id / image_width;

  const float4 world_pos =
    vmult(view_to_world(eye, look, up),
    vmult(screen_to_view(image_width, image_height, fovy),
    (float4)(x_pix, y_pix, 1, 1)
  ));

  Ray ray;
  ray.origin = eye;
  ray.direction = normalize((world_pos / world_pos.w).xyz - eye);

  random_seed = random_seed * id * id;
  mwc64x_state_t rand_state = init_rand_state(random_seed);
  MWC64X_Skip(&rand_state, 20);

  output[id] = rgb(pathtrace(ray, 20, &rand_state, objects, num_objects));
}

#include "cl/mwc64x/cl/mwc64x.cl"

// Doesn't return 0 so that rays can bounce without bumping.
float sphere_toi(
  const float3 eye,
  const float3 look,

  const float3 center,
  const float radius)
{
  // quadratic coefficients
  float a = dot(look, look);
  float b = 2 * dot(eye - center, look);
  float3 to_center = eye - center;
  float c = dot(to_center, to_center) - radius*radius;

  // discriminant
  float d = b*b - 4*a*c;

  if (d < 0) {
    return HUGE_VALF;
  }

  float s1 = (sqrt(d) - b) / (2 * a);
  if (s1 <= 0) {
    s1 = HUGE_VALF;
  }

  float s2 = (-sqrt(d) - b) / (2 * a);
  if (s1 < s2 || s2 <= 0) {
    return s1;
  }

  return s2;
}

typedef struct {
  float4 row1;
  float4 row2;
  float4 row3;
  float4 row4;
} mat4;

float4 vmult(mat4 m, float4 v) {
  return
    (float4)(
      dot(m.row1, v),
      dot(m.row2, v),
      dot(m.row3, v),
      dot(m.row4, v)
    );
}

mat4 screen_to_view(uint w, uint h, float fovy) {
  float aspect = (float)w / (float)h;

  float b = tan(fovy / 2);
  float a = 2 * b / h;
  b = -b;

  mat4 r;
  // We divide both x and y by h, to take aspect ratio into account.
  // An increase in image width will cause wider rays to be shot.
  r.row1 = (float4)(a, 0, 0, b * aspect);
  r.row2 = (float4)(0, a, 0, b);
  r.row3 = (float4)(0, 0, 1, 0);
  r.row4 = (float4)(0, 0, 0, 1);

  return r;
}

mat4 view_to_world(float3 eye, float3 look, float3 up) {
  float4 x = (float4)(cross(look, up), 0);
  float4 y = (float4)(up, 0);
  float4 z = (float4)(look, 0);
  float4 w = (float4)(eye, 1);

  // Change of basis

  mat4 r;
  r.row1.x = x.x;
  r.row2.x = x.y;
  r.row3.x = x.z;
  r.row4.x = x.w;

  r.row1.y = y.x;
  r.row2.y = y.y;
  r.row3.y = y.z;
  r.row4.y = y.w;

  r.row1.z = z.x;
  r.row2.z = z.y;
  r.row3.z = z.z;
  r.row4.z = z.w;

  r.row1.w = w.x;
  r.row2.w = w.y;
  r.row3.w = w.z;
  r.row4.w = w.w;

  return r;
}

typedef struct {
  float r;
  float g;
  float b;
} RGB;

RGB rgb(float3 xyz) {
  RGB r;
  r.r = xyz.x;
  r.g = xyz.y;
  r.b = xyz.z;
  return r;
}

typedef struct { float x, y, z } float3_parse;

#define MAKE_OBJECT(f3)  \
  struct {               \
    f3 center;           \
    float radius;        \
    f3 color;            \
    float diffuseness;   \
    float emittance;     \
    float reflectance;   \
    float transmittance; \
  }

typedef MAKE_OBJECT(float3) Object;
typedef MAKE_OBJECT(float3_parse) Object_parse;

float parse_float(__global const float** data) {
  float r = **data;
  ++*data;
  return r;
}

float3 parse_float3(__global const float** data) {
  float3 r;
  r.x = parse_float(data);
  r.y = parse_float(data);
  r.z = parse_float(data);
  return r;
}

Object parse_object(__global const float* data) {
  Object r;
  r.center        = parse_float3(&data);
  r.radius        = parse_float(&data);
  r.color         = parse_float3(&data);
  r.diffuseness   = parse_float(&data);
  r.emittance     = parse_float(&data);
  r.reflectance   = parse_float(&data);
  r.transmittance = parse_float(&data);
  return r;
}

typedef struct {
  float3 origin;
  float3 direction;
} Ray;

void raycast(
  Ray ray,

  __global const float* objects,
  const uint num_objects,

  float* toi,
  Object* collision
) {
  *toi = HUGE_VALF;

  for (uint i = 0; i < num_objects; ++i) {
    Object object = parse_object((Object_parse*)objects + i);
    float this_toi = sphere_toi(ray.origin, ray.direction, object.center, object.radius);

    if (this_toi >= *toi) {
      continue;
    }

    *toi = this_toi;
    *collision = object;
  }
}

float rand(mwc64x_state_t* rand_state) {
  return (float)MWC64X_NextUint(rand_state) / (float)UINT_MAX;
}

float3 perturb_frame(mwc64x_state_t* rand_state, const float max_angle, float3 x, float3 y, float3 z) {
  float3 coeffs;
  const float c = cos(max_angle);
  coeffs.y = rand(rand_state) * (1 - c) + c;
  const float xz = sqrt(1 - coeffs.y * coeffs.y);
  const float azimuth = rand(rand_state) * 2 * 3.14;
  coeffs.x = cos(azimuth);
  coeffs.z = sin(azimuth);
  coeffs.x *= xz;
  coeffs.z *= xz;
  return coeffs.x*x + coeffs.y*y + coeffs.z*z;
}

float3 perturb(mwc64x_state_t* rand_state, const float3 unperturbed, const float3 normal, const float max_angle) {
  const float3 y = unperturbed;
  // TODO: find z/x better when normal ~= unperturbed
  const float3 z = normalize(cross(normal, y));
  const float3 x = normalize(cross(z, y));

  for (int i = 0; i < 8; ++i) {
    const float3 r = perturb_frame(rand_state, max_angle, x, y, z);
    if (dot(r, normal) >= 0) {
      return r;
    }
  }

  // If we failed several times, we're probably almost perpendicular to the normal.
  // I think that's a pretty small area, so we can just forget the perturb here.
  return unperturbed;
}

float3 pathtrace(
  Ray ray,
  const uint max_depth,
  mwc64x_state_t* rand_state,
  __global const float* objects,
  const uint num_objects
) {
  float3 pixel_color = (float3)(0, 0, 0);
  float3 attenuation = (float3)(1, 1, 1);

  for (int i = 0; i < max_depth; ++i) {
    float toi;
    Object collided_object;

    raycast(ray, objects, num_objects, &toi, &collided_object);

    if (toi == HUGE_VALF) {
      break;
    }

    attenuation *= collided_object.color;

    pixel_color += attenuation * (float3)(collided_object.emittance);

    const float3 collision_point = ray.origin + toi*ray.direction;
    const float3 normal = (collision_point - collided_object.center) / collided_object.radius;
    const float max_scatter_angle = 3.14 * collided_object.diffuseness;

    float r = rand(rand_state);

    r -= collided_object.transmittance;
    if (r <= 0) {
      // TODO: cos_theta < 0?
      Ray transmitted_ray;
      const float3 unperturbed = ray.direction;
      transmitted_ray.direction = perturb(rand_state, unperturbed, -normal, max_scatter_angle);
      transmitted_ray.origin = collision_point + 0.1f * transmitted_ray.direction;
      ray = transmitted_ray;
      continue;
    }

    r -= collided_object.reflectance;
    if (r <= 0) {
      // TODO: cos_theta < 0?
      Ray reflected_ray;
      const float cos_theta = dot(ray.direction, normal);
      const float3 unperturbed = ray.direction - 2*cos_theta*normal;
      reflected_ray.direction = perturb(rand_state, unperturbed, normal, max_scatter_angle);
      reflected_ray.origin = collision_point + 0.1f * reflected_ray.direction;
      ray = reflected_ray;
      continue;
    }

    // Ray is absorbed.
    break;
  }

  return pixel_color;
}

mwc64x_state_t init_rand_state(ulong random_seed) {
  mwc64x_state_t rand_state;
  rand_state.x = (uint)(random_seed & 0xFFFFFFFF);
  rand_state.c = (random_seed & 0xFFFFFFFF00000000) >> 32;
  return rand_state;
}

__kernel void render(
  const uint image_width,
  const uint image_height,

  const float fovy,
  float3 eye,
  const float3 look,
  const float3 up,

  ulong random_seed,

  __global const float* objects,
  const uint num_objects,

  __global RGB * output)
{
  int id = get_global_id(0);

  const int x_pix = id % image_width;
  const int y_pix = id / image_width;

  float4 world_pos =
    vmult(view_to_world(eye, look, up),
    vmult(screen_to_view(image_width, image_height, fovy),
    (float4)(x_pix, y_pix, 1, 1)
  ));

  Ray ray;
  ray.origin = eye;
  ray.direction = normalize((world_pos / world_pos.w).xyz - eye);

  random_seed = random_seed * id * id;
  mwc64x_state_t rand_state = init_rand_state(random_seed);
  MWC64X_Skip(&rand_state, 20);

  output[id] = rgb(pathtrace(ray, 8, &rand_state, objects, num_objects));
}


OpenCL implementation of Park-Miller PRNG

/******************************************************************************
 * @file     prngcl_pm.cl
 * @author   Vadim Demchik <vadimdi@yahoo.com>
 * @version  1.1.1
 *
 * @brief    [PRNGCL library]
 *           contains OpenCL implementation of Park-Miller pseudo-random number generator
 *
 *
 * @section  CREDITS
 *
 *   Stephen K. Park, Keith W. Miller,
 *   "Random number generators: good ones are hard to find",
 *   Communications of the ACM {\bf 31} (10), 1192 (1988).
 *
 *
 * @section  LICENSE
 *
 * Copyright (c) 2013, 2014 Vadim Demchik
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/

#ifndef PRNGCL_PM_CL
#define PRNGCL_PM_CL

#include "prngcl_common.cl"

#define PM_m_FP   (2147483647.0)
#define PM_min    1
#define PM_max    2147483646
#define PM_k      (4.6566128752457969241058E-10) // 1/(2^31-1)

#define PM_m     2147483647
#define PM_a     16807
#define PM_q     127773         // (PM_m div PM_a)
#define PM_r     2836           // (PM_m mod PM_a)

//________________________________________________________________________________________________________ PARK-MILLER PRNG
//
// Stephen K. Park and Keith W. Miller
// "Random number generators: good ones are hard to find"
// Communications of the ACM 31 (10), 1192 (1988).
//

__attribute__((always_inline)) void
pm_step(uint4* seed)
//
// produces PRNs in range [1;2147483646]
// if seed=1 then 10001th = 1043618065
//
{
    uint4 PM_test_1, PM_test_2;

    PM_test_1 = ((uint) PM_a) * ((*seed) % PM_q);
    PM_test_2 = ((uint) PM_r) * ((*seed) / PM_q);

    if (PM_test_1.x > PM_test_2.x) (*seed).x = PM_test_1.x - PM_test_2.x; else (*seed).x = PM_test_1.x - PM_test_2.x + (uint) PM_m;
    if (PM_test_1.y > PM_test_2.y) (*seed).y = PM_test_1.y - PM_test_2.y; else (*seed).y = PM_test_1.y - PM_test_2.y + (uint) PM_m;
    if (PM_test_1.z > PM_test_2.z) (*seed).z = PM_test_1.z - PM_test_2.z; else (*seed).z = PM_test_1.z - PM_test_2.z + (uint) PM_m;
    if (PM_test_1.w > PM_test_2.w) (*seed).w = PM_test_1.w - PM_test_2.w; else (*seed).w = PM_test_1.w - PM_test_2.w + (uint) PM_m;
}

__kernel void
pm(__global uint4* seed_table,
   __global hgpu_float4* randoms,
      const uint N)
{
    uint giddst = GID;
#ifdef PRECISION_DOUBLE  // if double precision is defined
    uint4 rnd1, rnd2;
    hgpu_double4 result;
#else
    float4 normal = (float4) PM_m_FP;
#endif
    uint4 seed = seed_table[GID];
    for (uint i = 0; i < N; i++) {
#ifdef PRECISION_DOUBLE // if double precision is defined
        pm_step(&seed);
        rnd1 = seed;

#ifndef PRNG_SKIP_CHECK
        bool flag = true;
        while (flag) {
#endif
            pm_step(&seed);
            rnd2 = seed;
            result = hgpu_uint4_to_double4(rnd1,rnd2,PM_min,PM_max,PM_k);

#ifndef PRNG_SKIP_CHECK
            if ((rnd1.x>PM_min) && (rnd1.x<PM_max) &&
                (rnd1.y>PM_min) && (rnd1.y<PM_max) &&
                (rnd1.z>PM_min) && (rnd1.z<PM_max) &&
                (rnd1.w>PM_min) && (rnd1.w<PM_max)) {
                flag = false;
            }
            else
                rnd1 = rnd2;
        }
#endif

        randoms[giddst] = result;
#else
        pm_step(&seed);
        randoms[giddst] = hgpu_uint4_to_float4(seed) / normal;
#endif
        giddst += GID_SIZE;
    }
    seed_table[GID] = seed;
}

#endif

/******************************************************************************
 * @file     prngcl_pm.cl
 * @author   Vadim Demchik <vadimdi@yahoo.com>
 * @version  1.1
 *
 * @brief    [PRNGCL library]
 *           contains OpenCL implementation of Park-Miller pseudo-random number generator
 *
 *
 * @section  CREDITS
 *
 *   Stephen K. Park, Keith W. Miller,
 *   "Random number generators: good ones are hard to find",
 *   Communications of the ACM {\bf 31} (10), 1192 (1988).
 *
 *
 * @section  LICENSE
 *
 * Copyright (c) 2013, Vadim Demchik
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/

#ifndef PRNGCL_PM_CL
#define PRNGCL_PM_CL

#include "prngcl_common.cl"

#define PM_m_FP   (2147483647.0)
#define PM_min    1
#define PM_max    2147483646
#define PM_k      (4.6566128752457969241058E-10) // 1/(2^31-1)

#define PM_m     2147483647
#define PM_a     16807
#define PM_q     127773         // (PM_m div PM_a)
#define PM_r     2836           // (PM_m mod PM_a)

//________________________________________________________________________________________________________ PARK-MILLER PRNG
//
// Stephen K. Park and Keith W. Miller
// "Random number generators: good ones are hard to find"
// Communications of the ACM 31 (10), 1192 (1988).
//

__attribute__((always_inline)) void
pm_step(uint4* seed)
//
// produces PRNs in range [1;2147483646]
// if seed=1 then 10001th = 1043618065
//
{
    uint4 PM_test_1, PM_test_2;

    PM_test_1 = ((uint) PM_a) * ((*seed) % PM_q);
    PM_test_2 = ((uint) PM_r) * ((*seed) / PM_q);

    if (PM_test_1.x > PM_test_2.x) (*seed).x = PM_test_1.x - PM_test_2.x; else (*seed).x = PM_test_1.x - PM_test_2.x + (uint) PM_m;
    if (PM_test_1.y > PM_test_2.y) (*seed).y = PM_test_1.y - PM_test_2.y; else (*seed).y = PM_test_1.y - PM_test_2.y + (uint) PM_m;
    if (PM_test_1.z > PM_test_2.z) (*seed).z = PM_test_1.z - PM_test_2.z; else (*seed).z = PM_test_1.z - PM_test_2.z + (uint) PM_m;
    if (PM_test_1.w > PM_test_2.w) (*seed).w = PM_test_1.w - PM_test_2.w; else (*seed).w = PM_test_1.w - PM_test_2.w + (uint) PM_m;
}

__kernel void
pm(__global uint4* seed_table,
   __global hgpu_float4* randoms,
      const uint N)
{
    uint giddst = GID;
#ifdef PRECISION_DOUBLE  // if double precision is defined
    uint4 rnd1, rnd2;
    hgpu_double4 result;
#else
    float4 normal = (float4) PM_m_FP;
#endif
    uint4 seed = seed_table[GID];
    for (uint i = 0; i < N; i++) {
#ifdef PRECISION_DOUBLE // if double precision is defined

        bool flag = true;
        while (flag) {
            pm_step(&seed);
            rnd1 = seed;
            if ((rnd1.x>PM_min) && (rnd1.x<PM_max) &&
                (rnd1.y>PM_min) && (rnd1.y<PM_max) &&
                (rnd1.z>PM_min) && (rnd1.z<PM_max) &&
                (rnd1.w>PM_min) && (rnd1.w<PM_max)) {
                pm_step(&seed);
                rnd2 = seed;
                result = hgpu_uint4_to_double4(rnd1,rnd2,PM_min,PM_max,PM_k);
                flag = false;
            }
        }
        randoms[giddst] = result;
#else
        pm_step(&seed);
        randoms[giddst] = hgpu_uint4_to_float4(seed) / normal;
#endif
        giddst += GID_SIZE;
    }
    seed_table[GID] = seed;
}

#endif


Add __builtin_expect to if statements

Add __builtin_expect to if statements

// Evolve the scalar wave equation with Dirichlet boundaries

/* This kernel is very short. To run efficiently, probably the
   following optimizations need to occur:
   - Vectorization (with the device's natural vector length)
   - Maybe: Loop unrolling with small 3D blocks
   - Small explicit 3D loops (to amortize stencil loads, aka "loop
     blocking")
   - Multi-threading (aka parallelization)
   - Hoist setup operations (mostly integer operations) out of the
     kernel loop
   None of these are implemented explicitly here. We could provide
   several optimized versions, and then compare with pocl's
   capabilities.
 */

typedef struct grid_t {
  double dt;                    // time step
  double dx, dy, dz;            // resolution
  int ai, aj, ak;               // allocated size
  int ni, nj, nk;               // used size
} grid_t;

void
scalarwave(global double       *restrict const phi,
           global double const *restrict const phi_p,
           global double const *restrict const phi_p_p,
           constant grid_t     *restrict const grid)
{
  /* printf("dt=%g\n", grid->dt); */
  /* printf("dxyz=[%g,%g,%g]\n", grid->dx, grid->dy, grid->dz); */
  /* printf("aijk=[%d,%d,%d]\n", grid->ai, grid->aj, grid->ak); */
  /* printf("nijk=[%d,%d,%d]\n", grid->ni, grid->nj, grid->nk); */

  double const dt = grid->dt;

  double const dx = grid->dx;
  double const dy = grid->dy;
  double const dz = grid->dz;

  double const dt2 = pown(dt,2);

  double const idx2 = pown(dx,-2);
  double const idy2 = pown(dy,-2);
  double const idz2 = pown(dz,-2);

  size_t const ai = grid->ai;
  size_t const aj = grid->aj;
  size_t const ak = grid->ak;

  size_t const ni = grid->ni;
  size_t const nj = grid->nj;
  size_t const nk = grid->nk;

  size_t const di = 1;
  size_t const dj = di * ai;
  size_t const dk = dj * aj;

#if 0
  printf("work_dim     =%u\n", get_work_dim());
  printf("global_size  =[%zu,%zu,%zu]\n", get_global_size(0), get_global_size(1), get_global_size(2));
  printf("global_id    =[%zu,%zu,%zu]\n", get_global_id(0), get_global_id(1), get_global_id(2));
  printf("local_size   =[%zu,%zu,%zu]\n", get_local_size(0), get_local_size(1), get_local_size(2));
  printf("local_id     =[%zu,%zu,%zu]\n", get_local_id(0), get_local_id(1), get_local_id(2));
  printf("num_groups   =[%zu,%zu,%zu]\n", get_num_groups(0), get_num_groups(1), get_num_groups(2));
  printf("group_id     =[%zu,%zu,%zu]\n", get_group_id(0), get_group_id(1), get_group_id(2));
  printf("global_offset=[%zu,%zu,%zu]\n", get_global_offset(0), get_global_offset(1), get_global_offset(2));
#endif

  size_t const i = get_global_id(0);
  size_t const j = get_global_id(1);
  size_t const k = get_global_id(2);

  // If outside the domain, do nothing
  if (__builtin_expect(i>=ni || j>=nj || k>=nk, false)) return;

  size_t const ind3d = di*i + dj*j + dk*k;

  if (__builtin_expect(i==0 || j==0 || k==0 || i==ni-1 || j==nj-1 || k==nk-1,
                       false))
  {
    // Boundary condition

    phi[ind3d] = 0.0;

  } else {
    // Scalar wave equation

    phi[ind3d] =
      2.0 * phi_p[ind3d] - phi_p_p[ind3d] +
      dt2 * ((phi_p[ind3d-di] - 2.0*phi_p[ind3d] + phi_p[ind3d+di]) * idx2 +
             (phi_p[ind3d-dj] - 2.0*phi_p[ind3d] + phi_p[ind3d+dj]) * idy2 +
             (phi_p[ind3d-dk] - 2.0*phi_p[ind3d] + phi_p[ind3d+dk]) * idz2);

  }
}

// Evolve the scalar wave equation with Dirichlet boundaries

/* This kernel is very short. To run efficiently, probably the
   following optimizations need to occur:
   - Vectorization (with the device's natural vector length)
   - Maybe: Loop unrolling with small 3D blocks
   - Small explicit 3D loops (to amortize stencil loads, aka "loop
     blocking")
   - Multi-threading (aka parallelization)
   - Hoist setup operations (mostly integer operations) out of the
     kernel loop
   None of these are implemented explicitly here. We could provide
   several optimized versions, and then compare with pocl's
   capabilities.
 */

typedef struct grid_t {
  double dt;                    // time step
  double dx, dy, dz;            // resolution
  int ai, aj, ak;               // allocated size
  int ni, nj, nk;               // used size
} grid_t;

void
scalarwave(global double       *restrict const phi,
           global double const *restrict const phi_p,
           global double const *restrict const phi_p_p,
           constant grid_t     *restrict const grid)
{
  /* printf("dt=%g\n", grid->dt); */
  /* printf("dxyz=[%g,%g,%g]\n", grid->dx, grid->dy, grid->dz); */
  /* printf("aijk=[%d,%d,%d]\n", grid->ai, grid->aj, grid->ak); */
  /* printf("nijk=[%d,%d,%d]\n", grid->ni, grid->nj, grid->nk); */

  double const dt = grid->dt;

  double const dx = grid->dx;
  double const dy = grid->dy;
  double const dz = grid->dz;

  double const dt2 = pown(dt,2);

  double const idx2 = pown(dx,-2);
  double const idy2 = pown(dy,-2);
  double const idz2 = pown(dz,-2);

  size_t const ai = grid->ai;
  size_t const aj = grid->aj;
  size_t const ak = grid->ak;

  size_t const ni = grid->ni;
  size_t const nj = grid->nj;
  size_t const nk = grid->nk;

  size_t const di = 1;
  size_t const dj = di * ai;
  size_t const dk = dj * aj;

#if 0
  printf("work_dim     =%u\n", get_work_dim());
  printf("global_size  =[%zu,%zu,%zu]\n", get_global_size(0), get_global_size(1), get_global_size(2));
  printf("global_id    =[%zu,%zu,%zu]\n", get_global_id(0), get_global_id(1), get_global_id(2));
  printf("local_size   =[%zu,%zu,%zu]\n", get_local_size(0), get_local_size(1), get_local_size(2));
  printf("local_id     =[%zu,%zu,%zu]\n", get_local_id(0), get_local_id(1), get_local_id(2));
  printf("num_groups   =[%zu,%zu,%zu]\n", get_num_groups(0), get_num_groups(1), get_num_groups(2));
  printf("group_id     =[%zu,%zu,%zu]\n", get_group_id(0), get_group_id(1), get_group_id(2));
  printf("global_offset=[%zu,%zu,%zu]\n", get_global_offset(0), get_global_offset(1), get_global_offset(2));
#endif

  size_t const i = get_global_id(0);
  size_t const j = get_global_id(1);
  size_t const k = get_global_id(2);

  // If outside the domain, do nothing
  if (i>=ni || j>=nj || k>=nk) return;

  size_t const ind3d = di*i + dj*j + dk*k;

  if (i==0 || i==ni-1 || j==0 || j==nj-1 || k==0 || k==nk-1) {
    // Boundary condition

    phi[ind3d] = 0.0;

  } else {
    // Scalar wave equation

    phi[ind3d] =
      2.0 * phi_p[ind3d] - phi_p_p[ind3d] +
      dt2 * ((phi_p[ind3d-di] - 2.0*phi_p[ind3d] + phi_p[ind3d+di]) * idx2 +
             (phi_p[ind3d-dj] - 2.0*phi_p[ind3d] + phi_p[ind3d+dj]) * idy2 +
             (phi_p[ind3d-dk] - 2.0*phi_p[ind3d] + phi_p[ind3d+dk]) * idz2);

  }
}


plexfix: handle directories of files

plexfix: handle directories of files

Often we get a directory of files.  Handle that.
Added command line -m for mailing results.

;; plexfix :: fix filenames for Plex Media Server
;;
;; TODO:
;;  - handle rar files

(eval-when (compile eval load)
  ;;(require :anydate)
  (require :list2)
  (require :acldns)
  (require :smtp)
  (require :osi)
  (require :shell)
  (require :autozoom)
  (require :tget-utils "utils.fasl"))

(defpackage :cl-user
  (:use #:common-lisp
	#:excl
	#:excl.osi
	#:excl.shell
	#:net.post-office))

(in-package :cl-user)

(defvar *debug* nil)
(defvar *no-execute* nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun plexfix (stream filename)
  (if* (not (probe-file filename))
     then (.error "~a does not exist." filename)
   elseif (file-directory-p filename)
     then (let ((files (directory (pathname-as-directory filename))))
	    (if* (member "rar" files :key #'pathname-type :test #'string=)
	       then (.error "Can't handle rar files yet: ~a." filename)
	       else (dolist (file files)
		      ;; handle mp4 and mkv files, for now, warn of the
		      ;; rest, ignoring some known files
		      (if* (member (pathname-type file) '("mp4" "mkv")
				   :test #'string=)
			 then (plexfix-1 stream file)
		       elseif (member (pathname-type file)
				      '("nfo" "txt" "srt")
				      :test #'string=)
			 thenret
			 else (format stream "Unknown file:~a.~%" file)))))
     else (plexfix-1 stream filename)))

(defun plexfix-1 (stream filename &aux new-name type)
  (multiple-value-bind (series-name season episode pms-fail year month day)
      (parse-name-season-and-episode (file-namestring filename)
				     :episode-required t
				     :junk-allowed t)
    (when (not pms-fail) (return-from plexfix-1 nil))

    ;; PMS will not see this file, so make a symlink for it that it will
    ;; see.
    (setq type (pathname-type filename))
    (setq new-name
      (if* year
	 then ;; date-based name
	      (format nil "~a.~d.~2,'0d.~2,'0d.~a"
		      series-name year month day type)
	 else (format nil "~a.S~2,'0dE~2,'0d.~a"
		      series-name season episode type)))
    (with-verbosity 2
      (format stream "OLD name: ~a~%" filename)
      (format stream "NEW name: ~a~%" new-name))

    (if* *no-execute*
       then (format stream "Would symlink ~a ~a~%" filename new-name)
       else (symlink filename new-name))

    ;; Look for .srt file with the same name, and make a symlink for that,
    ;; too.  The Roku can't use subtitles unless the file has the same
    ;; name!
    (let ((srt (merge-pathnames (make-pathname :type "srt")
				filename))
	  new-srt)
      (when (probe-file srt)
	(with-verbosity 1
	  (format stream "Making link for srt file, too.~%"))
	(setq new-srt (merge-pathnames (make-pathname :type "srt") new-name))
	(if* *no-execute*
	   then (format stream "Would symlink ~a ~a~%" srt new-srt)
	   else (symlink srt new-srt))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define-condition plexfix (error) ())

(defun .error (format-string &rest format-arguments)
  ;; This separates known tget errors from unexpected program errors.  All
  ;; calls to error in this code should be to this function.  Any calls to
  ;; error or cerror cause a stack trace.
  (error 'plexfix :format-control format-string
	 :format-arguments format-arguments))

(defun user::main (&aux (stream t))
  (flet
      ((send-output ()
	 (ignore-errors
	  (when (not (eq 't stream))
	    (send-letter "192.168.0.1"
			 (sys:getenv "USER")
			 (sys:getenv "USER")
			 (get-output-stream-string stream)
			 :subject "plexfix"))))
       (doit (&aux torrent-dir torrent-name)
	 (system:with-command-line-arguments
	     (("d" :short debug)
	      ("m" :short email :required-companion)
	      ("n" :short no-execute)
	      ("q" :short quiet)
	      ("v" :short verbose :allow-multiple-options))
	     (rest)
	   (if* (and (null rest)
		     (setq torrent-dir (sys:getenv "TR_TORRENT_DIR"))
		     (setq torrent-name (sys:getenv "TR_TORRENT_NAME")))
	      then ;; called from Transmission
		   (setq rest
		     (list (format nil "~a~a" torrent-dir torrent-name)))
	    elseif (or (null rest) (/= 1 (length rest)))
	      then (.error "usage: plexfix file."))
	   (when debug (setq *debug* t))
	   (when no-execute (setq *no-execute* t))
	   (setq *verbose* (or verbose
			       (when quiet 0)
			       1))
	   (when (and (not debug) email)
	     (setq stream (make-string-output-stream)))
	   (plexfix stream (car rest)))))

    (if* *debug* ;; -d on command line doesn't effect this test!
       then (format t ";;;NOTE: debugging mode is on~%")
	    (doit)
       else (top-level.debug:with-auto-zoom-and-exit (*standard-output*)
	      (handler-case (doit)
		(plexfix (c)
		  ;; 'plexfix errors don't get a backtrace, since those are
		  ;; expected or, at least, planned for.  The unexpected
		  ;; ones get the zoom.
		  (format stream "~&~a~&" c)
		  (send-output)
		  (exit 1 :quiet t)))))
    (send-output)
    (exit 0 :quiet t)))

;; plexfix :: fix filenames for Plex Media Server

(eval-when (compile eval load)
  ;;(require :anydate)
  (require :osi)
  (require :shell)
  (require :autozoom)
  (require :tget-utils "utils.fasl"))

(defpackage :cl-user
  (:use #:common-lisp
	#:excl
	#:excl.osi
	#:excl.shell))

(in-package :cl-user)

(defvar *debug* nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun plexfix (filename &aux new-name type)
  (multiple-value-bind (series-name season episode pms-fail year month day)
      (parse-name-season-and-episode filename :episode-required t
				     :junk-allowed t)
    (when (not pms-fail) (return-from plexfix nil))

    ;; PMS will not see this file, so make a symlink for it that it will
    ;; see.
    (setq type (pathname-type filename))
    (setq new-name
      (if* year
	 then ;; date-based name
	      (format nil "~a.~d.~2,'0d.~2,'0d.~a"
		      series-name year month day type)
	 else (format nil "~a.S~2,'0dE~2,'0d.~a"
		      series-name season episode type)))
    (with-verbosity 2
      (format t "OLD name: ~a~%" filename)
      (format t "NEW name: ~a~%" new-name))
    (if* (probe-file filename)
       then (symlink filename new-name)
       else (.error "~a does not exist." filename))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define-condition plexfix (error) ())

(defun .error (format-string &rest format-arguments)
  ;; This separates known tget errors from unexpected program errors.  All
  ;; calls to error in this code should be to this function.  Any calls to
  ;; error or cerror cause a stack trace.
  (error 'plexfix :format-control format-string
	 :format-arguments format-arguments))

(defun user::main ()
  (flet
      ((doit (&aux torrent-dir torrent-name)
	 (system:with-command-line-arguments
	     (("d" :short debug)
	      ("q" :short quiet)
	      ("v" :short verbose :allow-multiple-options))
	     (rest)
	   (if* (and (null rest)
		     (setq torrent-dir (sys:getenv "TR_TORRENT_DIR"))
		     (setq torrent-name (sys:getenv "TR_TORRENT_NAME")))
	      then ;; called from Transmission
		   (setq rest
		     (list (format nil "~a~a" torrent-dir torrent-name)))
	    elseif (or (null rest) (/= 1 (length rest)))
	      then (.error "usage: plexfix file."))
	   (when debug (setq *debug* t))
	   (setq *verbose* (or verbose
			       (when quiet 0)
			       1))
	   (plexfix (car rest))
	   (exit 0))))

    (if* *debug* ;; -d on command line doesn't effect this test!
       then (format t ";;;NOTE: debugging mode is on~%")
	    (doit)
       else (top-level.debug:with-auto-zoom-and-exit (*standard-output*)
	      (handler-case (doit)
		(plexfix (c)
		  ;; 'plexfix errors don't get a backtrace, since those are
		  ;; expected or, at least, planned for.  The unexpected
		  ;; ones get the zoom.
		  (format t "~&~a~&" c)
		  (exit 1 :quiet t)))))))


Fix the edgeTraceKernel for CPU devices

Fix the edgeTraceKernel for CPU devices

The barrier in the while loop is necessary for Intel CPUs and maybe other
platforms to work correctly. I am not sure why it is required because we seem to
be performing sufficient synchronization otherwise.

/*******************************************************
 * Copyright (c) 2017, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#define STRONG 1
#define WEAK 2
#define NOEDGE 0

#if defined(INIT_EDGE_OUT)
kernel void initEdgeOutKernel(global T* output, KParam oInfo,
                                global const T* strong, KParam sInfo,
                                global const T* weak, KParam wInfo,
                                unsigned nBBS0, unsigned nBBS1) {
    // batch offsets for 3rd and 4th dimension
    const unsigned b2 = get_group_id(0) / nBBS0;
    const unsigned b3 = get_group_id(1) / nBBS1;

    // global indices
    const int gx =
        get_local_size(0) * (get_group_id(0) - b2 * nBBS0) + get_local_id(0);
    const int gy =
        get_local_size(1) * (get_group_id(1) - b3 * nBBS1) + get_local_id(1);

    // Offset input and output pointers to second pixel of second coloumn/row
    // to skip the border
    global const T* wPtr =
        weak + (b2 * wInfo.strides[2] + b3 * wInfo.strides[3] + wInfo.offset) +
        wInfo.strides[1] + 1;

    global const T* sPtr =
        strong +
        (b2 * sInfo.strides[2] + b3 * sInfo.strides[3] + sInfo.offset) +
        sInfo.strides[1] + 1;

    global T* oPtr =
        output +
        (b2 * oInfo.strides[2] + b3 * oInfo.strides[3] + oInfo.offset) +
        oInfo.strides[1] + 1;

    if (gx < (oInfo.dims[0] - 2) && gy < (oInfo.dims[1] - 2)) {
        int idx   = gx * oInfo.strides[0] + gy * oInfo.strides[1];
        oPtr[idx] = (sPtr[idx] > 0 ? STRONG : (wPtr[idx] > 0 ? WEAK : NOEDGE));
    }
}
#endif

#define VALID_BLOCK_IDX(j, i)                             \
    ((j) > 0 && (j) < (SHRD_MEM_HEIGHT - 1) && (i) > 0 && \
     (i) < (SHRD_MEM_WIDTH - 1))

#if defined(EDGE_TRACER)
kernel void edgeTrackKernel(global T* output, KParam oInfo, unsigned nBBS0,
                              unsigned nBBS1,
                              global volatile int* hasChanged) {
    // shared memory with 1 pixel border
    // strong and weak images are binary(char) images thus,
    // occupying only (16+2)*(16+2) = 324 bytes per shared memory tile
    local int outMem[SHRD_MEM_HEIGHT][SHRD_MEM_WIDTH];
    local bool predicates[TOTAL_NUM_THREADS];

    // local thread indices
    const int lx = get_local_id(0);
    const int ly = get_local_id(1);

    // batch offsets for 3rd and 4th dimension
    const unsigned b2 = get_group_id(0) / nBBS0;
    const unsigned b3 = get_group_id(1) / nBBS1;

    // global indices
    const int gx = get_local_size(0) * (get_group_id(0) - b2 * nBBS0) + lx;
    const int gy = get_local_size(1) * (get_group_id(1) - b3 * nBBS1) + ly;

    // Offset input and output pointers to second pixel of second coloumn/row
    // to skip the border
    global T* oPtr = output + (b2 * oInfo.strides[2] + b3 * oInfo.strides[3]);

    // pull image to local memory
#pragma unroll
    for (int b = ly, gy2 = gy - 1; b < SHRD_MEM_HEIGHT;
         b += get_local_size(1), gy2 += get_local_size(1)) {
#pragma unroll
        for (int a = lx, gx2 = gx - 1; a < SHRD_MEM_WIDTH;
             a += get_local_size(0), gx2 += get_local_size(0)) {
            if (gx2 >= 0 && gx2 < oInfo.dims[0] && gy2 >= 0 &&
                gy2 < oInfo.dims[1])
                outMem[b][a] =
                    oPtr[gx2 * oInfo.strides[0] + gy2 * oInfo.strides[1]];
            else
                outMem[b][a] = NOEDGE;
        }
    }

    int i = lx + 1;
    int j = ly + 1;

    barrier(CLK_LOCAL_MEM_FENCE);

    int tid = lx + get_local_size(0) * ly;

    bool continueIter = 1;

    int mycounter = 0;
    while (continueIter) {
        int nw, no, ne, we, ea, sw, so, se;

        if (outMem[j][i] == WEAK) {
            nw = outMem[j - 1][i - 1];
            no = outMem[j - 1][i];
            ne = outMem[j - 1][i + 1];
            we = outMem[j][i - 1];
            ea = outMem[j][i + 1];
            sw = outMem[j + 1][i - 1];
            so = outMem[j + 1][i];
            se = outMem[j + 1][i + 1];

            bool hasStrongNeighbour =
                nw == STRONG || no == STRONG || ne == STRONG || ea == STRONG ||
                se == STRONG || so == STRONG || sw == STRONG || we == STRONG;

            if (hasStrongNeighbour) outMem[j][i] = STRONG;
        }

        barrier(CLK_LOCAL_MEM_FENCE);

        predicates[tid] = false;
        if (outMem[j][i] == STRONG) {
            nw = outMem[j - 1][i - 1] == WEAK && VALID_BLOCK_IDX(j - 1, i - 1);
            no = outMem[j - 1][i] == WEAK && VALID_BLOCK_IDX(j - 1, i);
            ne = outMem[j - 1][i + 1] == WEAK && VALID_BLOCK_IDX(j - 1, i + 1);
            we = outMem[j][i - 1] == WEAK && VALID_BLOCK_IDX(j, i - 1);
            ea = outMem[j][i + 1] == WEAK && VALID_BLOCK_IDX(j, i + 1);
            sw = outMem[j + 1][i - 1] == WEAK && VALID_BLOCK_IDX(j + 1, i - 1);
            so = outMem[j + 1][i] == WEAK && VALID_BLOCK_IDX(j + 1, i);
            se = outMem[j + 1][i + 1] == WEAK && VALID_BLOCK_IDX(j + 1, i + 1);

            bool hasWeakNeighbour =
                nw || no || ne || ea || se || so || sw || we;

            predicates[tid] = hasWeakNeighbour;
        }
        barrier(CLK_LOCAL_MEM_FENCE);

        // Following Block is equivalent of __syncthreads_or in CUDA
        for (int nt = TOTAL_NUM_THREADS / 2; nt > 0; nt >>= 1) {
            if (tid < nt) {
                predicates[tid] = predicates[tid] || predicates[tid + nt];
            }
            barrier(CLK_LOCAL_MEM_FENCE);
        }

        continueIter = predicates[0];

        // Needed for Intel OpenCL implementation targeting CPUs
        barrier(CLK_LOCAL_MEM_FENCE);
    }

    // Check if any 1-pixel border ring
    // has weak pixels with strong candidates
    // within the main region, then increment hasChanged.
    int cu = outMem[j][i];
    int nw = outMem[j - 1][i - 1];
    int no = outMem[j - 1][i];
    int ne = outMem[j - 1][i + 1];
    int ea = outMem[j][i + 1];
    int se = outMem[j + 1][i + 1];
    int so = outMem[j + 1][i];
    int sw = outMem[j + 1][i - 1];
    int we = outMem[j][i - 1];

    bool hasWeakNeighbour = nw == WEAK || no == WEAK || ne == WEAK ||
                            ea == WEAK || se == WEAK || so == WEAK ||
                            sw == WEAK || we == WEAK;

    // Following Block is equivalent of __syncthreads_or in CUDA
    predicates[tid] = cu == STRONG && hasWeakNeighbour;
    barrier(CLK_LOCAL_MEM_FENCE);

    for (int nt = TOTAL_NUM_THREADS / 2; nt > 0; nt >>= 1) {
        if (tid < nt) predicates[tid] = predicates[tid] || predicates[tid + nt];
        barrier(CLK_LOCAL_MEM_FENCE);
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    continueIter = predicates[0];

    if (continueIter && lx == 0 && ly == 0) atomic_inc(hasChanged);

    // Update output with shared memory result
    if (gx < (oInfo.dims[0] - 1) && gy < (oInfo.dims[1] - 1))
        oPtr[(gx * oInfo.strides[0] + gy * oInfo.strides[1])] = outMem[j][i];
}
#endif

#if defined(SUPPRESS_LEFT_OVER)
kernel void suppressLeftOverKernel(global T* output, KParam oInfo,
                                     unsigned nBBS0, unsigned nBBS1) {
    // batch offsets for 3rd and 4th dimension
    const unsigned b2 = get_group_id(0) / nBBS0;
    const unsigned b3 = get_group_id(1) / nBBS1;

    // global indices
    const int gx =
        get_local_size(0) * (get_group_id(0) - b2 * nBBS0) + get_local_id(0);
    const int gy =
        get_local_size(1) * (get_group_id(1) - b3 * nBBS1) + get_local_id(1);

    // Offset input and output pointers to second pixel of second coloumn/row
    // to skip the border
    global T* oPtr = output +
                       (b2 * oInfo.strides[2] + b3 * oInfo.strides[3]) +
                       oInfo.strides[1] + 1;

    if (gx < (oInfo.dims[0] - 2) && gy < (oInfo.dims[1] - 2)) {
        int idx = gx * oInfo.strides[0] + gy * oInfo.strides[1];
        T val   = oPtr[idx];
        if (val == WEAK) oPtr[idx] = NOEDGE;
    }
}
#endif

/*******************************************************
 * Copyright (c) 2017, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

__constant int STRONG = 1;
__constant int WEAK   = 2;
__constant int NOEDGE = 0;

#if defined(INIT_EDGE_OUT)
kernel void initEdgeOutKernel(global T* output, KParam oInfo,
                                global const T* strong, KParam sInfo,
                                global const T* weak, KParam wInfo,
                                unsigned nBBS0, unsigned nBBS1) {
    // batch offsets for 3rd and 4th dimension
    const unsigned b2 = get_group_id(0) / nBBS0;
    const unsigned b3 = get_group_id(1) / nBBS1;

    // global indices
    const int gx =
        get_local_size(0) * (get_group_id(0) - b2 * nBBS0) + get_local_id(0);
    const int gy =
        get_local_size(1) * (get_group_id(1) - b3 * nBBS1) + get_local_id(1);

    // Offset input and output pointers to second pixel of second coloumn/row
    // to skip the border
    global const T* wPtr =
        weak + (b2 * wInfo.strides[2] + b3 * wInfo.strides[3] + wInfo.offset) +
        wInfo.strides[1] + 1;

    global const T* sPtr =
        strong +
        (b2 * sInfo.strides[2] + b3 * sInfo.strides[3] + sInfo.offset) +
        sInfo.strides[1] + 1;

    global T* oPtr =
        output +
        (b2 * oInfo.strides[2] + b3 * oInfo.strides[3] + oInfo.offset) +
        oInfo.strides[1] + 1;

    if (gx < (oInfo.dims[0] - 2) && gy < (oInfo.dims[1] - 2)) {
        int idx   = gx * oInfo.strides[0] + gy * oInfo.strides[1];
        oPtr[idx] = (sPtr[idx] > 0 ? STRONG : (wPtr[idx] > 0 ? WEAK : NOEDGE));
    }
}
#endif

#define VALID_BLOCK_IDX(j, i)                             \
    ((j) > 0 && (j) < (SHRD_MEM_HEIGHT - 1) && (i) > 0 && \
     (i) < (SHRD_MEM_WIDTH - 1))

#if defined(EDGE_TRACER)
kernel void edgeTrackKernel(global T* output, KParam oInfo, unsigned nBBS0,
                              unsigned nBBS1,
                              global volatile int* hasChanged) {
    // shared memory with 1 pixel border
    // strong and weak images are binary(char) images thus,
    // occupying only (16+2)*(16+2) = 324 bytes per shared memory tile
    local int outMem[SHRD_MEM_HEIGHT][SHRD_MEM_WIDTH];
    local bool predicates[TOTAL_NUM_THREADS];

    // local thread indices
    const int lx = get_local_id(0);
    const int ly = get_local_id(1);

    // batch offsets for 3rd and 4th dimension
    const unsigned b2 = get_group_id(0) / nBBS0;
    const unsigned b3 = get_group_id(1) / nBBS1;

    // global indices
    const int gx = get_local_size(0) * (get_group_id(0) - b2 * nBBS0) + lx;
    const int gy = get_local_size(1) * (get_group_id(1) - b3 * nBBS1) + ly;

    // Offset input and output pointers to second pixel of second coloumn/row
    // to skip the border
    global T* oPtr = output + (b2 * oInfo.strides[2] + b3 * oInfo.strides[3]);

    // pull image to local memory
#pragma unroll
    for (int b = ly, gy2 = gy - 1; b < SHRD_MEM_HEIGHT;
         b += get_local_size(1), gy2 += get_local_size(1)) {
#pragma unroll
        for (int a = lx, gx2 = gx - 1; a < SHRD_MEM_WIDTH;
             a += get_local_size(0), gx2 += get_local_size(0)) {
            if (gx2 >= 0 && gx2 < oInfo.dims[0] && gy2 >= 0 &&
                gy2 < oInfo.dims[1])
                outMem[b][a] =
                    oPtr[gx2 * oInfo.strides[0] + gy2 * oInfo.strides[1]];
            else
                outMem[b][a] = NOEDGE;
        }
    }

    int i = lx + 1;
    int j = ly + 1;

    barrier(CLK_LOCAL_MEM_FENCE);

    int tid = lx + get_local_size(0) * ly;

    bool continueIter = 1;

    int mycounter = 0;
    while (continueIter) {
        int nw, no, ne, we, ea, sw, so, se;

        if (outMem[j][i] == WEAK) {
            nw = outMem[j - 1][i - 1];
            no = outMem[j - 1][i];
            ne = outMem[j - 1][i + 1];
            we = outMem[j][i - 1];
            ea = outMem[j][i + 1];
            sw = outMem[j + 1][i - 1];
            so = outMem[j + 1][i];
            se = outMem[j + 1][i + 1];

            bool hasStrongNeighbour =
                nw == STRONG || no == STRONG || ne == STRONG || ea == STRONG ||
                se == STRONG || so == STRONG || sw == STRONG || we == STRONG;

            if (hasStrongNeighbour) outMem[j][i] = STRONG;
        }

        barrier(CLK_LOCAL_MEM_FENCE);

        predicates[tid] = false;
        if (outMem[j][i] == STRONG) {
            nw = outMem[j - 1][i - 1] == WEAK && VALID_BLOCK_IDX(j - 1, i - 1);
            no = outMem[j - 1][i] == WEAK && VALID_BLOCK_IDX(j - 1, i);
            ne = outMem[j - 1][i + 1] == WEAK && VALID_BLOCK_IDX(j - 1, i + 1);
            we = outMem[j][i - 1] == WEAK && VALID_BLOCK_IDX(j, i - 1);
            ea = outMem[j][i + 1] == WEAK && VALID_BLOCK_IDX(j, i + 1);
            sw = outMem[j + 1][i - 1] == WEAK && VALID_BLOCK_IDX(j + 1, i - 1);
            so = outMem[j + 1][i] == WEAK && VALID_BLOCK_IDX(j + 1, i);
            se = outMem[j + 1][i + 1] == WEAK && VALID_BLOCK_IDX(j + 1, i + 1);

            bool hasWeakNeighbour =
                nw || no || ne || ea || se || so || sw || we;

            predicates[tid] = hasWeakNeighbour;
        }
        barrier(CLK_LOCAL_MEM_FENCE);

        // Following Block is equivalent of __syncthreads_or in CUDA
        for (int nt = TOTAL_NUM_THREADS / 2; nt > 0; nt >>= 1) {
            if (tid < nt) {
                predicates[tid] = predicates[tid] || predicates[tid + nt];
            }
            barrier(CLK_LOCAL_MEM_FENCE);
        }

        continueIter = predicates[0];
    };

    // Check if any 1-pixel border ring
    // has weak pixels with strong candidates
    // within the main region, then increment hasChanged.
    int cu = outMem[j][i];
    int nw = outMem[j - 1][i - 1];
    int no = outMem[j - 1][i];
    int ne = outMem[j - 1][i + 1];
    int ea = outMem[j][i + 1];
    int se = outMem[j + 1][i + 1];
    int so = outMem[j + 1][i];
    int sw = outMem[j + 1][i - 1];
    int we = outMem[j][i - 1];

    bool hasWeakNeighbour = nw == WEAK || no == WEAK || ne == WEAK ||
                            ea == WEAK || se == WEAK || so == WEAK ||
                            sw == WEAK || we == WEAK;

    // Following Block is equivalent of __syncthreads_or in CUDA
    predicates[tid] = cu == STRONG && hasWeakNeighbour;
    barrier(CLK_LOCAL_MEM_FENCE);

    for (int nt = TOTAL_NUM_THREADS / 2; nt > 0; nt >>= 1) {
        if (tid < nt) predicates[tid] = predicates[tid] || predicates[tid + nt];
        barrier(CLK_LOCAL_MEM_FENCE);
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    continueIter = predicates[0];

    if (continueIter && lx == 0 && ly == 0) atomic_inc(hasChanged);

    // Update output with shared memory result
    if (gx < (oInfo.dims[0] - 1) && gy < (oInfo.dims[1] - 1))
        oPtr[(gx * oInfo.strides[0] + gy * oInfo.strides[1])] = outMem[j][i];
}
#endif

#if defined(SUPPRESS_LEFT_OVER)
kernel void suppressLeftOverKernel(global T* output, KParam oInfo,
                                     unsigned nBBS0, unsigned nBBS1) {
    // batch offsets for 3rd and 4th dimension
    const unsigned b2 = get_group_id(0) / nBBS0;
    const unsigned b3 = get_group_id(1) / nBBS1;

    // global indices
    const int gx =
        get_local_size(0) * (get_group_id(0) - b2 * nBBS0) + get_local_id(0);
    const int gy =
        get_local_size(1) * (get_group_id(1) - b3 * nBBS1) + get_local_id(1);

    // Offset input and output pointers to second pixel of second coloumn/row
    // to skip the border
    global T* oPtr = output +
                       (b2 * oInfo.strides[2] + b3 * oInfo.strides[3]) +
                       oInfo.strides[1] + 1;

    if (gx < (oInfo.dims[0] - 2) && gy < (oInfo.dims[1] - 2)) {
        int idx = gx * oInfo.strides[0] + gy * oInfo.strides[1];
        T val   = oPtr[idx];
        if (val == WEAK) oPtr[idx] = NOEDGE;
    }
}
#endif


Fix minor type in apidef

Fix minor type in apidef

;definitions manually adapted from sensekit_capi.h

(setq voidparam (make-param :type "void*" :name "streamService"))

;SENSEKIT_API sensekit_status_t sensekit_initialize();
(add-func 	:returntype "sensekit_status_t"
			:funcname "initialize"
			:params '()
)

;SENSEKIT_API sensekit_status_t sensekit_terminate();
(add-func 	:returntype "sensekit_status_t"
			:funcname "terminate"
			:params '()
)

;SENSEKIT_API sensekit_status_t sensekit_streamset_open(const char* connectionString,
;                                                       sensekit_streamset_t** streamSet);
(add-func 	:returntype "sensekit_status_t"
			:funcname "streamset_open"
			:params (list (make-param :type "const char*" :name "connectionString")
						  (make-param :type "sensekit_streamset_t**" :name "streamSet" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_streamset_close(sensekit_streamset_t** streamSet);
(add-func 	:returntype "sensekit_status_t"
			:funcname "streamset_close"
			:params (list (make-param :type "sensekit_streamset_t**" :name "streamSet" :deref T)
					)
)

;SENSEKIT_API char* sensekit_get_status_string(sensekit_status_t status);
(add-func 	:returntype "char*"
			:funcname "get_status_string"
			:params (list (make-param :type "sensekit_status_t" :name "status")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_create(sensekit_streamset_t* streamSet,
;                                                      sensekit_reader_t** reader);
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_create"
			:params (list (make-param :type "sensekit_streamset_t*" :name "streamSet")
						 (make-param :type "sensekit_reader_t**" :name "reader" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_destroy(sensekit_reader_t** reader);
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_destroy"
			:params (list (make-param :type "sensekit_reader_t**" :name "reader" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_get_stream(sensekit_reader_t* reader,
;                                                          sensekit_stream_type_t type,
;                                                          sensekit_stream_subtype_t subType,
;                                                          sensekit_streamconnection_t** connection);
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_get_stream"
			:params (list (make-param :type "sensekit_reader_t*" :name "reader")
						  (make-param :type "sensekit_stream_type_t" :name "type")
						  (make-param :type "sensekit_stream_subtype_t" :name "subType")
						  (make-param :type "sensekit_streamconnection_t**" :name "connection" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_get_description(sensekit_streamconnection_t* connection,
;                                                               sensekit_stream_desc_t* description);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_get_description"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
						  (make-param :type "sensekit_stream_desc_t*" :name "description")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_start(sensekit_streamconnection_t* connection);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_start"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_stop(sensekit_streamconnection_t* connection);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_stop"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_open_frame(sensekit_reader_t* reader,
;                                                          int timeoutMillis,
;                                                          sensekit_reader_frame_t** frame); //0 = return immediately
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_open_frame"
			:params (list (make-param :type "sensekit_reader_t*" :name "reader")
						  (make-param :type "int" :name "timeoutMillis")
						  (make-param :type "sensekit_reader_frame_t**" :name "frame" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_close_frame(sensekit_reader_frame_t** frame); //frame set to null
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_close_frame"
			:params (list (make-param :type "sensekit_reader_frame_t**" :name "frame" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_get_frame(sensekit_reader_frame_t* frame,
;                                                         sensekit_stream_type_t type,
;                                                         sensekit_stream_subtype_t subType,
;                                                         sensekit_frame_ref_t** frameRef);
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_get_frame"
			:params (list (make-param :type "sensekit_reader_frame_t*" :name "frame")
						  (make-param :type "sensekit_stream_type_t" :name "type")
						  (make-param :type "sensekit_stream_subtype_t" :name "subType")
						  (make-param :type "sensekit_frame_ref_t**" :name "frameRef" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_set_parameter(sensekit_streamconnection_t* connection,
;                                                             sensekit_parameter_id parameterId,
;                                                             size_t byteLength,
;                                                             sensekit_parameter_data_t* data);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_set_parameter"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
						  (make-param :type "sensekit_parameter_id" :name "parameterId")
						  (make-param :type "size_t" :name "byteLength")
						  (make-param :type "sensekit_parameter_data_t*" :name "data")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_get_parameter_size(sensekit_streamconnection_t* connection,
;                                                                  sensekit_parameter_id parameterId,
;                                                                  size_t* byteLength);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_get_parameter_size"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
						  (make-param :type "sensekit_parameter_id" :name "parameterId")
						  (make-param :type "size_t*" :name "byteLength" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_get_parameter_data(sensekit_streamconnection_t* connection,
;                                                                  sensekit_parameter_id parameterId,
;                                                                  size_t byteLength,
;                                                                  sensekit_parameter_data_t* data);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_get_parameter_data"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
						  (make-param :type "sensekit_parameter_id" :name "parameterId")
						  (make-param :type "size_t" :name "byteLength")
						  (make-param :type "sensekit_parameter_data_t*" :name "data")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_temp_update();
(add-func 	:returntype "sensekit_status_t"
			:funcname "temp_update"
			:params '()
)

;definitions 3manually adapted from sensekit_capi.h

(setq voidparam (make-param :type "void*" :name "streamService"))

;SENSEKIT_API sensekit_status_t sensekit_initialize();
(add-func 	:returntype "sensekit_status_t"
			:funcname "initialize"
			:params '()
)

;SENSEKIT_API void sensekit_terminate();
(add-func 	:returntype "sensekit_status_t"
			:funcname "terminate"
			:params '()
)

;SENSEKIT_API sensekit_status_t sensekit_streamset_open(const char* connectionString,
;                                                       sensekit_streamset_t** streamSet);
(add-func 	:returntype "sensekit_status_t"
			:funcname "streamset_open"
			:params (list (make-param :type "const char*" :name "connectionString")
						  (make-param :type "sensekit_streamset_t**" :name "streamSet" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_streamset_close(sensekit_streamset_t** streamSet);
(add-func 	:returntype "sensekit_status_t"
			:funcname "streamset_close"
			:params (list (make-param :type "sensekit_streamset_t**" :name "streamSet" :deref T)
					)
)

;SENSEKIT_API char* sensekit_get_status_string(sensekit_status_t status);
(add-func 	:returntype "char*"
			:funcname "get_status_string"
			:params (list (make-param :type "sensekit_status_t" :name "status")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_create(sensekit_streamset_t* streamSet,
;                                                      sensekit_reader_t** reader);
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_create"
			:params (list (make-param :type "sensekit_streamset_t*" :name "streamSet")
						 (make-param :type "sensekit_reader_t**" :name "reader" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_destroy(sensekit_reader_t** reader);
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_destroy"
			:params (list (make-param :type "sensekit_reader_t**" :name "reader" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_get_stream(sensekit_reader_t* reader,
;                                                          sensekit_stream_type_t type,
;                                                          sensekit_stream_subtype_t subType,
;                                                          sensekit_streamconnection_t** connection);
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_get_stream"
			:params (list (make-param :type "sensekit_reader_t*" :name "reader")
						  (make-param :type "sensekit_stream_type_t" :name "type")
						  (make-param :type "sensekit_stream_subtype_t" :name "subType")
						  (make-param :type "sensekit_streamconnection_t**" :name "connection" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_get_description(sensekit_streamconnection_t* connection,
;                                                               sensekit_stream_desc_t* description);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_get_description"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
						  (make-param :type "sensekit_stream_desc_t*" :name "description")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_start(sensekit_streamconnection_t* connection);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_start"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_stop(sensekit_streamconnection_t* connection);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_stop"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_open_frame(sensekit_reader_t* reader,
;                                                          int timeoutMillis,
;                                                          sensekit_reader_frame_t** frame); //0 = return immediately
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_open_frame"
			:params (list (make-param :type "sensekit_reader_t*" :name "reader")
						  (make-param :type "int" :name "timeoutMillis")
						  (make-param :type "sensekit_reader_frame_t**" :name "frame" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_close_frame(sensekit_reader_frame_t** frame); //frame set to null
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_close_frame"
			:params (list (make-param :type "sensekit_reader_frame_t**" :name "frame" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_reader_get_frame(sensekit_reader_frame_t* frame,
;                                                         sensekit_stream_type_t type,
;                                                         sensekit_stream_subtype_t subType,
;                                                         sensekit_frame_ref_t** frameRef);
(add-func 	:returntype "sensekit_status_t"
			:funcname "reader_get_frame"
			:params (list (make-param :type "sensekit_reader_frame_t*" :name "frame")
						  (make-param :type "sensekit_stream_type_t" :name "type")
						  (make-param :type "sensekit_stream_subtype_t" :name "subType")
						  (make-param :type "sensekit_frame_ref_t**" :name "frameRef" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_set_parameter(sensekit_streamconnection_t* connection,
;                                                             sensekit_parameter_id parameterId,
;                                                             size_t byteLength,
;                                                             sensekit_parameter_data_t* data);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_set_parameter"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
						  (make-param :type "sensekit_parameter_id" :name "parameterId")
						  (make-param :type "size_t" :name "byteLength")
						  (make-param :type "sensekit_parameter_data_t*" :name "data")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_get_parameter_size(sensekit_streamconnection_t* connection,
;                                                                  sensekit_parameter_id parameterId,
;                                                                  size_t* byteLength);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_get_parameter_size"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
						  (make-param :type "sensekit_parameter_id" :name "parameterId")
						  (make-param :type "size_t*" :name "byteLength" :deref T)
					)
)

;SENSEKIT_API sensekit_status_t sensekit_stream_get_parameter_data(sensekit_streamconnection_t* connection,
;                                                                  sensekit_parameter_id parameterId,
;                                                                  size_t byteLength,
;                                                                  sensekit_parameter_data_t* data);
(add-func 	:returntype "sensekit_status_t"
			:funcname "stream_get_parameter_data"
			:params (list (make-param :type "sensekit_streamconnection_t*" :name "connection")
						  (make-param :type "sensekit_parameter_id" :name "parameterId")
						  (make-param :type "size_t" :name "byteLength")
						  (make-param :type "sensekit_parameter_data_t*" :name "data")
					)
)

;SENSEKIT_API sensekit_status_t sensekit_temp_update();
(add-func 	:returntype "sensekit_status_t"
			:funcname "temp_update"
			:params '()
)