Enabling alpha-blended compounding in vtkCLVolumeReconstruction/kernels.cl

#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable

//#define PRINT
#define PRINT_RES0 3
#define PRINT_RES1 30
#define PRINT_RES2 6000

#define BSCAN_WINDOW 4 // must be >= 4 if PT
#define PT_OR_DW 1 // 0=PT (Probe Trajectory), 1=DW (Distance Weighted)

#define COMPOUND_AVG 0
#define COMPOUND_MAX 1
#define COMPOUND_IFEMPTY 2
#define COMPOUND_OVERWRITE 3
#define COMPOUND_ALPHABLEND 4

#define ALPHA 0.1

#define COMPOUND_METHOD COMPOUND_AVG

#define pixel_pos_c(i,c) (pixel_pos[(i)*3 + (c)])
#define pos_matrix_a(x,y) (pos_matrix[y*4 + x])
#define inrange(x,a,b) ((x) >= (a) && (x) <= (b))
#define volume_a(x,y,z) (volume[(x) + (y)*volume_w + (z)*volume_w*volume_h])

__kernel void round_off_translate(__global float * pixel_pos,
																	float volume_spacing,
																	int mask_size,
																	float origo_x,
																	float origo_y,
																	float origo_z) {
	int n = get_global_id(0);
	if (n >= mask_size) return;

	pixel_pos_c(n,0) = (int)(pixel_pos_c(n,0)/volume_spacing) - origo_x;
	pixel_pos_c(n,1) = (int)(pixel_pos_c(n,1)/volume_spacing) - origo_y;
	pixel_pos_c(n,2) = (int)(pixel_pos_c(n,2)/volume_spacing) - origo_z;
}

__kernel void fill_volume(__global float * pixel_pos,
													__global unsigned char * pixel_ill,
													int mask_size,
													__global unsigned char * volume,
													int volume_n,
													int volume_h,
													int volume_w) {

	int n = get_global_id(0);
	if (n >= mask_size) return;

	int x = pixel_pos_c(n,0);
	int y = pixel_pos_c(n,1);
	int z = pixel_pos_c(n,2);
	if (inrange(x,0,volume_w) && inrange(y,0,volume_h) && inrange(z,0,volume_n))
		volume_a(x,y,z) = pixel_ill[n];
}

__kernel void fill_holes(__global float * pixel_pos,
												 __global char * hole_ill,
												 int mask_size,
												 __global unsigned char * volume,
												 int volume_n,
												 int volume_h,
												 int volume_w) {
	// Assumes no black ultrasound input data

	int n = get_global_id(0);
	if (n >= mask_size) return;

	int x = pixel_pos_c(n,0);
	int y = pixel_pos_c(n,1);
	int z = pixel_pos_c(n,2);

	#define kernel_size 5
	#define half_kernel (kernel_size/2)
	//#define cutoff (kernel_size*kernel_size*kernel_size/3)

	//for (int a = -half_kernel; a <= half_kernel; a++)
		//for (int b = -half_kernel; b <= half_kernel; b++)
			//for (int c = -half_kernel; c <= half_kernel; c++)
	for (int h = 0; h < 5; h++) {
		int a = -(1+h); int b = -(1+h); int c = -(1+h); // TODO: Set to direction of probe trajectory
		//int a = (1+h); int b = (1+h); int c = (1+h); // TODO: Set to direction of probe trajectory
		if (inrange(x+a,0,volume_w) && inrange(y+b,0,volume_h) && inrange(z+c,0,volume_n)) {
			hole_ill[sizeof(unsigned char)*mask_size*h + n] = 0;
			if (volume_a(x+a,y+b,z+c) == 0) {
				int sum = 0;
				int sum_counter = 0;
				for (int i = -half_kernel; i <= half_kernel; i++) {
					for (int j = -half_kernel; j <= half_kernel; j++) {
						for (int k = -half_kernel; k <= half_kernel; k++) {
							if (inrange(x+a+i,0,volume_w) && inrange(y+b+j,0,volume_h) && inrange(z+c+k,0,volume_n)) {
								if (volume_a(x+a+i,y+b+j,z+c+k) != 0) {
									sum += volume_a(x+a+i,y+b+j,z+c+k);
									sum_counter++;
								}
							}
						}
					}
				}
				//if (sum_counter > cutoff) {
					volume_a(x+a,y+b,z+c) = sum/(float)sum_counter;
					hole_ill[sizeof(unsigned char)*mask_size*h + n] = sum/(float)sum_counter;
				//}
			}
		}
	}
}

__kernel void transform(__global float * pixel_pos,
												__global float * pos_matrix, // Access violation when set to __constant
												int mask_size) {

	int n = get_global_id(0);
	if (n >= mask_size) return;

	float sum0, sum1, sum2;
	for (int y = 0; y < 3; y++) {
		float sum = 0;
		for (int x = 0; x < 3; x++)
			sum += pos_matrix_a(x,y)*pixel_pos_c(n,x);
		sum += pos_matrix_a(3,y);
		if (y==0) sum0=sum; else if (y==1) sum1=sum; else sum2=sum;
	}
	pixel_pos_c(n,0) = sum0; pixel_pos_c(n,1) = sum1; pixel_pos_c(n,2) = sum2;
}

//#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable // warning: unknown action for '#pragma OPENCL' - ignored
//#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable // warning: unknown action for '#pragma OPENCL' - ignored

/*__kernel void fill_pixel_ill_pos(__global unsigned char * bscan,
																 __constant unsigned char * mask,
																 __global float * pixel_pos,
																 __global unsigned char * pixel_ill,
																 __constant int mask_size,
																 __constant int bscan_h,
																 __constant int bscan_w,
																 __constant float bscan_spacing_x,
																 __constant float bscan_spacing_y,
																 __global int * global_mask_counter) { // arg not used

	int mask_counter = 0;
	for (int y = 0; y < bscan_h; y++) {
		for (int x = 0; x < bscan_w; x++) {
			char foo = 1 << (y*bscan_w + x)%8;
			char mask_bit = mask[(x + y*bscan_w)/8] & foo;
			if (mask_bit != 0) {
				pixel_ill[mask_counter] = bscan[x + y*bscan_w];
				pixel_pos[mask_counter*3+0] = 0;//atom_inc(global_mask_counter);
				pixel_pos[mask_counter*3+1] = x*bscan_spacing_x;
				pixel_pos[mask_counter*3+2] = y*bscan_spacing_y;
				mask_counter++;
			}
		}
	}
}*/

__kernel void build_ray_dirs(__global unsigned char * volume,
														 int volume_w,
														 int volume_h,
														 int volume_n,
														 __global float4 * ray_dirs,
														 int bitmap_w,
														 int bitmap_h,
														 float4 camera_pos,
														 float4 camera_lookat,
														 __global float * printings) {
	int n = get_global_id(0);
	if (n >= bitmap_w*bitmap_h) return;

	int ray_x = n%bitmap_w;
	int ray_y = n/bitmap_w;

	float4 camera_forward = normalize(camera_lookat - camera_pos);
	float4 temp_up = {0, 1, 0, 0};
	float4 camera_right = normalize(cross(temp_up, camera_forward));
	float4 camera_up = normalize(cross(camera_right, camera_forward));

	float fov_hor = 45/2;
	float fov_ver = fov_hor*bitmap_h/(float)bitmap_w;
	fov_hor = fov_hor/180.0f*3.14f;
	fov_ver = fov_ver/180.0f*3.14f;

	float4 step_forward = camera_forward;
	//float temp = 1/cos(fov_hor);
	//temp *= sin(fov_hor);
	float temp = (ray_x-bitmap_w/2)/(float)(bitmap_w/2);
	float4 step_right = temp * fov_hor * camera_right;
	//temp = 1/cos(fov_ver);
	//temp *= sin(fov_ver);
	temp = (ray_y-bitmap_h/2)/(float)(bitmap_h/2);
	float4 step_up = temp * fov_ver * camera_up;
	float4 ray_dir = normalize(step_forward + step_right + step_up);

	ray_dirs[n] = ray_dir;

	//printings[n*3+0] = ray_dir.x;
	//printings[n*3+1] = ray_dir.y;
	//printings[n*3+2] = ray_dir.z;
}

__kernel void cast_rays(__global unsigned char * volume,
												int volume_w,
												int volume_h,
												int volume_n,
												__global float4 * ray_dirs,
												__global unsigned char * bitmap,
												int bitmap_w,
												int bitmap_h,
												float4 camera_pos,
												float4 camera_lookat,
												__global float * printings) {
	int n = get_global_id(0);
	if (n >= bitmap_w*bitmap_h) return;

	int ray_x = n%bitmap_w;
	int ray_y = n/bitmap_w;

	float4 ray_dir = ray_dirs[n];

	#define step_size 1.0f
	#define transparent_level 54
	#define transparency_ajustment 0.4f
	#define ray_strength_cutoff (255/10.0f)

	unsigned char accum = 0;
	float t = 0;

	float4 volume_0 = {0, 0, 0, 0};
	float4 volume_1 = {volume_w-1, volume_h-1, volume_n-1, 0};

	float4 foo0 = (volume_0 - camera_pos)/ray_dir;
	float4 foo1 = (volume_1 - camera_pos)/ray_dir;
	foo0 = min(foo0, foo1);
	t = max(foo0.x, max(foo0.y, foo0.z)) + 2;

	float4 t_pos = camera_pos + t*ray_dir;

	if (t_pos.x > 0 && t_pos.x < volume_w-1 &&
			t_pos.y > 0 && t_pos.y < volume_h-1 &&
			t_pos.z > 0 && t_pos.z < volume_n-1) {
		float ray_strength = 255;
		unsigned char voxel;
		float transparency;
		while(true) {
			if (t_pos.x < 0 || t_pos.x > volume_w-1 ||
					t_pos.y < 0 || t_pos.y > volume_h-1 ||
					t_pos.z < 0 || t_pos.z > volume_n-1) {
				break;
			}
			if (ray_strength < ray_strength_cutoff) break;

			voxel = volume_a((int)t_pos.x, (int)t_pos.y, (int)t_pos.z);
			if (voxel < transparent_level) voxel = 0;

			transparency = min((1 - voxel/255.0f) + transparency_ajustment, 1.0f);

			accum += ray_strength * (1-transparency);
			ray_strength *= transparency;

			t += step_size;
			t_pos = camera_pos + t*ray_dir;
		}
	} else { // miss
		accum = ((ray_x+ray_y)%2)*150;
	}

	bitmap[n] = accum;

	//printings[n*3+0] = ray_dir.x;
	//printings[n*3+1] = ray_dir.y;
	//printings[n*3+2] = ray_dir.z;
	//printings[n] = t;
}

#define NULL 0
#define distance_pp(v, plane) (plane.x*v.x + plane.y*v.y + plane.z*v.z + plane.w)/sqrt(plane.x*plane.x + plane.y*plane.y + plane.z*plane.z)
#define bscans_queue_a(n, x, y) bscans_queue[(n)*bscan_w*bscan_h + (y)*bscan_w + (x)]

typedef struct {
  float4 corner0;
  float4 cornerx;
  float4 cornery;
} plane_pts;

__kernel void adv_fill_voxels(__global float4 * intersections,
															__global unsigned char * volume,
															float volume_spacing,
															int volume_w,
															int volume_h,
															int volume_n,
															__global float4 * x_vector_queue,
															__global float4 * y_vector_queue,
															__global plane_pts * plane_points_queue,
															__global float4 * bscan_plane_equation_queue,
															float bscan_spacing_x,
															float bscan_spacing_y,
															int bscan_w,
															int bscan_h,
															__global unsigned char * mask,
															__global unsigned char * bscans_queue,
															__global float * bscan_timetags_queue,
															int intersection_counter) {

	int i = get_global_id(0);

	if (i >= intersection_counter) return;

	float4 intrs0 = intersections[i*2 + 0]/volume_spacing;
	float4 intrs1 = intersections[i*2 + 1]/volume_spacing;

	int x0 = min(intrs0.x,intrs1.x);
	int x1 = max(x0+1.0f, max(intrs0.x,intrs1.x));
	int y0 = min(intrs0.y,intrs1.y);
	int y1 = max(y0+1.0f, max(intrs0.y,intrs1.y));
	int z0 = min(intrs0.z,intrs1.z);
	int z1 = max(z0+1.0f, max(intrs0.z,intrs1.z));

	int safety = 0;
	for (int z = z0; z <= z1; z++) {
		for (int y = y0; y <= y1; y++) {
			for (int x = x0; x <= x1; x++) {
				float4 voxel_coord = {x*volume_spacing,y*volume_spacing,z*volume_spacing,0};
				if (inrange(x, 0, volume_w) && inrange(y, 0, volume_h) && inrange(z, 0, volume_n)) {
					float contribution = 0;
					if (PT_OR_DW) { // DW
						float dists[BSCAN_WINDOW];
						unsigned char bilinears[BSCAN_WINDOW];
						bool valid = true;
						float G = 0;
						for (int n = 0; n < BSCAN_WINDOW; n++) {
							int q_idx = n;

							float4 normal = { bscan_plane_equation_queue[q_idx].x, bscan_plane_equation_queue[q_idx].y, bscan_plane_equation_queue[q_idx].z, 0 };

								float dist0 = fabs(distance_pp(voxel_coord, bscan_plane_equation_queue[q_idx]));
							float4 p0 = voxel_coord + -dist0*normal - plane_points_queue[q_idx].corner0;
								float px0 = dot(p0, x_vector_queue[q_idx]) / bscan_spacing_x;
							float py0 = dot(p0, y_vector_queue[q_idx]) / bscan_spacing_y;
							float xa = px0 - floor(px0);
							float ya = py0 - floor(py0);
							int xa0 = (int)px0;
							int ya0 = (int)py0;

							bool valid0 = false;

							if (inrange(xa0, 0, bscan_w) && inrange(ya0, 0, bscan_h) && inrange(xa0 + 1, 0, bscan_w) && inrange(ya0 + 1, 0, bscan_h)) {
								if (mask[xa0 + ya0*bscan_w] != 0 && mask[xa0 + 1 + (ya0 + 1)*bscan_w] != 0 && mask[xa0 + 1 + ya0*bscan_w] != 0 && mask[xa0 + (ya0 + 1)*bscan_w] != 0) {
									bilinears[n] = bscans_queue_a(q_idx, xa0, ya0)*(1 - xa)*(1 - ya) + bscans_queue_a(q_idx, xa0 + 1, ya0)*xa*(1 - ya) + bscans_queue_a(q_idx, xa0, ya0 + 1)*(1 - xa)*ya + bscans_queue_a(q_idx, xa0 + 1, ya0 + 1)*xa*ya;
									valid0 = true;
								}
							}

							valid &= valid0;
							dists[n] = dist0;
							if (dist0 == 0)
								continue;

							G += 1 / dists[n];
							contribution += bilinears[n] / dists[n];
						}

						if (!valid) continue;

						if (G != 0)
							contribution /= G;

					} else { // PT
						// Find virtual plane time stamp:
						float dists[4];
						bool valid = true;
						for (int n = 0; n < 4; n++) {
							int q_idx = BSCAN_WINDOW/2-2+n;

							float4 normal = {bscan_plane_equation_queue[q_idx].x, bscan_plane_equation_queue[q_idx].y, bscan_plane_equation_queue[q_idx].z, 0};

							float dist0 = fabs(distance_pp(voxel_coord, bscan_plane_equation_queue[q_idx]));
							float4 p0 = voxel_coord + -dist0*normal - plane_points_queue[q_idx].corner0;
							float px0 = dot(p0, x_vector_queue[q_idx])/bscan_spacing_x;
							float py0 = dot(p0, y_vector_queue[q_idx])/bscan_spacing_y;
							float xa = px0-floor(px0);
							float ya = py0-floor(py0);
							int xa0 = (int)px0;
							int ya0 = (int)py0;

							bool valid0 = false;
							float bilinear0;

							if (inrange(xa0, 0, bscan_w) && inrange(ya0, 0, bscan_h) && inrange(xa0+1, 0, bscan_w) && inrange(ya0+1, 0, bscan_h))
								if (mask[xa0 + ya0*bscan_w] != 0 && mask[xa0+1 + (ya0+1)*bscan_w] != 0 && mask[xa0+1 + ya0*bscan_w] != 0 && mask[xa0 + (ya0+1)*bscan_w] != 0)
									valid0 = true;

							dists[n] = dist0;

							valid &= valid0;
						}
						if (!valid) continue;
						float G = dists[1] + dists[2];
						float t = dists[2]/G*bscan_timetags_queue[BSCAN_WINDOW/2-1] + dists[1]/G*bscan_timetags_queue[BSCAN_WINDOW/2];

						// Cubic interpolate 4 bscan plane equations, corner0s and x- and y-vectors:
						float4 v_plane_eq = {0,0,0,0};
						float4 v_corner0 = {0,0,0,0};
						float4 v_x_vector = {0,0,0,0};
						float4 v_y_vector = {0,0,0,0};
						for (int k = 0; k < 4; k++) {
							int q_idx = BSCAN_WINDOW/2-2+k;
							float phi = 0;
							float a = -1/2.0f;
							float abs_t = fabs((t-bscan_timetags_queue[q_idx]))/(bscan_timetags_queue[1]-bscan_timetags_queue[0]);
							if (inrange(abs_t, 0, 1))
								phi = (a+2)*abs_t*abs_t*abs_t - (a+3)*abs_t*abs_t + 1;
							else if (inrange(abs_t, 1, 2))
								phi = a*abs_t*abs_t*abs_t - 5*a*abs_t*abs_t + 8*a*abs_t - 4*a;
							v_plane_eq += bscan_plane_equation_queue[q_idx]*phi;
							v_corner0 += phi*plane_points_queue[q_idx].corner0;
							v_x_vector += phi*x_vector_queue[q_idx];
							v_y_vector += phi*y_vector_queue[q_idx];
						}

						// Find 2D coordinates on virtual plane:
						float4 p0 = voxel_coord - v_corner0;
						float px0 = dot(p0, v_x_vector)/bscan_spacing_x;
						float py0 = dot(p0, v_y_vector)/bscan_spacing_y;
						float xa = px0-floor(px0);
						float ya = py0-floor(py0);
						int xa0 = (int)px0;
						int ya0 = (int)py0;

						// Distance weight 4 bilinears:
						float F = 0;
						for (int n = 0; n < 4; n++) {
							int q_idx = BSCAN_WINDOW/2-2+n;
							float bilinear0 = bscans_queue_a(q_idx,xa0,ya0)*(1-xa)*(1-ya) + bscans_queue_a(q_idx,xa0+1,ya0)*xa*(1-ya) + bscans_queue_a(q_idx,xa0,ya0+1)*(1-xa)*ya + bscans_queue_a(q_idx,xa0+1,ya0+1)*xa*ya;
							F += 1/dists[n];
							contribution += bilinear0/dists[n];
						}
						contribution /= F;
					}

					if (COMPOUND_METHOD == COMPOUND_AVG)
						if (volume_a(x,y,z) != 0) volume_a(x,y,z) = (volume_a(x,y,z) + contribution)/2;	else volume_a(x,y,z) = contribution;
					if (COMPOUND_METHOD == COMPOUND_MAX)
						if (contribution > volume_a(x,y,z)) volume_a(x,y,z) = contribution;
					if (COMPOUND_METHOD == COMPOUND_IFEMPTY)
						if (volume_a(x,y,z) == 0) volume_a(x,y,z) = contribution;
					if (COMPOUND_METHOD == COMPOUND_OVERWRITE)
						volume_a(x,y,z) = contribution;
					if (COMPOUND_METHOD == COMPOUND_ALPHABLEND)
						if (volume_a(x, y, z) != 0) volume_a(x, y, z) = (1-ALPHA)*volume_a(x, y, z) + ALPHA*contribution;	else volume_a(x, y, z) = contribution;
				}

			}
		}
	}
}

__kernel void trace_intersections(__global float4 * intersections,
																	int volume_w,
																	int volume_h,
																	int volume_n,
																	float volume_spacing,
																	__global float4 * bscan_plane_equation_queue,
																	int axis) {

	float4 Rd = {axis == 0, axis == 1, axis == 2, 0};

	int iter_end[3] = {(axis != 0)*volume_w+(axis==0), (axis != 1)*volume_h+(axis==1), (axis != 2)*volume_n+(axis==2)};

	int n = get_global_id(0);

	if (n >= iter_end[0]*iter_end[1]*iter_end[2]) return;

	int x = (axis != 0);
	int y = (axis != 1);
	int z = (axis != 2);

	if (axis == 0) {
		y = n%volume_h;
		z = n/volume_h;
	}
	if (axis == 1) {
		x = n%volume_w;
		z = n/volume_w;
	}
	if (axis == 2) {
		x = n%volume_w;
		y = n/volume_w;
	}

	bool invalid = false;
	for(int f = 0; f < 2; f++) {
		int i = f==0 ? BSCAN_WINDOW/2-1 : BSCAN_WINDOW/2; // Fill voxels between two middle bscans
		//int i = f==0 ? BSCAN_WINDOW/2-BSCAN_WINDOW/4-1 : BSCAN_WINDOW/2+BSCAN_WINDOW/4; // Alternatively fill voxels between BSCAN_WINDOW/2 middle bscans
		//int i = f==0 ? 0 : BSCAN_WINDOW-1; // Alternatively fill voxels between first and last bscan
		float4 Pn = {bscan_plane_equation_queue[i].x, bscan_plane_equation_queue[i].y, bscan_plane_equation_queue[i].z, 0};
		float4 R0 = {x*volume_spacing, y*volume_spacing, z*volume_spacing, 0};
		float Vd = dot(Pn, Rd);
		float V0 = -(dot(Pn, R0) + bscan_plane_equation_queue[i].w);
		if (Vd == 0)
		{
			invalid = true;
			continue;
		}
		float t = V0 / Vd;

		float4 intersection = R0 + t*Rd;
		intersections[n*2 + f] = intersection;
	}
}

#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable

//#define PRINT
#define PRINT_RES0 3
#define PRINT_RES1 30
#define PRINT_RES2 6000

#define BSCAN_WINDOW 4 // must be >= 4 if PT
#define PT_OR_DW 1 // 0=PT (Probe Trajectory), 1=DW (Distance Weighted)

#define COMPOUND_AVG 0
#define COMPOUND_MAX 1
#define COMPOUND_IFEMPTY 2
#define COMPOUND_OVERWRITE 3

#define COMPOUND_METHOD COMPOUND_AVG

#define pixel_pos_c(i,c) (pixel_pos[(i)*3 + (c)])
#define pos_matrix_a(x,y) (pos_matrix[y*4 + x])
#define inrange(x,a,b) ((x) >= (a) && (x) <= (b))
#define volume_a(x,y,z) (volume[(x) + (y)*volume_w + (z)*volume_w*volume_h])

__kernel void round_off_translate(__global float * pixel_pos,
																	float volume_spacing,
																	int mask_size,
																	float origo_x,
																	float origo_y,
																	float origo_z) {
	int n = get_global_id(0);
	if (n >= mask_size) return;

	pixel_pos_c(n,0) = (int)(pixel_pos_c(n,0)/volume_spacing) - origo_x;
	pixel_pos_c(n,1) = (int)(pixel_pos_c(n,1)/volume_spacing) - origo_y;
	pixel_pos_c(n,2) = (int)(pixel_pos_c(n,2)/volume_spacing) - origo_z;
}

__kernel void fill_volume(__global float * pixel_pos,
													__global unsigned char * pixel_ill,
													int mask_size,
													__global unsigned char * volume,
													int volume_n,
													int volume_h,
													int volume_w) {

	int n = get_global_id(0);
	if (n >= mask_size) return;

	int x = pixel_pos_c(n,0);
	int y = pixel_pos_c(n,1);
	int z = pixel_pos_c(n,2);
	if (inrange(x,0,volume_w) && inrange(y,0,volume_h) && inrange(z,0,volume_n))
		volume_a(x,y,z) = pixel_ill[n];
}

__kernel void fill_holes(__global float * pixel_pos,
												 __global char * hole_ill,
												 int mask_size,
												 __global unsigned char * volume,
												 int volume_n,
												 int volume_h,
												 int volume_w) {
	// Assumes no black ultrasound input data

	int n = get_global_id(0);
	if (n >= mask_size) return;

	int x = pixel_pos_c(n,0);
	int y = pixel_pos_c(n,1);
	int z = pixel_pos_c(n,2);

	#define kernel_size 5
	#define half_kernel (kernel_size/2)
	//#define cutoff (kernel_size*kernel_size*kernel_size/3)

	//for (int a = -half_kernel; a <= half_kernel; a++)
		//for (int b = -half_kernel; b <= half_kernel; b++)
			//for (int c = -half_kernel; c <= half_kernel; c++)
	for (int h = 0; h < 5; h++) {
		int a = -(1+h); int b = -(1+h); int c = -(1+h); // TODO: Set to direction of probe trajectory
		//int a = (1+h); int b = (1+h); int c = (1+h); // TODO: Set to direction of probe trajectory
		if (inrange(x+a,0,volume_w) && inrange(y+b,0,volume_h) && inrange(z+c,0,volume_n)) {
			hole_ill[sizeof(unsigned char)*mask_size*h + n] = 0;
			if (volume_a(x+a,y+b,z+c) == 0) {
				int sum = 0;
				int sum_counter = 0;
				for (int i = -half_kernel; i <= half_kernel; i++) {
					for (int j = -half_kernel; j <= half_kernel; j++) {
						for (int k = -half_kernel; k <= half_kernel; k++) {
							if (inrange(x+a+i,0,volume_w) && inrange(y+b+j,0,volume_h) && inrange(z+c+k,0,volume_n)) {
								if (volume_a(x+a+i,y+b+j,z+c+k) != 0) {
									sum += volume_a(x+a+i,y+b+j,z+c+k);
									sum_counter++;
								}
							}
						}
					}
				}
				//if (sum_counter > cutoff) {
					volume_a(x+a,y+b,z+c) = sum/(float)sum_counter;
					hole_ill[sizeof(unsigned char)*mask_size*h + n] = sum/(float)sum_counter;
				//}
			}
		}
	}
}

__kernel void transform(__global float * pixel_pos,
												__global float * pos_matrix, // Access violation when set to __constant
												int mask_size) {

	int n = get_global_id(0);
	if (n >= mask_size) return;

	float sum0, sum1, sum2;
	for (int y = 0; y < 3; y++) {
		float sum = 0;
		for (int x = 0; x < 3; x++)
			sum += pos_matrix_a(x,y)*pixel_pos_c(n,x);
		sum += pos_matrix_a(3,y);
		if (y==0) sum0=sum; else if (y==1) sum1=sum; else sum2=sum;
	}
	pixel_pos_c(n,0) = sum0; pixel_pos_c(n,1) = sum1; pixel_pos_c(n,2) = sum2;
}

//#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable // warning: unknown action for '#pragma OPENCL' - ignored
//#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable // warning: unknown action for '#pragma OPENCL' - ignored

/*__kernel void fill_pixel_ill_pos(__global unsigned char * bscan,
																 __constant unsigned char * mask,
																 __global float * pixel_pos,
																 __global unsigned char * pixel_ill,
																 __constant int mask_size,
																 __constant int bscan_h,
																 __constant int bscan_w,
																 __constant float bscan_spacing_x,
																 __constant float bscan_spacing_y,
																 __global int * global_mask_counter) { // arg not used

	int mask_counter = 0;
	for (int y = 0; y < bscan_h; y++) {
		for (int x = 0; x < bscan_w; x++) {
			char foo = 1 << (y*bscan_w + x)%8;
			char mask_bit = mask[(x + y*bscan_w)/8] & foo;
			if (mask_bit != 0) {
				pixel_ill[mask_counter] = bscan[x + y*bscan_w];
				pixel_pos[mask_counter*3+0] = 0;//atom_inc(global_mask_counter);
				pixel_pos[mask_counter*3+1] = x*bscan_spacing_x;
				pixel_pos[mask_counter*3+2] = y*bscan_spacing_y;
				mask_counter++;
			}
		}
	}
}*/

__kernel void build_ray_dirs(__global unsigned char * volume,
														 int volume_w,
														 int volume_h,
														 int volume_n,
														 __global float4 * ray_dirs,
														 int bitmap_w,
														 int bitmap_h,
														 float4 camera_pos,
														 float4 camera_lookat,
														 __global float * printings) {
	int n = get_global_id(0);
	if (n >= bitmap_w*bitmap_h) return;

	int ray_x = n%bitmap_w;
	int ray_y = n/bitmap_w;

	float4 camera_forward = normalize(camera_lookat - camera_pos);
	float4 temp_up = {0, 1, 0, 0};
	float4 camera_right = normalize(cross(temp_up, camera_forward));
	float4 camera_up = normalize(cross(camera_right, camera_forward));

	float fov_hor = 45/2;
	float fov_ver = fov_hor*bitmap_h/(float)bitmap_w;
	fov_hor = fov_hor/180.0f*3.14f;
	fov_ver = fov_ver/180.0f*3.14f;

	float4 step_forward = camera_forward;
	//float temp = 1/cos(fov_hor);
	//temp *= sin(fov_hor);
	float temp = (ray_x-bitmap_w/2)/(float)(bitmap_w/2);
	float4 step_right = temp * fov_hor * camera_right;
	//temp = 1/cos(fov_ver);
	//temp *= sin(fov_ver);
	temp = (ray_y-bitmap_h/2)/(float)(bitmap_h/2);
	float4 step_up = temp * fov_ver * camera_up;
	float4 ray_dir = normalize(step_forward + step_right + step_up);

	ray_dirs[n] = ray_dir;

	//printings[n*3+0] = ray_dir.x;
	//printings[n*3+1] = ray_dir.y;
	//printings[n*3+2] = ray_dir.z;
}

__kernel void cast_rays(__global unsigned char * volume,
												int volume_w,
												int volume_h,
												int volume_n,
												__global float4 * ray_dirs,
												__global unsigned char * bitmap,
												int bitmap_w,
												int bitmap_h,
												float4 camera_pos,
												float4 camera_lookat,
												__global float * printings) {
	int n = get_global_id(0);
	if (n >= bitmap_w*bitmap_h) return;

	int ray_x = n%bitmap_w;
	int ray_y = n/bitmap_w;

	float4 ray_dir = ray_dirs[n];

	#define step_size 1.0f
	#define transparent_level 54
	#define transparency_ajustment 0.4f
	#define ray_strength_cutoff (255/10.0f)

	unsigned char accum = 0;
	float t = 0;

	float4 volume_0 = {0, 0, 0, 0};
	float4 volume_1 = {volume_w-1, volume_h-1, volume_n-1, 0};

	float4 foo0 = (volume_0 - camera_pos)/ray_dir;
	float4 foo1 = (volume_1 - camera_pos)/ray_dir;
	foo0 = min(foo0, foo1);
	t = max(foo0.x, max(foo0.y, foo0.z)) + 2;

	float4 t_pos = camera_pos + t*ray_dir;

	if (t_pos.x > 0 && t_pos.x < volume_w-1 &&
			t_pos.y > 0 && t_pos.y < volume_h-1 &&
			t_pos.z > 0 && t_pos.z < volume_n-1) {
		float ray_strength = 255;
		unsigned char voxel;
		float transparency;
		while(true) {
			if (t_pos.x < 0 || t_pos.x > volume_w-1 ||
					t_pos.y < 0 || t_pos.y > volume_h-1 ||
					t_pos.z < 0 || t_pos.z > volume_n-1) {
				break;
			}
			if (ray_strength < ray_strength_cutoff) break;

			voxel = volume_a((int)t_pos.x, (int)t_pos.y, (int)t_pos.z);
			if (voxel < transparent_level) voxel = 0;

			transparency = min((1 - voxel/255.0f) + transparency_ajustment, 1.0f);

			accum += ray_strength * (1-transparency);
			ray_strength *= transparency;

			t += step_size;
			t_pos = camera_pos + t*ray_dir;
		}
	} else { // miss
		accum = ((ray_x+ray_y)%2)*150;
	}

	bitmap[n] = accum;

	//printings[n*3+0] = ray_dir.x;
	//printings[n*3+1] = ray_dir.y;
	//printings[n*3+2] = ray_dir.z;
	//printings[n] = t;
}

#define NULL 0
#define distance_pp(v, plane) (plane.x*v.x + plane.y*v.y + plane.z*v.z + plane.w)/sqrt(plane.x*plane.x + plane.y*plane.y + plane.z*plane.z)
#define bscans_queue_a(n, x, y) bscans_queue[(n)*bscan_w*bscan_h + (y)*bscan_w + (x)]

typedef struct {
  float4 corner0;
  float4 cornerx;
  float4 cornery;
} plane_pts;

__kernel void adv_fill_voxels(__global float4 * intersections,
															__global unsigned char * volume,
															float volume_spacing,
															int volume_w,
															int volume_h,
															int volume_n,
															__global float4 * x_vector_queue,
															__global float4 * y_vector_queue,
															__global plane_pts * plane_points_queue,
															__global float4 * bscan_plane_equation_queue,
															float bscan_spacing_x,
															float bscan_spacing_y,
															int bscan_w,
															int bscan_h,
															__global unsigned char * mask,
															__global unsigned char * bscans_queue,
															__global float * bscan_timetags_queue,
															int intersection_counter) {

	int i = get_global_id(0);

	if (i >= intersection_counter) return;

	float4 intrs0 = intersections[i*2 + 0]/volume_spacing;
	float4 intrs1 = intersections[i*2 + 1]/volume_spacing;

	int x0 = min(intrs0.x,intrs1.x);
	int x1 = max(x0+1.0f, max(intrs0.x,intrs1.x));
	int y0 = min(intrs0.y,intrs1.y);
	int y1 = max(y0+1.0f, max(intrs0.y,intrs1.y));
	int z0 = min(intrs0.z,intrs1.z);
	int z1 = max(z0+1.0f, max(intrs0.z,intrs1.z));

	int safety = 0;
	for (int z = z0; z <= z1; z++) {
		for (int y = y0; y <= y1; y++) {
			for (int x = x0; x <= x1; x++) {
				float4 voxel_coord = {x*volume_spacing,y*volume_spacing,z*volume_spacing,0};
				if (inrange(x, 0, volume_w) && inrange(y, 0, volume_h) && inrange(z, 0, volume_n)) {
					float contribution = 0;
					if (PT_OR_DW) { // DW
						float dists[BSCAN_WINDOW];
						unsigned char bilinears[BSCAN_WINDOW];
						bool valid = true;
						float G = 0;
						for (int n = 0; n < BSCAN_WINDOW; n++) {
							int q_idx = n;

							float4 normal = { bscan_plane_equation_queue[q_idx].x, bscan_plane_equation_queue[q_idx].y, bscan_plane_equation_queue[q_idx].z, 0 };

								float dist0 = fabs(distance_pp(voxel_coord, bscan_plane_equation_queue[q_idx]));
							float4 p0 = voxel_coord + -dist0*normal - plane_points_queue[q_idx].corner0;
								float px0 = dot(p0, x_vector_queue[q_idx]) / bscan_spacing_x;
							float py0 = dot(p0, y_vector_queue[q_idx]) / bscan_spacing_y;
							float xa = px0 - floor(px0);
							float ya = py0 - floor(py0);
							int xa0 = (int)px0;
							int ya0 = (int)py0;

							bool valid0 = false;

							if (inrange(xa0, 0, bscan_w) && inrange(ya0, 0, bscan_h) && inrange(xa0 + 1, 0, bscan_w) && inrange(ya0 + 1, 0, bscan_h)) {
								if (mask[xa0 + ya0*bscan_w] != 0 && mask[xa0 + 1 + (ya0 + 1)*bscan_w] != 0 && mask[xa0 + 1 + ya0*bscan_w] != 0 && mask[xa0 + (ya0 + 1)*bscan_w] != 0) {
									bilinears[n] = bscans_queue_a(q_idx, xa0, ya0)*(1 - xa)*(1 - ya) + bscans_queue_a(q_idx, xa0 + 1, ya0)*xa*(1 - ya) + bscans_queue_a(q_idx, xa0, ya0 + 1)*(1 - xa)*ya + bscans_queue_a(q_idx, xa0 + 1, ya0 + 1)*xa*ya;
									valid0 = true;
								}
							}

							valid &= valid0;
							dists[n] = dist0;
							if (dist0 == 0)
								continue;

							G += 1 / dists[n];
							contribution += bilinears[n] / dists[n];
						}

						if (!valid) continue;

						if (G != 0)
							contribution /= G;

					} else { // PT
						// Find virtual plane time stamp:
						float dists[4];
						bool valid = true;
						for (int n = 0; n < 4; n++) {
							int q_idx = BSCAN_WINDOW/2-2+n;

							float4 normal = {bscan_plane_equation_queue[q_idx].x, bscan_plane_equation_queue[q_idx].y, bscan_plane_equation_queue[q_idx].z, 0};

							float dist0 = fabs(distance_pp(voxel_coord, bscan_plane_equation_queue[q_idx]));
							float4 p0 = voxel_coord + -dist0*normal - plane_points_queue[q_idx].corner0;
							float px0 = dot(p0, x_vector_queue[q_idx])/bscan_spacing_x;
							float py0 = dot(p0, y_vector_queue[q_idx])/bscan_spacing_y;
							float xa = px0-floor(px0);
							float ya = py0-floor(py0);
							int xa0 = (int)px0;
							int ya0 = (int)py0;

							bool valid0 = false;
							float bilinear0;

							if (inrange(xa0, 0, bscan_w) && inrange(ya0, 0, bscan_h) && inrange(xa0+1, 0, bscan_w) && inrange(ya0+1, 0, bscan_h))
								if (mask[xa0 + ya0*bscan_w] != 0 && mask[xa0+1 + (ya0+1)*bscan_w] != 0 && mask[xa0+1 + ya0*bscan_w] != 0 && mask[xa0 + (ya0+1)*bscan_w] != 0)
									valid0 = true;

							dists[n] = dist0;

							valid &= valid0;
						}
						if (!valid) continue;
						float G = dists[1] + dists[2];
						float t = dists[2]/G*bscan_timetags_queue[BSCAN_WINDOW/2-1] + dists[1]/G*bscan_timetags_queue[BSCAN_WINDOW/2];

						// Cubic interpolate 4 bscan plane equations, corner0s and x- and y-vectors:
						float4 v_plane_eq = {0,0,0,0};
						float4 v_corner0 = {0,0,0,0};
						float4 v_x_vector = {0,0,0,0};
						float4 v_y_vector = {0,0,0,0};
						for (int k = 0; k < 4; k++) {
							int q_idx = BSCAN_WINDOW/2-2+k;
							float phi = 0;
							float a = -1/2.0f;
							float abs_t = fabs((t-bscan_timetags_queue[q_idx]))/(bscan_timetags_queue[1]-bscan_timetags_queue[0]);
							if (inrange(abs_t, 0, 1))
								phi = (a+2)*abs_t*abs_t*abs_t - (a+3)*abs_t*abs_t + 1;
							else if (inrange(abs_t, 1, 2))
								phi = a*abs_t*abs_t*abs_t - 5*a*abs_t*abs_t + 8*a*abs_t - 4*a;
							v_plane_eq += bscan_plane_equation_queue[q_idx]*phi;
							v_corner0 += phi*plane_points_queue[q_idx].corner0;
							v_x_vector += phi*x_vector_queue[q_idx];
							v_y_vector += phi*y_vector_queue[q_idx];
						}

						// Find 2D coordinates on virtual plane:
						float4 p0 = voxel_coord - v_corner0;
						float px0 = dot(p0, v_x_vector)/bscan_spacing_x;
						float py0 = dot(p0, v_y_vector)/bscan_spacing_y;
						float xa = px0-floor(px0);
						float ya = py0-floor(py0);
						int xa0 = (int)px0;
						int ya0 = (int)py0;

						// Distance weight 4 bilinears:
						float F = 0;
						for (int n = 0; n < 4; n++) {
							int q_idx = BSCAN_WINDOW/2-2+n;
							float bilinear0 = bscans_queue_a(q_idx,xa0,ya0)*(1-xa)*(1-ya) + bscans_queue_a(q_idx,xa0+1,ya0)*xa*(1-ya) + bscans_queue_a(q_idx,xa0,ya0+1)*(1-xa)*ya + bscans_queue_a(q_idx,xa0+1,ya0+1)*xa*ya;
							F += 1/dists[n];
							contribution += bilinear0/dists[n];
						}
						contribution /= F;
					}

					if (COMPOUND_METHOD == COMPOUND_AVG)
						if (volume_a(x,y,z) != 0) volume_a(x,y,z) = (volume_a(x,y,z) + contribution)/2;	else volume_a(x,y,z) = contribution;
					if (COMPOUND_METHOD == COMPOUND_MAX)
						if (contribution > volume_a(x,y,z)) volume_a(x,y,z) = contribution;
					if (COMPOUND_METHOD == COMPOUND_IFEMPTY)
						if (volume_a(x,y,z) == 0) volume_a(x,y,z) = contribution;
					if (COMPOUND_METHOD == COMPOUND_OVERWRITE)
						volume_a(x,y,z) = contribution;
				}

			}
		}
	}
}

__kernel void trace_intersections(__global float4 * intersections,
																	int volume_w,
																	int volume_h,
																	int volume_n,
																	float volume_spacing,
																	__global float4 * bscan_plane_equation_queue,
																	int axis) {

	float4 Rd = {axis == 0, axis == 1, axis == 2, 0};

	int iter_end[3] = {(axis != 0)*volume_w+(axis==0), (axis != 1)*volume_h+(axis==1), (axis != 2)*volume_n+(axis==2)};

	int n = get_global_id(0);

	if (n >= iter_end[0]*iter_end[1]*iter_end[2]) return;

	int x = (axis != 0);
	int y = (axis != 1);
	int z = (axis != 2);

	if (axis == 0) {
		y = n%volume_h;
		z = n/volume_h;
	}
	if (axis == 1) {
		x = n%volume_w;
		z = n/volume_w;
	}
	if (axis == 2) {
		x = n%volume_w;
		y = n/volume_w;
	}

	bool invalid = false;
	for(int f = 0; f < 2; f++) {
		int i = f==0 ? BSCAN_WINDOW/2-1 : BSCAN_WINDOW/2; // Fill voxels between two middle bscans
		//int i = f==0 ? BSCAN_WINDOW/2-BSCAN_WINDOW/4-1 : BSCAN_WINDOW/2+BSCAN_WINDOW/4; // Alternatively fill voxels between BSCAN_WINDOW/2 middle bscans
		//int i = f==0 ? 0 : BSCAN_WINDOW-1; // Alternatively fill voxels between first and last bscan
		float4 Pn = {bscan_plane_equation_queue[i].x, bscan_plane_equation_queue[i].y, bscan_plane_equation_queue[i].z, 0};
		float4 R0 = {x*volume_spacing, y*volume_spacing, z*volume_spacing, 0};
		float Vd = dot(Pn, Rd);
		float V0 = -(dot(Pn, R0) + bscan_plane_equation_queue[i].w);
		if (Vd == 0)
		{
			invalid = true;
			continue;
		}
		float t = V0 / Vd;

		float4 intersection = R0 + t*Rd;
		intersections[n*2 + f] = intersection;
	}
}


Delete prngcl_ranmar.cl

Delete prngcl_ranmar.cl

/******************************************************************************
 * @file     prngcl_ranmar.cl
 * @author   Vadim Demchik <vadimdi@yahoo.com>
 * @version  1.0
 *
 * @brief    [PRNGCL library]
 *           contains OpenCL implementation of RANMAR pseudo-random number generator
 *
 *
 * @section  CREDITS
 *
 *   George Marsaglia, Arif Zaman and Wai Wan Tsang,
 *   "Toward a universal random number generator",
 *   Statistics & Probability Letters, 9 (1990), 35--39.
 *
 *   F. James,
 *   "A review of pseudorandom number generators",
 *   Computer Physics Communications, 60 (1990), 329--344.
 *
 *
 * @section  LICENSE
 *
 * Copyright (c) 2013, Vadim Demchik
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *
 *    Redistributions 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.
 *
 * 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 COPYRIGHT HOLDER 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.
 *
 *****************************************************************************/

#ifndef PRNGCL_RANMAR_CL
#define PRNGCL_RANMAR_CL

#include "prngcl_common.cl"

#define RM_min    (1.0/16777216.0)
#define RM_max    (16777215.0/16777216.0)
#define RM_k      (5.9604644775390625E-8) // 1/2^24

#define RM_CD (7654321.0f / 16777216.0f)
#define RM_CM (16777213.0f /16777216.0f)

//________________________________________________________________________________________________________ RANMAR PRNG
__kernel void
ranmar_init(const __global uint4 * seeds, __global float4 * seedtable)
{
    float4 seed;
    //
    uint4 RM_seed1 = seeds[GID];
    uint4 RM_seed2 = seeds[GID + GID_SIZE];
    //
    uint4 i = ((RM_seed1 / 177) % 177) + 2;
    uint4 j = (RM_seed1 % 177) + 2;
    uint4 k = ((RM_seed2 / 169) % 178) + 1;
    uint4 l = (RM_seed2 % 169);
    for (int n = 0; n < 97; n++)
    {
        uint4 s = (uint4) 0;
        uint  t = 8388608;
        for (int m = 0; m < 24;  m++)
        {
            uint4 u = (i * j) % 179;
            u = (u * k) % 179;
            i = j;
            j = k;
            k = u;
            l = (53 * l + 1) % 169;
            uint4 lus = (l * u) % 64;

            if ( lus.x >= 32) s.x += t;
            if ( lus.y >= 32) s.y += t;
            if ( lus.z >= 32) s.z += t;
            if ( lus.w >= 32) s.w += t;
            t = t >> 1;
        }
        seed.x = ((float) s.x);
        seed.y = ((float) s.y);
        seed.z = ((float) s.z);
        seed.w = ((float) s.w);
        seedtable[GID + GID_SIZE * n] = seed / ((float4) 16777216.0f);
	}
    Uint_and_Float indx_I97, indx_J97;
    indx_I97.uint_value = 96;
    indx_J97.uint_value = 32;
    float4 indx;
    indx.x = indx_I97.float_value;
    indx.y = indx_J97.float_value;
    indx.z = (362436.0f / 16777216.0f);
    indx.w = 0.0f;

    seedtable[GID + GID_SIZE * 97] = indx;   // (RM_I97,RM_J97,RM_C,0)
}

__attribute__((always_inline)) float4
rm_step(__global float4 * seedtable,uint* RM_I97,uint* RM_J97,float* uniz)
{
        float4 uni;
        uni = seedtable[GID + GID_SIZE * (*RM_I97)] - seedtable[GID + GID_SIZE * (*RM_J97)];
	    uni = select(uni, (uni + 1.0f), uni < (float4) 0.0f);
        seedtable[GID + GID_SIZE * (*RM_I97)] = uni;

	    if ((*RM_I97) == 0) (*RM_I97) = 97;
	    if ((*RM_J97) == 0) (*RM_J97) = 97;
	    (*RM_I97)--;
	    (*RM_J97)--;

        (*uniz) -= RM_CD;
	    if ((*uniz) < 0.0) {(*uniz) += RM_CM;}
        uni -= (*uniz);
	    uni = select(uni, (uni + 1.0f), uni < (float4) 0.0f);
        return uni;
}

#ifdef PRECISION_DOUBLE  // if double precision is defined
__attribute__((always_inline)) hgpu_double4
rm_step_double(__global float4 * seedtable,uint* RM_I97,uint* RM_J97,float* uniz)
{
    hgpu_double4 rnd_double;
    float4 rnd1, rnd2;
    bool flag = true;
    while (flag) {
        rnd1 = rm_step(seedtable,RM_I97,RM_J97,uniz);
        if ((rnd1.x>RM_min) && (rnd1.x<RM_max) &&
            (rnd1.y>RM_min) && (rnd1.y<RM_max) &&
            (rnd1.z>RM_min) && (rnd1.z<RM_max) &&
            (rnd1.w>RM_min) && (rnd1.w<RM_max)) {
            rnd2 = rm_step(seedtable,RM_I97,RM_J97,uniz);
            rnd_double = hgpu_float4_to_double4(rnd1,rnd2,RM_min,RM_max,RM_k);
            flag = false;
        }
    }
    return rnd_double;
}
#endif

__kernel void
ranmar(__global float4 * seedtable,__global hgpu_float4 * prns, const uint samples)
{
    uint giddst = GID;
    float4 uni = (float4) 0.0;
    Uint_and_Float indx_I97, indx_J97;
    float4 indx = seedtable[GID + GID_SIZE * 97];
    indx_I97.float_value = indx.x;
    indx_J97.float_value = indx.y;
    uint RM_I97 = indx_I97.uint_value;
    uint RM_J97 = indx_J97.uint_value;
    float uniz = indx.z;
    for (uint i=0; i<samples; i++) {
#ifdef PRECISION_DOUBLE // if double precision is defined
        hgpu_double4 result = rm_step_double(seedtable,&RM_I97,&RM_J97,&uniz);
        prns[giddst] = result;
#else
        uni = rm_step(seedtable,&RM_I97,&RM_J97,&uniz);
        prns[giddst] = uni;
#endif
        giddst += GID_SIZE;
    }

    indx_I97.uint_value = RM_I97;
    indx_J97.uint_value = RM_J97;
    indx.z = uniz;
    indx.x = indx_I97.float_value;
    indx.y = indx_J97.float_value;
    seedtable[GID + GID_SIZE * 97] = indx;
}

#endif


Add some shared load/store functions that take a pitch into account.

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

typedef unsigned char uc;
typedef signed char sc;

__inline signed char vp8_filter_mask(sc, sc, uchar8);
__inline signed char vp8_simple_filter_mask(signed char, signed char, uc, uc, uc, uc);
__inline uchar vp8_hevmask(signed char, uchar4);

__inline uchar8 vp8_mbfilter(signed char mask, uchar hev, uchar8);

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

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

#ifndef __CL_VERSION_1_0__
#define __CL_VERSION_1_0__ 100
#endif

#if __OPENCL_VERSION__ == __CL_VERSION_1_0__
#define clamp(x,y,z) vp8_char_clamp(x)
char vp8_char_clamp(int in){
    return max(min(in, 127), -128);
}
#endif

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

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

//OpenCL built-in functions (
size_t get_global_id(unsigned int);
size_t get_global_size(unsigned int);

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

    char vp8_filter;
    char2 Filter;
    char4 u;

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

    /* inner taps */
    vp8_filter = clamp(vp8_filter + 3 * (pq.s2 - pq.s1), -128, 127);
    vp8_filter &= mask;

    /* save bottom 3 bits so that we round one side +4 and the other +3
     * if it equals 4 we'll set to adjust by -1 to account for the fact
     * we'd round 3 the other way
     */
    Filter = add_sat((char2)vp8_filter, (char2){4,3});
    Filter.s0 >>= 3;
    Filter.s1 >>= 3;

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

    u.s0 = add_sat(pq.s0, vp8_filter);
    u.s1 = add_sat(pq.s1, Filter.s1);
    u.s2 = sub_sat(pq.s2, Filter.s0);
    u.s3 = sub_sat(pq.s3, vp8_filter);

    return as_uchar4(u ^ (char4)0x80);

}

__inline uchar8 load8(global unsigned char *s_base, int s_off, int p){
        uchar8 data;
        data.s0 = s_base[s_off-4*p];
        data.s1 = s_base[s_off-3*p];
        data.s2 = s_base[s_off-2*p];
        data.s3 = s_base[s_off-p];
        data.s4 = s_base[s_off];
        data.s5 = s_base[s_off+p];
        data.s6 = s_base[s_off+2*p];
        data.s7 = s_base[s_off+3*p];
        return data;
}

__inline void save4(global unsigned char *s_base, int s_off, int p, uchar8 data){
        s_base[s_off - 2*p] = data.s2;
        s_base[s_off - p  ] = data.s3;
        s_base[s_off      ] = data.s4;
        s_base[s_off + p  ] = data.s5;
}

__inline void save6(global unsigned char *s_base, int s_off, int p, uchar8 data){
    s_base[s_off - 3*p] = data.s1;
    s_base[s_off - 2*p] = data.s2;
    s_base[s_off - p  ] = data.s3;
    s_base[s_off      ] = data.s4;
    s_base[s_off + p  ] = data.s5;
    s_base[s_off + 2*p  ] = data.s6;
}

__inline void save8(global unsigned char *s_base, int s_off, int p, uchar8 data){
        s_base[s_off - 4*p] = data.s0;
        s_base[s_off - 3*p] = data.s1;
        s_base[s_off - 2*p] = data.s2;
        s_base[s_off - p  ] = data.s3;
        s_base[s_off      ] = data.s4;
        s_base[s_off + p  ] = data.s5;
        s_base[s_off + 2*p  ] = data.s6;
        s_base[s_off + 3*p  ] = data.s7;
}

// Filters horizontal edges of inner blocks in a Macroblock
__inline void vp8_loop_filter_horizontal_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int filter_level,
    int cur_iter,
    size_t num_blocks,
    size_t num_planes,
    size_t plane,
    size_t block,
    int p //pitches[plane]
){
    size_t thread = get_global_id(0);

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

        s_off += thread;
        //s_off += thread, so maybe it's possible to use a strided copy with local memory to load into the vector

        uchar8 data = load8(s_base, s_off, p);

        char mask = vp8_filter_mask(lfi->lim[thread], lfi->flim[thread], data);

        int hev = vp8_hevmask(lfi->thr[thread], data.s2345);

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

        save4(s_base, s_off, p, data);
    }
}

__inline void vp8_loop_filter_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int filter_level,
    int cur_iter,
    size_t num_blocks,
    size_t num_planes,
    size_t plane,
    size_t block,
    int p
){
    if (filters[num_blocks*filter_type + block] > 0){
        int block_offset = cur_iter*num_blocks*num_planes + block*num_planes+plane;
        int s_off = offsets[block_offset];

        size_t thread = get_global_id(0);
        s_off += p * thread;

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

        char mask = vp8_filter_mask(lfi->lim[thread], lfi->flim[thread], data);

        int hev = vp8_hevmask(lfi->thr[thread], data.s2345);

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

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

__inline void vp8_mbloop_filter_horizontal_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int filter_level,
    size_t num_blocks,
    size_t num_planes,
    size_t plane,
    size_t block,
    int p //pitches[plane]
){

    size_t thread = get_global_id(0);
    int s_off = offsets[8*num_blocks + block*num_planes+plane] + thread;

    uchar8 data = load8(s_base, s_off, p);

    char mask = vp8_filter_mask(lfi->lim[thread], lfi->mbflim[thread], data);

    char hev = vp8_hevmask(lfi->thr[thread], data.s2345);

    data = vp8_mbfilter(mask, hev, data);

    save6(s_base, s_off, p, data);

}

__inline void vp8_mbloop_filter_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int filter_level,
    size_t num_blocks,
    size_t num_planes,
    size_t plane,
    size_t block,
    int p //pitches[plane]
){

    int block_offset = block*num_planes+plane;
    size_t thread = get_global_id(0);
    int s_off = offsets[block_offset] + p*thread - 4;

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

    char mask = vp8_filter_mask(lfi->lim[thread], lfi->mbflim[thread], data);

    int hev = vp8_hevmask(lfi->thr[thread], data.s2345);

    data = vp8_mbfilter(mask, hev, data);

    vstore8(data, 0, &s_base[s_off]);
}

kernel void vp8_loop_filter_all_edges_kernel(
    global unsigned char *s_base,
    global int *offsets_in,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters_in,
    int priority_level,
    int num_levels,
    global int *block_offsets,
    global int *priority_num_blocks
){
    size_t thread = get_global_id(0);
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    //local char local_data[256]; //Local copy of frame data.

    int block_offset = block_offsets[priority_level];

    global int *offsets = &offsets_in[16*block_offset];
    global int *filters = &filters_in[4*block_offset];
    size_t num_blocks = get_global_size(2);
    int filter_level = filters[block];
    global loop_filter_info *lf_info = &lfi[filter_level];
    int p = pitches[plane];
    int thread_level_filter = (thread<threads[plane]) & (filter_level!=0);

    //Prefetch vertical edge source pixels into global cache (horizontal isn't worth it)
    for(int pln = 0; pln < 3; pln++){
        int pitch = pitches[pln];
        int offset = block*3+pln;
        int s_off = offsets[offset] - 4;
        for (int thread = 0; thread < 16; thread++){
            prefetch(&s_base[s_off+pitch*thread], 8);
        }
    }

    if (thread_level_filter){
        if ( filters[num_blocks*COLS_LOCATION + block] > 0 ){
            vp8_mbloop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    COLS_LOCATION, filter_level, num_blocks, 3,  plane, block, p);
        }

        //YUV planes, then 2 more passes of Y plane
        vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                DC_DIFFS_LOCATION, filter_level, 1, num_blocks, 3, plane, block, p);
        if (plane == 0){
            vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 6, num_blocks, 1, plane, block, p);
            vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 7, num_blocks, 1,  plane, block, p);
        }
    }

    barrier(CLK_GLOBAL_MEM_FENCE);

    if (thread_level_filter){
        if (filters[num_blocks*ROWS_LOCATION + block] > 0){
            vp8_mbloop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info,
                filters, ROWS_LOCATION, filter_level, num_blocks, 3, plane, block, p);
        }

        //YUV planes, then 2 more passes of Y plane
        vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                DC_DIFFS_LOCATION, filter_level, 0, num_blocks, 3, plane, block, p);
        if (plane == 0){
            vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 3, num_blocks, 1, plane, block, p);
            vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 4, num_blocks, 1, plane, block, p);
        }
    }
}

kernel void vp8_loop_filter_horizontal_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filters,
    int priority_level,
    int num_levels,
    global int *block_offsets,
    global int *priority_num_blocks
){
    size_t thread = get_global_id(0);
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_blocks = get_global_size(2);

    int block_offset = block_offsets[priority_level];

    filters = &filters[4*block_offset];
    offsets = &offsets[16*block_offset];
    int filter_level = filters[block];
    global loop_filter_info *lf_info = &lfi[filter_level];
    int p = pitches[plane];

    int thread_level_filter = (thread<threads[plane]) & (filter_level!=0);
    int do_filter = filters[num_blocks*ROWS_LOCATION + block] > 0;
    do_filter &= thread_level_filter;
    if (do_filter){
        vp8_mbloop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info,
            filters, ROWS_LOCATION, filter_level, num_blocks, 3, plane, block, p);
    }

    //YUV planes, then 2 more passes of Y plane
    if (thread_level_filter){
        vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                DC_DIFFS_LOCATION, filter_level, 0, num_blocks, 3, plane, block, p);
        if (plane == 0){
            vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 3, num_blocks, 1, plane, block, p);
            vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 4, num_blocks, 1, plane, block, p);
        }
    }
}

kernel void vp8_loop_filter_vertical_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int priority_level,
    int num_levels,
    global int *block_offsets,
    global int *priority_num_blocks
){
    size_t thread = get_global_id(0);
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_blocks = get_global_size(2);

    int block_offset = block_offsets[priority_level];

    filters = &filters[4*block_offset];
    offsets = &offsets[16*block_offset];
    int filter_level = filters[block];
    global loop_filter_info *lf_info = &lfi[filter_level];
    int p = pitches[plane];

    int thread_level_filter = (thread<threads[plane]) & (filter_level!=0);
    int do_filter = filters[num_blocks*COLS_LOCATION + block] > 0;
    do_filter &= thread_level_filter;
    if (do_filter){
        vp8_mbloop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
            COLS_LOCATION, filter_level, num_blocks, 3, plane, block, p);
    }

    //YUV planes, then 2 more passes of Y plane
    if (thread_level_filter){
        vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                DC_DIFFS_LOCATION, filter_level, 1, num_blocks, 3, plane, block, p);
        if (plane == 0){
            vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 6, num_blocks, 1, plane, block, p);
            vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 7, num_blocks, 1, plane, block, p);
        }
    }

}

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

    global int *filters = &filters_in[filter_offset];

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

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

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

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

                limit = lf_info->lim;

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

void vp8_loop_filter_simple_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets, /* Y or YUV offsets for EACH block being processed*/
    global int *pitches, /* 1 or 3 values for Y or YUV pitches*/
    global loop_filter_info *lfi, /* Single struct for the frame */
    global int *filters_in, /* Filters for each block being processed */
    int use_mbflim, /* Use lfi->flim or lfi->mbflim, need once per kernel call */
    int filter_type, /* Should dc_diffs, rows, or cols be used?*/
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    int filter_offset = 4*block_offset;
    int priority_offset = 8*block_offset;
    private size_t block = get_global_id(2);
    size_t num_blocks = priority_num_blocks[priority_level];

    global int *filters = &filters_in[filter_offset];

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

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

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

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

                limit = lf_info->lim;

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

kernel void vp8_loop_filter_simple_vertical_edges_kernel
(
    global unsigned char *s_base,
    global int *offsets, /* Y or YUV offsets for EACH block being processed*/
    global int *pitches, /* 1 or 3 values for Y or YUV pitches*/
    global loop_filter_info *lfi, /* Single struct for the frame */
    global int *filters_in, /* Filters for each block being processed */
    int filter_type, /* Should dc_diffs, rows, or cols be used?*/
    int priority_level,
    int num_levels,
    global int *block_offsets,
    global int *priority_num_blocks
){
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 1, COLS_LOCATION, 0, priority_level,
            block_offsets, priority_num_blocks
    );

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

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

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

    for (int i = 0; i < num_levels; i++){
        if (get_global_id(2) < priority_num_blocks[priority_level]){
            vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
                    lfi, filters_in, 1, COLS_LOCATION, 0, priority_level,
                    block_offsets, priority_num_blocks
            );

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

        barrier(CLK_GLOBAL_MEM_FENCE);

        if (get_global_id(2) < priority_num_blocks[priority_level]){
            vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
                    filters_in, 1, ROWS_LOCATION, 4, priority_level,
                    block_offsets, priority_num_blocks
            );
            vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
                    filters_in, 0, DC_DIFFS_LOCATION, 5, priority_level,
                    block_offsets, priority_num_blocks
            );
            vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
                    filters_in, 0, DC_DIFFS_LOCATION, 6, priority_level,
                    block_offsets, priority_num_blocks
            );
            vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
                    filters_in, 0, DC_DIFFS_LOCATION, 7, priority_level,
                    block_offsets, priority_num_blocks
            );
        }

        barrier(CLK_GLOBAL_MEM_FENCE);
        priority_level++;
    }
}

//Inline and non-kernel functions follow.
__inline uchar8 vp8_mbfilter(
    signed char mask,
    uchar hev,
    uchar8 base
)
{
    char4 u;

    char8 pq = as_char8(base);
    pq ^= (char8){0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0};

    /* add outer taps if we have high edge variance */
    char vp8_filter = sub_sat(pq.s2, pq.s5);
    vp8_filter = clamp(vp8_filter + 3 * (pq.s4 - pq.s3), -128, 127);
    vp8_filter &= mask;

    char2 filter = (char2)vp8_filter;
    filter &= hev;

    /* save bottom 3 bits so that we round one side +4 and the other +3 */
    filter = add_sat(filter, (char2){4,3});
    filter.s0 >>= 3;
    filter.s1 >>= 3;

    pq.s4 = sub_sat(pq.s4, filter.s0);
    pq.s3 = add_sat(pq.s3, filter.s1);

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

    /* roughly 3/7th, 2/7th, and 1/7th difference across boundary */
#if 0
    u = convert_char4(clamp(((short4)63 + (short4)filter.s1 * (short4){27, 18, 9, 0}) >> 7, -128, 127) );
#else
    u.s0 = clamp((63 + filter.s1 * 27) >> 7, -128, 127);
    u.s1 = clamp((63 + filter.s1 * 18) >> 7, -128, 127);
    u.s2 = clamp((63 + filter.s1 * 9) >> 7, -128, 127);
    u.s3 = 0;
#endif

#if 1
    char4 s;
    s = sub_sat(pq.s4567, u);
    pq.s4567 = s ^ (char4){0x80, 0x80, 0x80, 0};
    s = add_sat(pq.s0123, u.s3210);
    pq.s0123 = s ^ (char4){0, 0x80, 0x80, 0x80};
#else
    pq.s4567 = sub_sat(pq.s4567, u.s0123);
    pq.s3210 = add_sat(pq.s3210, u.s0123);
    pq ^= (char8){0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0};
#endif

    return as_uchar8(pq);
}

/* is there high variance internal edge ( 11111111 yes, 00000000 no) */
__inline uchar vp8_hevmask(signed char thresh, uchar4 pq)
{
    return ~any(abs_diff(pq.s03, pq.s12) > thresh) + 1;
    //return any(abs_diff(pq.s03, pq.s12) > thresh) * -1; //If return type = signed char
}

/* should we apply any filter at all ( 11111111 yes, 00000000 no) */
__inline signed char vp8_filter_mask( signed char limit, signed char flimit,
        uchar8 pq)
{
    //Only apply the filter if the difference is LESS than 'limit'
#if 1
    char mask = (abs_diff(pq.s0, pq.s1) > limit);
    mask |= (abs_diff(pq.s1, pq.s2) > limit);
    mask |= (abs_diff(pq.s2, pq.s3) > limit);
    mask |= (abs_diff(pq.s5, pq.s4) > limit);
    mask |= (abs_diff(pq.s6, pq.s5) > limit);
    mask |= (abs_diff(pq.s7, pq.s6) > limit);
    mask |= (abs_diff(pq.s3, pq.s4) * 2 + abs_diff(pq.s2, pq.s5) / 2  > flimit * 2 + limit);
    return mask - 1;
#else
    short8 mask8 = convert_short8(abs_diff(pq.s01256732, pq.s12345645));
    mask8.s6 = mask8.s6 * 2 + mask8.s7 / 2;

    short8 limits = (short8)limit;
    limits.s6 += flimit * 2;
    mask8 = mask8 > limits;
    mask8.s7 = 0;

    return any(mask8) - 1;
#endif

}

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

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

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

    signed char vp8_filter;
    char2 filter;

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

    signed char u;

    vp8_filter = sub_sat(pq.s0, pq.s3);
    vp8_filter = clamp(vp8_filter + 3 * (pq.s2 - pq.s1), -128, 127);
    vp8_filter &= mask;

    /* save bottom 3 bits so that we round one side +4 and the other +3 */
    filter = add_sat((char2)vp8_filter, (char2){4,3});
    filter.s0 >>= 3;
    filter.s1 >>= 3;

    u = sub_sat(pq.s2, filter.s0);
    *oq0  = u ^ 0x80;

    u = add_sat(pq.s1, filter.s1);
    *op0 = u ^ 0x80;
}

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

typedef unsigned char uc;
typedef signed char sc;

__inline signed char vp8_filter_mask(sc, sc, uchar8);
__inline signed char vp8_simple_filter_mask(signed char, signed char, uc, uc, uc, uc);
__inline uchar vp8_hevmask(signed char, uchar4);

__inline uchar8 vp8_mbfilter(signed char mask, uchar hev, uchar8);

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

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

#ifndef __CL_VERSION_1_0__
#define __CL_VERSION_1_0__ 100
#endif

#if __OPENCL_VERSION__ == __CL_VERSION_1_0__
#define clamp(x,y,z) vp8_char_clamp(x)
char vp8_char_clamp(int in){
    return max(min(in, 127), -128);
}
#endif

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

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

//OpenCL built-in functions (
size_t get_global_id(unsigned int);
size_t get_global_size(unsigned int);

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

    char vp8_filter;
    char2 Filter;
    char4 u;

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

    /* inner taps */
    vp8_filter = clamp(vp8_filter + 3 * (pq.s2 - pq.s1), -128, 127);
    vp8_filter &= mask;

    /* save bottom 3 bits so that we round one side +4 and the other +3
     * if it equals 4 we'll set to adjust by -1 to account for the fact
     * we'd round 3 the other way
     */
    Filter = add_sat((char2)vp8_filter, (char2){4,3});
    Filter.s0 >>= 3;
    Filter.s1 >>= 3;

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

    u.s0 = add_sat(pq.s0, vp8_filter);
    u.s1 = add_sat(pq.s1, Filter.s1);
    u.s2 = sub_sat(pq.s2, Filter.s0);
    u.s3 = sub_sat(pq.s3, vp8_filter);

    return as_uchar4(u ^ (char4)0x80);

}

// Filters horizontal edges of inner blocks in a Macroblock
__inline void vp8_loop_filter_horizontal_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int filter_level,
    int cur_iter,
    size_t num_blocks,
    size_t num_planes,
    size_t plane,
    size_t block
){
    size_t thread = get_global_id(0);

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

        s_off += thread;
        //s_off += thread, so maybe it's possible to use a strided copy with local memory to load into the vector

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

        char mask = vp8_filter_mask(lfi->lim[thread], lfi->flim[thread], data);

        int hev = vp8_hevmask(lfi->thr[thread], data.s2345);

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

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

__inline void vp8_loop_filter_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int filter_level,
    int cur_iter,
    size_t num_blocks,
    size_t num_planes,
    size_t plane,
    size_t block
){
    if (filters[num_blocks*filter_type + block] > 0){
        int p = pitches[plane];
        int block_offset = cur_iter*num_blocks*num_planes + block*num_planes+plane;
        int s_off = offsets[block_offset];

        size_t thread = get_global_id(0);
        s_off += p * thread;

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

        char mask = vp8_filter_mask(lfi->lim[thread], lfi->flim[thread], data);

        int hev = vp8_hevmask(lfi->thr[thread], data.s2345);

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

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

__inline void vp8_mbloop_filter_horizontal_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int filter_level,
    size_t num_blocks,
    size_t num_planes,
    size_t plane,
    size_t block
){

    int p = pitches[plane];
    size_t thread = get_global_id(0);
    int s_off = offsets[8*num_blocks + block*num_planes+plane] + thread;

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

    char mask = vp8_filter_mask(lfi->lim[thread], lfi->mbflim[thread], data);

    char hev = vp8_hevmask(lfi->thr[thread], data.s2345);

    data = vp8_mbfilter(mask, hev, data);

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

}

__inline void vp8_mbloop_filter_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int filter_type,
    int filter_level,
    size_t num_blocks,
    size_t num_planes,
    size_t plane,
    size_t block
){

    int p = pitches[plane];
    int block_offset = block*num_planes+plane;
    int s_off = offsets[block_offset];
    size_t thread = get_global_id(0);

    s_off += p * thread;

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

    char mask = vp8_filter_mask(lfi->lim[thread], lfi->mbflim[thread], data);

    int hev = vp8_hevmask(lfi->thr[thread], data.s2345);

    data = vp8_mbfilter(mask, hev, data);

    vstore8(data, 0, &s_base[s_off-4]);
}

kernel void vp8_loop_filter_all_edges_kernel(
    global unsigned char *s_base,
    global int *offsets_in,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters_in,
    int priority_level,
    int num_levels,
    global int *block_offsets,
    global int *priority_num_blocks
){
    size_t thread = get_global_id(0);
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);

    int block_offset = block_offsets[priority_level];

    global int *offsets = &offsets_in[16*block_offset];
    global int *filters = &filters_in[4*block_offset];
    size_t num_blocks = get_global_size(2);
    int filter_level = filters[block];
    global loop_filter_info *lf_info = &lfi[filter_level];
    int thread_level_filter = (thread<threads[plane]) & (filter_level!=0);

    if (block < num_blocks){
        //Prefetch vertical edge source pixels into global cache (horizontal isn't worth it)
        for(int pln = 0; pln < 3; pln++){
            int p = pitches[pln];
            int offset = block*3+pln;
            int s_off = offsets[offset] - 4;
            for (int thread = 0; thread < 16; thread++){
                prefetch(&s_base[s_off+p*thread], 8);
            }
        }

        if (thread_level_filter){
            if ( filters[num_blocks*COLS_LOCATION + block] > 0 ){
                vp8_mbloop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                        COLS_LOCATION, filter_level, num_blocks, 3,  plane, block);
            }

            //YUV planes, then 2 more passes of Y plane
            vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 1, num_blocks, 3, plane, block);
            if (plane == 0){
                vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                        DC_DIFFS_LOCATION, filter_level, 6, num_blocks, 1, plane, block);
                vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                        DC_DIFFS_LOCATION, filter_level, 7, num_blocks, 1,  plane, block);
            }
        }
    }

    barrier(CLK_GLOBAL_MEM_FENCE);

    if (block < num_blocks){

        if (thread_level_filter){
            if (filters[num_blocks*ROWS_LOCATION + block] > 0){
                vp8_mbloop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info,
                    filters, ROWS_LOCATION, filter_level, num_blocks, 3, plane, block);
            }

            //YUV planes, then 2 more passes of Y plane
            vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 0, num_blocks, 3, plane, block);
            if (plane == 0){
                vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                        DC_DIFFS_LOCATION, filter_level, 3, num_blocks, 1, plane, block);
                vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                        DC_DIFFS_LOCATION, filter_level, 4, num_blocks, 1, plane, block);
            }
        }
    }
}

kernel void vp8_loop_filter_horizontal_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches, /* pitch */
    global loop_filter_info *lfi,
    global int *filters,
    int priority_level,
    int num_levels,
    global int *block_offsets,
    global int *priority_num_blocks
){
    size_t thread = get_global_id(0);
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_blocks = get_global_size(2);

    int block_offset = block_offsets[priority_level];

    filters = &filters[4*block_offset];
    offsets = &offsets[16*block_offset];
    int filter_level = filters[block];
    global loop_filter_info *lf_info = &lfi[filter_level];

    int thread_level_filter = (thread<threads[plane]) & (filter_level!=0);
    int do_filter = filters[num_blocks*ROWS_LOCATION + block] > 0;
    do_filter &= thread_level_filter;
    if (do_filter){
        vp8_mbloop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info,
            filters, ROWS_LOCATION, filter_level, num_blocks, 3, plane, block);
    }

    //YUV planes, then 2 more passes of Y plane
    if (thread_level_filter){
        vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                DC_DIFFS_LOCATION, filter_level, 0, num_blocks, 3, plane, block);
        if (plane == 0){
            vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 3, num_blocks, 1, plane, block);
            vp8_loop_filter_horizontal_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 4, num_blocks, 1, plane, block);
        }
    }
}

kernel void vp8_loop_filter_vertical_edges_kernel(
    global unsigned char *s_base,
    global int *offsets,
    global int *pitches,
    global loop_filter_info *lfi,
    global int *filters,
    int priority_level,
    int num_levels,
    global int *block_offsets,
    global int *priority_num_blocks
){
    size_t thread = get_global_id(0);
    size_t plane = get_global_id(1);
    size_t block = get_global_id(2);
    size_t num_blocks = get_global_size(2);

    int block_offset = block_offsets[priority_level];

    filters = &filters[4*block_offset];
    offsets = &offsets[16*block_offset];
    int filter_level = filters[block];
    global loop_filter_info *lf_info = &lfi[filter_level];

    int thread_level_filter = (thread<threads[plane]) & (filter_level!=0);
    int do_filter = filters[num_blocks*COLS_LOCATION + block] > 0;
    do_filter &= thread_level_filter;
    if (do_filter){
        vp8_mbloop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
            COLS_LOCATION, filter_level, num_blocks, 3, plane, block);
    }

    //YUV planes, then 2 more passes of Y plane
    if (thread_level_filter){
        vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                DC_DIFFS_LOCATION, filter_level, 1, num_blocks, 3, plane, block);
        if (plane == 0){
            vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 6, num_blocks, 1, plane, block);
            vp8_loop_filter_vertical_edge_worker(s_base, offsets, pitches, lf_info, filters,
                    DC_DIFFS_LOCATION, filter_level, 7, num_blocks, 1, plane, block);
        }
    }

}

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

    global int *filters = &filters_in[filter_offset];

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

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

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

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

                limit = lf_info->lim;

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

void vp8_loop_filter_simple_vertical_edge_worker(
    global unsigned char *s_base,
    global int *offsets, /* Y or YUV offsets for EACH block being processed*/
    global int *pitches, /* 1 or 3 values for Y or YUV pitches*/
    global loop_filter_info *lfi, /* Single struct for the frame */
    global int *filters_in, /* Filters for each block being processed */
    int use_mbflim, /* Use lfi->flim or lfi->mbflim, need once per kernel call */
    int filter_type, /* Should dc_diffs, rows, or cols be used?*/
    int cur_iter,
    int priority_level,
    global int *block_offsets,
    global int *priority_num_blocks
){
    int block_offset = block_offsets[priority_level];
    int filter_offset = 4*block_offset;
    int priority_offset = 8*block_offset;
    private size_t block = get_global_id(2);
    size_t num_blocks = priority_num_blocks[priority_level];

    global int *filters = &filters_in[filter_offset];

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

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

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

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

                limit = lf_info->lim;

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

kernel void vp8_loop_filter_simple_vertical_edges_kernel
(
    global unsigned char *s_base,
    global int *offsets, /* Y or YUV offsets for EACH block being processed*/
    global int *pitches, /* 1 or 3 values for Y or YUV pitches*/
    global loop_filter_info *lfi, /* Single struct for the frame */
    global int *filters_in, /* Filters for each block being processed */
    int filter_type, /* Should dc_diffs, rows, or cols be used?*/
    int priority_level,
    int num_levels,
    global int *block_offsets,
    global int *priority_num_blocks
){
    vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
            lfi, filters_in, 1, COLS_LOCATION, 0, priority_level,
            block_offsets, priority_num_blocks
    );

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

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

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

    for (int i = 0; i < num_levels; i++){
        if (get_global_id(2) < priority_num_blocks[priority_level]){
            vp8_loop_filter_simple_vertical_edge_worker(s_base, offsets, pitches,
                    lfi, filters_in, 1, COLS_LOCATION, 0, priority_level,
                    block_offsets, priority_num_blocks
            );

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

        barrier(CLK_GLOBAL_MEM_FENCE);

        if (get_global_id(2) < priority_num_blocks[priority_level]){
            vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
                    filters_in, 1, ROWS_LOCATION, 4, priority_level,
                    block_offsets, priority_num_blocks
            );
            vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
                    filters_in, 0, DC_DIFFS_LOCATION, 5, priority_level,
                    block_offsets, priority_num_blocks
            );
            vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
                    filters_in, 0, DC_DIFFS_LOCATION, 6, priority_level,
                    block_offsets, priority_num_blocks
            );
            vp8_loop_filter_simple_horizontal_edge_worker(s_base, offsets, pitches, lfi,
                    filters_in, 0, DC_DIFFS_LOCATION, 7, priority_level,
                    block_offsets, priority_num_blocks
            );
        }

        barrier(CLK_GLOBAL_MEM_FENCE);
        priority_level++;
    }
}

//Inline and non-kernel functions follow.
__inline uchar8 vp8_mbfilter(
    signed char mask,
    uchar hev,
    uchar8 base
)
{
    char4 u;

    char8 pq = as_char8(base);
    pq ^= (char8){0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0};

    /* add outer taps if we have high edge variance */
    char vp8_filter = sub_sat(pq.s2, pq.s5);
    vp8_filter = clamp(vp8_filter + 3 * (pq.s4 - pq.s3), -128, 127);
    vp8_filter &= mask;

    char2 filter = (char2)vp8_filter;
    filter &= hev;

    /* save bottom 3 bits so that we round one side +4 and the other +3 */
    filter = add_sat(filter, (char2){4,3});
    filter.s0 >>= 3;
    filter.s1 >>= 3;

    pq.s4 = sub_sat(pq.s4, filter.s0);
    pq.s3 = add_sat(pq.s3, filter.s1);

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

    /* roughly 3/7th, 2/7th, and 1/7th difference across boundary */
#if 0
    u = convert_char4(clamp(((short4)63 + (short4)filter.s1 * (short4){27, 18, 9, 0}) >> 7, -128, 127) );
#else
    u.s0 = clamp((63 + filter.s1 * 27) >> 7, -128, 127);
    u.s1 = clamp((63 + filter.s1 * 18) >> 7, -128, 127);
    u.s2 = clamp((63 + filter.s1 * 9) >> 7, -128, 127);
    u.s3 = 0;
#endif

#if 1
    char4 s;
    s = sub_sat(pq.s4567, u);
    pq.s4567 = s ^ (char4){0x80, 0x80, 0x80, 0};
    s = add_sat(pq.s0123, u.s3210);
    pq.s0123 = s ^ (char4){0, 0x80, 0x80, 0x80};
#else
    pq.s4567 = sub_sat(pq.s4567, u.s0123);
    pq.s3210 = add_sat(pq.s3210, u.s0123);
    pq ^= (char8){0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0};
#endif

    return as_uchar8(pq);
}

/* is there high variance internal edge ( 11111111 yes, 00000000 no) */
__inline uchar vp8_hevmask(signed char thresh, uchar4 pq)
{
    return ~any(abs_diff(pq.s03, pq.s12) > thresh) + 1;
    //return any(abs_diff(pq.s03, pq.s12) > thresh) * -1; //If return type = signed char
}

/* should we apply any filter at all ( 11111111 yes, 00000000 no) */
__inline signed char vp8_filter_mask( signed char limit, signed char flimit,
        uchar8 pq)
{
    //Only apply the filter if the difference is LESS than 'limit'
#if 1
    char mask = (abs_diff(pq.s0, pq.s1) > limit);
    mask |= (abs_diff(pq.s1, pq.s2) > limit);
    mask |= (abs_diff(pq.s2, pq.s3) > limit);
    mask |= (abs_diff(pq.s5, pq.s4) > limit);
    mask |= (abs_diff(pq.s6, pq.s5) > limit);
    mask |= (abs_diff(pq.s7, pq.s6) > limit);
    mask |= (abs_diff(pq.s3, pq.s4) * 2 + abs_diff(pq.s2, pq.s5) / 2  > flimit * 2 + limit);
    return mask - 1;
#else
    short8 mask8 = convert_short8(abs_diff(pq.s01256732, pq.s12345645));
    mask8.s6 = mask8.s6 * 2 + mask8.s7 / 2;

    short8 limits = (short8)limit;
    limits.s6 += flimit * 2;
    mask8 = mask8 > limits;
    mask8.s7 = 0;

    return any(mask8) - 1;
#endif

}

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

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

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

    signed char vp8_filter;
    char2 filter;

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

    signed char u;

    vp8_filter = sub_sat(pq.s0, pq.s3);
    vp8_filter = clamp(vp8_filter + 3 * (pq.s2 - pq.s1), -128, 127);
    vp8_filter &= mask;

    /* save bottom 3 bits so that we round one side +4 and the other +3 */
    filter = add_sat((char2)vp8_filter, (char2){4,3});
    filter.s0 >>= 3;
    filter.s1 >>= 3;

    u = sub_sat(pq.s2, filter.s0);
    *oq0  = u ^ 0x80;

    u = add_sat(pq.s1, filter.s1);
    *op0 = u ^ 0x80;
}


removed empty lines

removed empty lines


minor update to kernels

minor update to kernels