Combine ps and qs in vp8_mbfilter into a single char8.

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

__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};

#ifndef __CL_VERSION_1_0__
#define __CL_VERSION_1_0__ 100
#endif

#if __OPENCL_VERSION__ == __CL_VERSION_1_0__
#define clamp(x,y,z) vp8_char_clamp(x)
char vp8_char_clamp(int in){
    if (in > 127)
        return 127;
    if (in < -128)
        return -128;

    return in;
}
#endif

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

typedef struct
{
    int mb_rows;
    int mb_cols;
} frame_info;

uchar4 vp8_filter(
    signed char mask,
    signed char hev,
    uchar4 base
)
{
    char4 pq = convert_char4(base) ^ 0x80;

    char vp8_filter;
    char2 Filter;
    char4 u;

    /* add outer taps if we have high edge variance */
    vp8_filter = sub_sat(pq.s0, pq.s3);
    vp8_filter &= hev;

    /* inner taps */
    vp8_filter = clamp(vp8_filter + 3 * (pq.s2 - pq.s1), -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
     */
    Filter = add_sat((char2)vp8_filter, (char2){4,3});
    Filter.s0 >>= 3;
    Filter.s1 >>= 3;

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

    //u.s01 = add_sat(pq.s01, (char2){vp8_filter, Filter.s1});
    //u.s23 = sub_sat(pq.s23, (char2){Filter.s0, vp8_filter});
    u.s0 = clamp(pq.s0 + vp8_filter, -128, 127);
    u.s1 = clamp(pq.s1 + Filter.s1, -128, 127);
    u.s2 = clamp(pq.s2 - Filter.s0, -128, 127);
    u.s3 = clamp(pq.s3 - vp8_filter, -128, 127);

    return convert_uchar4(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
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes = 3;
    size_t num_blocks = get_global_size(2);
    int filter_level = filters[block];

    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];

                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;

                    uchar8 data;
                    data.s0 = s_base[s_off-4*p];
                    data.s1 = s_base[s_off-3*p];
                    data.s2 = s_base[s_off-2*p];
                    data.s3 = s_base[s_off-p];
                    data.s4 = s_base[s_off];
                    data.s5 = s_base[s_off+p];
                    data.s6 = s_base[s_off+2*p];
                    data.s7 = s_base[s_off+3*p];

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

                    hev = vp8_hevmask(thresh[i], data.s2345);

                    data.s2345 = vp8_filter(mask, hev, data.s2345);

                    s_base[s_off - 2*p] = data.s2;
                    s_base[s_off - p  ] = data.s3;
                    s_base[s_off      ] = data.s4;
                    s_base[s_off + p  ] = data.s5;

                }
            }
        }
    }
}

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
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes = 3;
    size_t 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];

            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;

                uchar8 data = vload8(0, &s_base[s_off-4]);

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

                hev = vp8_hevmask(thresh[i], data.s2345);

                data.s2345 = vp8_filter(mask, hev, data.s2345);

                vstore4(data.s2345, 0, &s_base[s_off-2]);

            }
        }
    }
}

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,
    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];

            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;

#if 1
                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];
                uchar8 data = vload8(0, s_data);
#else
                uchar8 data;
                data.s0 = s_base[s_off-4*p];
                data.s1 = s_base[s_off-3*p];
                data.s2 = s_base[s_off-2*p];
                data.s3 = s_base[s_off-p];
                data.s4 = s_base[s_off];
                data.s5 = s_base[s_off+p];
                data.s6 = s_base[s_off+2*p];
                data.s7 = s_base[s_off+3*p];
#endif

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

                hev = vp8_hevmask(thresh[i], data.s2345);

                //TODO: change vp8_mbfilter to use uchar8 instead of local uchar*
                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_in,
    int use_mbflim, //unused for normal filters
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    local unsigned char s_data[16*8*3];

    int filter_offset = 4*block_offset;
    int priority_offset = 16*block_offset;

    global int *filters = &filters_in[filter_offset];

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

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

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,
    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];

            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];

                uchar8 data = vload8(0, s_data);
                mask = vp8_filter_mask(limit[i], flimit[i], data);

                hev = vp8_hevmask(thresh[i], data.s2345);

                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_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){

    int block_offset = block_offsets[priority_level];
    local unsigned char s_data[16*8*3];
    int filter_offset = 4*block_offset;
    int priority_offset = 16*block_offset;

    global int *filters = &filters_in[filter_offset];

    //Prefetch vertical edge source pixels into global cache
    int num_blocks = get_global_size(2);
    for(int plane = 0; plane < 3; plane++){
        int p = pitches[plane];
        int offset = get_global_id(2)*3+plane;
        int s_off = offsets[offset+priority_offset];
        for (int thread = 0; thread < 16; thread++){
            prefetch(&s_base[s_off+p*thread-4], 8);
        }
    }

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

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

    barrier(CLK_GLOBAL_MEM_FENCE);

    //Prefetch horizontal source pixels
#if 0
    for(int plane = 0; plane < 3; plane++){
        int p = pitches[plane];
        int offset = get_global_id(2)*3+plane;
        int s_off = offsets[offset+priority_offset];
        for (int thread = 0; thread < 16; thread++){
            prefetch(&s_base[s_off+thread-4*p], 8*p);
        }
    }
#endif

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

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

}

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_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    local unsigned char s_data[16*8*3];
    int filter_offset = 4*block_offset;
    int priority_offset = 16*block_offset;

    global int *filters = &filters_in[filter_offset];

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

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

}

void vp8_loop_filter_simple_horizontal_edge_worker
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    int filter_offset = 4*block_offset;
    int priority_offset = 8*block_offset;
    private size_t plane = get_global_id(1);
    private size_t block = get_global_id(2);
    size_t num_planes = get_global_size(1);
    size_t num_blocks = get_global_size(2);

    global int *filters = &filters_in[filter_offset];

    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);
            }
        }
    }
}

void vp8_loop_filter_simple_vertical_edge_worker(
    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_in, /* 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_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    int filter_offset = 4*block_offset;
    int priority_offset = 8*block_offset;
    private size_t block = get_global_id(2);
    size_t num_blocks = get_global_size(2);

    global int *filters = &filters_in[filter_offset];

    if (filters[filter_type * num_blocks + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[0];
            int block_offset = cur_iter*num_blocks + block;
            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[0]){
                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);
            }
        }
    }
}

kernel void vp8_loop_filter_simple_vertical_edges_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_in, /* 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_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 1, COLS_LOCATION, 0, priority_level,
            block_offsets, priority_num_blocks
    );

    //3 Y plane iterations
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 1, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 2, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 3, priority_level,
            block_offsets, priority_num_blocks
    );
}

kernel void vp8_loop_filter_simple_horizontal_edges_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 1, ROWS_LOCATION, 4, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 5, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 6, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 7, priority_level,
            block_offsets, priority_num_blocks
    );
}

kernel void vp8_loop_filter_simple_all_edges_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
)
{

    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 1, COLS_LOCATION, 0, priority_level,
            block_offsets, priority_num_blocks
    );

    //3 Y plane iterations
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 1, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 2, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 3, priority_level,
            block_offsets, priority_num_blocks
    );

    barrier(CLK_GLOBAL_MEM_FENCE);

    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 1, ROWS_LOCATION, 4, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 5, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 6, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 7, priority_level,
            block_offsets, priority_num_blocks
    );
}

//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;

    char8 pq = { *op0, *op1, *op2, 0, *oq0, *oq1, *oq2, 0 };
    pq ^= (char8)0x80;

    /* add outer taps if we have high edge variance */
    vp8_filter = clamp(pq.s1 - pq.s5, -128, 127);
    vp8_filter = clamp(vp8_filter + 3 * (pq.s4 - pq.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;

    pq.s4 = clamp(pq.s4 - filter.s0, -128, 127);
    pq.s0 = clamp(pq.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(pq.s4 - u, -128, 127);
    *oq0 = s ^ 0x80;
    s = clamp(pq.s0 + u, -128, 127);
    *op0 = s ^ 0x80;

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

    /* roughly 1/7th difference across boundary */
    u = clamp((63 + filter.s1 * 9) >> 7, -128, 127);
    s = clamp(pq.s6 - u, -128, 127);
    *oq2 = s ^ 0x80;
    s = clamp(pq.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, uchar4 pq)
{
    signed char hev = 0;
    hev  |= (abs(pq.s0 - pq.s1) > thresh) * -1;
    hev  |= (abs(pq.s3 - pq.s2) > 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,
        uchar8 pq)
{
    signed char mask = 0;

#if 1
    mask |= (abs(pq.s0 - pq.s1) > limit) * -1;
    mask |= (abs(pq.s1 - pq.s2) > limit) * -1;
    mask |= (abs(pq.s2 - pq.s3) > limit) * -1;
    mask |= (abs(pq.s5 - pq.s4) > limit) * -1;
    mask |= (abs(pq.s6 - pq.s5) > limit) * -1;
    mask |= (abs(pq.s7 - pq.s6) > limit) * -1;
    mask |= (abs(pq.s3 - pq.s4) * 2 + abs(pq.s2 - pq.s5) / 2  > flimit * 2 + limit) * -1;
    mask = ~mask;
    return mask;
#else
    //Only apply the filter if the difference is LESS than 'limit'
    mask |= (abs(pq.s0 - pq.s1) > limit);
    mask |= (abs(pq.s1 - pq.s2) > limit);
    mask |= (abs(pq.s2 - pq.s3) > limit);
    mask |= (abs(pq.s5 - pq.s4) > limit);
    mask |= (abs(pq.s6 - pq.s5) > limit);
    mask |= (abs(pq.s7 - pq.s6) > limit);
    mask |= (abs(pq.s3 - pq.s4) * 2 + abs(pq.s2 - pq.s5) / 2  > flimit * 2 + limit);

    return (mask != 0 ? 0 : -1);
#endif

}

/* 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, uchar8);
__inline signed char vp8_simple_filter_mask(signed char, signed char, uc, uc, uc, uc);
__inline signed char vp8_hevmask(signed char, uchar4);

__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};

#ifndef __CL_VERSION_1_0__
#define __CL_VERSION_1_0__ 100
#endif

#if __OPENCL_VERSION__ == __CL_VERSION_1_0__
#define clamp(x,y,z) vp8_char_clamp(x)
char vp8_char_clamp(int in){
    if (in > 127)
        return 127;
    if (in < -128)
        return -128;

    return in;
}
#endif

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

typedef struct
{
    int mb_rows;
    int mb_cols;
} frame_info;

uchar4 vp8_filter(
    signed char mask,
    signed char hev,
    uchar4 base
)
{
    char4 pq = convert_char4(base) ^ 0x80;

    char vp8_filter;
    char2 Filter;
    char4 u;

    /* add outer taps if we have high edge variance */
    vp8_filter = sub_sat(pq.s0, pq.s3);
    vp8_filter &= hev;

    /* inner taps */
    vp8_filter = clamp(vp8_filter + 3 * (pq.s2 - pq.s1), -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
     */
    Filter = add_sat((char2)vp8_filter, (char2){4,3});
    Filter.s0 >>= 3;
    Filter.s1 >>= 3;

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

    //u.s01 = add_sat(pq.s01, (char2){vp8_filter, Filter.s1});
    //u.s23 = sub_sat(pq.s23, (char2){Filter.s0, vp8_filter});
    u.s0 = clamp(pq.s0 + vp8_filter, -128, 127);
    u.s1 = clamp(pq.s1 + Filter.s1, -128, 127);
    u.s2 = clamp(pq.s2 - Filter.s0, -128, 127);
    u.s3 = clamp(pq.s3 - vp8_filter, -128, 127);

    return convert_uchar4(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
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes = 3;
    size_t num_blocks = get_global_size(2);
    int filter_level = filters[block];

    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];

                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;

                    uchar8 data;
                    data.s0 = s_base[s_off-4*p];
                    data.s1 = s_base[s_off-3*p];
                    data.s2 = s_base[s_off-2*p];
                    data.s3 = s_base[s_off-p];
                    data.s4 = s_base[s_off];
                    data.s5 = s_base[s_off+p];
                    data.s6 = s_base[s_off+2*p];
                    data.s7 = s_base[s_off+3*p];

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

                    hev = vp8_hevmask(thresh[i], data.s2345);

                    data.s2345 = vp8_filter(mask, hev, data.s2345);

                    s_base[s_off - 2*p] = data.s2;
                    s_base[s_off - p  ] = data.s3;
                    s_base[s_off      ] = data.s4;
                    s_base[s_off + p  ] = data.s5;

                }
            }
        }
    }
}

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
){
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_planes = 3;
    size_t 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];

            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;

                uchar8 data = vload8(0, &s_base[s_off-4]);

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

                hev = vp8_hevmask(thresh[i], data.s2345);

                data.s2345 = vp8_filter(mask, hev, data.s2345);

                vstore4(data.s2345, 0, &s_base[s_off-2]);

            }
        }
    }
}

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,
    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];

            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;

#if 1
                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];
                uchar8 data = vload8(0, s_data);
#else
                uchar8 data;
                data.s0 = s_base[s_off-4*p];
                data.s1 = s_base[s_off-3*p];
                data.s2 = s_base[s_off-2*p];
                data.s3 = s_base[s_off-p];
                data.s4 = s_base[s_off];
                data.s5 = s_base[s_off+p];
                data.s6 = s_base[s_off+2*p];
                data.s7 = s_base[s_off+3*p];
#endif

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

                hev = vp8_hevmask(thresh[i], data.s2345);

                //TODO: change vp8_mbfilter to use uchar8 instead of local uchar*
                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_in,
    int use_mbflim, //unused for normal filters
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    local unsigned char s_data[16*8*3];

    int filter_offset = 4*block_offset;
    int priority_offset = 16*block_offset;

    global int *filters = &filters_in[filter_offset];

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

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

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,
    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];

            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];

                uchar8 data = vload8(0, s_data);
                mask = vp8_filter_mask(limit[i], flimit[i], data);

                hev = vp8_hevmask(thresh[i], data.s2345);

                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_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){

    int block_offset = block_offsets[priority_level];
    local unsigned char s_data[16*8*3];
    int filter_offset = 4*block_offset;
    int priority_offset = 16*block_offset;

    global int *filters = &filters_in[filter_offset];

    //Prefetch vertical edge source pixels into global cache
    int num_blocks = get_global_size(2);
    for(int plane = 0; plane < 3; plane++){
        int p = pitches[plane];
        int offset = get_global_id(2)*3+plane;
        int s_off = offsets[offset+priority_offset];
        for (int thread = 0; thread < 16; thread++){
            prefetch(&s_base[s_off+p*thread-4], 8);
        }
    }

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

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

    barrier(CLK_GLOBAL_MEM_FENCE);

    //Prefetch horizontal source pixels
#if 0
    for(int plane = 0; plane < 3; plane++){
        int p = pitches[plane];
        int offset = get_global_id(2)*3+plane;
        int s_off = offsets[offset+priority_offset];
        for (int thread = 0; thread < 16; thread++){
            prefetch(&s_base[s_off+thread-4*p], 8*p);
        }
    }
#endif

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

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

}

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_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    local unsigned char s_data[16*8*3];
    int filter_offset = 4*block_offset;
    int priority_offset = 16*block_offset;

    global int *filters = &filters_in[filter_offset];

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

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

}

void vp8_loop_filter_simple_horizontal_edge_worker
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    int filter_offset = 4*block_offset;
    int priority_offset = 8*block_offset;
    private size_t plane = get_global_id(1);
    private size_t block = get_global_id(2);
    size_t num_planes = get_global_size(1);
    size_t num_blocks = get_global_size(2);

    global int *filters = &filters_in[filter_offset];

    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);
            }
        }
    }
}

void vp8_loop_filter_simple_vertical_edge_worker(
    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_in, /* 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_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    int filter_offset = 4*block_offset;
    int priority_offset = 8*block_offset;
    private size_t block = get_global_id(2);
    size_t num_blocks = get_global_size(2);

    global int *filters = &filters_in[filter_offset];

    if (filters[filter_type * num_blocks + block] > 0){
        int filter_level = filters[block];
        if (filter_level){
            int p = pitches[0];
            int block_offset = cur_iter*num_blocks + block;
            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[0]){
                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);
            }
        }
    }
}

kernel void vp8_loop_filter_simple_vertical_edges_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_in, /* 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_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 1, COLS_LOCATION, 0, priority_level,
            block_offsets, priority_num_blocks
    );

    //3 Y plane iterations
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 1, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 2, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 3, priority_level,
            block_offsets, priority_num_blocks
    );
}

kernel void vp8_loop_filter_simple_horizontal_edges_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 1, ROWS_LOCATION, 4, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 5, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 6, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 7, priority_level,
            block_offsets, priority_num_blocks
    );
}

kernel void vp8_loop_filter_simple_all_edges_kernel
(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters_in,
    int use_mbflim,
    int filter_type,
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
)
{

    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 1, COLS_LOCATION, 0, priority_level,
            block_offsets, priority_num_blocks
    );

    //3 Y plane iterations
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 1, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 2, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 0, DC_DIFFS_LOCATION, 3, priority_level,
            block_offsets, priority_num_blocks
    );

    barrier(CLK_GLOBAL_MEM_FENCE);

    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 1, ROWS_LOCATION, 4, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 5, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 6, priority_level,
            block_offsets, priority_num_blocks
    );
    vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
            filters_in, 0, DC_DIFFS_LOCATION, 7, priority_level,
            block_offsets, priority_num_blocks
    );
}

//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, uchar4 pq)
{
    signed char hev = 0;
    hev  |= (abs(pq.s0 - pq.s1) > thresh) * -1;
    hev  |= (abs(pq.s3 - pq.s2) > 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,
        uchar8 pq)
{
    signed char mask = 0;

#if 1
    mask |= (abs(pq.s0 - pq.s1) > limit) * -1;
    mask |= (abs(pq.s1 - pq.s2) > limit) * -1;
    mask |= (abs(pq.s2 - pq.s3) > limit) * -1;
    mask |= (abs(pq.s5 - pq.s4) > limit) * -1;
    mask |= (abs(pq.s6 - pq.s5) > limit) * -1;
    mask |= (abs(pq.s7 - pq.s6) > limit) * -1;
    mask |= (abs(pq.s3 - pq.s4) * 2 + abs(pq.s2 - pq.s5) / 2  > flimit * 2 + limit) * -1;
    mask = ~mask;
    return mask;
#else
    //Only apply the filter if the difference is LESS than 'limit'
    mask |= (abs(pq.s0 - pq.s1) > limit);
    mask |= (abs(pq.s1 - pq.s2) > limit);
    mask |= (abs(pq.s2 - pq.s3) > limit);
    mask |= (abs(pq.s5 - pq.s4) > limit);
    mask |= (abs(pq.s6 - pq.s5) > limit);
    mask |= (abs(pq.s7 - pq.s6) > limit);
    mask |= (abs(pq.s3 - pq.s4) * 2 + abs(pq.s2 - pq.s5) / 2  > flimit * 2 + limit);

    return (mask != 0 ? 0 : -1);
#endif

}

/* 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;
}


cleaned a bit the code

cleaned a bit the code

#include "kernel_header.h"
#include "kernel_matrix.h"
#include "kernel_cam.h"
#include "kernel_color.h"
#include "kernel_cone.h"
#include "kernel_cylinder.h"
#include "kernel_data.h"
#include "kernel_debug.h"
#include "kernel_plane.h"
#include "kernel_sphere.h"

float3					rotate_obj(float3 v, float pitch, float yaw, float roll)
{
	float3				res;

	res = rotat_zyx(v, pitch, yaw, roll);

	return (normalize(res));
}

static t_hit			ray_hit(const float3 origin, const float3 ray, const t_scene scene)
{
	unsigned int			i = 0;
	int						max = get_max_obj(PARAM);
	t_hit					hit = hit_init();
	float					dist = 0;

	while (i < max)
	{
		if (i < PARAM->n_cones)
			if (((dist = inter_cone(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 1;
				hit.id = i;
			}
		if (i < PARAM->n_cylinders)
			if (((dist = inter_cylinder(CYLIND[i], ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
		//	if (((dist = inter_cylinder(CYLIND[i].height, rotate_obj(CYLIND[i].dir, CYLIND[i].pitch, CYLIND[i].yaw, 0), CYLIND[i].radius, CYLIND[i].pos, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 2;
				hit.id = i;
			}
		if (i < PARAM->n_planes)
			if (((dist = inter_plan(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 4;
				hit.id = i;
			}
		if (i < PARAM->n_spheres)
			if (((dist = inter_sphere(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 5;
				hit.id = i;
			}
		i++;
	}
	return (hit);
}

float3			rotate_matrix(float angle, float3 v)
{
	float3		res;

	res.x = v.x;
	res.y = (cos(angle) * v.y) - (sin(angle) * v.z);
	res.z = (sin(angle) * v.y) + (cos(angle) * v.z);
	return (res);
}

float16			trans_matrix(float3 dir, float angle)
{
	float16		res = 0;
	float3		rot = 0;

	rot = rotate_obj(dir, 0, angle, 0);
	res[0] = rot.x;
	res[1] = rot.y;
	res[2] = rot.z;
	rot = rotate_obj(dir, -angle, 0, 0);
	res[4] = rot.x;
	res[5] = rot.y;
	res[6] = rot.z;
	res[8] = dir.x;
	res[9] = dir.y;
	res[10] = dir.z;
	return (res);
}

float3			apply_matrix(float16 mat, float3 v)
{
	float3		res = 0;

	res.x = mat[0] * v.x + mat[4] * v.y + mat[8] * v.z;
	res.y = mat[1] * v.x + mat[5] * v.y + mat[9] * v.z;
	res.z = mat[2] * v.x + mat[6] * v.y + mat[10] * v.z;
	return (res);
}

float3			get_hit_normale(t_scene scene, t_hit hit)
{
	float3		res;

	if (hit.type == 1)
		res = get_cone_normale(scene, hit);
	else if (hit.type == 2)
		res = get_cylinder_normal(scene, hit);
	else if (hit.type == 4)
	{
		if (dot(PLANE[hit.id].normale, -scene.ray) < 0)
			res = -PLANE[hit.id].normale;
		else
			res = PLANE[hit.id].normale;
	}
	else if (hit.type == 5)
		res = hit.pos - SPHERE[hit.id].pos;
	return (fast_normalize(res));
}

static unsigned int			phong(const t_hit hit, const t_scene scene)
{
	int					i = -1;
	unsigned int		res_color = get_ambient(scene, get_obj_hue(scene, hit));
	float				tmp;
	float3				reflect = 0;

	t_light_ray			light_ray;
	t_hit				light_hit = hit_init();

	while (++i < PARAM->n_lights)
	{
		tmp = 0;
		light_ray.dir = LIGHT[i].pos - hit.pos;
		light_ray.dist = length(light_ray.dir);
		light_ray.dir = normalize(light_ray.dir);
		light_hit = ray_hit(hit.pos, light_ray.dir, scene);
		light_hit.id = i;
		light_hit.type = 3;
		if (light_hit.dist < light_ray.dist && light_hit.dist > 0)
		;
		else
		{
			tmp = dot(hit.normale, light_ray.dir);
			if (tmp > 0)
				res_color = color_diffuse(scene, hit, light_hit, res_color, tmp);
			reflect = normalize(((float)(2.0 * dot(hit.normale, light_ray.dir)) * hit.normale) - light_ray.dir);
			tmp = dot(reflect, -scene.ray);
			if (tmp > 0)
				res_color = color_specular(scene, hit, light_hit, res_color, tmp);
		}
	}
	return (res_color);
}

unsigned int			phong2(t_hit hit, t_scene scene)
{
	int					i = -1;
	unsigned int		res_color = get_ambient(scene, get_obj_hue(scene, hit));
	float				tmp = 0;
	float3				reflect = 0;

	t_light_ray			light_ray;
	t_hit				light_hit;

	while (++i < PARAM->n_lights)
	{
		light_ray.dir = LIGHT[i].pos - hit.pos;
		light_ray.dist = length(light_ray.dir);
		light_ray.dir = normalize(light_ray.dir);
		light_hit = ray_hit(hit.pos, light_ray.dir, scene);
		if (light_hit.dist < light_ray.dist && light_hit.dist > 0)
		;
		else
		{
			tmp = dot(hit.normale, light_ray.dir);
			if (tmp > 0)
				res_color = color_diffuse(scene, hit, light_hit, res_color, tmp);
			reflect = normalize(((float)(2.0 * dot(hit.normale, light_ray.dir)) * hit.normale) - light_ray.dir);
			tmp = dot(reflect, -scene.ray);
			if (tmp > 0)
				res_color = color_specular(scene, hit, light_hit, res_color, tmp);
		}
	}
	return (res_color);
}

static unsigned int		bounce(const t_scene scene, const t_hit old_hit, const int depth)
{
	int				i = depth;
	unsigned int	color = 0;
	float3			reflex = 0;
	t_hit			new_hit;
	while (i > 0)
	{
		reflex = normalize(scene.ray - (2 * (float)dot(old_hit.normale, scene.ray) * old_hit.normale));
		new_hit.dist = MAX_DIST;
		new_hit = ray_hit(old_hit.pos, reflex, scene);
		if (new_hit.dist > 0 && new_hit.dist < MAX_DIST)
		{
			new_hit.pos = (new_hit.dist * reflex) + old_hit.pos;
			new_hit.normale = get_hit_normale(scene, new_hit);
			new_hit.pos = new_hit.pos + ((new_hit.dist / 100) * new_hit.normale);
			color += 0.1 * phong2(new_hit, scene);
		}
		i--;
	}
	return (color);
}

static unsigned int	get_pixel_color(const t_scene scene)
{
	t_hit			hit;
	int				depth = PARAM->depth;
	unsigned int	color  = 0;
	unsigned int	bounce_color = 0;

	hit.dist = MAX_DIST;
	hit = ray_hit((ACTIVECAM.pos + PARAM->mvt), scene.ray, scene);
	if (hit.dist > 0 && hit.dist < MAX_DIST) // ajout d'une distance max pour virer acnee mais pas fiable a 100%
	{
		hit.pos = (hit.dist * scene.ray) + (ACTIVECAM.pos + PARAM->mvt);
		hit.normale = get_hit_normale(scene, hit);
		hit.pos = hit.pos + ((hit.dist / 100) * hit.normale);
		color = phong(hit, scene);
		if (depth > 0)
			bounce_color = bounce(scene, hit, depth);
		return (color + bounce_color);
//		return (blend_add(color, 0.8*bounce_color));
	}
	return (get_ambient(scene, BACKCOLOR));
}

__kernel void	ray_trace(__global		char		*output,
						  				t_param		param,
						  __constant	t_cam		*cameras,
						  __constant	t_cone		*cones,
						  __constant	t_cylinder	*cylinders,
						  __constant	t_light		*lights,
						  __constant	t_plane		*planes,
						  __constant	t_sphere	*spheres,
						  __global		t_hit		*target_obj)
{
	t_scene		scene = grab_data(cameras, cones, cylinders, lights, planes, spheres, param);
	scene.pix.x = get_global_id(0);
	scene.pix.y = get_global_id(1);
	int			id = scene.pix.x + (PARAM->win_w * scene.pix.y); // NE PAS VIRER ID CAR BESOIN DANS MACRO OUTPUTE
	scene.ray = get_ray_cam(ACTIVECAM, scene, scene.pix.x ,scene.pix.y);
	if (scene.pix.x == PARAM->mou_x && scene.pix.y == PARAM->mou_y)
		*target_obj = ray_hit((ACTIVECAM.pos + PARAM->mvt), scene.ray, scene);
	OUTPUTE = get_pixel_color(scene);
}

#include "kernel_header.h"
#include "kernel_matrix.h"
#include "kernel_cam.h"
#include "kernel_color.h"
#include "kernel_cone.h"
#include "kernel_cylinder.h"
#include "kernel_data.h"
#include "kernel_debug.h"
#include "kernel_plane.h"
#include "kernel_sphere.h"

float3					rotate_obj(float3 v, float pitch, float yaw, float roll)
{
	float3				res;

	res = rotat_zyx(v, pitch, yaw, roll);

	return (normalize(res));
}

static t_hit			ray_hit(const float3 origin, const float3 ray, const t_scene scene)
{
	unsigned int			i = 0;
	int						max = get_max_obj(PARAM);
	t_hit					hit = hit_init();
	float					dist = 0;

	while (i < max)
	{
		if (i < PARAM->n_cones)
			if (((dist = inter_cone(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 1;
				hit.id = i;
			}
		if (i < PARAM->n_cylinders)
			if (((dist = inter_cylinder(CYLIND[i], ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
		//	if (((dist = inter_cylinder(CYLIND[i].height, rotate_obj(CYLIND[i].dir, CYLIND[i].pitch, CYLIND[i].yaw, 0), CYLIND[i].radius, CYLIND[i].pos, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 2;
				hit.id = i;
			}
		if (i < PARAM->n_planes)
			if (((dist = inter_plan(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 4;
				hit.id = i;
			}
		if (i < PARAM->n_spheres)
			if (((dist = inter_sphere(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 5;
				hit.id = i;
			}
		i++;
	}
	return (hit);
}

float3			rotate_matrix(float angle, float3 v)
{
	float3		res;

	res.x = v.x;
	res.y = (cos(angle) * v.y) - (sin(angle) * v.z);
	res.z = (sin(angle) * v.y) + (cos(angle) * v.z);
	return (res);
}

float16			trans_matrix(float3 dir, float angle)
{
	float16		res = 0;
	float3		rot = 0;

	rot = rotate_obj(dir, 0, angle, 0);
	res[0] = rot.x;
	res[1] = rot.y;
	res[2] = rot.z;
	rot = rotate_obj(dir, -angle, 0, 0);
	res[4] = rot.x;
	res[5] = rot.y;
	res[6] = rot.z;
	res[8] = dir.x;
	res[9] = dir.y;
	res[10] = dir.z;
	return (res);
}

float3			apply_matrix(float16 mat, float3 v)
{
	float3		res = 0;

	res.x = mat[0] * v.x + mat[4] * v.y + mat[8] * v.z;
	res.y = mat[1] * v.x + mat[5] * v.y + mat[9] * v.z;
	res.z = mat[2] * v.x + mat[6] * v.y + mat[10] * v.z;
	return (res);
}

float3			get_hit_normale(t_scene scene, t_hit hit)
{
	float3		res;

	if (hit.type == 1)
	{
		res = get_cone_normale(scene, hit);
	//	float k = radians(CONES[hit.id].angle);
	//	k = tan(k);
	//	k = 1 + k * k;
	//	res = dot(-scene.ray, fast_normalize(CONES[hit.id].dir)) * \
	//		hit.dist - dot(ACTIVECAM.pos + PARAM->mvt - CONES[hit.id].pos, fast_normalize(CONES[hit.id].dir));
	//	res = ((hit.pos - fast_normalize(CONES[hit.id].pos)) - (k * fast_normalize(CONES[hit.id].dir) * res)) * -1;
	}
	else if (hit.type == 2)
	{
		res = get_cylinder_normal(scene, hit);
	}
	else if (hit.type == 4)
	{
		if (dot(PLANE[hit.id].normale, -scene.ray) < 0)
			res = -PLANE[hit.id].normale;
		else
			res = PLANE[hit.id].normale;
	}
	else if (hit.type == 5)
		res = hit.pos - SPHERE[hit.id].pos;
	return (fast_normalize(res));
}

static unsigned int			phong(const t_hit hit, const t_scene scene)
{
	int					i = -1;
	unsigned int		res_color = get_ambient(scene, get_obj_hue(scene, hit));
	float				tmp;
	float3				reflect = 0;

	t_light_ray			light_ray;
	t_hit				light_hit = hit_init();

	while (++i < PARAM->n_lights)
	{
		tmp = 0;
		light_ray.dir = LIGHT[i].pos - hit.pos;
		light_ray.dist = length(light_ray.dir);
		light_ray.dir = normalize(light_ray.dir);
		light_hit = ray_hit(hit.pos, light_ray.dir, scene);
		light_hit.id = i;
		light_hit.type = 3;
		if (light_hit.dist < light_ray.dist && light_hit.dist > 0)
		;
		else
		{
			tmp = dot(hit.normale, light_ray.dir);
			if (tmp > 0)
				res_color = color_diffuse(scene, hit, light_hit, res_color, tmp);
			reflect = normalize(((float)(2.0 * dot(hit.normale, light_ray.dir)) * hit.normale) - light_ray.dir);
			tmp = dot(reflect, -scene.ray);
			if (tmp > 0)
				res_color = color_specular(scene, hit, light_hit, res_color, tmp);
		}
	}
	return (res_color);
}

unsigned int			phong2(t_hit hit, t_scene scene)
{
	int					i = -1;
	unsigned int		res_color = get_ambient(scene, get_obj_hue(scene, hit));
	float				tmp = 0;
	float3				reflect = 0;

	t_light_ray			light_ray;
	t_hit				light_hit;

	while (++i < PARAM->n_lights)
	{
		light_ray.dir = LIGHT[i].pos - hit.pos;
		light_ray.dist = length(light_ray.dir);
		light_ray.dir = normalize(light_ray.dir);
		light_hit = ray_hit(hit.pos, light_ray.dir, scene);
		if (light_hit.dist < light_ray.dist && light_hit.dist > 0)
		;
		else
		{
			tmp = dot(hit.normale, light_ray.dir);
			if (tmp > 0)
				res_color = color_diffuse(scene, hit, light_hit, res_color, tmp);
			reflect = normalize(((float)(2.0 * dot(hit.normale, light_ray.dir)) * hit.normale) - light_ray.dir);
			tmp = dot(reflect, -scene.ray);
			if (tmp > 0)
				res_color = color_specular(scene, hit, light_hit, res_color, tmp);
		}
	}
	return (res_color);
}

static unsigned int		bounce(const t_scene scene, const t_hit old_hit, const int depth)
{
	int				i = depth;
	unsigned int	color = 0;
	float3			reflex = 0;
	t_hit			new_hit;
	while (i > 0)
	{
		reflex = normalize(scene.ray - (2 * (float)dot(old_hit.normale, scene.ray) * old_hit.normale));
		new_hit.dist = MAX_DIST;
		new_hit = ray_hit(old_hit.pos, reflex, scene);
		if (new_hit.dist > 0 && new_hit.dist < MAX_DIST)
		{
			new_hit.pos = (new_hit.dist * reflex) + old_hit.pos;
			new_hit.normale = get_hit_normale(scene, new_hit);
			new_hit.pos = new_hit.pos + ((new_hit.dist / 100) * new_hit.normale);
			color += 0.1 * phong2(new_hit, scene);
		}
		i--;
	}
	return (color);
}

static unsigned int	get_pixel_color(const t_scene scene)
{
	t_hit			hit;
	int				depth = PARAM->depth;
	unsigned int	color  = 0;
	unsigned int	bounce_color = 0;

	hit.dist = MAX_DIST;
	hit = ray_hit((ACTIVECAM.pos + PARAM->mvt), scene.ray, scene);
	if (hit.dist > 0 && hit.dist < MAX_DIST) // ajout d'une distance max pour virer acnee mais pas fiable a 100%
	{
		hit.pos = (hit.dist * scene.ray) + (ACTIVECAM.pos + PARAM->mvt);
		hit.normale = get_hit_normale(scene, hit);
		hit.pos = hit.pos + ((hit.dist / 100) * hit.normale);
		color = phong(hit, scene);
		if (depth > 0)
			bounce_color = bounce(scene, hit, depth);
		return (color + bounce_color);
//		return (blend_add(color, 0.8*bounce_color));
	}
	return (get_ambient(scene, BACKCOLOR));
}

__kernel void	ray_trace(__global		char		*output,
						  				t_param		param,
						  __constant	t_cam		*cameras,
						  __constant	t_cone		*cones,
						  __constant	t_cylinder	*cylinders,
						  __constant	t_light		*lights,
						  __constant	t_plane		*planes,
						  __constant	t_sphere	*spheres,
						  __global		t_hit		*target_obj)
{
	t_scene		scene = grab_data(cameras, cones, cylinders, lights, planes, spheres, param);
	scene.pix.x = get_global_id(0);
	scene.pix.y = get_global_id(1);
	int			id = scene.pix.x + (PARAM->win_w * scene.pix.y); // NE PAS VIRER ID CAR BESOIN DANS MACRO OUTPUTE
	scene.ray = get_ray_cam(ACTIVECAM, scene, scene.pix.x ,scene.pix.y);
	if (scene.pix.x == PARAM->mou_x && scene.pix.y == PARAM->mou_y)
		*target_obj = ray_hit((ACTIVECAM.pos + PARAM->mvt), scene.ray, scene);
	OUTPUTE = get_pixel_color(scene);
}


remove old file

remove old file

float interpolate(float x0, float x1, float alpha)
{
    float interpolation = x0 * (1.0 - alpha) + alpha * x1;
    return interpolation;
}

float perlinnoise(int2 coord, __read_only image2d_t input_data, int octave)
{

    const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;

    float final_noise = 0.0f;

    int x = coord.x;
    int y = coord.y;

    int greatest_multiple_x = (coord.x / 32) * 32;
    int greatest_multiple_y = (coord.y / 32) * 32;
    int2 coords = (int2)(greatest_multiple_x, greatest_multiple_y);
    float out = read_imagef(input_data, sampler, coords).x;

    return out;
}

__kernel void simple_world(__read_only image2d_t input_map, __write_only image2d_t output_map)
{
    const sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;
    int x = get_global_id(0);
	int y = get_global_id(1);

	int2 coord = (int2) (x, y);

    float a = perlinnoise(coord, input_map, 1);
    float4 outvalue;
    outvalue.x = a;
    outvalue.y = a;
    outvalue.z = a;
    outvalue.w = 1.0f;

    write_imagef(output_map, coord, outvalue);
}


fixed some stuff

fixed some stuff

(defvar *task-list* nil)

(defun prompt (text)
    (format *query-io* "~a" text)
    (force-output *query-io*)
    (read-line *query-io*))

(defun any-key ()
    (format *query-io* "PRESS ANY KEY TO CONTINUE . . . ")
    (force-output *query-io*)
    (read *query-io*))

(defun add-task (name desc)
    (push (list name desc) *task-list*)
    (save))

(defun remove-task (task)
    (setf *task-list* (append (cdr (member task (reverse *task-list*) :test #'equal)) (cdr (member task *task-list* :test #'equal))))
    (save)
    (cls)
    (print-tasks))

(defun cls ()
    (format t "~A[H~@*~A[J" #\escape))

(defun print-tasks ()
    (setq x 1)
    (format t "TODO:~%-----~%")
    (dolist (item *task-list*)
        (format t "~a: " x)
        (incf x)
        (format t "~{~a~%~}" (cdr (reverse item))))
    (setq x (prompt "lance> "))
    (handler-case (setq y (parse-integer x)) (error (e) (setq y (- 0 1))))
    (if (= (- 0 1) y) (parse-str x) (parse-int y)))

(defun del-ambiguous ()
    (remove-task (parse-integer (prompt "Enter task to delete: "))))

(defun parse-str (x)
    (handler-case (if (string-equal (subseq x 0 3) "del") (if (= 3 (length x)) (del-ambiguous) (remove-task (task (parse-integer (subseq x 3))))) (if (string-equal (subseq x 0 3) "add") (new-task) (if (string-equal (subseq x 0 4) "exit") (sb-ext:quit)))) (error (e) (learn-to-type))))

(defun learn-to-type ()
    (cls)
        (format t "Learn to type, baka.~%")
    (print-tasks))

(defun parse-int (x)
    (if (<= x 0) (not-num) (read-task x)))

(defun not-num ()
    (format t "Choose a better number, baka.~%")
    (cls)
    (print-tasks))

(defun task (num)
    (setq l *task-list*)
    (dotimes (n (- num 1))
        (setq l (cdr l)))
    (car l))

(defun read-task (num)
    (if (= 0 (length *task-list*)) (print-tasks) (format t "Task name: ~{~a~%Description: ~a~}~%" (task num)))
    (any-key)
    (cls)
    (print-tasks))

(defun new-task ()
    (add-task (prompt "Task name: ") (prompt "Task description: "))
    (cls)
    (print-tasks))

(defun save ()
    (with-open-file (out ".tasks.christo" :direction :output :if-exists :supersede)
        (with-standard-io-syntax (print *task-list* out))))

(defun reload ()
    (with-open-file (in ".tasks.christo")
        (with-standard-io-syntax (setf *task-list* (read in)))))

(defun main ()
    (handler-case (reload) (error (e) ()))
    (cls)
    (print-tasks))

(defvar *task-list* nil)

(defun prompt (text)
    (format *query-io* "~a" text)
    (force-output *query-io*)
    (read-line *query-io*))

(defun add-task (name desc)
    (push (list name desc) *task-list*)
    (save))

(defun remove-task (task)
    (setf *task-list* (append (cdr (member task (reverse *task-list*) :test #'equal)) (cdr (member task *task-list* :test #'equal))))
    (save)
    (print-tasks))

(defun print-tasks ()
    (setq x 1)
    (format t "TODO:~%-----~%")
    (dolist (item *task-list*)
        (format t "~a: " x)
        (incf x)
        (format t "~{~a~%~}" (cdr (reverse item))))
    (setq x (handler-case (parse-integer (prompt "> ")) (error (e) (sb-ext:exit))))
    (if (= 0 x) (new-task) (read-task x)))

(defun task (num)
    (setq l *task-list*)
    (dotimes (n (- num 1))
        (setq l (cdr l)))
    (car l))

(defun read-task (num)
    (if (= 0 (length *task-list*)) (print-tasks) (format t "Task name: ~{~a~%Description: ~a~}~%" (task num)))
    (if (y-or-n-p "Delete task?") (remove-task (task num)) (print-tasks)))

(defun new-task ()
    (add-task (prompt "Task name: ") (prompt "Task description: "))
    (print-tasks))

(defun save ()
    (with-open-file (out "tasks.christo" :direction :output :if-exists :supersede)
        (with-standard-io-syntax (print *task-list* out))))

(defun reload ()
    (with-open-file (in "tasks.christo")
        (with-standard-io-syntax (setf *task-list* (read in)))))

(defun main ()
    (handler-case (reload) (error (e) ()))
    (print-tasks))


Gamma read/write pixel

Gamma read/write pixel

/* Deathray - An Avisynth plug-in filter for spatial/temporal non-local means de-noising.
 *
 * version 1.01
 *
 * Copyright 2013, Jawed Ashraf - Deathray@cupidity.f9.co.uk
 */

#define TILE_SIDE 53

__kernel void Zero(__global float4 *A) {
    int pos = get_global_id(0);
	A[pos] = 0.f;
}

// fast_power
// OpenCL on AMD GPUs doesn't expose the fast
// pow. The OpenCL pow function and its variants
// are all maximum precision. It's also more than
// twice as slow as this, which will have 1 or 2 ULP
// worse precision, I guess (not measured)
float fast_power(float x, float y) {
	return exp2(y * log2(x));
}

float4 fast_power4(float4 x, float y) {
	float4 power;

	float4 log_2 = log2(x);
#if 0 // slowest
	power.x = exp2(y * log2(x.x));
	power.y = exp2(y * log2(x.y));
	power.z = exp2(y * log2(x.z));
	power.w = exp2(y * log2(x.w));
#else
#if 0 // faster
	power = exp2(y * log_2);
#else // fastest
	power.x = exp2(y * log_2.x);
	power.y = exp2(y * log_2.y);
	power.z = exp2(y * log_2.z);
	power.w = exp2(y * log_2.w);
#endif
#endif

	return power;
}

// gamma_decode
// Converts input from gamma space into linear space.
float gamma_decode(float x) {
#if 1
	if (x <= 0.081f) return x/4.5f;
	return fast_power(((x + 0.099f)/1.099f), 2.22222222f);
#else
	return fast_power(x, 2.22222222f);
#endif
}

float4 gamma_decode4(float4 x) {
	float4 de_gamma;

	de_gamma.x = gamma_decode(x.x);
	de_gamma.y = gamma_decode(x.y);
	de_gamma.z = gamma_decode(x.z);
	de_gamma.w = gamma_decode(x.w);

	return de_gamma;
}

// gamma_encode
// Converts input from linear space into gamma space.
float gamma_encode(float x) {
#if 1
	if (x <= 0.018f) return 4.5f * x;
	return 1.099f * fast_power(x, 0.45f) - 0.099f;
#else
	return fast_power(x, 0.45f);
#endif
}

float4 gamma_encode4(float4 x) {
	float4 en_gamma;

	en_gamma.x = gamma_encode(x.x);
	en_gamma.y = gamma_encode(x.y);
	en_gamma.z = gamma_encode(x.z);
	en_gamma.w = gamma_encode(x.w);

	return en_gamma;
}

float4 ReadPixel4(
	read_only 	image2d_t 	plane,
	const		int2		coordinates) {

	const sampler_t frame = CLK_NORMALIZED_COORDS_FALSE | // TODO rename plane
							CLK_ADDRESS_CLAMP |
							CLK_FILTER_NEAREST;

	float4 pixel = read_imagef(plane, frame, coordinates);
	pixel = gamma_decode4(pixel);
	return pixel;
}

void WritePixel4(
	const		float4 		pixel,
	const		int2		coordinates,
	write_only 	image2d_t 	plane) {

	float4 gamma_encoded_pixel = gamma_encode4(pixel);
	write_imagef(plane, coordinates, gamma_encoded_pixel);
}

void WriteTile4(
	float4 store,
	int x,					// coordinates of a strip ...
	int y,					// ... of 4 pixels to be written
	local float *tile) {	// 48x48 portion of plane in local memory

	vstore4(store, 0, tile + ((y * TILE_SIDE) + x));
	write_mem_fence(CLK_LOCAL_MEM_FENCE);
}

float4 ReadTile4(
	int x,					// coordinates of a strip ...
	int y,					// ... of 4 pixels to be fetched
	local float *tile) {	// 48x48 portion of plane in local memory

	float4 result;

	result = vload4(0, tile + ((y * TILE_SIDE) + x));
	read_mem_fence(CLK_LOCAL_MEM_FENCE);
	return result;
}

float16 ReadTile16(
	int x,					// coordinates of a strip ...
	int y,					// ... of 16 pixels to be fetched
	local float *tile) {	// 48x48 portion of plane in local memory

	float16 result;

	result = vload16(0, tile + ((y * TILE_SIDE) + x));
	read_mem_fence(CLK_LOCAL_MEM_FENCE);
	return result;
}

float16 Unpack10PixelsAndNormalise(uint4 sixteen_pixels) {
	// Unpack 10 pixels, which are packed into 128 bits as uchars,
	// into 10 normalised pixels as floats.
	//
	// Only 10 pixels are required from each row of a window.

	uchar4 four_pixels;
	float16 result;

	four_pixels = as_uchar4(sixteen_pixels.x);

	result.s0 = (float)four_pixels.x * 0.0039215686f;
	result.s1 = (float)four_pixels.y * 0.0039215686f;
	result.s2 = (float)four_pixels.z * 0.0039215686f;
	result.s3 = (float)four_pixels.w * 0.0039215686f;

	four_pixels = as_uchar4(sixteen_pixels.y);

	result.s4 = (float)four_pixels.x * 0.0039215686f;
	result.s5 = (float)four_pixels.y * 0.0039215686f;
	result.s6 = (float)four_pixels.z * 0.0039215686f;
	result.s7 = (float)four_pixels.w * 0.0039215686f;

	four_pixels = as_uchar4(sixteen_pixels.z);

	result.s8 = (float)four_pixels.x * 0.0039215686f;
	result.s9 = (float)four_pixels.y * 0.0039215686f;

	return result;
}

uint4 Pack10PixelsIntoTargetRow(float16 sixteen_pixels) {
	// Pack 10 float pixels into 10 uchars, stored as a uint4.
	//
	// Only 10 pixels are required for target window's row.

	uchar4 four_pixels;
	uint4 result;

	four_pixels.x = (uchar)(sixteen_pixels.s0 * 255.f);
	four_pixels.y = (uchar)(sixteen_pixels.s1 * 255.f);
	four_pixels.z = (uchar)(sixteen_pixels.s2 * 255.f);
	four_pixels.w = (uchar)(sixteen_pixels.s3 * 255.f);

	result.x = as_uint(four_pixels);

	four_pixels.x = (uchar)(sixteen_pixels.s4 * 255.f);
	four_pixels.y = (uchar)(sixteen_pixels.s5 * 255.f);
	four_pixels.z = (uchar)(sixteen_pixels.s6 * 255.f);
	four_pixels.w = (uchar)(sixteen_pixels.s7 * 255.f);

	result.y = as_uint(four_pixels);

	four_pixels.x = (uchar)(sixteen_pixels.s8 * 255.f);
	four_pixels.y = (uchar)(sixteen_pixels.s9 * 255.f);

	result.z = as_uint(four_pixels);

	return result;
}

void Coordinates32x32(
	int2 *local_id,	// Work item
	int2 *source) {	// Each work item processes 4 pixels from source as a single row uchar4/float4

	// Generate coordinates for use by a variety of kernels based upon
	// a tile size of 32x32 pixels.

	// The 32x32 tile's top-left position in the plane, in uchar4s
	int2 tile_top_left = (int2)(get_group_id(0) << 3, get_group_id(1) << 5);

	*local_id = (int2)(get_local_id(0), get_local_id(1));
	*source = tile_top_left + *local_id;
}

void FetchAndMirror48x48(
	read_only 	image2d_t 	target_plane,	// input image
	const		int			width,			// width in pixels
	const		int			height,			// height in pixels
	const		int2		local_id,		// Work item
	const		int2		source,			// coordinates
	local		float		*tile) {		// existing block of local memory populated with 48x48 pixels
	// Fetch pixels from source and populate a 48x48 tile of pixels.
	//
	// The tile is defined as a 32x32 region to be filtered plus an
	// apron of 8 pixels on all four sides, making 48x48.
	//
	// The apron is filled with pixels from adjacent regions. At the
	// four edges of the frame the apron is filled, instead, with
	// pixels mirrored from just inside the frame.

	const sampler_t plane = CLK_NORMALIZED_COORDS_FALSE |
							CLK_ADDRESS_CLAMP |
							CLK_FILTER_NEAREST;

	float4 source_pixels = read_imagef(target_plane, plane, source);

	write_mem_fence(CLK_LOCAL_MEM_FENCE);

	// Scalar address for left-most pixel of 4 pixels that are put into tile
	int2 target = (int2)((local_id.x << 2) + 8, local_id.y + 8);

	WriteTile4(source_pixels, target.x, target.y, tile);

	if (local_id.y < 8 || local_id.y > 23) { // 8 top and bottom rows of apron are filled from adjacent tiles
		int offset = (local_id.y < 8) ? -8 : 8;
		source_pixels = read_imagef(target_plane, plane, source + (int2)(0, offset));
		WriteTile4(source_pixels, target.x, target.y + offset, tile);
	}
	if (local_id.x < 2 || local_id.x > 5) { // 8 columns at left and right
		int offset = (local_id.x < 2) ? -2 : 2;
		source_pixels = read_imagef(target_plane, plane, source + (int2)(offset, 0));
		WriteTile4(source_pixels, target.x + (offset << 2), target.y, tile);
	}
	if (local_id.y < 8 || local_id.y > 23) { // 4 corners, each 8x8
		int2 offset;
		offset.y = (local_id.y < 8) ? -8 : 8;
		if (local_id.x < 2 || local_id.x > 5) {
			offset.x = (local_id.x < 2) ? -2 : 2;
			source_pixels = read_imagef(target_plane, plane, source + offset);
			WriteTile4(source_pixels, target.x + (offset.x << 2), target.y + offset.y, tile);
		}
	}
	barrier(CLK_LOCAL_MEM_FENCE);

	// Mirror into apron when at frame border
	float4 mirror;
	bool left_group  = (get_group_id(0) == 0);
	bool right_group = (get_group_id(0) == (get_num_groups(0) - 1));
	bool top_group   = (get_group_id(1) == 0);
	bool bot_group   = (get_group_id(1) == (get_num_groups(1) - 1));

	if (top_group && local_id.y < 8) { 	// top 8 rows
		mirror = ReadTile4(target.x, target.y + 1, tile);
		WriteTile4(mirror, target.x, 8 - local_id.y - 1, tile);
	}
	barrier(CLK_LOCAL_MEM_FENCE);

	if (bot_group && local_id.y < 8) { // bottom 8 rows
		int centre = ((height - 1) & 31) + 8;

		mirror = ReadTile4(target.x, centre - local_id.y - 1, tile);
		WriteTile4(mirror, target.x, centre + local_id.y + 1, tile);
	}
	barrier(CLK_LOCAL_MEM_FENCE);
	// left 8 columns + top-left and bottom-left apron corners per tile
	int read_x  = (local_id.x == 1) ? 13 : 9;
	int write_x = (local_id.x == 1) ? 0 : 4;
	if (local_id.x < 2) {
		if (left_group) { // left 8 columns, 32 rows
			mirror = ReadTile4(read_x, target.y, tile);
			WriteTile4(mirror.wzyx, write_x, target.y, tile);
		}

		// TODO - cleanup IF structure - not sure if the compiler will jinx this
		if (local_id.y < 8) {
			if (left_group) { // left edge of frame apron corners, top and bottom
				mirror = ReadTile4(read_x, local_id.y, tile);
				WriteTile4(mirror.wzyx, write_x, local_id.y, tile);
				mirror = ReadTile4(read_x, 40 + local_id.y, tile);
				WriteTile4(mirror.wzyx, write_x, 40 + local_id.y, tile);
			}
		}
	}
	barrier(CLK_LOCAL_MEM_FENCE);
	if (local_id.x < 2 && local_id.y < 8) {
		int x = (local_id.x == 1) ? 4 : 0;
		if (top_group) { // apron at top edge of frame, left corners
			mirror = ReadTile4(x, 8 + local_id.y + 1, tile);
			WriteTile4(mirror, x, 8 - local_id.y - 1, tile);
		}
		if (bot_group) { // apron at bottom edge of frame, left corners
			int bottom = ((height - 1) & 31) + 8;
			mirror = ReadTile4(x, bottom - local_id.y - 1, tile);
			WriteTile4(mirror, x, bottom + local_id.y + 1, tile);
		}
	}
	barrier(CLK_LOCAL_MEM_FENCE);

	if (local_id.x > 5) { // right 8 columns + top-right and bottom-right apron corners per tile

		if (right_group) { // right edge of frame
			int centre  = ((width - 1) & 31) + 8;
			int read_x  = (local_id.x == 7) ? centre - 4 : centre - 8;
			int write_x = (local_id.x == 7) ? centre + 1 : centre + 5;

			mirror = ReadTile4(read_x, target.y, tile);
			WriteTile4(mirror.wzyx, write_x, target.y, tile);

			if (local_id.y < 8) { // top right and bottom right corner of every tile on right edge
				mirror = ReadTile4(read_x, local_id.y, tile);
				WriteTile4(mirror.wzyx, write_x, local_id.y, tile);
				mirror = ReadTile4(read_x, 40 + local_id.y, tile);
				WriteTile4(mirror.wzyx, write_x, 40 + local_id.y, tile);

				if (bot_group) { // bottom right corner of frame
					int bottom = ((height - 1) & 31) + 8;
					mirror = ReadTile4(read_x, bottom + local_id.y + 1, tile);
					WriteTile4(mirror.wzyx, write_x, bottom + local_id.y + 1, tile);
				}
			}
		} else if ((top_group || bot_group) && local_id.y < 8) {
			if (top_group) {
				int x = (local_id.x == 7) ? 44 : 40; // ATI 2.3: compiler bug requires this here if TILE_SIDE is not 48
				mirror = ReadTile4(x, 8 + local_id.y + 1, tile);
				WriteTile4(mirror, x, 8 - local_id.y - 1, tile);
			}
			if (bot_group) {
				int x = (local_id.x == 7) ? 44 : 40; // ATI 2.3: compiler bug requires this here if TILE_SIDE is not 48
				int bottom = ((height - 1) & 31) + 8;
				mirror = ReadTile4(x, bottom - local_id.y - 1, tile);
				WriteTile4(mirror, x, bottom + local_id.y + 1, tile);
			}
		}
	}
	barrier(CLK_LOCAL_MEM_FENCE);
}

/* Deathray - An Avisynth plug-in filter for spatial/temporal non-local means de-noising.
 *
 * version 1.01
 *
 * Copyright 2013, Jawed Ashraf - Deathray@cupidity.f9.co.uk
 */

#define TILE_SIDE 53

__kernel void Zero(__global float4 *A) {
    int pos = get_global_id(0);
	A[pos] = 0.f;
}

// fast_power
// OpenCL on AMD GPUs doesn't expose the fast
// pow. The OpenCL pow function and its variants
// are all maximum precision. It's also more than
// twice as slow as this, which will have 1 or 2 ULP
// worse precision, I guess (not measured)
float fast_power(float x, float y) {
	return exp2(y * log2(x));
}

float4 fast_power4(float4 x, float y) {
	float4 power;

	float4 log_2 = log2(x);
#if 0 // slowest
	power.x = exp2(y * log2(x.x));
	power.y = exp2(y * log2(x.y));
	power.z = exp2(y * log2(x.z));
	power.w = exp2(y * log2(x.w));
#else
#if 0 // faster
	power = exp2(y * log_2);
#else // fastest
	power.x = exp2(y * log_2.x);
	power.y = exp2(y * log_2.y);
	power.z = exp2(y * log_2.z);
	power.w = exp2(y * log_2.w);
#endif
#endif

	return power;
}

// gamma_decode
// Converts input from gamma space into linear space.
float gamma_decode(float x) {
#if 1
	if (x <= 0.081f) return x/4.5f;
	return fast_power(((x + 0.099f)/1.099f), 2.22222222f);
#else
	return fast_power(x, 2.22222222f);
#endif
}

float4 gamma_decode4(float4 x) {
	float4 de_gamma;

	de_gamma.x = gamma_decode(x.x);
	de_gamma.y = gamma_decode(x.y);
	de_gamma.z = gamma_decode(x.z);
	de_gamma.w = gamma_decode(x.w);

	return de_gamma;
}

// gamma_encode
// Converts input from linear space into gamma space.
float gamma_encode(float x) {
#if 1
	if (x <= 0.018f) return 4.5f * x;
	return 1.099f * fast_power(x, 0.45f) - 0.099f;
#else
	return fast_power(x, 0.45f);
#endif
}

float4 gamma_encode4(float4 x) {
	float4 en_gamma;

	en_gamma.x = gamma_encode(x.x);
	en_gamma.y = gamma_encode(x.y);
	en_gamma.z = gamma_encode(x.z);
	en_gamma.w = gamma_encode(x.w);

	return en_gamma;
}

void WriteTile4(
	float4 store,
	int x,					// coordinates of a strip ...
	int y,					// ... of 4 pixels to be written
	local float *tile) {	// 48x48 portion of plane in local memory

	vstore4(store, 0, tile + ((y * TILE_SIDE) + x));
	write_mem_fence(CLK_LOCAL_MEM_FENCE);
}

float4 ReadTile4(
	int x,					// coordinates of a strip ...
	int y,					// ... of 4 pixels to be fetched
	local float *tile) {	// 48x48 portion of plane in local memory

	float4 result;

	result = vload4(0, tile + ((y * TILE_SIDE) + x));
	read_mem_fence(CLK_LOCAL_MEM_FENCE);
	return result;
}

float16 ReadTile16(
	int x,					// coordinates of a strip ...
	int y,					// ... of 16 pixels to be fetched
	local float *tile) {	// 48x48 portion of plane in local memory

	float16 result;

	result = vload16(0, tile + ((y * TILE_SIDE) + x));
	read_mem_fence(CLK_LOCAL_MEM_FENCE);
	return result;
}

float16 Unpack10PixelsAndNormalise(uint4 sixteen_pixels) {
	// Unpack 10 pixels, which are packed into 128 bits as uchars,
	// into 10 normalised pixels as floats.
	//
	// Only 10 pixels are required from each row of a window.

	uchar4 four_pixels;
	float16 result;

	four_pixels = as_uchar4(sixteen_pixels.x);

	result.s0 = (float)four_pixels.x * 0.0039215686f;
	result.s1 = (float)four_pixels.y * 0.0039215686f;
	result.s2 = (float)four_pixels.z * 0.0039215686f;
	result.s3 = (float)four_pixels.w * 0.0039215686f;

	four_pixels = as_uchar4(sixteen_pixels.y);

	result.s4 = (float)four_pixels.x * 0.0039215686f;
	result.s5 = (float)four_pixels.y * 0.0039215686f;
	result.s6 = (float)four_pixels.z * 0.0039215686f;
	result.s7 = (float)four_pixels.w * 0.0039215686f;

	four_pixels = as_uchar4(sixteen_pixels.z);

	result.s8 = (float)four_pixels.x * 0.0039215686f;
	result.s9 = (float)four_pixels.y * 0.0039215686f;

	return result;
}

uint4 Pack10PixelsIntoTargetRow(float16 sixteen_pixels) {
	// Pack 10 float pixels into 10 uchars, stored as a uint4.
	//
	// Only 10 pixels are required for target window's row.

	uchar4 four_pixels;
	uint4 result;

	four_pixels.x = (uchar)(sixteen_pixels.s0 * 255.f);
	four_pixels.y = (uchar)(sixteen_pixels.s1 * 255.f);
	four_pixels.z = (uchar)(sixteen_pixels.s2 * 255.f);
	four_pixels.w = (uchar)(sixteen_pixels.s3 * 255.f);

	result.x = as_uint(four_pixels);

	four_pixels.x = (uchar)(sixteen_pixels.s4 * 255.f);
	four_pixels.y = (uchar)(sixteen_pixels.s5 * 255.f);
	four_pixels.z = (uchar)(sixteen_pixels.s6 * 255.f);
	four_pixels.w = (uchar)(sixteen_pixels.s7 * 255.f);

	result.y = as_uint(four_pixels);

	four_pixels.x = (uchar)(sixteen_pixels.s8 * 255.f);
	four_pixels.y = (uchar)(sixteen_pixels.s9 * 255.f);

	result.z = as_uint(four_pixels);

	return result;
}

void Coordinates32x32(
	int2 *local_id,	// Work item
	int2 *source) {	// Each work item processes 4 pixels from source as a single row uchar4/float4

	// Generate coordinates for use by a variety of kernels based upon
	// a tile size of 32x32 pixels.

	// The 32x32 tile's top-left position in the plane, in uchar4s
	int2 tile_top_left = (int2)(get_group_id(0) << 3, get_group_id(1) << 5);

	*local_id = (int2)(get_local_id(0), get_local_id(1));
	*source = tile_top_left + *local_id;
}

void FetchAndMirror48x48(
	read_only 	image2d_t 	target_plane,	// input image
	const		int			width,			// width in pixels
	const		int			height,			// height in pixels
	const		int2		local_id,		// Work item
	const		int2		source,			// coordinates
	local		float		*tile) {		// existing block of local memory populated with 48x48 pixels
	// Fetch pixels from source and populate a 48x48 tile of pixels.
	//
	// The tile is defined as a 32x32 region to be filtered plus an
	// apron of 8 pixels on all four sides, making 48x48.
	//
	// The apron is filled with pixels from adjacent regions. At the
	// four edges of the frame the apron is filled, instead, with
	// pixels mirrored from just inside the frame.

	const sampler_t plane = CLK_NORMALIZED_COORDS_FALSE |
							CLK_ADDRESS_CLAMP |
							CLK_FILTER_NEAREST;

	float4 source_pixels = read_imagef(target_plane, plane, source);

	write_mem_fence(CLK_LOCAL_MEM_FENCE);

	// Scalar address for left-most pixel of 4 pixels that are put into tile
	int2 target = (int2)((local_id.x << 2) + 8, local_id.y + 8);

	WriteTile4(source_pixels, target.x, target.y, tile);

	if (local_id.y < 8 || local_id.y > 23) { // 8 top and bottom rows of apron are filled from adjacent tiles
		int offset = (local_id.y < 8) ? -8 : 8;
		source_pixels = read_imagef(target_plane, plane, source + (int2)(0, offset));
		WriteTile4(source_pixels, target.x, target.y + offset, tile);
	}
	if (local_id.x < 2 || local_id.x > 5) { // 8 columns at left and right
		int offset = (local_id.x < 2) ? -2 : 2;
		source_pixels = read_imagef(target_plane, plane, source + (int2)(offset, 0));
		WriteTile4(source_pixels, target.x + (offset << 2), target.y, tile);
	}
	if (local_id.y < 8 || local_id.y > 23) { // 4 corners, each 8x8
		int2 offset;
		offset.y = (local_id.y < 8) ? -8 : 8;
		if (local_id.x < 2 || local_id.x > 5) {
			offset.x = (local_id.x < 2) ? -2 : 2;
			source_pixels = read_imagef(target_plane, plane, source + offset);
			WriteTile4(source_pixels, target.x + (offset.x << 2), target.y + offset.y, tile);
		}
	}
	barrier(CLK_LOCAL_MEM_FENCE);

	// Mirror into apron when at frame border
	float4 mirror;
	bool left_group  = (get_group_id(0) == 0);
	bool right_group = (get_group_id(0) == (get_num_groups(0) - 1));
	bool top_group   = (get_group_id(1) == 0);
	bool bot_group   = (get_group_id(1) == (get_num_groups(1) - 1));

	if (top_group && local_id.y < 8) { 	// top 8 rows
		mirror = ReadTile4(target.x, target.y + 1, tile);
		WriteTile4(mirror, target.x, 8 - local_id.y - 1, tile);
	}
	barrier(CLK_LOCAL_MEM_FENCE);

	if (bot_group && local_id.y < 8) { // bottom 8 rows
		int centre = ((height - 1) & 31) + 8;

		mirror = ReadTile4(target.x, centre - local_id.y - 1, tile);
		WriteTile4(mirror, target.x, centre + local_id.y + 1, tile);
	}
	barrier(CLK_LOCAL_MEM_FENCE);
	// left 8 columns + top-left and bottom-left apron corners per tile
	int read_x  = (local_id.x == 1) ? 13 : 9;
	int write_x = (local_id.x == 1) ? 0 : 4;
	if (local_id.x < 2) {
		if (left_group) { // left 8 columns, 32 rows
			mirror = ReadTile4(read_x, target.y, tile);
			WriteTile4(mirror.wzyx, write_x, target.y, tile);
		}

		// TODO - cleanup IF structure - not sure if the compiler will jinx this
		if (local_id.y < 8) {
			if (left_group) { // left edge of frame apron corners, top and bottom
				mirror = ReadTile4(read_x, local_id.y, tile);
				WriteTile4(mirror.wzyx, write_x, local_id.y, tile);
				mirror = ReadTile4(read_x, 40 + local_id.y, tile);
				WriteTile4(mirror.wzyx, write_x, 40 + local_id.y, tile);
			}
		}
	}
	barrier(CLK_LOCAL_MEM_FENCE);
	if (local_id.x < 2 && local_id.y < 8) {
		int x = (local_id.x == 1) ? 4 : 0;
		if (top_group) { // apron at top edge of frame, left corners
			mirror = ReadTile4(x, 8 + local_id.y + 1, tile);
			WriteTile4(mirror, x, 8 - local_id.y - 1, tile);
		}
		if (bot_group) { // apron at bottom edge of frame, left corners
			int bottom = ((height - 1) & 31) + 8;
			mirror = ReadTile4(x, bottom - local_id.y - 1, tile);
			WriteTile4(mirror, x, bottom + local_id.y + 1, tile);
		}
	}
	barrier(CLK_LOCAL_MEM_FENCE);

	if (local_id.x > 5) { // right 8 columns + top-right and bottom-right apron corners per tile

		if (right_group) { // right edge of frame
			int centre  = ((width - 1) & 31) + 8;
			int read_x  = (local_id.x == 7) ? centre - 4 : centre - 8;
			int write_x = (local_id.x == 7) ? centre + 1 : centre + 5;

			mirror = ReadTile4(read_x, target.y, tile);
			WriteTile4(mirror.wzyx, write_x, target.y, tile);

			if (local_id.y < 8) { // top right and bottom right corner of every tile on right edge
				mirror = ReadTile4(read_x, local_id.y, tile);
				WriteTile4(mirror.wzyx, write_x, local_id.y, tile);
				mirror = ReadTile4(read_x, 40 + local_id.y, tile);
				WriteTile4(mirror.wzyx, write_x, 40 + local_id.y, tile);

				if (bot_group) { // bottom right corner of frame
					int bottom = ((height - 1) & 31) + 8;
					mirror = ReadTile4(read_x, bottom + local_id.y + 1, tile);
					WriteTile4(mirror.wzyx, write_x, bottom + local_id.y + 1, tile);
				}
			}
		} else if ((top_group || bot_group) && local_id.y < 8) {
			if (top_group) {
				int x = (local_id.x == 7) ? 44 : 40; // ATI 2.3: compiler bug requires this here if TILE_SIDE is not 48
				mirror = ReadTile4(x, 8 + local_id.y + 1, tile);
				WriteTile4(mirror, x, 8 - local_id.y - 1, tile);
			}
			if (bot_group) {
				int x = (local_id.x == 7) ? 44 : 40; // ATI 2.3: compiler bug requires this here if TILE_SIDE is not 48
				int bottom = ((height - 1) & 31) + 8;
				mirror = ReadTile4(x, bottom - local_id.y - 1, tile);
				WriteTile4(mirror, x, bottom + local_id.y + 1, tile);
			}
		}
	}
	barrier(CLK_LOCAL_MEM_FENCE);
}


Add some basic functionality

Add some basic functionality

(defun poly+ (poly1 poly2)
  (format t "Poly One: ~d~%" poly1)
  (format t "Poly Two: ~d~%" poly2)
  (if (equal (length poly1) 1)
    (format t "Poly 1 has exactly one term: ~a Ex: ~a Mul: ~a~%"
            (find-variable-symbol poly1)
            (find-exponent        poly1)
            (find-multiplier      poly1))
    (format t "Poly 1 has more than one term~%")))

(defun collect-like-terms (poly)
  (format t "collecting terms"))

(defun find-variable-symbol (single-poly)
  (car (car (car single-poly))))

(defun find-exponent (single-poly)
  (cdr (car (car single-poly))))

(defun find-multiplier (single-poly)
  (cdr (car single-poly)))

(poly+ '(((x 2) 3)) '(((y 2) 4)))
(poly+ '(((x 2) 3) ((y 2) 3)) '(((y 2) 4)))