runcl.c (8612B)
1 #define CL_TARGET_OPENCL_VERSION 300 2 #define USAGE \ 3 "usage: runcl -p <platform-index> -w <image-width> -h <image-height> " \ 4 "input-opencl-file output-png-file" 5 6 #define DEF_WIDTH 640 7 #define DEF_HEIGHT 480 8 #define MAX_SRC_SIZE 1048576 9 #define MAX_PLATFORM_COUNT 16 10 #define MAX_PLATFORM_NAME_SIZE 256 11 12 #define STR_LITERAL(x) #x 13 #define STRINGIFY(x) STR_LITERAL(x) 14 15 #include <CL/cl.h> 16 #include <getopt.h> 17 #include <png.h> 18 #include <stdio.h> 19 #include <unistd.h> 20 21 struct Args { 22 int img_width; 23 int img_height; 24 int platform_index; 25 char *source_file; 26 char *out_file; 27 }; 28 29 void 30 print_help() { 31 printf(USAGE "\n"); 32 } 33 34 void 35 print_version() { 36 printf(STRINGIFY(PROG_NAME) " " STRINGIFY(VERSION) "\n"); 37 printf("Build: " STRINGIFY(BUILD_TYPE) "\n"); 38 printf("CFLAGS: " STRINGIFY(CFLAGS) "\n"); 39 printf("LDFLAGS: " STRINGIFY(LDFLAGS) "\n"); 40 } 41 42 int 43 parse_args(int argc, char **argv, struct Args *out) { 44 45 int arg; 46 47 out->img_width = DEF_WIDTH; 48 out->img_height = DEF_HEIGHT; 49 out->platform_index = 0; 50 51 while((arg = getopt(argc, argv, "p:w:h:Hv")) != -1) { 52 switch (arg) { 53 case 'p': 54 out->platform_index = atoi(optarg); 55 break; 56 case 'w': 57 out->img_width = atoi(optarg); 58 break; 59 case 'h': 60 out->img_height = atoi(optarg); 61 break; 62 case 'H': 63 print_help(); 64 exit(0); 65 case 'v': 66 print_version(); 67 exit(0); 68 case '?': 69 return -1; 70 } 71 } 72 73 if(argc < optind + 2) 74 return -1; 75 76 out->source_file = argv[optind]; 77 out->out_file = argv[optind + 1]; 78 79 return 0; 80 } 81 82 int 83 read_source(char *path, char *out, size_t max_size, size_t *source_size) { 84 85 FILE *fp; 86 87 fp = fopen(path, "r"); 88 if(!fp) { 89 return -1; 90 } 91 92 *source_size = fread(out, 1, max_size, fp); 93 94 if(!feof(fp)) { 95 return -1; 96 } 97 98 fclose(fp); 99 100 return 0; 101 } 102 103 int 104 get_device(int platform_index, cl_device_id *device) { 105 106 cl_platform_id platforms[MAX_PLATFORM_COUNT]; 107 cl_uint num_platforms; 108 cl_platform_id platform_id; 109 110 char name[MAX_PLATFORM_NAME_SIZE]; 111 112 int res; 113 114 res = clGetPlatformIDs(MAX_PLATFORM_COUNT, platforms, &num_platforms); 115 116 if(platform_index >= (int)num_platforms) { 117 fprintf(stderr, 118 "Platform index exceeds number of platforms...\n"); 119 return -1; 120 } 121 122 platform_id = platforms[platform_index]; 123 124 res = clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, 125 MAX_PLATFORM_NAME_SIZE, name, NULL); 126 127 if(res == CL_OUT_OF_HOST_MEMORY) { 128 fprintf(stderr, "Insufficient resources...\n"); 129 return -1; 130 } 131 132 printf("Platform in Use: %s\n", name); 133 134 res = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, device, NULL); 135 136 if(res == CL_DEVICE_NOT_FOUND) { 137 fprintf(stderr, 138 "Specified platform does not provide a GPU...\n"); 139 return -1; 140 } 141 142 if(res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { 143 fprintf(stderr, "Insufficient resources...\n"); 144 return -1; 145 } 146 147 return 0; 148 } 149 150 int 151 write_image(char *out_file, int width, int height, float *raster) { 152 153 FILE *fp; 154 155 png_structp png_ptr; 156 png_infop info_ptr; 157 png_bytep row; 158 159 row = (png_bytep) malloc(3 * width * sizeof(png_byte)); 160 161 fp = fopen(out_file, "wb"); 162 163 if(!fp) { 164 printf("Couldn't open output file\n"); 165 free(row); 166 return -1; 167 } 168 169 png_ptr = 170 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, 171 NULL); 172 173 info_ptr = png_create_info_struct(png_ptr); 174 175 png_init_io(png_ptr, fp); 176 177 png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, 178 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 179 PNG_FILTER_TYPE_BASE); 180 181 png_write_info(png_ptr, info_ptr); 182 183 int x, y; 184 185 for(y = 0; y < height; y++) { 186 for(x = 0; x < width; x++) { 187 row[x * 3 + 0] = 188 (int)(255 * raster[3 * (y * width + x) + 0]); 189 row[x * 3 + 1] = 190 (int)(255 * raster[3 * (y * width + x) + 1]); 191 row[x * 3 + 2] = 192 (int)(255 * raster[3 * (y * width + x) + 2]); 193 } 194 png_write_row(png_ptr, row); 195 } 196 197 png_write_end(png_ptr, NULL); 198 199 fclose(fp); 200 free(row); 201 202 return 0; 203 } 204 205 int 206 main(int argc, char **argv) { 207 208 struct Args args; 209 int res; 210 211 float *data_out; 212 int data_out_size; 213 214 cl_device_id device_id; 215 216 cl_mem out_buff; 217 218 cl_context context = NULL; 219 cl_command_queue command_queue = NULL; 220 cl_kernel kernel = NULL; 221 cl_program program = NULL; 222 223 char *source_str; 224 size_t source_size; 225 226 size_t g_work_size, l_work_size; 227 228 res = parse_args(argc, argv, &args); 229 230 if(res) { 231 fprintf(stderr, "Error parsing command-line arguments...\n"); 232 233 // This is before anything has been allocated, so no cleanup is needed. 234 exit(1); 235 } 236 237 data_out_size = sizeof(float) * args.img_width * args.img_height * 3; 238 239 data_out = (float *)malloc(data_out_size); 240 source_str = (char *)malloc(MAX_SRC_SIZE * sizeof(char)); 241 242 res = read_source(args.source_file, source_str, MAX_SRC_SIZE, 243 &source_size); 244 245 if(res) { 246 fprintf(stderr, "Error reading source file: %s", 247 args.source_file); 248 goto error; 249 } 250 // Get Platform & Device 251 res = get_device(args.platform_index, &device_id); 252 253 if(res) { 254 goto error; 255 } 256 // Create Context & Queue 257 context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &res); 258 259 if(res == CL_DEVICE_NOT_AVAILABLE) { 260 fprintf(stderr, "Selected platform/device is not available..."); 261 goto error; 262 } 263 264 if(res == CL_OUT_OF_HOST_MEMORY) { 265 fprintf(stderr, "Insufficient resources...\n"); 266 goto error; 267 } 268 269 command_queue = 270 clCreateCommandQueueWithProperties(context, device_id, NULL, 271 &res); 272 273 if(res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { 274 fprintf(stderr, "Insufficient resources...\n"); 275 goto error; 276 } 277 // Create Buffers 278 out_buff = 279 clCreateBuffer(context, CL_MEM_WRITE_ONLY, data_out_size, NULL, 280 &res); 281 282 if(res == CL_INVALID_BUFFER_SIZE) { 283 fprintf(stderr, "Invalid buffer size: %d...", data_out_size); 284 } 285 286 if(res == CL_MEM_OBJECT_ALLOCATION_FAILURE || res == CL_OUT_OF_RESOURCES 287 || res == CL_OUT_OF_HOST_MEMORY) { 288 fprintf(stderr, "Insufficient resources...\n"); 289 goto error; 290 } 291 292 program = 293 clCreateProgramWithSource(context, 1, 294 (const char **)&source_str, 295 &source_size, &res); 296 297 if(res == CL_OUT_OF_RESOURCES || res == CL_OUT_OF_HOST_MEMORY) { 298 fprintf(stderr, "Insufficient resources...\n"); 299 goto error; 300 } 301 302 res = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); 303 304 if(res != CL_SUCCESS) { 305 fprintf(stderr, "Failed to build program!\n"); 306 char build_log[16348]; 307 308 clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 309 sizeof(build_log), build_log, NULL); 310 fprintf(stderr, "Build Error: %s\n", build_log); 311 goto error; 312 } 313 314 kernel = clCreateKernel(program, "render", &res); 315 316 if(res != CL_SUCCESS) { 317 fprintf(stderr, "Error creating kernel: %d\n", res); 318 goto error; 319 } 320 321 res = clSetKernelArg(kernel, 0, sizeof(cl_int), 322 (void *)&args.img_width); 323 324 if(res != CL_SUCCESS) { 325 fprintf(stderr, "Error setting arguments..."); 326 goto error; 327 } 328 329 res = clSetKernelArg(kernel, 1, sizeof(cl_int), 330 (void *)&args.img_height); 331 332 if(res != CL_SUCCESS) { 333 fprintf(stderr, "Error setting arguments..."); 334 goto error; 335 } 336 337 res = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&out_buff); 338 339 if(res != CL_SUCCESS) { 340 fprintf(stderr, "Error setting arguments..."); 341 goto error; 342 } 343 344 l_work_size = 128; 345 g_work_size = 346 (args.img_width * args.img_height / l_work_size + 347 1) * l_work_size; 348 349 res = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, 350 &g_work_size, &l_work_size, 0, NULL, NULL); 351 352 if(res != CL_SUCCESS) { 353 printf("Error executing kernel: %d\n", (int)res); 354 goto error; 355 } 356 357 res = clEnqueueReadBuffer(command_queue, out_buff, CL_TRUE, 0, 358 data_out_size, (void *)data_out, 0, NULL, 359 NULL); 360 361 if(res != CL_SUCCESS) { 362 printf("Error reading result: %d\n", (int)res); 363 goto error; 364 } 365 // Write PNG 366 write_image(args.out_file, args.img_width, args.img_height, data_out); 367 368 error: 369 370 clFlush(command_queue); 371 clFinish(command_queue); 372 373 clReleaseMemObject(out_buff); 374 375 clReleaseCommandQueue(command_queue); 376 clReleaseContext(context); 377 378 free(data_out); 379 free(source_str); 380 381 return 0; 382 }