gr-fosphor/lib/fosphor/cl_compat.c

287 lines
6.5 KiB
C

/*
* cl_compat.c
*
* Handle OpenCL 1.1 <> 1.2 fallback and the related uglyness
*
* Copyright (C) 2013-2021 Sylvain Munaut
* SPDX-License-Identifier: GPL-3.0-or-later
*/
/*! \addtogroup cl
* @{
*/
/*! \file cl_compat.c
* \brief Handle OpenCL 1.1 <> 1.2 fallback and the related uglyness
*/
/* Include whatever is needed for dynamic symbol lookup */
#ifdef _WIN32
# include <windows.h>
#else
# define _GNU_SOURCE
# include <dlfcn.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Make sure we allow OpenCL 1.1 fn without warnings */
#define CL_USE_DEPRECATED_OPENCL_1_1_APIS
#include "cl_compat.h"
/* -------------------------------------------------------------------------- */
/* Fallback magic */
/* -------------------------------------------------------------------------- */
#define ALT_WRAP(rtype, fn, arg_list, arg_call) \
\
static CL_API_ENTRY rtype (CL_API_CALL * fn ## _icd) arg_list = NULL; \
static rtype fn ## _alt arg_list; \
\
CL_API_ENTRY rtype CL_API_CALL fn arg_list \
{ \
if (g_allow_cl12 && fn ## _icd) \
return fn ## _icd arg_call; \
else \
return fn ## _alt arg_call; \
} \
\
static rtype fn ## _alt arg_list
#define ALT_INIT(fn) \
*(void **)(&fn ## _icd) = _cl_icd_get_sym(#fn); \
if (!fn ## _icd) \
g_allow_cl12 = 0;
/*! \brief Whether to allow direct CL 1.2 usage or not */
static int g_allow_cl12 = 1;
/*! \brief Tries to find a function pointer to a given OpenCL function
* \param[in] fn The name of the function to lookup
*/
static void *
_cl_icd_get_sym(const char *fn)
{
#ifdef _WIN32
static HMODULE h = NULL;
if (!h)
h = GetModuleHandle(L"OpenCL.dll");
return GetProcAddress(h, fn);
#else
return dlsym(RTLD_NEXT, fn);
#endif
}
/* -------------------------------------------------------------------------- */
/* Fallback implementations */
/* -------------------------------------------------------------------------- */
/* These are only valid for fosphor and might not cover all use cases ! */
ALT_WRAP(cl_mem,
clCreateFromGLTexture,
(cl_context context,
cl_mem_flags flags,
GLenum texture_target,
GLint miplevel,
GLuint texture,
cl_int *errcode_ret),
(context, flags, texture_target, miplevel, texture, errcode_ret)
)
{
return clCreateFromGLTexture2D(
context,
flags,
texture_target,
miplevel,
texture,
errcode_ret
);
}
ALT_WRAP(cl_mem,
clCreateImage,
(cl_context context,
cl_mem_flags flags,
const cl_image_format *image_format,
const cl_image_desc *image_desc,
void *host_ptr,
cl_int *errcode_ret),
(context, flags, image_format, image_desc, host_ptr, errcode_ret)
)
{
if (image_desc->image_type != CL_MEM_OBJECT_IMAGE2D)
{
*errcode_ret = CL_IMAGE_FORMAT_NOT_SUPPORTED;
return NULL;
}
return clCreateImage2D(
context,
flags,
image_format,
image_desc->image_width,
image_desc->image_height,
image_desc->image_row_pitch,
host_ptr,
errcode_ret
);
}
ALT_WRAP(cl_int,
clEnqueueFillBuffer,
(cl_command_queue command_queue,
cl_mem buffer,
const void *pattern,
size_t pattern_size,
size_t offset,
size_t size,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event),
(command_queue, buffer, pattern, pattern_size, offset, size,
num_events_in_wait_list, event_wait_list, event)
)
{
cl_int err;
char *buf;
int i;
/* Generate the pattern 'manually' */
buf = malloc(size);
if (!buf)
return CL_OUT_OF_RESOURCES;
for (i=0; i<size; i+=pattern_size)
{
int s = (size - i) > pattern_size ? pattern_size : (size - i);
memcpy(&buf[i], pattern, s);
}
/* Do a blocking write */
err = clEnqueueWriteBuffer(
command_queue,
buffer,
CL_TRUE,
offset,
size,
buf,
num_events_in_wait_list,
event_wait_list,
event
);
/* Done */
free(buf);
return err;
}
ALT_WRAP(cl_int,
clEnqueueFillImage,
(cl_command_queue command_queue,
cl_mem image,
const void *fill_color,
const size_t *origin,
const size_t *region,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event),
(command_queue, image, fill_color, origin, region,
num_events_in_wait_list, event_wait_list, event)
)
{
cl_int err;
cl_image_format fmt;
float *buf, *color = (float *)fill_color;
int i;
/* Grab a bunch of infos about the image */
err = clGetImageInfo(image, CL_IMAGE_FORMAT, sizeof(fmt), &fmt, NULL);
if (err != CL_SUCCESS)
return err;
/* Very limited replacement :p */
if ((fmt.image_channel_order != CL_R) ||
(fmt.image_channel_data_type != CL_FLOAT))
return CL_IMAGE_FORMAT_NOT_SUPPORTED;
if ((origin[2] != 0) || (region[2] != 1))
return CL_IMAGE_FORMAT_NOT_SUPPORTED;
/* Fill a buffer manually */
buf = malloc(region[0] * region[1] * sizeof(float));
if (!buf)
return CL_OUT_OF_RESOURCES;
for (i=0; i<(region[0] * region[1]); i++)
buf[i] = color[0];
/* Do a blocking write */
err = clEnqueueWriteImage(
command_queue,
image,
CL_TRUE,
origin,
region,
0,
0,
buf,
num_events_in_wait_list,
event_wait_list,
event
);
/* Done */
free(buf);
return err;
}
/* -------------------------------------------------------------------------- */
/* Compat API control */
/* -------------------------------------------------------------------------- */
void
cl_compat_init(void)
{
ALT_INIT(clCreateFromGLTexture)
ALT_INIT(clCreateImage)
ALT_INIT(clEnqueueFillBuffer)
ALT_INIT(clEnqueueFillImage)
}
void
cl_compat_check_platform(cl_platform_id pl_id)
{
cl_int err;
char buf[128];
if (!g_allow_cl12)
return;
err = clGetPlatformInfo(pl_id, CL_PLATFORM_VERSION, sizeof(buf), buf, NULL);
if (err != CL_SUCCESS) {
fprintf(stderr, "[!] Failed to fetch platform version. Assume it can't do OpenCL 1.2\n");
g_allow_cl12 = 0;
}
if (!strncmp(buf, "OpenCL 1.2 pocl", 15)) {
fprintf(stderr, "[w] POCL detected, blacklisting CL 1.2 since it's buggy\n");
g_allow_cl12 = 0;
}
if (strncmp(buf, "OpenCL 1.2 ", 11)) {
g_allow_cl12 = 0;
}
}
/*! @} */