Removed workaround for Intel platform.

Removed workaround for Intel platform.

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Wenju He, wenju@multicorewareinc.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#define CELL_WIDTH 8
#define CELL_HEIGHT 8
#define CELLS_PER_BLOCK_X 2
#define CELLS_PER_BLOCK_Y 2
#define NTHREADS 256
#define CV_PI_F 3.1415926535897932384626433832795f

//----------------------------------------------------------------------------
// Histogram computation
// 12 threads for a cell, 12x4 threads per block
// Use pre-computed gaussian and interp_weight lookup tables
__kernel void compute_hists_lut_kernel(
    const int cblock_stride_x, const int cblock_stride_y,
    const int cnbins, const int cblock_hist_size, const int img_block_width,
    const int blocks_in_group, const int blocks_total,
    const int grad_quadstep, const int qangle_step,
    __global const float* grad, __global const uchar* qangle,
    __global const float* gauss_w_lut,
    __global float* block_hists, __local float* smem)
{
    const int lx = get_local_id(0);
    const int lp = lx / 24; /* local group id */
    const int gid = get_group_id(0) * blocks_in_group + lp;/* global group id */
    const int gidY = gid / img_block_width;
    const int gidX = gid - gidY * img_block_width;

    const int lidX = lx - lp * 24;
    const int lidY = get_local_id(1);

    const int cell_x = lidX / 12;
    const int cell_y = lidY;
    const int cell_thread_x = lidX - cell_x * 12;

    __local float* hists = smem + lp * cnbins * (CELLS_PER_BLOCK_X *
        CELLS_PER_BLOCK_Y * 12 + CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y);
    __local float* final_hist = hists + cnbins *
        (CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y * 12);

    const int offset_x = gidX * cblock_stride_x + (cell_x << 2) + cell_thread_x;
    const int offset_y = gidY * cblock_stride_y + (cell_y << 2);

    __global const float* grad_ptr = (gid < blocks_total) ?
        grad + offset_y * grad_quadstep + (offset_x << 1) : grad;
    __global const uchar* qangle_ptr = (gid < blocks_total) ?
        qangle + offset_y * qangle_step + (offset_x << 1) : qangle;

    __local float* hist = hists + 12 * (cell_y * CELLS_PER_BLOCK_Y + cell_x) +
        cell_thread_x;
    for (int bin_id = 0; bin_id < cnbins; ++bin_id)
        hist[bin_id * 48] = 0.f;

    const int dist_x = -4 + cell_thread_x - 4 * cell_x;
    const int dist_center_x = dist_x - 4 * (1 - 2 * cell_x);

    const int dist_y_begin = -4 - 4 * lidY;
    for (int dist_y = dist_y_begin; dist_y < dist_y_begin + 12; ++dist_y)
    {
        float2 vote = (float2) (grad_ptr[0], grad_ptr[1]);
        uchar2 bin = (uchar2) (qangle_ptr[0], qangle_ptr[1]);

        grad_ptr += grad_quadstep;
        qangle_ptr += qangle_step;

        int dist_center_y = dist_y - 4 * (1 - 2 * cell_y);

        int idx = (dist_center_y + 8) * 16 + (dist_center_x + 8);
        float gaussian = gauss_w_lut[idx];
        idx = (dist_y + 8) * 16 + (dist_x + 8);
        float interp_weight = gauss_w_lut[256+idx];

        hist[bin.x * 48] += gaussian * interp_weight * vote.x;
        hist[bin.y * 48] += gaussian * interp_weight * vote.y;
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    volatile __local float* hist_ = hist;
    for (int bin_id = 0; bin_id < cnbins; ++bin_id, hist_ += 48)
    {
        if (cell_thread_x < 6)
            hist_[0] += hist_[6];
        barrier(CLK_LOCAL_MEM_FENCE);
        if (cell_thread_x < 3)
            hist_[0] += hist_[3];
#ifdef CPU
        barrier(CLK_LOCAL_MEM_FENCE);
#endif
        if (cell_thread_x == 0)
            final_hist[(cell_x * 2 + cell_y) * cnbins + bin_id] =
                hist_[0] + hist_[1] + hist_[2];
    }
#ifdef CPU
    barrier(CLK_LOCAL_MEM_FENCE);
#endif

    int tid = (cell_y * CELLS_PER_BLOCK_Y + cell_x) * 12 + cell_thread_x;
    if ((tid < cblock_hist_size) && (gid < blocks_total))
    {
        __global float* block_hist = block_hists +
            (gidY * img_block_width + gidX) * cblock_hist_size;
        block_hist[tid] = final_hist[tid];
    }
}

//-------------------------------------------------------------
//  Normalization of histograms via L2Hys_norm
//  optimized for the case of 9 bins
__kernel void normalize_hists_36_kernel(__global float* block_hists,
                                        const float threshold, __local float *squares)
{
    const int tid = get_local_id(0);
    const int gid = get_global_id(0);
    const int bid = tid / 36;      /* block-hist id, (0 - 6) */
    const int boffset = bid * 36;  /* block-hist offset in the work-group */
    const int hid = tid - boffset; /* histogram bin id, (0 - 35) */

    float elem = block_hists[gid];
    squares[tid] = elem * elem;
    barrier(CLK_LOCAL_MEM_FENCE);

    __local float* smem = squares + boffset;
    float sum = smem[hid];
    if (hid < 18)
        smem[hid] = sum = sum + smem[hid + 18];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (hid < 9)
        smem[hid] = sum = sum + smem[hid + 9];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (hid < 4)
        smem[hid] = sum + smem[hid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    sum = smem[0] + smem[1] + smem[2] + smem[3] + smem[8];

    elem = elem / (sqrt(sum) + 3.6f);
    elem = min(elem, threshold);

    barrier(CLK_LOCAL_MEM_FENCE);
    squares[tid] = elem * elem;
    barrier(CLK_LOCAL_MEM_FENCE);

    sum = smem[hid];
    if (hid < 18)
      smem[hid] = sum = sum + smem[hid + 18];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (hid < 9)
        smem[hid] = sum = sum + smem[hid + 9];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (hid < 4)
        smem[hid] = sum + smem[hid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    sum = smem[0] + smem[1] + smem[2] + smem[3] + smem[8];

    block_hists[gid] = elem / (sqrt(sum) + 1e-3f);
}

//-------------------------------------------------------------
//  Normalization of histograms via L2Hys_norm
//
inline float reduce_smem(volatile __local float* smem, int size)
{
    unsigned int tid = get_local_id(0);
    float sum = smem[tid];

    if (size >= 512) { if (tid < 256) smem[tid] = sum = sum + smem[tid + 256];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 256) { if (tid < 128) smem[tid] = sum = sum + smem[tid + 128];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 128) { if (tid < 64) smem[tid] = sum = sum + smem[tid + 64];
        barrier(CLK_LOCAL_MEM_FENCE); }
#ifdef CPU
    if (size >= 64) { if (tid < 32) smem[tid] = sum = sum + smem[tid + 32];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 32) { if (tid < 16) smem[tid] = sum = sum + smem[tid + 16];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 16) { if (tid < 8) smem[tid] = sum = sum + smem[tid + 8];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 8) { if (tid < 4) smem[tid] = sum = sum + smem[tid + 4];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 4) { if (tid < 2) smem[tid] = sum = sum + smem[tid + 2];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 2) { if (tid < 1) smem[tid] = sum = sum + smem[tid + 1];
        barrier(CLK_LOCAL_MEM_FENCE); }
#else
    if (tid < 32)
    {
        if (size >= 64) smem[tid] = sum = sum + smem[tid + 32];
#if WAVE_SIZE < 32
    } barrier(CLK_LOCAL_MEM_FENCE);
    if (tid < 16) {
#endif
        if (size >= 32) smem[tid] = sum = sum + smem[tid + 16];
        if (size >= 16) smem[tid] = sum = sum + smem[tid + 8];
        if (size >= 8) smem[tid] = sum = sum + smem[tid + 4];
        if (size >= 4) smem[tid] = sum = sum + smem[tid + 2];
        if (size >= 2) smem[tid] = sum = sum + smem[tid + 1];
    }
#endif

    return sum;
}

__kernel void normalize_hists_kernel(
    const int nthreads, const int block_hist_size, const int img_block_width,
    __global float* block_hists, const float threshold, __local float *squares)
{
    const int tid = get_local_id(0);
    const int gidX = get_group_id(0);
    const int gidY = get_group_id(1);

    __global float* hist = block_hists + (gidY * img_block_width + gidX) *
        block_hist_size + tid;

    float elem = 0.f;
    if (tid < block_hist_size)
        elem = hist[0];

    squares[tid] = elem * elem;

    barrier(CLK_LOCAL_MEM_FENCE);
    float sum = reduce_smem(squares, nthreads);

    float scale = 1.0f / (sqrt(sum) + 0.1f * block_hist_size);
    elem = min(elem * scale, threshold);

    barrier(CLK_LOCAL_MEM_FENCE);
    squares[tid] = elem * elem;

    barrier(CLK_LOCAL_MEM_FENCE);
    sum = reduce_smem(squares, nthreads);
    scale = 1.0f / (sqrt(sum) + 1e-3f);

    if (tid < block_hist_size)
        hist[0] = elem * scale;
}

//---------------------------------------------------------------------
//  Linear SVM based classification
//  48x96 window, 9 bins and default parameters
//  180 threads, each thread corresponds to a bin in a row
__kernel void classify_hists_180_kernel(
    const int cdescr_width, const int cdescr_height, const int cblock_hist_size,
    const int img_win_width, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float * block_hists, __global const float* coefs,
    float free_coef, float threshold, __global uchar* labels)
{
    const int tid = get_local_id(0);
    const int gidX = get_group_id(0);
    const int gidY = get_group_id(1);

    __global const float* hist = block_hists + (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    float product = 0.f;

    for (int i = 0; i < cdescr_height; i++)
    {
        product += coefs[i * cdescr_width + tid] *
            hist[i * img_block_width * cblock_hist_size + tid];
    }

    __local float products[180];

    products[tid] = product;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 90) products[tid] = product = product + products[tid + 90];
    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 45) products[tid] = product = product + products[tid + 45];
    barrier(CLK_LOCAL_MEM_FENCE);

    volatile __local float* smem = products;
#ifdef CPU
    if (tid < 13) smem[tid] = product = product + smem[tid + 32];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (tid < 16) smem[tid] = product = product + smem[tid + 16];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<8) smem[tid] = product = product + smem[tid + 8];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<4) smem[tid] = product = product + smem[tid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<2) smem[tid] = product = product + smem[tid + 2];
    barrier(CLK_LOCAL_MEM_FENCE);
#else
    if (tid < 13)
    {
        smem[tid] = product = product + smem[tid + 32];
    }
#if WAVE_SIZE < 32
    barrier(CLK_LOCAL_MEM_FENCE);
#endif
    if (tid < 16)
    {
        smem[tid] = product = product + smem[tid + 16];
        smem[tid] = product = product + smem[tid + 8];
        smem[tid] = product = product + smem[tid + 4];
        smem[tid] = product = product + smem[tid + 2];
    }
#endif

    if (tid == 0){
        product = product + smem[tid + 1];
        labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold);
    }
}

//---------------------------------------------------------------------
//  Linear SVM based classification
//  64x128 window, 9 bins and default parameters
//  256 threads, 252 of them are used
__kernel void classify_hists_252_kernel(
    const int cdescr_width, const int cdescr_height, const int cblock_hist_size,
    const int img_win_width, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float * block_hists, __global const float* coefs,
    float free_coef, float threshold, __global uchar* labels)
{
    const int tid = get_local_id(0);
    const int gidX = get_group_id(0);
    const int gidY = get_group_id(1);

    __global const float* hist = block_hists + (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    float product = 0.f;
    if (tid < cdescr_width)
    {
        for (int i = 0; i < cdescr_height; i++)
            product += coefs[i * cdescr_width + tid] *
                hist[i * img_block_width * cblock_hist_size + tid];
    }

    __local float products[NTHREADS];

    products[tid] = product;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 128) products[tid] = product = product + products[tid + 128];
    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 64) products[tid] = product = product + products[tid + 64];
    barrier(CLK_LOCAL_MEM_FENCE);

    volatile __local float* smem = products;
#ifdef CPU
    if(tid<32) smem[tid] = product = product + smem[tid + 32];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<16) smem[tid] = product = product + smem[tid + 16];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<8) smem[tid] = product = product + smem[tid + 8];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<4) smem[tid] = product = product + smem[tid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<2) smem[tid] = product = product + smem[tid + 2];
    barrier(CLK_LOCAL_MEM_FENCE);
#else
    if (tid < 32)
    {
        smem[tid] = product = product + smem[tid + 32];
#if WAVE_SIZE < 32
    } barrier(CLK_LOCAL_MEM_FENCE);
    if (tid < 16) {
#endif
        smem[tid] = product = product + smem[tid + 16];
        smem[tid] = product = product + smem[tid + 8];
        smem[tid] = product = product + smem[tid + 4];
        smem[tid] = product = product + smem[tid + 2];
    }
#endif
    if (tid == 0){
        product = product + smem[tid + 1];
        labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold);
    }
}

//---------------------------------------------------------------------
//  Linear SVM based classification
//  256 threads
__kernel void classify_hists_kernel(
    const int cdescr_size, const int cdescr_width, const int cblock_hist_size,
    const int img_win_width, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float * block_hists, __global const float* coefs,
    float free_coef, float threshold, __global uchar* labels)
{
    const int tid = get_local_id(0);
    const int gidX = get_group_id(0);
    const int gidY = get_group_id(1);

    __global const float* hist = block_hists + (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    float product = 0.f;
    for (int i = tid; i < cdescr_size; i += NTHREADS)
    {
        int offset_y = i / cdescr_width;
        int offset_x = i - offset_y * cdescr_width;
        product += coefs[i] *
            hist[offset_y * img_block_width * cblock_hist_size + offset_x];
    }

    __local float products[NTHREADS];

    products[tid] = product;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 128) products[tid] = product = product + products[tid + 128];
    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 64) products[tid] = product = product + products[tid + 64];
    barrier(CLK_LOCAL_MEM_FENCE);

    volatile __local float* smem = products;
#ifdef CPU
    if(tid<32) smem[tid] = product = product + smem[tid + 32];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<16) smem[tid] = product = product + smem[tid + 16];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<8) smem[tid] = product = product + smem[tid + 8];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<4) smem[tid] = product = product + smem[tid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<2) smem[tid] = product = product + smem[tid + 2];
    barrier(CLK_LOCAL_MEM_FENCE);
#else
    if (tid < 32)
    {
        smem[tid] = product = product + smem[tid + 32];
#if WAVE_SIZE < 32
    } barrier(CLK_LOCAL_MEM_FENCE);
    if (tid < 16) {
#endif
        smem[tid] = product = product + smem[tid + 16];
        smem[tid] = product = product + smem[tid + 8];
        smem[tid] = product = product + smem[tid + 4];
        smem[tid] = product = product + smem[tid + 2];
    }
#endif
    if (tid == 0){
        smem[tid] = product = product + smem[tid + 1];
        labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold);
    }
}

//----------------------------------------------------------------------------
// Extract descriptors

__kernel void extract_descrs_by_rows_kernel(
    const int cblock_hist_size, const int descriptors_quadstep,
    const int cdescr_size, const int cdescr_width, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float* block_hists, __global float* descriptors)
{
    int tid = get_local_id(0);
    int gidX = get_group_id(0);
    int gidY = get_group_id(1);

    // Get left top corner of the window in src
    __global const float* hist = block_hists + (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    // Get left top corner of the window in dst
    __global float* descriptor = descriptors +
        (gidY * get_num_groups(0) + gidX) * descriptors_quadstep;

    // Copy elements from src to dst
    for (int i = tid; i < cdescr_size; i += NTHREADS)
    {
        int offset_y = i / cdescr_width;
        int offset_x = i - offset_y * cdescr_width;
        descriptor[i] = hist[offset_y * img_block_width * cblock_hist_size + offset_x];
    }
}

__kernel void extract_descrs_by_cols_kernel(
    const int cblock_hist_size, const int descriptors_quadstep, const int cdescr_size,
    const int cnblocks_win_x, const int cnblocks_win_y, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float* block_hists, __global float* descriptors)
{
    int tid = get_local_id(0);
    int gidX = get_group_id(0);
    int gidY = get_group_id(1);

    // Get left top corner of the window in src
    __global const float* hist = block_hists +  (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    // Get left top corner of the window in dst
    __global float* descriptor = descriptors +
        (gidY * get_num_groups(0) + gidX) * descriptors_quadstep;

    // Copy elements from src to dst
    for (int i = tid; i < cdescr_size; i += NTHREADS)
    {
        int block_idx = i / cblock_hist_size;
        int idx_in_block = i - block_idx * cblock_hist_size;

        int y = block_idx / cnblocks_win_x;
        int x = block_idx - y * cnblocks_win_x;

        descriptor[(x * cnblocks_win_y + y) * cblock_hist_size + idx_in_block] =
            hist[(y * img_block_width  + x) * cblock_hist_size + idx_in_block];
    }
}

//----------------------------------------------------------------------------
// Gradients computation

__kernel void compute_gradients_8UC4_kernel(
    const int height, const int width,
    const int img_step, const int grad_quadstep, const int qangle_step,
    const __global uchar4 * img, __global float * grad, __global uchar * qangle,
    const float angle_scale, const char correct_gamma, const int cnbins)
{
    const int x = get_global_id(0);
    const int tid = get_local_id(0);
    const int gSizeX = get_local_size(0);
    const int gidY = get_group_id(1);

    __global const uchar4* row = img + gidY * img_step;

    __local float sh_row[(NTHREADS + 2) * 3];

    uchar4 val;
    if (x < width)
        val = row[x];
    else
        val = row[width - 2];

    sh_row[tid + 1] = val.x;
    sh_row[tid + 1 + (NTHREADS + 2)] = val.y;
    sh_row[tid + 1 + 2 * (NTHREADS + 2)] = val.z;

    if (tid == 0)
    {
        val = row[max(x - 1, 1)];
        sh_row[0] = val.x;
        sh_row[(NTHREADS + 2)] = val.y;
        sh_row[2 * (NTHREADS + 2)] = val.z;
    }

    if (tid == gSizeX - 1)
    {
        val = row[min(x + 1, width - 2)];
        sh_row[gSizeX + 1] = val.x;
        sh_row[gSizeX + 1 + (NTHREADS + 2)] = val.y;
        sh_row[gSizeX + 1 + 2 * (NTHREADS + 2)] = val.z;
    }

    barrier(CLK_LOCAL_MEM_FENCE);
    if (x < width)
    {
        float3 a = (float3) (sh_row[tid], sh_row[tid + (NTHREADS + 2)],
            sh_row[tid + 2 * (NTHREADS + 2)]);
        float3 b = (float3) (sh_row[tid + 2], sh_row[tid + 2 + (NTHREADS + 2)],
            sh_row[tid + 2 + 2 * (NTHREADS + 2)]);

        float3 dx;
        if (correct_gamma == 1)
            dx = sqrt(b) - sqrt(a);
        else
            dx = b - a;

        float3 dy = (float3) 0.f;

        if (gidY > 0 && gidY < height - 1)
        {
            a = convert_float3(img[(gidY - 1) * img_step + x].xyz);
            b = convert_float3(img[(gidY + 1) * img_step + x].xyz);

            if (correct_gamma == 1)
                dy = sqrt(b) - sqrt(a);
            else
                dy = b - a;
        }

        float best_dx = dx.x;
        float best_dy = dy.x;

        float mag0 = dx.x * dx.x + dy.x * dy.x;
        float mag1 = dx.y * dx.y + dy.y * dy.y;
        if (mag0 < mag1)
        {
            best_dx = dx.y;
            best_dy = dy.y;
            mag0 = mag1;
        }

        mag1 = dx.z * dx.z + dy.z * dy.z;
        if (mag0 < mag1)
        {
            best_dx = dx.z;
            best_dy = dy.z;
            mag0 = mag1;
        }

        mag0 = sqrt(mag0);

        float ang = (atan2(best_dy, best_dx) + CV_PI_F) * angle_scale - 0.5f;
        int hidx = (int)floor(ang);
        ang -= hidx;
        hidx = (hidx + cnbins) % cnbins;

        qangle[(gidY * qangle_step + x) << 1] = hidx;
        qangle[((gidY * qangle_step + x) << 1) + 1] = (hidx + 1) % cnbins;
        grad[(gidY * grad_quadstep + x) << 1] = mag0 * (1.f - ang);
        grad[((gidY * grad_quadstep + x) << 1) + 1] = mag0 * ang;
    }
}

__kernel void compute_gradients_8UC1_kernel(
    const int height, const int width,
    const int img_step, const int grad_quadstep, const int qangle_step,
    __global const uchar * img, __global float * grad, __global uchar * qangle,
    const float angle_scale, const char correct_gamma, const int cnbins)
{
    const int x = get_global_id(0);
    const int tid = get_local_id(0);
    const int gSizeX = get_local_size(0);
    const int gidY = get_group_id(1);

    __global const uchar* row = img + gidY * img_step;

    __local float sh_row[NTHREADS + 2];

    if (x < width)
        sh_row[tid + 1] = row[x];
    else
        sh_row[tid + 1] = row[width - 2];

    if (tid == 0)
        sh_row[0] = row[max(x - 1, 1)];

    if (tid == gSizeX - 1)
        sh_row[gSizeX + 1] = row[min(x + 1, width - 2)];

    barrier(CLK_LOCAL_MEM_FENCE);
    if (x < width)
    {
        float dx;

        if (correct_gamma == 1)
            dx = sqrt(sh_row[tid + 2]) - sqrt(sh_row[tid]);
        else
            dx = sh_row[tid + 2] - sh_row[tid];

        float dy = 0.f;
        if (gidY > 0 && gidY < height - 1)
        {
            float a = (float) img[ (gidY + 1) * img_step + x ];
            float b = (float) img[ (gidY - 1) * img_step + x ];
            if (correct_gamma == 1)
                dy = sqrt(a) - sqrt(b);
            else
                dy = a - b;
        }
        float mag = sqrt(dx * dx + dy * dy);

        float ang = (atan2(dy, dx) + CV_PI_F) * angle_scale - 0.5f;
        int hidx = (int)floor(ang);
        ang -= hidx;
        hidx = (hidx + cnbins) % cnbins;

        qangle[ (gidY * qangle_step + x) << 1 ]     = hidx;
        qangle[ ((gidY * qangle_step + x) << 1) + 1 ] = (hidx + 1) % cnbins;
        grad[ (gidY * grad_quadstep + x) << 1 ]       = mag * (1.f - ang);
        grad[ ((gidY * grad_quadstep + x) << 1) + 1 ]   = mag * ang;
    }
}

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Wenju He, wenju@multicorewareinc.com
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#define CELL_WIDTH 8
#define CELL_HEIGHT 8
#define CELLS_PER_BLOCK_X 2
#define CELLS_PER_BLOCK_Y 2
#define NTHREADS 256
#define CV_PI_F 3.1415926535897932384626433832795f

#ifdef INTEL_DEVICE
#define QANGLE_TYPE		int
#define QANGLE_TYPE2	int2
#else
#define QANGLE_TYPE		uchar
#define QANGLE_TYPE2	uchar2
#endif

//----------------------------------------------------------------------------
// Histogram computation
// 12 threads for a cell, 12x4 threads per block
// Use pre-computed gaussian and interp_weight lookup tables
__kernel void compute_hists_lut_kernel(
    const int cblock_stride_x, const int cblock_stride_y,
    const int cnbins, const int cblock_hist_size, const int img_block_width,
    const int blocks_in_group, const int blocks_total,
    const int grad_quadstep, const int qangle_step,
    __global const float* grad, __global const QANGLE_TYPE* qangle,
    __global const float* gauss_w_lut,
    __global float* block_hists, __local float* smem)
{
    const int lx = get_local_id(0);
    const int lp = lx / 24; /* local group id */
    const int gid = get_group_id(0) * blocks_in_group + lp;/* global group id */
    const int gidY = gid / img_block_width;
    const int gidX = gid - gidY * img_block_width;

    const int lidX = lx - lp * 24;
    const int lidY = get_local_id(1);

    const int cell_x = lidX / 12;
    const int cell_y = lidY;
    const int cell_thread_x = lidX - cell_x * 12;

    __local float* hists = smem + lp * cnbins * (CELLS_PER_BLOCK_X *
        CELLS_PER_BLOCK_Y * 12 + CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y);
    __local float* final_hist = hists + cnbins *
        (CELLS_PER_BLOCK_X * CELLS_PER_BLOCK_Y * 12);

    const int offset_x = gidX * cblock_stride_x + (cell_x << 2) + cell_thread_x;
    const int offset_y = gidY * cblock_stride_y + (cell_y << 2);

    __global const float* grad_ptr = (gid < blocks_total) ?
        grad + offset_y * grad_quadstep + (offset_x << 1) : grad;
    __global const QANGLE_TYPE* qangle_ptr = (gid < blocks_total) ?
        qangle + offset_y * qangle_step + (offset_x << 1) : qangle;

    __local float* hist = hists + 12 * (cell_y * CELLS_PER_BLOCK_Y + cell_x) +
        cell_thread_x;
    for (int bin_id = 0; bin_id < cnbins; ++bin_id)
        hist[bin_id * 48] = 0.f;

    const int dist_x = -4 + cell_thread_x - 4 * cell_x;
    const int dist_center_x = dist_x - 4 * (1 - 2 * cell_x);

    const int dist_y_begin = -4 - 4 * lidY;
    for (int dist_y = dist_y_begin; dist_y < dist_y_begin + 12; ++dist_y)
    {
        float2 vote = (float2) (grad_ptr[0], grad_ptr[1]);
        QANGLE_TYPE2 bin = (QANGLE_TYPE2) (qangle_ptr[0], qangle_ptr[1]);

        grad_ptr += grad_quadstep;
        qangle_ptr += qangle_step;

        int dist_center_y = dist_y - 4 * (1 - 2 * cell_y);

        int idx = (dist_center_y + 8) * 16 + (dist_center_x + 8);
        float gaussian = gauss_w_lut[idx];
        idx = (dist_y + 8) * 16 + (dist_x + 8);
        float interp_weight = gauss_w_lut[256+idx];

        hist[bin.x * 48] += gaussian * interp_weight * vote.x;
        hist[bin.y * 48] += gaussian * interp_weight * vote.y;
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    volatile __local float* hist_ = hist;
    for (int bin_id = 0; bin_id < cnbins; ++bin_id, hist_ += 48)
    {
        if (cell_thread_x < 6)
            hist_[0] += hist_[6];
        barrier(CLK_LOCAL_MEM_FENCE);
        if (cell_thread_x < 3)
            hist_[0] += hist_[3];
#ifdef CPU
        barrier(CLK_LOCAL_MEM_FENCE);
#endif
        if (cell_thread_x == 0)
            final_hist[(cell_x * 2 + cell_y) * cnbins + bin_id] =
                hist_[0] + hist_[1] + hist_[2];
    }
#ifdef CPU
    barrier(CLK_LOCAL_MEM_FENCE);
#endif

    int tid = (cell_y * CELLS_PER_BLOCK_Y + cell_x) * 12 + cell_thread_x;
    if ((tid < cblock_hist_size) && (gid < blocks_total))
    {
        __global float* block_hist = block_hists +
            (gidY * img_block_width + gidX) * cblock_hist_size;
        block_hist[tid] = final_hist[tid];
    }
}

//-------------------------------------------------------------
//  Normalization of histograms via L2Hys_norm
//  optimized for the case of 9 bins
__kernel void normalize_hists_36_kernel(__global float* block_hists,
                                        const float threshold, __local float *squares)
{
    const int tid = get_local_id(0);
    const int gid = get_global_id(0);
    const int bid = tid / 36;      /* block-hist id, (0 - 6) */
    const int boffset = bid * 36;  /* block-hist offset in the work-group */
    const int hid = tid - boffset; /* histogram bin id, (0 - 35) */

    float elem = block_hists[gid];
    squares[tid] = elem * elem;
    barrier(CLK_LOCAL_MEM_FENCE);

    __local float* smem = squares + boffset;
    float sum = smem[hid];
    if (hid < 18)
        smem[hid] = sum = sum + smem[hid + 18];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (hid < 9)
        smem[hid] = sum = sum + smem[hid + 9];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (hid < 4)
        smem[hid] = sum + smem[hid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    sum = smem[0] + smem[1] + smem[2] + smem[3] + smem[8];

    elem = elem / (sqrt(sum) + 3.6f);
    elem = min(elem, threshold);

    barrier(CLK_LOCAL_MEM_FENCE);
    squares[tid] = elem * elem;
    barrier(CLK_LOCAL_MEM_FENCE);

    sum = smem[hid];
    if (hid < 18)
      smem[hid] = sum = sum + smem[hid + 18];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (hid < 9)
        smem[hid] = sum = sum + smem[hid + 9];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (hid < 4)
        smem[hid] = sum + smem[hid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    sum = smem[0] + smem[1] + smem[2] + smem[3] + smem[8];

    block_hists[gid] = elem / (sqrt(sum) + 1e-3f);
}

//-------------------------------------------------------------
//  Normalization of histograms via L2Hys_norm
//
inline float reduce_smem(volatile __local float* smem, int size)
{
    unsigned int tid = get_local_id(0);
    float sum = smem[tid];

    if (size >= 512) { if (tid < 256) smem[tid] = sum = sum + smem[tid + 256];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 256) { if (tid < 128) smem[tid] = sum = sum + smem[tid + 128];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 128) { if (tid < 64) smem[tid] = sum = sum + smem[tid + 64];
        barrier(CLK_LOCAL_MEM_FENCE); }
#ifdef CPU
    if (size >= 64) { if (tid < 32) smem[tid] = sum = sum + smem[tid + 32];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 32) { if (tid < 16) smem[tid] = sum = sum + smem[tid + 16];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 16) { if (tid < 8) smem[tid] = sum = sum + smem[tid + 8];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 8) { if (tid < 4) smem[tid] = sum = sum + smem[tid + 4];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 4) { if (tid < 2) smem[tid] = sum = sum + smem[tid + 2];
        barrier(CLK_LOCAL_MEM_FENCE); }
    if (size >= 2) { if (tid < 1) smem[tid] = sum = sum + smem[tid + 1];
        barrier(CLK_LOCAL_MEM_FENCE); }
#else
    if (tid < 32)
    {
        if (size >= 64) smem[tid] = sum = sum + smem[tid + 32];
#if WAVE_SIZE < 32
    } barrier(CLK_LOCAL_MEM_FENCE);
    if (tid < 16) {
#endif
        if (size >= 32) smem[tid] = sum = sum + smem[tid + 16];
        if (size >= 16) smem[tid] = sum = sum + smem[tid + 8];
        if (size >= 8) smem[tid] = sum = sum + smem[tid + 4];
        if (size >= 4) smem[tid] = sum = sum + smem[tid + 2];
        if (size >= 2) smem[tid] = sum = sum + smem[tid + 1];
    }
#endif

    return sum;
}

__kernel void normalize_hists_kernel(
    const int nthreads, const int block_hist_size, const int img_block_width,
    __global float* block_hists, const float threshold, __local float *squares)
{
    const int tid = get_local_id(0);
    const int gidX = get_group_id(0);
    const int gidY = get_group_id(1);

    __global float* hist = block_hists + (gidY * img_block_width + gidX) *
        block_hist_size + tid;

    float elem = 0.f;
    if (tid < block_hist_size)
        elem = hist[0];

    squares[tid] = elem * elem;

    barrier(CLK_LOCAL_MEM_FENCE);
    float sum = reduce_smem(squares, nthreads);

    float scale = 1.0f / (sqrt(sum) + 0.1f * block_hist_size);
    elem = min(elem * scale, threshold);

    barrier(CLK_LOCAL_MEM_FENCE);
    squares[tid] = elem * elem;

    barrier(CLK_LOCAL_MEM_FENCE);
    sum = reduce_smem(squares, nthreads);
    scale = 1.0f / (sqrt(sum) + 1e-3f);

    if (tid < block_hist_size)
        hist[0] = elem * scale;
}

//---------------------------------------------------------------------
//  Linear SVM based classification
//  48x96 window, 9 bins and default parameters
//  180 threads, each thread corresponds to a bin in a row
__kernel void classify_hists_180_kernel(
    const int cdescr_width, const int cdescr_height, const int cblock_hist_size,
    const int img_win_width, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float * block_hists, __global const float* coefs,
    float free_coef, float threshold, __global uchar* labels)
{
    const int tid = get_local_id(0);
    const int gidX = get_group_id(0);
    const int gidY = get_group_id(1);

    __global const float* hist = block_hists + (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    float product = 0.f;

    for (int i = 0; i < cdescr_height; i++)
    {
        product += coefs[i * cdescr_width + tid] *
            hist[i * img_block_width * cblock_hist_size + tid];
    }

    __local float products[180];

    products[tid] = product;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 90) products[tid] = product = product + products[tid + 90];
    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 45) products[tid] = product = product + products[tid + 45];
    barrier(CLK_LOCAL_MEM_FENCE);

    volatile __local float* smem = products;
#ifdef CPU
    if (tid < 13) smem[tid] = product = product + smem[tid + 32];
    barrier(CLK_LOCAL_MEM_FENCE);
    if (tid < 16) smem[tid] = product = product + smem[tid + 16];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<8) smem[tid] = product = product + smem[tid + 8];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<4) smem[tid] = product = product + smem[tid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<2) smem[tid] = product = product + smem[tid + 2];
    barrier(CLK_LOCAL_MEM_FENCE);
#else
    if (tid < 13)
    {
        smem[tid] = product = product + smem[tid + 32];
    }
#if WAVE_SIZE < 32
    barrier(CLK_LOCAL_MEM_FENCE);
#endif
    if (tid < 16)
    {
        smem[tid] = product = product + smem[tid + 16];
        smem[tid] = product = product + smem[tid + 8];
        smem[tid] = product = product + smem[tid + 4];
        smem[tid] = product = product + smem[tid + 2];
    }
#endif

    if (tid == 0){
        product = product + smem[tid + 1];
        labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold);
    }
}

//---------------------------------------------------------------------
//  Linear SVM based classification
//  64x128 window, 9 bins and default parameters
//  256 threads, 252 of them are used
__kernel void classify_hists_252_kernel(
    const int cdescr_width, const int cdescr_height, const int cblock_hist_size,
    const int img_win_width, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float * block_hists, __global const float* coefs,
    float free_coef, float threshold, __global uchar* labels)
{
    const int tid = get_local_id(0);
    const int gidX = get_group_id(0);
    const int gidY = get_group_id(1);

    __global const float* hist = block_hists + (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    float product = 0.f;
    if (tid < cdescr_width)
    {
        for (int i = 0; i < cdescr_height; i++)
            product += coefs[i * cdescr_width + tid] *
                hist[i * img_block_width * cblock_hist_size + tid];
    }

    __local float products[NTHREADS];

    products[tid] = product;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 128) products[tid] = product = product + products[tid + 128];
    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 64) products[tid] = product = product + products[tid + 64];
    barrier(CLK_LOCAL_MEM_FENCE);

    volatile __local float* smem = products;
#ifdef CPU
    if(tid<32) smem[tid] = product = product + smem[tid + 32];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<16) smem[tid] = product = product + smem[tid + 16];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<8) smem[tid] = product = product + smem[tid + 8];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<4) smem[tid] = product = product + smem[tid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<2) smem[tid] = product = product + smem[tid + 2];
    barrier(CLK_LOCAL_MEM_FENCE);
#else
    if (tid < 32)
    {
        smem[tid] = product = product + smem[tid + 32];
#if WAVE_SIZE < 32
    } barrier(CLK_LOCAL_MEM_FENCE);
    if (tid < 16) {
#endif
        smem[tid] = product = product + smem[tid + 16];
        smem[tid] = product = product + smem[tid + 8];
        smem[tid] = product = product + smem[tid + 4];
        smem[tid] = product = product + smem[tid + 2];
    }
#endif
    if (tid == 0){
        product = product + smem[tid + 1];
        labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold);
    }
}

//---------------------------------------------------------------------
//  Linear SVM based classification
//  256 threads
__kernel void classify_hists_kernel(
    const int cdescr_size, const int cdescr_width, const int cblock_hist_size,
    const int img_win_width, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float * block_hists, __global const float* coefs,
    float free_coef, float threshold, __global uchar* labels)
{
    const int tid = get_local_id(0);
    const int gidX = get_group_id(0);
    const int gidY = get_group_id(1);

    __global const float* hist = block_hists + (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    float product = 0.f;
    for (int i = tid; i < cdescr_size; i += NTHREADS)
    {
        int offset_y = i / cdescr_width;
        int offset_x = i - offset_y * cdescr_width;
        product += coefs[i] *
            hist[offset_y * img_block_width * cblock_hist_size + offset_x];
    }

    __local float products[NTHREADS];

    products[tid] = product;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 128) products[tid] = product = product + products[tid + 128];
    barrier(CLK_LOCAL_MEM_FENCE);

    if (tid < 64) products[tid] = product = product + products[tid + 64];
    barrier(CLK_LOCAL_MEM_FENCE);

    volatile __local float* smem = products;
#ifdef CPU
    if(tid<32) smem[tid] = product = product + smem[tid + 32];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<16) smem[tid] = product = product + smem[tid + 16];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<8) smem[tid] = product = product + smem[tid + 8];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<4) smem[tid] = product = product + smem[tid + 4];
    barrier(CLK_LOCAL_MEM_FENCE);
    if(tid<2) smem[tid] = product = product + smem[tid + 2];
    barrier(CLK_LOCAL_MEM_FENCE);
#else
    if (tid < 32)
    {
        smem[tid] = product = product + smem[tid + 32];
#if WAVE_SIZE < 32
    } barrier(CLK_LOCAL_MEM_FENCE);
    if (tid < 16) {
#endif
        smem[tid] = product = product + smem[tid + 16];
        smem[tid] = product = product + smem[tid + 8];
        smem[tid] = product = product + smem[tid + 4];
        smem[tid] = product = product + smem[tid + 2];
    }
#endif
    if (tid == 0){
        smem[tid] = product = product + smem[tid + 1];
        labels[gidY * img_win_width + gidX] = (product + free_coef >= threshold);
    }
}

//----------------------------------------------------------------------------
// Extract descriptors

__kernel void extract_descrs_by_rows_kernel(
    const int cblock_hist_size, const int descriptors_quadstep,
    const int cdescr_size, const int cdescr_width, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float* block_hists, __global float* descriptors)
{
    int tid = get_local_id(0);
    int gidX = get_group_id(0);
    int gidY = get_group_id(1);

    // Get left top corner of the window in src
    __global const float* hist = block_hists + (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    // Get left top corner of the window in dst
    __global float* descriptor = descriptors +
        (gidY * get_num_groups(0) + gidX) * descriptors_quadstep;

    // Copy elements from src to dst
    for (int i = tid; i < cdescr_size; i += NTHREADS)
    {
        int offset_y = i / cdescr_width;
        int offset_x = i - offset_y * cdescr_width;
        descriptor[i] = hist[offset_y * img_block_width * cblock_hist_size + offset_x];
    }
}

__kernel void extract_descrs_by_cols_kernel(
    const int cblock_hist_size, const int descriptors_quadstep, const int cdescr_size,
    const int cnblocks_win_x, const int cnblocks_win_y, const int img_block_width,
    const int win_block_stride_x, const int win_block_stride_y,
    __global const float* block_hists, __global float* descriptors)
{
    int tid = get_local_id(0);
    int gidX = get_group_id(0);
    int gidY = get_group_id(1);

    // Get left top corner of the window in src
    __global const float* hist = block_hists +  (gidY * win_block_stride_y *
        img_block_width + gidX * win_block_stride_x) * cblock_hist_size;

    // Get left top corner of the window in dst
    __global float* descriptor = descriptors +
        (gidY * get_num_groups(0) + gidX) * descriptors_quadstep;

    // Copy elements from src to dst
    for (int i = tid; i < cdescr_size; i += NTHREADS)
    {
        int block_idx = i / cblock_hist_size;
        int idx_in_block = i - block_idx * cblock_hist_size;

        int y = block_idx / cnblocks_win_x;
        int x = block_idx - y * cnblocks_win_x;

        descriptor[(x * cnblocks_win_y + y) * cblock_hist_size + idx_in_block] =
            hist[(y * img_block_width  + x) * cblock_hist_size + idx_in_block];
    }
}

//----------------------------------------------------------------------------
// Gradients computation

__kernel void compute_gradients_8UC4_kernel(
    const int height, const int width,
    const int img_step, const int grad_quadstep, const int qangle_step,
    const __global uchar4 * img, __global float * grad, __global QANGLE_TYPE * qangle,
    const float angle_scale, const char correct_gamma, const int cnbins)
{
    const int x = get_global_id(0);
    const int tid = get_local_id(0);
    const int gSizeX = get_local_size(0);
    const int gidY = get_group_id(1);

    __global const uchar4* row = img + gidY * img_step;

    __local float sh_row[(NTHREADS + 2) * 3];

    uchar4 val;
    if (x < width)
        val = row[x];
    else
        val = row[width - 2];

    sh_row[tid + 1] = val.x;
    sh_row[tid + 1 + (NTHREADS + 2)] = val.y;
    sh_row[tid + 1 + 2 * (NTHREADS + 2)] = val.z;

    if (tid == 0)
    {
        val = row[max(x - 1, 1)];
        sh_row[0] = val.x;
        sh_row[(NTHREADS + 2)] = val.y;
        sh_row[2 * (NTHREADS + 2)] = val.z;
    }

    if (tid == gSizeX - 1)
    {
        val = row[min(x + 1, width - 2)];
        sh_row[gSizeX + 1] = val.x;
        sh_row[gSizeX + 1 + (NTHREADS + 2)] = val.y;
        sh_row[gSizeX + 1 + 2 * (NTHREADS + 2)] = val.z;
    }

    barrier(CLK_LOCAL_MEM_FENCE);
    if (x < width)
    {
        float3 a = (float3) (sh_row[tid], sh_row[tid + (NTHREADS + 2)],
            sh_row[tid + 2 * (NTHREADS + 2)]);
        float3 b = (float3) (sh_row[tid + 2], sh_row[tid + 2 + (NTHREADS + 2)],
            sh_row[tid + 2 + 2 * (NTHREADS + 2)]);

        float3 dx;
        if (correct_gamma == 1)
            dx = sqrt(b) - sqrt(a);
        else
            dx = b - a;

        float3 dy = (float3) 0.f;

        if (gidY > 0 && gidY < height - 1)
        {
            a = convert_float3(img[(gidY - 1) * img_step + x].xyz);
            b = convert_float3(img[(gidY + 1) * img_step + x].xyz);

            if (correct_gamma == 1)
                dy = sqrt(b) - sqrt(a);
            else
                dy = b - a;
        }

        float best_dx = dx.x;
        float best_dy = dy.x;

        float mag0 = dx.x * dx.x + dy.x * dy.x;
        float mag1 = dx.y * dx.y + dy.y * dy.y;
        if (mag0 < mag1)
        {
            best_dx = dx.y;
            best_dy = dy.y;
            mag0 = mag1;
        }

        mag1 = dx.z * dx.z + dy.z * dy.z;
        if (mag0 < mag1)
        {
            best_dx = dx.z;
            best_dy = dy.z;
            mag0 = mag1;
        }

        mag0 = sqrt(mag0);

        float ang = (atan2(best_dy, best_dx) + CV_PI_F) * angle_scale - 0.5f;
        int hidx = (int)floor(ang);
        ang -= hidx;
        hidx = (hidx + cnbins) % cnbins;

        qangle[(gidY * qangle_step + x) << 1] = hidx;
        qangle[((gidY * qangle_step + x) << 1) + 1] = (hidx + 1) % cnbins;
        grad[(gidY * grad_quadstep + x) << 1] = mag0 * (1.f - ang);
        grad[((gidY * grad_quadstep + x) << 1) + 1] = mag0 * ang;
    }
}

__kernel void compute_gradients_8UC1_kernel(
    const int height, const int width,
    const int img_step, const int grad_quadstep, const int qangle_step,
    __global const uchar * img, __global float * grad, __global QANGLE_TYPE * qangle,
    const float angle_scale, const char correct_gamma, const int cnbins)
{
    const int x = get_global_id(0);
    const int tid = get_local_id(0);
    const int gSizeX = get_local_size(0);
    const int gidY = get_group_id(1);

    __global const uchar* row = img + gidY * img_step;

    __local float sh_row[NTHREADS + 2];

    if (x < width)
        sh_row[tid + 1] = row[x];
    else
        sh_row[tid + 1] = row[width - 2];

    if (tid == 0)
        sh_row[0] = row[max(x - 1, 1)];

    if (tid == gSizeX - 1)
        sh_row[gSizeX + 1] = row[min(x + 1, width - 2)];

    barrier(CLK_LOCAL_MEM_FENCE);
    if (x < width)
    {
        float dx;

        if (correct_gamma == 1)
            dx = sqrt(sh_row[tid + 2]) - sqrt(sh_row[tid]);
        else
            dx = sh_row[tid + 2] - sh_row[tid];

        float dy = 0.f;
        if (gidY > 0 && gidY < height - 1)
        {
            float a = (float) img[ (gidY + 1) * img_step + x ];
            float b = (float) img[ (gidY - 1) * img_step + x ];
            if (correct_gamma == 1)
                dy = sqrt(a) - sqrt(b);
            else
                dy = a - b;
        }
        float mag = sqrt(dx * dx + dy * dy);

        float ang = (atan2(dy, dx) + CV_PI_F) * angle_scale - 0.5f;
        int hidx = (int)floor(ang);
        ang -= hidx;
        hidx = (hidx + cnbins) % cnbins;

        qangle[ (gidY * qangle_step + x) << 1 ]     = hidx;
        qangle[ ((gidY * qangle_step + x) << 1) + 1 ] = (hidx + 1) % cnbins;
        grad[ (gidY * grad_quadstep + x) << 1 ]       = mag * (1.f - ang);
        grad[ ((gidY * grad_quadstep + x) << 1) + 1 ]   = mag * ang;
    }
}


plexfix: change order of ignored files

plexfix: change order of ignored files

ignore-file-p was called too late to do anything, and it was clear
fromm the emails I got that it was ineffective.

;; plexfix :: fix filenames for Plex Media Server

(eval-when (compile eval load)
  (require :tget-defs "defs.fasl")
  (require :tget-utils "utils.fasl"))

(in-package :user)

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

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

(defun plexfix (filename &key (stream t)
			      ((:no-execute *no-execute*) *no-execute*))
  (if* (not (probe-file filename))
     then (.error "~a does not exist." filename)
   elseif (ignore-file-p filename)
     thenret
   elseif (file-directory-p filename)
     then (let ((files (directory (pathname-as-directory filename)))
		rar)
	    (if* (setq rar
		   (member "rar" files :key #'pathname-type :test #'string=))
	       then (setq rar (car rar))
		    (format stream "extracting ~a...~%" (file-namestring rar))
		    (excl.osi:command-output
		     (format nil "unrar e ~a ./" (file-namestring rar))
		     :directory (directory-namestring rar))
	       else (dolist (file files)
		      ;; handle mp4 and mkv files, for now, warn of the
		      ;; rest, ignoring some known files
		      (if* (member (pathname-type file) '("mp4" "mkv")
				   :test #'string=)
			 then (plexfix-1 stream file)
		       elseif (member (pathname-type file)
				      '("nfo" "txt" "srt")
				      :test #'string=)
			 thenret
			 else (format stream "Unknown file:~a.~%" file)))))
     else (plexfix-1 stream filename)))

(defun ignore-file-p (filename)
  ;; don't fix anything in /tmp/... since they almost never need fixing
  ;; and plexfix would make more of a mess.  This makes all the previous
  ;; ignore rules obsolete.
;;;;TODO: need a better way to specific which directories get the treatment
  (match-re "(/movies/|/tmp/)" (namestring filename) :return nil))

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

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

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

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

(defun make-symlink (target link-name)
  ;; like symlink, but the link-name is relative, meaning we need to change
  ;; to the directory first
  (chdir (path-pathname link-name))
  (symlink (file-namestring target) (file-namestring link-name)
	   :raw t))

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

(define-condition plexfix (error) ())

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

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

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

;; plexfix :: fix filenames for Plex Media Server

(eval-when (compile eval load)
  (require :tget-defs "defs.fasl")
  (require :tget-utils "utils.fasl"))

(in-package :user)

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

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

(defun plexfix (filename &key (stream t)
			      ((:no-execute *no-execute*) *no-execute*))
  (if* (not (probe-file filename))
     then (.error "~a does not exist." filename)
   elseif (file-directory-p filename)
     then (let ((files (directory (pathname-as-directory filename)))
		rar)
	    (if* (setq rar
		   (member "rar" files :key #'pathname-type :test #'string=))
	       then (setq rar (car rar))
		    (format stream "extracting ~a...~%" (file-namestring rar))
		    (excl.osi:command-output
		     (format nil "unrar e ~a ./" (file-namestring rar))
		     :directory (directory-namestring rar))
	       else (dolist (file files)
		      ;; handle mp4 and mkv files, for now, warn of the
		      ;; rest, ignoring some known files
		      (if* (member (pathname-type file) '("mp4" "mkv")
				   :test #'string=)
			 then (plexfix-1 stream file)
		       elseif (member (pathname-type file)
				      '("nfo" "txt" "srt")
				      :test #'string=)
			 thenret
			 else (format stream "Unknown file:~a.~%" file)))))
   elseif (ignore-file-p filename)
     thenret
     else (plexfix-1 stream filename)))

(defun ignore-file-p (filename)
  ;; don't fix anything in /tmp/... since they almost never need fixing
  ;; and plexfix would make more of a mess.  This makes all the previous
  ;; ignore rules obsolete.
;;;;TODO: need a better way to specific which directories get the treatment
  (match-re "(/movies/|/tmp/)" (namestring filename) :return nil))

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

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

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

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

(defun make-symlink (target link-name)
  ;; like symlink, but the link-name is relative, meaning we need to change
  ;; to the directory first
  (chdir (path-pathname link-name))
  (symlink (file-namestring target) (file-namestring link-name)
	   :raw t))

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

(define-condition plexfix (error) ())

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

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

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


add usb camera sobel example

add usb camera sobel example

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

#include "../host/inc/defines.h"

// Sobel filter kernel
// frame_in and frame_out are different buffers. Specify restrict on
// them so that the compiler knows they do not alias each other.
__kernel
void camera_sobel(global unsigned short * restrict frame_in, global unsigned int * restrict frame_out,
           const int iterations, const unsigned int threshold)
{
    // Filter coefficients
    int Gx[3][3] = {{-1,-2,-1},{0,0,0},{1,2,1}};
    int Gy[3][3] = {{-1,0,1},{-2,0,2},{-1,0,1}};

    // Pixel buffer of 2 rows and 3 extra pixels
    unsigned short rows[2 * COLS + 3];

    // The initial iterations are used to initialize the pixel buffer.
    int count = -(2 * COLS + 3);
    while (count != iterations) {
        // Each cycle, shift a new pixel into the buffer.
        // Unrolling this loop allows the compile to infer a shift register.
        #pragma unroll
        for (int i = COLS * 2 + 2; i > 0; --i) {
            rows[i] = rows[i - 1];
        }
        rows[0] = count >= 0 ? frame_in[count] : 0;

        int x_dir = 0;
        int y_dir = 0;

        #pragma unroll
        for (int i = 0; i < 3; ++i) {
            #pragma unroll
            for (int j = 0; j < 3; ++j) {
		//Get Y form YU or YV
                unsigned int pixel = rows[i * COLS + j];
                unsigned int luma = pixel & 0xff;
                x_dir += luma * Gx[i][j];
                y_dir += luma * Gy[i][j];
            }
        }
        int temp = abs(x_dir) + abs(y_dir);
        unsigned int clamped;
        if (temp > threshold) {
            clamped = 0xffffffff;
        } else {
            clamped = 0xff000000;
        }

        if (count >= 0) {
            frame_out[count] = clamped;
        }
        count++;
    }
}

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

#include "../host/inc/defines.h"

// Sobel filter kernel
// frame_in and frame_out are different buffers. Specify restrict on
// them so that the compiler knows they do not alias each other.
__kernel
void camera_sobel(global unsigned short * restrict frame_in, global unsigned int * restrict frame_out,
           const int iterations, const unsigned int threshold)
{
    // Filter coefficients
    int Gx[3][3] = {{-1,-2,-1},{0,0,0},{1,2,1}};
    int Gy[3][3] = {{-1,0,1},{-2,0,2},{-1,0,1}};

    // Pixel buffer of 2 rows and 3 extra pixels
    unsigned short rows[2 * COLS + 3];

    // The initial iterations are used to initialize the pixel buffer.
    int count = -(2 * COLS + 3);
    while (count != iterations) {
        // Each cycle, shift a new pixel into the buffer.
        // Unrolling this loop allows the compile to infer a shift register.
        #pragma unroll
        for (int i = COLS * 2 + 2; i > 0; --i) {
            rows[i] = rows[i - 1];
        }
        rows[0] = count >= 0 ? frame_in[count] : 0;

        int x_dir = 0;
        int y_dir = 0;

        #pragma unroll
        for (int i = 0; i < 3; ++i) {
            #pragma unroll
            for (int j = 0; j < 3; ++j) {
		//Get Y form YU or YV
                unsigned int pixel = rows[i * COLS + j];
                unsigned int luma = (pixel >> 8) & 0xff;
                x_dir += luma * Gx[i][j];
                y_dir += luma * Gy[i][j];
            }
        }
        int temp = abs(x_dir) + abs(y_dir);
        unsigned int clamped;
        if (temp > threshold) {
            clamped = 0xffffffff;
        } else {
            clamped = 0xff000000;
        }

        if (count >= 0) {
            frame_out[count] = clamped;
        }
        count++;
    }
}


fixed silly syntax error of missing semicolons

#if __OPENCL_VERSION__ == CL_VERSION_1_1
    #pragma OPENCL EXTENSION cl_khr_fp64 : enable
#endif
#define NVIDIA_WARP_SIZE 32
#define MAPPING  __local double mapping[4]; mapping[0]=0.0; mapping[1]=9.0; mapping[2]=1.0; mapping[3]=2.0;

__kernel void reset_x(
	__global double * x,
	const int n,
	const double val
) {
	int i = get_global_id(0);
	if (i < n){
		x[i] = val;
	}
	return;
}

__kernel void compute_xt_times_vector(
	const int observations,
	const int snps,
	const int subject_chunks,
	const int packedstride_snpmajor,
	const int max_work_group_size,
	__global const char * packedgeno_snpmajor,
	__global double * Xt_vec_chunks,
	__global const double * vec,
	__global const double * means,
	__global const double * precisions,
	__global const long * mask_n,
	__local  double * local_floatgeno
){
    // initialize lookup table
    MAPPING

    // extract thread information
    int subject_chunk = get_group_id(0);
    int snp           = get_group_id(1);
    int threadindex   = get_local_id(0);

    // pull current snp mean, prec from input
    double mean      = means[snp];
    double precision = precisions[snp];

    // initialize values of floating point and compressed genotype arrays
    local_floatgeno[threadindex] = 0.0;

    // synchronize threads in local workgroup
    // barrier(CLK_LOCAL_MEM_FENCE);

    // index of current subject?
    int subject_index = subject_chunk * max_work_group_size + threadindex;

    // now query current value of vector y
    // also save the bitmask value
    double y = vec[subject_index];
    int mask = mask_n[subject_index];

    // ensure that subject is in set of observations
    // this is a standard bounds check with OpenCL kernels
    if (subject_index < observations){

        // decompress genotypes into local floating point arrays
        // decompressed genotypes are in local_floatgeno
        int row = subject_chunk * max_work_group_size + threadindex;
        int k = 2*(row & 3);
        char genotype_block = packedgeno_snpmajor[snp * packedstride_snpmajor + (row >> 2)];
        int val  = (((int)genotype_block)>>k) & 3;
        //local_floatgeno[threadindex] = mapping[val];
        double geno = mapping[val];

        // synchronize threads in local workgroup
        // barrier(CLK_LOCAL_MEM_FENCE);

        // now translate and standardize the decompressed genotype to the correct floating point genotype
        // if missing then set to 0.0, otherwise standardize on fly using mean and precision
        // in this process, will multiply against value at correct index of vector
        // in essence, this is the X'*y part
        // local_floatgeno[threadindex] = (local_floatgeno[threadindex] == 9.0 || mask_n[subject_index] == 0) ? 0.0 : (local_floatgeno[threadindex] - mean) * precision * vec[subject_index];
        // try storing this as a local variable too
        local_floatgeno[threadindex] = (geno == 9.0 || mask == 0) ? 0.0 : (geno - mean) * precision * y;

        // synchronize threads in local workgroup
        barrier(CLK_LOCAL_MEM_FENCE);

        // reduce across local workgroup
        // GPUs that are compliant with OpenCL 2.0 can replace this loop with work_group_reduce(local_floatgeno)
        for(int s = max_work_group_size / 2; s > 0; s >>= 1) {
            if (threadindex < s) {
                local_floatgeno[threadindex] += local_floatgeno[threadindex + s];
            }

            // synchronize threads in local workgroup
            barrier(CLK_LOCAL_MEM_FENCE);
        }

        if(threadindex == 0){
            Xt_vec_chunks[snp * subject_chunks + subject_chunk] += local_floatgeno[0];
        }
    }
    return;
}

__kernel void reduce_xt_vec_chunks(
    const int observations,
    const int subject_chunks,
    const int chunk_clusters,
    const int max_work_group_size,
    __global double * Xt_vec_chunks,
    __global double * Xt_vec,
    __local  double * local_xt
){
    // get SNP and thread indices
    int snp = get_group_id(1);
    int threadindex = get_local_id(0);

    // initialize local memory array with components equal to 0.0
    local_xt[threadindex] = 0.0;

    // synchronize threads in local workgroup
    //barrier(CLK_LOCAL_MEM_FENCE);

    // spawn computations for each chunk
    for (int chunk_cluster = 0; chunk_cluster < chunk_clusters; ++chunk_cluster){

        int subject_chunk = chunk_cluster * max_work_group_size + threadindex;

        if (subject_chunk < subject_chunks){

            // this accumuates chunks of X' times vector
            local_xt[threadindex] += Xt_vec_chunks[snp * subject_chunks + subject_chunk];
        }

        // synchronize threads in local workgroup
        barrier(CLK_LOCAL_MEM_FENCE);
    }

    // now reduce across the workgroup
    // in OpenCL 2.0, can use work_group_reduce(local_xt)
    for (int s = max_work_group_size / 2; s > 0; s >>= 1) {
        if (threadindex < s) {
            local_xt[threadindex] += local_xt[threadindex + s];
        }

        // synchronize threads in local workgroup
        barrier(CLK_LOCAL_MEM_FENCE);
    }

    // topmost thread assigns reduction across workgroup to correct entry in output vector
    if ( threadindex == 0){
        Xt_vec[snp] = local_xt[0];
    }
    return;
}

#if __OPENCL_VERSION__ == CL_VERSION_1_1
    #pragma OPENCL EXTENSION cl_khr_fp64 : enable
#endif
#define NVIDIA_WARP_SIZE 32
#define MAPPING  __local double mapping[4]; mapping[0]=0.0; mapping[1]=9.0; mapping[2]=1.0; mapping[3]=2.0;

__kernel void reset_x(
	__global double * x,
	const int n,
	const double val
) {
	int i = get_global_id(0);
	if (i < n){
		x[i] = val;
	}
	return;
}

__kernel void compute_xt_times_vector(
	const int observations,
	const int snps,
	const int subject_chunks,
	const int packedstride_snpmajor,
	const int max_work_group_size,
	__global const char * packedgeno_snpmajor,
	__global double * Xt_vec_chunks,
	__global const double * vec,
	__global const double * means,
	__global const double * precisions,
	__global const long * mask_n,
	__local  double * local_floatgeno
){
    // initialize lookup table
    MAPPING

    // extract thread information
    int subject_chunk = get_group_id(0);
    int snp           = get_group_id(1);
    int threadindex   = get_local_id(0);

    // pull current snp mean, prec from input
    double mean      = means[snp];
    double precision = precisions[snp];

    // initialize values of floating point and compressed genotype arrays
    local_floatgeno[threadindex] = 0.0;

    // synchronize threads in local workgroup
    // barrier(CLK_LOCAL_MEM_FENCE);

    // index of current subject?
    int subject_index = subject_chunk * max_work_group_size + threadindex;

    // now query current value of vector y
    // also save the bitmask value
    double y = vec[subject_index]
    int mask = mask_n[subject_index]

    // ensure that subject is in set of observations
    // this is a standard bounds check with OpenCL kernels
    if (subject_index < observations){

        // decompress genotypes into local floating point arrays
        // decompressed genotypes are in local_floatgeno
        int row = subject_chunk * max_work_group_size + threadindex;
        int k = 2*(row & 3);
        char genotype_block = packedgeno_snpmajor[snp * packedstride_snpmajor + (row >> 2)];
        int val  = (((int)genotype_block)>>k) & 3;
        //local_floatgeno[threadindex] = mapping[val];
        double geno = mapping[val];

        // synchronize threads in local workgroup
        // barrier(CLK_LOCAL_MEM_FENCE);

        // now translate and standardize the decompressed genotype to the correct floating point genotype
        // if missing then set to 0.0, otherwise standardize on fly using mean and precision
        // in this process, will multiply against value at correct index of vector
        // in essence, this is the X'*y part
        // local_floatgeno[threadindex] = (local_floatgeno[threadindex] == 9.0 || mask_n[subject_index] == 0) ? 0.0 : (local_floatgeno[threadindex] - mean) * precision * vec[subject_index];
        // try storing this as a local variable too
        local_floatgeno[threadindex] = (geno == 9.0 || mask == 0) ? 0.0 : (geno - mean) * precision * y;

        // synchronize threads in local workgroup
        barrier(CLK_LOCAL_MEM_FENCE);

        // reduce across local workgroup
        // GPUs that are compliant with OpenCL 2.0 can replace this loop with work_group_reduce(local_floatgeno)
        for(int s = max_work_group_size / 2; s > 0; s >>= 1) {
            if (threadindex < s) {
                local_floatgeno[threadindex] += local_floatgeno[threadindex + s];
            }

            // synchronize threads in local workgroup
            barrier(CLK_LOCAL_MEM_FENCE);
        }

        if(threadindex == 0){
            Xt_vec_chunks[snp * subject_chunks + subject_chunk] += local_floatgeno[0];
        }
    }
    return;
}

__kernel void reduce_xt_vec_chunks(
    const int observations,
    const int subject_chunks,
    const int chunk_clusters,
    const int max_work_group_size,
    __global double * Xt_vec_chunks,
    __global double * Xt_vec,
    __local  double * local_xt
){
    // get SNP and thread indices
    int snp = get_group_id(1);
    int threadindex = get_local_id(0);

    // initialize local memory array with components equal to 0.0
    local_xt[threadindex] = 0.0;

    // synchronize threads in local workgroup
    //barrier(CLK_LOCAL_MEM_FENCE);

    // spawn computations for each chunk
    for (int chunk_cluster = 0; chunk_cluster < chunk_clusters; ++chunk_cluster){

        int subject_chunk = chunk_cluster * max_work_group_size + threadindex;

        if (subject_chunk < subject_chunks){

            // this accumuates chunks of X' times vector
            local_xt[threadindex] += Xt_vec_chunks[snp * subject_chunks + subject_chunk];
        }

        // synchronize threads in local workgroup
        barrier(CLK_LOCAL_MEM_FENCE);
    }

    // now reduce across the workgroup
    // in OpenCL 2.0, can use work_group_reduce(local_xt)
    for (int s = max_work_group_size / 2; s > 0; s >>= 1) {
        if (threadindex < s) {
            local_xt[threadindex] += local_xt[threadindex + s];
        }

        // synchronize threads in local workgroup
        barrier(CLK_LOCAL_MEM_FENCE);
    }

    // topmost thread assigns reduction across workgroup to correct entry in output vector
    if ( threadindex == 0){
        Xt_vec[snp] = local_xt[0];
    }
    return;
}


Fixed another bug in the OpenCL kernels

Fixed another bug in the OpenCL kernels

//the Euclidean distance kernel - N is the side length of the images
__kernel void manhattan(__global const int *vect1, __global const int *vect2, __global int *out, int N){
	int xIndex = get_global_id(0);
    int yIndex = get_global_id(1);

	if (xIndex >= N || yIndex >= N)
		return;

	int index = N*yIndex + xIndex;
	out[index] = abs(vect1[index] - vect2[index]);
}

//the Euclidean distance kernel - N is the side length of the images
__kernel void euclidean(__global const int *vect1, __global const int *vect2, __global int *out, int N){
	int xIndex = get_global_id(0);
    int yIndex = get_global_id(1);

	if (xIndex >= N || yIndex >= N)
		return;

	int index = N*yIndex + xIndex;
	out[index] = abs(vect1[index] - vect2[index]);
}