createclbin.c 3.84 KB
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif

#define KERNEL "part4.cl"

size_t
clPutProgramBinaryToFile(
		const char * const       filename,
		const cl_program * const program)
{
	cl_int cl_status;

	cl_uint num_devices;
	cl_status = clGetProgramInfo(
			*program,
			CL_PROGRAM_NUM_DEVICES,
			sizeof(cl_uint),
			&num_devices,
			NULL);

	if (cl_status != CL_SUCCESS) {
		return 0;
	}

	cl_device_id devices[num_devices];
	cl_status =
		clGetProgramInfo(
				*program,
				CL_PROGRAM_DEVICES,
				sizeof(cl_device_id) * num_devices,
				devices,
				NULL);

	if (cl_status != CL_SUCCESS) {
		return 0;
	}

	size_t binary_size[num_devices];
	cl_status =
		clGetProgramInfo(
				*program,
				CL_PROGRAM_BINARY_SIZES,
				sizeof(size_t) * num_devices,
				binary_size,
				NULL);

	if (cl_status != CL_SUCCESS) {
		return 0;
	}

	unsigned char * binaries[num_devices];
	for (cl_uint i = 0; i < num_devices; i++) {
		binaries[i] = (unsigned char *) malloc(binary_size[i]);
	}
	cl_status =
		clGetProgramInfo(
				*program,
				CL_PROGRAM_BINARIES,
				sizeof(unsigned char *) * num_devices,
				binaries,
				NULL);

	if (cl_status != CL_SUCCESS) {
		for (cl_uint i = 0; i < num_devices; i++) {
			free(binaries[i]);
		}
		return 0;
	}

	FILE * handle = fopen(filename, "wb");
	size_t size = fwrite(binaries[0], sizeof(unsigned char), binary_size[0], handle);

	for (cl_uint i = 0; i < num_devices; i++) {
		free(binaries[i]);
	}
	fclose(handle);

	return size;
}

size_t
clGetProgramFromSourceFile(
		const char * const       filename,
		const cl_context * const context,
		cl_program * const       program)
{
	/*
	 * Get a build OpenCL program from source
	 */
	FILE   * handle;
	char   * buffer;
	size_t   size;

	cl_int         cl_status;
	cl_uint        num_devices;

	// get size of kernel source
	handle = fopen(filename, "r");
	fseek(handle, 0, SEEK_END);
	size = ftell(handle);
	rewind(handle);

	// read kernel source into buffer
	buffer = (char*) malloc(size + 1);
	buffer[size] = '\0';

	if (size != fread(buffer, sizeof(char), size, handle))
	{
		fclose(handle);
		free(buffer);
		return 0;
	}

	fclose(handle);

	// create and build program
	*program = clCreateProgramWithSource(
			*context, 1, (const char**) &buffer, &size, &cl_status);

	free(buffer);

	if (cl_status != CL_SUCCESS) {
		return 0;
	}

	cl_status = clGetContextInfo(
			*context,
			CL_CONTEXT_NUM_DEVICES,
			sizeof(cl_uint),
			&num_devices,
			NULL);

	if (cl_status != CL_SUCCESS) {
		clReleaseProgram(*program);
		return 0;
	}

	cl_device_id devices[num_devices];

	cl_status = clGetContextInfo(
			*context,
			CL_CONTEXT_DEVICES,
			sizeof(cl_device_id) * num_devices,
			devices,
			NULL);

	cl_status = clBuildProgram(
			*program, 1, devices, "-Werror -cl-std=CL1.1", NULL, NULL);

	if (cl_status != CL_SUCCESS) {
		clReleaseProgram(*program);
		return 0;
	}

	return size;
}

int
clInit(cl_context * const context)
{
	/*
	 * TODO add failure handling
	 */
	cl_platform_id platform;
	cl_uint        num_devices;

	// get first available sdk and gpu and create context
	clGetPlatformIDs(1, &platform, NULL);
	clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 10, NULL, &num_devices);
	printf("%u devices during init.\n", num_devices);
	cl_device_id devices[num_devices];
	clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, num_devices, devices, NULL);
	*context = clCreateContext(NULL, num_devices, devices, NULL, NULL, NULL);

	return 0;
}

int main()
{
	cl_int     cl_status;
	cl_context context;
	cl_program program;

	size_t sourceSize;
	size_t count;

	clInit(&context);
	sourceSize =
		clGetProgramFromSourceFile(KERNEL, &context, &program);

	assert(sourceSize != 0);

	count = clPutProgramBinaryToFile(KERNEL "bin", &program);

	assert(count != 0);

	clReleaseProgram(program);
	clReleaseContext(context);

	return 0;
}

// vim: set ft=c ts=4 sw=4: