I'm having trouble with my assignment where I have to implement Conway's Game of Life using JOCL (http://jocl.org/), which is as you might've guessed OpenCL for Java
Currently it compiles fine, but the output after the kernel execution is just zeros which in this case is just the default initialization of the output array.
Edit: Even if I initialize the entire output array to 1 it still returns from the read buffer as 0s
I thought it might have been a problem in the kernel but even if it's just output[gid] = 1 it fails to modify the output array. But then I also can't see any problems with the JOCL implementation
Any advice would be deeply appreciated
Kernel:
__kernel void gameOfLife(
__global constant int *input,
__global int *output ) {
int gid = get_global_id( 0 );
int rowUp = gid - 100;
int rowDown = gid + 100;
bool offGrid = (i < 100);
offGrid |= (i >= (100 * (100 - 1)));
offGrid |= (i % 100 == 0);
offGrid |= (i % 100 == 100 - 1);
if (offGrid) {
output[gid] = 0;
return;
}
int neighbours = input[rowUp-1] + input[rowUp] + input[rowUp+1];
neighbours += input[gid-1] + input[gid+1];
neighbours += input[rowDown-1] + input[rowDown] + input[rowDown+1];
if (neighbours == 3 || ((neighbours == 2) && (input[gid] == 1))) {
output[gid] = 1;
}
else {
output[gid] = 0;
}
}
Java:
import org.jocl.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Random;
import java.util.stream.Collectors;
import static org.jocl.CL.*;
public class GOLifeOpenCL {
public static void main(String[] args) {
// TODO: Initialization
int width = 100;
int height = 100;
int cells = width * height;
int[] board = new int[cells];
int[] input = new int[cells];
int[] output = new int[cells];
final Pointer inputBoardPointer = Pointer.to(input);
final Pointer outputBoardPointer = Pointer.to(output);
cl_mem inputMem;
cl_mem outputMem;
final Random random = new Random(2015);
for (int i = 0; i < board.length; i++) {
if (random.nextBoolean()) {
board[i] = 1;
}
else {
board[i] = 0;
}
}
for (int i = 0; i < board.length; i++) {
System.out.print(board[i]);
}
System.arraycopy(board, 0, input, 0, board.length);
PrintBoard(board, width, height);
// TODO: Set up platform, contextproperties, device, context, commandqueue
// Number of platforms
// Finding number of platforms
// Find the platform, grab the first one
// Can utilize more platforms if has AMD + INTEL etc
final int numOfPlatforms[] = new int[ 1 ];
clGetPlatformIDs( 0, null, numOfPlatforms );
System.out.println("Platforms: " + numOfPlatforms[0]);
final cl_platform_id platforms[] = new cl_platform_id[numOfPlatforms[0]];
clGetPlatformIDs( numOfPlatforms[0], platforms, null);
final cl_platform_id platform = platforms[0];
System.out.println(platform);
final cl_context_properties contextProperties = new cl_context_properties();
contextProperties.addProperty( CL_CONTEXT_PLATFORM, platform);
int numOfDevices[] = new int[ 1 ];
clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, null, numOfDevices);
System.out.println("Devices: " + numOfDevices[0]);
final cl_device_id[] devices = new cl_device_id[numOfDevices[0]];
clGetDeviceIDs( platform, CL_DEVICE_TYPE_ALL, numOfDevices[0], devices, null);
final cl_device_id device = devices[0];
final cl_context context = clCreateContext( contextProperties, 1, new cl_device_id[]{ device }, null, null, null );
final cl_command_queue commandQueue = clCreateCommandQueue( context, device, 0, null);
// TODO: Read in kernel, compile it
// Read kernel file from resources
final String programSource = new BufferedReader( new InputStreamReader(
GOLifeOpenCL.class.getResourceAsStream( "gameOfLife.cl" )
) ).lines().parallel().collect( Collectors.joining("\n") );
final cl_program program = clCreateProgramWithSource( context, 1, new String[]{programSource}, null, null );
clBuildProgram( program, 0, null, null, null, null);
cl_kernel kernel = clCreateKernel(program, "gameOfLife", null);
// TODO: Memory objects
inputMem = clCreateBuffer( context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, Sizeof.cl_int * input.length, inputBoardPointer, null );
outputMem = clCreateBuffer( context, CL_MEM_WRITE_ONLY, Sizeof.cl_int * output.length, null, null);
//TODO: Local group size, kernel arguments
final long workGroupSize[] = new long[1];
final long oneWGS[] = new long[]{1};
Pointer workGroupSizePointer = Pointer.to(workGroupSize);
clGetKernelWorkGroupInfo(kernel, device, CL_KERNEL_WORK_GROUP_SIZE, Sizeof.cl_long, workGroupSizePointer, null);
clSetKernelArg(kernel, 0, Sizeof.cl_mem, Pointer.to(inputMem));
clSetKernelArg(kernel, 1, Sizeof.cl_mem, Pointer.to(outputMem));
long[] boardLen = new long[1];
boardLen[0] = input.length;
//clEnqueueWriteBuffer(commandQueue, inputMem, CL_TRUE, 0, cells * Sizeof.cl_int, inputBoardPointer, 0, null, null);
//TODO: Execute kernel on cells
clEnqueueNDRangeKernel( commandQueue, kernel, 1, null, new long[]{100*100}, oneWGS, 0, null, null);
//TODO: Read results from output
int err;
err = clEnqueueReadBuffer( commandQueue, outputMem, CL_TRUE, 0, cells * Sizeof.cl_int, outputBoardPointer , 0, null,null);
if (err != CL_SUCCESS) {
System.out.println("Unable to read results");
} else if (err == CL_INVALID_COMMAND_QUEUE) {
System.out.println("Invalid Command Queue");
}
for (int i = 0; i < output.length; i++) {
System.out.print(output[i]);
}
//Copy output to input for next round and board for printing
System.arraycopy(output, 0, input, 0, output.length);
System.arraycopy(output, 0, board, 0, output.length);
PrintBoard(output, width, height);
}
private static void PrintBoard(int[] board, int width, int height) {
int i = 0;
System.out.println("Printing board...");
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (board[i++] == 1) {
System.out.print("*");
}
else {
System.out.print(" ");
}
}
System.out.println();
}
System.out.println();
System.out.println();
System.out.println();
}
}