/* * Copyright (c) 2017 ARM Limited. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "arm_compute/core/CL/OpenCL.h" #include #include namespace arm_compute { CLSymbols &CLSymbols::get() { static CLSymbols symbols; return symbols; } bool CLSymbols::load_default() { static const std::vector libraries{ "libOpenCL.so", "libGLES_mali.so", "libmali.so" }; if(_loaded.first) { return _loaded.second; } // Indicate that default loading has been tried _loaded.first = true; for(const auto &lib : libraries) { if(load(lib)) { return true; } } std::cerr << "Couldn't find any OpenCL library.\n"; return false; } bool CLSymbols::load(const std::string &library) { void *handle = dlopen(library.c_str(), RTLD_LAZY | RTLD_LOCAL); if(handle == nullptr) { std::cerr << "Can't load " << library << ": " << dlerror() << "\n"; // Set status of loading to failed _loaded.second = false; return false; } clBuildProgram = reinterpret_cast(dlsym(handle, "clBuildProgram")); clEnqueueNDRangeKernel = reinterpret_cast(dlsym(handle, "clEnqueueNDRangeKernel")); clSetKernelArg = reinterpret_cast(dlsym(handle, "clSetKernelArg")); clReleaseKernel = reinterpret_cast(dlsym(handle, "clReleaseKernel")); clCreateProgramWithSource = reinterpret_cast(dlsym(handle, "clCreateProgramWithSource")); clCreateBuffer = reinterpret_cast(dlsym(handle, "clCreateBuffer")); clRetainKernel = reinterpret_cast(dlsym(handle, "clRetainKernel")); clCreateKernel = reinterpret_cast(dlsym(handle, "clCreateKernel")); clGetProgramInfo = reinterpret_cast(dlsym(handle, "clGetProgramInfo")); clFlush = reinterpret_cast(dlsym(handle, "clFlush")); clFinish = reinterpret_cast(dlsym(handle, "clFinish")); clReleaseProgram = reinterpret_cast(dlsym(handle, "clReleaseProgram")); clRetainContext = reinterpret_cast(dlsym(handle, "clRetainContext")); clCreateProgramWithBinary = reinterpret_cast(dlsym(handle, "clCreateProgramWithBinary")); clReleaseCommandQueue = reinterpret_cast(dlsym(handle, "clReleaseCommandQueue")); clEnqueueMapBuffer = reinterpret_cast(dlsym(handle, "clEnqueueMapBuffer")); clRetainProgram = reinterpret_cast(dlsym(handle, "clRetainProgram")); clGetProgramBuildInfo = reinterpret_cast(dlsym(handle, "clGetProgramBuildInfo")); clEnqueueReadBuffer = reinterpret_cast(dlsym(handle, "clEnqueueReadBuffer")); clEnqueueWriteBuffer = reinterpret_cast(dlsym(handle, "clEnqueueWriteBuffer")); clReleaseEvent = reinterpret_cast(dlsym(handle, "clReleaseEvent")); clReleaseContext = reinterpret_cast(dlsym(handle, "clReleaseContext")); clRetainCommandQueue = reinterpret_cast(dlsym(handle, "clRetainCommandQueue")); clEnqueueUnmapMemObject = reinterpret_cast(dlsym(handle, "clEnqueueUnmapMemObject")); clRetainMemObject = reinterpret_cast(dlsym(handle, "clRetainMemObject")); clReleaseMemObject = reinterpret_cast(dlsym(handle, "clReleaseMemObject")); clGetDeviceInfo = reinterpret_cast(dlsym(handle, "clGetDeviceInfo")); clGetDeviceIDs = reinterpret_cast(dlsym(handle, "clGetDeviceIDs")); clRetainEvent = reinterpret_cast(dlsym(handle, "clRetainEvent")); clGetPlatformIDs = reinterpret_cast(dlsym(handle, "clGetPlatformIDs")); clGetKernelWorkGroupInfo = reinterpret_cast(dlsym(handle, "clGetKernelWorkGroupInfo")); dlclose(handle); // Disable default loading and set status to successful _loaded = std::make_pair(true, true); return true; } bool opencl_is_available() { CLSymbols::get().load_default(); return CLSymbols::get().clBuildProgram != nullptr; } } // namespace arm_compute cl_int clBuildProgram( cl_program program, cl_uint num_devices, const cl_device_id *device_list, const char *options, void(CL_CALLBACK *pfn_notify)(cl_program program, void *user_data), void *user_data) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clBuildProgram; if(func != nullptr) { return func(program, num_devices, device_list, options, pfn_notify, user_data); } else { return CL_OUT_OF_RESOURCES; } } cl_int clEnqueueNDRangeKernel( cl_command_queue command_queue, cl_kernel kernel, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clEnqueueNDRangeKernel; if(func != nullptr) { return func(command_queue, kernel, work_dim, global_work_offset, global_work_size, local_work_size, num_events_in_wait_list, event_wait_list, event); } else { return CL_OUT_OF_RESOURCES; } } cl_int clSetKernelArg( cl_kernel kernel, cl_uint arg_index, size_t arg_size, const void *arg_value) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clSetKernelArg; if(func != nullptr) { return func(kernel, arg_index, arg_size, arg_value); } else { return CL_OUT_OF_RESOURCES; } } cl_int clRetainMemObject(cl_mem memobj) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clRetainMemObject; if(func != nullptr) { return func(memobj); } else { return CL_OUT_OF_RESOURCES; } } cl_int clReleaseMemObject(cl_mem memobj) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clReleaseMemObject; if(func != nullptr) { return func(memobj); } else { return CL_OUT_OF_RESOURCES; } } cl_int clEnqueueUnmapMemObject( cl_command_queue command_queue, cl_mem memobj, void *mapped_ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clEnqueueUnmapMemObject; if(func != nullptr) { return func(command_queue, memobj, mapped_ptr, num_events_in_wait_list, event_wait_list, event); } else { return CL_OUT_OF_RESOURCES; } } cl_int clRetainCommandQueue(cl_command_queue command_queue) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clRetainCommandQueue; if(func != nullptr) { return func(command_queue); } else { return CL_OUT_OF_RESOURCES; } } cl_int clReleaseContext(cl_context context) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clReleaseContext; if(func != nullptr) { return func(context); } else { return CL_OUT_OF_RESOURCES; } } cl_int clReleaseEvent(cl_event event) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clReleaseEvent; if(func != nullptr) { return func(event); } else { return CL_OUT_OF_RESOURCES; } } cl_int clEnqueueWriteBuffer( cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_write, size_t offset, size_t size, const void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clEnqueueWriteBuffer; if(func != nullptr) { return func(command_queue, buffer, blocking_write, offset, size, ptr, num_events_in_wait_list, event_wait_list, event); } else { return CL_OUT_OF_RESOURCES; } } cl_int clEnqueueReadBuffer( cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_read, size_t offset, size_t size, void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clEnqueueReadBuffer; if(func != nullptr) { return func(command_queue, buffer, blocking_read, offset, size, ptr, num_events_in_wait_list, event_wait_list, event); } else { return CL_OUT_OF_RESOURCES; } } cl_int clGetProgramBuildInfo( cl_program program, cl_device_id device, cl_program_build_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clGetProgramBuildInfo; if(func != nullptr) { return func(program, device, param_name, param_value_size, param_value, param_value_size_ret); } else { return CL_OUT_OF_RESOURCES; } } cl_int clRetainProgram(cl_program program) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clRetainProgram; if(func != nullptr) { return func(program); } else { return CL_OUT_OF_RESOURCES; } } void *clEnqueueMapBuffer( cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_map, cl_map_flags map_flags, size_t offset, size_t size, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event, cl_int *errcode_ret) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clEnqueueMapBuffer; if(func != nullptr) { return func(command_queue, buffer, blocking_map, map_flags, offset, size, num_events_in_wait_list, event_wait_list, event, errcode_ret); } else { if(errcode_ret != nullptr) { *errcode_ret = CL_OUT_OF_RESOURCES; } return nullptr; } } cl_int clReleaseCommandQueue(cl_command_queue command_queue) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clReleaseCommandQueue; if(func != nullptr) { return func(command_queue); } else { return CL_OUT_OF_RESOURCES; } } cl_program clCreateProgramWithBinary( cl_context context, cl_uint num_devices, const cl_device_id *device_list, const size_t *lengths, const unsigned char **binaries, cl_int *binary_status, cl_int *errcode_ret) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clCreateProgramWithBinary; if(func != nullptr) { return func(context, num_devices, device_list, lengths, binaries, binary_status, errcode_ret); } else { if(errcode_ret != nullptr) { *errcode_ret = CL_OUT_OF_RESOURCES; } return nullptr; } } cl_int clRetainContext(cl_context context) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clRetainContext; if(func != nullptr) { return func(context); } else { return CL_OUT_OF_RESOURCES; } } cl_int clReleaseProgram(cl_program program) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clReleaseProgram; if(func != nullptr) { return func(program); } else { return CL_OUT_OF_RESOURCES; } } cl_int clFlush(cl_command_queue command_queue) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clFlush; if(func != nullptr) { return func(command_queue); } else { return CL_OUT_OF_RESOURCES; } } cl_int clFinish(cl_command_queue command_queue) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clFinish; if(func != nullptr) { return func(command_queue); } else { return CL_OUT_OF_RESOURCES; } } cl_int clGetProgramInfo( cl_program program, cl_program_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clGetProgramInfo; if(func != nullptr) { return func(program, param_name, param_value_size, param_value, param_value_size_ret); } else { return CL_OUT_OF_RESOURCES; } } cl_kernel clCreateKernel( cl_program program, const char *kernel_name, cl_int *errcode_ret) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clCreateKernel; if(func != nullptr) { return func(program, kernel_name, errcode_ret); } else { if(errcode_ret != nullptr) { *errcode_ret = CL_OUT_OF_RESOURCES; } return nullptr; } } cl_int clRetainKernel(cl_kernel kernel) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clRetainKernel; if(func != nullptr) { return func(kernel); } else { return CL_OUT_OF_RESOURCES; } } cl_mem clCreateBuffer( cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clCreateBuffer; if(func != nullptr) { return func(context, flags, size, host_ptr, errcode_ret); } else { if(errcode_ret != nullptr) { *errcode_ret = CL_OUT_OF_RESOURCES; } return nullptr; } } cl_program clCreateProgramWithSource( cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clCreateProgramWithSource; if(func != nullptr) { return func(context, count, strings, lengths, errcode_ret); } else { if(errcode_ret != nullptr) { *errcode_ret = CL_OUT_OF_RESOURCES; } return nullptr; } } cl_int clReleaseKernel(cl_kernel kernel) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clReleaseKernel; if(func != nullptr) { return func(kernel); } else { return CL_OUT_OF_RESOURCES; } } cl_int clGetDeviceIDs(cl_platform_id platform, cl_device_type device_type, cl_uint num_entries, cl_device_id *devices, cl_uint *num_devices) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clGetDeviceIDs; if(func != nullptr) { return func(platform, device_type, num_entries, devices, num_devices); } else { return CL_OUT_OF_RESOURCES; } } cl_int clGetDeviceInfo(cl_device_id device, cl_device_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clGetDeviceInfo; if(func != nullptr) { return func(device, param_name, param_value_size, param_value, param_value_size_ret); } else { return CL_OUT_OF_RESOURCES; } } cl_int clRetainEvent(cl_event event) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clRetainEvent; if(func != nullptr) { return func(event); } else { return CL_OUT_OF_RESOURCES; } } cl_int clGetPlatformIDs(cl_uint num_entries, cl_platform_id *platforms, cl_uint *num_platforms) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clGetPlatformIDs; if(func != nullptr) { return func(num_entries, platforms, num_platforms); } else { return CL_OUT_OF_RESOURCES; } } cl_int clGetKernelWorkGroupInfo(cl_kernel kernel, cl_device_id device, cl_kernel_work_group_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) { arm_compute::CLSymbols::get().load_default(); auto func = arm_compute::CLSymbols::get().clGetKernelWorkGroupInfo; if(func != nullptr) { return func(kernel, device, param_name, param_value_size, param_value, param_value_size_ret); } else { return CL_OUT_OF_RESOURCES; } }