convolve: OpenCL core uses double instead of float

To avoid rounding errors with large images.

// OpenCL Kernel
// https://www.khronos.org/files/opencl-1-2-quick-reference-card.pdf

kernel void convolve_image(__read_only image2d_t image,
                           __read_only image2d_t pattern,
                           __global __write_only float* output,
                           sampler_t sampler,
                           const int2 top_left_rc,   // image (row, column)
                           const int image_start_r,  // where in the image row to start writing (for partitions)
                           const int image_end_r)    // end row writing (for partitions)
{
   // From a birds-eye-view what this kernel does is to compute a similarity
   // measure almost like a convolve operation, but with a distance measure
   // that uses the alpha channel of the pattern as a mask (to ignore or
   // down-weight parts of the pattern) and further uses a squared distance
   // measure. One call to this method computes a single pixel
   // in the `output` image (`output` is our region-of-interest (ROI)). The
   // output just contains float values (NOT in scale 0..1) for how similar
   // pattern and image are at that pixel. Lower value mean "more similar".
   // `top_left_rc` defines to which pixel coordinate the (0, 0) pixel in the
   // output corresponds.

    // Position (row, column) of the pixel in the output image.
    // Note, that OpenCL has uses column-major ("fortran"-style) storage, so
    // in the end we have to access the pixel data (through a sampler) in
    // (column, row) order. But we stick to naming like "C"-style row-major
    // ordering and just do the flip in the two nested for-loops in the loop
    // variables c and r, which are then used according to OpenCL's convention.
    const int2 pos = {get_global_id(0), get_global_id(1)};

    // The width of the image
    const int image_width = get_image_width(image);

    // The pattern should be at least 3x3 and have an odd width and height
    const int pattern_half_w = (get_image_width(pattern)-1) / 2;
    const int pattern_half_h = (get_image_height(pattern)-1) / 2;

    // 4-tuple of the RGBA values from the pattern image and RRB of the image.
    float4 pattern_color = (float4)(0.0, 0.0, 0.0, 0.0);
    float4 image_color = (float4)(0.0, 0.0, 0.0, 0.0);

    // The (column, row) of the center pixel in the pattern is computed
    // Note, that later one we use this as (column, row), therefore we switch
    // already here the .s0 and .s1 assignment
    // (s0 is the first entry, s1 second)
    int2 pattern_pos_cr = (int2)(0, 0);
    pattern_pos_cr.s1 = -top_left_rc.s0 - pos.s0 + pattern_half_h; // row
    pattern_pos_cr.s0 = -top_left_rc.s1 - pos.s1 + pattern_half_w; // column

    // value for the output pixel we are going to compute in this kernel
    double value = 0.0;
    // the distance in the color-space between the image and the pattern
    double dist = 0.0f;
    const double max_dist = sqrt(3.0);

    // Go though all pixel of the pattern image
    for (int r = image_start_r; r < image_end_r; r++) {

        for (int c = 0; c < image_width; c++) {

            pattern_color = read_imagef(pattern, sampler, pattern_pos_cr + (int2)(c, r));

            if(pattern_color.w > 0.0f) {
                // Use the alpha value `.w` from an RGBA image (pattern) as
                // weight and compute the `distance` which is the squared
                // absolute difference
                image_color = read_imagef(image, sampler, (int2)(c, r));
                dist = fast_distance(pattern_color.xyz, image_color.xyz);
                value += (1-pattern_color.w) * max_dist + pattern_color.w * dist;
            } else {
                // Just add a constant that represents the maximal possible
                // difference between image and pattern for a single pixel.
                // E.g. from white (1,1,1) to black (0,0,0).
                value += max_dist;
            }
        }
    }

    output[pos.s0 * get_global_size(1) + pos.s1] = value;
}

// OpenCL Kernel
// https://www.khronos.org/files/opencl-1-2-quick-reference-card.pdf

kernel void convolve_image(__read_only image2d_t image,
                           __read_only image2d_t pattern,
                           __global __write_only float* output,
                           sampler_t sampler,
                           const int2 top_left_rc,   // image (row, column)
                           const int image_start_r,  // where in the image row to start writing (for partitions)
                           const int image_end_r)    // end row writing (for partitions)
{
   // From a birds-eye-view what this kernel does is to compute a similarity
   // measure almost like a convolve operation, but with a distance measure
   // that uses the alpha channel of the pattern as a mask (to ignore or
   // down-weight parts of the pattern) and further uses a squared distance
   // measure. One call to this method computes a single pixel
   // in the `output` image (`output` is our region-of-interest (ROI)). The
   // output just contains float values (NOT in scale 0..1) for how similar
   // pattern and image are at that pixel. Lower value mean "more similar".
   // `top_left_rc` defines to which pixel coordinate the (0, 0) pixel in the
   // output corresponds.

    // Position (row, column) of the pixel in the output image.
    // Note, that OpenCL has uses column-major ("fortran"-style) storage, so
    // in the end we have to access the pixel data (through a sampler) in
    // (column, row) order. But we stick to naming like "C"-style row-major
    // ordering and just do the flip in the two nested for-loops in the loop
    // variables c and r, which are then used according to OpenCL's convention.
    const int2 pos = {get_global_id(0), get_global_id(1)};

    // The width of the image
    const int image_width = get_image_width(image);

    // The pattern should be at least 3x3 and have an odd width and height
    const int pattern_half_w = (get_image_width(pattern)-1) / 2;
    const int pattern_half_h = (get_image_height(pattern)-1) / 2;

    // 4-tuple of the RGBA values from the pattern image and RRB of the image.
    float4 pattern_color = (float4)(0.0, 0.0, 0.0, 0.0);
    float4 image_color = (float4)(0.0, 0.0, 0.0, 0.0);

    // The (column, row) of the center pixel in the pattern is computed
    // Note, that later one we use this as (column, row), therefore we switch
    // already here the .s0 and .s1 assignment
    // (s0 is the first entry, s1 second)
    int2 pattern_pos_cr = (int2)(0, 0);
    pattern_pos_cr.s1 = -top_left_rc.s0 - pos.s0 + pattern_half_h; // row
    pattern_pos_cr.s0 = -top_left_rc.s1 - pos.s1 + pattern_half_w; // column

    // value for the output pixel we are going to compute in this kernel
    float value = 0.0;
    // the distance in the color-space between the image and the pattern
    float dist = 0.0f;
    const float max_dist = sqrt(3.0);

    // Go though all pixel of the pattern image
    for (int r = image_start_r; r < image_end_r; r++) {

        for (int c = 0; c < image_width; c++) {

            pattern_color = read_imagef(pattern, sampler, pattern_pos_cr + (int2)(c, r));

            if(pattern_color.w > 0.0f) {
                // Use the alpha value `.w` from an RGBA image (pattern) as
                // weight and compute the `distance` which is the squared
                // absolute difference
                image_color = read_imagef(image, sampler, (int2)(c, r));
                dist = fast_distance(pattern_color.xyz, image_color.xyz);
                value += (1-pattern_color.w) * max_dist + pattern_color.w * dist;
            } else {
                // Just add a constant that represents the maximal possible
                // difference between image and pattern for a single pixel.
                // E.g. from white (1,1,1) to black (0,0,0).
                value += max_dist;
            }
        }
    }

    output[pos.s0 * get_global_size(1) + pos.s1] = value;
}


Improve mask precision.

Improve mask precision.

__kernel void
downscaledconvolution(
        __write_only image2d_t output_image,
        int output_origin_x,
        int output_origin_y,
        __read_only image2d_t input_image,
        int input_origin_x,
        int input_origin_y)
{
    const float mask[5][5] = {
        3.90625e-03f, 1.56250e-02f, 2.34375e-02f, 1.56250e-02f, 3.90625e-03f,
        1.56250e-02f, 6.25000e-02f, 9.37500e-02f, 6.25000e-02f, 1.56250e-02f,
        2.34375e-02f, 9.37500e-02f, 1.40625e-01f, 9.37500e-02f, 2.34375e-02f,
        1.56250e-02f, 6.25000e-02f, 9.37500e-02f, 6.25000e-02f, 1.56250e-02f,
        3.90625e-03f, 1.56250e-02f, 2.34375e-02f, 1.56250e-02f, 3.90625e-03f,
    };

    const sampler_t sampler =
        CLK_FILTER_NEAREST|CLK_NORMALIZED_COORDS_FALSE|CLK_ADDRESS_CLAMP_TO_EDGE;

    int x_in_output = output_origin_x + get_global_id(0);
    int y_in_output = output_origin_y + get_global_id(1);

    float x_in_input = (float)(input_origin_x + get_global_id(0)*2);
    float y_in_input = (float)(input_origin_y + get_global_id(1)*2);

    float4 c = 0.f;

    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input-3.5f))) * mask[0][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input-3.5f))) * mask[1][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input-3.5f))) * mask[2][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input-3.5f))) * mask[3][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input-3.5f))) * mask[4][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input-1.5f))) * mask[0][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input-1.5f))) * mask[1][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input-1.5f))) * mask[2][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input-1.5f))) * mask[3][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input-1.5f))) * mask[4][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input+0.5f))) * mask[0][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input+0.5f))) * mask[1][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input+0.5f))) * mask[2][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input+0.5f))) * mask[3][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input+0.5f))) * mask[4][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input+2.5f))) * mask[0][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input+2.5f))) * mask[1][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input+2.5f))) * mask[2][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input+2.5f))) * mask[3][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input+2.5f))) * mask[4][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input+4.5f))) * mask[0][4];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input+4.5f))) * mask[1][4];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input+4.5f))) * mask[2][4];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input+4.5f))) * mask[3][4];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input+4.5f))) * mask[4][4];

    barrier(CLK_LOCAL_MEM_FENCE);

    write_imageui(output_image, (int2)(x_in_output, y_in_output), convert_int4(c));
}

__kernel void
downscaledconvolution(
        __write_only image2d_t output_image,
        int output_origin_x,
        int output_origin_y,
        __read_only image2d_t input_image,
        int input_origin_x,
        int input_origin_y)
{
    const float mask[5][5] = {
        0.003906, 0.015625, 0.023438, 0.015625, 0.003906,
        0.015625, 0.062500, 0.093750, 0.062500, 0.015625,
        0.023438, 0.093750, 0.140625, 0.093750, 0.023438,
        0.015625, 0.062500, 0.093750, 0.062500, 0.015625,
        0.003906, 0.015625, 0.023438, 0.015625, 0.003906
    };

    const sampler_t sampler =
        CLK_FILTER_NEAREST|CLK_NORMALIZED_COORDS_FALSE|CLK_ADDRESS_CLAMP_TO_EDGE;

    int x_in_output = output_origin_x + get_global_id(0);
    int y_in_output = output_origin_y + get_global_id(1);

    float x_in_input = (float)(input_origin_x + get_global_id(0)*2);
    float y_in_input = (float)(input_origin_y + get_global_id(1)*2);

    float4 c = 0.f;

    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input-3.5f))) * mask[0][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input-3.5f))) * mask[1][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input-3.5f))) * mask[2][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input-3.5f))) * mask[3][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input-3.5f))) * mask[4][0];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input-1.5f))) * mask[0][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input-1.5f))) * mask[1][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input-1.5f))) * mask[2][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input-1.5f))) * mask[3][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input-1.5f))) * mask[4][1];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input+0.5f))) * mask[0][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input+0.5f))) * mask[1][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input+0.5f))) * mask[2][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input+0.5f))) * mask[3][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input+0.5f))) * mask[4][2];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input+2.5f))) * mask[0][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input+2.5f))) * mask[1][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input+2.5f))) * mask[2][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input+2.5f))) * mask[3][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input+2.5f))) * mask[4][3];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-3.5f, y_in_input+4.5f))) * mask[0][4];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input-1.5f, y_in_input+4.5f))) * mask[1][4];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+0.5f, y_in_input+4.5f))) * mask[2][4];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+2.5f, y_in_input+4.5f))) * mask[3][4];
    c += convert_float4(read_imageui(input_image, sampler, (float2)(x_in_input+4.5f, y_in_input+4.5f))) * mask[4][4];

    barrier(CLK_LOCAL_MEM_FENCE);

    write_imageui(output_image, (int2)(x_in_output, y_in_output), convert_int4(c));
}


remove debugging error from *.cl file

remove debugging error from *.cl file

__kernel void vector_add(__global int *A, __global int *B, __global int *C) {

    // Get the index of the current element
    int i = get_global_id(0);

    // Do the operation
    C[i] = A[i] + B[i];
}

__kernel void vector_add(__global int *A, __global int *B, __global int *C) {

    // Get the index of the current element
    int i = get_global_id(0);

    // Do the operation
    C[i] = A[i] + sin(B[i]);
}


float gives pretty pink?

float gives pretty pink?

__constant sampler_t nearest = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE
	| CLK_FILTER_NEAREST;

__constant sampler_t linear = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE
	| CLK_FILTER_LINEAR;

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

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

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

__constant sampler_t nearest = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE
	| CLK_FILTER_NEAREST;

__constant sampler_t linear = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE
	| CLK_FILTER_LINEAR;

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

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

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