/*
* Copyright © 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Author: Benjamin Segovia
*/
#include "cl_platform_id.h"
#include "cl_device_id.h"
#include "cl_context.h"
#include "cl_command_queue.h"
#include "cl_enqueue.h"
#include "cl_event.h"
#include "cl_program.h"
#include "cl_kernel.h"
#include "cl_mem.h"
#include "cl_image.h"
#include "cl_sampler.h"
#include "cl_accelerator_intel.h"
#include "cl_alloc.h"
#include "cl_utils.h"
#include "cl_cmrt.h"
#include "CL/cl.h"
#include "CL/cl_ext.h"
#include "CL/cl_intel.h"
#include
#include
#include
#include
#include "performance.h"
#ifndef CL_VERSION_1_2
#define CL_MAP_WRITE_INVALIDATE_REGION (1 << 2)
#define CL_DEVICE_TYPE_CUSTOM (1 << 4)
#define CL_MEM_HOST_WRITE_ONLY (1 << 7)
#define CL_MEM_HOST_READ_ONLY (1 << 8)
#define CL_MEM_HOST_NO_ACCESS (1 << 9)
typedef intptr_t cl_device_partition_property;
#endif
#define FILL_GETINFO_RET(TYPE, ELT, VAL, RET) \
do { \
if (param_value && param_value_size < sizeof(TYPE)*ELT) \
return CL_INVALID_VALUE; \
if (param_value) { \
memset(param_value, 0, param_value_size); \
memcpy(param_value, (VAL), sizeof(TYPE)*ELT); \
} \
\
if (param_value_size_ret) \
*param_value_size_ret = sizeof(TYPE)*ELT; \
return RET; \
} while(0)
cl_int
clGetPlatformIDs(cl_uint num_entries,
cl_platform_id * platforms,
cl_uint * num_platforms)
{
if(UNLIKELY(platforms == NULL && num_platforms == NULL))
return CL_INVALID_VALUE;
if(UNLIKELY(num_entries == 0 && platforms != NULL))
return CL_INVALID_VALUE;
return cl_get_platform_ids(num_entries, platforms, num_platforms);
}
cl_mem
clCreateBuffer(cl_context context,
cl_mem_flags flags,
size_t size,
void * host_ptr,
cl_int * errcode_ret)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
mem = cl_mem_new_buffer(context, flags, size, host_ptr, &err);
error:
if (errcode_ret)
*errcode_ret = err;
return mem;
}
cl_mem
clCreateSubBuffer(cl_mem buffer,
cl_mem_flags flags,
cl_buffer_create_type buffer_create_type,
const void * buffer_create_info,
cl_int * errcode_ret)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
CHECK_MEM(buffer);
mem = cl_mem_new_sub_buffer(buffer, flags, buffer_create_type,
buffer_create_info, &err);
error:
if (errcode_ret)
*errcode_ret = err;
return mem;
}
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)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
if (image_format == NULL) {
err = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
goto error;
}
if (image_format->image_channel_order < CL_R ||
(image_format->image_channel_order > CL_sBGRA && image_format->image_channel_order != CL_NV12_INTEL)) {
err = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
goto error;
}
if (image_format->image_channel_data_type < CL_SNORM_INT8 ||
image_format->image_channel_data_type > CL_FLOAT) {
err = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
goto error;
}
if (image_desc == NULL) {
err = CL_INVALID_IMAGE_DESCRIPTOR;
goto error;
}
if (image_desc->image_type <= CL_MEM_OBJECT_BUFFER ||
image_desc->image_type > CL_MEM_OBJECT_IMAGE1D_BUFFER) {
err = CL_INVALID_IMAGE_DESCRIPTOR;
goto error;
}
/* buffer refers to a valid buffer memory object if image_type is
CL_MEM_OBJECT_IMAGE1D_BUFFER or CL_MEM_OBJECT_IMAGE2D. Otherwise it must be NULL. */
if (image_desc->image_type != CL_MEM_OBJECT_IMAGE1D_BUFFER &&
image_desc->image_type != CL_MEM_OBJECT_IMAGE2D &&
image_desc->buffer) {
err = CL_INVALID_IMAGE_DESCRIPTOR;
goto error;
}
if (image_desc->num_mip_levels || image_desc->num_samples) {
err = CL_INVALID_IMAGE_DESCRIPTOR;
goto error;
}
if (image_format->image_channel_order == CL_NV12_INTEL &&
(image_format->image_channel_data_type != CL_UNORM_INT8 ||
image_desc->image_width % 4 || image_desc->image_height % 4)) {
err = CL_INVALID_IMAGE_DESCRIPTOR;
goto error;
}
/* Other details check for image_desc will leave to image create. */
mem = cl_mem_new_image(context,
flags,
image_format,
image_desc,
host_ptr,
&err);
error:
if (errcode_ret)
*errcode_ret = err;
return mem;
}
void *
clSVMAlloc (cl_context context,
cl_svm_mem_flags flags,
size_t size,
unsigned int alignment)
{
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
(void) err;
return cl_mem_svm_allocate(context, flags, size, alignment);
error:
return NULL;
}
void
clSVMFree (cl_context context, void* svm_pointer)
{
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
(void) err;
return cl_mem_svm_delete(context, svm_pointer);
error:
return;
}
cl_int
clEnqueueSVMFree (cl_command_queue command_queue,
cl_uint num_svm_pointers,
void *svm_pointers[],
void (CL_CALLBACK *pfn_free_func)( cl_command_queue queue,
cl_uint num_svm_pointers,
void *svm_pointers[],
void *user_data),
void *user_data,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
cl_int i = 0;
void** pointers = NULL;
cl_event e = NULL;
cl_int e_status;
enqueue_data *data;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if(num_svm_pointers == 0 || svm_pointers == NULL) {
err = CL_INVALID_VALUE;
break;
}
for(i=0; ictx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_SVM_FREE, &err);
if (err != CL_SUCCESS) {
break;
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
pointers = malloc(num_svm_pointers * sizeof(void *));
if(UNLIKELY(pointers == NULL)) {
err = CL_OUT_OF_HOST_MEMORY;
break;
}
memcpy(pointers, svm_pointers, num_svm_pointers * sizeof(void *));
data = &e->exec_data;
data->type = EnqueueSVMFree;
data->queue = command_queue;
data->pointers = pointers;
data->free_func = pfn_free_func;
data->size = num_svm_pointers;
data->ptr = user_data;
if (e_status == CL_COMPLETE) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
}
} while (0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int
clEnqueueSVMMap (cl_command_queue command_queue,
cl_bool blocking_map,
cl_map_flags map_flags,
void *svm_ptr,
size_t size,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
cl_mem buffer;
CHECK_QUEUE(command_queue);
buffer = cl_context_get_svm_from_ptr(command_queue->ctx, svm_ptr);
if(buffer == NULL) {
err = CL_INVALID_VALUE;
goto error;
}
clEnqueueMapBuffer(command_queue, buffer, blocking_map, map_flags, 0, size,
num_events_in_wait_list, event_wait_list, event, &err);
if(event)
(*event)->event_type = CL_COMMAND_SVM_MAP;
error:
return err;
}
cl_int
clEnqueueSVMUnmap (cl_command_queue command_queue,
void *svm_ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
cl_mem buffer;
CHECK_QUEUE(command_queue);
buffer = cl_context_get_svm_from_ptr(command_queue->ctx, svm_ptr);
if(buffer == NULL) {
err = CL_INVALID_VALUE;
goto error;
}
err = clEnqueueUnmapMemObject(command_queue, buffer, svm_ptr,
num_events_in_wait_list, event_wait_list, event);
if(event)
(*event)->event_type = CL_COMMAND_SVM_UNMAP;
error:
return err;
}
cl_int clEnqueueSVMMemcpy (cl_command_queue command_queue,
cl_bool blocking_copy,
void *dst_ptr,
const void *src_ptr,
size_t size,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
enqueue_data *data;
cl_int e_status;
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if(UNLIKELY(dst_ptr == NULL || src_ptr == NULL || size == 0 )) {
err = CL_INVALID_VALUE;
break;
}
if(((size_t)src_ptr < (size_t)dst_ptr && ((size_t)src_ptr + size > (size_t)dst_ptr)) ||
((size_t)dst_ptr < (size_t)src_ptr && ((size_t)dst_ptr + size > (size_t)src_ptr))) {
err = CL_MEM_COPY_OVERLAP;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_SVM_MEMCPY, &err);
if (err != CL_SUCCESS) {
break;
}
if (blocking_copy) {
err = cl_event_wait_for_event_ready(e);
if (err != CL_SUCCESS)
break;
/* Blocking call API is a sync point of flush. */
err = cl_command_queue_wait_flush(command_queue);
if (err != CL_SUCCESS) {
break;
}
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueSVMMemCopy;
data->queue = command_queue;
data->ptr = dst_ptr;
data->const_ptr = src_ptr;
data->size = size;
if (e_status == CL_COMPLETE) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
}
} while(0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_int clEnqueueSVMMemFill (cl_command_queue command_queue,
void *svm_ptr,
const void *pattern,
size_t pattern_size,
size_t size,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
{
cl_int err = CL_SUCCESS;
enqueue_data *data;
cl_int e_status;
cl_event e = NULL;
do {
if (!CL_OBJECT_IS_COMMAND_QUEUE(command_queue)) {
err = CL_INVALID_COMMAND_QUEUE;
break;
}
if(UNLIKELY(svm_ptr == NULL ||
((size_t)svm_ptr & (pattern_size - 1)) != 0)) {
err = CL_INVALID_VALUE;
break;
}
if(UNLIKELY(pattern == NULL ||
(pattern_size & (pattern_size - 1)) != 0 ||
pattern_size > 128)) {
err = CL_INVALID_VALUE;
break;
}
if(UNLIKELY(size == 0 ||
(size % pattern_size) != 0)) {
err = CL_INVALID_VALUE;
break;
}
err = cl_event_check_waitlist(num_events_in_wait_list, event_wait_list,
event, command_queue->ctx);
if (err != CL_SUCCESS) {
break;
}
e = cl_event_create(command_queue->ctx, command_queue, num_events_in_wait_list,
event_wait_list, CL_COMMAND_SVM_MEMFILL, &err);
if (err != CL_SUCCESS) {
break;
}
e_status = cl_event_is_ready(e);
if (e_status < CL_COMPLETE) {
err = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
break;
}
data = &e->exec_data;
data->type = EnqueueSVMMemFill;
data->queue = command_queue;
data->ptr = svm_ptr;
data->const_ptr = pattern;
data->pattern_size = pattern_size;
data->size = size;
if (e_status == CL_COMPLETE) {
// Sync mode, no need to queue event.
err = cl_event_exec(e, CL_COMPLETE, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
} else {
err = cl_event_exec(e, CL_QUEUED, CL_FALSE);
if (err != CL_SUCCESS) {
break;
}
cl_command_queue_enqueue_event(command_queue, e);
}
} while(0);
if (err == CL_SUCCESS && event) {
*event = e;
} else {
cl_event_delete(e);
}
return err;
}
cl_mem
clCreateImage2D(cl_context context,
cl_mem_flags flags,
const cl_image_format * image_format,
size_t image_width,
size_t image_height,
size_t image_row_pitch,
void * host_ptr,
cl_int * errcode_ret)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
cl_image_desc image_desc;
memset(&image_desc, 0, sizeof(image_desc));
image_desc.image_type = CL_MEM_OBJECT_IMAGE2D;
image_desc.image_width = image_width;
image_desc.image_height = image_height;
image_desc.image_row_pitch = image_row_pitch;
mem = cl_mem_new_image(context,
flags,
image_format,
&image_desc,
host_ptr,
&err);
error:
if (errcode_ret)
*errcode_ret = err;
return mem;
}
cl_mem
clCreateImage3D(cl_context context,
cl_mem_flags flags,
const cl_image_format * image_format,
size_t image_width,
size_t image_height,
size_t image_depth,
size_t image_row_pitch,
size_t image_slice_pitch,
void * host_ptr,
cl_int * errcode_ret)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
cl_image_desc image_desc;
image_desc.image_type = CL_MEM_OBJECT_IMAGE3D;
image_desc.image_width = image_width;
image_desc.image_height = image_height;
image_desc.image_depth = image_depth;
image_desc.image_row_pitch = image_row_pitch;
image_desc.image_slice_pitch = image_slice_pitch;
mem = cl_mem_new_image(context,
flags,
image_format,
&image_desc,
host_ptr,
&err);
error:
if (errcode_ret)
*errcode_ret = err;
return mem;
}
cl_int
clGetSupportedImageFormats(cl_context ctx,
cl_mem_flags flags,
cl_mem_object_type image_type,
cl_uint num_entries,
cl_image_format * image_formats,
cl_uint * num_image_formats)
{
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (ctx);
if (UNLIKELY(num_entries == 0 && image_formats != NULL)) {
err = CL_INVALID_VALUE;
goto error;
}
if (UNLIKELY(image_type != CL_MEM_OBJECT_IMAGE1D &&
image_type != CL_MEM_OBJECT_IMAGE1D_ARRAY &&
image_type != CL_MEM_OBJECT_IMAGE1D_BUFFER &&
image_type != CL_MEM_OBJECT_IMAGE2D_ARRAY &&
image_type != CL_MEM_OBJECT_IMAGE2D &&
image_type != CL_MEM_OBJECT_IMAGE3D)) {
err = CL_INVALID_VALUE;
goto error;
}
err = cl_image_get_supported_fmt(ctx,
flags,
image_type,
num_entries,
image_formats,
num_image_formats);
error:
return err;
}
cl_sampler
clCreateSamplerWithProperties(cl_context context,
const cl_sampler_properties *sampler_properties,
cl_int * errcode_ret)
{
cl_sampler sampler = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
cl_bool normalized = 0xFFFFFFFF;
cl_addressing_mode addressing = 0xFFFFFFFF;
cl_filter_mode filter = 0xFFFFFFFF;
if(sampler_properties)
{
cl_ulong sam_type;
cl_ulong sam_val;
cl_uint i;
for(i = 0;(sam_type = sampler_properties[i++])!=0;i++)
{
sam_val = sampler_properties[i];
switch(sam_type)
{
case CL_SAMPLER_NORMALIZED_COORDS:
if(normalized != 0xFFFFFFFF)
err = CL_INVALID_VALUE;
else if(sam_val == CL_TRUE || sam_val == CL_FALSE)
normalized = sam_val;
else
err = CL_INVALID_VALUE;
break;
case CL_SAMPLER_ADDRESSING_MODE:
if(addressing != 0xFFFFFFFF)
err = CL_INVALID_VALUE;
else if(sam_val == CL_ADDRESS_MIRRORED_REPEAT || sam_val == CL_ADDRESS_REPEAT ||
sam_val == CL_ADDRESS_CLAMP_TO_EDGE || sam_val == CL_ADDRESS_CLAMP ||
sam_val == CL_ADDRESS_NONE)
addressing = sam_val;
else
err = CL_INVALID_VALUE;
break;
case CL_SAMPLER_FILTER_MODE:
if(filter != 0xFFFFFFFF)
err = CL_INVALID_VALUE;
else if(sam_val == CL_FILTER_LINEAR || sam_val == CL_FILTER_NEAREST)
filter = sam_val;
else
err = CL_INVALID_VALUE;
break;
default:
err = CL_INVALID_VALUE;
break;
}
}
}
if(err)
goto error;
if(normalized == 0xFFFFFFFF) normalized = CL_TRUE;
if(addressing == 0xFFFFFFFF) addressing = CL_ADDRESS_CLAMP;
if(filter == 0xFFFFFFFF) filter = CL_FILTER_NEAREST;
sampler = cl_create_sampler(context, normalized, addressing, filter, &err);
error:
if (errcode_ret)
*errcode_ret = err;
return sampler;
}
cl_program
clCreateProgramWithSource(cl_context context,
cl_uint count,
const char ** strings,
const size_t * lengths,
cl_int * errcode_ret)
{
cl_program program = NULL;
cl_int err = CL_SUCCESS;
cl_uint i;
CHECK_CONTEXT (context);
INVALID_VALUE_IF (count == 0);
INVALID_VALUE_IF (strings == NULL);
for(i = 0; i < count; i++) {
if(UNLIKELY(strings[i] == NULL)) {
err = CL_INVALID_VALUE;
goto error;
}
}
program = cl_program_create_from_source(context,
count,
strings,
lengths,
&err);
error:
if (errcode_ret)
*errcode_ret = err;
return program;
}
cl_program
clCreateProgramWithBinary(cl_context context,
cl_uint num_devices,
const cl_device_id * devices,
const size_t * lengths,
const unsigned char ** binaries,
cl_int * binary_status,
cl_int * errcode_ret)
{
cl_program program = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
program = cl_program_create_from_binary(context,
num_devices,
devices,
lengths,
binaries,
binary_status,
&err);
error:
if (errcode_ret)
*errcode_ret = err;
return program;
}
cl_program
clCreateProgramWithBuiltInKernels(cl_context context,
cl_uint num_devices,
const cl_device_id * device_list,
const char * kernel_names,
cl_int * errcode_ret)
{
cl_program program = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
INVALID_VALUE_IF (kernel_names == NULL);
program = cl_program_create_with_built_in_kernles(context,
num_devices,
device_list,
kernel_names,
&err);
error:
if (errcode_ret)
*errcode_ret = err;
return program;
}
cl_int
clRetainProgram(cl_program program)
{
cl_int err = CL_SUCCESS;
CHECK_PROGRAM (program);
cl_program_add_ref(program);
error:
return err;
}
cl_int
clReleaseProgram(cl_program program)
{
cl_int err = CL_SUCCESS;
CHECK_PROGRAM (program);
cl_program_delete(program);
error:
return err;
}
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, void*),
void * user_data)
{
cl_int err = CL_SUCCESS;
CHECK_PROGRAM(program);
INVALID_VALUE_IF (num_devices > 1);
INVALID_VALUE_IF (num_devices == 0 && device_list != NULL);
INVALID_VALUE_IF (num_devices != 0 && device_list == NULL);
INVALID_VALUE_IF (pfn_notify == 0 && user_data != NULL);
/* Everything is easy. We only support one device anyway */
if (num_devices != 0) {
assert(program->ctx);
err = cl_devices_list_include_check(program->ctx->device_num,
program->ctx->devices, num_devices, device_list);
if (err)
goto error;
}
assert(program->source_type == FROM_LLVM ||
program->source_type == FROM_SOURCE ||
program->source_type == FROM_LLVM_SPIR ||
program->source_type == FROM_BINARY ||
program->source_type == FROM_CMRT);
if((err = cl_program_build(program, options)) != CL_SUCCESS) {
goto error;
}
program->is_built = CL_TRUE;
if (pfn_notify) pfn_notify(program, user_data);
error:
return err;
}
cl_int
clCompileProgram(cl_program program ,
cl_uint num_devices ,
const cl_device_id * device_list ,
const char * options ,
cl_uint num_input_headers ,
const cl_program * input_headers ,
const char ** header_include_names ,
void (CL_CALLBACK * pfn_notify )(cl_program, void *),
void * user_data )
{
cl_int err = CL_SUCCESS;
CHECK_PROGRAM(program);
INVALID_VALUE_IF (num_devices > 1);
INVALID_VALUE_IF (num_devices == 0 && device_list != NULL);
INVALID_VALUE_IF (num_devices != 0 && device_list == NULL);
INVALID_VALUE_IF (pfn_notify == 0 && user_data != NULL);
INVALID_VALUE_IF (num_input_headers == 0 && input_headers != NULL);
INVALID_VALUE_IF (num_input_headers != 0 && input_headers == NULL);
/* Everything is easy. We only support one device anyway */
if (num_devices != 0) {
assert(program->ctx);
err = cl_devices_list_include_check(program->ctx->device_num,
program->ctx->devices, num_devices, device_list);
if (err)
goto error;
}
/* TODO support create program from binary */
assert(program->source_type == FROM_LLVM ||
program->source_type == FROM_SOURCE ||
program->source_type == FROM_LLVM_SPIR ||
program->source_type == FROM_BINARY);
if((err = cl_program_compile(program, num_input_headers, input_headers, header_include_names, options)) != CL_SUCCESS) {
goto error;
}
program->is_built = CL_TRUE;
if (pfn_notify) pfn_notify(program, user_data);
error:
return err;
}
cl_program
clLinkProgram(cl_context context,
cl_uint num_devices,
const cl_device_id * device_list,
const char * options,
cl_uint num_input_programs,
const cl_program * input_programs,
void (CL_CALLBACK * pfn_notify)(cl_program program, void * user_data),
void * user_data,
cl_int * errcode_ret)
{
cl_int err = CL_SUCCESS;
cl_program program = NULL;
CHECK_CONTEXT (context);
INVALID_VALUE_IF (num_devices > 1);
INVALID_VALUE_IF (num_devices == 0 && device_list != NULL);
INVALID_VALUE_IF (num_devices != 0 && device_list == NULL);
INVALID_VALUE_IF (pfn_notify == 0 && user_data != NULL);
INVALID_VALUE_IF (num_input_programs == 0 && input_programs != NULL);
INVALID_VALUE_IF (num_input_programs != 0 && input_programs == NULL);
INVALID_VALUE_IF (num_input_programs == 0 && input_programs == NULL);
program = cl_program_link(context, num_input_programs, input_programs, options, &err);
if(program) program->is_built = CL_TRUE;
if (pfn_notify) pfn_notify(program, user_data);
error:
if (errcode_ret)
*errcode_ret = err;
return program;
}
cl_int
clUnloadCompiler(void)
{
return CL_SUCCESS;
}
cl_int
clUnloadPlatformCompiler(cl_platform_id platform)
{
return CL_SUCCESS;
}
cl_kernel
clCreateKernel(cl_program program,
const char * kernel_name,
cl_int * errcode_ret)
{
cl_kernel kernel = NULL;
cl_int err = CL_SUCCESS;
CHECK_PROGRAM (program);
if (program->ker_n <= 0) {
err = CL_INVALID_PROGRAM_EXECUTABLE;
goto error;
}
INVALID_VALUE_IF (kernel_name == NULL);
kernel = cl_program_create_kernel(program, kernel_name, &err);
error:
if (errcode_ret)
*errcode_ret = err;
return kernel;
}
cl_int
clCreateKernelsInProgram(cl_program program,
cl_uint num_kernels,
cl_kernel * kernels,
cl_uint * num_kernels_ret)
{
cl_int err = CL_SUCCESS;
CHECK_PROGRAM (program);
if (program->ker_n <= 0) {
err = CL_INVALID_PROGRAM_EXECUTABLE;
goto error;
}
if (kernels && num_kernels < program->ker_n) {
err = CL_INVALID_VALUE;
goto error;
}
if(num_kernels_ret)
*num_kernels_ret = program->ker_n;
if(kernels)
err = cl_program_create_kernels_in_program(program, kernels);
error:
return err;
}
cl_int
clRetainKernel(cl_kernel kernel)
{
cl_int err = CL_SUCCESS;
CHECK_KERNEL(kernel);
cl_kernel_add_ref(kernel);
error:
return err;
}
cl_int
clReleaseKernel(cl_kernel kernel)
{
cl_int err = CL_SUCCESS;
CHECK_KERNEL(kernel);
cl_kernel_delete(kernel);
error:
return err;
}
cl_int
clSetKernelArg(cl_kernel kernel,
cl_uint arg_index,
size_t arg_size,
const void * arg_value)
{
cl_int err = CL_SUCCESS;
CHECK_KERNEL(kernel);
#ifdef HAS_CMRT
if (kernel->cmrt_kernel != NULL)
err = cmrt_set_kernel_arg(kernel, arg_index, arg_size, arg_value);
else
#endif
err = cl_kernel_set_arg(kernel, arg_index, arg_size, arg_value);
error:
return err;
}
cl_int
clSetKernelArgSVMPointer(cl_kernel kernel,
cl_uint arg_index,
const void *arg_value)
{
cl_int err = CL_SUCCESS;
CHECK_KERNEL(kernel);
err = cl_kernel_set_arg_svm_pointer(kernel, arg_index, arg_value);
error:
return err;
}
cl_int
clSetKernelExecInfo(cl_kernel kernel,
cl_kernel_exec_info param_name,
size_t param_value_size,
const void *param_value)
{
cl_int err = CL_SUCCESS;
CHECK_KERNEL(kernel);
if((param_name != CL_KERNEL_EXEC_INFO_SVM_PTRS &&
param_name != CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM) ||
param_value == NULL || param_value_size == 0) {
err = CL_INVALID_VALUE;
goto error;
}
if(param_name == CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM &&
*(cl_bool *)param_value == CL_TRUE) {
err = CL_INVALID_OPERATION;
goto error;
}
err = cl_kernel_set_exec_info(kernel, param_value_size, param_value);
error:
return err;
}
cl_int clGetKernelArgInfo(cl_kernel kernel, cl_uint arg_index, cl_kernel_arg_info param_name,
size_t param_value_size, void *param_value, size_t *param_value_size_ret)
{
cl_int err = CL_SUCCESS;
CHECK_KERNEL(kernel);
if(kernel->program->build_opts == NULL ||
strstr(kernel->program->build_opts,"-cl-kernel-arg-info") == NULL ) {
err = CL_KERNEL_ARG_INFO_NOT_AVAILABLE;
goto error;
}
if (param_name != CL_KERNEL_ARG_ADDRESS_QUALIFIER
&& param_name != CL_KERNEL_ARG_ACCESS_QUALIFIER
&& param_name != CL_KERNEL_ARG_TYPE_NAME
&& param_name != CL_KERNEL_ARG_TYPE_QUALIFIER
&& param_name != CL_KERNEL_ARG_NAME) {
err = CL_INVALID_VALUE;
goto error;
}
if (arg_index >= kernel->arg_n) {
err = CL_INVALID_ARG_INDEX;
goto error;
}
err = cl_get_kernel_arg_info(kernel, arg_index, param_name, param_value_size,
param_value, param_value_size_ret);
error:
return err;
}
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)
{
return cl_get_kernel_workgroup_info(kernel,
device,
param_name,
param_value_size,
param_value,
param_value_size_ret);
}
cl_int
clGetKernelSubGroupInfoKHR(cl_kernel kernel,
cl_device_id device,
cl_kernel_work_group_info param_name,
size_t input_value_size,
const void * input_value,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret)
{
return cl_get_kernel_subgroup_info(kernel,
device,
param_name,
input_value_size,
input_value,
param_value_size,
param_value,
param_value_size_ret);
}
cl_int
clRetainEvent(cl_event event)
{
cl_int err = CL_SUCCESS;
CHECK_EVENT(event);
cl_event_add_ref(event);
error:
return err;
}
cl_int
clReleaseEvent(cl_event event)
{
cl_int err = CL_SUCCESS;
CHECK_EVENT(event);
cl_event_delete(event);
error:
return err;
}
cl_mem clCreatePipe (cl_context context,
cl_mem_flags flags,
cl_uint pipe_packet_size,
cl_uint pipe_max_packets,
const cl_pipe_properties *properties,
cl_int *errcode_ret)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
cl_uint device_max_size = 0;
CHECK_CONTEXT (context);
if(UNLIKELY((flags & ~(CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS)) != 0)) {
err = CL_INVALID_VALUE;
goto error;
}
if(UNLIKELY(properties != NULL)) {
err = CL_INVALID_VALUE;
goto error;
}
if(UNLIKELY(pipe_packet_size == 0 || pipe_max_packets == 0)) {
err = CL_INVALID_PIPE_SIZE;
goto error;
}
if ((err = cl_get_device_info(context->devices[0],
CL_DEVICE_PIPE_MAX_PACKET_SIZE,
sizeof(device_max_size),
&device_max_size,
NULL)) != CL_SUCCESS) {
goto error;
}
if(UNLIKELY(pipe_packet_size > device_max_size)) {
err = CL_INVALID_PIPE_SIZE;
goto error;
}
if(flags == 0)
flags = CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS;
mem = cl_mem_new_pipe(context, flags, pipe_packet_size, pipe_max_packets, &err);
error:
if (errcode_ret)
*errcode_ret = err;
return mem;
}
cl_int clGetPipeInfo (cl_mem pipe,
cl_pipe_info param_name,
size_t param_value_size,
void *param_value,
size_t *param_value_size_ret)
{
cl_int err = CL_SUCCESS;
CHECK_MEM(pipe);
err = cl_get_pipe_info(pipe,
param_name,
param_value_size,
param_value,
param_value_size_ret);
error:
return err;
}
#define EXTFUNC(x) \
if (strcmp(#x, func_name) == 0) \
return (void *)x;
static void*
internal_clGetExtensionFunctionAddress(const char *func_name)
{
if (func_name == NULL)
return NULL;
#ifdef HAS_OCLIcd
/* cl_khr_icd */
EXTFUNC(clIcdGetPlatformIDsKHR)
#endif
EXTFUNC(clCreateProgramWithLLVMIntel)
EXTFUNC(clGetGenVersionIntel)
EXTFUNC(clMapBufferIntel)
EXTFUNC(clUnmapBufferIntel)
EXTFUNC(clMapBufferGTTIntel)
EXTFUNC(clUnmapBufferGTTIntel)
EXTFUNC(clPinBufferIntel)
EXTFUNC(clUnpinBufferIntel)
EXTFUNC(clReportUnfreedIntel)
EXTFUNC(clCreateBufferFromLibvaIntel)
EXTFUNC(clCreateImageFromLibvaIntel)
EXTFUNC(clGetMemObjectFdIntel)
EXTFUNC(clCreateBufferFromFdINTEL)
EXTFUNC(clCreateImageFromFdINTEL)
EXTFUNC(clCreateAcceleratorINTEL)
EXTFUNC(clRetainAcceleratorINTEL)
EXTFUNC(clReleaseAcceleratorINTEL)
EXTFUNC(clGetAcceleratorInfoINTEL)
EXTFUNC(clGetKernelSubGroupInfoKHR)
return NULL;
}
void*
clGetExtensionFunctionAddress(const char *func_name)
{
return internal_clGetExtensionFunctionAddress(func_name);
}
void*
clGetExtensionFunctionAddressForPlatform(cl_platform_id platform,
const char *func_name)
{
if (UNLIKELY(platform != NULL && platform != cl_get_platform_default()))
return NULL;
return internal_clGetExtensionFunctionAddress(func_name);
}
#undef EXTFUNC
cl_int
clReportUnfreedIntel(void)
{
return cl_report_unfreed();
}
void*
clMapBufferIntel(cl_mem mem, cl_int *errcode_ret)
{
void *ptr = NULL;
cl_int err = CL_SUCCESS;
CHECK_MEM (mem);
ptr = cl_mem_map(mem, 1);
error:
if (errcode_ret)
*errcode_ret = err;
return ptr;
}
cl_int
clUnmapBufferIntel(cl_mem mem)
{
cl_int err = CL_SUCCESS;
CHECK_MEM (mem);
err = cl_mem_unmap(mem);
error:
return err;
}
void*
clMapBufferGTTIntel(cl_mem mem, cl_int *errcode_ret)
{
void *ptr = NULL;
cl_int err = CL_SUCCESS;
CHECK_MEM (mem);
ptr = cl_mem_map_gtt(mem);
error:
if (errcode_ret)
*errcode_ret = err;
return ptr;
}
cl_int
clUnmapBufferGTTIntel(cl_mem mem)
{
cl_int err = CL_SUCCESS;
CHECK_MEM (mem);
err = cl_mem_unmap_gtt(mem);
error:
return err;
}
cl_int
clPinBufferIntel(cl_mem mem)
{
cl_int err = CL_SUCCESS;
CHECK_MEM (mem);
cl_mem_pin(mem);
error:
return err;
}
cl_int
clUnpinBufferIntel(cl_mem mem)
{
cl_int err = CL_SUCCESS;
CHECK_MEM (mem);
cl_mem_unpin(mem);
error:
return err;
}
cl_int
clGetGenVersionIntel(cl_device_id device, cl_int *ver)
{
return cl_device_get_version(device, ver);
}
cl_program
clCreateProgramWithLLVMIntel(cl_context context,
cl_uint num_devices,
const cl_device_id * devices,
const char * filename,
cl_int * errcode_ret)
{
return cl_program_create_from_llvm(context,
num_devices,
devices,
filename,
errcode_ret);
}
cl_mem
clCreateBufferFromLibvaIntel(cl_context context,
unsigned int bo_name,
cl_int *errorcode_ret)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
mem = cl_mem_new_libva_buffer(context, bo_name, &err);
error:
if (errorcode_ret)
*errorcode_ret = err;
return mem;
}
cl_mem
clCreateImageFromLibvaIntel(cl_context context,
const cl_libva_image *info,
cl_int *errorcode_ret)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
if (!info) {
err = CL_INVALID_VALUE;
goto error;
}
mem = cl_mem_new_libva_image(context,
info->bo_name, info->offset, info->width, info->height,
info->fmt, info->row_pitch,
&err);
error:
if (errorcode_ret)
*errorcode_ret = err;
return mem;
}
extern CL_API_ENTRY cl_int CL_API_CALL
clGetMemObjectFdIntel(cl_context context,
cl_mem memobj,
int* fd)
{
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
CHECK_MEM (memobj);
err = cl_mem_get_fd(memobj, fd);
error:
return err;
}
cl_mem
clCreateBufferFromFdINTEL(cl_context context,
const cl_import_buffer_info_intel* info,
cl_int *errorcode_ret)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
if (!info) {
err = CL_INVALID_VALUE;
goto error;
}
mem = cl_mem_new_buffer_from_fd(context, info->fd, info->size, &err);
error:
if (errorcode_ret)
*errorcode_ret = err;
return mem;
}
cl_mem
clCreateImageFromFdINTEL(cl_context context,
const cl_import_image_info_intel* info,
cl_int *errorcode_ret)
{
cl_mem mem = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT (context);
if (!info) {
err = CL_INVALID_VALUE;
goto error;
}
/* Create image object from fd.
* We just support creating CL_MEM_OBJECT_IMAGE2D image object now.
* Other image type will be supported later if necessary.
*/
if(info->type == CL_MEM_OBJECT_IMAGE2D){
mem = cl_mem_new_image_from_fd(context,
info->fd, info->size,
info->offset,
info->width, info->height,
info->fmt, info->row_pitch,
&err);
}
else{
err = CL_INVALID_ARG_VALUE;
goto error;
}
error:
if (errorcode_ret)
*errorcode_ret = err;
return mem;
}
cl_accelerator_intel
clCreateAcceleratorINTEL(cl_context context,
cl_accelerator_type_intel accel_type,
size_t desc_sz,
const void* desc,
cl_int* errcode_ret)
{
cl_accelerator_intel accel = NULL;
cl_int err = CL_SUCCESS;
CHECK_CONTEXT(context);
accel = cl_accelerator_intel_new(context, accel_type, desc_sz, desc, &err);
error:
if (errcode_ret)
*errcode_ret = err;
return accel;
}
cl_int
clRetainAcceleratorINTEL(cl_accelerator_intel accel)
{
cl_int err = CL_SUCCESS;
CHECK_ACCELERATOR_INTEL(accel);
cl_accelerator_intel_add_ref(accel);
error:
return err;
}
cl_int
clReleaseAcceleratorINTEL(cl_accelerator_intel accel)
{
cl_int err = CL_SUCCESS;
CHECK_ACCELERATOR_INTEL(accel);
cl_accelerator_intel_delete(accel);
error:
return err;
}
cl_int
clGetAcceleratorInfoINTEL(cl_accelerator_intel accel,
cl_accelerator_info_intel param_name,
size_t param_value_size,
void* param_value,
size_t* param_value_size_ret)
{
cl_int err = CL_SUCCESS;
CHECK_ACCELERATOR_INTEL(accel);
if (param_name == CL_ACCELERATOR_REFERENCE_COUNT_INTEL) {
cl_uint ref = CL_OBJECT_GET_REF(accel);
FILL_GETINFO_RET (cl_uint, 1, &ref, CL_SUCCESS);
} else if (param_name == CL_ACCELERATOR_CONTEXT_INTEL) {
FILL_GETINFO_RET (cl_context, 1, &accel->ctx, CL_SUCCESS);
} else if (param_name == CL_ACCELERATOR_TYPE_INTEL) {
FILL_GETINFO_RET (cl_uint, 1, &accel->type, CL_SUCCESS);
} else if (param_name == CL_ACCELERATOR_DESCRIPTOR_INTEL) {
FILL_GETINFO_RET (cl_motion_estimation_desc_intel, 1, &(accel->desc.me), CL_SUCCESS);
} else{
return CL_INVALID_VALUE;
}
error:
return err;
}