runcl

A minimal OpenCL harness for rendering images
git clone git://pollux.codes/git/runcl.git
Log | Files | Refs | README | LICENSE

commit deb6c72f2428afd5ca5c69559982073659fabbee
parent b13a64eea668fafb689305a3eae0c1c365c93216
Author: Pollux <pollux@pollux.codes>
Date:   Sun, 19 Jan 2025 13:47:20 -0600

refactor: Break up main and better error handling

Signed-off-by: Pollux <pollux@pollux.codes>

Diffstat:
Msrc/runcl.c | 300++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
1 file changed, 199 insertions(+), 101 deletions(-)

diff --git a/src/runcl.c b/src/runcl.c @@ -6,6 +6,9 @@ #define DEF_WIDTH 640 #define DEF_HEIGHT 480 +#define MAX_SRC_SIZE 1048576 +#define MAX_PLATFORM_COUNT 16 +#define MAX_PLATFORM_NAME_SIZE 256 #define STR_LITERAL(x) #x #define STRINGIFY(x) STR_LITERAL(x) @@ -20,6 +23,8 @@ struct Args { int img_width; int img_height; int platform_index; + char *source_file; + char *out_file; }; void print_help() { printf(USAGE "\n"); } @@ -52,141 +57,267 @@ int parse_args(int argc, char **argv, struct Args *out) { break; case 'H': print_help(); - return 255; + exit(0); case 'v': print_version(); - return 255; + exit(0); case '?': - fprintf(stderr, "Error parsing command-line arguments...\n"); - return 1; + return -1; } } - if (argc < optind + 2) { - fprintf(stderr, "Error parsing command-line arguments...\n"); - return 1; + if (argc < optind + 2) + return -1; + + out->source_file = argv[optind]; + out->out_file = argv[optind + 1]; + + return 0; +} + +int read_source(char *path, char *out, size_t max_size, size_t *source_size) { + + FILE *fp; + + fp = fopen(path, "r"); + if (!fp) { + return -1; + } + + *source_size = fread(out, 1, max_size, fp); + + if (!feof(fp)) { + return -1; } + fclose(fp); + return 0; } -int main(int argc, char **argv) { +int get_device(int platform_index, cl_device_id *device) { + + cl_platform_id platforms[MAX_PLATFORM_COUNT]; + cl_uint num_platforms; + cl_platform_id platform_id; + + char name[MAX_PLATFORM_NAME_SIZE]; - struct Args args; int res; - char *source_file = NULL; - char *out_file = NULL; + res = clGetPlatformIDs(MAX_PLATFORM_COUNT, platforms, &num_platforms); - int data_size_out; - float *data_out; + if (platform_index >= (int)num_platforms) { + fprintf(stderr, "Platform index exceeds number of platforms...\n"); + return -1; + } - cl_platform_id platform_id = NULL; + platform_id = platforms[platform_index]; - cl_device_id device_id = NULL; + res = clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, MAX_PLATFORM_NAME_SIZE, + name, NULL); - cl_mem out_buff; + if (res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + return -1; + } - cl_context context = NULL; - cl_command_queue command_queue = NULL; - cl_kernel kernel = NULL; - cl_program program = NULL; + printf("Platform in Use: %s\n", name); - char *source_str = NULL; - size_t source_size = 0; + res = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, device, NULL); - FILE *fp; + if (res == CL_DEVICE_NOT_FOUND) { + fprintf(stderr, "Specified platform does not provide a GPU...\n"); + return -1; + } - cl_uint platform_count = 256; - cl_platform_id *platforms; + if (res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + return -1; + } - size_t g_work_size, l_work_size; + return 0; +} + +int write_image(char *out_file, int width, int height, float *raster) { - char name[100]; - size_t name_size; + FILE *fp; png_structp png_ptr; png_infop info_ptr; png_bytep row; - res = parse_args(argc, argv, &args); + row = (png_bytep)malloc(3 * width * sizeof(png_byte)); - if (res) { - if (res == 255) { - exit(0); - } - exit(res); + fp = fopen(out_file, "wb"); + + if (!fp) { + printf("Couldn't open output file\n"); + free(row); + return -1; } - data_size_out = sizeof(float) * args.img_width * args.img_height * 3; - data_out = (float *)malloc(data_size_out); + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - platforms = malloc(platform_count * sizeof(cl_platform_id)); - row = (png_bytep)malloc(3 * args.img_width * sizeof(png_byte)); + info_ptr = png_create_info_struct(png_ptr); - source_file = argv[optind]; - out_file = argv[optind + 1]; + png_init_io(png_ptr, fp); - // Load Program Source + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); - fp = fopen(source_file, "r"); - if (!fp) { - printf("Cannot open file: %s\n", source_file); - goto error; + png_write_info(png_ptr, info_ptr); + + int x, y; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + row[x * 3 + 0] = (int)(255 * raster[3 * (y * width + x) + 0]); + row[x * 3 + 1] = (int)(255 * raster[3 * (y * width + x) + 1]); + row[x * 3 + 2] = (int)(255 * raster[3 * (y * width + x) + 2]); + } + png_write_row(png_ptr, row); } - source_str = (char *)malloc(1048576); - source_size = fread(source_str, 1, 1048576, fp); + png_write_end(png_ptr, NULL); + fclose(fp); + free(row); - // Define Vars + return 0; +} - // Get Platform & Device - clGetPlatformIDs(0, NULL, &platform_count); +int main(int argc, char **argv) { - clGetPlatformIDs(platform_count, platforms, NULL); + struct Args args; + int res; - platform_id = platforms[args.platform_index]; + float *data_out; + int data_out_size; - clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL); + cl_device_id device_id; - clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, 100, name, &name_size); + cl_mem out_buff; - printf("Platform in Use: %s\n", name); + cl_context context = NULL; + cl_command_queue command_queue = NULL; + cl_kernel kernel = NULL; + cl_program program = NULL; + + char *source_str; + size_t source_size; + + size_t g_work_size, l_work_size; + + res = parse_args(argc, argv, &args); + + if (res) { + fprintf(stderr, "Error parsing command-line arguments...\n"); + + // This is before anything has been allocated, so no cleanup is needed. + exit(1); + } + + data_out_size = sizeof(float) * args.img_width * args.img_height * 3; + + data_out = (float *)malloc(data_out_size); + source_str = (char *)malloc(MAX_SRC_SIZE * sizeof(char)); + + res = read_source(args.source_file, source_str, MAX_SRC_SIZE, &source_size); + + if (res) { + fprintf(stderr, "Error reading source file: %s", args.source_file); + goto error; + } + + // Get Platform & Device + res = get_device(args.platform_index, &device_id); + + if (res) { + goto error; + } // Create Context & Queue - context = clCreateContext(NULL, 1, &device_id, NULL, NULL, NULL); + context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &res); + + if (res == CL_DEVICE_NOT_AVAILABLE) { + fprintf(stderr, "Selected platform/device is not available..."); + goto error; + } + + if (res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + goto error; + } + command_queue = - clCreateCommandQueueWithProperties(context, device_id, 0, NULL); + clCreateCommandQueueWithProperties(context, device_id, NULL, &res); + + if (res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + goto error; + } // Create Buffers out_buff = - clCreateBuffer(context, CL_MEM_WRITE_ONLY, data_size_out, NULL, NULL); + clCreateBuffer(context, CL_MEM_WRITE_ONLY, data_out_size, NULL, &res); + + if (res == CL_INVALID_BUFFER_SIZE) { + fprintf(stderr, "Invalid buffer size: %d...", data_out_size); + } + + if (res == CL_MEM_OBJECT_ALLOCATION_FAILURE || res == CL_OUT_OF_RESOURCES || + res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + goto error; + } program = clCreateProgramWithSource(context, 1, (const char **)&source_str, - (const size_t *)&source_size, NULL); + &source_size, &res); + + if (res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + goto error; + } res = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); if (res != CL_SUCCESS) { - printf("Failed to build program!\n"); + fprintf(stderr, "Failed to build program!\n"); char build_log[16348]; clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, sizeof(build_log), build_log, NULL); - printf("Build Error: %s\n", build_log); + fprintf(stderr, "Build Error: %s\n", build_log); goto error; } kernel = clCreateKernel(program, "render", &res); if (res != CL_SUCCESS) { - printf("Error creating kernel: %d\n", res); + fprintf(stderr, "Error creating kernel: %d\n", res); goto error; } - clSetKernelArg(kernel, 0, sizeof(cl_int), (void *)&args.img_width); - clSetKernelArg(kernel, 1, sizeof(cl_int), (void *)&args.img_height); - clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&out_buff); + res = clSetKernelArg(kernel, 0, sizeof(cl_int), (void *)&args.img_width); + + if (res != CL_SUCCESS) { + fprintf(stderr, "Error setting arguments..."); + goto error; + } + + res = clSetKernelArg(kernel, 1, sizeof(cl_int), (void *)&args.img_height); + + if (res != CL_SUCCESS) { + fprintf(stderr, "Error setting arguments..."); + goto error; + } + + res = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&out_buff); + + if (res != CL_SUCCESS) { + fprintf(stderr, "Error setting arguments..."); + goto error; + } l_work_size = 128; g_work_size = @@ -200,7 +331,7 @@ int main(int argc, char **argv) { goto error; } - res = clEnqueueReadBuffer(command_queue, out_buff, CL_TRUE, 0, data_size_out, + res = clEnqueueReadBuffer(command_queue, out_buff, CL_TRUE, 0, data_out_size, (void *)data_out, 0, NULL, NULL); if (res != CL_SUCCESS) { @@ -209,38 +340,7 @@ int main(int argc, char **argv) { } // Write PNG - fp = fopen(out_file, "wb"); - - if (!fp) { - printf("Couldn't open output file\n"); - goto error; - } - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - info_ptr = png_create_info_struct(png_ptr); - - png_init_io(png_ptr, fp); - - png_set_IHDR(png_ptr, info_ptr, args.img_width, args.img_height, 8, - PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_write_info(png_ptr, info_ptr); - - int x, y; - for (y = 0; y < args.img_height; y++) { - for (x = 0; x < args.img_width; x++) { - row[x * 3 + 0] = (int)(255 * data_out[3 * (y * args.img_width + x) + 0]); - row[x * 3 + 1] = (int)(255 * data_out[3 * (y * args.img_width + x) + 1]); - row[x * 3 + 2] = (int)(255 * data_out[3 * (y * args.img_width + x) + 2]); - } - png_write_row(png_ptr, row); - } - - png_write_end(png_ptr, NULL); - - fclose(fp); + write_image(args.out_file, args.img_width, args.img_height, data_out); error: @@ -252,10 +352,8 @@ error: clReleaseCommandQueue(command_queue); clReleaseContext(context); - free(platforms); - free(source_str); free(data_out); - free(row); + free(source_str); return 0; }