Program Listing for File OpenCL_Loader.cpp
↰ Return to documentation for file (include\util\common\BackendLoader\OpenCL_Loader.cpp)
#define CL_TARGET_OPENCL_VERSION 300
#include "OpenCL_Loader.hpp"
#include <CL/opencl.h>
#include <atomic>
#include <mutex>
#if defined(_WIN32)
#include <windows.h>
#elif defined(__linux__)
#include <dlfcn.h>
#endif
#ifndef CL_PLATFORM_NOT_FOUND_KHR
#define CL_PLATFORM_NOT_FOUND_KHR -1001
#endif
namespace {
#define PDJE_OPENCL_RUNTIME_SYMBOLS(X) \
X(clGetPlatformIDs) \
X(clGetPlatformInfo) \
X(clGetDeviceIDs) \
X(clGetDeviceInfo) \
X(clRetainDevice) \
X(clReleaseDevice) \
X(clCreateContext) \
X(clCreateContextFromType) \
X(clGetContextInfo) \
X(clRetainContext) \
X(clReleaseContext) \
X(clCreateCommandQueue) \
X(clCreateCommandQueueWithProperties) \
X(clGetCommandQueueInfo) \
X(clRetainCommandQueue) \
X(clReleaseCommandQueue) \
X(clFlush) \
X(clFinish) \
X(clCreateProgramWithSource) \
X(clBuildProgram) \
X(clGetProgramInfo) \
X(clGetProgramBuildInfo) \
X(clRetainProgram) \
X(clReleaseProgram) \
X(clCreateKernel) \
X(clSetKernelArg) \
X(clGetKernelInfo) \
X(clGetKernelWorkGroupInfo) \
X(clRetainKernel) \
X(clReleaseKernel) \
X(clCreateBuffer) \
X(clCreateBufferWithProperties) \
X(clGetMemObjectInfo) \
X(clRetainMemObject) \
X(clReleaseMemObject) \
X(clEnqueueReadBuffer) \
X(clEnqueueWriteBuffer) \
X(clEnqueueNDRangeKernel) \
X(clWaitForEvents) \
X(clGetEventInfo) \
X(clRetainEvent) \
X(clReleaseEvent) \
X(clGetExtensionFunctionAddress) \
X(clGetExtensionFunctionAddressForPlatform)
#if defined(_WIN32)
using OpenCLLibraryHandle = HMODULE;
#else
using OpenCLLibraryHandle = void *;
#endif
struct OpenCLRuntimeDispatch {
#define PDJE_DECLARE_DISPATCH_MEMBER(name) decltype(&::name) name = nullptr;
PDJE_OPENCL_RUNTIME_SYMBOLS(PDJE_DECLARE_DISPATCH_MEMBER)
#undef PDJE_DECLARE_DISPATCH_MEMBER
};
OpenCLRuntimeDispatch gOpenCLDispatch{};
OpenCLLibraryHandle gOpenCLLibraryHandle = nullptr;
std::once_flag gOpenCLRuntimeInitOnce;
std::atomic<bool> gOpenCLRuntimeReady{ false };
#if defined(_WIN32)
OpenCLLibraryHandle
OpenCLibraryOpen() noexcept
{
return ::LoadLibraryA("OpenCL.dll");
}
void *
OpenCLibrarySymbol(OpenCLLibraryHandle handle,
const char *symbolName) noexcept
{
if (handle == nullptr || symbolName == nullptr) {
return nullptr;
}
return reinterpret_cast<void *>(::GetProcAddress(handle, symbolName));
}
void
OpenCLibraryClose(OpenCLLibraryHandle handle) noexcept
{
if (handle != nullptr) {
::FreeLibrary(handle);
}
}
#elif defined(__linux__)
OpenCLLibraryHandle
OpenCLibraryOpen() noexcept
{
OpenCLLibraryHandle handle = ::dlopen("libOpenCL.so.1", RTLD_NOW | RTLD_LOCAL);
if (handle == nullptr) {
handle = ::dlopen("libOpenCL.so", RTLD_NOW | RTLD_LOCAL);
}
return handle;
}
void *
OpenCLibrarySymbol(OpenCLLibraryHandle handle,
const char *symbolName) noexcept
{
if (handle == nullptr || symbolName == nullptr) {
return nullptr;
}
return ::dlsym(handle, symbolName);
}
void
OpenCLibraryClose(OpenCLLibraryHandle handle) noexcept
{
if (handle != nullptr) {
::dlclose(handle);
}
}
#else
OpenCLLibraryHandle
OpenCLibraryOpen() noexcept
{
return nullptr;
}
void *
OpenCLibrarySymbol(OpenCLLibraryHandle,
const char *) noexcept
{
return nullptr;
}
void
OpenCLibraryClose(OpenCLLibraryHandle) noexcept
{}
#endif
bool
ResolveOpenCLRuntimeSymbols(OpenCLLibraryHandle handle,
OpenCLRuntimeDispatch &dispatch) noexcept
{
#define PDJE_RESOLVE_DISPATCH_SYMBOL(name) \
dispatch.name = reinterpret_cast<decltype(dispatch.name)>( \
OpenCLibrarySymbol(handle, #name)); \
if (dispatch.name == nullptr) { \
return false; \
}
PDJE_OPENCL_RUNTIME_SYMBOLS(PDJE_RESOLVE_DISPATCH_SYMBOL)
#undef PDJE_RESOLVE_DISPATCH_SYMBOL
return true;
}
bool
SmokeProbeOpenCLPlatforms(const OpenCLRuntimeDispatch &dispatch) noexcept
{
cl_uint platformCount = 0;
const cl_int err = dispatch.clGetPlatformIDs(0, nullptr, &platformCount);
return err == CL_SUCCESS && platformCount > 0;
}
void
InitializeOpenCLRuntime() noexcept
{
#if !defined(_WIN32) && !defined(__linux__)
return;
#else
OpenCLRuntimeDispatch dispatch;
OpenCLLibraryHandle handle = OpenCLibraryOpen();
if (handle == nullptr) {
return;
}
if (!ResolveOpenCLRuntimeSymbols(handle, dispatch) ||
!SmokeProbeOpenCLPlatforms(dispatch)) {
OpenCLibraryClose(handle);
return;
}
gOpenCLDispatch = dispatch;
gOpenCLLibraryHandle = handle;
gOpenCLRuntimeReady.store(true, std::memory_order_release);
#endif
}
const OpenCLRuntimeDispatch *
GetOpenCLRuntimeDispatch() noexcept
{
if (!gOpenCLRuntimeReady.load(std::memory_order_acquire)) {
return nullptr;
}
return &gOpenCLDispatch;
}
cl_int
GetUnavailableOpenCLError() noexcept
{
return CL_INVALID_OPERATION;
}
cl_int
GetUnavailablePlatformError() noexcept
{
return CL_PLATFORM_NOT_FOUND_KHR;
}
#define PDJE_OPENCL_INT_WRAPPER(name, signature, arguments, failureCode) \
extern "C" CL_API_ENTRY cl_int CL_API_CALL \
name signature \
{ \
const auto *dispatch = GetOpenCLRuntimeDispatch(); \
if (dispatch == nullptr || dispatch->name == nullptr) { \
return failureCode; \
} \
return dispatch->name arguments; \
}
#define PDJE_OPENCL_HANDLE_WRAPPER(returnType, name, signature, arguments, \
errcode_ret_name) \
extern "C" CL_API_ENTRY returnType CL_API_CALL \
name signature \
{ \
const auto *dispatch = GetOpenCLRuntimeDispatch(); \
if (dispatch == nullptr || dispatch->name == nullptr) { \
if (errcode_ret_name != nullptr) { \
*errcode_ret_name = GetUnavailableOpenCLError(); \
} \
return nullptr; \
} \
return dispatch->name arguments; \
}
#define PDJE_OPENCL_VOIDPTR_WRAPPER(name, signature, arguments) \
extern "C" CL_API_ENTRY void * CL_API_CALL \
name signature \
{ \
const auto *dispatch = GetOpenCLRuntimeDispatch(); \
if (dispatch == nullptr || dispatch->name == nullptr) { \
return nullptr; \
} \
return dispatch->name arguments; \
}
PDJE_OPENCL_INT_WRAPPER(clGetPlatformIDs,
(cl_uint num_entries,
cl_platform_id * platforms,
cl_uint * num_platforms),
(num_entries, platforms, num_platforms),
GetUnavailablePlatformError())
PDJE_OPENCL_INT_WRAPPER(clGetPlatformInfo,
(cl_platform_id platform,
cl_platform_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret),
(platform,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clGetDeviceIDs,
(cl_platform_id platform,
cl_device_type device_type,
cl_uint num_entries,
cl_device_id * devices,
cl_uint * num_devices),
(platform,
device_type,
num_entries,
devices,
num_devices),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clGetDeviceInfo,
(cl_device_id device,
cl_device_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret),
(device,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clRetainDevice,
(cl_device_id device),
(device),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clReleaseDevice,
(cl_device_id device),
(device),
GetUnavailableOpenCLError())
PDJE_OPENCL_HANDLE_WRAPPER(
cl_context,
clCreateContext,
(const cl_context_properties *properties,
cl_uint num_devices,
const cl_device_id *devices,
void (CL_CALLBACK *pfn_notify)(const char *errinfo,
const void *private_info,
size_t cb,
void *user_data),
void *user_data,
cl_int *errcode_ret),
(properties, num_devices, devices, pfn_notify, user_data, errcode_ret),
errcode_ret)
PDJE_OPENCL_HANDLE_WRAPPER(
cl_context,
clCreateContextFromType,
(const cl_context_properties *properties,
cl_device_type device_type,
void (CL_CALLBACK *pfn_notify)(const char *errinfo,
const void *private_info,
size_t cb,
void *user_data),
void *user_data,
cl_int *errcode_ret),
(properties, device_type, pfn_notify, user_data, errcode_ret),
errcode_ret)
PDJE_OPENCL_INT_WRAPPER(clGetContextInfo,
(cl_context context,
cl_context_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret),
(context,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clRetainContext,
(cl_context context),
(context),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clReleaseContext,
(cl_context context),
(context),
GetUnavailableOpenCLError())
PDJE_OPENCL_HANDLE_WRAPPER(
cl_command_queue,
clCreateCommandQueue,
(cl_context context,
cl_device_id device,
cl_command_queue_properties properties,
cl_int *errcode_ret),
(context, device, properties, errcode_ret),
errcode_ret)
PDJE_OPENCL_HANDLE_WRAPPER(
cl_command_queue,
clCreateCommandQueueWithProperties,
(cl_context context,
cl_device_id device,
const cl_queue_properties *properties,
cl_int *errcode_ret),
(context, device, properties, errcode_ret),
errcode_ret)
PDJE_OPENCL_INT_WRAPPER(clGetCommandQueueInfo,
(cl_command_queue command_queue,
cl_command_queue_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret),
(command_queue,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clRetainCommandQueue,
(cl_command_queue command_queue),
(command_queue),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clReleaseCommandQueue,
(cl_command_queue command_queue),
(command_queue),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clFlush,
(cl_command_queue command_queue),
(command_queue),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clFinish,
(cl_command_queue command_queue),
(command_queue),
GetUnavailableOpenCLError())
PDJE_OPENCL_HANDLE_WRAPPER(
cl_program,
clCreateProgramWithSource,
(cl_context context,
cl_uint count,
const char **strings,
const size_t *lengths,
cl_int *errcode_ret),
(context, count, strings, lengths, errcode_ret),
errcode_ret)
PDJE_OPENCL_INT_WRAPPER(
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),
(program, num_devices, device_list, options, pfn_notify, user_data),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clGetProgramInfo,
(cl_program program,
cl_program_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret),
(program,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(
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),
(program,
device,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clRetainProgram,
(cl_program program),
(program),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clReleaseProgram,
(cl_program program),
(program),
GetUnavailableOpenCLError())
PDJE_OPENCL_HANDLE_WRAPPER(cl_kernel,
clCreateKernel,
(cl_program program,
const char *kernel_name,
cl_int *errcode_ret),
(program, kernel_name, errcode_ret),
errcode_ret)
PDJE_OPENCL_INT_WRAPPER(clSetKernelArg,
(cl_kernel kernel,
cl_uint arg_index,
size_t arg_size,
const void * arg_value),
(kernel, arg_index, arg_size, arg_value),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clGetKernelInfo,
(cl_kernel kernel,
cl_kernel_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret),
(kernel,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(
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),
(kernel,
device,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clRetainKernel,
(cl_kernel kernel),
(kernel),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clReleaseKernel,
(cl_kernel kernel),
(kernel),
GetUnavailableOpenCLError())
PDJE_OPENCL_HANDLE_WRAPPER(cl_mem,
clCreateBuffer,
(cl_context context,
cl_mem_flags flags,
size_t size,
void *host_ptr,
cl_int *errcode_ret),
(context, flags, size, host_ptr, errcode_ret),
errcode_ret)
PDJE_OPENCL_HANDLE_WRAPPER(
cl_mem,
clCreateBufferWithProperties,
(cl_context context,
const cl_mem_properties *properties,
cl_mem_flags flags,
size_t size,
void *host_ptr,
cl_int *errcode_ret),
(context, properties, flags, size, host_ptr, errcode_ret),
errcode_ret)
PDJE_OPENCL_INT_WRAPPER(clGetMemObjectInfo,
(cl_mem memobj,
cl_mem_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret),
(memobj,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clRetainMemObject,
(cl_mem memobj),
(memobj),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clReleaseMemObject,
(cl_mem memobj),
(memobj),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(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),
(command_queue,
buffer,
blocking_read,
offset,
size,
ptr,
num_events_in_wait_list,
event_wait_list,
event),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(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),
(command_queue,
buffer,
blocking_write,
offset,
size,
ptr,
num_events_in_wait_list,
event_wait_list,
event),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(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),
(command_queue,
kernel,
work_dim,
global_work_offset,
global_work_size,
local_work_size,
num_events_in_wait_list,
event_wait_list,
event),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clWaitForEvents,
(cl_uint num_events,
const cl_event * event_list),
(num_events, event_list),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clGetEventInfo,
(cl_event event,
cl_event_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret),
(event,
param_name,
param_value_size,
param_value,
param_value_size_ret),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clRetainEvent,
(cl_event event),
(event),
GetUnavailableOpenCLError())
PDJE_OPENCL_INT_WRAPPER(clReleaseEvent,
(cl_event event),
(event),
GetUnavailableOpenCLError())
PDJE_OPENCL_VOIDPTR_WRAPPER(clGetExtensionFunctionAddress,
(const char * func_name),
(func_name))
PDJE_OPENCL_VOIDPTR_WRAPPER(clGetExtensionFunctionAddressForPlatform,
(cl_platform_id platform,
const char * func_name),
(platform, func_name))
#undef PDJE_OPENCL_INT_WRAPPER
#undef PDJE_OPENCL_HANDLE_WRAPPER
#undef PDJE_OPENCL_VOIDPTR_WRAPPER
#undef PDJE_OPENCL_RUNTIME_SYMBOLS
} // namespace
namespace PDJE_PARALLEL {
bool
EnsureOpenCLRuntimeLoaded() noexcept
{
#if !defined(_WIN32) && !defined(__linux__)
return false;
#else
std::call_once(gOpenCLRuntimeInitOnce, InitializeOpenCLRuntime);
return gOpenCLRuntimeReady.load(std::memory_order_acquire);
#endif
}
} // namespace PDJE_PARALLEL