Replace vec3 with vec4 because vec3 arrived in CL 1.1.

#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, uc, uc, uc, uc, uc, uc, uc, uc);
__inline signed char vp8_simple_filter_mask(signed char, signed char, uc, uc, uc, uc);
__inline signed char vp8_hevmask(signed char, uc, uc, uc, uc);

__inline void vp8_mbfilter(signed char mask,signed char hev,global uc *op2,
    global uc *op1,global uc *op0,global uc *oq0,global uc *oq1,global uc *oq2);

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

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,
    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 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 = vp8_char_clamp(ps1 - qs1);

    vp8_filter &= hev;

    /* inner taps */
    vp8_filter = vp8_char_clamp(vp8_filter + 3 * (qs0 - ps0));
    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 = vp8_char_clamp(vp8_filter + 4);
    Filter2 = vp8_char_clamp(vp8_filter + 3);
    Filter1 >>= 3;
    Filter2 >>= 3;
    u = vp8_char_clamp(qs0 - Filter1);
    *oq0 = u ^ 0x80;
    u = vp8_char_clamp(ps0 + Filter2);
    *op0 = u ^ 0x80;
    vp8_filter = Filter1;

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

    u = vp8_char_clamp(qs1 - vp8_filter);
    *oq1 = u ^ 0x80;
    u = vp8_char_clamp(ps1 + vp8_filter);
    *op1 = u ^ 0x80;
}

kernel void vp8_loop_filter_horizontal_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];
                    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];
                        if (use_mbflim == 0){
                            flimit = lf_info->flim;
                        } else {
                            flimit = lf_info->mbflim;
                        }

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

                        s_off += i;

                        mask = vp8_filter_mask(limit[i], flimit[i], s_base[s_off - 4*p],
                                s_base[s_off - 3*p], s_base[s_off - 2*p], s_base[s_off - p],
                                s_base[s_off], s_base[s_off + p], s_base[s_off + 2*p],
                                s_base[s_off + 3*p]);

                        hev = vp8_hevmask(thresh[i], s_base[s_off - 2*p], s_base[s_off - p],
                                s_base[s_off], s_base[s_off+p]);

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

kernel void vp8_loop_filter_vertical_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];
                    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];
                        if (use_mbflim == 0){
                            flimit = lf_info->flim;
                        } else {
                            flimit = lf_info->mbflim;
                        }

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

                        s_off += p * i;
                        mask = vp8_filter_mask(limit[i], flimit[i],
                                s_base[s_off-4], s_base[s_off-3], s_base[s_off-2],
                                s_base[s_off-1], s_base[s_off], s_base[s_off+1],
                                s_base[s_off+2], s_base[s_off+3]);

                        hev = vp8_hevmask(thresh[i], s_base[s_off-2], s_base[s_off-1],
                                s_base[s_off], s_base[s_off+1]);

                        vp8_filter(mask, hev, s_base, s_off - 2, s_off - 1, s_off, s_off + 1);

                    }
                }
            }
        }
    }
}

kernel void vp8_mbloop_filter_horizontal_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];

                    global uc *s = s_base+s_off;

                    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];
                        if (use_mbflim == 0){
                            flimit = lf_info->flim;
                        } else {
                            flimit = lf_info->mbflim;
                        }

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

                        s += i;

                        mask = vp8_filter_mask(limit[i], flimit[i],
                                               s[-4*p], s[-3*p], s[-2*p], s[-1*p],
                                               s[0*p], s[1*p], s[2*p], s[3*p]);

                        hev = vp8_hevmask(thresh[i], s[-2*p], s[-1*p], s[0*p], s[1*p]);

                        vp8_mbfilter(mask, hev, s - 3 * p, s - 2 * p, s - 1 * p, s, s + 1 * p, s + 2 * p);

                    }
                }
            }
        }
    }
}

kernel void vp8_mbloop_filter_vertical_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];

                    global uc *s = s_base + s_off;

                    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];
                        if (use_mbflim == 0){
                            flimit = lf_info->flim;
                        } else {
                            flimit = lf_info->mbflim;
                        }

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

                        s += p * i;

                        mask = vp8_filter_mask(limit[i], flimit[i],
                                               s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]);

                        hev = vp8_hevmask(thresh[i], s[-2], s[-1], s[0], s[1]);

                        vp8_mbfilter(mask, hev, s - 3, s - 2, s - 1, s, s + 1, s + 2);

                    }
                }
            }
        }
    }
}

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 *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];

                    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 *filter_levels, /* Filter level for each block being processed */
    int use_mbflim, /* Use lfi->flim or lfi->mbflim, need once per kernel call */
    global int *threads, /* Thread counts per plane */
    global int *apply_filters /* Should the filter be applied (per block) */
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];

                    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,
    global uc *op2,
    global uc *op1,
    global uc *op0,
    global uc *oq0,
    global uc *oq1,
    global uc *oq2
)
{
    signed char s;
    int4 s4, u4;
    signed char vp8_filter;

    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 = vp8_char_clamp(ps.s1 - qs.s1);
    vp8_filter = vp8_char_clamp(vp8_filter + 3 * (qs.s0 - ps.s0));
    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 += (char2){4,3};
    filter.s0 = vp8_char_clamp(filter.s0);
    filter.s1 = vp8_char_clamp(filter.s1);
    filter.s0 >>= 3;
    filter.s1 >>= 3;

    qs.s0 = vp8_char_clamp(qs.s0 - filter.s0);
    ps.s0 = vp8_char_clamp(ps.s0 + filter.s1);

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

    u4 = (int4){filter.s1, filter.s1, filter.s1, 0};
    u4 *= (int4){27, 18, 9, 0};
    u4 += 63;
    u4 >>= 7;
    u4.s0 = vp8_char_clamp(u4.s0);
    u4.s1 = vp8_char_clamp(u4.s1);
    u4.s2 = vp8_char_clamp(u4.s2);

    /* roughly 3/7th difference across boundary */
    s = vp8_char_clamp(qs.s0 - u4.s0);
    *oq0 = s ^ 0x80;
    s = vp8_char_clamp(ps.s0 + u4.s0);
    *op0 = s ^ 0x80;

    /* roughly 2/7th difference across boundary */
    s = vp8_char_clamp(qs.s1 - u4.s1);
    *oq1 = s ^ 0x80;
    s = vp8_char_clamp(ps.s1 + u4.s1);
    *op1 = s ^ 0x80;

    /* roughly 1/7th difference across boundary */
    s = vp8_char_clamp(qs.s2 - u4.s2);
    *oq2 = s ^ 0x80;
    s = vp8_char_clamp(ps.s2 + u4.s2);
    *op2 = s ^ 0x80;
}

/* is there high variance internal edge ( 11111111 yes, 00000000 no) */
__inline signed char vp8_hevmask(signed char thresh, uc p1, uc p0, uc q0, uc q1)
{
    signed char hev = 0;
    hev  |= (abs(p1 - p0) > thresh) * -1;
    hev  |= (abs(q1 - q0) > 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,
     uc p3, uc p2, uc p1, uc p0, uc q0, uc q1, uc q2, uc q3)
{
    signed char mask = 0;
    mask |= (abs(p3 - p2) > limit) * -1;
    mask |= (abs(p2 - p1) > limit) * -1;
    mask |= (abs(p1 - p0) > limit) * -1;
    mask |= (abs(q1 - q0) > limit) * -1;
    mask |= (abs(q2 - q1) > limit) * -1;
    mask |= (abs(q3 - q2) > limit) * -1;
    mask |= (abs(p0 - q0) * 2 + abs(p1 - q1) / 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 = vp8_char_clamp(p1 - q1);
    vp8_filter = vp8_char_clamp(vp8_filter + 3 * (q0 - p0));
    vp8_filter &= mask;

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

    Filter2 = vp8_char_clamp(vp8_filter + 3);
    Filter2 >>= 3;
    u = vp8_char_clamp(p0 + Filter2);
    *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, uc, uc, uc, uc, uc, uc, uc, uc);
__inline signed char vp8_simple_filter_mask(signed char, signed char, uc, uc, uc, uc);
__inline signed char vp8_hevmask(signed char, uc, uc, uc, uc);

__inline void vp8_mbfilter(signed char mask,signed char hev,global uc *op2,
    global uc *op1,global uc *op0,global uc *oq0,global uc *oq1,global uc *oq2);

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

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,
    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 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 = vp8_char_clamp(ps1 - qs1);

    vp8_filter &= hev;

    /* inner taps */
    vp8_filter = vp8_char_clamp(vp8_filter + 3 * (qs0 - ps0));
    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 = vp8_char_clamp(vp8_filter + 4);
    Filter2 = vp8_char_clamp(vp8_filter + 3);
    Filter1 >>= 3;
    Filter2 >>= 3;
    u = vp8_char_clamp(qs0 - Filter1);
    *oq0 = u ^ 0x80;
    u = vp8_char_clamp(ps0 + Filter2);
    *op0 = u ^ 0x80;
    vp8_filter = Filter1;

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

    u = vp8_char_clamp(qs1 - vp8_filter);
    *oq1 = u ^ 0x80;
    u = vp8_char_clamp(ps1 + vp8_filter);
    *op1 = u ^ 0x80;
}

kernel void vp8_loop_filter_horizontal_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];
                    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];
                        if (use_mbflim == 0){
                            flimit = lf_info->flim;
                        } else {
                            flimit = lf_info->mbflim;
                        }

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

                        s_off += i;

                        mask = vp8_filter_mask(limit[i], flimit[i], s_base[s_off - 4*p],
                                s_base[s_off - 3*p], s_base[s_off - 2*p], s_base[s_off - p],
                                s_base[s_off], s_base[s_off + p], s_base[s_off + 2*p],
                                s_base[s_off + 3*p]);

                        hev = vp8_hevmask(thresh[i], s_base[s_off - 2*p], s_base[s_off - p],
                                s_base[s_off], s_base[s_off+p]);

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

kernel void vp8_loop_filter_vertical_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];
                    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];
                        if (use_mbflim == 0){
                            flimit = lf_info->flim;
                        } else {
                            flimit = lf_info->mbflim;
                        }

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

                        s_off += p * i;
                        mask = vp8_filter_mask(limit[i], flimit[i],
                                s_base[s_off-4], s_base[s_off-3], s_base[s_off-2],
                                s_base[s_off-1], s_base[s_off], s_base[s_off+1],
                                s_base[s_off+2], s_base[s_off+3]);

                        hev = vp8_hevmask(thresh[i], s_base[s_off-2], s_base[s_off-1],
                                s_base[s_off], s_base[s_off+1]);

                        vp8_filter(mask, hev, s_base, s_off - 2, s_off - 1, s_off, s_off + 1);

                    }
                }
            }
        }
    }
}

kernel void vp8_mbloop_filter_horizontal_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];

                    global uc *s = s_base+s_off;

                    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];
                        if (use_mbflim == 0){
                            flimit = lf_info->flim;
                        } else {
                            flimit = lf_info->mbflim;
                        }

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

                        s += i;

                        mask = vp8_filter_mask(limit[i], flimit[i],
                                               s[-4*p], s[-3*p], s[-2*p], s[-1*p],
                                               s[0*p], s[1*p], s[2*p], s[3*p]);

                        hev = vp8_hevmask(thresh[i], s[-2*p], s[-1*p], s[0*p], s[1*p]);

                        vp8_mbfilter(mask, hev, s - 3 * p, s - 2 * p, s - 1 * p, s, s + 1 * p, s + 2 * p);

                    }
                }
            }
        }
    }
}

kernel void vp8_mbloop_filter_vertical_edge_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];

                    global uc *s = s_base + s_off;

                    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];
                        if (use_mbflim == 0){
                            flimit = lf_info->flim;
                        } else {
                            flimit = lf_info->mbflim;
                        }

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

                        s += p * i;

                        mask = vp8_filter_mask(limit[i], flimit[i],
                                               s[-4], s[-3], s[-2], s[-1], s[0], s[1], s[2], s[3]);

                        hev = vp8_hevmask(thresh[i], s[-2], s[-1], s[0], s[1]);

                        vp8_mbfilter(mask, hev, s - 3, s - 2, s - 1, s, s + 1, s + 2);

                    }
                }
            }
        }
    }
}

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 *filter_levels,
    int use_mbflim,
    global int *threads,
    global int *apply_filters
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];

                    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 *filter_levels, /* Filter level for each block being processed */
    int use_mbflim, /* Use lfi->flim or lfi->mbflim, need once per kernel call */
    global int *threads, /* Thread counts per plane */
    global int *apply_filters /* Should the filter be applied (per block) */
)
{
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    if (plane < get_global_size(1)){
        if (block < get_global_size(2)){
            if (apply_filters[block] > 0){
                int filter_level = filter_levels[block];
                if (filter_level){
                    int p = pitches[plane];
                    int s_off = offsets[block*get_global_size(1)+plane];

                    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,
    global uc *op2,
    global uc *op1,
    global uc *op0,
    global uc *oq0,
    global uc *oq1,
    global uc *oq2
)
{
    signed char s;
    int3 s3, u3;
    signed char vp8_filter;

    char2 filter;

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

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

    /* add outer taps if we have high edge variance */
    vp8_filter = vp8_char_clamp(ps.s1 - qs.s1);
    vp8_filter = vp8_char_clamp(vp8_filter + 3 * (qs.s0 - ps.s0));
    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 += (char2){4,3};
    filter.s0 = vp8_char_clamp(filter.s0);
    filter.s1 = vp8_char_clamp(filter.s1);
    filter.s0 >>= 3;
    filter.s1 >>= 3;

    qs.s0 = vp8_char_clamp(qs.s0 - filter.s0);
    ps.s0 = vp8_char_clamp(ps.s0 + filter.s1);

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

    u3 = (int3){filter.s1, filter.s1, filter.s1};
    u3 *= (int3){27, 18, 9};
    u3 += 63;
    u3 >>= 7;
    u3.s0 = vp8_char_clamp(u3.s0);
    u3.s1 = vp8_char_clamp(u3.s1);
    u3.s2 = vp8_char_clamp(u3.s2);

    /* roughly 3/7th difference across boundary */
    s = vp8_char_clamp(qs.s0 - u3.s0);
    *oq0 = s ^ 0x80;
    s = vp8_char_clamp(ps.s0 + u3.s0);
    *op0 = s ^ 0x80;

    /* roughly 2/7th difference across boundary */
    s = vp8_char_clamp(qs.s1 - u3.s1);
    *oq1 = s ^ 0x80;
    s = vp8_char_clamp(ps.s1 + u3.s1);
    *op1 = s ^ 0x80;

    /* roughly 1/7th difference across boundary */
    s = vp8_char_clamp(qs.s2 - u3.s2);
    *oq2 = s ^ 0x80;
    s = vp8_char_clamp(ps.s2 + u3.s2);
    *op2 = s ^ 0x80;
}

/* is there high variance internal edge ( 11111111 yes, 00000000 no) */
__inline signed char vp8_hevmask(signed char thresh, uc p1, uc p0, uc q0, uc q1)
{
    signed char hev = 0;
    hev  |= (abs(p1 - p0) > thresh) * -1;
    hev  |= (abs(q1 - q0) > 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,
     uc p3, uc p2, uc p1, uc p0, uc q0, uc q1, uc q2, uc q3)
{
    signed char mask = 0;
    mask |= (abs(p3 - p2) > limit) * -1;
    mask |= (abs(p2 - p1) > limit) * -1;
    mask |= (abs(p1 - p0) > limit) * -1;
    mask |= (abs(q1 - q0) > limit) * -1;
    mask |= (abs(q2 - q1) > limit) * -1;
    mask |= (abs(q3 - q2) > limit) * -1;
    mask |= (abs(p0 - q0) * 2 + abs(p1 - q1) / 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 = vp8_char_clamp(p1 - q1);
    vp8_filter = vp8_char_clamp(vp8_filter + 3 * (q0 - p0));
    vp8_filter &= mask;

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

    Filter2 = vp8_char_clamp(vp8_filter + 3);
    Filter2 >>= 3;
    u = vp8_char_clamp(p0 + Filter2);
    *op0 = u ^ 0x80;
}


Forgot to change normalized coords flag back to FALSE

from when I was guessing earlier, now it works

I feel silly

__constant sampler_t nearest = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE
	| CLK_FILTER_NEAREST;

__constant sampler_t linear = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE
	| CLK_FILTER_LINEAR;

//For this simple test we'll just take a vector as the velocity
__kernel void simpleAdvect(__global float2 *vel, read_only image2d_t vals, write_only image2d_t valsNext)
{
	//We'll pick a time step
	float dt = 1.0f / 60.0f;
	int2 coord = (int2)(get_global_id(0), get_global_id(1));
	float2 x_n = (float2)(coord.x, coord.y);

	//We take only s01 since we're doing 2d, x/y values
	float2 x_nHalf = x_n - 0.5f * dt * (*vel);
	float2 x_nS = x_n - dt * (*vel);

	//Now sample the value where we "started" and set the next value at x_n to that one
	//We use the linear sampler to get linear interpolation at the traceposition for free
	//float4 tVal = read_imagef(vals, linear, x_nS);
	//float4 tVal = (float4)(0.5f, 0.0f, 0.0f, 1.0f);
	//write_imagef(valsNext, coord, tVal);
	float4 tVal = read_imagef(vals, nearest, coord);
	write_imagef(valsNext, coord, tVal);
}

__constant sampler_t nearest = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE
	| CLK_FILTER_NEAREST;

__constant sampler_t linear = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE
	| CLK_FILTER_LINEAR;

//For this simple test we'll just take a vector as the velocity
__kernel void simpleAdvect(__global float2 *vel, read_only image2d_t vals, write_only image2d_t valsNext)
{
	//We'll pick a time step
	float dt = 1.0f / 60.0f;
	int2 coord = (int2)(get_global_id(0), get_global_id(1));
	float2 x_n = (float2)(coord.x, coord.y);

	//We take only s01 since we're doing 2d, x/y values
	float2 x_nHalf = x_n - 0.5f * dt * (*vel);
	float2 x_nS = x_n - dt * (*vel);

	//Now sample the value where we "started" and set the next value at x_n to that one
	//We use the linear sampler to get linear interpolation at the traceposition for free
	//float4 tVal = read_imagef(vals, linear, x_nS);
	//float4 tVal = (float4)(0.5f, 0.0f, 0.0f, 1.0f);
	//write_imagef(valsNext, coord, tVal);
	float4 tVal = read_imagef(vals, nearest, coord);
	write_imagef(valsNext, coord, tVal);
}


math: Fix log2 vectorization on non-fp64 hw

reviewer: tstellard
Signed-off-by: Jan Vesely <jan.vesely@rutgers.edu>

git-svn-id: e7f1ab7c2a259259587475a3e7520e757882f167@260301 91177308-0d34-0410-b5e6-96231b3b80d8

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

#include <clc/clc.h>
#include "../clcmacro.h"
#include "tables.h"

#ifdef cl_khr_fp64
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#endif // cl_khr_fp64

#define COMPILING_LOG2
#include "log_base.h"
#undef COMPILING_LOG2

_CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, float, log2, float);

#ifdef cl_khr_fp64
_CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, log2, double);
#endif // cl_khr_fp64

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

#include <clc/clc.h>
#include "../clcmacro.h"
#include "tables.h"

#ifdef cl_khr_fp64
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#endif // cl_khr_fp64

#define COMPILING_LOG2
#include "log_base.h"
#undef COMPILING_LOG2

_CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, float, log2, float);

_CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, log2, double);


Added speed limitation

Added speed limitation

typedef struct
{
	float2 position;
	float2 velocity;
} mosquito;

typedef mosquito dragonfly;

__kernel void
rule_1 (__global mosquito* _swarm, __global float2* _mass_centre,
    const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 mass_centre = (float2)(0.0f, 0.0f);

	for (unsigned int i = 0; i < _swarm_size; i++)
	{
		if (i == idx) continue;
		mass_centre += _swarm[i].position;
	}

	mass_centre /= (float)(_swarm_size - 1);
	_mass_centre[idx] = mass_centre;
}

__kernel void
rule_2 (__global mosquito* _swarm, __global float2 *_centre,
    const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 centre = (float2)(0.0f, 0.0f);

	for (unsigned int i = 0; i < _swarm_size; i++)
	{
		if (i == idx) continue;
		float2 difference = _swarm[i].position - _swarm[idx].position;
		if (fast_length(difference) < 20.0f)
			centre -= difference;
	}

	_centre[idx] = centre;
}

__kernel void
rule_3 (__global mosquito* _swarm, __global float2 *_velocity,
    const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 velocity = (float2)(0.0f, 0.0f);

	for (unsigned int i = 0; i < _swarm_size; i++)
	{
		if (i == idx) continue;
		velocity += _swarm[i].velocity;
	}
	velocity /= (float)(_swarm_size - 1);
	velocity = _swarm[idx].velocity - velocity;
	velocity /= 2.0f;

	_velocity[idx] = velocity;
}

__kernel void
rule_4 (__global mosquito* _swarm, __global float2 *_border_force,
    const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 top_velocity = (float2)(0.0f, 0.0f);
	float2 bottom_velocity = (float2)(0.0f, 0.0f);
	float2 left_velocity = (float2)(0.0f, 0.0f);
	float2 right_velocity = (float2)(0.0f, 0.0f);

	if (_swarm[idx].position.x == 0.0f
	 || _swarm[idx].position.y == 0.0f
	 || _swarm[idx].position.x == 600.0f
	 || _swarm[idx].position.y == 600.0f)
	{
		_border_force[idx] = (float2)(0.0f, 0.0f);
		return;
	}

	top_velocity.y = fabs(20.0f / _swarm[idx].position.y);
	bottom_velocity.y = -fabs(20.0f / (_swarm[idx].position.y - 600.0f));
	left_velocity.x = fabs(20.0f / _swarm[idx].position.x);
	right_velocity.x = -fabs(20.0f / (_swarm[idx].position.x - 600.0f));

	float2 result = top_velocity + bottom_velocity + left_velocity +
	    right_velocity;
	result /= 0.1f;

	_border_force[idx] = result;
}

__kernel void
rule_5 (__global mosquito* _swarm, __global float2 *_fear,
    __global dragonfly *_predator, const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 result = _swarm[idx].position - _predator->position;
	result /= 60.0f;

	_fear[idx] = result;
}

__kernel void
single_step (__global mosquito* _swarm, __global float2* _rule_1,
    __global float2* _rule_2, __global float2* _rule_3,
    __global float2* _rule_4, __global float2* _rule_5,
    __global mosquito* _new_swarm)
{
	unsigned int idx = get_global_id(0);
	float2 velocity = _rule_1[idx] + _rule_2[idx] + _rule_3[idx] + _rule_4[idx]
	    + _rule_5[idx];
	velocity /= 10000.0f;

	if (velocity.length() > 0.2f)
		velocity = normalize(velocity) * 0.2f;

	_new_swarm[idx].velocity = _swarm[idx].velocity + velocity;
	_new_swarm[idx].position = _swarm[idx].position + _swarm[idx].velocity
	    + velocity;
}

typedef struct
{
	float2 position;
	float2 velocity;
} mosquito;

typedef mosquito dragonfly;

__kernel void
rule_1 (__global mosquito* _swarm, __global float2* _mass_centre,
    const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 mass_centre = (float2)(0.0f, 0.0f);

	for (unsigned int i = 0; i < _swarm_size; i++)
	{
		if (i == idx) continue;
		mass_centre += _swarm[i].position;
	}

	mass_centre /= (float)(_swarm_size - 1);
	_mass_centre[idx] = mass_centre;
}

__kernel void
rule_2 (__global mosquito* _swarm, __global float2 *_centre,
    const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 centre = (float2)(0.0f, 0.0f);

	for (unsigned int i = 0; i < _swarm_size; i++)
	{
		if (i == idx) continue;
		float2 difference = _swarm[i].position - _swarm[idx].position;
		if (fast_length(difference) < 20.0f)
			centre -= difference;
	}

	_centre[idx] = centre;
}

__kernel void
rule_3 (__global mosquito* _swarm, __global float2 *_velocity,
    const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 velocity = (float2)(0.0f, 0.0f);

	for (unsigned int i = 0; i < _swarm_size; i++)
	{
		if (i == idx) continue;
		velocity += _swarm[i].velocity;
	}
	velocity /= (float)(_swarm_size - 1);
	velocity = _swarm[idx].velocity - velocity;
	velocity /= 2.0f;

	_velocity[idx] = velocity;
}

__kernel void
rule_4 (__global mosquito* _swarm, __global float2 *_border_force,
    const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 top_velocity = (float2)(0.0f, 0.0f);
	float2 bottom_velocity = (float2)(0.0f, 0.0f);
	float2 left_velocity = (float2)(0.0f, 0.0f);
	float2 right_velocity = (float2)(0.0f, 0.0f);

	if (_swarm[idx].position.x == 0.0f
	 || _swarm[idx].position.y == 0.0f
	 || _swarm[idx].position.x == 600.0f
	 || _swarm[idx].position.y == 600.0f)
	{
		_border_force[idx] = (float2)(0.0f, 0.0f);
		return;
	}

	top_velocity.y = fabs(20.0f / _swarm[idx].position.y);
	bottom_velocity.y = -fabs(20.0f / (_swarm[idx].position.y - 600.0f));
	left_velocity.x = fabs(20.0f / _swarm[idx].position.x);
	right_velocity.x = -fabs(20.0f / (_swarm[idx].position.x - 600.0f));

	float2 result = top_velocity + bottom_velocity + left_velocity +
	    right_velocity;
	result /= 0.1f;

	_border_force[idx] = result;
}

__kernel void
rule_5 (__global mosquito* _swarm, __global float2 *_fear,
    __global dragonfly *_predator, const unsigned int _swarm_size)
{
	unsigned int idx = get_global_id(0);
	float2 result = _swarm[idx].position - _predator->position;
	result /= 60.0f;

	_fear[idx] = result;
}

__kernel void
single_step (__global mosquito* _swarm, __global float2* _rule_1,
    __global float2* _rule_2, __global float2* _rule_3,
    __global float2* _rule_4, __global float2* _rule_5,
    __global mosquito* _new_swarm)
{
	unsigned int idx = get_global_id(0);
	float2 velocity = _rule_1[idx] + _rule_2[idx] + _rule_3[idx] + _rule_4[idx]
	    + _rule_5[idx];
	velocity /= 10000.0f;

	_new_swarm[idx].velocity = _swarm[idx].velocity + velocity;
	_new_swarm[idx].position = _swarm[idx].position + _swarm[idx].velocity
	    + velocity;
}