/* Copyright (C) 2024 Aiden Gall
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
#include "util.h"
#include
#include
#include
#include
#include
cl_platform_id *get_platforms(cl_uint *num_platforms);
cl_device_id *get_devices(cl_platform_id platform, cl_uint *num_devices);
cl_program compile_spirv_program(cl_context context, cl_device_id device,
const void *spirv_start, size_t spirv_size);
const char *cl_strerror(cl_int err);
cl_platform_id *
get_platforms(cl_uint *const num_platforms)
{
cl_int err;
cl_platform_id *platforms;
cl_uint len;
err = clGetPlatformIDs(0, NULL, &len);
if (err != CL_SUCCESS)
die("clGetPlatformIDs: %s\n", cl_strerror(err));
warn("number of platforms = %d\n", len);
if (len < 1)
die("clGetPlatformIDs: No OpenCL platforms\n");
platforms = calloc(len, sizeof(*platforms));
if (!platforms)
die("calloc: Out of memory\n");
err = clGetPlatformIDs(len, platforms, NULL);
if (err != CL_SUCCESS)
die("clGetPlatformIDs: %s\n", cl_strerror(err));
*num_platforms = len;
return platforms;
}
cl_device_id *
get_devices(const cl_platform_id platform, cl_uint *const num_devices)
{
cl_int err;
cl_device_id *devices;
cl_uint len;
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &len);
if (err != CL_SUCCESS)
die("clGetDeviceIDs: %s\n", cl_strerror(err));
warn("number of devices in platform = %d\n", len);
if (len < 1)
die("clGetDeviceIDs: No OpenCL devices in platform\n");
devices = calloc(len, sizeof(*devices));
if (!devices)
die("calloc: Out of memory\n");
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, len, devices, NULL);
if (err != CL_SUCCESS)
die("clGetDeviceIDs: %s\n", cl_strerror(err));
*num_devices = len;
return devices;
}
cl_program
compile_spirv_program(const cl_context context, const cl_device_id device,
const void *const spirv_start, const size_t spirv_size)
{
cl_int err, build_err;
cl_program program;
program = clCreateProgramWithIL(context, spirv_start, spirv_size, &err);
if (err != CL_SUCCESS)
die("clCreateProgramWithIL: %s\n", cl_strerror(err));
build_err = clBuildProgram(program, 1, &device, NULL, NULL, NULL);
if (build_err != CL_SUCCESS) {
cl_char *log;
size_t buffer_size;
err = clGetProgramBuildInfo(program, device,
CL_PROGRAM_BUILD_LOG, 0, NULL,
&buffer_size);
if (err != CL_SUCCESS)
die("clGetProgramBuildInfo: %s\n", cl_strerror(err));
if (buffer_size < 1)
die("clGetProgramBuildInfo: "
"Build log buffer is empty\n");
log = calloc(buffer_size, sizeof(*log));
if (!log)
die("calloc: Out of memory\n");
err = clGetProgramBuildInfo(
program, device, CL_PROGRAM_BUILD_LOG,
sizeof(*log) * buffer_size, log, NULL);
if (err != CL_SUCCESS)
die("clGetProgramBuildInfo: %s\n", cl_strerror(err));
efwrite(log, sizeof(*log), buffer_size, stderr);
free(log);
die("\nclBuildProgram: %s\n", cl_strerror(build_err));
}
return program;
}
const char *
cl_strerror(const cl_int err)
{
switch (err) {
case CL_SUCCESS:
return "CL_SUCCESS";
case CL_DEVICE_NOT_FOUND:
return "CL_DEVICE_NOT_FOUND";
case CL_DEVICE_NOT_AVAILABLE:
return "CL_DEVICE_NOT_AVAILABLE";
case CL_COMPILER_NOT_AVAILABLE:
return "CL_COMPILER_NOT_AVAILABLE";
case CL_MEM_OBJECT_ALLOCATION_FAILURE:
return "CL_MEM_OBJECT_ALLOCATION_FAILURE";
case CL_OUT_OF_RESOURCES:
return "CL_OUT_OF_RESOURCES";
case CL_OUT_OF_HOST_MEMORY:
return "CL_OUT_OF_HOST_MEMORY";
case CL_PROFILING_INFO_NOT_AVAILABLE:
return "CL_PROFILING_INFO_NOT_AVAILABLE";
case CL_MEM_COPY_OVERLAP:
return "CL_MEM_COPY_OVERLAP";
case CL_IMAGE_FORMAT_MISMATCH:
return "CL_IMAGE_FORMAT_MISMATCH";
case CL_IMAGE_FORMAT_NOT_SUPPORTED:
return "CL_IMAGE_FORMAT_NOT_SUPPORTED";
case CL_BUILD_PROGRAM_FAILURE:
return "CL_BUILD_PROGRAM_FAILURE";
case CL_MAP_FAILURE:
return "CL_MAP_FAILURE";
case CL_INVALID_VALUE:
return "CL_INVALID_VALUE";
case CL_INVALID_DEVICE_TYPE:
return "CL_INVALID_DEVICE_TYPE";
case CL_INVALID_PLATFORM:
return "CL_INVALID_PLATFORM";
case CL_INVALID_DEVICE:
return "CL_INVALID_DEVICE";
case CL_INVALID_CONTEXT:
return "CL_INVALID_CONTEXT";
case CL_INVALID_QUEUE_PROPERTIES:
return "CL_INVALID_QUEUE_PROPERTIES";
case CL_INVALID_COMMAND_QUEUE:
return "CL_INVALID_COMMAND_QUEUE";
case CL_INVALID_HOST_PTR:
return "CL_INVALID_HOST_PTR";
case CL_INVALID_MEM_OBJECT:
return "CL_INVALID_MEM_OBJECT";
case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR:
return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR";
case CL_INVALID_IMAGE_SIZE:
return "CL_INVALID_IMAGE_SIZE";
case CL_INVALID_SAMPLER:
return "CL_INVALID_SAMPLER";
case CL_INVALID_BINARY:
return "CL_INVALID_BINARY";
case CL_INVALID_BUILD_OPTIONS:
return "CL_INVALID_BUILD_OPTIONS";
case CL_INVALID_PROGRAM:
return "CL_INVALID_PROGRAM";
case CL_INVALID_PROGRAM_EXECUTABLE:
return "CL_INVALID_PROGRAM_EXECUTABLE";
case CL_INVALID_KERNEL_NAME:
return "CL_INVALID_KERNEL_NAME";
case CL_INVALID_KERNEL_DEFINITION:
return "CL_INVALID_KERNEL_DEFINITION";
case CL_INVALID_KERNEL:
return "CL_INVALID_KERNEL";
case CL_INVALID_ARG_INDEX:
return "CL_INVALID_ARG_INDEX";
case CL_INVALID_ARG_VALUE:
return "CL_INVALID_ARG_VALUE";
case CL_INVALID_ARG_SIZE:
return "CL_INVALID_ARG_SIZE";
case CL_INVALID_KERNEL_ARGS:
return "CL_INVALID_KERNEL_ARGS";
case CL_INVALID_WORK_DIMENSION:
return "CL_INVALID_WORK_DIMENSION";
case CL_INVALID_WORK_GROUP_SIZE:
return "CL_INVALID_WORK_GROUP_SIZE";
case CL_INVALID_WORK_ITEM_SIZE:
return "CL_INVALID_WORK_ITEM_SIZE";
case CL_INVALID_GLOBAL_OFFSET:
return "CL_INVALID_GLOBAL_OFFSET";
case CL_INVALID_EVENT_WAIT_LIST:
return "CL_INVALID_EVENT_WAIT_LIST";
case CL_INVALID_EVENT:
return "CL_INVALID_EVENT";
case CL_INVALID_OPERATION:
return "CL_INVALID_OPERATION";
case CL_INVALID_GL_OBJECT:
return "CL_INVALID_GL_OBJECT";
case CL_INVALID_BUFFER_SIZE:
return "CL_INVALID_BUFFER_SIZE";
case CL_INVALID_MIP_LEVEL:
return "CL_INVALID_MIP_LEVEL";
case CL_INVALID_GLOBAL_WORK_SIZE:
return "CL_INVALID_GLOBAL_WORK_SIZE";
#ifdef CL_VERSION_1_1
case CL_MISALIGNED_SUB_BUFFER_OFFSET:
return "CL_MISALIGNED_SUB_BUFFER_OFFSET";
case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST:
return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST";
case CL_INVALID_PROPERTY:
return "CL_INVALID_PROPERTY";
#endif
#ifdef CL_VERSION_1_2
case CL_COMPILE_PROGRAM_FAILURE:
return "CL_COMPILE_PROGRAM_FAILURE";
case CL_LINKER_NOT_AVAILABLE:
return "CL_LINKER_NOT_AVAILABLE";
case CL_LINK_PROGRAM_FAILURE:
return "CL_LINK_PROGRAM_FAILURE";
case CL_DEVICE_PARTITION_FAILED:
return "CL_DEVICE_PARTITION_FAILED";
case CL_KERNEL_ARG_INFO_NOT_AVAILABLE:
return "CL_KERNEL_ARG_INFO_NOT_AVAILABLE";
case CL_INVALID_IMAGE_DESCRIPTOR:
return "CL_INVALID_IMAGE_DESCRIPTOR";
case CL_INVALID_COMPILER_OPTIONS:
return "CL_INVALID_COMPILER_OPTIONS";
case CL_INVALID_LINKER_OPTIONS:
return "CL_INVALID_LINKER_OPTIONS";
case CL_INVALID_DEVICE_PARTITION_COUNT:
return "CL_INVALID_DEVICE_PARTITION_COUNT";
#endif
#ifdef CL_VERSION_2_0
case CL_INVALID_PIPE_SIZE:
return "CL_INVALID_PIPE_SIZE";
case CL_INVALID_DEVICE_QUEUE:
return "CL_INVALID_DEVICE_QUEUE";
#endif
#ifdef CL_VERSION_2_2
case CL_INVALID_SPEC_ID:
return "CL_INVALID_SPEC_ID";
case CL_MAX_SIZE_RESTRICTION_EXCEEDED:
return "CL_MAX_SIZE_RESTRICTION_EXCEEDED";
#endif
default:
return "OpenCL unknown error";
}
}