//
// Copyright 2012 Francisco Jerez
//
// 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 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 "api/util.hpp"
#include "core/memory.hpp"
#include "core/format.hpp"
using namespace clover;
PUBLIC cl_mem
clCreateBuffer(cl_context ctx, cl_mem_flags flags, size_t size,
void *host_ptr, cl_int *errcode_ret) try {
if (!ctx)
throw error(CL_INVALID_CONTEXT);
if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
CL_MEM_COPY_HOST_PTR)))
throw error(CL_INVALID_HOST_PTR);
if (!size)
throw error(CL_INVALID_BUFFER_SIZE);
if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
CL_MEM_COPY_HOST_PTR))
throw error(CL_INVALID_VALUE);
ret_error(errcode_ret, CL_SUCCESS);
return new root_buffer(*ctx, flags, size, host_ptr);
} catch (error &e) {
ret_error(errcode_ret, e);
return NULL;
}
PUBLIC cl_mem
clCreateSubBuffer(cl_mem obj, cl_mem_flags flags, cl_buffer_create_type op,
const void *op_info, cl_int *errcode_ret) try {
root_buffer *parent = dynamic_cast<root_buffer *>(obj);
if (!parent)
throw error(CL_INVALID_MEM_OBJECT);
if ((flags & (CL_MEM_USE_HOST_PTR |
CL_MEM_ALLOC_HOST_PTR |
CL_MEM_COPY_HOST_PTR)) ||
(~flags & parent->flags() & (CL_MEM_READ_ONLY |
CL_MEM_WRITE_ONLY)))
throw error(CL_INVALID_VALUE);
if (op == CL_BUFFER_CREATE_TYPE_REGION) {
const cl_buffer_region *reg = (const cl_buffer_region *)op_info;
if (!reg ||
reg->origin > parent->size() ||
reg->origin + reg->size > parent->size())
throw error(CL_INVALID_VALUE);
if (!reg->size)
throw error(CL_INVALID_BUFFER_SIZE);
ret_error(errcode_ret, CL_SUCCESS);
return new sub_buffer(*parent, flags, reg->origin, reg->size);
} else {
throw error(CL_INVALID_VALUE);
}
} catch (error &e) {
ret_error(errcode_ret, e);
return NULL;
}
PUBLIC cl_mem
clCreateImage2D(cl_context ctx, cl_mem_flags flags,
const cl_image_format *format,
size_t width, size_t height, size_t row_pitch,
void *host_ptr, cl_int *errcode_ret) try {
if (!ctx)
throw error(CL_INVALID_CONTEXT);
if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
CL_MEM_COPY_HOST_PTR))
throw error(CL_INVALID_VALUE);
if (!format)
throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
if (width < 1 || height < 1)
throw error(CL_INVALID_IMAGE_SIZE);
if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
CL_MEM_COPY_HOST_PTR)))
throw error(CL_INVALID_HOST_PTR);
if (!supported_formats(ctx, CL_MEM_OBJECT_IMAGE2D).count(*format))
throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
ret_error(errcode_ret, CL_SUCCESS);
return new image2d(*ctx, flags, format, width, height,
row_pitch, host_ptr);
} catch (error &e) {
ret_error(errcode_ret, e);
return NULL;
}
PUBLIC cl_mem
clCreateImage3D(cl_context ctx, cl_mem_flags flags,
const cl_image_format *format,
size_t width, size_t height, size_t depth,
size_t row_pitch, size_t slice_pitch,
void *host_ptr, cl_int *errcode_ret) try {
if (!ctx)
throw error(CL_INVALID_CONTEXT);
if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
CL_MEM_COPY_HOST_PTR))
throw error(CL_INVALID_VALUE);
if (!format)
throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
if (width < 1 || height < 1 || depth < 2)
throw error(CL_INVALID_IMAGE_SIZE);
if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
CL_MEM_COPY_HOST_PTR)))
throw error(CL_INVALID_HOST_PTR);
if (!supported_formats(ctx, CL_MEM_OBJECT_IMAGE3D).count(*format))
throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
ret_error(errcode_ret, CL_SUCCESS);
return new image3d(*ctx, flags, format, width, height, depth,
row_pitch, slice_pitch, host_ptr);
} catch (error &e) {
ret_error(errcode_ret, e);
return NULL;
}
PUBLIC cl_int
clGetSupportedImageFormats(cl_context ctx, cl_mem_flags flags,
cl_mem_object_type type, cl_uint count,
cl_image_format *buf, cl_uint *count_ret) try {
if (!ctx)
throw error(CL_INVALID_CONTEXT);
if (flags & ~(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY |
CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR |
CL_MEM_COPY_HOST_PTR))
throw error(CL_INVALID_VALUE);
if (!count && buf)
throw error(CL_INVALID_VALUE);
auto formats = supported_formats(ctx, type);
if (buf)
std::copy_n(formats.begin(), std::min((cl_uint)formats.size(), count),
buf);
if (count_ret)
*count_ret = formats.size();
return CL_SUCCESS;
} catch (error &e) {
return e.get();
}
PUBLIC cl_int
clGetMemObjectInfo(cl_mem obj, cl_mem_info param,
size_t size, void *buf, size_t *size_ret) {
if (!obj)
return CL_INVALID_MEM_OBJECT;
switch (param) {
case CL_MEM_TYPE:
return scalar_property<cl_mem_object_type>(buf, size, size_ret,
obj->type());
case CL_MEM_FLAGS:
return scalar_property<cl_mem_flags>(buf, size, size_ret, obj->flags());
case CL_MEM_SIZE:
return scalar_property<size_t>(buf, size, size_ret, obj->size());
case CL_MEM_HOST_PTR:
return scalar_property<void *>(buf, size, size_ret, obj->host_ptr());
case CL_MEM_MAP_COUNT:
return scalar_property<cl_uint>(buf, size, size_ret, 0);
case CL_MEM_REFERENCE_COUNT:
return scalar_property<cl_uint>(buf, size, size_ret, obj->ref_count());
case CL_MEM_CONTEXT:
return scalar_property<cl_context>(buf, size, size_ret, &obj->ctx);
case CL_MEM_ASSOCIATED_MEMOBJECT: {
sub_buffer *sub = dynamic_cast<sub_buffer *>(obj);
return scalar_property<cl_mem>(buf, size, size_ret,
(sub ? &sub->parent : NULL));
}
case CL_MEM_OFFSET: {
sub_buffer *sub = dynamic_cast<sub_buffer *>(obj);
return scalar_property<size_t>(buf, size, size_ret,
(sub ? sub->offset() : 0));
}
default:
return CL_INVALID_VALUE;
}
}
PUBLIC cl_int
clGetImageInfo(cl_mem obj, cl_image_info param,
size_t size, void *buf, size_t *size_ret) {
image *img = dynamic_cast<image *>(obj);
if (!img)
return CL_INVALID_MEM_OBJECT;
switch (param) {
case CL_IMAGE_FORMAT:
return scalar_property<cl_image_format>(buf, size, size_ret,
img->format());
case CL_IMAGE_ELEMENT_SIZE:
return scalar_property<size_t>(buf, size, size_ret, 0);
case CL_IMAGE_ROW_PITCH:
return scalar_property<size_t>(buf, size, size_ret, img->row_pitch());
case CL_IMAGE_SLICE_PITCH:
return scalar_property<size_t>(buf, size, size_ret, img->slice_pitch());
case CL_IMAGE_WIDTH:
return scalar_property<size_t>(buf, size, size_ret, img->width());
case CL_IMAGE_HEIGHT:
return scalar_property<size_t>(buf, size, size_ret, img->height());
case CL_IMAGE_DEPTH:
return scalar_property<size_t>(buf, size, size_ret, img->depth());
default:
return CL_INVALID_VALUE;
}
}
PUBLIC cl_int
clRetainMemObject(cl_mem obj) {
if (!obj)
return CL_INVALID_MEM_OBJECT;
obj->retain();
return CL_SUCCESS;
}
PUBLIC cl_int
clReleaseMemObject(cl_mem obj) {
if (!obj)
return CL_INVALID_MEM_OBJECT;
if (obj->release())
delete obj;
return CL_SUCCESS;
}
PUBLIC cl_int
clSetMemObjectDestructorCallback(cl_mem obj,
void (CL_CALLBACK *pfn_notify)(cl_mem, void *),
void *user_data) {
if (!obj)
return CL_INVALID_MEM_OBJECT;
if (!pfn_notify)
return CL_INVALID_VALUE;
obj->destroy_notify([=]{ pfn_notify(obj, user_data); });
return CL_SUCCESS;
}