i present to you the 150 line "HelloWorld" program in opencl. well actually it's a bit more complicated. the program takes the string "GdkknVnqkc", then adds 1 to all the ascii values, and prints the result.
here's the heavily commented main code
#include "stdafx.h" //standard something
#include <stdlib.h> //standard library
#include <string.h> //for string
#include <stdio.h> //standard input and output
#include <iostream> //input output stream
#include <string> //also for string
#include <fstream> //file stream
#include <CL/cl.h> //for opencl
using namespace std; //we don't have to type std every time
int convertToString(const char *filename, string& s){
//filename is the name of the file
//s the address of the string
size_t size; //an unsigned long long int that contains size of object
char * str; //initialize pointer str
fstream f(filename, (fstream::in | fstream::binary));
//make f a file object with the filename and mode is input and binary
if(f.is_open()){ // if file opened
size_t fileSize; //unsigned long long int that contains size of file object
f.seekg(0, fstream::end); //go to the end of the file, then offset by zero
size = (size_t)f.tellg(); //get the current position, convert it to type size_t, store in size
fileSize = size; //set filesize equal to size
f.seekg(0, fstream::beg); //go back to beginning of file and offset by zero
str = new char[size+1]; //initialize array of characters just big enough to store the file
if(!str){ //if the array is empty
f.close(); //close the file
return 0; //signifies success
}else{ //if the array is not empty
f.read(str, fileSize); //read the file until the end, store it in the char array
f.close(); //close the file
str[size] = '\0'; //set the last character to 0, termiating the string
s = str; //put the character array into s
delete[] str; //delete str, saves memory
return 0;//success
}
}else{ //the file did not open
return 1; //1 signifies failure
}
}
int main(){ //the main program or whatever
cl_uint numPlatforms; //number of platforms stored as a unsigned cl integer
cl_platform_id platform = NULL; //set the platform to none or something
cl_int status = clGetPlatformIDs(0,NULL,&numPlatforms);//get the platform id of null, assign it to numplatforms
if(status != CL_SUCCESS){ //if the platform failed
return 1; //failure
} //if it did not fail
if(numPlatforms > 0){ //if more than one platform available
cl_platform_id* platforms = (cl_platform_id* )malloc(numPlatforms* sizeof(cl_platform_id));
//allocate an array to store all the platform IDs
status = clGetPlatformIDs(numPlatforms, platforms, NULL); //put all the platforms ids into the array
platform = platforms[0]; //set the platform to the first platform found
free(platforms); //unallocate the array from before
}
cl_uint numDevices = 0; //zero devices
cl_device_id *devices; //stores device ids
status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0 , NULL, &numDevices);
//get devices of type gpu, available on platform, of type gpu, and store the number in numDevices
if(numDevices == 0){//there are no gpus
status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 0, NULL, &numDevices);
//get the devices of type cpu, available on platform, and store number in numdevices
devices = (cl_device_id*)malloc(numDevices * sizeof(cl_device_id));
//allocate an array to store all the devices
status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, numDevices, devices, NULL);
//store the devices into the devices array
}else{//there are at least 1 gpu
devices = (cl_device_id*)malloc(numDevices * sizeof(cl_device_id));
//allocate an array to store all the devices
status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, numDevices, devices, NULL);
//store all the devices into the devices array
}
cl_context context = clCreateContext(NULL,1, devices,NULL,NULL,NULL);
//create a context with one device, and pass the devices to it
cl_command_queue commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);
//create a command queue, give it the context, and the first devices
const char *filename = "HelloWorld_Kernel.cl"; //the name of the file where the kernel is stored
string sourceStr; //initialize the string that will store the code
status = convertToString(filename, sourceStr); //get the code, place it in sourceSTR
const char *source = sourceStr.c_str(); //get a pointer to the string containing the kernel
size_t sourceSize[] = {strlen(source)}; //array of length 1 containing the size of the kernel
cl_program program = clCreateProgramWithSource(context, 1, &source, sourceSize, NULL);
//now we create the program with given context, the kernel string, and the size of the kernel
status=clBuildProgram(program, 1,devices,NULL,NULL,NULL); //build the program for the device
const char* input = "GdkknVnqkc"; //initialize an object that is the same size of helloworld
size_t strlength = strlen(input); //store the size of this object
char *output = (char*) malloc(strlength + 1); //allocate an output one char bigger than input
cl_mem inputBuffer = clCreateBuffer(context, //allocate memory (a buffer)
CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR, //it is read only | copies the input
(strlength + 1) * sizeof(char), //the size enough to contain hello world
(void *) input, //and give it a pointer to the input
NULL);
cl_mem outputBuffer = clCreateBuffer(context, //allocate memory ( a buffer)
CL_MEM_WRITE_ONLY , //it is write only
(strlength + 1) * sizeof(char), //size enough to contain hello world
NULL, NULL);
cl_kernel kernel = clCreateKernel(program,"helloworld", NULL); //create the kernel object with hello world string
status = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&inputBuffer); //set the kernel's in buffer
status = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&outputBuffer); //set the kerels' out buffer
size_t global_work_size[1] = {strlength}; //use as many workers as there are characters
status = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL, global_work_size, NULL, 0, NULL, NULL);
//send the instructions to the workers using the specified command queue, kernel, and worksize
status = clEnqueueReadBuffer(commandQueue, outputBuffer, CL_TRUE, 0, strlength * sizeof(char), output, 0, NULL, NULL);
//read back in the data with command queue, the output buffer, put the memory into the output string
output[strlength] = '\0'; //add terminating character to the output
printf(output); //print the string
printf("\n");
status = clReleaseKernel(kernel); //release kernel
status = clReleaseProgram(program); //release the program object
status = clReleaseMemObject(inputBuffer); //release input buffer
status = clReleaseMemObject(outputBuffer); //release output buffer
status = clReleaseCommandQueue(commandQueue); //release command queue
status = clReleaseContext(context); //release the context
if (output != NULL){ //if the output contains a string
free(output); //remove it
output = NULL; //dereference the pointer
}
if (devices != NULL){ //if devices exist
free(devices); //free the devices
devices = NULL; //dereference the pointer
}
system("pause"); //makes sure the window doesn't close out immediately
return 0; //signifies success
}
and here's the kernel, which is used on 10 of your gpu/cpu/whatever cores
__kernel void helloworld(__global char* in, __global char* out) //make a kernel function
{
int num = get_global_id(0); //read in the id
out[num] = in[num] + 1; //get the character, add one
}