Less implicit vector advect

Less implicit vector advect

// TODO

#include "std_helpers.clh"
#include "fluid_defs.clh"
#include "solve_poisson.clh"

//
// Symbol table
// ·∇, ∇²
//

//
// du
// ── = -(u·∇)u - (1/ϱ)∇p + ν·∇²u(x, t) + F(t)
// dt
//
// w = -(u·∇)u + ν·∇²u(x, t) + F(t)
//
// w - (1/ϱ)∇p = du/dt
//

struct VoxelGridDescription {
    float3 origin_m;
    float spacing_m;
};

__kernel void apply_velocity_bdry_cond(
    __read_only image3d_t u0,
    __write_only image3d_t u1) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    // This is terrible, I know. We'll make it faster once it's stable.
    const sampler_t smp_volume_nearest =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP |
        CLK_FILTER_NEAREST;

    const int3 volume_size = (int3) (
        get_image_width(u0),
        get_image_height(u0),
        get_image_depth(u0)
    );

    const int4 unit_x = (int4) (1, 0, 0, 0);
    const int4 unit_y = (int4) (0, 1, 0, 0);
    const int4 unit_z = (int4) (0, 0, 1, 0);
    const float3 u_inner_bdry = read_imagef(u0, smp_volume_nearest, vxl_coord).xyz;
    if (vxl_coord.x == (volume_size.x - 2)) {
        write_imagef(u1, vxl_coord + unit_x, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.x == 1) {
        write_imagef(u1, vxl_coord - unit_x, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.y == (volume_size.y - 2)) {
        write_imagef(u1, vxl_coord + unit_y, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.y == 1) {
        write_imagef(u1, vxl_coord - unit_y, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.z == (volume_size.z - 2)) {
        write_imagef(u1, vxl_coord + unit_z, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.z == 1) {
        write_imagef(u1, vxl_coord - unit_z, (float4) (-u_inner_bdry, 0.0f));
    }

    // Note: There's a race condition in corners and edges
    write_imagef(u1, vxl_coord, (float4) (u_inner_bdry, 0.0f));
}

__kernel void advect_velocity(
    __read_only image3d_t vol_u_0,
    __write_only image3d_t vol_u_1,
    struct FluidSimConfig cfg) {
    //
    // u0 = vol_u_0[x]
    // vol_u_1[x] = vol_u_0[x - (u0 * dt_sec)]
    //
    const sampler_t smp_volume_interp =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP_TO_EDGE |
        CLK_FILTER_LINEAR;

    const sampler_t smp_volume_nearest =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP |
        CLK_FILTER_NEAREST;

    const int4 vxl_coordi = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);
    const float3 u0 = read_imagef(vol_u_0, smp_volume_nearest, vxl_coordi).xyz;

    const float3 vxl_coordf = convert_float4(vxl_coordi).xyz;
    const float3 u0_real_coord = (vxl_coordf / cfg.dx_m);

    const float3 u1_real_coord = u0_real_coord - (u0 * cfg.dt_sec);
    const float3 u1_vxl_coordf = u1_real_coord * cfg.dx_m;
    const int4 u1_vxl_coordi = (int4) (convert_int3(u1_vxl_coordf), 0);
    const float4 u1 = read_imagef(vol_u_0, smp_volume_interp, u1_vxl_coordi);

    float4 force = (float4) (0.0f, 0.0f, 0.0f, 0.0f);
    if ((vxl_coordi.x > 45) &&
        (vxl_coordi.x < 55) &&
        (vxl_coordi.y > 45) &&
        (vxl_coordi.y < 55) &&
        (vxl_coordi.z > 45) &&
        (vxl_coordi.z < 55)) {
        force.x = 0.1f;
        force.y = 0.1f;
        force.z = 0.1f;
    }

    force += (float4) (0.0f, -0.01f, 0.0f, 0.0f);

    float4 u1_damped = u1 + (force * cfg.dt_sec);

    write_imagef(vol_u_1, vxl_coordi, u1_damped);
}

__kernel void advect_vector(
    __read_only image3d_t vol_u_0,
    __read_only image3d_t vol_q_0,
    __write_only image3d_t vol_q_1,
    struct FluidSimConfig cfg) {
    const sampler_t smp_volume_interp =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP_TO_EDGE |
        CLK_FILTER_LINEAR;

    const sampler_t smp_volume_nearest =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP |
        CLK_FILTER_NEAREST;

    const int4 vxl_coordi = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);
    const float3 u0 = read_imagef(vol_u_0, smp_volume_nearest, vxl_coordi).xyz;

    const float3 vxl_coordf = convert_float4(vxl_coordi).xyz;
    const float3 u0_real_coord = (vxl_coordf / cfg.dx_m);

    const float3 q0_real_coord = u0_real_coord - (u0 * cfg.dt_sec);
    const float3 q0_vxl_coordf = q0_real_coord * cfg.dx_m;
    const int4 q0_vxl_coordi = (int4) (convert_int3(q0_vxl_coordf), 0);
    const float4 q0_0 = read_imagef(vol_q_0, smp_volume_interp, q0_vxl_coordi);
    // const float4 q0_1 = read_imagef(vol_q_0, smp_volume_interp, vxl_coordi);
    // const float4 q1 = (q0_0 + q0_1) * 0.5f;
    write_imagef(vol_q_1, vxl_coordi, q0_0);
}

// Viscous Diffusion
//
// du
// ── = ν·∇²u(x, t) =
// dt

__kernel void diffuse(
    __read_only image3d_t vol_u_0,
    __read_only image3d_t vol_u_next1,
    __write_only image3d_t vol_u_next2,
    struct FluidSimConfig cfg) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const float alpha = (cfg.dx_m * cfg.dx_m * cfg.dx_m) / (cfg.nu * cfg.dt_sec);
    const float beta = 6.0f + alpha;

    const float4 jacobi_iterate = poisson_step_3d_vector(
        vol_u_next1,
        vol_u_0,
        vxl_coord,
        alpha,
        beta
    );

    write_imagef(vol_u_next2, vxl_coord, jacobi_iterate);
}

__kernel void compute_divergence(
    __read_only image3d_t vol_u,
    __write_only image3d_t vol_out,
    struct FluidSimConfig cfg) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const sampler_t smp =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP_TO_EDGE |
        CLK_FILTER_NEAREST;

    const int4 unit_x = (int4) (1, 0, 0, 0);
    const int4 unit_y = (int4) (0, 1, 0, 0);
    const int4 unit_z = (int4) (0, 0, 1, 0);

    // +/- x
    const float xk_nx = read_imagef(vol_u, smp, (vxl_coord - unit_x)).x;
    const float xk_px = read_imagef(vol_u, smp, (vxl_coord + unit_x)).x;

    // +/- y
    const float xk_ny = read_imagef(vol_u, smp, (vxl_coord - unit_y)).y;
    const float xk_py = read_imagef(vol_u, smp, (vxl_coord + unit_y)).y;

    // +/- z
    const float xk_nz = read_imagef(vol_u, smp, (vxl_coord - unit_z)).z;
    const float xk_pz = read_imagef(vol_u, smp, (vxl_coord + unit_z)).z;

    const float inv_2dx = 0.5f / (cfg.dx_m);
    float div_u = (xk_pz - xk_nz) * inv_2dx;
    div_u += (xk_py - xk_ny) * inv_2dx;
    div_u += (xk_px - xk_nx) * inv_2dx;

    float4 div = (float4) (div_u, div_u, div_u, 0.0f);
    write_imagef(vol_out, vxl_coord, (float4) div_u);
}

__kernel void apply_pressure_bdry_cond(
    __read_only image3d_t p0,
    __write_only image3d_t p1) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const sampler_t smp_volume_nearest =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP |
        CLK_FILTER_NEAREST;

    const int3 volume_size = (int3) (
        get_image_width(p0),
        get_image_height(p0),
        get_image_depth(p0)
    );

    // This is terrible, I know. We'll make it faster once it's stable.

    const int4 unit_x = (int4) (1, 0, 0, 0);
    const int4 unit_y = (int4) (0, 1, 0, 0);
    const int4 unit_z = (int4) (0, 0, 1, 0);
    const float4 p_inner_bdry = read_imagef(p0, smp_volume_nearest, vxl_coord);
    if (vxl_coord.x == (volume_size.x - 2)) {
        write_imagef(p1, vxl_coord + unit_x, p_inner_bdry);
    }
    if (vxl_coord.x == 1) {
        write_imagef(p1, vxl_coord - unit_x, p_inner_bdry);
    }
    if (vxl_coord.y == (volume_size.y - 2)) {
        write_imagef(p1, vxl_coord + unit_y, p_inner_bdry);
    }
    if (vxl_coord.y == 1) {
        write_imagef(p1, vxl_coord - unit_y, p_inner_bdry);
    }
    if (vxl_coord.z == (volume_size.z - 2)) {
        write_imagef(p1, vxl_coord + unit_z, p_inner_bdry);
    }
    if (vxl_coord.z == 1) {
        write_imagef(p1, vxl_coord - unit_z, p_inner_bdry);
    }
    write_imagef(p1, vxl_coord, p_inner_bdry);
}
// du
// ── = ∇·u(x, t)
// dt
//
// w = (u + ∇p)
// ∇²p = ∇·w
__kernel void compute_pressure(
    __read_only image3d_t div_w,
    __read_only image3d_t vol_p0,
    __write_only image3d_t vol_p1,
    struct FluidSimConfig cfg) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const float alpha = -(cfg.dx_m * cfg.dx_m * cfg.dx_m);
    const float beta = 6.0f;

    const float jacobi_iterate = poisson_step_3d_scalar(
        vol_p0,
        div_w,
        vxl_coord,
        alpha,
        beta
    );
    write_imagef(vol_p1, vxl_coord, (float4) jacobi_iterate);
}

// Eliminate divergence
__kernel void chiron_projection(
    __read_only image3d_t u_divergent,
    __read_only image3d_t vol_p,
    __write_only image3d_t vol_u_1,
    struct FluidSimConfig cfg) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const sampler_t smp =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP_TO_EDGE |
        CLK_FILTER_NEAREST;

    const float3 w = read_imagef(u_divergent, smp, vxl_coord).xyz;

    const int4 unit_x = (int4) (1, 0, 0, 0);
    const int4 unit_y = (int4) (0, 1, 0, 0);
    const int4 unit_z = (int4) (0, 0, 1, 0);

    const float p0x = read_imagef(vol_p, smp, vxl_coord).x;
    const float3 p000 = (float3) (p0x, p0x, p0x);
    const float pp100 = read_imagef(vol_p, smp, vxl_coord + unit_x).x;
    const float pp010 = read_imagef(vol_p, smp, vxl_coord + unit_y).x;
    const float pp001 = read_imagef(vol_p, smp, vxl_coord + unit_z).x;

    const float3 p_p = (float3) (pp100, pp010, pp001);

    const float3 dp_dx = (p_p - p000) / cfg.dx_m;
    const float3 u1 = w - dp_dx;

    write_imagef(vol_u_1, vxl_coord, (float4) (u1, 0.0f));

}

// TODO

#include "std_helpers.clh"
#include "fluid_defs.clh"
#include "solve_poisson.clh"

//
// Symbol table
// ·∇, ∇²
//

//
// du
// ── = -(u·∇)u - (1/ϱ)∇p + ν·∇²u(x, t) + F(t)
// dt
//
// w = -(u·∇)u + ν·∇²u(x, t) + F(t)
//
// w - (1/ϱ)∇p = du/dt
//

struct VoxelGridDescription {
    float3 origin_m;
    float spacing_m;
};

__kernel void apply_velocity_bdry_cond(
    __read_only image3d_t u0,
    __write_only image3d_t u1) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    // This is terrible, I know. We'll make it faster once it's stable.
    const sampler_t smp_volume_nearest =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP |
        CLK_FILTER_NEAREST;

    const int3 volume_size = (int3) (
        get_image_width(u0),
        get_image_height(u0),
        get_image_depth(u0)
    );

    const int4 unit_x = (int4) (1, 0, 0, 0);
    const int4 unit_y = (int4) (0, 1, 0, 0);
    const int4 unit_z = (int4) (0, 0, 1, 0);
    const float3 u_inner_bdry = read_imagef(u0, smp_volume_nearest, vxl_coord).xyz;
    if (vxl_coord.x == (volume_size.x - 2)) {
        write_imagef(u1, vxl_coord + unit_x, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.x == 1) {
        write_imagef(u1, vxl_coord - unit_x, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.y == (volume_size.y - 2)) {
        write_imagef(u1, vxl_coord + unit_y, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.y == 1) {
        write_imagef(u1, vxl_coord - unit_y, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.z == (volume_size.z - 2)) {
        write_imagef(u1, vxl_coord + unit_z, (float4) (-u_inner_bdry, 0.0f));
    }
    if (vxl_coord.z == 1) {
        write_imagef(u1, vxl_coord - unit_z, (float4) (-u_inner_bdry, 0.0f));
    }

    // Note: There's a race condition in corners and edges
    write_imagef(u1, vxl_coord, (float4) (u_inner_bdry, 0.0f));
}

__kernel void advect_velocity(
    __read_only image3d_t vol_u_0,
    __write_only image3d_t vol_u_1,
    struct FluidSimConfig cfg) {
    //
    // u0 = vol_u_0[x]
    // vol_u_1[x] = vol_u_0[x - (u0 * dt_sec)]
    //
    const sampler_t smp_volume_interp =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP_TO_EDGE |
        CLK_FILTER_LINEAR;

    const sampler_t smp_volume_nearest =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP |
        CLK_FILTER_NEAREST;

    const int4 vxl_coordi = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);
    const float3 u0 = read_imagef(vol_u_0, smp_volume_nearest, vxl_coordi).xyz;

    const float3 vxl_coordf = convert_float4(vxl_coordi).xyz;
    const float3 u0_real_coord = (vxl_coordf / cfg.dx_m);

    const float3 u1_real_coord = u0_real_coord - (u0 * cfg.dt_sec);
    const float3 u1_vxl_coordf = u1_real_coord * cfg.dx_m;
    const int4 u1_vxl_coordi = (int4) (convert_int3(u1_vxl_coordf), 0);
    const float4 u1 = read_imagef(vol_u_0, smp_volume_interp, u1_vxl_coordi);

    float4 force = (float4) (0.0f, 0.0f, 0.0f, 0.0f);
    if ((vxl_coordi.x > 45) &&
        (vxl_coordi.x < 55) &&
        (vxl_coordi.y > 45) &&
        (vxl_coordi.y < 55) &&
        (vxl_coordi.z > 45) &&
        (vxl_coordi.z < 55)) {
        force.x = 0.1f;
        force.y = 0.1f;
        force.z = 0.1f;
    }

    force += (float4) (0.0f, -0.01f, 0.0f, 0.0f);

    float4 u1_damped = u1 + (force * cfg.dt_sec);

    write_imagef(vol_u_1, vxl_coordi, u1_damped);
}

__kernel void advect_vector(
    __read_only image3d_t vol_u_0,
    __read_only image3d_t vol_q_0,
    __write_only image3d_t vol_q_1,
    struct FluidSimConfig cfg) {
    const sampler_t smp_volume_interp =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP_TO_EDGE |
        CLK_FILTER_LINEAR;

    const sampler_t smp_volume_nearest =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP |
        CLK_FILTER_NEAREST;

    const int4 vxl_coordi = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);
    const float3 u0 = read_imagef(vol_u_0, smp_volume_nearest, vxl_coordi).xyz;

    const float3 vxl_coordf = convert_float4(vxl_coordi).xyz;
    const float3 u0_real_coord = (vxl_coordf / cfg.dx_m);

    const float3 q0_real_coord = u0_real_coord - (u0 * cfg.dt_sec);
    const float3 q0_vxl_coordf = q0_real_coord * cfg.dx_m;
    const int4 q0_vxl_coordi = (int4) (convert_int3(q0_vxl_coordf), 0);
    const float4 q0_0 = read_imagef(vol_q_0, smp_volume_interp, q0_vxl_coordi);
    const float4 q0_1 = read_imagef(vol_q_0, smp_volume_interp, vxl_coordi);

    const float4 q1 = (q0_0 + q0_1) * 0.5f;
    write_imagef(vol_q_1, vxl_coordi, q1);
}

// Viscous Diffusion
//
// du
// ── = ν·∇²u(x, t) =
// dt

__kernel void diffuse(
    __read_only image3d_t vol_u_0,
    __read_only image3d_t vol_u_next1,
    __write_only image3d_t vol_u_next2,
    struct FluidSimConfig cfg) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const float alpha = (cfg.dx_m * cfg.dx_m * cfg.dx_m) / (cfg.nu * cfg.dt_sec);
    const float beta = 6.0f + alpha;

    const float4 jacobi_iterate = poisson_step_3d_vector(
        vol_u_next1,
        vol_u_0,
        vxl_coord,
        alpha,
        beta
    );

    write_imagef(vol_u_next2, vxl_coord, jacobi_iterate);
}

__kernel void compute_divergence(
    __read_only image3d_t vol_u,
    __write_only image3d_t vol_out,
    struct FluidSimConfig cfg) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const sampler_t smp =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP_TO_EDGE |
        CLK_FILTER_NEAREST;

    const int4 unit_x = (int4) (1, 0, 0, 0);
    const int4 unit_y = (int4) (0, 1, 0, 0);
    const int4 unit_z = (int4) (0, 0, 1, 0);

    // +/- x
    const float xk_nx = read_imagef(vol_u, smp, (vxl_coord - unit_x)).x;
    const float xk_px = read_imagef(vol_u, smp, (vxl_coord + unit_x)).x;

    // +/- y
    const float xk_ny = read_imagef(vol_u, smp, (vxl_coord - unit_y)).y;
    const float xk_py = read_imagef(vol_u, smp, (vxl_coord + unit_y)).y;

    // +/- z
    const float xk_nz = read_imagef(vol_u, smp, (vxl_coord - unit_z)).z;
    const float xk_pz = read_imagef(vol_u, smp, (vxl_coord + unit_z)).z;

    const float inv_2dx = 0.5f / (cfg.dx_m);
    float div_u = (xk_pz - xk_nz) * inv_2dx;
    div_u += (xk_py - xk_ny) * inv_2dx;
    div_u += (xk_px - xk_nx) * inv_2dx;

    float4 div = (float4) (div_u, div_u, div_u, 0.0f);
    write_imagef(vol_out, vxl_coord, (float4) div_u);
}

__kernel void apply_pressure_bdry_cond(
    __read_only image3d_t p0,
    __write_only image3d_t p1) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const sampler_t smp_volume_nearest =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP |
        CLK_FILTER_NEAREST;

    const int3 volume_size = (int3) (
        get_image_width(p0),
        get_image_height(p0),
        get_image_depth(p0)
    );

    // This is terrible, I know. We'll make it faster once it's stable.

    const int4 unit_x = (int4) (1, 0, 0, 0);
    const int4 unit_y = (int4) (0, 1, 0, 0);
    const int4 unit_z = (int4) (0, 0, 1, 0);
    const float4 p_inner_bdry = read_imagef(p0, smp_volume_nearest, vxl_coord);
    if (vxl_coord.x == (volume_size.x - 2)) {
        write_imagef(p1, vxl_coord + unit_x, p_inner_bdry);
    }
    if (vxl_coord.x == 1) {
        write_imagef(p1, vxl_coord - unit_x, p_inner_bdry);
    }
    if (vxl_coord.y == (volume_size.y - 2)) {
        write_imagef(p1, vxl_coord + unit_y, p_inner_bdry);
    }
    if (vxl_coord.y == 1) {
        write_imagef(p1, vxl_coord - unit_y, p_inner_bdry);
    }
    if (vxl_coord.z == (volume_size.z - 2)) {
        write_imagef(p1, vxl_coord + unit_z, p_inner_bdry);
    }
    if (vxl_coord.z == 1) {
        write_imagef(p1, vxl_coord - unit_z, p_inner_bdry);
    }
    write_imagef(p1, vxl_coord, p_inner_bdry);
}
// du
// ── = ∇·u(x, t)
// dt
//
// w = (u + ∇p)
// ∇²p = ∇·w
__kernel void compute_pressure(
    __read_only image3d_t div_w,
    __read_only image3d_t vol_p0,
    __write_only image3d_t vol_p1,
    struct FluidSimConfig cfg) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const float alpha = -(cfg.dx_m * cfg.dx_m * cfg.dx_m);
    const float beta = 6.0f;

    const float jacobi_iterate = poisson_step_3d_scalar(
        vol_p0,
        div_w,
        vxl_coord,
        alpha,
        beta
    );
    write_imagef(vol_p1, vxl_coord, (float4) jacobi_iterate);
}

// Eliminate divergence
__kernel void chiron_projection(
    __read_only image3d_t u_divergent,
    __read_only image3d_t vol_p,
    __write_only image3d_t vol_u_1,
    struct FluidSimConfig cfg) {
    const int4 vxl_coord = (int4) (get_global_id(0), get_global_id(1), get_global_id(2), 0);

    const sampler_t smp =
        CLK_NORMALIZED_COORDS_FALSE |
        CLK_ADDRESS_CLAMP_TO_EDGE |
        CLK_FILTER_NEAREST;

    const float3 w = read_imagef(u_divergent, smp, vxl_coord).xyz;

    const int4 unit_x = (int4) (1, 0, 0, 0);
    const int4 unit_y = (int4) (0, 1, 0, 0);
    const int4 unit_z = (int4) (0, 0, 1, 0);

    const float p0x = read_imagef(vol_p, smp, vxl_coord).x;
    const float3 p000 = (float3) (p0x, p0x, p0x);
    const float pp100 = read_imagef(vol_p, smp, vxl_coord + unit_x).x;
    const float pp010 = read_imagef(vol_p, smp, vxl_coord + unit_y).x;
    const float pp001 = read_imagef(vol_p, smp, vxl_coord + unit_z).x;

    const float3 p_p = (float3) (pp100, pp010, pp001);

    const float3 dp_dx = (p_p - p000) / cfg.dx_m;
    const float3 u1 = w - dp_dx;

    write_imagef(vol_u_1, vxl_coord, (float4) (u1, 0.0f));

}


commented out printf because it causes problems on my machine

#include "md5.cl"

__kernel void vector_add(__global const int *starts, __global const int *stops, __global const int *maxlen_in, __global uint *pw_hash, __global char *cracked_pw) {
  // Get the index of the current element to be processed
  __private int id = get_global_id(0);
  int start = starts[id];
  int stop = stops[id];
  int maxlen = *maxlen_in;
  char chars[32];

  for (int i = start; i < stop; i++) {
    int actual_length = 0;
    int next = i + 1;
    for (int j = 0; j <= maxlen; j++) {
      char c = (char) (97 + (next - 1) % 26);
      chars[j] = c;
      next = (next - 1) / 26;
      if (next == 0) {
        actual_length = j + 1;
        break;
      }
    }
    uint this_hash[4];
    md5(chars, actual_length, &this_hash);
    if (
      this_hash[0] == pw_hash[0] &&
      this_hash[1] == pw_hash[1] &&
      this_hash[2] == pw_hash[2] &&
      this_hash[3] == pw_hash[3]
      ) {
        // printf("Found hash!\n");
        for (int i = 0; i < actual_length; i++) {
          cracked_pw[i] = chars[i];
          cracked_pw[i + 1] = 0x00;
        }
      }
  }
}

#include "md5.cl"

__kernel void vector_add(__global const int *starts, __global const int *stops, __global const int *maxlen_in, __global uint *pw_hash, __global char *cracked_pw) {
  // Get the index of the current element to be processed
  __private int id = get_global_id(0);
  int start = starts[id];
  int stop = stops[id];
  int maxlen = *maxlen_in;
  char chars[32];

  for (int i = start; i < stop; i++) {
    int actual_length = 0;
    int next = i + 1;
    for (int j = 0; j <= maxlen; j++) {
      char c = (char) (97 + (next - 1) % 26);
      chars[j] = c;
      next = (next - 1) / 26;
      if (next == 0) {
        actual_length = j + 1;
        break;
      }
    }
    uint this_hash[4];
    md5(chars, actual_length, &this_hash);
    if (
      this_hash[0] == pw_hash[0] &&
      this_hash[1] == pw_hash[1] &&
      this_hash[2] == pw_hash[2] &&
      this_hash[3] == pw_hash[3]
      ) {
        printf("Found hash!\n");
        for (int i = 0; i < actual_length; i++) {
          cracked_pw[i] = chars[i];
          cracked_pw[i + 1] = 0x00;
        }
      }
  }
}


Start looking into prefetch/async_copies for loop filter kernels.

#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable
#pragma OPENCL EXTENSION cl_amd_printf : enable

typedef unsigned char uc;
typedef signed char sc;

__inline signed char vp8_filter_mask(sc, sc, local uc*);
__inline signed char vp8_simple_filter_mask(signed char, signed char, uc, uc, uc, uc);
__inline signed char vp8_hevmask(signed char, local uc*);

__inline void vp8_mbfilter(signed char mask,signed char hev,local uc*);

void vp8_simple_filter(signed char mask,global uc *base, int op1_off,int op0_off,int oq0_off,int oq1_off);

constant int threads[3] = {16, 8, 8};

#if __OPENCL_VERSION__ == __CL_VERSION_1_0__
#define clamp(x,y,z) vp8_char_clamp(x)
#endif

char vp8_char_clamp(int in){
    if (in > 127)
        return 127;
    if (in < -128)
        return -128;

    return in;
}

typedef struct
{
    signed char lim[16];
    signed char flim[16];
    signed char thr[16];
    signed char mbflim[16];
} loop_filter_info;

void vp8_filter(
    signed char mask,
    signed char hev,
    local uc *base
)
{

    local uc *op1 = &base[0];
    local uc *op0 = &base[1];
    local uc *oq0 = &base[2];
    local uc *oq1 = &base[3];

    char vp8_filter, Filter1, Filter2;
    char u;

    char ps1 = (char) * op1 ^ 0x80;
    char ps0 = (char) * op0 ^ 0x80;
    char qs0 = (char) * oq0 ^ 0x80;
    char qs1 = (char) * oq1 ^ 0x80;

    /* add outer taps if we have high edge variance */
    vp8_filter = clamp(ps1 - qs1, -128, 127);
    vp8_filter &= hev;

    /* inner taps */
    vp8_filter = clamp(vp8_filter + 3 * (qs0 - ps0), -128, 127);
    vp8_filter &= mask;

    /* save bottom 3 bits so that we round one side +4 and the other +3
     * if it equals 4 we'll set to adjust by -1 to account for the fact
     * we'd round 3 the other way
     */
    Filter1 = clamp(vp8_filter + 4, -128, 127);
    Filter2 = clamp(vp8_filter + 3, -128, 127);
    Filter1 >>= 3;
    Filter2 >>= 3;
    u = clamp(qs0 - Filter1, -128, 127);
    *oq0 = u ^ 0x80;
    u = clamp(ps0 + Filter2, -128, 127);
    *op0 = u ^ 0x80;
    vp8_filter = Filter1;

    /* outer tap adjustments */
    vp8_filter += 1;
    vp8_filter >>= 1;
    vp8_filter &= ~hev;

    u = clamp(qs1 - vp8_filter, -128, 127);
    *oq1 = u ^ 0x80;
    u = clamp(ps1 + vp8_filter, -128, 127);
    *op1 = u ^ 0x80;
}

// Filters horizontal edges of inner blocks in a Macroblock
void vp8_loop_filter_horizontal_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int cur_iter,
    int priority_offset,
    local unsigned char *s_data
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    int filter_level = filters[block];
    size_t num_planes;
    size_t num_blocks;
    num_planes = 3;
    num_blocks = get_global_size(2);

    if (filters[num_blocks*filter_type + block] > 0){
        if (cur_iter == 0 || plane == 0){
            if (cur_iter > 0){
                num_planes = 1;
            }

            if (filter_level){
                int p = pitches[plane];
                int block_offset = num_blocks*11 + cur_iter*num_blocks*num_planes + block*num_planes+plane;
                int s_off = offsets[block_offset+priority_offset];

                size_t i = get_global_id(0);

                int  hev = 0; /* high edge variance */
                signed char mask = 0;

                global signed char *limit, *flimit, *thresh;
                global loop_filter_info *lf_info;

                if (i < threads[plane]){
                    lf_info = &lfi[filter_level];
                    flimit = lf_info->flim;
                    limit = lf_info->lim;
                    thresh = lf_info->thr;

                    s_off += i;
                    s_data += plane*128+i*8;

                    s_data[0] = s_base[s_off - 4*p];
                    s_data[1] = s_base[s_off - 3*p];
                    s_data[2] = s_base[s_off - 2*p];
                    s_data[3] = s_base[s_off - 1*p];
                    s_data[4] = s_base[s_off];
                    s_data[5] = s_base[s_off + p];
                    s_data[6] = s_base[s_off + 2*p];
                    s_data[7] = s_base[s_off + 3*p];

                    mask = vp8_filter_mask(limit[i], flimit[i], s_data);

                    hev = vp8_hevmask(thresh[i], &s_data[2]);

                    vp8_filter(mask, hev, &s_data[2]);

                    s_base[s_off - 2*p] = s_data[2];
                    s_base[s_off - p  ] = s_data[3];
                    s_base[s_off      ] = s_data[4];
                    s_base[s_off + p  ] = s_data[5];

                }
            }
        }
    }
}

void vp8_loop_filter_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int cur_iter,
    int priority_offset,
    local unsigned char *s_data
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes;
    size_t num_blocks;
    num_planes = 3;
    num_blocks = get_global_size(2);

    if ((cur_iter ==1 || plane == 0) && filters[num_blocks*filter_type + block] > 0){
        if (cur_iter > 1){
            num_planes = 1;
        }

        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = cur_iter*num_blocks*num_planes + block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            int  hev = 0; /* high edge variance */
            signed char mask = 0;
            size_t i = get_global_id(0);

            global signed char *limit, *flimit, *thresh;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                flimit = lf_info->flim;

                limit = lf_info->lim;
                thresh = lf_info->thr;

                s_off += p * i;
                s_data += plane*128+i*8;

                s_data[0] = s_base[s_off - 4];
                s_data[1] = s_base[s_off - 3];
                s_data[2] = s_base[s_off - 2];
                s_data[3] = s_base[s_off - 1];
                s_data[4] = s_base[s_off];
                s_data[5] = s_base[s_off + 1];
                s_data[6] = s_base[s_off + 2];
                s_data[7] = s_base[s_off + 3];

                mask = vp8_filter_mask(limit[i], flimit[i], s_data);

                hev = vp8_hevmask(thresh[i], &s_data[2]);

                vp8_filter(mask, hev, s_data+2);

                s_base[s_off - 2] = s_data[2];
                s_base[s_off - 1] = s_data[3];
                s_base[s_off    ] = s_data[4];
                s_base[s_off + 1] = s_data[5];

            }
        }
    }
}

void vp8_mbloop_filter_horizontal_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int priority_offset,
    local unsigned char *s_data
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes;
    size_t num_blocks;
    num_planes = 3;
    num_blocks = get_global_size(2);

    if (filters[num_blocks*ROWS_LOCATION + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = 8*num_blocks + block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            signed char hev = 0; /* high edge variance */
            signed char mask = 0;
            size_t i= get_global_id(0);

            global signed char *limit, *flimit, *thresh;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                flimit = lf_info->mbflim;

                limit = lf_info->lim;
                thresh = lf_info->thr;

                s_off += i;
                s_data += plane*128+i*8;

                s_data[0] = s_base[s_off - 4*p];
                s_data[1] = s_base[s_off - 3*p];
                s_data[2] = s_base[s_off - 2*p];
                s_data[3] = s_base[s_off - 1*p];
                s_data[4] = s_base[s_off];
                s_data[5] = s_base[s_off + p];
                s_data[6] = s_base[s_off + 2*p];
                s_data[7] = s_base[s_off + 3*p];

                mask = vp8_filter_mask(limit[i], flimit[i], s_data);

                hev = vp8_hevmask(thresh[i], &s_data[2]);

                vp8_mbfilter(mask, hev, s_data + 1);

                s_base[s_off - 3*p] = s_data[1];
                s_base[s_off - 2*p] = s_data[2];
                s_base[s_off - 1*p] = s_data[3];
                s_base[s_off      ] = s_data[4];
                s_base[s_off + p  ] = s_data[5];
                s_base[s_off + 2*p] = s_data[6];
            }
        }
    }
}

kernel void vp8_loop_filter_horizontal_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filters,
    int use_mbflim, //unused for normal filters
    int filter_type,
    int cur_iter,
    int priority_offset
){
    local unsigned char s_data[16*8*3];

    vp8_mbloop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters,  priority_offset, s_data);
    //YUV planes, then 2 more passes of Y plane
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 0, priority_offset, s_data);
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 3, priority_offset, s_data);
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 4, priority_offset, s_data);
}

void vp8_mbloop_filter_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int priority_offset,
    local unsigned char *s_data
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes;
    size_t num_blocks;
    num_planes = get_global_size(1);
    num_blocks = get_global_size(2);

    if (filters[num_blocks*filter_type + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            signed char hev = 0; /* high edge variance */
            signed char mask = 0;
            size_t i= get_global_id(0);

            global signed char *limit, *flimit, *thresh;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                flimit = lf_info->mbflim;

                limit = lf_info->lim;
                thresh = lf_info->thr;

                s_off += p * i;
                s_data += plane*128+i*8;

#if 1
                prefetch(&s_base[s_off-4], 8);
                s_data[0] = s_base[s_off - 4];
                s_data[1] = s_base[s_off - 3];
                s_data[2] = s_base[s_off - 2];
                s_data[3] = s_base[s_off - 1];
                s_data[4] = s_base[s_off];
                s_data[5] = s_base[s_off + 1];
                s_data[6] = s_base[s_off + 2];
                s_data[7] = s_base[s_off + 3];
#endif

                mask = vp8_filter_mask(limit[i], flimit[i], s_data);

                hev = vp8_hevmask(thresh[i], &s_data[2]);

                vp8_mbfilter(mask, hev, s_data + 1);

                s_base[s_off - 3] = s_data[1];
                s_base[s_off - 2] = s_data[2];
                s_base[s_off - 1] = s_data[3];
                s_base[s_off    ] = s_data[4];
                s_base[s_off + 1] = s_data[5];
                s_base[s_off + 2] = s_data[6];
            }
        }
    }
}

kernel void vp8_loop_filter_all_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_offset
){
    local unsigned char s_data[16*8*3];

#if 0
    event_t e;
    for(int plane = 0; plane < 3; plane++){
        int p = pitches[plane];
        int block_offset = get_global_id(2)*3+plane;
        int s_off = offsets[block_offset+priority_offset];
        for (int thread = 0; thread < 16; thread++){
            e = async_work_group_strided_copy(s_data+plane*128+thread*8, &s_base[s_off+p*thread-4], 8, 1, e);
        }
    }
    wait_group_events(1, &e);
#else
#if 1
    for(int plane = 0; plane < 3; plane++){
        int p = pitches[plane];
        int block_offset = get_global_id(2)*3+plane;
        int s_off = offsets[block_offset+priority_offset];
        for (int thread = 0; thread < 16; thread++){
            prefetch(&s_base[s_off+p*thread-4], 8);
        }
    }
#endif
#endif

    vp8_mbloop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            COLS_LOCATION, priority_offset, s_data);

    //YUV planes, then 2 more passes of Y plane
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 1, priority_offset, s_data);
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 6, priority_offset, s_data);
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 7, priority_offset, s_data);

    //barrier(CLK_GLOBAL_MEM_FENCE);

    vp8_mbloop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters,  priority_offset, s_data);

    //YUV planes, then 2 more passes of Y plane
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 0, priority_offset, s_data);
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 3, priority_offset, s_data);
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 4, priority_offset, s_data);

}

kernel void vp8_loop_filter_vertical_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_offset
){
    local unsigned char s_data[16*8*3];

    vp8_mbloop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            COLS_LOCATION, priority_offset, s_data);

    //YUV planes, then 2 more passes of Y plane
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 1, priority_offset, s_data);
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 6, priority_offset, s_data);
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 7, priority_offset, s_data);

}

kernel void vp8_loop_filter_simple_horizontal_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_offset
)
{
    private size_t plane = get_global_id(1);
    private size_t block = get_global_id(2);
    local size_t num_planes;
    local size_t num_blocks;
    num_planes = get_global_size(1);
    num_blocks = get_global_size(2);

    local unsigned char s_data[16*8*3];

    if (filters[num_blocks*filter_type + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = cur_iter*num_blocks*num_planes + block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            signed char mask = 0;
            size_t i= get_global_id(0);

            global signed char *limit, *flimit;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                if (use_mbflim == 0){
                    flimit = lf_info->flim;
                } else {
                    flimit = lf_info->mbflim;
                }

                limit = lf_info->lim;

                s_off += i;
                mask = vp8_simple_filter_mask(limit[i], flimit[i], s_base[s_off-2*p], s_base[s_off-p], s_base[s_off], s_base[s_off+p]);
                vp8_simple_filter(mask, s_base, s_off - 2 * p, s_off - 1 * p, s_off, s_off + 1 * p);
            }
        }
    }
}

kernel void vp8_loop_filter_simple_vertical_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets, /* Y or YUV offsets for EACH block being processed*/
    global int *pitches, /* 1 or 3 values for Y or YUV pitches*/
    global loop_filter_info *lfi, /* Single struct for the frame */
    global int *filters, /* Filters for each block being processed */
    int use_mbflim, /* Use lfi->flim or lfi->mbflim, need once per kernel call */
    int filter_type, /* Should dc_diffs, rows, or cols be used?*/
    int cur_iter,
    int priority_offset
)
{
    private size_t plane = get_global_id(1);
    private size_t block = get_global_id(2);
    local size_t num_planes;
    local size_t num_blocks;
    num_planes = get_global_size(1);
    num_blocks = get_global_size(2);

    local unsigned char s_data[16*8*3];

    if (filters[filter_type * num_blocks + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = cur_iter*num_blocks*num_planes + block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            signed char mask = 0;
            size_t i= get_global_id(0);

            global signed char *limit, *flimit;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                if (use_mbflim == 0){
                    flimit = lf_info->flim;
                } else {
                    flimit = lf_info->mbflim;
                }

                limit = lf_info->lim;

                s_off += p * i;
                mask = vp8_simple_filter_mask(limit[i], flimit[i], s_base[s_off-2], s_base[s_off-1], s_base[s_off], s_base[s_off+1]);
                vp8_simple_filter(mask, s_base, s_off - 2, s_off - 1, s_off, s_off + 1);
            }
        }
    }
}

//Inline and non-kernel functions follow.

__inline void vp8_mbfilter(
    signed char mask,
    signed char hev,
    local uc *base
)
{
    signed char s, u;
    signed char vp8_filter;

    local uc *op2 = base;
    local uc *op1 = base + 1;
    local uc *op0 = base + 2;
    local uc *oq0 = base + 3;
    local uc *oq1 = base + 4;
    local uc *oq2 = base + 5;

    char2 filter;

    char4 ps = { *op0, *op1, *op2, 0 };
    ps ^= (char4){0x80, 0x80, 0x80, 0x80};

    char4 qs = { *oq0, *oq1, *oq2, 0 };
    qs ^= (char4){0x80, 0x80, 0x80, 0x80};

    /* add outer taps if we have high edge variance */
    vp8_filter = clamp(ps.s1 - qs.s1, -128, 127);
    vp8_filter = clamp(vp8_filter + 3 * (qs.s0 - ps.s0), -128, 127);
    vp8_filter &= mask;

    filter.s1 = vp8_filter;
    filter.s1 &= hev;
    filter.s0 = filter.s1;

    /* save bottom 3 bits so that we round one side +4 and the other +3 */
    filter.s0 = clamp(filter.s0 + 4, -128, 127);
    filter.s1 = clamp(filter.s1 + 3, -128, 127);
    filter.s0 >>= 3;
    filter.s1 >>= 3;

    qs.s0 = clamp(qs.s0 - filter.s0, -128, 127);
    ps.s0 = clamp(ps.s0 + filter.s1, -128, 127);

    /* only apply wider filter if not high edge variance */
    vp8_filter &= ~hev;
    filter.s1 = vp8_filter;

    /* roughly 3/7th difference across boundary */
    u = clamp((63 + filter.s1 * 27) >> 7, -128, 127);
    s = clamp(qs.s0 - u, -128, 127);
    *oq0 = s ^ 0x80;
    s = clamp(ps.s0 + u, -128, 127);
    *op0 = s ^ 0x80;

    /* roughly 2/7th difference across boundary */
    u = clamp((63 + filter.s1 * 18) >> 7, -128, 127);
    s = clamp(qs.s1 - u, -128, 127);
    *oq1 = s ^ 0x80;
    s = clamp(ps.s1 + u, -128, 127);
    *op1 = s ^ 0x80;

    /* roughly 1/7th difference across boundary */
    u = clamp((63 + filter.s1 * 9) >> 7, -128, 127);
    s = clamp(qs.s2 - u, -128, 127);
    *oq2 = s ^ 0x80;
    s = clamp(ps.s2 + u, -128, 127);
    *op2 = s ^ 0x80;
}

/* is there high variance internal edge ( 11111111 yes, 00000000 no) */
__inline signed char vp8_hevmask(signed char thresh, local uc pq[])
{
    signed char hev = 0;
    hev  |= (abs(pq[0] - pq[1]) > thresh) * -1;
    hev  |= (abs(pq[3] - pq[2]) > thresh) * -1;
    return hev;
}

/* should we apply any filter at all ( 11111111 yes, 00000000 no) */
__inline signed char vp8_filter_mask( signed char limit, signed char flimit,
        local uc *pq)
{
    signed char mask = 0;
    mask |= (abs(pq[0] - pq[1]) > limit) * -1;
    mask |= (abs(pq[1] - pq[2]) > limit) * -1;
    mask |= (abs(pq[2] - pq[3]) > limit) * -1;
    mask |= (abs(pq[5] - pq[4]) > limit) * -1;
    mask |= (abs(pq[6] - pq[5]) > limit) * -1;
    mask |= (abs(pq[7] - pq[6]) > limit) * -1;
    mask |= (abs(pq[3] - pq[4]) * 2 + abs(pq[2] - pq[5]) / 2  > flimit * 2 + limit) * -1;
    mask = ~mask;
    return mask;
}

/* should we apply any filter at all ( 11111111 yes, 00000000 no) */
__inline signed char vp8_simple_filter_mask(
    signed char limit,
    signed char flimit,
    uc p1,
    uc p0,
    uc q0,
    uc q1
)
{
    signed char mask = (abs(p0 - q0) * 2 + abs(p1 - q1) / 2  <= flimit * 2 + limit) * -1;
    return mask;
}

void vp8_simple_filter(
    signed char mask,
    global uc *base,
    int op1_off,
    int op0_off,
    int oq0_off,
    int oq1_off
)
{

    global uc *op1 = base + op1_off;
    global uc *op0 = base + op0_off;
    global uc *oq0 = base + oq0_off;
    global uc *oq1 = base + oq1_off;

    signed char vp8_filter, Filter1, Filter2;
    signed char p1 = (signed char) * op1 ^ 0x80;
    signed char p0 = (signed char) * op0 ^ 0x80;
    signed char q0 = (signed char) * oq0 ^ 0x80;
    signed char q1 = (signed char) * oq1 ^ 0x80;
    signed char u;

    vp8_filter = clamp(p1 - q1, -128, 127);
    vp8_filter = clamp(vp8_filter + 3 * (q0 - p0), -128, 127);
    vp8_filter &= mask;

    /* save bottom 3 bits so that we round one side +4 and the other +3 */
    Filter1 = clamp(vp8_filter + 4, -128, 127);
    Filter1 >>= 3;
    u = clamp(q0 - Filter1, -128, 127);
    *oq0  = u ^ 0x80;

    Filter2 = clamp(vp8_filter + 3, -128, 127);
    Filter2 >>= 3;
    u = clamp(p0 + Filter2, -128, 127);
    *op0 = u ^ 0x80;
}

#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable
#pragma OPENCL EXTENSION cl_amd_printf : enable

typedef unsigned char uc;
typedef signed char sc;

__inline signed char vp8_filter_mask(sc, sc, local uc*);
__inline signed char vp8_simple_filter_mask(signed char, signed char, uc, uc, uc, uc);
__inline signed char vp8_hevmask(signed char, local uc*);

__inline void vp8_mbfilter(signed char mask,signed char hev,local uc*);

void vp8_simple_filter(signed char mask,global uc *base, int op1_off,int op0_off,int oq0_off,int oq1_off);

constant int threads[3] = {16, 8, 8};

#if __OPENCL_VERSION__ == __CL_VERSION_1_0__
#define clamp(x,y,z) vp8_char_clamp(x)
#endif

char vp8_char_clamp(int in){
    if (in > 127)
        return 127;
    if (in < -128)
        return -128;

    return in;
}

typedef struct
{
    signed char lim[16];
    signed char flim[16];
    signed char thr[16];
    signed char mbflim[16];
} loop_filter_info;

void vp8_filter(
    signed char mask,
    signed char hev,
    local uc *base
)
{

    local uc *op1 = &base[0];
    local uc *op0 = &base[1];
    local uc *oq0 = &base[2];
    local uc *oq1 = &base[3];

    signed char ps0, qs0;
    signed char ps1, qs1;
    signed char vp8_filter, Filter1, Filter2;
    signed char u;

    ps1 = (signed char) * op1 ^ 0x80;
    ps0 = (signed char) * op0 ^ 0x80;
    qs0 = (signed char) * oq0 ^ 0x80;
    qs1 = (signed char) * oq1 ^ 0x80;

    /* add outer taps if we have high edge variance */
    vp8_filter = clamp(ps1 - qs1, -128, 127);

    vp8_filter &= hev;

    /* inner taps */
    vp8_filter = clamp(vp8_filter + 3 * (qs0 - ps0), -128, 127);
    vp8_filter &= mask;

    /* save bottom 3 bits so that we round one side +4 and the other +3
     * if it equals 4 we'll set to adjust by -1 to account for the fact
     * we'd round 3 the other way
     */
    Filter1 = clamp(vp8_filter + 4, -128, 127);
    Filter2 = clamp(vp8_filter + 3, -128, 127);
    Filter1 >>= 3;
    Filter2 >>= 3;
    u = clamp(qs0 - Filter1, -128, 127);
    *oq0 = u ^ 0x80;
    u = clamp(ps0 + Filter2, -128, 127);
    *op0 = u ^ 0x80;
    vp8_filter = Filter1;

    /* outer tap adjustments */
    vp8_filter += 1;
    vp8_filter >>= 1;
    vp8_filter &= ~hev;

    u = clamp(qs1 - vp8_filter, -128, 127);
    *oq1 = u ^ 0x80;
    u = clamp(ps1 + vp8_filter, -128, 127);
    *op1 = u ^ 0x80;
}

void vp8_loop_filter_horizontal_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int cur_iter,
    int priority_offset,
    local unsigned char *s_data
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes;
    size_t num_blocks;
    num_planes = 3;
    num_blocks = get_global_size(2);

    if (filters[num_blocks*filter_type + block] > 0)
    if (cur_iter == 0 || plane == 0){
        if (cur_iter > 0){
            num_planes = 1;
        }

        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = num_blocks*11 + cur_iter*num_blocks*num_planes + block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            size_t i = get_global_id(0);

            int  hev = 0; /* high edge variance */
            signed char mask = 0;

            global signed char *limit, *flimit, *thresh;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                flimit = lf_info->flim;
                limit = lf_info->lim;
                thresh = lf_info->thr;

                s_off += i;
                s_data += plane*128+i*8;

                s_data[0] = s_base[s_off - 4*p];
                s_data[1] = s_base[s_off - 3*p];
                s_data[2] = s_base[s_off - 2*p];
                s_data[3] = s_base[s_off - 1*p];
                s_data[4] = s_base[s_off];
                s_data[5] = s_base[s_off + p];
                s_data[6] = s_base[s_off + 2*p];
                s_data[7] = s_base[s_off + 3*p];

                mask = vp8_filter_mask(limit[i], flimit[i], s_data);

                hev = vp8_hevmask(thresh[i], &s_data[2]);

                //vp8_filter(mask, hev, s_base, s_off - 2 * p, s_off - p, s_off,
                //        s_off + p);

                vp8_filter(mask, hev, s_data+2);

                s_base[s_off - 2*p] = s_data[2];
                s_base[s_off - p  ] = s_data[3];
                s_base[s_off      ] = s_data[4];
                s_base[s_off + p  ] = s_data[5];

            }
        }
    }
}

void vp8_loop_filter_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int cur_iter,
    int priority_offset,
    local unsigned char *s_data
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes;
    size_t num_blocks;
    num_planes = 3;
    num_blocks = get_global_size(2);

    if ((cur_iter ==1 || plane == 0) && filters[num_blocks*filter_type + block] > 0){
        if (cur_iter > 1){
            num_planes = 1;
        }

        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = cur_iter*num_blocks*num_planes + block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            int  hev = 0; /* high edge variance */
            signed char mask = 0;
            size_t i = get_global_id(0);

            global signed char *limit, *flimit, *thresh;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                flimit = lf_info->flim;

                limit = lf_info->lim;
                thresh = lf_info->thr;

                s_off += p * i;
                s_data += plane*128+i*8;

                s_data[0] = s_base[s_off - 4];
                s_data[1] = s_base[s_off - 3];
                s_data[2] = s_base[s_off - 2];
                s_data[3] = s_base[s_off - 1];
                s_data[4] = s_base[s_off];
                s_data[5] = s_base[s_off + 1];
                s_data[6] = s_base[s_off + 2];
                s_data[7] = s_base[s_off + 3];

                mask = vp8_filter_mask(limit[i], flimit[i], s_data);

                hev = vp8_hevmask(thresh[i], &s_data[2]);

                vp8_filter(mask, hev, s_data+2);

                s_base[s_off - 2] = s_data[2];
                s_base[s_off - 1] = s_data[3];
                s_base[s_off    ] = s_data[4];
                s_base[s_off + 1] = s_data[5];

            }
        }
    }
}

void vp8_mbloop_filter_horizontal_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int priority_offset,
    local unsigned char *s_data
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes;
    size_t num_blocks;
    num_planes = 3;
    num_blocks = get_global_size(2);

    if (filters[num_blocks*ROWS_LOCATION + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = 8*num_blocks + block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            signed char hev = 0; /* high edge variance */
            signed char mask = 0;
            size_t i= get_global_id(0);

            global signed char *limit, *flimit, *thresh;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                flimit = lf_info->mbflim;

                limit = lf_info->lim;
                thresh = lf_info->thr;

                s_off += i;
                s_data += plane*128+i*8;

                s_data[0] = s_base[s_off - 4*p];
                s_data[1] = s_base[s_off - 3*p];
                s_data[2] = s_base[s_off - 2*p];
                s_data[3] = s_base[s_off - 1*p];
                s_data[4] = s_base[s_off];
                s_data[5] = s_base[s_off + p];
                s_data[6] = s_base[s_off + 2*p];
                s_data[7] = s_base[s_off + 3*p];

                mask = vp8_filter_mask(limit[i], flimit[i], s_data);

                hev = vp8_hevmask(thresh[i], &s_data[2]);

                vp8_mbfilter(mask, hev, s_data + 1);

                s_base[s_off - 3*p] = s_data[1];
                s_base[s_off - 2*p] = s_data[2];
                s_base[s_off - 1*p] = s_data[3];
                s_base[s_off      ] = s_data[4];
                s_base[s_off + p  ] = s_data[5];
                s_base[s_off + 2*p] = s_data[6];

            }
        }
    }
}

kernel void vp8_loop_filter_horizontal_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filters,
    int use_mbflim, //unused for normal filters
    int filter_type,
    int cur_iter,
    int priority_offset
){
    local unsigned char s_data[16*8*3];

    vp8_mbloop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters,  priority_offset, s_data);
    //YUV planes, then 2 more passes of Y plane
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 0, priority_offset, s_data);
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 3, priority_offset, s_data);
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 4, priority_offset, s_data);

}

void vp8_mbloop_filter_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int priority_offset,
    local unsigned char *s_data
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes;
    size_t num_blocks;
    num_planes = get_global_size(1);
    num_blocks = get_global_size(2);

    if (filters[num_blocks*filter_type + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            signed char hev = 0; /* high edge variance */
            signed char mask = 0;
            size_t i= get_global_id(0);

            global signed char *limit, *flimit, *thresh;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                flimit = lf_info->mbflim;

                limit = lf_info->lim;
                thresh = lf_info->thr;

                s_off += p * i;
                s_data += plane*128+i*8;

                s_data[0] = s_base[s_off - 4];
                s_data[1] = s_base[s_off - 3];
                s_data[2] = s_base[s_off - 2];
                s_data[3] = s_base[s_off - 1];
                s_data[4] = s_base[s_off];
                s_data[5] = s_base[s_off + 1];
                s_data[6] = s_base[s_off + 2];
                s_data[7] = s_base[s_off + 3];

                mask = vp8_filter_mask(limit[i], flimit[i], s_data);

                hev = vp8_hevmask(thresh[i], &s_data[2]);

                vp8_mbfilter(mask, hev, s_data + 1);

                s_base[s_off - 3] = s_data[1];
                s_base[s_off - 2] = s_data[2];
                s_base[s_off - 1] = s_data[3];
                s_base[s_off    ] = s_data[4];
                s_base[s_off + 1] = s_data[5];
                s_base[s_off + 2] = s_data[6];
            }
        }
    }
}

kernel void vp8_loop_filter_all_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_offset
){
    local unsigned char s_data[16*8*3];

    vp8_mbloop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            COLS_LOCATION, priority_offset, s_data);

    //YUV planes, then 2 more passes of Y plane
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 1, priority_offset, s_data);
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 6, priority_offset, s_data);
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 7, priority_offset, s_data);

    //barrier(CLK_GLOBAL_MEM_FENCE);

    vp8_mbloop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters,  priority_offset, s_data);

    //YUV planes, then 2 more passes of Y plane
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 0, priority_offset, s_data);
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 3, priority_offset, s_data);
    vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 4, priority_offset, s_data);

}

kernel void vp8_loop_filter_vertical_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_offset
){
    local unsigned char s_data[16*8*3];

    vp8_mbloop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            COLS_LOCATION, priority_offset, s_data);

    //YUV planes, then 2 more passes of Y plane
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 1, priority_offset, s_data);
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 6, priority_offset, s_data);
    vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lfi, filters,
            DC_DIFFS_LOCATION, 7, priority_offset, s_data);

}

kernel void vp8_loop_filter_simple_horizontal_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_offset
)
{
    private size_t plane = get_global_id(1);
    private size_t block = get_global_id(2);
    local size_t num_planes;
    local size_t num_blocks;
    num_planes = get_global_size(1);
    num_blocks = get_global_size(2);

    local unsigned char s_data[16*8*3];

    if (filters[num_blocks*filter_type + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = cur_iter*num_blocks*num_planes + block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            signed char mask = 0;
            size_t i= get_global_id(0);

            global signed char *limit, *flimit;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                if (use_mbflim == 0){
                    flimit = lf_info->flim;
                } else {
                    flimit = lf_info->mbflim;
                }

                limit = lf_info->lim;

                s_off += i;
                mask = vp8_simple_filter_mask(limit[i], flimit[i], s_base[s_off-2*p], s_base[s_off-p], s_base[s_off], s_base[s_off+p]);
                vp8_simple_filter(mask, s_base, s_off - 2 * p, s_off - 1 * p, s_off, s_off + 1 * p);
            }
        }
    }
}

kernel void vp8_loop_filter_simple_vertical_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets, /* Y or YUV offsets for EACH block being processed*/
    global int *pitches, /* 1 or 3 values for Y or YUV pitches*/
    global loop_filter_info *lfi, /* Single struct for the frame */
    global int *filters, /* Filters for each block being processed */
    int use_mbflim, /* Use lfi->flim or lfi->mbflim, need once per kernel call */
    int filter_type, /* Should dc_diffs, rows, or cols be used?*/
    int cur_iter,
    int priority_offset
)
{
    private size_t plane = get_global_id(1);
    private size_t block = get_global_id(2);
    local size_t num_planes;
    local size_t num_blocks;
    num_planes = get_global_size(1);
    num_blocks = get_global_size(2);

    local unsigned char s_data[16*8*3];

    if (filters[filter_type * num_blocks + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[plane];
            int block_offset = cur_iter*num_blocks*num_planes + block*num_planes+plane;
            int s_off = offsets[block_offset+priority_offset];

            signed char mask = 0;
            size_t i= get_global_id(0);

            global signed char *limit, *flimit;
            global loop_filter_info *lf_info;

            if (i < threads[plane]){
                lf_info = &lfi[filter_level];
                if (use_mbflim == 0){
                    flimit = lf_info->flim;
                } else {
                    flimit = lf_info->mbflim;
                }

                limit = lf_info->lim;

                s_off += p * i;
                mask = vp8_simple_filter_mask(limit[i], flimit[i], s_base[s_off-2], s_base[s_off-1], s_base[s_off], s_base[s_off+1]);
                vp8_simple_filter(mask, s_base, s_off - 2, s_off - 1, s_off, s_off + 1);
            }
        }
    }
}

//Inline and non-kernel functions follow.

__inline void vp8_mbfilter(
    signed char mask,
    signed char hev,
    local uc *base
)
{
    signed char s, u;
    signed char vp8_filter;

    local uc *op2 = base;
    local uc *op1 = base + 1;
    local uc *op0 = base + 2;
    local uc *oq0 = base + 3;
    local uc *oq1 = base + 4;
    local uc *oq2 = base + 5;

    char2 filter;

    char4 ps = { *op0, *op1, *op2, 0 };
    ps ^= (char4){0x80, 0x80, 0x80, 0x80};

    char4 qs = { *oq0, *oq1, *oq2, 0 };
    qs ^= (char4){0x80, 0x80, 0x80, 0x80};

    /* add outer taps if we have high edge variance */
    vp8_filter = clamp(ps.s1 - qs.s1, -128, 127);
    vp8_filter = clamp(vp8_filter + 3 * (qs.s0 - ps.s0), -128, 127);
    vp8_filter &= mask;

    filter.s1 = vp8_filter;
    filter.s1 &= hev;
    filter.s0 = filter.s1;

    /* save bottom 3 bits so that we round one side +4 and the other +3 */
    filter.s0 = clamp(filter.s0 + 4, -128, 127);
    filter.s1 = clamp(filter.s1 + 3, -128, 127);
    filter.s0 >>= 3;
    filter.s1 >>= 3;

    qs.s0 = clamp(qs.s0 - filter.s0, -128, 127);
    ps.s0 = clamp(ps.s0 + filter.s1, -128, 127);

    /* only apply wider filter if not high edge variance */
    vp8_filter &= ~hev;
    filter.s1 = vp8_filter;

    /* roughly 3/7th difference across boundary */
    u = clamp((63 + filter.s1 * 27) >> 7, -128, 127);
    s = clamp(qs.s0 - u, -128, 127);
    *oq0 = s ^ 0x80;
    s = clamp(ps.s0 + u, -128, 127);
    *op0 = s ^ 0x80;

    /* roughly 2/7th difference across boundary */
    u = clamp((63 + filter.s1 * 18) >> 7, -128, 127);
    s = clamp(qs.s1 - u, -128, 127);
    *oq1 = s ^ 0x80;
    s = clamp(ps.s1 + u, -128, 127);
    *op1 = s ^ 0x80;

    /* roughly 1/7th difference across boundary */
    u = clamp((63 + filter.s1 * 9) >> 7, -128, 127);
    s = clamp(qs.s2 - u, -128, 127);
    *oq2 = s ^ 0x80;
    s = clamp(ps.s2 + u, -128, 127);
    *op2 = s ^ 0x80;
}

/* is there high variance internal edge ( 11111111 yes, 00000000 no) */
__inline signed char vp8_hevmask(signed char thresh, local uc pq[])
{
    signed char hev = 0;
    hev  |= (abs(pq[0] - pq[1]) > thresh) * -1;
    hev  |= (abs(pq[3] - pq[2]) > thresh) * -1;
    return hev;
}

/* should we apply any filter at all ( 11111111 yes, 00000000 no) */
__inline signed char vp8_filter_mask( signed char limit, signed char flimit,
        local uc *pq)
{
    signed char mask = 0;
    mask |= (abs(pq[0] - pq[1]) > limit) * -1;
    mask |= (abs(pq[1] - pq[2]) > limit) * -1;
    mask |= (abs(pq[2] - pq[3]) > limit) * -1;
    mask |= (abs(pq[5] - pq[4]) > limit) * -1;
    mask |= (abs(pq[6] - pq[5]) > limit) * -1;
    mask |= (abs(pq[7] - pq[6]) > limit) * -1;
    mask |= (abs(pq[3] - pq[4]) * 2 + abs(pq[2] - pq[5]) / 2  > flimit * 2 + limit) * -1;
    mask = ~mask;
    return mask;
}

/* should we apply any filter at all ( 11111111 yes, 00000000 no) */
__inline signed char vp8_simple_filter_mask(
    signed char limit,
    signed char flimit,
    uc p1,
    uc p0,
    uc q0,
    uc q1
)
{
    signed char mask = (abs(p0 - q0) * 2 + abs(p1 - q1) / 2  <= flimit * 2 + limit) * -1;
    return mask;
}

void vp8_simple_filter(
    signed char mask,
    global uc *base,
    int op1_off,
    int op0_off,
    int oq0_off,
    int oq1_off
)
{

    global uc *op1 = base + op1_off;
    global uc *op0 = base + op0_off;
    global uc *oq0 = base + oq0_off;
    global uc *oq1 = base + oq1_off;

    signed char vp8_filter, Filter1, Filter2;
    signed char p1 = (signed char) * op1 ^ 0x80;
    signed char p0 = (signed char) * op0 ^ 0x80;
    signed char q0 = (signed char) * oq0 ^ 0x80;
    signed char q1 = (signed char) * oq1 ^ 0x80;
    signed char u;

    vp8_filter = clamp(p1 - q1, -128, 127);
    vp8_filter = clamp(vp8_filter + 3 * (q0 - p0), -128, 127);
    vp8_filter &= mask;

    /* save bottom 3 bits so that we round one side +4 and the other +3 */
    Filter1 = clamp(vp8_filter + 4, -128, 127);
    Filter1 >>= 3;
    u = clamp(q0 - Filter1, -128, 127);
    *oq0  = u ^ 0x80;

    Filter2 = clamp(vp8_filter + 3, -128, 127);
    Filter2 >>= 3;
    u = clamp(p0 + Filter2, -128, 127);
    *op0 = u ^ 0x80;
}


Changed pown to square to increase performance significantly

#define UMUL(a, b) ((a) * (b))
#define UMAD(a, b, c) (UMUL((a), (b)) + (c))
#define SQUARE(a) ((a) * (a))

__kernel
void count_violations(__global float8 *restraints,
                      float16 rotmat,
                      __global int *access_interspace,
                      __global float *viol_counter,
                      __local float *loc_viol,
                      __local float4 *restraints_center,
                      __local float *mindist2,
                      __local float *maxdist2,
                      uint nrestraints, uint4 shape, float weight)
{
    uint id = get_global_id(0);
    uint stride = get_global_size(0);
    uint lid = get_local_id(0);
    uint slice = shape.s2 * shape.s1;

    //set loc_viol to 0
    uint nrestraints2 = nrestraints*nrestraints;
    uint ind_z = lid*nrestraints2;
    for (uint i = 0; i < nrestraints2; i++)
        loc_viol[i + ind_z] = 0;

    // calculate the center of the restraints
    if (lid < nrestraints) {
        restraints_center[lid].s0 = restraints[lid].s0 -
                                   (rotmat.s0*restraints[lid].s3 +
                                    rotmat.s1*restraints[lid].s4 +
                                    rotmat.s2*restraints[lid].s5);
        restraints_center[lid].s1 = restraints[lid].s1 -
                                   (rotmat.s3*restraints[lid].s3 +
                                    rotmat.s4*restraints[lid].s4 +
                                    rotmat.s5*restraints[lid].s5);
        restraints_center[lid].s2 = restraints[lid].s2 -
                                   (rotmat.s6*restraints[lid].s3 +
                                    rotmat.s7*restraints[lid].s4 +
                                    rotmat.s8*restraints[lid].s5);
        mindist2[lid] = SQUARE(restraints[lid].s6);
        maxdist2[lid] = SQUARE(restraints[lid].s7);
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    // loop over the accessable interaction space
    for (uint i = id; i < shape.s3; i += stride) {
        int consistent = access_interspace[i];
        if ((consistent == 0) || (consistent == nrestraints))
            continue;
        consistent--;

        // get x, y, z map coordinate
        uint z = i/slice;
        uint y = (i - slice*z)/shape.s2;
        uint x = i - slice*z - y*shape.s2;

        // check which restraints are violated for a certain number
        // of consistent restraints
        for (uint j = 0; j < nrestraints; j++){
            float dist2 = SQUARE(x - restraints_center[j].s0) +
                          SQUARE(y - restraints_center[j].s1) +
                          SQUARE(z - restraints_center[j].s2);
            if ((dist2 < mindist2[j]) || (dist2 > maxdist2[j])){
                uint ind = ind_z + nrestraints*consistent + j;
                loc_viol[ind] += weight;
            }
        }
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    // merge the work item subhistograms into work group histogram
    if (lid < nrestraints2) {
        uint gind_z = get_group_id(0)*nrestraints2;
        for (uint i = lid; i < nrestraints2; i += get_local_size(0)){

            float sum = 0;
            for (uint j = 0; j < get_local_size(0); j++)
                sum += loc_viol[nrestraints2*j + i];

            viol_counter[gind_z + i] += sum;
        }
    }
}

__kernel
void copy_partial(__global float *part, __global float *full, int4 part_size, int4 full_size)
{
    uint z, y, x, full_ind;
    uint part_slice = part_size.s2*part_size.s1;
    uint full_slice = full_size.s2*full_size.s1;

    for (uint i = get_global_id(0); i < part_size.s3; i += get_global_size(0)) {
        z = i/part_slice;
        y = (i - z*part_slice)/part_size.s2;
        x = i - z*part_slice - y*part_size.s2;

        full_ind = z * full_slice + y * full_size.s2 + x;
        full[full_ind] = part[i];
    }
}

__kernel
void histogram(__global int *data,
                 __global float *subhists,
                 __local float *local_hist,
                 uint nrestraints,
                 float weight,
                 uint size)
{
    uint lid = get_local_id(0);

    for (uint i = 0; i < nrestraints; i++)
        local_hist[lid + i * get_local_size(0)] = 0;

    for (uint pos = get_global_id(0); pos < size; pos += get_global_size(0))
        local_hist[lid + data[pos] * get_local_size(0)] += weight;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (lid < nrestraints) {
        for (uint j =  lid; j < nrestraints; j += get_local_size(0)) {

            float sum = 0;
            int pos = get_local_size(0) * lid;

            for (uint i = 0; i < get_local_size(0); i++)
                sum += local_hist[pos + i];

            subhists[get_group_id(0)*nrestraints + j] += sum;
        }
    }
}

__kernel
void rotate_image3d(sampler_t sampler,
                    read_only image3d_t image,
                    float16 rotmat,
                   __global float *out,
                   float4 center,
                   int4 shape)
{
    int id = get_global_id(0);
    int stride = get_global_size(0);

    int x, y, z, slice;
    float xrot, yrot, zrot;
    float4 coordinate, weight;

    slice = shape.s2*shape.s1;
    float OFFSET = 0.5f;

    int i;
    for (i = id; i < shape.s3; i += stride) {

        z = i/slice;
        y = (i - z*slice)/shape.s2;
        x = i - z*slice - y*shape.s2;

        if (x >= 0.5*shape.s2)
            x -= shape.s2;
        if (y >= 0.5*shape.s1)
            y -= shape.s1;
        if (z >= 0.5*shape.s0)
            z -= shape.s0;

        xrot = rotmat.s0*x + rotmat.s1*y + rotmat.s2*z;
        yrot = rotmat.s3*x + rotmat.s4*y + rotmat.s5*z;
        zrot = rotmat.s6*x + rotmat.s7*y + rotmat.s8*z;

        xrot += OFFSET + center.s0;
        yrot += OFFSET + center.s1;
        zrot += OFFSET + center.s2;

        coordinate = (float4) (xrot, yrot, zrot, 0);
        weight = read_imagef(image, sampler, coordinate);

        out[i] = weight.s0;
    }
}

__kernel
void distance_restraint(__global float8 *restraints,
                       float16 rotmat,
                       __global int *restspace,
                       int4 shape, int nrestraints)
{

    uint zid = get_global_id(0);
    uint yid = get_global_id(1);
    uint xid = get_global_id(2);

    uint zstride = get_global_size(0);
    uint ystride = get_global_size(1);
    uint xstride = get_global_size(2);

    uint i, ix, iy, iz;
    uint z_ind, yz_ind, xyz_ind;
    float xligand, yligand, zligand;
    float xcenter, ycenter, zcenter, mindis2, maxdis2, z_dis2, yz_dis2, xyz_dis2;

    uint slice = shape.s2 * shape.s1;

    for (i = 0; i < nrestraints; i++){

         // determine the center of the point that will be dilated
         xligand = rotmat.s0 * restraints[i].s3 + rotmat.s1 * restraints[i].s4 + rotmat.s2 * restraints[i].s5;
         yligand = rotmat.s3 * restraints[i].s3 + rotmat.s4 * restraints[i].s4 + rotmat.s5 * restraints[i].s5;
         zligand = rotmat.s6 * restraints[i].s3 + rotmat.s7 * restraints[i].s4 + rotmat.s8 * restraints[i].s5;

         xcenter = restraints[i].s0 - xligand;
         ycenter = restraints[i].s1 - yligand;
         zcenter = restraints[i].s2 - zligand;

         mindis2 = SQUARE(restraints[i].s6);
         maxdis2 = SQUARE(restraints[i].s7);

         // calculate the distance of every voxel to the determined center
         for (iz = zid; iz < shape.s0; iz += zstride){

             z_dis2 = SQUARE(iz - zcenter);

             z_ind = iz * slice;

             for (iy = yid; iy < shape.s1; iy += ystride){
                 yz_dis2 = SQUARE(iy - ycenter) + z_dis2;

                 yz_ind = z_ind + iy*shape.s2;

                 for (ix = xid; ix < shape.s2; ix += xstride){

                     xyz_dis2 = SQUARE(ix - xcenter) + yz_dis2;

                     if ((xyz_dis2 <= maxdis2) && (xyz_dis2 >= mindis2)){
                         xyz_ind = ix + yz_ind;
                         restspace[xyz_ind] += 1;
                     }
                 }
             }
         }
    }
}

#define UMUL(a, b) ((a) * (b))
#define UMAD(a, b, c) (UMUL((a), (b)) + (c))

__kernel
void count_violations(__global float8 *restraints,
                      float16 rotmat,
                      __global int *access_interspace,
                      __global float *viol_counter,
                      __local float *loc_viol,
                      __local float4 *restraints_center,
                      __local float *mindist2,
                      __local float *maxdist2,
                      uint nrestraints, uint4 shape, float weight)
{
    uint id = get_global_id(0);
    uint stride = get_global_size(0);
    uint lid = get_local_id(0);
    uint slice = shape.s2 * shape.s1;

    //set loc_viol to 0
    uint nrestraints2 = nrestraints*nrestraints;
    uint ind_z = lid*nrestraints2;
    for (uint i = 0; i < nrestraints2; i++)
        loc_viol[i + ind_z] = 0;

    // calculate the center of the restraints
    if (lid < nrestraints) {
        restraints_center[lid].s0 = restraints[lid].s0 -
                                   (rotmat.s0*restraints[lid].s3 +
                                    rotmat.s1*restraints[lid].s4 +
                                    rotmat.s2*restraints[lid].s5);
        restraints_center[lid].s1 = restraints[lid].s1 -
                                   (rotmat.s3*restraints[lid].s3 +
                                    rotmat.s4*restraints[lid].s4 +
                                    rotmat.s5*restraints[lid].s5);
        restraints_center[lid].s2 = restraints[lid].s2 -
                                   (rotmat.s6*restraints[lid].s3 +
                                    rotmat.s7*restraints[lid].s4 +
                                    rotmat.s8*restraints[lid].s5);
        mindist2[lid] = pown(restraints[lid].s6, 2);
        maxdist2[lid] = pown(restraints[lid].s7, 2);
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    // loop over the accessable interaction space
    for (uint i = id; i < shape.s3; i += stride) {
        int consistent = access_interspace[i];
        if ((consistent == 0) || (consistent == nrestraints))
            continue;
        consistent--;

        // get x, y, z map coordinate
        uint z = i/slice;
        uint y = (i - slice*z)/shape.s2;
        uint x = i - slice*z - y*shape.s2;

        // check which restraints are violated for a certain number
        // of consistent restraints
        for (uint j = 0; j < nrestraints; j++){
            float dist2 = pown(x - restraints_center[j].s0, 2) +
                          pown(y - restraints_center[j].s1, 2) +
                          pown(z - restraints_center[j].s2, 2);
            if ((dist2 < mindist2[j]) || (dist2 > maxdist2[j])){
                uint ind = ind_z + nrestraints*consistent + j;
                loc_viol[ind] += weight;
            }
        }
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    // merge the work item subhistograms into work group histogram
    if (lid < nrestraints2) {
        uint gind_z = get_group_id(0)*nrestraints2;
        for (uint i = lid; i < nrestraints2; i += get_local_size(0)){

            float sum = 0;
            for (uint j = 0; j < get_local_size(0); j++)
                sum += loc_viol[nrestraints2*j + i];

            viol_counter[gind_z + i] += sum;
        }
    }
}

__kernel
void copy_partial(__global float *part, __global float *full, int4 part_size, int4 full_size)
{
    uint z, y, x, full_ind;
    uint part_slice = part_size.s2*part_size.s1;
    uint full_slice = full_size.s2*full_size.s1;

    for (uint i = get_global_id(0); i < part_size.s3; i += get_global_size(0)) {
        z = i/part_slice;
        y = (i - z*part_slice)/part_size.s2;
        x = i - z*part_slice - y*part_size.s2;

        full_ind = z * full_slice + y * full_size.s2 + x;
        full[full_ind] = part[i];
    }
}

__kernel
void histogram(__global int *data,
                 __global float *subhists,
                 __local float *local_hist,
                 uint nrestraints,
                 float weight,
                 uint size)
{
    uint lid = get_local_id(0);

    for (uint i = 0; i < nrestraints; i++)
        local_hist[lid + i * get_local_size(0)] = 0;

    for (uint pos = get_global_id(0); pos < size; pos += get_global_size(0))
        local_hist[lid + data[pos] * get_local_size(0)] += weight;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (lid < nrestraints) {
        for (uint j =  lid; j < nrestraints; j += get_local_size(0)) {

            float sum = 0;
            int pos = get_local_size(0) * lid;

            for (uint i = 0; i < get_local_size(0); i++)
                sum += local_hist[pos + i];

            subhists[get_group_id(0)*nrestraints + j] += sum;
        }
    }
}

__kernel
void rotate_image3d(sampler_t sampler,
                    read_only image3d_t image,
                    float16 rotmat,
                   __global float *out,
                   float4 center,
                   int4 shape)
{
    int id = get_global_id(0);
    int stride = get_global_size(0);

    int x, y, z, slice;
    float xrot, yrot, zrot;
    float4 coordinate, weight;

    slice = shape.s2*shape.s1;
    float OFFSET = 0.5f;

    int i;
    for (i = id; i < shape.s3; i += stride) {

        z = i/slice;
        y = (i - z*slice)/shape.s2;
        x = i - z*slice - y*shape.s2;

        if (x >= 0.5*shape.s2)
            x -= shape.s2;
        if (y >= 0.5*shape.s1)
            y -= shape.s1;
        if (z >= 0.5*shape.s0)
            z -= shape.s0;

        xrot = rotmat.s0*x + rotmat.s1*y + rotmat.s2*z;
        yrot = rotmat.s3*x + rotmat.s4*y + rotmat.s5*z;
        zrot = rotmat.s6*x + rotmat.s7*y + rotmat.s8*z;

        xrot += OFFSET + center.s0;
        yrot += OFFSET + center.s1;
        zrot += OFFSET + center.s2;

        coordinate = (float4) (xrot, yrot, zrot, 0);
        weight = read_imagef(image, sampler, coordinate);

        out[i] = weight.s0;
    }
}

__kernel
void distance_restraint(__global float8 *restraints,
                       float16 rotmat,
                       __global int *restspace,
                       int4 shape, int nrestraints)
{

    uint zid = get_global_id(0);
    uint yid = get_global_id(1);
    uint xid = get_global_id(2);

    uint zstride = get_global_size(0);
    uint ystride = get_global_size(1);
    uint xstride = get_global_size(2);

    uint i, ix, iy, iz;
    uint z_ind, yz_ind, xyz_ind;
    float xligand, yligand, zligand;
    float xcenter, ycenter, zcenter, mindis2, maxdis2, z_dis2, yz_dis2, xyz_dis2;

    uint slice = shape.s2 * shape.s1;

    for (i = 0; i < nrestraints; i++){

         // determine the center of the point that will be dilated
         xligand = rotmat.s0 * restraints[i].s3 + rotmat.s1 * restraints[i].s4 + rotmat.s2 * restraints[i].s5;
         yligand = rotmat.s3 * restraints[i].s3 + rotmat.s4 * restraints[i].s4 + rotmat.s5 * restraints[i].s5;
         zligand = rotmat.s6 * restraints[i].s3 + rotmat.s7 * restraints[i].s4 + rotmat.s8 * restraints[i].s5;

         xcenter = restraints[i].s0 - xligand;
         ycenter = restraints[i].s1 - yligand;
         zcenter = restraints[i].s2 - zligand;

         mindis2 = pown(restraints[i].s6, 2);
         maxdis2 = pown(restraints[i].s7, 2);

         // calculate the distance of every voxel to the determined center
         for (iz = zid; iz < shape.s0; iz += zstride){

             z_dis2 = pown(iz - zcenter, 2);

             z_ind = iz * slice;

             for (iy = yid; iy < shape.s1; iy += ystride){
                 yz_dis2 = pown(iy - ycenter, 2) + z_dis2;

                 yz_ind = z_ind + iy*shape.s2;

                 for (ix = xid; ix < shape.s2; ix += xstride){

                     xyz_dis2 = pown(ix - xcenter, 2) + yz_dis2;

                     if ((xyz_dis2 <= maxdis2) && (xyz_dis2 >= mindis2)){
                         xyz_ind = ix + yz_ind;
                         restspace[xyz_ind] += 1;
                     }
                 }
             }
         }
    }
}


Main mean-shift kernel done

Main mean-shift kernel done

/*
 * Accelerated k-means and mean-shift algorithms via OpenCL
 * Authors: Martin Simon & Pavel Sirucek
 *
 * OpenCL kernels
 */

__kernel void k_means()
{
}

__kernel void mean_shift(__global uchar4* input, __global uint* peaks, __global uint* counts,
__local float* cache, uint width, uint height, uint winsize, float maxlength)
{
int x = get_global_id(0);
int y = get_global_id(1);

//reconstruct window by given param
int actx = x;
int acty = y;
int wymax = acty + ((winsize-1) / 2) + 1;
int wymin = acty - ((winsize-1) / 2);
int wxmax = actx + ((winsize-1) / 2) + 1;
int wxmin = actx - ((winsize-1) / 2);
int oldx = x;
int oldy = y;

//cycle control value
bool cont = true;

//mean structures
float denominatorX = 0;
float numeratorX = 0;
float denominatorY = 0;
float numeratorY = 0;
float fNumerator;

//begincycle - until the step is bigger than relevant
do {
    for (int wy = wymin; wy < wymax; wy++)
    {
        for (int wx = wxmin; wx < wxmax; wx++)
        {
            if (wx < 0 || wy < 0 || wx > width-1|| wy > height-1)
            {
                //out of original window
                //set 0 to the position of the x in local cache
                cache[wx - wxmin + (wy-wymin)*winsize] = convert_float(0);
            }
            else if (wx == actx && wy == acty)
            {
                //set 1 to the position of the x
                //to [actx-wxmin,acty-wymin] set 1
                cache[wx - wxmin + (wy-wymin)*winsize] = convert_float(1);
            }
            else
            {
                //compute lengths for [wx,wy] - [x,y]
                //if the length is bigger the maxlength, set 0 there
                //otherwise set the length
                float length = 1 - 1/sqrt(
                    (actx-wx)*(actx-wx) +
                    (acty-wy)*(acty-wy) +
                    (input[actx + acty*width].s0 - input[wx + wy*width].s0)*(input[actx + acty*width].s0 - input[wx + wy*width].s0) +
                    (input[actx + acty*width].s1 - input[wx + wy*width].s1)*(input[actx + acty*width].s1 - input[wx + wy*width].s1) +
                    (input[actx + acty*width].s2 - input[wx + wy*width].s2)*(input[actx + acty*width].s2 - input[wx + wy*width].s2));
                if (length > maxlength)
                {
                    cache[wx - wxmin + (wy-wymin)*winsize] = convert_float(0);
                }
                else
                {
                    //store the value to its place
                    cache[wx - wxmin + (wy-wymin)*winsize] = convert_float(1-length);

                    //add numerator and denominator for the X mean computation
                    fNumerator = sqrt((wx-actx)*(wx-actx));
                    numeratorX += fNumerator * (1-length);
                    denominatorX += fNumerator;

                    //add numerator and denominator for the Y mean computation
                    fNumerator = sqrt((wy-acty)*(wy-acty));
                    numeratorY += fNumerator * (1-length);
                    denominatorY += fNumerator;
                }
            }
        }
    }

    //recompute mean of the window
    actx = convert_int(numeratorX/denominatorX);
    acty = convert_int(numeratorY/denominatorY);

    //shift the window to the mean be in the center
    wymax = acty + ((winsize-1) / 2) + 1;
    wymin = acty - ((winsize-1) / 2);
    wxmax = actx + ((winsize-1) / 2) + 1;
    wxmin = actx - ((winsize-1) / 2);

    if (actx == oldx && acty == oldy)
    {
        //the step is lower the 0.5pix
        cont = false;
    }

    //endcycle
} while (cont);

//store the peak position to peaks array
peaks[x+y*width] = actx + acty*width;

//increment value on peak position in counts array
counts[actx + acty*width] = counts[actx + acty*width] + 1;

}

__kernel void mean_shift_result(__global uint* counts, __global uint* peaks, __global uchar4* output, uint width, uint height)
{
	int x = get_global_id(0);
	int y = get_global_id(1);

	if(x < width && y < height)
	{
		int gid = x + y*width;
		output[gid] = add_sat(sobel_x[gid], sobel_y[gid]);
		output[gid].s3 = 255;
	}
}

//TODO delete following

__kernel void edge_x( __global uchar4* input, __global uchar4* output, uint width, uint height, __local float4* cache)
{
	int x = get_global_id(0); //defines column
	int y = get_global_id(1); //defines row

	int lx = get_local_id(0);
	int lw = get_local_size(0);

	if(lx == 0)
	{
		int startI = y*width;
		int endI = y*width + height - 1;
		output[startI] = (uchar4)(0, 0, 0, 0);
		output[endI] = (uchar4)(0, 0, 0, 0);
	}

	int kw = 0;
	while(kw < width)
	{
		int gindex = y*width + lx + kw;

		//cache in the row
		if(lx + kw < width)
		{
			cache[lx] = convert_float4(input[gindex]);
		}

		barrier(CLK_LOCAL_MEM_FENCE);

		if(lx + kw < width-1 && lx > 0 && lx < lw - 1)
		{
			output[gindex] = convert_uchar4(fabs(cache[lx - 1] - cache[lx + 1]));
		}

		kw += lw - 1;
	}
}

__kernel void edge_y( __global uchar4* input, __global uchar4* output, uint width, uint height, __local float4* cache)
{
	int x = get_global_id(0); //defines column
	int y = get_global_id(1); //defines row

	int ly = get_local_id(1);
	int lh = get_local_size(1);

	if(ly == 0)
	{
		int startI = x;
		int endI = (height-1)*width + x;
		output[startI] = (uchar4)(0, 0, 0, 0);
		output[endI] = (uchar4)(0, 0, 0, 0);
	}

	int kh = 0;
	while(kh < height)
	{
		int gindex = (ly + kh)*width + x;

		//cache in the column
		if(ly + kh < height)
		{
			cache[ly] = convert_float4(input[gindex]);
		}

		barrier(CLK_LOCAL_MEM_FENCE);

		if(ly + kh < height-1 && ly > 0 && ly < lh - 1)
		{
			output[gindex] = convert_uchar4_sat_rte(fabs(cache[ly - 1] - cache[ly + 1]));
		}

		kh += lh - 1;
	}
}

__kernel void edge_result(__global uchar4* sobel_x, __global uchar4* sobel_y, __global uchar4* output, uint width, uint height)
{
	int x = get_global_id(0);
	int y = get_global_id(1);

	if(x < width && y < height)
	{
		int gid = x + y*width;
		output[gid] = add_sat(sobel_x[gid], sobel_y[gid]);
		output[gid].s3 = 255;
	}
}

/*
 * Accelerated k-means and mean-shift algorithms via OpenCL
 * Authors: Martin Simon & Pavel Sirucek
 *
 * OpenCL kernels
 */

__kernel void k_means()
{
}

__kernel void mean_shift(__global uchar4* input, __global uint* peaks, __global uint* counts,
__local float* cache, uint width, uint height, uint winsize, float maxlength)
{
int x = get_global_id(0);
int y = get_global_id(1);

//reconstruct window by given param
int actx = x;
int acty = y;
int wymax = acty + ((winsize-1) / 2) + 1;
int wymin = acty - ((winsize-1) / 2);
int wxmax = actx + ((winsize-1) / 2) + 1;
int wxmin = actx - ((winsize-1) / 2);

//begincycle - until the step is bigger than given
do {
    for (int wy = wymin; wy < wymax; wy++)
    {
        for (int wx = wxmin; wx < wxmax; wx++)
        {
            if (wx < 0 || wy < 0 || wx > width-1|| wy > height-1)
            {
                //out of original window
                //set 0 to the position of the x in local cache
                cache[wx - wxmin + (wy-wymin)*winsize] = convert_float(0);
            }
            else if (wx == actx && wy == acty)
            {
                //set 1 to the position of the x
                //to [actx-wxmin,acty-wymin] set 1
                cache[wx - wxmin + (wy-wymin)*winsize] = convert_float(1);
            }
            else
            {
                //compute lengths for [wx,wy] - [x,y]
                //if the length is bigger the maxlength, set 0 there
                //otherwise set the length
                float length = 1 - 1/sqrt(
                    (actx-wx)*(actx-wx) +
                    (acty-wy)*(acty-wy) +
                    (input[actx + acty*width].s0 - input[wx + wy*width].s0)*(input[actx + acty*width].s0 - input[wx + wy*width].s0) +
                    (input[actx + acty*width].s1 - input[wx + wy*width].s1)*(input[actx + acty*width].s1 - input[wx + wy*width].s1) +
                    (input[actx + acty*width].s2 - input[wx + wy*width].s2)*(input[actx + acty*width].s2 - input[wx + wy*width].s2));
                if (length > maxlength)
                {
                    cache[wx - wxmin + (wy-wymin)*winsize] = convert_float(0);
                }
                else
                {
                    cache[wx - wxmin + (wy-wymin)*winsize] = convert_float(1-length);
                }
            }
        }
    }

//recompute mean of the window
//TODO how?

//shift the window to the mean be in the center
//actx = newx
//acty = newy
wymax = acty + ((winsize-1) / 2) + 1;
wymin = acty - ((winsize-1) / 2);
wxmax = actx + ((winsize-1) / 2) + 1;
wxmin = actx - ((winsize-1) / 2);

//endcycle
} while (/* step > threshold */);

//store the peak position to peaks array
peaks[x+y*width] = actx + acty*width;
//incement value on peak position in counts array
counts[actx + acty*width] = counts[actx + acty*width] + 1;

}

__kernel void mean_shift_result(__global uint* counts, __global uint* peaks, __global uchar4* output, uint width, uint height)
{
	int x = get_global_id(0);
	int y = get_global_id(1);

	if(x < width && y < height)
	{
		int gid = x + y*width;
		output[gid] = add_sat(sobel_x[gid], sobel_y[gid]);
		output[gid].s3 = 255;
	}
}

//TODO delete following

__kernel void edge_x( __global uchar4* input, __global uchar4* output, uint width, uint height, __local float4* cache)
{
	int x = get_global_id(0); //defines column
	int y = get_global_id(1); //defines row

	int lx = get_local_id(0);
	int lw = get_local_size(0);

	if(lx == 0)
	{
		int startI = y*width;
		int endI = y*width + height - 1;
		output[startI] = (uchar4)(0, 0, 0, 0);
		output[endI] = (uchar4)(0, 0, 0, 0);
	}

	int kw = 0;
	while(kw < width)
	{
		int gindex = y*width + lx + kw;

		//cache in the row
		if(lx + kw < width)
		{
			cache[lx] = convert_float4(input[gindex]);
		}

		barrier(CLK_LOCAL_MEM_FENCE);

		if(lx + kw < width-1 && lx > 0 && lx < lw - 1)
		{
			output[gindex] = convert_uchar4(fabs(cache[lx - 1] - cache[lx + 1]));
		}

		kw += lw - 1;
	}
}

__kernel void edge_y( __global uchar4* input, __global uchar4* output, uint width, uint height, __local float4* cache)
{
	int x = get_global_id(0); //defines column
	int y = get_global_id(1); //defines row

	int ly = get_local_id(1);
	int lh = get_local_size(1);

	if(ly == 0)
	{
		int startI = x;
		int endI = (height-1)*width + x;
		output[startI] = (uchar4)(0, 0, 0, 0);
		output[endI] = (uchar4)(0, 0, 0, 0);
	}

	int kh = 0;
	while(kh < height)
	{
		int gindex = (ly + kh)*width + x;

		//cache in the column
		if(ly + kh < height)
		{
			cache[ly] = convert_float4(input[gindex]);
		}

		barrier(CLK_LOCAL_MEM_FENCE);

		if(ly + kh < height-1 && ly > 0 && ly < lh - 1)
		{
			output[gindex] = convert_uchar4_sat_rte(fabs(cache[ly - 1] - cache[ly + 1]));
		}

		kh += lh - 1;
	}
}

__kernel void edge_result(__global uchar4* sobel_x, __global uchar4* sobel_y, __global uchar4* output, uint width, uint height)
{
	int x = get_global_id(0);
	int y = get_global_id(1);

	if(x < width && y < height)
	{
		int gid = x + y*width;
		output[gid] = add_sat(sobel_x[gid], sobel_y[gid]);
		output[gid].s3 = 255;
	}
}


Update spmv_kernel.cl

Update spmv_kernel.cl

/*
 * Copyright July 29, 2011 by Virginia Polytechnic Institute and State University
 * All rights reserved.
 *
 * Virginia Polytechnic Institute and State University (Virginia Tech) owns the
 * OpenCL and the 13 Dwarfs software and its associated documentation (Software).
 * You should carefully read the following terms and conditions before using this
 * software.  Your use of this Software indicates your acceptance of this license
 * agreement and all terms and conditions.
 *
 * You are hereby licensed to use the Software for Non-Commercial Purpose only.
 * Non-Commercial Purpose means the use of the Software solely for research.
 * Non-Commercial Purpose excludes, without limitation, any use of the Software, as
 * part of, or in any way in connection with a product or service which is sold,
 * offered for sale, licensed, leased, loaned, or rented.  Permission to use, copy,
 * modify, and distribute this compilation for Non-Commercial Purpose is hereby
 * granted without fee, subject to the following terms of this license.
 */

 /*
 */

void __kernel csr_ocl(const unsigned int num_rows,
		__global unsigned int * Ap,
		__global unsigned int * Aj,
		__global float * Ax,
		__global float * x,
		__global float * y)
{
	unsigned int row = get_global_id(0);

	if(row < num_rows) {
		float sum = y[row];

		const unsigned int row_start = Ap[row];
		const unsigned int row_end = Ap[row+1];

		unsigned int jj = 0;
		for (jj = row_start; jj < row_end; jj++)
			sum += Ax[jj] * x[Aj[jj]];

		y[row] = sum;
	}
}