home | blog | art | now | git gpg | email | rss

runcl

A minimal OpenCL harness for rendering images
git clone git://pollux.codes/git/runcl.git
Log | Files | Refs | README | LICENSE
commit 6ba78fabaf784862e891fb13b91f5434d86ecd45
parent 25cafeb7a68d7d099747e291091d0a11b9e61993
Author: Pollux <pollux@pollux.codes>
Date:   Sun,  9 Feb 2025 23:07:01 -0600

style: reformat code

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

Diffstat:
Msrc/runcl.c | 537+++++++++++++++++++++++++++++++++++++++++--------------------------------------
1 file changed, 280 insertions(+), 257 deletions(-)

diff --git a/src/runcl.c b/src/runcl.c @@ -1,4 +1,3 @@ - #define CL_TARGET_OPENCL_VERSION 300 #define USAGE \ "usage: runcl -p <platform-index> -w <image-width> -h <image-height> " \ @@ -20,340 +19,364 @@ #include <unistd.h> struct Args { - int img_width; - int img_height; - int platform_index; - char *source_file; - char *out_file; + int img_width; + int img_height; + int platform_index; + char *source_file; + char *out_file; }; -void print_help() { printf(USAGE "\n"); } +void +print_help() { + printf(USAGE "\n"); +} -void print_version() { - printf(STRINGIFY(PROG_NAME) " " STRINGIFY(VERSION) "\n"); - printf("Build: " STRINGIFY(BUILD_TYPE) "\n"); - printf("CFLAGS: " STRINGIFY(CFLAGS) "\n"); - printf("LDFLAGS: " STRINGIFY(LDFLAGS) "\n"); +void +print_version() { + printf(STRINGIFY(PROG_NAME) " " STRINGIFY(VERSION) "\n"); + printf("Build: " STRINGIFY(BUILD_TYPE) "\n"); + printf("CFLAGS: " STRINGIFY(CFLAGS) "\n"); + printf("LDFLAGS: " STRINGIFY(LDFLAGS) "\n"); } -int parse_args(int argc, char **argv, struct Args *out) { - - int arg; - - out->img_width = DEF_WIDTH; - out->img_height = DEF_HEIGHT; - out->platform_index = 0; - - while ((arg = getopt(argc, argv, "p:w:h:Hv")) != -1) { - switch (arg) { - case 'p': - out->platform_index = atoi(optarg); - break; - case 'w': - out->img_width = atoi(optarg); - break; - case 'h': - out->img_height = atoi(optarg); - break; - case 'H': - print_help(); - exit(0); - case 'v': - print_version(); - exit(0); - case '?': - return -1; - } - } - - if (argc < optind + 2) - return -1; - - out->source_file = argv[optind]; - out->out_file = argv[optind + 1]; - - return 0; +int +parse_args(int argc, char **argv, struct Args *out) { + + int arg; + + out->img_width = DEF_WIDTH; + out->img_height = DEF_HEIGHT; + out->platform_index = 0; + + while((arg = getopt(argc, argv, "p:w:h:Hv")) != -1) { + switch (arg) { + case 'p': + out->platform_index = atoi(optarg); + break; + case 'w': + out->img_width = atoi(optarg); + break; + case 'h': + out->img_height = atoi(optarg); + break; + case 'H': + print_help(); + exit(0); + case 'v': + print_version(); + exit(0); + case '?': + 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) { +int +read_source(char *path, char *out, size_t max_size, size_t *source_size) { - FILE *fp; + FILE *fp; - fp = fopen(path, "r"); - if (!fp) { - return -1; - } + fp = fopen(path, "r"); + if(!fp) { + return -1; + } - *source_size = fread(out, 1, max_size, fp); + *source_size = fread(out, 1, max_size, fp); - if (!feof(fp)) { - return -1; - } + if(!feof(fp)) { + return -1; + } - fclose(fp); + fclose(fp); - return 0; + return 0; } -int get_device(int platform_index, cl_device_id *device) { +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; + cl_platform_id platforms[MAX_PLATFORM_COUNT]; + cl_uint num_platforms; + cl_platform_id platform_id; - char name[MAX_PLATFORM_NAME_SIZE]; + char name[MAX_PLATFORM_NAME_SIZE]; - int res; + int res; - res = clGetPlatformIDs(MAX_PLATFORM_COUNT, platforms, &num_platforms); + res = clGetPlatformIDs(MAX_PLATFORM_COUNT, platforms, &num_platforms); - if (platform_index >= (int)num_platforms) { - fprintf(stderr, "Platform index exceeds number of platforms...\n"); - return -1; - } + if(platform_index >= (int)num_platforms) { + fprintf(stderr, + "Platform index exceeds number of platforms...\n"); + return -1; + } - platform_id = platforms[platform_index]; + platform_id = platforms[platform_index]; - res = clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, MAX_PLATFORM_NAME_SIZE, - name, NULL); + res = clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, + MAX_PLATFORM_NAME_SIZE, name, NULL); - if (res == CL_OUT_OF_HOST_MEMORY) { - fprintf(stderr, "Insufficient resources...\n"); - return -1; - } + if(res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + return -1; + } - printf("Platform in Use: %s\n", name); + printf("Platform in Use: %s\n", name); - res = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, device, NULL); + res = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, device, NULL); - if (res == CL_DEVICE_NOT_FOUND) { - fprintf(stderr, "Specified platform does not provide a GPU...\n"); - return -1; - } + if(res == CL_DEVICE_NOT_FOUND) { + fprintf(stderr, + "Specified platform does not provide a GPU...\n"); + return -1; + } - if (res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { - fprintf(stderr, "Insufficient resources...\n"); - return -1; - } + if(res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + return -1; + } - return 0; + return 0; } -int write_image(char *out_file, int width, int height, float *raster) { - - FILE *fp; - - png_structp png_ptr; - png_infop info_ptr; - png_bytep row; - - row = (png_bytep)malloc(3 * width * sizeof(png_byte)); +int +write_image(char *out_file, int width, int height, float *raster) { - fp = fopen(out_file, "wb"); + FILE *fp; - if (!fp) { - printf("Couldn't open output file\n"); - free(row); - return -1; - } + png_structp png_ptr; + png_infop info_ptr; + png_bytep row; - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + row = (png_bytep) malloc(3 * width * sizeof(png_byte)); - info_ptr = png_create_info_struct(png_ptr); + fp = fopen(out_file, "wb"); - png_init_io(png_ptr, fp); + if(!fp) { + printf("Couldn't open output file\n"); + free(row); + return -1; + } - 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); + png_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, + NULL); - png_write_info(png_ptr, info_ptr); + info_ptr = png_create_info_struct(png_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); - } - - png_write_end(png_ptr, NULL); - - fclose(fp); - free(row); - - return 0; -} + png_init_io(png_ptr, fp); -int main(int argc, char **argv) { + 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); - struct Args args; - int res; + png_write_info(png_ptr, info_ptr); - float *data_out; - int data_out_size; + int x, y; - cl_device_id device_id; + 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); + } - cl_mem out_buff; + png_write_end(png_ptr, NULL); - cl_context context = NULL; - cl_command_queue command_queue = NULL; - cl_kernel kernel = NULL; - cl_program program = NULL; + fclose(fp); + free(row); - 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); + return 0; +} - if (res) { - fprintf(stderr, "Error reading source file: %s", args.source_file); - goto error; - } +int +main(int argc, char **argv) { - // Get Platform & Device - res = get_device(args.platform_index, &device_id); + struct Args args; + int res; - if (res) { - goto error; - } + float *data_out; + int data_out_size; - // Create Context & Queue - context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &res); + cl_device_id device_id; - if (res == CL_DEVICE_NOT_AVAILABLE) { - fprintf(stderr, "Selected platform/device is not available..."); - goto error; - } + cl_mem out_buff; - if (res == CL_OUT_OF_HOST_MEMORY) { - fprintf(stderr, "Insufficient resources...\n"); - goto error; - } + cl_context context = NULL; + cl_command_queue command_queue = NULL; + cl_kernel kernel = NULL; + cl_program program = NULL; - command_queue = - clCreateCommandQueueWithProperties(context, device_id, NULL, &res); + char *source_str; + size_t source_size; - if (res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { - fprintf(stderr, "Insufficient resources...\n"); - goto error; - } + size_t g_work_size, l_work_size; - // Create Buffers - out_buff = - clCreateBuffer(context, CL_MEM_WRITE_ONLY, data_out_size, NULL, &res); + res = parse_args(argc, argv, &args); - if (res == CL_INVALID_BUFFER_SIZE) { - fprintf(stderr, "Invalid buffer size: %d...", data_out_size); - } + if(res) { + fprintf(stderr, "Error parsing command-line arguments...\n"); - 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; - } + // This is before anything has been allocated, so no cleanup is needed. + exit(1); + } - program = clCreateProgramWithSource(context, 1, (const char **)&source_str, - &source_size, &res); + data_out_size = sizeof(float) * args.img_width * args.img_height * 3; - if (res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { - fprintf(stderr, "Insufficient resources...\n"); - goto error; - } + data_out = (float *)malloc(data_out_size); + source_str = (char *)malloc(MAX_SRC_SIZE * sizeof(char)); - res = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); + res = read_source(args.source_file, source_str, MAX_SRC_SIZE, + &source_size); - if (res != CL_SUCCESS) { - 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); - fprintf(stderr, "Build Error: %s\n", build_log); - goto error; - } + 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); - kernel = clCreateKernel(program, "render", &res); + if(res) { + goto error; + } + // Create Context & Queue + context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &res); - if (res != CL_SUCCESS) { - fprintf(stderr, "Error creating kernel: %d\n", res); - goto error; - } + if(res == CL_DEVICE_NOT_AVAILABLE) { + fprintf(stderr, "Selected platform/device is not available..."); + goto error; + } - res = clSetKernelArg(kernel, 0, sizeof(cl_int), (void *)&args.img_width); + if(res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + goto error; + } - if (res != CL_SUCCESS) { - fprintf(stderr, "Error setting arguments..."); - goto error; - } + command_queue = + clCreateCommandQueueWithProperties(context, device_id, NULL, + &res); - res = clSetKernelArg(kernel, 1, sizeof(cl_int), (void *)&args.img_height); + 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_out_size, NULL, + &res); - if (res != CL_SUCCESS) { - fprintf(stderr, "Error setting arguments..."); - goto error; - } + if(res == CL_INVALID_BUFFER_SIZE) { + fprintf(stderr, "Invalid buffer size: %d...", data_out_size); + } - res = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&out_buff); + 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; + } - if (res != CL_SUCCESS) { - fprintf(stderr, "Error setting arguments..."); - goto error; - } + program = + clCreateProgramWithSource(context, 1, + (const char **)&source_str, + &source_size, &res); - l_work_size = 128; - g_work_size = - (args.img_width * args.img_height / l_work_size + 1) * l_work_size; + if(res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { + fprintf(stderr, "Insufficient resources...\n"); + goto error; + } - res = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, &g_work_size, - &l_work_size, 0, NULL, NULL); + res = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); - if (res != CL_SUCCESS) { - printf("Error executing kernel: %d\n", (int)res); - goto error; - } + if(res != CL_SUCCESS) { + fprintf(stderr, "Failed to build program!\n"); + char build_log[16348]; - res = clEnqueueReadBuffer(command_queue, out_buff, CL_TRUE, 0, data_out_size, - (void *)data_out, 0, NULL, NULL); + clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, + sizeof(build_log), build_log, NULL); + fprintf(stderr, "Build Error: %s\n", build_log); + goto error; + } - if (res != CL_SUCCESS) { - printf("Error reading result: %d\n", (int)res); - goto error; - } + kernel = clCreateKernel(program, "render", &res); - // Write PNG - write_image(args.out_file, args.img_width, args.img_height, data_out); + if(res != CL_SUCCESS) { + fprintf(stderr, "Error creating kernel: %d\n", res); + goto error; + } -error: + res = clSetKernelArg(kernel, 0, sizeof(cl_int), + (void *)&args.img_width); - clFlush(command_queue); - clFinish(command_queue); + 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 = + (args.img_width * args.img_height / l_work_size + + 1) * l_work_size; + + res = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, + &g_work_size, &l_work_size, 0, NULL, NULL); + + if(res != CL_SUCCESS) { + printf("Error executing kernel: %d\n", (int)res); + goto error; + } + + res = clEnqueueReadBuffer(command_queue, out_buff, CL_TRUE, 0, + data_out_size, (void *)data_out, 0, NULL, + NULL); + + if(res != CL_SUCCESS) { + printf("Error reading result: %d\n", (int)res); + goto error; + } + // Write PNG + write_image(args.out_file, args.img_width, args.img_height, data_out); - clReleaseMemObject(out_buff); + error: + + clFlush(command_queue); + clFinish(command_queue); - clReleaseCommandQueue(command_queue); - clReleaseContext(context); + clReleaseMemObject(out_buff); + + clReleaseCommandQueue(command_queue); + clReleaseContext(context); - free(data_out); - free(source_str); + free(data_out); + free(source_str); - return 0; + return 0; }