Fix for new scoring (CPU)

Fix for new scoring (CPU)

__kernel
void interleaveSeq(__global char const * _src, __global char * dest) {

	__global char const * src = _src + ((global_index) * ref_length);
	dest = dest + ((global_index / interleave_number) * interleave_number * ref_length) + global_index % interleave_number;

	int i = 0;
	for (i = 0; i < ref_length / 4 * 4; i += 4) {
		char4 temp = vload4(0, src);
		dest[(i) * interleave_number] = temp.s0;
		dest[(i + 1) * interleave_number] = temp.s1;
		dest[(i + 2) * interleave_number] = temp.s2;
		dest[(i + 3) * interleave_number] = temp.s3;
		src += 4;
	}

	for (; i < ref_length; i += 1) {
		dest[(i) * interleave_number] = *src++;
	}
}

#ifdef __GPU__

#ifndef __BS__
__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix) {
#else
	__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix, __global char const * direction) {
#endif

		matrix = matrix + ((global_index / threads_per_block) * threads_per_block * ((corridor_length + 1) * (read_length + 1))) + global_index % threads_per_block;
		read = read + (global_index * read_length);
		scaff = scaff + ((global_index / interleave_number) * interleave_number * ref_length) + global_index % interleave_number;
		result = result + result_number * global_index;

		__local
		short l_matrix_lines[MATRIX_LENGTH];
		__local
		//	short * local_matrix_line = l_matrix_lines + local_index * corridor_length;
		short * local_matrix_line = l_matrix_lines + local_index;

		//Init matrix lines
		for (short i = 0; i < corridor_length; ++i) {
			local_matrix_line[i * threads_per_block] = 0;
			matrix[i * threads_per_block] = CIGAR_STOP;
		}
		matrix[corridor_length * threads_per_block] = CIGAR_STOP;

		short curr_max = -1;
		short read_index = 0;

		//	if (read[0] != '\0') {
		//		//printf("GPU Ref : %s\n", scaff);
		//		//printf("GPU Read: %s\n", read);
		//		printf("S:\t");
		//		char c;
		//		int i = 0;
		//		while ((c = scaff[i * interleave_number]) != '\0') {
		//			printf("\t%c", c);
		//			i += 1;
		//		}
		//		printf("\n");
		//	}

		//for (char read_char_cache; (read_char_cache = *read) != line_end; read
		//		= read + threads_per_block) {
		for (char read_char_cache; (read_char_cache = *read) != line_end; ++read) {
			//						printf("%c:\t", read_char_cache);
			//						for (short i = 0; i < read_index; ++i) {
			//							printf("\t");
			//						}
			matrix += (corridor_length + 1) * threads_per_block;
			//char read_char_cache;
			//while ((read_char_cache = read[read_index]) != line_end) {
			short left_cell = 0;
			matrix[0] = CIGAR_STOP;
			for (short ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

				//init values
				left_cell += gap_ref;
				short diag_cell = local_matrix_line[ref_index * threads_per_block];
				//			printf("%c == %c\n", read_char_cache, scaff[ref_index * interleave_number]);
				int pointer = CIGAR_X;

#ifndef __BS__
				//if (read_char_cache == scaff[ref_index * interleave_number]) {
				//	diag_cell += match;//typedef struct {
				//	pointer = CIGAR_EQ;
				//} else if (read_char_cache != 'N' && read_char_cache != line_end) {
				//	diag_cell += mismatch;
				//}
				diag_cell += scores[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				pointer = select(CIGAR_X, CIGAR_EQ, (read_char_cache == scaff[ref_index * interleave_number]));
#else
				short score = 0;
				if(direction[global_index] == 0) {
					score = scoresTC[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				} else {
					score = scoresAG[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				}
				diag_cell += score;
				//pointer = select(CIGAR_X, CIGAR_EQ, (score == match));
				pointer = select(CIGAR_X, CIGAR_EQ, (read_char_cache == scaff[ref_index * interleave_number]));
#endif

				//			int eq = (read_char_cache == scaff[ref_index * interleave_number]);
				//			diag_cell += select(mismatch, match, eq);
				//			if (!eq && (read_char_cache == 'N' || read_char_cache == line_end)) {
				//				diag_cell -= mismatch;
				//			}

				short up_cell = local_matrix_line[(ref_index + 1) * threads_per_block] + gap_read;

				//find max
				short max_cell = 0;
				max_cell = max(left_cell, max_cell);
				max_cell = max(diag_cell, max_cell);
				max_cell = max(up_cell, max_cell);

				//store "pointer"
				//int pointer = 0;//typedef struct {
				//	short best_ref_index;
				//	short best_read_index;
				//} Index;
				//if (max_cell > 0) {

				//						if (max_cell == up_cell) {
				//							//pointer = 2;
				//							pointer = CIGAR_I;
				//						} else if (max_cell == left_cell) {
				//							//pointer = 1;
				//							pointer = CIGAR_D;
				//						} else if (max_cell > 0) {
				//							//pointer = 4;
				//						} else {
				//							pointer = CIGAR_STOP;
				//						}

//chr4:1,803,533-1,803,603

				if(max_cell <= 0) {
					pointer = CIGAR_STOP;
				} else if(max_cell == diag_cell ||
					 	   max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
				} else if(max_cell == up_cell) {
					pointer = CIGAR_I;
				} else {
					pointer = CIGAR_D;
				}

				//if (max_cell == up_cell && max_cell != (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
				//	//pointer = 2;
				//	pointer = CIGAR_I;
				//} else if (max_cell == left_cell && max_cell != (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
				//	//pointer = 1;
				//	pointer = CIGAR_D;
				//} else if (max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))) {
				//	//pointer = 4;
				//} else {
				//	pointer = CIGAR_STOP;
				//}

				//}
				//printf("\t%d", max_cell);
				matrix[(ref_index + 1) * threads_per_block] = pointer;

				if (max_cell > curr_max) {
					curr_max = max_cell;
					result[param_best_read_index] = read_index;
					result[param_best_ref_index] = ref_index;
				}

				left_cell = max_cell;
				local_matrix_line[ref_index * threads_per_block] = max_cell;
			}
			matrix[corridor_length * threads_per_block] = CIGAR_STOP;
			scaff += interleave_number;
			read_index += 1;

			//for (short i = 0; i < corridor_length + 1; ++i) {
			//	printf("%d ", matrix[i]);
			//}
			//printf("\n");
		}
		result[qend] = read_index - result[param_best_read_index] - 1;
		if (read_index == 0) {
			result[param_best_read_index] = result[param_best_read_index] = 0;
		}
	}

#ifndef __BS__
	__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results) {
#else
		__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results, __global char const * direction) {
#endif

			read = read + (global_index * read_length);
			scaff = scaff + ((global_index / interleave_number) * interleave_number * ref_length) + (global_index % interleave_number);

			__local
			short l_matrix_lines[MATRIX_LENGTH];
			__local
			short * matrix_lines = l_matrix_lines + local_index;
			//Init matrix lines
			for (short i = 0; i < corridor_length; ++i) {
				matrix_lines[i * threads_per_block] = 0;
			}

			short curr_max = -1;

			//for (char read_char_cache; (read_char_cache = *read) != line_end; read += interleave_number) {
			for (int read_pos = 0; read_pos < read_length; ++read_pos) {
				//char read_char_cache = *read;
				//read += interleave_number;
				char read_char_cache = *read++;
				short left_cell = 0;
				//		for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
				for (int ref_index = 0; ref_index < (corridor_length - 1); ++ref_index) {

					short diag_cell = matrix_lines[ref_index * threads_per_block];

#ifndef __BS__
					//int eq = (read_char_cache == scaff[ref_index * interleave_number]) && read_char_cache != line_end;
					//diag_cell += select(mismatch, match, eq);
					//if (!eq && (read_char_cache == 'N' || read_char_cache == line_end)) {
					//	diag_cell -= mismatch;
					//}
					diag_cell += scores[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
#else
					if(direction[global_index] == 0) {
						diag_cell += scoresTC[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
					} else {
						diag_cell += scoresAG[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
					}
#endif

					//diag_cell += select(0, match, eq);
					//diag_cell += select(0, mismatch, (!eq && read_char_cache != N && read_char_cache != line_end));

					//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
					left_cell = max(null, (short) (left_cell + gap_ref));
					left_cell = max((short) (matrix_lines[ref_index * threads_per_block + threads_per_block] + gap_read), left_cell);
					left_cell = max(diag_cell, left_cell);

					curr_max = max(curr_max, left_cell);
					matrix_lines[ref_index * threads_per_block] = left_cell;
				}
				scaff += interleave_number;
				//scaff += 1;
			}
			results[global_index] = curr_max;
		}

#endif

#ifdef __CPU__

//__kernel void interleaveSeq(__global char const * src, __global char * dest) {
//	src = src + (global_index * ref_length * 4);
//
//	dest = dest + ((global_index / interleave_number) * interleave_number * ref_length * 4)
//	+ (global_index % interleave_number) * 4;
//	for (int i = 0; i < ref_length; ++i) {
//		dest[i * interleave_number * 4] = src[0];
//		dest[i * interleave_number * 4 + 1] = src[ref_length * 1];
//		dest[i * interleave_number * 4 + 2] = src[ref_length * 2];
//		dest[i * interleave_number * 4 + 3] = src[ref_length * 3];
//		src += 1;
//	}
//}

#ifndef __BS__
		__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix) {
#else
			__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix, __global char const * direction) {

			int4 direction4 =  convert_int4(vload4(global_index, direction));
#endif

				matrix = matrix + (global_index * ((corridor_length + 1) * (read_length + 1)) * 4);
				read = read + (global_index * read_length * 4);
				scaff = scaff + (global_index * ref_length * 4);
				result = result + result_number * global_index * 4;

//	int corridor_lengt4 = corridor_length * 4;

				float4 best_read_index4 = null4;
				float4 best_ref_index4 = null4;
				float4 qend4 = null4;

//	for(int k = 0; k < 4; ++k) {
//		printf("Ref  (GPU) %d:", k);
//		for(int i = 0; i < read_length + corridor_length - 1; ++i) {
//			printf("%c", scaff[i + k * ref_length]);
//		}
//		printf("\n");
//		printf("Read (GPU) %d:", k);
//		for(int i = 0; i < read_length; ++i) {
//			if(read[i + k * read_length] == '\0') {
//				printf("X");
//			} else {
//				printf("%c", read[i + k * read_length]);
//			}
//		}
//		printf("\n");
//	}

				if (read[0] != line_end) {
					float4 l_matrix_lines[MATRIX_LENGTH];
					float4 * local_matrix_line = l_matrix_lines + local_index * corridor_length;

					//Init matrix lines
					for (short i = 0; i < corridor_length; ++i) {
						local_matrix_line[i] = null4;
						vstore4(CIGAR_STOP, i, matrix);
					}
					vstore4(CIGAR_STOP, corridor_length, matrix);

					float4 curr_max = -1;
					float4 read_index = null4;

					for (short read_pos = 0; read_pos < read_length; ++read_pos) {
						//		while (true) {
						//			int read_pos = 0;
						int4 read_char_cache = (int4)(trans[read[read_pos + 0 * read_length]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
						//			read += 1;
						//			int4 test = read_char_cache == (int4) 5;
						//			printf("%d %d %d %d\n", test.s0, test.s1, test.s2, test.s3);
						//			if (test.s0 == -1 && test.s1 == -1 && test.s2 == -1 && test.s3 == -1) {
						//				break;
						//			}

						matrix += (corridor_length + 1) * 4;

						float4 left_cell = null4;

						vstore4(CIGAR_STOP, 0, matrix);

						for (short ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

							//
							//init values
							left_cell += gap_ref4;
#ifndef __BS__
							float4 score = (float4)(scores[read_char_cache.s0][trans[scaff[ref_index]]], scores[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]);
							float4 diag_cell = local_matrix_line[ref_index] + score;
							float4 pointerX = select(CIGAR_X4, CIGAR_EQ4, (score == match));
#else
							float4 score = select((float4)(scoresAG[read_char_cache.s0][trans[scaff[ref_index]]], scoresAG[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresAG[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresAG[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), (float4)(scoresTC[read_char_cache.s0][trans[scaff[ref_index]]], scoresTC[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresTC[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresTC[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), direction4 == 0);

							float4 diag_cell = local_matrix_line[ref_index] + score;
							float4 pointerX = select(CIGAR_X4, CIGAR_EQ4, (read_char_cache == (int4)(trans[scaff[ref_index]], trans[scaff[ref_index + 1 * ref_length]], trans[scaff[ref_index + 2 * ref_length]], trans[scaff[ref_index + 3 * ref_length]])));
#endif

							//int4 pointer = select(CIGAR_X, CIGAR_EQ, (score == match));
							//
							float4 up_cell = local_matrix_line[(ref_index + 1)] + gap_read4;

							//find max
							float4 max_cell = null4;
							max_cell = max(left_cell, max_cell);
							max_cell = max(diag_cell, max_cell);
							max_cell = max(up_cell, max_cell);

							//pointer = select(pointer, CIGAR_STOP, (max_cell == 0));

							//pointer = select(CIGAR_STOP, pointer, (max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))));
							//pointer = select(pointer, CIGAR_D, (max_cell == left_cell && max_cell != (local_matrix_line[ref_index] + mismatch)));
							//pointer = select(pointer, CIGAR_I, (max_cell == up_cell && max_cell != (local_matrix_line[ref_index] + mismatch)));

							float4 pointer = 0;
							pointer = select(pointer, CIGAR_D, max_cell == left_cell);
							pointer = select(pointer, CIGAR_I, max_cell == up_cell);
							pointer = select(pointer, pointerX, max_cell == diag_cell || max_cell == (local_matrix_line[ref_index] + mismatch));
							pointer = select(pointer, CIGAR_STOP, pointer == 0 || max_cell <= 0);

							//max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))

							vstore4(convert_char4(pointer), (ref_index + 1), matrix);

							best_read_index4 = select(best_read_index4, read_index, (max_cell > curr_max));
							best_ref_index4 = select(best_ref_index4, ref_index, (max_cell > curr_max));

							curr_max = max(curr_max, max_cell);

							left_cell = max_cell;

							local_matrix_line[ref_index] = max_cell;

						}
						vstore4(CIGAR_STOP, corridor_length, matrix);
						scaff += 1;
						//			read_index += 1;
						//			read_index = select(read_index + 1, read_index, test);
						read_index = select(read_index + 1, read_index, read_char_cache == (int4) 6);
						//			read_index -= convert_float4(test);
						//			read_index -= read_char_cache == 5.0;
					}
					qend4 = read_index - best_read_index4 - 1;
				}

				vstore4(convert_short4(best_read_index4), param_best_read_index, result);
				vstore4(convert_short4(best_ref_index4), param_best_ref_index, result);
				vstore4(convert_short4(qend4), qend, result);
			}

#ifndef __BS__
			__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results) {
#else
				__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results, __global char const * direction) {

				int4 direction4 =  convert_int4(vload4(global_index, direction));
#endif

					scaff = scaff + (global_index * ref_length * 4);
					read = read + (global_index * read_length * 4);

					float4 l_matrix_lines[MATRIX_LENGTH];
					float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;

					float4 curr_max = (float4)(-1.0f);
					if (read[0] != line_end) {
						//printf("Ref:  %s\n", scaff);
						//printf("Read: %s\n", read);
						//Init matrix lines
						for (short i = 0; i < corridor_length; ++i) {
							matrix_lines[i] = null4;
						}
						for (int read_pos = 0; read_pos < read_length; ++read_pos) {

							int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);

							float4 left_cell = 0;
							for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

								//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
								left_cell = max(null4, left_cell + gap_ref);
								left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);

#ifndef __BS__
								float4 scores4 = (float4)(scores[read_char_cache.s0][trans[scaff[ref_index]]], scores[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]);
#else
								float4 scores4 = select((float4)(scoresAG[read_char_cache.s0][trans[scaff[ref_index]]], scoresAG[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresAG[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresAG[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), (float4)(scoresTC[read_char_cache.s0][trans[scaff[ref_index]]], scoresTC[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresTC[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresTC[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), direction4 == 0);
#endif

								left_cell = max(matrix_lines[ref_index] + scores4, left_cell);

								curr_max = max(curr_max, left_cell);

								matrix_lines[ref_index] = left_cell;
							}
							scaff += 1;
						}
					}
					vstore4(curr_max, global_index, results);
					//printf("%f %f %f %f\n", curr_max.s0, curr_max.s1, curr_max.s2, curr_max.s3);
				}

				__kernel void oclSW_wSSE(__global char const * scaff, __global char const * read, __global float * results) {

					scaff = scaff + (global_index * ref_length);
					read = read + (global_index * read_length);

					float l_matrix_lines[MATRIX_LENGTH];
					float * matrix_lines = l_matrix_lines + local_index * corridor_length;

					float curr_max = -1.0f;
					if (read[0] != line_end) {
						//printf("Refxxx: %s\n", scaff);
						//Init matrix lines
						for (short i = 0; i < corridor_length; ++i) {
							matrix_lines[i] = 0.0f;
						}
						for (int read_pos = 0; read_pos < read_length; ++read_pos) {

							int read_char_cache = trans[read[read_pos]];

							float left_cell = 0.0f;
							for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

								//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
								left_cell = max(0.0f, left_cell + gap_ref);
								left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);

								//printf("%c", 'X');
								//printf("%c == %c\n", read_char_cache, scaff[ref_index]);
								float score = scores[read_char_cache][trans[scaff[ref_index]]];

								left_cell = max(matrix_lines[ref_index] + score, left_cell);

								curr_max = max(curr_max, left_cell);

								matrix_lines[ref_index] = left_cell;
							}
							scaff += 1;
						}
					}
					results[global_index] = curr_max;

					//results[global_index] = -101.0f;
				}

//__kernel void oclSW(__global char const * _scaff, __global char const * _read, __global float * results) {
//	for (int x = 0; x < 4; ++x) {
//		__global
//		char const *scaff = _scaff + (global_index * ref_length * 4 * 4) + 4 * x * ref_length;
//		__global
//		char const *read = _read + (global_index * read_length * 4 * 4) + 4 * x * read_length;
//
//		float4 l_matrix_lines[MATRIX_LENGTH];
//		float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;
//
//		float4 curr_max = (float4)(-1.0f, -1.0f, -1.0f, -1.0f);
//		if (read[0] != line_end) {
//			//printf("Ref: %s\n", scaff);
//			//Init matrix lines
//			for (short i = 0; i < corridor_length; ++i) {
//				matrix_lines[i] = null4;
//			}
//			for (int read_pos = 0; read_pos < read_length; ++read_pos) {
//
//				int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
//
//				float4 left_cell = 0;
//				for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
//
//					//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
//					left_cell = max(null4, left_cell + gap_ref);
//					left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);
//
//					float4 scores4 = (float4)(scores[read_char_cache.x][trans[scaff[ref_index]]], scores[read_char_cache.y][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.z][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.w][trans[scaff[ref_index + 3 * ref_length]]]);
//
//					left_cell = max(matrix_lines[ref_index] + scores4, left_cell);
//
//					curr_max = max(curr_max, left_cell);
//
//					matrix_lines[ref_index] = left_cell;
//				}
//				scaff += 1;
//			}
//		}
//		vstore4(curr_max, global_index * 4, results + 4 * x);
//	}
//	//	scaff = _scaff + global_index * (ref_length * 8) + 4 * ref_length;
//	//	read = _read + global_index * (read_length * 8) + 4 * read_length;
//	//
//	//	curr_max = (float4)(-1.0f, -1.0f, -1.0f, -1.0f);
//	//	if (read[0] != line_end) {
//	//		//printf("Ref: %s\n", scaff);
//	//
//	//		float4 l_matrix_lines[MATRIX_LENGTH];
//	//		float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;
//	//		//Init matrix lines
//	//		for (short i = 0; i < corridor_length; ++i) {
//	//			matrix_lines[i] = null4;
//	//		}
//	//
//	//		for (int read_pos = 0; read_pos < read_length; ++read_pos) {
//	//
//	//			int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
//	//
//	//			float4 left_cell = 0;
//	//			for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
//	//
//	//				//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
//	//				left_cell = max(null4, left_cell + gap_ref);
//	//				left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);
//	//
//	//				float4 scores4 = (float4)(scores[read_char_cache.x][trans[scaff[ref_index]]], scores[read_char_cache.y][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.z][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.w][trans[scaff[ref_index + 3 * ref_length]]]);
//	//
//	//				left_cell = max(matrix_lines[ref_index] + scores4, left_cell);
//	//
//	//				curr_max = max(curr_max, left_cell);
//	//
//	//				matrix_lines[ref_index] = left_cell;
//	//			}
//	//			scaff += 1;
//	//		}
//	//	}
//	//	vstore4(curr_max, global_index * 2, results + 4);
//}
#endif

__kernel
void interleaveSeq(__global char const * _src, __global char * dest) {

	__global char const * src = _src + ((global_index) * ref_length);
	dest = dest + ((global_index / interleave_number) * interleave_number * ref_length) + global_index % interleave_number;

	int i = 0;
	for (i = 0; i < ref_length / 4 * 4; i += 4) {
		char4 temp = vload4(0, src);
		dest[(i) * interleave_number] = temp.s0;
		dest[(i + 1) * interleave_number] = temp.s1;
		dest[(i + 2) * interleave_number] = temp.s2;
		dest[(i + 3) * interleave_number] = temp.s3;
		src += 4;
	}

	for (; i < ref_length; i += 1) {
		dest[(i) * interleave_number] = *src++;
	}
}

#ifdef __GPU__

#ifndef __BS__
__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix) {
#else
	__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix, __global char const * direction) {
#endif

		matrix = matrix + ((global_index / threads_per_block) * threads_per_block * ((corridor_length + 1) * (read_length + 1))) + global_index % threads_per_block;
		read = read + (global_index * read_length);
		scaff = scaff + ((global_index / interleave_number) * interleave_number * ref_length) + global_index % interleave_number;
		result = result + result_number * global_index;

		__local
		short l_matrix_lines[MATRIX_LENGTH];
		__local
		//	short * local_matrix_line = l_matrix_lines + local_index * corridor_length;
		short * local_matrix_line = l_matrix_lines + local_index;

		//Init matrix lines
		for (short i = 0; i < corridor_length; ++i) {
			local_matrix_line[i * threads_per_block] = 0;
			matrix[i * threads_per_block] = CIGAR_STOP;
		}
		matrix[corridor_length * threads_per_block] = CIGAR_STOP;

		short curr_max = -1;
		short read_index = 0;

		//	if (read[0] != '\0') {
		//		//printf("GPU Ref : %s\n", scaff);
		//		//printf("GPU Read: %s\n", read);
		//		printf("S:\t");
		//		char c;
		//		int i = 0;
		//		while ((c = scaff[i * interleave_number]) != '\0') {
		//			printf("\t%c", c);
		//			i += 1;
		//		}
		//		printf("\n");
		//	}

		//for (char read_char_cache; (read_char_cache = *read) != line_end; read
		//		= read + threads_per_block) {
		for (char read_char_cache; (read_char_cache = *read) != line_end; ++read) {
			//						printf("%c:\t", read_char_cache);
			//						for (short i = 0; i < read_index; ++i) {
			//							printf("\t");
			//						}
			matrix += (corridor_length + 1) * threads_per_block;
			//char read_char_cache;
			//while ((read_char_cache = read[read_index]) != line_end) {
			short left_cell = 0;
			matrix[0] = CIGAR_STOP;
			for (short ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

				//init values
				left_cell += gap_ref;
				short diag_cell = local_matrix_line[ref_index * threads_per_block];
				//			printf("%c == %c\n", read_char_cache, scaff[ref_index * interleave_number]);
				int pointer = CIGAR_X;

#ifndef __BS__
				//if (read_char_cache == scaff[ref_index * interleave_number]) {
				//	diag_cell += match;//typedef struct {
				//	pointer = CIGAR_EQ;
				//} else if (read_char_cache != 'N' && read_char_cache != line_end) {
				//	diag_cell += mismatch;
				//}
				diag_cell += scores[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				pointer = select(CIGAR_X, CIGAR_EQ, (read_char_cache == scaff[ref_index * interleave_number]));
#else
				short score = 0;
				if(direction[global_index] == 0) {
					score = scoresTC[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				} else {
					score = scoresAG[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
				}
				diag_cell += score;
				//pointer = select(CIGAR_X, CIGAR_EQ, (score == match));
				pointer = select(CIGAR_X, CIGAR_EQ, (read_char_cache == scaff[ref_index * interleave_number]));
#endif

				//			int eq = (read_char_cache == scaff[ref_index * interleave_number]);
				//			diag_cell += select(mismatch, match, eq);
				//			if (!eq && (read_char_cache == 'N' || read_char_cache == line_end)) {
				//				diag_cell -= mismatch;
				//			}

				short up_cell = local_matrix_line[(ref_index + 1) * threads_per_block] + gap_read;

				//find max
				short max_cell = 0;
				max_cell = max(left_cell, max_cell);
				max_cell = max(diag_cell, max_cell);
				max_cell = max(up_cell, max_cell);

				//store "pointer"
				//int pointer = 0;//typedef struct {
				//	short best_ref_index;
				//	short best_read_index;
				//} Index;
				//if (max_cell > 0) {

				//						if (max_cell == up_cell) {
				//							//pointer = 2;
				//							pointer = CIGAR_I;
				//						} else if (max_cell == left_cell) {
				//							//pointer = 1;
				//							pointer = CIGAR_D;
				//						} else if (max_cell > 0) {
				//							//pointer = 4;
				//						} else {
				//							pointer = CIGAR_STOP;
				//						}

//chr4:1,803,533-1,803,603

				if(max_cell <= 0) {
					pointer = CIGAR_STOP;
				} else if(max_cell == diag_cell ||
					 	   max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
				} else if(max_cell == up_cell) {
					pointer = CIGAR_I;
				} else {
					pointer = CIGAR_D;
				}

				//if (max_cell == up_cell && max_cell != (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
				//	//pointer = 2;
				//	pointer = CIGAR_I;
				//} else if (max_cell == left_cell && max_cell != (local_matrix_line[ref_index * threads_per_block] + mismatch)) {
				//	//pointer = 1;
				//	pointer = CIGAR_D;
				//} else if (max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))) {
				//	//pointer = 4;
				//} else {
				//	pointer = CIGAR_STOP;
				//}

				//}
				//printf("\t%d", max_cell);
				matrix[(ref_index + 1) * threads_per_block] = pointer;

				if (max_cell > curr_max) {
					curr_max = max_cell;
					result[param_best_read_index] = read_index;
					result[param_best_ref_index] = ref_index;
				}

				left_cell = max_cell;
				local_matrix_line[ref_index * threads_per_block] = max_cell;
			}
			matrix[corridor_length * threads_per_block] = CIGAR_STOP;
			scaff += interleave_number;
			read_index += 1;

			//for (short i = 0; i < corridor_length + 1; ++i) {
			//	printf("%d ", matrix[i]);
			//}
			//printf("\n");
		}
		result[qend] = read_index - result[param_best_read_index] - 1;
		if (read_index == 0) {
			result[param_best_read_index] = result[param_best_read_index] = 0;
		}
	}

#ifndef __BS__
	__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results) {
#else
		__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results, __global char const * direction) {
#endif

			read = read + (global_index * read_length);
			scaff = scaff + ((global_index / interleave_number) * interleave_number * ref_length) + (global_index % interleave_number);

			__local
			short l_matrix_lines[MATRIX_LENGTH];
			__local
			short * matrix_lines = l_matrix_lines + local_index;
			//Init matrix lines
			for (short i = 0; i < corridor_length; ++i) {
				matrix_lines[i * threads_per_block] = 0;
			}

			short curr_max = -1;

			//for (char read_char_cache; (read_char_cache = *read) != line_end; read += interleave_number) {
			for (int read_pos = 0; read_pos < read_length; ++read_pos) {
				//char read_char_cache = *read;
				//read += interleave_number;
				char read_char_cache = *read++;
				short left_cell = 0;
				//		for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
				for (int ref_index = 0; ref_index < (corridor_length - 1); ++ref_index) {

					short diag_cell = matrix_lines[ref_index * threads_per_block];

#ifndef __BS__
					//int eq = (read_char_cache == scaff[ref_index * interleave_number]) && read_char_cache != line_end;
					//diag_cell += select(mismatch, match, eq);
					//if (!eq && (read_char_cache == 'N' || read_char_cache == line_end)) {
					//	diag_cell -= mismatch;
					//}
					diag_cell += scores[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
#else
					if(direction[global_index] == 0) {
						diag_cell += scoresTC[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
					} else {
						diag_cell += scoresAG[trans[read_char_cache]][trans[scaff[ref_index * interleave_number]]];
					}
#endif

					//diag_cell += select(0, match, eq);
					//diag_cell += select(0, mismatch, (!eq && read_char_cache != N && read_char_cache != line_end));

					//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
					left_cell = max(null, (short) (left_cell + gap_ref));
					left_cell = max((short) (matrix_lines[ref_index * threads_per_block + threads_per_block] + gap_read), left_cell);
					left_cell = max(diag_cell, left_cell);

					curr_max = max(curr_max, left_cell);
					matrix_lines[ref_index * threads_per_block] = left_cell;
				}
				scaff += interleave_number;
				//scaff += 1;
			}
			results[global_index] = curr_max;
		}

#endif

#ifdef __CPU__

//__kernel void interleaveSeq(__global char const * src, __global char * dest) {
//	src = src + (global_index * ref_length * 4);
//
//	dest = dest + ((global_index / interleave_number) * interleave_number * ref_length * 4)
//	+ (global_index % interleave_number) * 4;
//	for (int i = 0; i < ref_length; ++i) {
//		dest[i * interleave_number * 4] = src[0];
//		dest[i * interleave_number * 4 + 1] = src[ref_length * 1];
//		dest[i * interleave_number * 4 + 2] = src[ref_length * 2];
//		dest[i * interleave_number * 4 + 3] = src[ref_length * 3];
//		src += 1;
//	}
//}

#ifndef __BS__
		__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix) {
#else
			__kernel void oclSW_Score(__global char const * scaff, __global char const * read, __global short * result, __global char * matrix, __global char const * direction) {

			int4 direction4 =  convert_int4(vload4(global_index, direction));
#endif

				matrix = matrix + (global_index * ((corridor_length + 1) * (read_length + 1)) * 4);
				read = read + (global_index * read_length * 4);
				scaff = scaff + (global_index * ref_length * 4);
				result = result + result_number * global_index * 4;

//	int corridor_lengt4 = corridor_length * 4;

				float4 best_read_index4 = null4;
				float4 best_ref_index4 = null4;
				float4 qend4 = null4;

//	for(int k = 0; k < 4; ++k) {
//		printf("Ref  (GPU) %d:", k);
//		for(int i = 0; i < read_length + corridor_length - 1; ++i) {
//			printf("%c", scaff[i + k * ref_length]);
//		}
//		printf("\n");
//		printf("Read (GPU) %d:", k);
//		for(int i = 0; i < read_length; ++i) {
//			if(read[i + k * read_length] == '\0') {
//				printf("X");
//			} else {
//				printf("%c", read[i + k * read_length]);
//			}
//		}
//		printf("\n");
//	}

				if (read[0] != line_end) {
					float4 l_matrix_lines[MATRIX_LENGTH];
					float4 * local_matrix_line = l_matrix_lines + local_index * corridor_length;

					//Init matrix lines
					for (short i = 0; i < corridor_length; ++i) {
						local_matrix_line[i] = null4;
						vstore4(CIGAR_STOP, i, matrix);
					}
					vstore4(CIGAR_STOP, corridor_length, matrix);

					float4 curr_max = -1;
					float4 read_index = null4;

					for (short read_pos = 0; read_pos < read_length; ++read_pos) {
						//		while (true) {
						//			int read_pos = 0;
						int4 read_char_cache = (int4)(trans[read[read_pos + 0 * read_length]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
						//			read += 1;
						//			int4 test = read_char_cache == (int4) 5;
						//			printf("%d %d %d %d\n", test.s0, test.s1, test.s2, test.s3);
						//			if (test.s0 == -1 && test.s1 == -1 && test.s2 == -1 && test.s3 == -1) {
						//				break;
						//			}

						matrix += (corridor_length + 1) * 4;

						float4 left_cell = null4;

						vstore4(CIGAR_STOP, 0, matrix);

						for (short ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

							//
							//init values
							left_cell += gap_ref4;
#ifndef __BS__
							float4 score = (float4)(scores[read_char_cache.s0][trans[scaff[ref_index]]], scores[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]);
							float4 diag_cell = local_matrix_line[ref_index] + score;
							float4 pointerX = select(CIGAR_X4, CIGAR_EQ4, (score == match));
#else
							float4 score = select((float4)(scoresAG[read_char_cache.s0][trans[scaff[ref_index]]], scoresAG[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresAG[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresAG[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), (float4)(scoresTC[read_char_cache.s0][trans[scaff[ref_index]]], scoresTC[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresTC[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresTC[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), direction4 == 0);

							float4 diag_cell = local_matrix_line[ref_index] + score;
							float4 pointerX = select(CIGAR_X4, CIGAR_EQ4, (read_char_cache == (int4)(trans[scaff[ref_index]], trans[scaff[ref_index + 1 * ref_length]], trans[scaff[ref_index + 2 * ref_length]], trans[scaff[ref_index + 3 * ref_length]])));
#endif

							//int4 pointer = select(CIGAR_X, CIGAR_EQ, (score == match));
							//
							float4 up_cell = local_matrix_line[(ref_index + 1)] + gap_read4;

							//find max
							float4 max_cell = null4;
							max_cell = max(left_cell, max_cell);
							max_cell = max(diag_cell, max_cell);
							max_cell = max(up_cell, max_cell);

							//pointer = select(pointer, CIGAR_STOP, (max_cell == 0));

							float4 pointer = select(pointerX, CIGAR_D, max_cell == left_cell);
							pointer = select(pointer, CIGAR_I, max_cell == up_cell);
							pointer = select(pointer, pointerX, max_cell == diag_cell || max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch));
							pointer = select(pointer, CIGAR_STOP, max_cell <= 0);

							//max_cell > 0 && (max_cell == diag_cell || max_cell == (local_matrix_line[ref_index * threads_per_block] + mismatch) || max_cell == (local_matrix_line[ref_index] + match))

							vstore4(convert_char4(pointer), (ref_index + 1), matrix);

							best_read_index4 = select(best_read_index4, read_index, (max_cell > curr_max));
							best_ref_index4 = select(best_ref_index4, ref_index, (max_cell > curr_max));

							curr_max = max(curr_max, max_cell);

							left_cell = max_cell;

							local_matrix_line[ref_index] = max_cell;

						}
						vstore4(CIGAR_STOP, corridor_length, matrix);
						scaff += 1;
						//			read_index += 1;
						//			read_index = select(read_index + 1, read_index, test);
						read_index = select(read_index + 1, read_index, read_char_cache == (int4) 6);
						//			read_index -= convert_float4(test);
						//			read_index -= read_char_cache == 5.0;
					}
					qend4 = read_index - best_read_index4 - 1;
				}

				vstore4(convert_short4(best_read_index4), param_best_read_index, result);
				vstore4(convert_short4(best_ref_index4), param_best_ref_index, result);
				vstore4(convert_short4(qend4), qend, result);
			}

#ifndef __BS__
			__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results) {
#else
				__kernel void oclSW(__global char const * scaff, __global char const * read, __global float * results, __global char const * direction) {

				int4 direction4 =  convert_int4(vload4(global_index, direction));
#endif

					scaff = scaff + (global_index * ref_length * 4);
					read = read + (global_index * read_length * 4);

					float4 l_matrix_lines[MATRIX_LENGTH];
					float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;

					float4 curr_max = (float4)(-1.0f);
					if (read[0] != line_end) {
						//printf("Ref:  %s\n", scaff);
						//printf("Read: %s\n", read);
						//Init matrix lines
						for (short i = 0; i < corridor_length; ++i) {
							matrix_lines[i] = null4;
						}
						for (int read_pos = 0; read_pos < read_length; ++read_pos) {

							int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);

							float4 left_cell = 0;
							for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

								//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
								left_cell = max(null4, left_cell + gap_ref);
								left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);

#ifndef __BS__
								float4 scores4 = (float4)(scores[read_char_cache.s0][trans[scaff[ref_index]]], scores[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]);
#else
								float4 scores4 = select((float4)(scoresAG[read_char_cache.s0][trans[scaff[ref_index]]], scoresAG[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresAG[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresAG[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), (float4)(scoresTC[read_char_cache.s0][trans[scaff[ref_index]]], scoresTC[read_char_cache.s1][trans[scaff[ref_index + 1 * ref_length]]], scoresTC[read_char_cache.s2][trans[scaff[ref_index + 2 * ref_length]]], scoresTC[read_char_cache.s3][trans[scaff[ref_index + 3 * ref_length]]]), direction4 == 0);
#endif

								left_cell = max(matrix_lines[ref_index] + scores4, left_cell);

								curr_max = max(curr_max, left_cell);

								matrix_lines[ref_index] = left_cell;
							}
							scaff += 1;
						}
					}
					vstore4(curr_max, global_index, results);
					//printf("%f %f %f %f\n", curr_max.s0, curr_max.s1, curr_max.s2, curr_max.s3);
				}

				__kernel void oclSW_wSSE(__global char const * scaff, __global char const * read, __global float * results) {

					scaff = scaff + (global_index * ref_length);
					read = read + (global_index * read_length);

					float l_matrix_lines[MATRIX_LENGTH];
					float * matrix_lines = l_matrix_lines + local_index * corridor_length;

					float curr_max = -1.0f;
					if (read[0] != line_end) {
						//printf("Refxxx: %s\n", scaff);
						//Init matrix lines
						for (short i = 0; i < corridor_length; ++i) {
							matrix_lines[i] = 0.0f;
						}
						for (int read_pos = 0; read_pos < read_length; ++read_pos) {

							int read_char_cache = trans[read[read_pos]];

							float left_cell = 0.0f;
							for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {

								//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
								left_cell = max(0.0f, left_cell + gap_ref);
								left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);

								//printf("%c", 'X');
								//printf("%c == %c\n", read_char_cache, scaff[ref_index]);
								float score = scores[read_char_cache][trans[scaff[ref_index]]];

								left_cell = max(matrix_lines[ref_index] + score, left_cell);

								curr_max = max(curr_max, left_cell);

								matrix_lines[ref_index] = left_cell;
							}
							scaff += 1;
						}
					}
					results[global_index] = curr_max;

					//results[global_index] = -101.0f;
				}

//__kernel void oclSW(__global char const * _scaff, __global char const * _read, __global float * results) {
//	for (int x = 0; x < 4; ++x) {
//		__global
//		char const *scaff = _scaff + (global_index * ref_length * 4 * 4) + 4 * x * ref_length;
//		__global
//		char const *read = _read + (global_index * read_length * 4 * 4) + 4 * x * read_length;
//
//		float4 l_matrix_lines[MATRIX_LENGTH];
//		float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;
//
//		float4 curr_max = (float4)(-1.0f, -1.0f, -1.0f, -1.0f);
//		if (read[0] != line_end) {
//			//printf("Ref: %s\n", scaff);
//			//Init matrix lines
//			for (short i = 0; i < corridor_length; ++i) {
//				matrix_lines[i] = null4;
//			}
//			for (int read_pos = 0; read_pos < read_length; ++read_pos) {
//
//				int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
//
//				float4 left_cell = 0;
//				for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
//
//					//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
//					left_cell = max(null4, left_cell + gap_ref);
//					left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);
//
//					float4 scores4 = (float4)(scores[read_char_cache.x][trans[scaff[ref_index]]], scores[read_char_cache.y][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.z][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.w][trans[scaff[ref_index + 3 * ref_length]]]);
//
//					left_cell = max(matrix_lines[ref_index] + scores4, left_cell);
//
//					curr_max = max(curr_max, left_cell);
//
//					matrix_lines[ref_index] = left_cell;
//				}
//				scaff += 1;
//			}
//		}
//		vstore4(curr_max, global_index * 4, results + 4 * x);
//	}
//	//	scaff = _scaff + global_index * (ref_length * 8) + 4 * ref_length;
//	//	read = _read + global_index * (read_length * 8) + 4 * read_length;
//	//
//	//	curr_max = (float4)(-1.0f, -1.0f, -1.0f, -1.0f);
//	//	if (read[0] != line_end) {
//	//		//printf("Ref: %s\n", scaff);
//	//
//	//		float4 l_matrix_lines[MATRIX_LENGTH];
//	//		float4 * matrix_lines = l_matrix_lines + local_index * corridor_length;
//	//		//Init matrix lines
//	//		for (short i = 0; i < corridor_length; ++i) {
//	//			matrix_lines[i] = null4;
//	//		}
//	//
//	//		for (int read_pos = 0; read_pos < read_length; ++read_pos) {
//	//
//	//			int4 read_char_cache = (int4)(trans[read[read_pos]], trans[read[read_pos + 1 * read_length]], trans[read[read_pos + 2 * read_length]], trans[read[read_pos + 3 * read_length]]);
//	//
//	//			float4 left_cell = 0;
//	//			for (int ref_index = 0; ref_index < corridor_length - 1; ++ref_index) {
//	//
//	//				//Max can be set to left_cell because we are computing the score row-wise, so the actual max is the left_cell for the next cell
//	//				left_cell = max(null4, left_cell + gap_ref);
//	//				left_cell = max(matrix_lines[(ref_index + 1)] + gap_read, left_cell);
//	//
//	//				float4 scores4 = (float4)(scores[read_char_cache.x][trans[scaff[ref_index]]], scores[read_char_cache.y][trans[scaff[ref_index + 1 * ref_length]]], scores[read_char_cache.z][trans[scaff[ref_index + 2 * ref_length]]], scores[read_char_cache.w][trans[scaff[ref_index + 3 * ref_length]]]);
//	//
//	//				left_cell = max(matrix_lines[ref_index] + scores4, left_cell);
//	//
//	//				curr_max = max(curr_max, left_cell);
//	//
//	//				matrix_lines[ref_index] = left_cell;
//	//			}
//	//			scaff += 1;
//	//		}
//	//	}
//	//	vstore4(curr_max, global_index * 2, results + 4);
//}
#endif


minor changes

minor changes

#include "cl/mwc64x/cl/mwc64x.cl"

// Doesn't return 0 so that rays can bounce without bumping.
float sphere_toi(
  const float3 eye,
  const float3 look,

  const float3 center,
  const float radius)
{
  // quadratic coefficients
  float a = dot(look, look);
  float b = 2 * dot(eye - center, look);
  float3 to_center = eye - center;
  float c = dot(to_center, to_center) - radius*radius;

  // discriminant
  float d = b*b - 4*a*c;

  if (d < 0) {
    return HUGE_VALF;
  }

  float s1 = (sqrt(d) - b) / (2 * a);
  if (s1 <= 0) {
    s1 = HUGE_VALF;
  }

  float s2 = (-sqrt(d) - b) / (2 * a);
  if (s1 < s2 || s2 <= 0) {
    return s1;
  }

  return s2;
}

typedef struct {
  float4 row1;
  float4 row2;
  float4 row3;
  float4 row4;
} mat4;

float4 vmult(mat4 m, float4 v) {
  return
    (float4)(
      dot(m.row1, v),
      dot(m.row2, v),
      dot(m.row3, v),
      dot(m.row4, v)
    );
}

mat4 screen_to_view(uint w, uint h, float fovy) {
  float aspect = (float)w / (float)h;

  float b = tan(fovy / 2);
  float a = 2 * b / h;
  b = -b;

  mat4 r;
  // We divide both x and y by h, to take aspect ratio into account.
  // An increase in image width will cause wider rays to be shot.
  r.row1 = (float4)(a, 0, 0, b * aspect);
  r.row2 = (float4)(0, a, 0, b);
  r.row3 = (float4)(0, 0, 1, 0);
  r.row4 = (float4)(0, 0, 0, 1);

  return r;
}

mat4 view_to_world(float3 eye, float3 look, float3 up) {
  float4 x = (float4)(cross(look, up), 0);
  float4 y = (float4)(up, 0);
  float4 z = (float4)(look, 0);
  float4 w = (float4)(eye, 1);

  // Change of basis

  mat4 r;
  r.row1.x = x.x;
  r.row2.x = x.y;
  r.row3.x = x.z;
  r.row4.x = x.w;

  r.row1.y = y.x;
  r.row2.y = y.y;
  r.row3.y = y.z;
  r.row4.y = y.w;

  r.row1.z = z.x;
  r.row2.z = z.y;
  r.row3.z = z.z;
  r.row4.z = z.w;

  r.row1.w = w.x;
  r.row2.w = w.y;
  r.row3.w = w.z;
  r.row4.w = w.w;

  return r;
}

typedef struct {
  float r;
  float g;
  float b;
} RGB;

RGB rgb(float3 xyz) {
  RGB r;
  r.r = xyz.x;
  r.g = xyz.y;
  r.b = xyz.z;
  return r;
}

typedef struct { float x, y, z } float3_parse;

float3 pack_float3(float3_parse f) {
  return (float3)(f.x, f.y, f.z);
}

typedef struct {
  float3_parse center;
  float radius;
  float3_parse color;
  float emittance;
  float reflectance;
} Object;

float parse_float(__global const float** data) {
  float r = **data;
  ++*data;
  return r;
}

float3_parse parse_float3(__global const float** data) {
  float3_parse r;
  r.x = parse_float(data);
  r.y = parse_float(data);
  r.z = parse_float(data);
  return r;
}

Object parse_object(__global const float* data) {
  Object r;
  r.center      = parse_float3(&data);
  r.radius      = parse_float(&data);
  r.color       = parse_float3(&data);
  r.emittance   = parse_float(&data);
  r.reflectance = parse_float(&data);
  return r;
}

typedef struct {
  float3 origin;
  float3 direction;
} Ray;

void raycast(
  Ray ray,

  __global const float* objects,
  const uint num_objects,

  float* toi,
  Object* collision
) {
  *toi = HUGE_VALF;

  for (uint i = 0; i < num_objects; ++i) {
    Object object = parse_object((Object*)objects + i);
    float this_toi = sphere_toi(ray.origin, ray.direction, pack_float3(object.center), object.radius);

    if (this_toi >= *toi) {
      continue;
    }

    *toi = this_toi;
    *collision = object;
  }
}

float rand(mwc64x_state_t* rand_state) {
  return (float)MWC64X_NextUint(rand_state) / (float)UINT_MAX;
}

float3 perturb(mwc64x_state_t* rand_state, float3 x, float3 y, float3 z) {
  float3 coeffs;
  coeffs.y = 2 * (rand(rand_state) - 0.5);
  const float xz = sqrt(1 - coeffs.y * coeffs.y);
  float azimuth = rand(rand_state ) * 2 * 3.14;
  coeffs.x = cos(azimuth);
  coeffs.z = sin(azimuth);
  coeffs.x *= xz;
  coeffs.z *= xz;
  return coeffs.x*x + coeffs.y*y + coeffs.z*z;
}

float3 pathtrace(
  Ray ray,
  uint max_depth,
  float3 ambient,
  mwc64x_state_t* rand_state,
  __global const float* objects,
  const uint num_objects
) {
  if (max_depth == 0) {
    return ambient;
  }

  float toi;
  Object collided_object;

  raycast(ray, objects, num_objects, &toi, &collided_object);

  if (toi == HUGE_VALF) {
    return ambient;
  }

  float3 emitted = (float3)(collided_object.emittance);

  float3 collision_point = ray.origin + toi*ray.direction;
  float3 normal = (collision_point - pack_float3(collided_object.center)) / collided_object.radius;

  // TODO: cos_theta < 0?
  // TODO: loop + accumulators
  Ray reflected_ray;
  {
    float cos_theta = dot(ray.direction, normal);
    const float3 reflected = 2*cos_theta*normal - ray.direction;

    const float3 y = reflected;
    // TODO: find z/x better when normal ~= reflected
    const float3 z = normalize(cross(normal, y));
    const float3 x = normalize(cross(z, y));
    do {
      reflected_ray.direction = perturb(rand_state, x, y, z);
    }
    while (dot(reflected_ray.direction, normal) < 0);

    reflected_ray.origin = collision_point + 0.1f * reflected_ray.direction;
  }

  const float r = rand(rand_state);
  float3 reflected = (float3)(0, 0, 0);
  if (r <= collided_object.reflectance) {
    reflected +=
      pathtrace(
        reflected_ray,
        max_depth - 1,
        ambient,
        rand_state,
        objects,
        num_objects
      );
  }

  return pack_float3(collided_object.color) * (ambient + emitted + reflected);
}

mwc64x_state_t init_rand_state(ulong random_seed) {
  mwc64x_state_t rand_state;
  rand_state.x = (uint)(random_seed & 0xFFFFFFFF);
  rand_state.c = (random_seed & 0xFFFFFFFF00000000) >> 32;
  return rand_state;
}

__kernel void render(
  const uint image_width,
  const uint image_height,

  const float fovy,
  float3 eye,
  const float3 look,
  const float3 up,

  ulong random_seed,
  float3 ambient_light,

  __global const float* objects,
  const uint num_objects,

  __global RGB * output)
{
  int id = get_global_id(0);

  const int x_pix = id % image_width;
  const int y_pix = id / image_width;

  float4 world_pos =
    vmult(view_to_world(eye, look, up),
    vmult(screen_to_view(image_width, image_height, fovy),
    (float4)(x_pix, y_pix, 1, 1)
  ));

  Ray ray;
  ray.origin = eye;
  ray.direction = normalize((world_pos / world_pos.w).xyz - eye);

  random_seed = random_seed * id * id;
  mwc64x_state_t rand_state = init_rand_state(random_seed);
  MWC64X_Skip(&rand_state, 20);

  output[id] = rgb(pathtrace(ray, 2, ambient_light, &rand_state, objects, num_objects));
}

#include "cl/mwc64x/cl/mwc64x.cl"

// Doesn't return 0 so that rays can bounce without bumping.
float sphere_toi(
  const float3 eye,
  const float3 look,

  const float3 center,
  const float radius)
{
  // quadratic coefficients
  float a = dot(look, look);
  float b = 2 * dot(eye - center, look);
  float3 to_center = eye - center;
  float c = dot(to_center, to_center) - radius*radius;

  // discriminant
  float d = b*b - 4*a*c;

  if (d < 0) {
    return HUGE_VALF;
  }

  float s1 = (sqrt(d) - b) / (2 * a);
  if (s1 <= 0) {
    s1 = HUGE_VALF;
  }

  float s2 = (-sqrt(d) - b) / (2 * a);
  if (s1 < s2 || s2 <= 0) {
    return s1;
  }

  return s2;
}

typedef struct {
  float4 row1;
  float4 row2;
  float4 row3;
  float4 row4;
} mat4;

float4 vmult(mat4 m, float4 v) {
  return
    (float4)(
      dot(m.row1, v),
      dot(m.row2, v),
      dot(m.row3, v),
      dot(m.row4, v)
    );
}

mat4 screen_to_view(uint w, uint h, float fovy) {
  float aspect = (float)w / (float)h;

  float b = tan(fovy / 2);
  float a = 2 * b / h;
  b = -b;

  mat4 r;
  // We divide both x and y by h, to take aspect ratio into account.
  // An increase in image width will cause wider rays to be shot.
  r.row1 = (float4)(a, 0, 0, b * aspect);
  r.row2 = (float4)(0, a, 0, b);
  r.row3 = (float4)(0, 0, 1, 0);
  r.row4 = (float4)(0, 0, 0, 1);

  return r;
}

mat4 view_to_world(float3 eye, float3 look, float3 up) {
  float4 x = (float4)(cross(look, up), 0);
  float4 y = (float4)(up, 0);
  float4 z = (float4)(look, 0);
  float4 w = (float4)(eye, 1);

  // Change of basis

  mat4 r;
  r.row1.x = x.x;
  r.row2.x = x.y;
  r.row3.x = x.z;
  r.row4.x = x.w;

  r.row1.y = y.x;
  r.row2.y = y.y;
  r.row3.y = y.z;
  r.row4.y = y.w;

  r.row1.z = z.x;
  r.row2.z = z.y;
  r.row3.z = z.z;
  r.row4.z = z.w;

  r.row1.w = w.x;
  r.row2.w = w.y;
  r.row3.w = w.z;
  r.row4.w = w.w;

  return r;
}

typedef struct {
  float r;
  float g;
  float b;
} RGB;

RGB rgb(float3 xyz) {
  RGB r;
  r.r = xyz.x;
  r.g = xyz.y;
  r.b = xyz.z;
  return r;
}

typedef struct { float x, y, z } float3_parse;

float3 pack_float3(float3_parse f) {
  return (float3)(f.x, f.y, f.z);
}

typedef struct {
  float3_parse center;
  float radius;
  float3_parse color;
  float emittance;
  float reflectance;
} Object;

float parse_float(__global const float** data) {
  float r = **data;
  ++*data;
  return r;
}

float3_parse parse_float3(__global const float** data) {
  float3_parse r;
  r.x = parse_float(data);
  r.y = parse_float(data);
  r.z = parse_float(data);
  return r;
}

Object parse_object(__global const float* data) {
  Object r;
  r.center      = parse_float3(&data);
  r.radius      = parse_float(&data);
  r.color       = parse_float3(&data);
  r.emittance   = parse_float(&data);
  r.reflectance = parse_float(&data);
  return r;
}

typedef struct {
  float3 origin;
  float3 direction;
} Ray;

void raycast(
  Ray ray,

  __global const float* objects,
  const uint num_objects,

  float* toi,
  Object* collision
) {
  *toi = HUGE_VALF;

  for (uint i = 0; i < num_objects; ++i) {
    Object object = parse_object((Object*)objects + i);
    float this_toi = sphere_toi(ray.origin, ray.direction, pack_float3(object.center), object.radius);

    if (this_toi >= *toi) {
      continue;
    }

    *toi = this_toi;
    *collision = object;
  }
}

float rand(mwc64x_state_t* rand_state) {
  return (float)MWC64X_NextUint(rand_state) / (float)UINT_MAX;
}

float3 perturb(mwc64x_state_t* rand_state, float3 x, float3 y, float3 z) {
  float3 coeffs;
  coeffs.y = 2 * (rand(rand_state) - 0.5);
  const float xz = sqrt(1 - coeffs.y * coeffs.y);
  float azimuth = rand(rand_state ) * 2 * 3.14;
  coeffs.x = cos(azimuth);
  coeffs.z = sin(azimuth);
  coeffs.x *= xz;
  coeffs.z *= xz;
  return coeffs.x*x + coeffs.y*y + coeffs.z*z;
}

float3 pathtrace(
  Ray ray,
  uint max_depth,
  float3 ambient,
  mwc64x_state_t* rand_state,
  __global const float* objects,
  const uint num_objects
) {
  if (max_depth == 0) {
    return ambient;
  }

  float toi;
  Object collided_object;

  raycast(ray, objects, num_objects, &toi, &collided_object);

  if (toi == HUGE_VALF) {
    return ambient;
  }

  float3 emitted = (float3)(collided_object.emittance);

  float3 collision_point = ray.origin + toi*ray.direction;
  float3 normal = (collision_point - pack_float3(collided_object.center)) / collided_object.radius;

  // TODO: cos_theta < 0?
  // TODO: loop + accumulators
  Ray reflected_ray;
  {
    float cos_theta = dot(ray.direction, normal);
    const float3 reflected = 2*cos_theta*normal - ray.direction;

    const float3 y = reflected;
    // TODO: find z/x better when normal ~= reflected
    const float3 z = normalize(cross(normal, y));
    const float3 x = normalize(cross(z, y));
    do {
      reflected_ray.direction = perturb(rand_state, x, y, z);
    }
    while (dot(reflected_ray.direction, normal) < 0);

    reflected_ray.origin = collision_point + 0.1f * reflected_ray.direction;
  }

  const float3 reflected =
    collided_object.reflectance *
    pathtrace(
      reflected_ray,
      max_depth - 1,
      ambient,
      rand_state,
      objects,
      num_objects
    );

  return pack_float3(collided_object.color) * (ambient + emitted + reflected);
}

mwc64x_state_t init_rand_state(ulong random_seed) {
  mwc64x_state_t rand_state;
  rand_state.x = (uint)(random_seed & 0xFFFFFFFF);
  rand_state.c = (random_seed & 0xFFFFFFFF00000000) >> 32;
  return rand_state;
}

__kernel void render(
  const uint image_width,
  const uint image_height,

  const float fovy,
  float3 eye,
  const float3 look,
  const float3 up,

  ulong random_seed,
  float3 ambient_light,

  __global const float* objects,
  const uint num_objects,

  __global RGB * output)
{
  int id = get_global_id(0);

  const int x_pix = id % image_width;
  const int y_pix = id / image_width;

  float4 world_pos =
    vmult(view_to_world(eye, look, up),
    vmult(screen_to_view(image_width, image_height, fovy),
    (float4)(x_pix, y_pix, 1, 1)
  ));

  Ray ray;
  ray.origin = eye;
  ray.direction = normalize((world_pos / world_pos.w).xyz - eye);

  random_seed = random_seed * id * id;
  mwc64x_state_t rand_state = init_rand_state(random_seed);
  MWC64X_Skip(&rand_state, 20);

  output[id] = rgb(pathtrace(ray, 2, ambient_light, &rand_state, objects, num_objects));
}


fixed compile.cl

fixed compile.cl

(defun main ()
    (load "database.cl")
    (sb-ext:save-lisp-and-die "todo" :executable t :toplevel 'main))


Fix bug in 9-point stencil increments.

Fix bug in 9-point stencil increments.

#define __NINE_STENCIL__

__constant sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_REPEAT | CLK_FILTER_NEAREST;

__kernel void calc_2d(__read_only image2d_t Phi,
					  __write_only image2d_t PhiNext,
					  const float M,
					  const float a_2,
					  const float a_4,
					  const float K,
					  const float dx,
					  const float dt)
{
	int2 coord = {get_global_id(0),get_global_id(1)};
	int2 size = {get_global_size(0),get_global_size(1)};
    float2 normalizedCoord = (float2)((float)coord.x/size.x, (float)coord.y/size.y);
//    float2 normalizedCoord = (float2)((coord.x+0.5f)/size.x, (coord.y+0.5f)/size.y);
    float incrementx = 1.0f/size.x;
    float incrementy = 1.0f/size.y;
    float4 phi = (read_imagef(Phi, sampler, normalizedCoord).x);
    float4 xm= (read_imagef(Phi,sampler,(normalizedCoord+(float2){-incrementx,0})));
    float4 xp= (read_imagef(Phi,sampler,(normalizedCoord+(float2){incrementx,0})));
    float4 ym= (read_imagef(Phi,sampler,(normalizedCoord+(float2){0,-incrementy})));
    float4 yp= (read_imagef(Phi,sampler,(normalizedCoord+(float2){0,incrementy})));
#ifndef __NINE_STENCIL__
    float4 laplacian =(xm+xp+ym+yp-4.0f*phi)/(dx*dx);  // 5-point stencil
#else
    float4 xym= (read_imagef(Phi,sampler,(normalizedCoord+(float2){-incrementx,-incrementy})));
    float4 xyp= (read_imagef(Phi,sampler,(normalizedCoord+(float2){incrementx,incrementy})));
    float4 xpym= (read_imagef(Phi,sampler,(normalizedCoord+(float2){incrementx,-incrementy})));
    float4 xmyp= (read_imagef(Phi,sampler,(normalizedCoord+(float2){-incrementx,incrementy})));

    float4 laplacian =((xm+xp+ym+yp)/2.0f + (xyp+xym+xmyp+xpym)/4.0f - 3.0f*phi)/(dx*dx); // 9-point stencil
#undef __NINE_STENCIL__
#endif
    float4 phi_next = phi + dt * M * ( 2.0f * K * laplacian - a_2 * phi - a_4 * phi * phi * phi);
    write_imagef(PhiNext,coord,phi_next);
}

#define __NINE_STENCIL__

__constant sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_REPEAT | CLK_FILTER_NEAREST;

__kernel void calc_2d(__read_only image2d_t Phi,
					  __write_only image2d_t PhiNext,
					  const float M,
					  const float a_2,
					  const float a_4,
					  const float K,
					  const float dx,
					  const float dt)
{
	int2 coord = {get_global_id(0),get_global_id(1)};
	int2 size = {get_global_size(0),get_global_size(1)};
    float2 normalizedCoord = (float2)((float)coord.x/size.x, (float)coord.y/size.y);
//    float2 normalizedCoord = (float2)((coord.x+0.5f)/size.x, (coord.y+0.5f)/size.y);
    float incrementx = 1.0f/size.x;
    float incrementy = 1.0f/size.y;
    float4 phi = (read_imagef(Phi, sampler, normalizedCoord).x);
    float4 xm= (read_imagef(Phi,sampler,(normalizedCoord+(float2){-incrementx,0})));
    float4 xp= (read_imagef(Phi,sampler,(normalizedCoord+(float2){incrementx,0})));
    float4 ym= (read_imagef(Phi,sampler,(normalizedCoord+(float2){0,-incrementy})));
    float4 yp= (read_imagef(Phi,sampler,(normalizedCoord+(float2){0,incrementy})));
#ifndef __NINE_STENCIL__
    float4 laplacian =(xm+xp+ym+yp-4.0f*phi)/(dx*dx);  // 5-point stencil
#else
    float4 xym= (read_imagef(Phi,sampler,(normalizedCoord+(float2){-incrementx,-incrementx})));
    float4 xyp= (read_imagef(Phi,sampler,(normalizedCoord+(float2){incrementx,incrementx})));
    float4 xpym= (read_imagef(Phi,sampler,(normalizedCoord+(float2){incrementx,-incrementy})));
    float4 xmyp= (read_imagef(Phi,sampler,(normalizedCoord+(float2){-incrementx,incrementy})));

    float4 laplacian =((xm+xp+ym+yp)/2.0f + (xyp+xym+xmyp+xpym)/4.0f - 3.0f*phi)/(dx*dx); // 9-point stencil
#undef __NINE_STENCIL__
#endif
    float4 phi_next = phi + dt * M * ( 2.0f * K * laplacian - a_2 * phi - a_4 * phi * phi * phi);
    write_imagef(PhiNext,coord,phi_next);
}


fix some mismatch on cpu device running OCL

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

#define ROWSperTHREAD 21     // the number of rows a thread will process
#define BLOCK_W       128    // the thread block width (464)
#define N_DISPARITIES 8

#define STEREO_MIND 0                    // The minimum d range to check
#define STEREO_DISP_STEP N_DISPARITIES   // the d step, must be <= 1 to avoid aliasing

int SQ(int a)
{
    return a * a;
}

unsigned int CalcSSD(volatile __local unsigned int *col_ssd_cache,
                     volatile __local unsigned int *col_ssd, int radius)
{
    unsigned int cache = 0;
    unsigned int cache2 = 0;

    for(int i = 1; i <= radius; i++)
        cache += col_ssd[i];

    col_ssd_cache[0] = cache;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (get_local_id(0) < BLOCK_W - radius)
        cache2 = col_ssd_cache[radius];
    else
        for(int i = radius + 1; i < (2 * radius + 1); i++)
            cache2 += col_ssd[i];

    return col_ssd[0] + cache + cache2;
}

uint2 MinSSD(volatile __local unsigned int *col_ssd_cache,
             volatile __local unsigned int *col_ssd, int radius)
{
    unsigned int ssd[N_DISPARITIES];

    //See above:  #define COL_SSD_SIZE (BLOCK_W + 2 * radius)
    ssd[0] = CalcSSD(col_ssd_cache, col_ssd + 0 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[1] = CalcSSD(col_ssd_cache, col_ssd + 1 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[2] = CalcSSD(col_ssd_cache, col_ssd + 2 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[3] = CalcSSD(col_ssd_cache, col_ssd + 3 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[4] = CalcSSD(col_ssd_cache, col_ssd + 4 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[5] = CalcSSD(col_ssd_cache, col_ssd + 5 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[6] = CalcSSD(col_ssd_cache, col_ssd + 6 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[7] = CalcSSD(col_ssd_cache, col_ssd + 7 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);

    unsigned int mssd = min(min(min(ssd[0], ssd[1]), min(ssd[4], ssd[5])), min(min(ssd[2], ssd[3]), min(ssd[6], ssd[7])));

    int bestIdx = 0;
    for (int i = 0; i < N_DISPARITIES; i++)
    {
        if (mssd == ssd[i])
            bestIdx = i;
    }

    return (uint2)(mssd, bestIdx);
}

void StepDown(int idx1, int idx2, __global unsigned char* imageL,
              __global unsigned char* imageR, int d, volatile  __local unsigned int *col_ssd, int radius)
{
    unsigned char leftPixel1;
    unsigned char leftPixel2;
    unsigned char rightPixel1[8];
    unsigned char rightPixel2[8];
    unsigned int diff1, diff2;

    leftPixel1 = imageL[idx1];
    leftPixel2 = imageL[idx2];

    idx1 = idx1 - d;
    idx2 = idx2 - d;

    rightPixel1[7] = imageR[idx1 - 7];
    rightPixel1[0] = imageR[idx1 - 0];
    rightPixel1[1] = imageR[idx1 - 1];
    rightPixel1[2] = imageR[idx1 - 2];
    rightPixel1[3] = imageR[idx1 - 3];
    rightPixel1[4] = imageR[idx1 - 4];
    rightPixel1[5] = imageR[idx1 - 5];
    rightPixel1[6] = imageR[idx1 - 6];

    rightPixel2[7] = imageR[idx2 - 7];
    rightPixel2[0] = imageR[idx2 - 0];
    rightPixel2[1] = imageR[idx2 - 1];
    rightPixel2[2] = imageR[idx2 - 2];
    rightPixel2[3] = imageR[idx2 - 3];
    rightPixel2[4] = imageR[idx2 - 4];
    rightPixel2[5] = imageR[idx2 - 5];
    rightPixel2[6] = imageR[idx2 - 6];

    //See above:  #define COL_SSD_SIZE (BLOCK_W + 2 * radius)
    diff1 = leftPixel1 - rightPixel1[0];
    diff2 = leftPixel2 - rightPixel2[0];
    col_ssd[0 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[1];
    diff2 = leftPixel2 - rightPixel2[1];
    col_ssd[1 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[2];
    diff2 = leftPixel2 - rightPixel2[2];
    col_ssd[2 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[3];
    diff2 = leftPixel2 - rightPixel2[3];
    col_ssd[3 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[4];
    diff2 = leftPixel2 - rightPixel2[4];
    col_ssd[4 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[5];
    diff2 = leftPixel2 - rightPixel2[5];
    col_ssd[5 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[6];
    diff2 = leftPixel2 - rightPixel2[6];
    col_ssd[6 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[7];
    diff2 = leftPixel2 - rightPixel2[7];
    col_ssd[7 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);
}

void InitColSSD(int x_tex, int y_tex, int im_pitch, __global unsigned char* imageL,
                __global unsigned char* imageR, int d,
                volatile __local unsigned int *col_ssd, int radius)
{
    unsigned char leftPixel1;
    int idx;
    unsigned int diffa[] = {0, 0, 0, 0, 0, 0, 0, 0};

    for(int i = 0; i < (2 * radius + 1); i++)
    {
        idx = y_tex * im_pitch + x_tex;
        leftPixel1 = imageL[idx];
        idx = idx - d;

        diffa[0] += SQ(leftPixel1 - imageR[idx - 0]);
        diffa[1] += SQ(leftPixel1 - imageR[idx - 1]);
        diffa[2] += SQ(leftPixel1 - imageR[idx - 2]);
        diffa[3] += SQ(leftPixel1 - imageR[idx - 3]);
        diffa[4] += SQ(leftPixel1 - imageR[idx - 4]);
        diffa[5] += SQ(leftPixel1 - imageR[idx - 5]);
        diffa[6] += SQ(leftPixel1 - imageR[idx - 6]);
        diffa[7] += SQ(leftPixel1 - imageR[idx - 7]);

        y_tex += 1;
    }
    //See above:  #define COL_SSD_SIZE (BLOCK_W + 2 * radius)
    col_ssd[0 * (BLOCK_W + 2 * radius)] = diffa[0];
    col_ssd[1 * (BLOCK_W + 2 * radius)] = diffa[1];
    col_ssd[2 * (BLOCK_W + 2 * radius)] = diffa[2];
    col_ssd[3 * (BLOCK_W + 2 * radius)] = diffa[3];
    col_ssd[4 * (BLOCK_W + 2 * radius)] = diffa[4];
    col_ssd[5 * (BLOCK_W + 2 * radius)] = diffa[5];
    col_ssd[6 * (BLOCK_W + 2 * radius)] = diffa[6];
    col_ssd[7 * (BLOCK_W + 2 * radius)] = diffa[7];
}

__kernel void stereoKernel(__global unsigned char *left, __global unsigned char *right,
                           __global unsigned int *cminSSDImage, int cminSSD_step,
                           __global unsigned char *disp, int disp_step,int cwidth, int cheight,
                           int img_step, int maxdisp, int radius,
                           __local unsigned int *col_ssd_cache)
{

    volatile __local unsigned int *col_ssd = col_ssd_cache + BLOCK_W + get_local_id(0);
    volatile __local unsigned int *col_ssd_extra = get_local_id(0) < (2 * radius) ? col_ssd + BLOCK_W : 0;

    int X = get_group_id(0) * BLOCK_W + get_local_id(0) + maxdisp + radius;
    // int Y = get_group_id(1) * ROWSperTHREAD + radius;

#define Y (get_group_id(1) * ROWSperTHREAD + radius)

    volatile __global unsigned int* minSSDImage = cminSSDImage + X + Y * cminSSD_step;
    __global unsigned char* disparImage = disp + X + Y * disp_step;

    int end_row = ROWSperTHREAD < (cheight - Y) ? ROWSperTHREAD:(cheight - Y);
    int y_tex;
    int x_tex = X - radius;

    if (x_tex >= cwidth)
        return;

    for(int d = STEREO_MIND; d < maxdisp; d += STEREO_DISP_STEP)
    {
        y_tex = Y - radius;

        InitColSSD(x_tex, y_tex, img_step, left, right, d, col_ssd, radius);
        if (col_ssd_extra > 0)
            if (x_tex + BLOCK_W < cwidth)
                InitColSSD(x_tex + BLOCK_W, y_tex, img_step, left, right, d, col_ssd_extra, radius);

        barrier(CLK_LOCAL_MEM_FENCE); //before MinSSD function

        uint2 minSSD = MinSSD(col_ssd_cache + get_local_id(0), col_ssd, radius);
        if (X < cwidth - radius && Y < cheight - radius)
        {
            if (minSSD.x < minSSDImage[0])
            {
                disparImage[0] = (unsigned char)(d + minSSD.y);
                minSSDImage[0] = minSSD.x;
            }
        }

        for(int row = 1; row < end_row; row++)
        {
            int idx1 = y_tex * img_step + x_tex;
            int idx2 = min(y_tex + (2 * radius + 1), cheight - 1) * img_step + x_tex;

            barrier(CLK_GLOBAL_MEM_FENCE);
            barrier(CLK_LOCAL_MEM_FENCE);

            StepDown(idx1, idx2, left, right, d, col_ssd, radius);
            if (col_ssd_extra > 0)
                if (x_tex + BLOCK_W < cwidth)
                    StepDown(idx1, idx2, left + BLOCK_W, right + BLOCK_W, d, col_ssd_extra, radius);

            y_tex += 1;

            barrier(CLK_LOCAL_MEM_FENCE);

            uint2 minSSD = MinSSD(col_ssd_cache + get_local_id(0), col_ssd, radius);
            if (X < cwidth - radius && row < cheight - radius - Y)
            {
                int idx = row * cminSSD_step;
                if (minSSD.x < minSSDImage[idx])
                {
                    disparImage[disp_step * row] = (unsigned char)(d + minSSD.y);
                    minSSDImage[idx] = minSSD.x;
                }
            }
        } // for row loop
    } // for d loop
}

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Sobel Prefiler (signal channel)//////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////

__kernel void prefilter_xsobel(__global unsigned char *input, __global unsigned char *output,
                               int rows, int cols, int prefilterCap)
{
    int x = get_global_id(0);
    int y = get_global_id(1);

    if(x < cols && y < rows)
    {
        int cov = input[(y-1) * cols + (x-1)] * (-1) + input[(y-1) * cols + (x+1)] * (1) +
                  input[(y)   * cols + (x-1)] * (-2) + input[(y)   * cols + (x+1)] * (2) +
                  input[(y+1) * cols + (x-1)] * (-1) + input[(y+1) * cols + (x+1)] * (1);

        cov = min(min(max(-prefilterCap, cov), prefilterCap) + prefilterCap, 255);
        output[y * cols + x] = cov & 0xFF;
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Textureness filtering ////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////

float sobel(__global unsigned char *input, int x, int y, int rows, int cols)
{
    float conv = 0;
    int y1 = y==0? 0 : y-1;
    int x1 = x==0? 0 : x-1;
    if(x < cols && y < rows && x > 0 && y > 0)
    {
        conv = (float)input[(y1)  * cols + (x1)] * (-1) + (float)input[(y1)  * cols + (x+1)] * (1) +
               (float)input[(y)   * cols + (x1)] * (-2) + (float)input[(y)   * cols + (x+1)] * (2) +
               (float)input[(y+1) * cols + (x1)] * (-1) + (float)input[(y+1) * cols + (x+1)] * (1);

    }
    return fabs(conv);
}

float CalcSums(__local float *cols, __local float *cols_cache, int winsz)
{
    float cache = 0;
    float cache2 = 0;
    int winsz2 = winsz/2;

    int x = get_local_id(0);
    int group_size_x = get_local_size(0);

    for(int i = 1; i <= winsz2; i++)
        cache += cols[i];

    cols_cache[0] = cache;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (x < group_size_x - winsz2)
        cache2 = cols_cache[winsz2];
    else
        for(int i = winsz2 + 1; i < winsz; i++)
            cache2 += cols[i];

    return cols[0] + cache + cache2;
}

#define RpT (2 * ROWSperTHREAD)  // got experimentally
__kernel void textureness_kernel(__global unsigned char *disp, int disp_rows, int disp_cols,
                                 int disp_step, __global unsigned char *input, int input_rows,
                                 int input_cols,int winsz, float threshold,
                                 __local float *cols_cache)
{
    int winsz2 = winsz/2;
    int n_dirty_pixels = (winsz2) * 2;

    int local_id_x = get_local_id(0);
    int group_size_x = get_local_size(0);
    int group_id_y = get_group_id(1);

    __local float *cols = cols_cache + group_size_x + local_id_x;
    __local float *cols_extra = local_id_x < n_dirty_pixels ? cols + group_size_x : 0;

    int x = get_global_id(0);
    int beg_row = group_id_y * RpT;
    int end_row = min(beg_row + RpT, disp_rows);

//   if (x < disp_cols)
//   {
    int y = beg_row;

    float sum = 0;
    float sum_extra = 0;

    for(int i = y - winsz2; i <= y + winsz2; ++i)
    {
        sum += sobel(input, x - winsz2, i, input_rows, input_cols);
        if (cols_extra)
            sum_extra += sobel(input, x + group_size_x - winsz2, i, input_rows, input_cols);
    }
    *cols = sum;
    if (cols_extra)
        *cols_extra = sum_extra;

    barrier(CLK_LOCAL_MEM_FENCE);

    float sum_win = CalcSums(cols, cols_cache + local_id_x, winsz) * 255;
    if (sum_win < threshold)
        disp[y * disp_step + x] = 0;

    barrier(CLK_LOCAL_MEM_FENCE);

    for(int y = beg_row + 1; y < end_row; ++y)
    {
        sum = sum - sobel(input, x - winsz2, y - winsz2 - 1, input_rows, input_cols) +
              sobel(input, x - winsz2, y + winsz2, input_rows, input_cols);
        *cols = sum;

        if (cols_extra)
        {
            sum_extra = sum_extra - sobel(input, x + group_size_x - winsz2, y - winsz2 - 1,input_rows, input_cols)
                        + sobel(input, x + group_size_x - winsz2, y + winsz2, input_rows, input_cols);
            *cols_extra = sum_extra;
        }

        barrier(CLK_LOCAL_MEM_FENCE);
        float sum_win = CalcSums(cols, cols_cache + local_id_x, winsz) * 255;
        if (sum_win < threshold)
            disp[y * disp_step + x] = 0;

        barrier(CLK_LOCAL_MEM_FENCE);
    }
    //  }
}

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

#define ROWSperTHREAD 21     // the number of rows a thread will process
#define BLOCK_W       128    // the thread block width (464)
#define N_DISPARITIES 8

#define STEREO_MIND 0                    // The minimum d range to check
#define STEREO_DISP_STEP N_DISPARITIES   // the d step, must be <= 1 to avoid aliasing

int SQ(int a)
{
    return a * a;
}

unsigned int CalcSSD(volatile __local unsigned int *col_ssd_cache,
                     volatile __local unsigned int *col_ssd, int radius)
{
    unsigned int cache = 0;
    unsigned int cache2 = 0;

    for(int i = 1; i <= radius; i++)
        cache += col_ssd[i];

    col_ssd_cache[0] = cache;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (get_local_id(0) < BLOCK_W - radius)
        cache2 = col_ssd_cache[radius];
    else
        for(int i = radius + 1; i < (2 * radius + 1); i++)
            cache2 += col_ssd[i];

    return col_ssd[0] + cache + cache2;
}

uint2 MinSSD(volatile __local unsigned int *col_ssd_cache,
             volatile __local unsigned int *col_ssd, int radius)
{
    unsigned int ssd[N_DISPARITIES];

    //See above:  #define COL_SSD_SIZE (BLOCK_W + 2 * radius)
    ssd[0] = CalcSSD(col_ssd_cache, col_ssd + 0 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[1] = CalcSSD(col_ssd_cache, col_ssd + 1 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[2] = CalcSSD(col_ssd_cache, col_ssd + 2 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[3] = CalcSSD(col_ssd_cache, col_ssd + 3 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[4] = CalcSSD(col_ssd_cache, col_ssd + 4 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[5] = CalcSSD(col_ssd_cache, col_ssd + 5 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[6] = CalcSSD(col_ssd_cache, col_ssd + 6 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);
    ssd[7] = CalcSSD(col_ssd_cache, col_ssd + 7 * (BLOCK_W + 2 * radius), radius);
    barrier(CLK_LOCAL_MEM_FENCE);

    unsigned int mssd = min(min(min(ssd[0], ssd[1]), min(ssd[4], ssd[5])), min(min(ssd[2], ssd[3]), min(ssd[6], ssd[7])));

    int bestIdx = 0;
    for (int i = 0; i < N_DISPARITIES; i++)
    {
        if (mssd == ssd[i])
            bestIdx = i;
    }

    return (uint2)(mssd, bestIdx);
}

void StepDown(int idx1, int idx2, __global unsigned char* imageL,
              __global unsigned char* imageR, int d, volatile  __local unsigned int *col_ssd, int radius)
{
    unsigned char leftPixel1;
    unsigned char leftPixel2;
    unsigned char rightPixel1[8];
    unsigned char rightPixel2[8];
    unsigned int diff1, diff2;

    leftPixel1 = imageL[idx1];
    leftPixel2 = imageL[idx2];

    idx1 = idx1 - d;
    idx2 = idx2 - d;

    rightPixel1[7] = imageR[idx1 - 7];
    rightPixel1[0] = imageR[idx1 - 0];
    rightPixel1[1] = imageR[idx1 - 1];
    rightPixel1[2] = imageR[idx1 - 2];
    rightPixel1[3] = imageR[idx1 - 3];
    rightPixel1[4] = imageR[idx1 - 4];
    rightPixel1[5] = imageR[idx1 - 5];
    rightPixel1[6] = imageR[idx1 - 6];

    rightPixel2[7] = imageR[idx2 - 7];
    rightPixel2[0] = imageR[idx2 - 0];
    rightPixel2[1] = imageR[idx2 - 1];
    rightPixel2[2] = imageR[idx2 - 2];
    rightPixel2[3] = imageR[idx2 - 3];
    rightPixel2[4] = imageR[idx2 - 4];
    rightPixel2[5] = imageR[idx2 - 5];
    rightPixel2[6] = imageR[idx2 - 6];

    //See above:  #define COL_SSD_SIZE (BLOCK_W + 2 * radius)
    diff1 = leftPixel1 - rightPixel1[0];
    diff2 = leftPixel2 - rightPixel2[0];
    col_ssd[0 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[1];
    diff2 = leftPixel2 - rightPixel2[1];
    col_ssd[1 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[2];
    diff2 = leftPixel2 - rightPixel2[2];
    col_ssd[2 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[3];
    diff2 = leftPixel2 - rightPixel2[3];
    col_ssd[3 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[4];
    diff2 = leftPixel2 - rightPixel2[4];
    col_ssd[4 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[5];
    diff2 = leftPixel2 - rightPixel2[5];
    col_ssd[5 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[6];
    diff2 = leftPixel2 - rightPixel2[6];
    col_ssd[6 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);

    diff1 = leftPixel1 - rightPixel1[7];
    diff2 = leftPixel2 - rightPixel2[7];
    col_ssd[7 * (BLOCK_W + 2 * radius)] += SQ(diff2) - SQ(diff1);
}

void InitColSSD(int x_tex, int y_tex, int im_pitch, __global unsigned char* imageL,
                __global unsigned char* imageR, int d,
                volatile __local unsigned int *col_ssd, int radius)
{
    unsigned char leftPixel1;
    int idx;
    unsigned int diffa[] = {0, 0, 0, 0, 0, 0, 0, 0};

    for(int i = 0; i < (2 * radius + 1); i++)
    {
        idx = y_tex * im_pitch + x_tex;
        leftPixel1 = imageL[idx];
        idx = idx - d;

        diffa[0] += SQ(leftPixel1 - imageR[idx - 0]);
        diffa[1] += SQ(leftPixel1 - imageR[idx - 1]);
        diffa[2] += SQ(leftPixel1 - imageR[idx - 2]);
        diffa[3] += SQ(leftPixel1 - imageR[idx - 3]);
        diffa[4] += SQ(leftPixel1 - imageR[idx - 4]);
        diffa[5] += SQ(leftPixel1 - imageR[idx - 5]);
        diffa[6] += SQ(leftPixel1 - imageR[idx - 6]);
        diffa[7] += SQ(leftPixel1 - imageR[idx - 7]);

        y_tex += 1;
    }
    //See above:  #define COL_SSD_SIZE (BLOCK_W + 2 * radius)
    col_ssd[0 * (BLOCK_W + 2 * radius)] = diffa[0];
    col_ssd[1 * (BLOCK_W + 2 * radius)] = diffa[1];
    col_ssd[2 * (BLOCK_W + 2 * radius)] = diffa[2];
    col_ssd[3 * (BLOCK_W + 2 * radius)] = diffa[3];
    col_ssd[4 * (BLOCK_W + 2 * radius)] = diffa[4];
    col_ssd[5 * (BLOCK_W + 2 * radius)] = diffa[5];
    col_ssd[6 * (BLOCK_W + 2 * radius)] = diffa[6];
    col_ssd[7 * (BLOCK_W + 2 * radius)] = diffa[7];
}

__kernel void stereoKernel(__global unsigned char *left, __global unsigned char *right,
                           __global unsigned int *cminSSDImage, int cminSSD_step,
                           __global unsigned char *disp, int disp_step,int cwidth, int cheight,
                           int img_step, int maxdisp, int radius,
                           __local unsigned int *col_ssd_cache)
{

    volatile __local unsigned int *col_ssd = col_ssd_cache + BLOCK_W + get_local_id(0);
    volatile __local unsigned int *col_ssd_extra = get_local_id(0) < (2 * radius) ? col_ssd + BLOCK_W : 0;

    int X = get_group_id(0) * BLOCK_W + get_local_id(0) + maxdisp + radius;
   // int Y = get_group_id(1) * ROWSperTHREAD + radius;

    #define Y (get_group_id(1) * ROWSperTHREAD + radius)

    volatile __global unsigned int* minSSDImage = cminSSDImage + X + Y * cminSSD_step;
    __global unsigned char* disparImage = disp + X + Y * disp_step;

    int end_row = ROWSperTHREAD < (cheight - Y) ? ROWSperTHREAD:(cheight - Y);
    int y_tex;
    int x_tex = X - radius;

    if (x_tex >= cwidth)
        return;

    for(int d = STEREO_MIND; d < maxdisp; d += STEREO_DISP_STEP)
    {
        y_tex = Y - radius;

        InitColSSD(x_tex, y_tex, img_step, left, right, d, col_ssd, radius);
        if (col_ssd_extra > 0)
            if (x_tex + BLOCK_W < cwidth)
                InitColSSD(x_tex + BLOCK_W, y_tex, img_step, left, right, d, col_ssd_extra, radius);

        barrier(CLK_LOCAL_MEM_FENCE); //before MinSSD function

        if (X < cwidth - radius && Y < cheight - radius)
        {
            uint2 minSSD = MinSSD(col_ssd_cache + get_local_id(0), col_ssd, radius);
            if (minSSD.x < minSSDImage[0])
            {
                disparImage[0] = (unsigned char)(d + minSSD.y);
                minSSDImage[0] = minSSD.x;
            }
        }

        for(int row = 1; row < end_row; row++)
        {
            int idx1 = y_tex * img_step + x_tex;
            int idx2 = (y_tex + (2 * radius + 1)) * img_step + x_tex;

            barrier(CLK_GLOBAL_MEM_FENCE);
            barrier(CLK_LOCAL_MEM_FENCE);

            StepDown(idx1, idx2, left, right, d, col_ssd, radius);
            if (col_ssd_extra > 0)
                if (x_tex + BLOCK_W < cwidth)
                    StepDown(idx1, idx2, left + BLOCK_W, right + BLOCK_W, d, col_ssd_extra, radius);

            y_tex += 1;

            barrier(CLK_LOCAL_MEM_FENCE);

            if (X < cwidth - radius && row < cheight - radius - Y)
            {
                int idx = row * cminSSD_step;
                uint2 minSSD = MinSSD(col_ssd_cache + get_local_id(0), col_ssd, radius);
                if (minSSD.x < minSSDImage[idx])
                {
                    disparImage[disp_step * row] = (unsigned char)(d + minSSD.y);
                    minSSDImage[idx] = minSSD.x;
                }
            }
        } // for row loop
    } // for d loop
}

//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Sobel Prefiler (signal channel)//////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////

__kernel void prefilter_xsobel(__global unsigned char *input, __global unsigned char *output,
                               int rows, int cols, int prefilterCap)
{
    int x = get_global_id(0);
    int y = get_global_id(1);

    if(x < cols && y < rows)
    {
        int cov = input[(y-1) * cols + (x-1)] * (-1) + input[(y-1) * cols + (x+1)] * (1) +
                  input[(y)   * cols + (x-1)] * (-2) + input[(y)   * cols + (x+1)] * (2) +
                  input[(y+1) * cols + (x-1)] * (-1) + input[(y+1) * cols + (x+1)] * (1);

        cov = min(min(max(-prefilterCap, cov), prefilterCap) + prefilterCap, 255);
        output[y * cols + x] = cov & 0xFF;
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// Textureness filtering ////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////

float sobel(__global unsigned char *input, int x, int y, int rows, int cols)
{
    float conv = 0;
    int y1 = y==0? 0 : y-1;
    int x1 = x==0? 0 : x-1;
    if(x < cols && y < rows && x > 0 && y > 0)
    {
        conv = (float)input[(y1)  * cols + (x1)] * (-1) + (float)input[(y1)  * cols + (x+1)] * (1) +
               (float)input[(y)   * cols + (x1)] * (-2) + (float)input[(y)   * cols + (x+1)] * (2) +
               (float)input[(y+1) * cols + (x1)] * (-1) + (float)input[(y+1) * cols + (x+1)] * (1);

    }
    return fabs(conv);
}

float CalcSums(__local float *cols, __local float *cols_cache, int winsz)
{
    float cache = 0;
    float cache2 = 0;
    int winsz2 = winsz/2;

    int x = get_local_id(0);
    int group_size_x = get_local_size(0);

    for(int i = 1; i <= winsz2; i++)
        cache += cols[i];

    cols_cache[0] = cache;

    barrier(CLK_LOCAL_MEM_FENCE);

    if (x < group_size_x - winsz2)
        cache2 = cols_cache[winsz2];
    else
        for(int i = winsz2 + 1; i < winsz; i++)
            cache2 += cols[i];

    return cols[0] + cache + cache2;
}

#define RpT (2 * ROWSperTHREAD)  // got experimentally
__kernel void textureness_kernel(__global unsigned char *disp, int disp_rows, int disp_cols,
                                 int disp_step, __global unsigned char *input, int input_rows,
                                 int input_cols,int winsz, float threshold,
                                 __local float *cols_cache)
{
    int winsz2 = winsz/2;
    int n_dirty_pixels = (winsz2) * 2;

    int local_id_x = get_local_id(0);
    int group_size_x = get_local_size(0);
    int group_id_y = get_group_id(1);

    __local float *cols = cols_cache + group_size_x + local_id_x;
    __local float *cols_extra = local_id_x < n_dirty_pixels ? cols + group_size_x : 0;

    int x = get_global_id(0);
    int beg_row = group_id_y * RpT;
    int end_row = min(beg_row + RpT, disp_rows);

 //   if (x < disp_cols)
 //   {
        int y = beg_row;

        float sum = 0;
        float sum_extra = 0;

        for(int i = y - winsz2; i <= y + winsz2; ++i)
        {
            sum += sobel(input, x - winsz2, i, input_rows, input_cols);
            if (cols_extra)
                sum_extra += sobel(input, x + group_size_x - winsz2, i, input_rows, input_cols);
        }
        *cols = sum;
        if (cols_extra)
            *cols_extra = sum_extra;

        barrier(CLK_LOCAL_MEM_FENCE);

        float sum_win = CalcSums(cols, cols_cache + local_id_x, winsz) * 255;
        if (sum_win < threshold)
            disp[y * disp_step + x] = 0;

        barrier(CLK_LOCAL_MEM_FENCE);

        for(int y = beg_row + 1; y < end_row; ++y)
        {
            sum = sum - sobel(input, x - winsz2, y - winsz2 - 1, input_rows, input_cols) +
                  sobel(input, x - winsz2, y + winsz2, input_rows, input_cols);
            *cols = sum;

            if (cols_extra)
            {
                sum_extra = sum_extra - sobel(input, x + group_size_x - winsz2, y - winsz2 - 1,input_rows, input_cols)
                            + sobel(input, x + group_size_x - winsz2, y + winsz2, input_rows, input_cols);
                *cols_extra = sum_extra;
            }

            barrier(CLK_LOCAL_MEM_FENCE);
            float sum_win = CalcSums(cols, cols_cache + local_id_x, winsz) * 255;
            if (sum_win < threshold)
                disp[y * disp_step + x] = 0;

            barrier(CLK_LOCAL_MEM_FENCE);
        }
  //  }
}


fixed float -> float3 in a kernel

fixed float -> float3 in a kernel

R"(

__constant const float G = 6.67408e-11f * 1e10f;
__constant const float Geps = 1e-1f;

static float3 grav_accel(float3 delta, float mass) {
	float l = length(delta);
	float d = l*l + Geps * Geps;

	return (float)-G * mass / d / l * delta;
}

__kernel void gr_step(
		const int N,
		const float dt,
		const float ratio,

		__global const float3 *p0,
		__global const float3 *v0,
		__global const float3 *p1,
		__global const float3 *v1,

		__global const float *m,
		__global const uchar *active,

		__global float3 *p2,
		__global float3 *v2,
		__global float3 *va,
		__global float3 *aa
		) {

	const int i = get_global_id(0);

	if(i >= N) return;
	if(!active[i]) return;

	float3 pos = p1[i];

	float3 acc = (float3)(.0f, .0f, .0f);
	for(int j = 0; j < N; j++) {
		if(i == j || !active[j]) continue;

		acc += grav_accel(pos - p1[j], m[j]);
	}

	p2[i] = p0[i] + v1[i] * dt;
	v2[i] = v0[i] + acc * dt;

	va[i] += v0[i] * ratio;
	aa[i] += acc * ratio;
}

__kernel void gr_end(
		const int N,
		const float dt,
		__global const bool *active,

		__global const float3 *va,
		__global const float3 *aa,

		__global float3 *pos,
		__global float3 *vel
		) {

	const int i = get_global_id(0);

	if(i >= N) return;
	if(!active[i]) return;

	pos[i] = pos[i] + dt * va[i] / 6.0f;
	vel[i] = vel[i] + dt * aa[i] / 6.0f;
}
)"

R"(

__constant const float G = 6.67408e-11f * 1e10f;
__constant const float Geps = 1e-1f;

static float3 grav_accel(float3 delta, float mass) {
	float l = length(delta);
	float d = l*l + Geps * Geps;

	return (float)-G * mass / d / l * delta;
}

__kernel void gr_step(
		const int N,
		const float dt,
		const float ratio,

		__global const float3 *p0,
		__global const float3 *v0,
		__global const float3 *p1,
		__global const float3 *v1,

		__global const float *m,
		__global const uchar *active,

		__global float3 *p2,
		__global float3 *v2,
		__global float3 *va,
		__global float3 *aa
		) {

	const int i = get_global_id(0);

	if(i >= N) return;
	if(!active[i]) return;

	float3 pos = p1[i];

	float3 acc = (float3)(.0f, .0f, .0f);
	for(int j = 0; j < N; j++) {
		if(i == j || !active[j]) continue;

		acc += grav_accel(pos - p1[j], m[j]);
	}

	p2[i] = p0[i] + v1[i] * dt;
	v2[i] = v0[i] + acc * dt;

	va[i] += v0[i] * ratio;
	aa[i] += acc * ratio;
}

__kernel void gr_end(
		const int N,
		const float dt,
		__global const bool *active,

		__global const float *va,
		__global const float *aa,

		__global float3 *pos,
		__global float3 *vel
		) {

	const int i = get_global_id(0);

	if(i >= N) return;
	if(!active[i]) return;

	pos[i] = pos[i] + dt * va[i] / 6.0f;
	vel[i] = vel[i] + dt * aa[i] / 6.0f;
}
)"