aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/frontends/clover/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/frontends/clover/api')
-rw-r--r--src/gallium/frontends/clover/api/context.cpp144
-rw-r--r--src/gallium/frontends/clover/api/device.cpp421
-rw-r--r--src/gallium/frontends/clover/api/dispatch.cpp174
-rw-r--r--src/gallium/frontends/clover/api/dispatch.hpp105
-rw-r--r--src/gallium/frontends/clover/api/event.cpp309
-rw-r--r--src/gallium/frontends/clover/api/interop.cpp69
-rw-r--r--src/gallium/frontends/clover/api/kernel.cpp390
-rw-r--r--src/gallium/frontends/clover/api/memory.cpp497
-rw-r--r--src/gallium/frontends/clover/api/platform.cpp235
-rw-r--r--src/gallium/frontends/clover/api/program.cpp479
-rw-r--r--src/gallium/frontends/clover/api/queue.cpp135
-rw-r--r--src/gallium/frontends/clover/api/sampler.cpp100
-rw-r--r--src/gallium/frontends/clover/api/transfer.cpp1059
-rw-r--r--src/gallium/frontends/clover/api/util.hpp84
14 files changed, 4201 insertions, 0 deletions
diff --git a/src/gallium/frontends/clover/api/context.cpp b/src/gallium/frontends/clover/api/context.cpp
new file mode 100644
index 00000000000..c0cd2d32b95
--- /dev/null
+++ b/src/gallium/frontends/clover/api/context.cpp
@@ -0,0 +1,144 @@
+//
+// 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 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 "api/util.hpp"
+#include "core/context.hpp"
+#include "core/platform.hpp"
+
+using namespace clover;
+
+CLOVER_API cl_context
+clCreateContext(const cl_context_properties *d_props, cl_uint num_devs,
+ const cl_device_id *d_devs,
+ void (CL_CALLBACK *pfn_notify)(const char *, const void *,
+ size_t, void *),
+ void *user_data, cl_int *r_errcode) try {
+ auto props = obj<property_list_tag>(d_props);
+ auto devs = objs(d_devs, num_devs);
+
+ if (!pfn_notify && user_data)
+ throw error(CL_INVALID_VALUE);
+
+ for (auto &prop : props) {
+ if (prop.first == CL_CONTEXT_PLATFORM)
+ obj(prop.second.as<cl_platform_id>());
+ else
+ throw error(CL_INVALID_PROPERTY);
+ }
+
+ const auto notify = (!pfn_notify ? context::notify_action() :
+ [=](const char *s) {
+ pfn_notify(s, NULL, 0, user_data);
+ });
+
+ ret_error(r_errcode, CL_SUCCESS);
+ return desc(new context(props, devs, notify));
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_context
+clCreateContextFromType(const cl_context_properties *d_props,
+ cl_device_type type,
+ void (CL_CALLBACK *pfn_notify)(
+ const char *, const void *, size_t, void *),
+ void *user_data, cl_int *r_errcode) try {
+ cl_platform_id d_platform;
+ cl_uint num_platforms;
+ cl_int ret;
+ std::vector<cl_device_id> devs;
+ cl_uint num_devices;
+
+ ret = clGetPlatformIDs(1, &d_platform, &num_platforms);
+ if (ret || !num_platforms)
+ throw error(CL_INVALID_PLATFORM);
+
+ ret = clGetDeviceIDs(d_platform, type, 0, NULL, &num_devices);
+ if (ret)
+ throw error(CL_DEVICE_NOT_FOUND);
+ devs.resize(num_devices);
+ ret = clGetDeviceIDs(d_platform, type, num_devices, devs.data(), 0);
+ if (ret)
+ throw error(CL_DEVICE_NOT_FOUND);
+
+ return clCreateContext(d_props, num_devices, devs.data(), pfn_notify,
+ user_data, r_errcode);
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_int
+clRetainContext(cl_context d_ctx) try {
+ obj(d_ctx).retain();
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clReleaseContext(cl_context d_ctx) try {
+ if (obj(d_ctx).release())
+ delete pobj(d_ctx);
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetContextInfo(cl_context d_ctx, cl_context_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &ctx = obj(d_ctx);
+
+ switch (param) {
+ case CL_CONTEXT_REFERENCE_COUNT:
+ buf.as_scalar<cl_uint>() = ctx.ref_count();
+ break;
+
+ case CL_CONTEXT_NUM_DEVICES:
+ buf.as_scalar<cl_uint>() = ctx.devices().size();
+ break;
+
+ case CL_CONTEXT_DEVICES:
+ buf.as_vector<cl_device_id>() = descs(ctx.devices());
+ break;
+
+ case CL_CONTEXT_PROPERTIES:
+ buf.as_vector<cl_context_properties>() = desc(ctx.properties());
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
diff --git a/src/gallium/frontends/clover/api/device.cpp b/src/gallium/frontends/clover/api/device.cpp
new file mode 100644
index 00000000000..042f2eda21c
--- /dev/null
+++ b/src/gallium/frontends/clover/api/device.cpp
@@ -0,0 +1,421 @@
+//
+// 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 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 "api/util.hpp"
+#include "core/platform.hpp"
+#include "core/device.hpp"
+#include "git_sha1.h"
+
+using namespace clover;
+
+CLOVER_API cl_int
+clGetDeviceIDs(cl_platform_id d_platform, cl_device_type device_type,
+ cl_uint num_entries, cl_device_id *rd_devices,
+ cl_uint *rnum_devices) try {
+ auto &platform = obj(d_platform);
+ std::vector<cl_device_id> d_devs;
+
+ if ((!num_entries && rd_devices) ||
+ (!rnum_devices && !rd_devices))
+ throw error(CL_INVALID_VALUE);
+
+ // Collect matching devices
+ for (device &dev : platform) {
+ if (((device_type & CL_DEVICE_TYPE_DEFAULT) &&
+ dev == platform.front()) ||
+ (device_type & dev.type()))
+ d_devs.push_back(desc(dev));
+ }
+
+ if (d_devs.empty())
+ throw error(CL_DEVICE_NOT_FOUND);
+
+ // ...and return the requested data.
+ if (rnum_devices)
+ *rnum_devices = d_devs.size();
+ if (rd_devices)
+ copy(range(d_devs.begin(),
+ std::min((unsigned)d_devs.size(), num_entries)),
+ rd_devices);
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clCreateSubDevices(cl_device_id d_dev,
+ const cl_device_partition_property *props,
+ cl_uint num_devs, cl_device_id *rd_devs,
+ cl_uint *rnum_devs) {
+ // There are no currently supported partitioning schemes.
+ return CL_INVALID_VALUE;
+}
+
+CLOVER_API cl_int
+clRetainDevice(cl_device_id d_dev) try {
+ obj(d_dev);
+
+ // The reference count doesn't change for root devices.
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clReleaseDevice(cl_device_id d_dev) try {
+ obj(d_dev);
+
+ // The reference count doesn't change for root devices.
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetDeviceInfo(cl_device_id d_dev, cl_device_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &dev = obj(d_dev);
+
+ switch (param) {
+ case CL_DEVICE_TYPE:
+ buf.as_scalar<cl_device_type>() = dev.type();
+ break;
+
+ case CL_DEVICE_VENDOR_ID:
+ buf.as_scalar<cl_uint>() = dev.vendor_id();
+ break;
+
+ case CL_DEVICE_MAX_COMPUTE_UNITS:
+ buf.as_scalar<cl_uint>() = dev.max_compute_units();
+ break;
+
+ case CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:
+ buf.as_scalar<cl_uint>() = dev.max_block_size().size();
+ break;
+
+ case CL_DEVICE_MAX_WORK_ITEM_SIZES:
+ buf.as_vector<size_t>() = dev.max_block_size();
+ break;
+
+ case CL_DEVICE_MAX_WORK_GROUP_SIZE:
+ buf.as_scalar<size_t>() = dev.max_threads_per_block();
+ break;
+
+ case CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR:
+ buf.as_scalar<cl_uint>() = 16;
+ break;
+
+ case CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT:
+ buf.as_scalar<cl_uint>() = 8;
+ break;
+
+ case CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT:
+ buf.as_scalar<cl_uint>() = 4;
+ break;
+
+ case CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG:
+ buf.as_scalar<cl_uint>() = 2;
+ break;
+
+ case CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT:
+ buf.as_scalar<cl_uint>() = 4;
+ break;
+
+ case CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE:
+ buf.as_scalar<cl_uint>() = dev.has_doubles() ? 2 : 0;
+ break;
+
+ case CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF:
+ buf.as_scalar<cl_uint>() = dev.has_halves() ? 8 : 0;
+ break;
+
+ case CL_DEVICE_MAX_CLOCK_FREQUENCY:
+ buf.as_scalar<cl_uint>() = dev.max_clock_frequency();
+ break;
+
+ case CL_DEVICE_ADDRESS_BITS:
+ buf.as_scalar<cl_uint>() = dev.address_bits();
+ break;
+
+ case CL_DEVICE_MAX_READ_IMAGE_ARGS:
+ buf.as_scalar<cl_uint>() = dev.max_images_read();
+ break;
+
+ case CL_DEVICE_MAX_WRITE_IMAGE_ARGS:
+ buf.as_scalar<cl_uint>() = dev.max_images_write();
+ break;
+
+ case CL_DEVICE_MAX_MEM_ALLOC_SIZE:
+ buf.as_scalar<cl_ulong>() = dev.max_mem_alloc_size();
+ break;
+
+ case CL_DEVICE_IMAGE2D_MAX_WIDTH:
+ case CL_DEVICE_IMAGE2D_MAX_HEIGHT:
+ buf.as_scalar<size_t>() = 1 << dev.max_image_levels_2d();
+ break;
+
+ case CL_DEVICE_IMAGE3D_MAX_WIDTH:
+ case CL_DEVICE_IMAGE3D_MAX_HEIGHT:
+ case CL_DEVICE_IMAGE3D_MAX_DEPTH:
+ buf.as_scalar<size_t>() = 1 << dev.max_image_levels_3d();
+ break;
+
+ case CL_DEVICE_IMAGE_MAX_BUFFER_SIZE:
+ buf.as_scalar<size_t>() = dev.max_image_buffer_size();
+ break;
+
+ case CL_DEVICE_IMAGE_MAX_ARRAY_SIZE:
+ buf.as_scalar<size_t>() = dev.max_image_array_number();
+ break;
+
+ case CL_DEVICE_IMAGE_SUPPORT:
+ buf.as_scalar<cl_bool>() = dev.image_support();
+ break;
+
+ case CL_DEVICE_MAX_PARAMETER_SIZE:
+ buf.as_scalar<size_t>() = dev.max_mem_input();
+ break;
+
+ case CL_DEVICE_MAX_SAMPLERS:
+ buf.as_scalar<cl_uint>() = dev.max_samplers();
+ break;
+
+ case CL_DEVICE_MEM_BASE_ADDR_ALIGN:
+ buf.as_scalar<cl_uint>() = 8 *
+ std::max(dev.mem_base_addr_align(), (cl_uint) sizeof(cl_long) * 16);
+ break;
+
+ case CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE:
+ buf.as_scalar<cl_uint>() = 128;
+ break;
+
+ case CL_DEVICE_HALF_FP_CONFIG:
+ // This is the "mandated minimum half precision floating-point
+ // capability" for OpenCL 1.x.
+ buf.as_scalar<cl_device_fp_config>() =
+ CL_FP_INF_NAN | CL_FP_ROUND_TO_NEAREST;
+ break;
+
+ case CL_DEVICE_SINGLE_FP_CONFIG:
+ // This is the "mandated minimum single precision floating-point
+ // capability" for OpenCL 1.1. In OpenCL 1.2, nothing is required for
+ // custom devices.
+ buf.as_scalar<cl_device_fp_config>() =
+ CL_FP_INF_NAN | CL_FP_ROUND_TO_NEAREST;
+ break;
+
+ case CL_DEVICE_DOUBLE_FP_CONFIG:
+ if (dev.has_doubles())
+ // This is the "mandated minimum double precision floating-point
+ // capability"
+ buf.as_scalar<cl_device_fp_config>() =
+ CL_FP_FMA
+ | CL_FP_ROUND_TO_NEAREST
+ | CL_FP_ROUND_TO_ZERO
+ | CL_FP_ROUND_TO_INF
+ | CL_FP_INF_NAN
+ | CL_FP_DENORM;
+ else
+ buf.as_scalar<cl_device_fp_config>() = 0;
+ break;
+
+ case CL_DEVICE_GLOBAL_MEM_CACHE_TYPE:
+ buf.as_scalar<cl_device_mem_cache_type>() = CL_NONE;
+ break;
+
+ case CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE:
+ buf.as_scalar<cl_uint>() = 0;
+ break;
+
+ case CL_DEVICE_GLOBAL_MEM_CACHE_SIZE:
+ buf.as_scalar<cl_ulong>() = 0;
+ break;
+
+ case CL_DEVICE_GLOBAL_MEM_SIZE:
+ buf.as_scalar<cl_ulong>() = dev.max_mem_global();
+ break;
+
+ case CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:
+ buf.as_scalar<cl_ulong>() = dev.max_const_buffer_size();
+ break;
+
+ case CL_DEVICE_MAX_CONSTANT_ARGS:
+ buf.as_scalar<cl_uint>() = dev.max_const_buffers();
+ break;
+
+ case CL_DEVICE_LOCAL_MEM_TYPE:
+ buf.as_scalar<cl_device_local_mem_type>() = CL_LOCAL;
+ break;
+
+ case CL_DEVICE_LOCAL_MEM_SIZE:
+ buf.as_scalar<cl_ulong>() = dev.max_mem_local();
+ break;
+
+ case CL_DEVICE_ERROR_CORRECTION_SUPPORT:
+ buf.as_scalar<cl_bool>() = CL_FALSE;
+ break;
+
+ case CL_DEVICE_PROFILING_TIMER_RESOLUTION:
+ buf.as_scalar<size_t>() = 0;
+ break;
+
+ case CL_DEVICE_ENDIAN_LITTLE:
+ buf.as_scalar<cl_bool>() = (dev.endianness() == PIPE_ENDIAN_LITTLE);
+ break;
+
+ case CL_DEVICE_AVAILABLE:
+ case CL_DEVICE_COMPILER_AVAILABLE:
+ case CL_DEVICE_LINKER_AVAILABLE:
+ buf.as_scalar<cl_bool>() = CL_TRUE;
+ break;
+
+ case CL_DEVICE_EXECUTION_CAPABILITIES:
+ buf.as_scalar<cl_device_exec_capabilities>() = CL_EXEC_KERNEL;
+ break;
+
+ case CL_DEVICE_QUEUE_PROPERTIES:
+ buf.as_scalar<cl_command_queue_properties>() = CL_QUEUE_PROFILING_ENABLE;
+ break;
+
+ case CL_DEVICE_BUILT_IN_KERNELS:
+ buf.as_string() = "";
+ break;
+
+ case CL_DEVICE_NAME:
+ buf.as_string() = dev.device_name();
+ break;
+
+ case CL_DEVICE_VENDOR:
+ buf.as_string() = dev.vendor_name();
+ break;
+
+ case CL_DRIVER_VERSION:
+ buf.as_string() = PACKAGE_VERSION;
+ break;
+
+ case CL_DEVICE_PROFILE:
+ buf.as_string() = "FULL_PROFILE";
+ break;
+
+ case CL_DEVICE_VERSION:
+ buf.as_string() = "OpenCL " + dev.device_version() + " Mesa " PACKAGE_VERSION MESA_GIT_SHA1;
+ break;
+
+ case CL_DEVICE_EXTENSIONS:
+ buf.as_string() = dev.supported_extensions();
+ break;
+
+ case CL_DEVICE_PLATFORM:
+ buf.as_scalar<cl_platform_id>() = desc(dev.platform);
+ break;
+
+ case CL_DEVICE_HOST_UNIFIED_MEMORY:
+ buf.as_scalar<cl_bool>() = dev.has_unified_memory();
+ break;
+
+ case CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR:
+ buf.as_scalar<cl_uint>() = 16;
+ break;
+
+ case CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT:
+ buf.as_scalar<cl_uint>() = 8;
+ break;
+
+ case CL_DEVICE_NATIVE_VECTOR_WIDTH_INT:
+ buf.as_scalar<cl_uint>() = 4;
+ break;
+
+ case CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG:
+ buf.as_scalar<cl_uint>() = 2;
+ break;
+
+ case CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT:
+ buf.as_scalar<cl_uint>() = 4;
+ break;
+
+ case CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE:
+ buf.as_scalar<cl_uint>() = dev.has_doubles() ? 2 : 0;
+ break;
+
+ case CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF:
+ buf.as_scalar<cl_uint>() = dev.has_halves() ? 8 : 0;
+ break;
+
+ case CL_DEVICE_OPENCL_C_VERSION:
+ buf.as_string() = "OpenCL C " + dev.device_clc_version() + " ";
+ break;
+
+ case CL_DEVICE_PRINTF_BUFFER_SIZE:
+ // Per the spec, the minimum value for the FULL profile is 1 MB.
+ // However, clover is not ready yet to support it
+ buf.as_scalar<size_t>() = 0 /* 1024 */;
+ break;
+
+ case CL_DEVICE_PREFERRED_INTEROP_USER_SYNC:
+ buf.as_scalar<cl_bool>() = CL_TRUE;
+ break;
+
+ case CL_DEVICE_PARENT_DEVICE:
+ buf.as_scalar<cl_device_id>() = NULL;
+ break;
+
+ case CL_DEVICE_PARTITION_MAX_SUB_DEVICES:
+ buf.as_scalar<cl_uint>() = 0;
+ break;
+
+ case CL_DEVICE_PARTITION_PROPERTIES:
+ buf.as_vector<cl_device_partition_property>() =
+ desc(property_list<cl_device_partition_property>());
+ break;
+
+ case CL_DEVICE_PARTITION_AFFINITY_DOMAIN:
+ buf.as_scalar<cl_device_affinity_domain>() = 0;
+ break;
+
+ case CL_DEVICE_PARTITION_TYPE:
+ buf.as_vector<cl_device_partition_property>() =
+ desc(property_list<cl_device_partition_property>());
+ break;
+
+ case CL_DEVICE_REFERENCE_COUNT:
+ buf.as_scalar<cl_uint>() = 1;
+ break;
+
+ case CL_DEVICE_SVM_CAPABILITIES:
+ case CL_DEVICE_SVM_CAPABILITIES_ARM:
+ buf.as_scalar<cl_device_svm_capabilities>() = dev.svm_support();
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
diff --git a/src/gallium/frontends/clover/api/dispatch.cpp b/src/gallium/frontends/clover/api/dispatch.cpp
new file mode 100644
index 00000000000..6e1b0351afa
--- /dev/null
+++ b/src/gallium/frontends/clover/api/dispatch.cpp
@@ -0,0 +1,174 @@
+//
+// Copyright 2013 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 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 "api/dispatch.hpp"
+
+namespace clover {
+ const cl_icd_dispatch _dispatch = {
+ clGetPlatformIDs,
+ GetPlatformInfo,
+ clGetDeviceIDs,
+ clGetDeviceInfo,
+ clCreateContext,
+ clCreateContextFromType,
+ clRetainContext,
+ clReleaseContext,
+ clGetContextInfo,
+ clCreateCommandQueue,
+ clRetainCommandQueue,
+ clReleaseCommandQueue,
+ clGetCommandQueueInfo,
+ NULL, // clSetCommandQueueProperty
+ clCreateBuffer,
+ clCreateImage2D,
+ clCreateImage3D,
+ clRetainMemObject,
+ clReleaseMemObject,
+ clGetSupportedImageFormats,
+ clGetMemObjectInfo,
+ clGetImageInfo,
+ clCreateSampler,
+ clRetainSampler,
+ clReleaseSampler,
+ clGetSamplerInfo,
+ clCreateProgramWithSource,
+ clCreateProgramWithBinary,
+ clRetainProgram,
+ clReleaseProgram,
+ clBuildProgram,
+ clUnloadCompiler,
+ clGetProgramInfo,
+ clGetProgramBuildInfo,
+ clCreateKernel,
+ clCreateKernelsInProgram,
+ clRetainKernel,
+ clReleaseKernel,
+ clSetKernelArg,
+ clGetKernelInfo,
+ clGetKernelWorkGroupInfo,
+ clWaitForEvents,
+ clGetEventInfo,
+ clRetainEvent,
+ clReleaseEvent,
+ clGetEventProfilingInfo,
+ clFlush,
+ clFinish,
+ clEnqueueReadBuffer,
+ clEnqueueWriteBuffer,
+ clEnqueueCopyBuffer,
+ clEnqueueReadImage,
+ clEnqueueWriteImage,
+ clEnqueueCopyImage,
+ clEnqueueCopyImageToBuffer,
+ clEnqueueCopyBufferToImage,
+ clEnqueueMapBuffer,
+ clEnqueueMapImage,
+ clEnqueueUnmapMemObject,
+ clEnqueueNDRangeKernel,
+ clEnqueueTask,
+ clEnqueueNativeKernel,
+ clEnqueueMarker,
+ clEnqueueWaitForEvents,
+ clEnqueueBarrier,
+ GetExtensionFunctionAddress,
+ NULL, // clCreateFromGLBuffer
+ NULL, // clCreateFromGLTexture2D
+ NULL, // clCreateFromGLTexture3D
+ NULL, // clCreateFromGLRenderbuffer
+ NULL, // clGetGLObjectInfo
+ NULL, // clGetGLTextureInfo
+ NULL, // clEnqueueAcquireGLObjects
+ NULL, // clEnqueueReleaseGLObjects
+ NULL, // clGetGLContextInfoKHR
+ NULL, // clGetDeviceIDsFromD3D10KHR
+ NULL, // clCreateFromD3D10BufferKHR
+ NULL, // clCreateFromD3D10Texture2DKHR
+ NULL, // clCreateFromD3D10Texture3DKHR
+ NULL, // clEnqueueAcquireD3D10ObjectsKHR
+ NULL, // clEnqueueReleaseD3D10ObjectsKHR
+ clSetEventCallback,
+ clCreateSubBuffer,
+ clSetMemObjectDestructorCallback,
+ clCreateUserEvent,
+ clSetUserEventStatus,
+ clEnqueueReadBufferRect,
+ clEnqueueWriteBufferRect,
+ clEnqueueCopyBufferRect,
+ NULL, // clCreateSubDevicesEXT
+ NULL, // clRetainDeviceEXT
+ NULL, // clReleaseDeviceEXT
+ NULL, // clCreateEventFromGLsyncKHR
+ clCreateSubDevices,
+ clRetainDevice,
+ clReleaseDevice,
+ clCreateImage,
+ clCreateProgramWithBuiltInKernels,
+ clCompileProgram,
+ clLinkProgram,
+ clUnloadPlatformCompiler,
+ clGetKernelArgInfo,
+ clEnqueueFillBuffer,
+ clEnqueueFillImage,
+ clEnqueueMigrateMemObjects,
+ clEnqueueMarkerWithWaitList,
+ clEnqueueBarrierWithWaitList,
+ GetExtensionFunctionAddressForPlatform,
+ NULL, // clCreateFromGLTexture
+ NULL, // clGetDeviceIDsFromD3D11KHR
+ NULL, // clCreateFromD3D11BufferKHR
+ NULL, // clCreateFromD3D11Texture2DKHR
+ NULL, // clCreateFromD3D11Texture3DKHR
+ NULL, // clCreateFromDX9MediaSurfaceKHR
+ NULL, // clEnqueueAcquireD3D11ObjectsKHR
+ NULL, // clEnqueueReleaseD3D11ObjectsKHR
+ NULL, // clGetDeviceIDsFromDX9MediaAdapterKHR
+ NULL, // clEnqueueAcquireDX9MediaSurfacesKHR
+ NULL, // clEnqueueReleaseDX9MediaSurfacesKHR
+ NULL, // clCreateFromEGLImageKHR
+ NULL, // clEnqueueAcquireEGLObjectsKHR
+ NULL, // clEnqueueReleaseEGLObjectsKHR
+ NULL, // clCreateEventFromEGLSyncKHR
+ clCreateCommandQueueWithProperties,
+ NULL, // clCreatePipe
+ NULL, // clGetPipeInfo
+ clSVMAlloc,
+ clSVMFree,
+ clEnqueueSVMFree,
+ clEnqueueSVMMemcpy,
+ clEnqueueSVMMemFill,
+ clEnqueueSVMMap,
+ clEnqueueSVMUnmap,
+ NULL, // clCreateSamplerWithProperties
+ clSetKernelArgSVMPointer,
+ clSetKernelExecInfo,
+ NULL, // clGetKernelSubGroupInfoKHR
+ NULL, // clCloneKernel
+ NULL, // clCreateProgramWithIL
+ clEnqueueSVMMigrateMem,
+ NULL, // clGetDeviceAndHostTimer
+ NULL, // clGetHostTimer
+ NULL, // clGetKernelSubGroupInfo
+ NULL, // clSetDefaultDeviceCommandQueue
+ NULL, // clSetProgramReleaseCallback
+ NULL, // clSetProgramSpecializationConstant
+ };
+}
diff --git a/src/gallium/frontends/clover/api/dispatch.hpp b/src/gallium/frontends/clover/api/dispatch.hpp
new file mode 100644
index 00000000000..ea835ed6da4
--- /dev/null
+++ b/src/gallium/frontends/clover/api/dispatch.hpp
@@ -0,0 +1,105 @@
+//
+// Copyright 2013 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 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.
+//
+
+#ifndef API_DISPATCH_HPP
+#define API_DISPATCH_HPP
+
+#include "CL/cl.h"
+#include "CL/cl_ext.h"
+#include "CL/cl_egl.h"
+#include "CL/cl_gl.h"
+#include "CL/cl_icd.h"
+
+namespace clover {
+ extern const cl_icd_dispatch _dispatch;
+
+ cl_int
+ GetPlatformInfo(cl_platform_id d_platform, cl_platform_info param,
+ size_t size, void *r_buf, size_t *r_size);
+
+ void *
+ GetExtensionFunctionAddress(const char *p_name);
+
+ void *
+ GetExtensionFunctionAddressForPlatform(cl_platform_id d_platform,
+ const char *p_name);
+
+ cl_int
+ IcdGetPlatformIDsKHR(cl_uint num_entries, cl_platform_id *rd_platforms,
+ cl_uint *rnum_platforms);
+
+ cl_int
+ EnqueueSVMFree(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 cmd);
+
+ cl_int
+ EnqueueSVMMemcpy(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 cmd);
+
+ cl_int
+ EnqueueSVMMap(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 cmd);
+
+ cl_int
+ EnqueueSVMMemFill(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 cmd);
+
+ cl_int
+ EnqueueSVMUnmap(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 cmd);
+}
+
+#endif
diff --git a/src/gallium/frontends/clover/api/event.cpp b/src/gallium/frontends/clover/api/event.cpp
new file mode 100644
index 00000000000..3f89644d0a4
--- /dev/null
+++ b/src/gallium/frontends/clover/api/event.cpp
@@ -0,0 +1,309 @@
+//
+// 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 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 "api/util.hpp"
+#include "core/event.hpp"
+
+using namespace clover;
+
+CLOVER_API cl_event
+clCreateUserEvent(cl_context d_ctx, cl_int *r_errcode) try {
+ auto &ctx = obj(d_ctx);
+
+ ret_error(r_errcode, CL_SUCCESS);
+ return desc(new soft_event(ctx, {}, false));
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_int
+clSetUserEventStatus(cl_event d_ev, cl_int status) try {
+ auto &sev = obj<soft_event>(d_ev);
+
+ if (status > 0)
+ return CL_INVALID_VALUE;
+
+ if (sev.status() <= 0)
+ return CL_INVALID_OPERATION;
+
+ if (status)
+ sev.abort(status);
+ else
+ sev.trigger();
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clWaitForEvents(cl_uint num_evs, const cl_event *d_evs) try {
+ auto evs = objs(d_evs, num_evs);
+
+ for (auto &ev : evs) {
+ if (ev.context() != evs.front().context())
+ throw error(CL_INVALID_CONTEXT);
+
+ if (ev.status() < 0)
+ throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
+ }
+
+ // Create a temporary soft event that depends on all the events in
+ // the wait list
+ auto sev = create<soft_event>(evs.front().context(), evs, true);
+
+ // ...and wait on it.
+ sev().wait();
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetEventInfo(cl_event d_ev, cl_event_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &ev = obj(d_ev);
+
+ switch (param) {
+ case CL_EVENT_COMMAND_QUEUE:
+ buf.as_scalar<cl_command_queue>() = desc(ev.queue());
+ break;
+
+ case CL_EVENT_CONTEXT:
+ buf.as_scalar<cl_context>() = desc(ev.context());
+ break;
+
+ case CL_EVENT_COMMAND_TYPE:
+ buf.as_scalar<cl_command_type>() = ev.command();
+ break;
+
+ case CL_EVENT_COMMAND_EXECUTION_STATUS:
+ buf.as_scalar<cl_int>() = ev.status();
+ break;
+
+ case CL_EVENT_REFERENCE_COUNT:
+ buf.as_scalar<cl_uint>() = ev.ref_count();
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clSetEventCallback(cl_event d_ev, cl_int type,
+ void (CL_CALLBACK *pfn_notify)(cl_event, cl_int, void *),
+ void *user_data) try {
+ auto &ev = obj(d_ev);
+
+ if (!pfn_notify ||
+ (type != CL_COMPLETE && type != CL_SUBMITTED && type != CL_RUNNING))
+ throw error(CL_INVALID_VALUE);
+
+ // Create a temporary soft event that depends on ev, with
+ // pfn_notify as completion action.
+ create<soft_event>(ev.context(), ref_vector<event> { ev }, true,
+ [=, &ev](event &) {
+ ev.wait();
+ pfn_notify(desc(ev), ev.status(), user_data);
+ });
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clRetainEvent(cl_event d_ev) try {
+ obj(d_ev).retain();
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clReleaseEvent(cl_event d_ev) try {
+ if (obj(d_ev).release())
+ delete pobj(d_ev);
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueMarker(cl_command_queue d_q, cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+
+ if (!rd_ev)
+ throw error(CL_INVALID_VALUE);
+
+ *rd_ev = desc(new hard_event(q, CL_COMMAND_MARKER, {}));
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueMarkerWithWaitList(cl_command_queue d_q, cl_uint num_deps,
+ const cl_event *d_deps, cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+
+ for (auto &ev : deps) {
+ if (ev.context() != q.context())
+ throw error(CL_INVALID_CONTEXT);
+ }
+
+ // Create a hard event that depends on the events in the wait list:
+ // previous commands in the same queue are implicitly serialized
+ // with respect to it -- hard events always are.
+ auto hev = create<hard_event>(q, CL_COMMAND_MARKER, deps);
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueBarrier(cl_command_queue d_q) try {
+ obj(d_q);
+
+ // No need to do anything, q preserves data ordering strictly.
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueBarrierWithWaitList(cl_command_queue d_q, cl_uint num_deps,
+ const cl_event *d_deps, cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+
+ for (auto &ev : deps) {
+ if (ev.context() != q.context())
+ throw error(CL_INVALID_CONTEXT);
+ }
+
+ // Create a hard event that depends on the events in the wait list:
+ // subsequent commands in the same queue will be implicitly
+ // serialized with respect to it -- hard events always are.
+ auto hev = create<hard_event>(q, CL_COMMAND_BARRIER, deps);
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueWaitForEvents(cl_command_queue d_q, cl_uint num_evs,
+ const cl_event *d_evs) try {
+ // The wait list is mandatory for clEnqueueWaitForEvents().
+ objs(d_evs, num_evs);
+
+ return clEnqueueBarrierWithWaitList(d_q, num_evs, d_evs, NULL);
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetEventProfilingInfo(cl_event d_ev, cl_profiling_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ hard_event &hev = dynamic_cast<hard_event &>(obj(d_ev));
+
+ if (hev.status() != CL_COMPLETE)
+ throw error(CL_PROFILING_INFO_NOT_AVAILABLE);
+
+ switch (param) {
+ case CL_PROFILING_COMMAND_QUEUED:
+ buf.as_scalar<cl_ulong>() = hev.time_queued();
+ break;
+
+ case CL_PROFILING_COMMAND_SUBMIT:
+ buf.as_scalar<cl_ulong>() = hev.time_submit();
+ break;
+
+ case CL_PROFILING_COMMAND_START:
+ buf.as_scalar<cl_ulong>() = hev.time_start();
+ break;
+
+ case CL_PROFILING_COMMAND_END:
+ buf.as_scalar<cl_ulong>() = hev.time_end();
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (std::bad_cast &e) {
+ return CL_PROFILING_INFO_NOT_AVAILABLE;
+
+} catch (lazy<cl_ulong>::undefined_error &e) {
+ return CL_PROFILING_INFO_NOT_AVAILABLE;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clFinish(cl_command_queue d_q) try {
+ auto &q = obj(d_q);
+
+ // Create a temporary hard event -- it implicitly depends on all
+ // the previously queued hard events.
+ auto hev = create<hard_event>(q, 0, ref_vector<event> {});
+
+ // And wait on it.
+ hev().wait();
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
diff --git a/src/gallium/frontends/clover/api/interop.cpp b/src/gallium/frontends/clover/api/interop.cpp
new file mode 100644
index 00000000000..b96069f5167
--- /dev/null
+++ b/src/gallium/frontends/clover/api/interop.cpp
@@ -0,0 +1,69 @@
+//
+// Copyright 2015 Advanced Micro Devices, Inc.
+// All Rights Reserved.
+//
+// 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 "core/event.hpp"
+#include "api/util.hpp"
+
+using namespace clover;
+
+extern "C" {
+
+PUBLIC bool
+opencl_dri_event_add_ref(cl_event event)
+{
+ /* This should fail if the event hasn't been created by
+ * clEnqueueReleaseGLObjects or clEnqueueReleaseEGLObjects.
+ *
+ * TODO: implement the CL functions
+ */
+ return false; /*return clRetainEvent(event) == CL_SUCCESS;*/
+}
+
+PUBLIC bool
+opencl_dri_event_release(cl_event event)
+{
+ return clReleaseEvent(event) == CL_SUCCESS;
+}
+
+PUBLIC bool
+opencl_dri_event_wait(cl_event event, uint64_t timeout) try {
+ if (!timeout) {
+ return obj(event).status() == CL_COMPLETE;
+ }
+
+ obj(event).wait();
+ return true;
+
+} catch (error &) {
+ return false;
+}
+
+PUBLIC struct pipe_fence_handle *
+opencl_dri_event_get_fence(cl_event event) try {
+ return obj(event).fence();
+
+} catch (error &) {
+ return NULL;
+}
+
+}
diff --git a/src/gallium/frontends/clover/api/kernel.cpp b/src/gallium/frontends/clover/api/kernel.cpp
new file mode 100644
index 00000000000..31a87b63868
--- /dev/null
+++ b/src/gallium/frontends/clover/api/kernel.cpp
@@ -0,0 +1,390 @@
+//
+// 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 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 "api/util.hpp"
+#include "core/kernel.hpp"
+#include "core/event.hpp"
+
+using namespace clover;
+
+CLOVER_API cl_kernel
+clCreateKernel(cl_program d_prog, const char *name, cl_int *r_errcode) try {
+ auto &prog = obj(d_prog);
+
+ if (!name)
+ throw error(CL_INVALID_VALUE);
+
+ auto &sym = find(name_equals(name), prog.symbols());
+
+ ret_error(r_errcode, CL_SUCCESS);
+ return new kernel(prog, name, range(sym.args));
+
+} catch (std::out_of_range &e) {
+ ret_error(r_errcode, CL_INVALID_KERNEL_NAME);
+ return NULL;
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_int
+clCreateKernelsInProgram(cl_program d_prog, cl_uint count,
+ cl_kernel *rd_kerns, cl_uint *r_count) try {
+ auto &prog = obj(d_prog);
+ auto &syms = prog.symbols();
+
+ if (rd_kerns && count < syms.size())
+ throw error(CL_INVALID_VALUE);
+
+ if (rd_kerns)
+ copy(map([&](const module::symbol &sym) {
+ return desc(new kernel(prog,
+ std::string(sym.name.begin(),
+ sym.name.end()),
+ range(sym.args)));
+ }, syms),
+ rd_kerns);
+
+ if (r_count)
+ *r_count = syms.size();
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clRetainKernel(cl_kernel d_kern) try {
+ obj(d_kern).retain();
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clReleaseKernel(cl_kernel d_kern) try {
+ if (obj(d_kern).release())
+ delete pobj(d_kern);
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clSetKernelArg(cl_kernel d_kern, cl_uint idx, size_t size,
+ const void *value) try {
+ obj(d_kern).args().at(idx).set(size, value);
+ return CL_SUCCESS;
+
+} catch (std::out_of_range &e) {
+ return CL_INVALID_ARG_INDEX;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetKernelInfo(cl_kernel d_kern, cl_kernel_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &kern = obj(d_kern);
+
+ switch (param) {
+ case CL_KERNEL_FUNCTION_NAME:
+ buf.as_string() = kern.name();
+ break;
+
+ case CL_KERNEL_NUM_ARGS:
+ buf.as_scalar<cl_uint>() = kern.args().size();
+ break;
+
+ case CL_KERNEL_REFERENCE_COUNT:
+ buf.as_scalar<cl_uint>() = kern.ref_count();
+ break;
+
+ case CL_KERNEL_CONTEXT:
+ buf.as_scalar<cl_context>() = desc(kern.program().context());
+ break;
+
+ case CL_KERNEL_PROGRAM:
+ buf.as_scalar<cl_program>() = desc(kern.program());
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetKernelWorkGroupInfo(cl_kernel d_kern, cl_device_id d_dev,
+ cl_kernel_work_group_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &kern = obj(d_kern);
+ auto &dev = (d_dev ? *pobj(d_dev) : unique(kern.program().devices()));
+
+ if (!count(dev, kern.program().devices()))
+ throw error(CL_INVALID_DEVICE);
+
+ switch (param) {
+ case CL_KERNEL_WORK_GROUP_SIZE:
+ buf.as_scalar<size_t>() = dev.max_threads_per_block();
+ break;
+
+ case CL_KERNEL_COMPILE_WORK_GROUP_SIZE:
+ buf.as_vector<size_t>() = kern.required_block_size();
+ break;
+
+ case CL_KERNEL_LOCAL_MEM_SIZE:
+ buf.as_scalar<cl_ulong>() = kern.mem_local();
+ break;
+
+ case CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE:
+ buf.as_scalar<size_t>() = dev.subgroup_size();
+ break;
+
+ case CL_KERNEL_PRIVATE_MEM_SIZE:
+ buf.as_scalar<cl_ulong>() = kern.mem_private();
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+
+} catch (std::out_of_range &e) {
+ return CL_INVALID_DEVICE;
+}
+
+CLOVER_API cl_int
+clGetKernelArgInfo(cl_kernel d_kern,
+ cl_uint idx, cl_kernel_arg_info param,
+ size_t size, void *r_buf, size_t *r_size) {
+ CLOVER_NOT_SUPPORTED_UNTIL("1.2");
+ return CL_KERNEL_ARG_INFO_NOT_AVAILABLE;
+}
+
+namespace {
+ ///
+ /// Common argument checking shared by kernel invocation commands.
+ ///
+ void
+ validate_common(const command_queue &q, kernel &kern,
+ const ref_vector<event> &deps) {
+ if (kern.program().context() != q.context() ||
+ any_of([&](const event &ev) {
+ return ev.context() != q.context();
+ }, deps))
+ throw error(CL_INVALID_CONTEXT);
+
+ if (any_of([](kernel::argument &arg) {
+ return !arg.set();
+ }, kern.args()))
+ throw error(CL_INVALID_KERNEL_ARGS);
+
+ // If the command queue's device is not associated to the program, we get
+ // a module, with no sections, which will also fail the following test.
+ auto &m = kern.program().build(q.device()).binary;
+ if (!any_of(type_equals(module::section::text_executable), m.secs))
+ throw error(CL_INVALID_PROGRAM_EXECUTABLE);
+ }
+
+ std::vector<size_t>
+ validate_grid_size(const command_queue &q, cl_uint dims,
+ const size_t *d_grid_size) {
+ auto grid_size = range(d_grid_size, dims);
+
+ if (dims < 1 || dims > q.device().max_block_size().size())
+ throw error(CL_INVALID_WORK_DIMENSION);
+
+ if (!d_grid_size || any_of(is_zero(), grid_size))
+ throw error(CL_INVALID_GLOBAL_WORK_SIZE);
+
+ return grid_size;
+ }
+
+ std::vector<size_t>
+ validate_grid_offset(const command_queue &q, cl_uint dims,
+ const size_t *d_grid_offset) {
+ if (d_grid_offset)
+ return range(d_grid_offset, dims);
+ else
+ return std::vector<size_t>(dims, 0);
+ }
+
+ std::vector<size_t>
+ validate_block_size(const command_queue &q, const kernel &kern,
+ cl_uint dims, const size_t *d_grid_size,
+ const size_t *d_block_size) {
+ auto grid_size = range(d_grid_size, dims);
+
+ if (d_block_size) {
+ auto block_size = range(d_block_size, dims);
+
+ if (any_of(is_zero(), block_size) ||
+ any_of(greater(), block_size, q.device().max_block_size()))
+ throw error(CL_INVALID_WORK_ITEM_SIZE);
+
+ if (any_of(modulus(), grid_size, block_size))
+ throw error(CL_INVALID_WORK_GROUP_SIZE);
+
+ if (fold(multiplies(), 1u, block_size) >
+ q.device().max_threads_per_block())
+ throw error(CL_INVALID_WORK_GROUP_SIZE);
+
+ return block_size;
+
+ } else {
+ return kern.optimal_block_size(q, grid_size);
+ }
+ }
+}
+
+CLOVER_API cl_int
+clEnqueueNDRangeKernel(cl_command_queue d_q, cl_kernel d_kern,
+ cl_uint dims, const size_t *d_grid_offset,
+ const size_t *d_grid_size, const size_t *d_block_size,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &kern = obj(d_kern);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto grid_size = validate_grid_size(q, dims, d_grid_size);
+ auto grid_offset = validate_grid_offset(q, dims, d_grid_offset);
+ auto block_size = validate_block_size(q, kern, dims,
+ d_grid_size, d_block_size);
+
+ validate_common(q, kern, deps);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_NDRANGE_KERNEL, deps,
+ [=, &kern, &q](event &) {
+ kern.launch(q, grid_offset, grid_size, block_size);
+ });
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueTask(cl_command_queue d_q, cl_kernel d_kern,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &kern = obj(d_kern);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+
+ validate_common(q, kern, deps);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_TASK, deps,
+ [=, &kern, &q](event &) {
+ kern.launch(q, { 0 }, { 1 }, { 1 });
+ });
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueNativeKernel(cl_command_queue d_q, void (*func)(void *),
+ void *args, size_t args_size,
+ cl_uint num_mems, const cl_mem *d_mems,
+ const void **mem_handles, cl_uint num_deps,
+ const cl_event *d_deps, cl_event *rd_ev) {
+ return CL_INVALID_OPERATION;
+}
+
+CLOVER_API cl_int
+clSetKernelArgSVMPointer(cl_kernel d_kern,
+ cl_uint arg_index,
+ const void *arg_value) try {
+ obj(d_kern).args().at(arg_index).set_svm(arg_value);
+ return CL_SUCCESS;
+
+} catch (std::out_of_range &e) {
+ return CL_INVALID_ARG_INDEX;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clSetKernelExecInfo(cl_kernel d_kern,
+ cl_kernel_exec_info param_name,
+ size_t param_value_size,
+ const void *param_value) try {
+ auto &kern = obj(d_kern);
+ const bool has_system_svm = all_of(std::mem_fn(&device::has_system_svm),
+ kern.program().context().devices());
+
+ if (!param_value)
+ return CL_INVALID_VALUE;
+
+ switch (param_name) {
+ case CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM:
+ case CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM_ARM: {
+ if (param_value_size != sizeof(cl_bool))
+ return CL_INVALID_VALUE;
+
+ cl_bool val = *static_cast<const cl_bool*>(param_value);
+ if (val == CL_TRUE && !has_system_svm)
+ return CL_INVALID_OPERATION;
+ else
+ return CL_SUCCESS;
+ }
+
+ case CL_KERNEL_EXEC_INFO_SVM_PTRS:
+ case CL_KERNEL_EXEC_INFO_SVM_PTRS_ARM:
+ if (has_system_svm)
+ return CL_SUCCESS;
+
+ CLOVER_NOT_SUPPORTED_UNTIL("2.0");
+ return CL_INVALID_VALUE;
+
+ default:
+ return CL_INVALID_VALUE;
+ }
+
+} catch (error &e) {
+ return e.get();
+}
diff --git a/src/gallium/frontends/clover/api/memory.cpp b/src/gallium/frontends/clover/api/memory.cpp
new file mode 100644
index 00000000000..e03793339c1
--- /dev/null
+++ b/src/gallium/frontends/clover/api/memory.cpp
@@ -0,0 +1,497 @@
+//
+// 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 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 "util/u_math.h"
+#include "api/util.hpp"
+#include "core/memory.hpp"
+#include "core/format.hpp"
+
+using namespace clover;
+
+namespace {
+ cl_mem_flags
+ validate_flags(cl_mem d_parent, cl_mem_flags d_flags, bool svm) {
+ const cl_mem_flags dev_access_flags =
+ CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY;
+ const cl_mem_flags host_ptr_flags =
+ CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR;
+ const cl_mem_flags host_access_flags =
+ CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS;
+ const cl_mem_flags svm_flags =
+ CL_MEM_SVM_FINE_GRAIN_BUFFER | CL_MEM_SVM_ATOMICS;
+
+ const cl_mem_flags valid_flags =
+ dev_access_flags
+ | (svm || d_parent ? 0 : host_ptr_flags)
+ | (svm ? svm_flags : host_access_flags);
+
+ if ((d_flags & ~valid_flags) ||
+ util_bitcount(d_flags & dev_access_flags) > 1 ||
+ util_bitcount(d_flags & host_access_flags) > 1)
+ throw error(CL_INVALID_VALUE);
+
+ if ((d_flags & CL_MEM_USE_HOST_PTR) &&
+ (d_flags & (CL_MEM_COPY_HOST_PTR | CL_MEM_ALLOC_HOST_PTR)))
+ throw error(CL_INVALID_VALUE);
+
+ if ((d_flags & CL_MEM_SVM_ATOMICS) &&
+ !(d_flags & CL_MEM_SVM_FINE_GRAIN_BUFFER))
+ throw error(CL_INVALID_VALUE);
+
+ if (d_parent) {
+ const auto &parent = obj(d_parent);
+ const cl_mem_flags flags = (d_flags |
+ (d_flags & dev_access_flags ? 0 :
+ parent.flags() & dev_access_flags) |
+ (d_flags & host_access_flags ? 0 :
+ parent.flags() & host_access_flags) |
+ (parent.flags() & host_ptr_flags));
+
+ if (~flags & parent.flags() & (dev_access_flags & ~CL_MEM_READ_WRITE))
+ throw error(CL_INVALID_VALUE);
+
+ // Check if new host access flags cause a mismatch between
+ // host-read/write-only.
+ if (!(flags & CL_MEM_HOST_NO_ACCESS) &&
+ (~flags & parent.flags() & host_access_flags))
+ throw error(CL_INVALID_VALUE);
+
+ return flags;
+
+ } else {
+ return d_flags | (d_flags & dev_access_flags ? 0 : CL_MEM_READ_WRITE);
+ }
+ }
+}
+
+CLOVER_API cl_mem
+clCreateBuffer(cl_context d_ctx, cl_mem_flags d_flags, size_t size,
+ void *host_ptr, cl_int *r_errcode) try {
+ const cl_mem_flags flags = validate_flags(NULL, d_flags, false);
+ auto &ctx = obj(d_ctx);
+
+ if (bool(host_ptr) != bool(flags & (CL_MEM_USE_HOST_PTR |
+ CL_MEM_COPY_HOST_PTR)))
+ throw error(CL_INVALID_HOST_PTR);
+
+ if (!size ||
+ size > fold(maximum(), cl_ulong(0),
+ map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices())
+ ))
+ throw error(CL_INVALID_BUFFER_SIZE);
+
+ ret_error(r_errcode, CL_SUCCESS);
+ return new root_buffer(ctx, flags, size, host_ptr);
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_mem
+clCreateSubBuffer(cl_mem d_mem, cl_mem_flags d_flags,
+ cl_buffer_create_type op,
+ const void *op_info, cl_int *r_errcode) try {
+ auto &parent = obj<root_buffer>(d_mem);
+ const cl_mem_flags flags = validate_flags(d_mem, d_flags, false);
+
+ if (op == CL_BUFFER_CREATE_TYPE_REGION) {
+ auto reg = reinterpret_cast<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(r_errcode, CL_SUCCESS);
+ return new sub_buffer(parent, flags, reg->origin, reg->size);
+
+ } else {
+ throw error(CL_INVALID_VALUE);
+ }
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_mem
+clCreateImage(cl_context d_ctx, cl_mem_flags d_flags,
+ const cl_image_format *format,
+ const cl_image_desc *desc,
+ void *host_ptr, cl_int *r_errcode) try {
+ auto &ctx = obj(d_ctx);
+
+ if (!any_of(std::mem_fn(&device::image_support), ctx.devices()))
+ throw error(CL_INVALID_OPERATION);
+
+ if (!format)
+ throw error(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
+
+ if (!desc)
+ throw error(CL_INVALID_IMAGE_DESCRIPTOR);
+
+ if (desc->image_array_size == 0 &&
+ (desc->image_type == CL_MEM_OBJECT_IMAGE1D_ARRAY ||
+ desc->image_type == CL_MEM_OBJECT_IMAGE2D_ARRAY))
+ throw error(CL_INVALID_IMAGE_DESCRIPTOR);
+
+ if (!host_ptr &&
+ (desc->image_row_pitch || desc->image_slice_pitch))
+ throw error(CL_INVALID_IMAGE_DESCRIPTOR);
+
+ if (desc->num_mip_levels || desc->num_samples)
+ throw error(CL_INVALID_IMAGE_DESCRIPTOR);
+
+ if (bool(desc->buffer) != (desc->image_type == CL_MEM_OBJECT_IMAGE1D_BUFFER))
+ throw error(CL_INVALID_IMAGE_DESCRIPTOR);
+
+ if (bool(host_ptr) != bool(d_flags & (CL_MEM_USE_HOST_PTR |
+ CL_MEM_COPY_HOST_PTR)))
+ throw error(CL_INVALID_HOST_PTR);
+
+ const cl_mem_flags flags = validate_flags(desc->buffer, d_flags, false);
+
+ if (!supported_formats(ctx, desc->image_type).count(*format))
+ throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
+
+ ret_error(r_errcode, CL_SUCCESS);
+
+ switch (desc->image_type) {
+ case CL_MEM_OBJECT_IMAGE2D:
+ if (!desc->image_width || !desc->image_height)
+ throw error(CL_INVALID_IMAGE_SIZE);
+
+ if (all_of([=](const device &dev) {
+ const size_t max = 1 << dev.max_image_levels_2d();
+ return (desc->image_width > max ||
+ desc->image_height > max);
+ }, ctx.devices()))
+ throw error(CL_INVALID_IMAGE_SIZE);
+
+ return new image2d(ctx, flags, format,
+ desc->image_width, desc->image_height,
+ desc->image_row_pitch, host_ptr);
+
+ case CL_MEM_OBJECT_IMAGE3D:
+ if (!desc->image_width || !desc->image_height || !desc->image_depth)
+ throw error(CL_INVALID_IMAGE_SIZE);
+
+ if (all_of([=](const device &dev) {
+ const size_t max = 1 << dev.max_image_levels_3d();
+ return (desc->image_width > max ||
+ desc->image_height > max ||
+ desc->image_depth > max);
+ }, ctx.devices()))
+ throw error(CL_INVALID_IMAGE_SIZE);
+
+ return new image3d(ctx, flags, format,
+ desc->image_width, desc->image_height,
+ desc->image_depth, desc->image_row_pitch,
+ desc->image_slice_pitch, host_ptr);
+
+ case CL_MEM_OBJECT_IMAGE1D:
+ case CL_MEM_OBJECT_IMAGE1D_ARRAY:
+ case CL_MEM_OBJECT_IMAGE1D_BUFFER:
+ case CL_MEM_OBJECT_IMAGE2D_ARRAY:
+ // XXX - Not implemented.
+ throw error(CL_IMAGE_FORMAT_NOT_SUPPORTED);
+
+ default:
+ throw error(CL_INVALID_IMAGE_DESCRIPTOR);
+ }
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_mem
+clCreateImage2D(cl_context d_ctx, cl_mem_flags d_flags,
+ const cl_image_format *format,
+ size_t width, size_t height, size_t row_pitch,
+ void *host_ptr, cl_int *r_errcode) {
+ const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE2D, width, height, 0, 0,
+ row_pitch, 0, 0, 0, NULL };
+
+ return clCreateImage(d_ctx, d_flags, format, &desc, host_ptr, r_errcode);
+}
+
+CLOVER_API cl_mem
+clCreateImage3D(cl_context d_ctx, cl_mem_flags d_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 *r_errcode) {
+ const cl_image_desc desc = { CL_MEM_OBJECT_IMAGE3D, width, height, depth, 0,
+ row_pitch, slice_pitch, 0, 0, NULL };
+
+ return clCreateImage(d_ctx, d_flags, format, &desc, host_ptr, r_errcode);
+}
+
+CLOVER_API cl_int
+clGetSupportedImageFormats(cl_context d_ctx, cl_mem_flags flags,
+ cl_mem_object_type type, cl_uint count,
+ cl_image_format *r_buf, cl_uint *r_count) try {
+ auto &ctx = obj(d_ctx);
+ auto formats = supported_formats(ctx, type);
+
+ validate_flags(NULL, flags, false);
+
+ if (r_buf && !r_count)
+ throw error(CL_INVALID_VALUE);
+
+ if (r_buf)
+ std::copy_n(formats.begin(),
+ std::min((cl_uint)formats.size(), count),
+ r_buf);
+
+ if (r_count)
+ *r_count = formats.size();
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetMemObjectInfo(cl_mem d_mem, cl_mem_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &mem = obj(d_mem);
+
+ switch (param) {
+ case CL_MEM_TYPE:
+ buf.as_scalar<cl_mem_object_type>() = mem.type();
+ break;
+
+ case CL_MEM_FLAGS:
+ buf.as_scalar<cl_mem_flags>() = mem.flags();
+ break;
+
+ case CL_MEM_SIZE:
+ buf.as_scalar<size_t>() = mem.size();
+ break;
+
+ case CL_MEM_HOST_PTR:
+ buf.as_scalar<void *>() = mem.host_ptr();
+ break;
+
+ case CL_MEM_MAP_COUNT:
+ buf.as_scalar<cl_uint>() = 0;
+ break;
+
+ case CL_MEM_REFERENCE_COUNT:
+ buf.as_scalar<cl_uint>() = mem.ref_count();
+ break;
+
+ case CL_MEM_CONTEXT:
+ buf.as_scalar<cl_context>() = desc(mem.context());
+ break;
+
+ case CL_MEM_ASSOCIATED_MEMOBJECT: {
+ sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
+ buf.as_scalar<cl_mem>() = (sub ? desc(sub->parent()) : NULL);
+ break;
+ }
+ case CL_MEM_OFFSET: {
+ sub_buffer *sub = dynamic_cast<sub_buffer *>(&mem);
+ buf.as_scalar<size_t>() = (sub ? sub->offset() : 0);
+ break;
+ }
+ case CL_MEM_USES_SVM_POINTER:
+ case CL_MEM_USES_SVM_POINTER_ARM: {
+ // with system SVM all host ptrs are SVM pointers
+ // TODO: once we support devices with lower levels of SVM, we have to
+ // check the ptr in more detail
+ const bool system_svm = all_of(std::mem_fn(&device::has_system_svm),
+ mem.context().devices());
+ buf.as_scalar<cl_bool>() = mem.host_ptr() && system_svm;
+ break;
+ }
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetImageInfo(cl_mem d_mem, cl_image_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &img = obj<image>(d_mem);
+
+ switch (param) {
+ case CL_IMAGE_FORMAT:
+ buf.as_scalar<cl_image_format>() = img.format();
+ break;
+
+ case CL_IMAGE_ELEMENT_SIZE:
+ buf.as_scalar<size_t>() = 0;
+ break;
+
+ case CL_IMAGE_ROW_PITCH:
+ buf.as_scalar<size_t>() = img.row_pitch();
+ break;
+
+ case CL_IMAGE_SLICE_PITCH:
+ buf.as_scalar<size_t>() = img.slice_pitch();
+ break;
+
+ case CL_IMAGE_WIDTH:
+ buf.as_scalar<size_t>() = img.width();
+ break;
+
+ case CL_IMAGE_HEIGHT:
+ buf.as_scalar<size_t>() = img.height();
+ break;
+
+ case CL_IMAGE_DEPTH:
+ buf.as_scalar<size_t>() = img.depth();
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clRetainMemObject(cl_mem d_mem) try {
+ obj(d_mem).retain();
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clReleaseMemObject(cl_mem d_mem) try {
+ if (obj(d_mem).release())
+ delete pobj(d_mem);
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clSetMemObjectDestructorCallback(cl_mem d_mem,
+ void (CL_CALLBACK *pfn_notify)(cl_mem, void *),
+ void *user_data) try {
+ auto &mem = obj(d_mem);
+
+ if (!pfn_notify)
+ return CL_INVALID_VALUE;
+
+ mem.destroy_notify([=]{ pfn_notify(d_mem, user_data); });
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API 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) {
+ CLOVER_NOT_SUPPORTED_UNTIL("1.2");
+ return CL_INVALID_VALUE;
+}
+
+CLOVER_API 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) {
+ CLOVER_NOT_SUPPORTED_UNTIL("1.2");
+ return CL_INVALID_VALUE;
+}
+
+CLOVER_API void *
+clSVMAlloc(cl_context d_ctx,
+ cl_svm_mem_flags flags,
+ size_t size,
+ unsigned int alignment) try {
+ auto &ctx = obj(d_ctx);
+ validate_flags(NULL, flags, true);
+
+ if (!size ||
+ size > fold(minimum(), cl_ulong(ULONG_MAX),
+ map(std::mem_fn(&device::max_mem_alloc_size), ctx.devices())))
+ return nullptr;
+
+ if (!util_is_power_of_two_or_zero(alignment))
+ return nullptr;
+
+ if (!alignment)
+ alignment = 0x80; // sizeof(long16)
+
+ bool can_emulate = all_of(std::mem_fn(&device::has_system_svm), ctx.devices());
+ if (can_emulate) {
+ // we can ignore all the flags as it's not required to honor them.
+ void *ptr = nullptr;
+ if (alignment < sizeof(void*))
+ alignment = sizeof(void*);
+ posix_memalign(&ptr, alignment, size);
+ return ptr;
+ }
+
+ CLOVER_NOT_SUPPORTED_UNTIL("2.0");
+ return nullptr;
+
+} catch (error &e) {
+ return nullptr;
+}
+
+CLOVER_API void
+clSVMFree(cl_context d_ctx,
+ void *svm_pointer) try {
+ auto &ctx = obj(d_ctx);
+ bool can_emulate = all_of(std::mem_fn(&device::has_system_svm), ctx.devices());
+
+ if (can_emulate)
+ return free(svm_pointer);
+
+ CLOVER_NOT_SUPPORTED_UNTIL("2.0");
+
+} catch (error &e) {
+}
diff --git a/src/gallium/frontends/clover/api/platform.cpp b/src/gallium/frontends/clover/api/platform.cpp
new file mode 100644
index 00000000000..7360461e62f
--- /dev/null
+++ b/src/gallium/frontends/clover/api/platform.cpp
@@ -0,0 +1,235 @@
+//
+// 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 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 <unordered_map>
+
+#include "api/dispatch.hpp"
+#include "api/util.hpp"
+#include "core/platform.hpp"
+#include "git_sha1.h"
+#include "util/u_debug.h"
+
+using namespace clover;
+
+namespace {
+ platform _clover_platform;
+}
+
+CLOVER_API cl_int
+clGetPlatformIDs(cl_uint num_entries, cl_platform_id *rd_platforms,
+ cl_uint *rnum_platforms) {
+ if ((!num_entries && rd_platforms) ||
+ (!rnum_platforms && !rd_platforms))
+ return CL_INVALID_VALUE;
+
+ if (rnum_platforms)
+ *rnum_platforms = 1;
+ if (rd_platforms)
+ *rd_platforms = desc(_clover_platform);
+
+ return CL_SUCCESS;
+}
+
+cl_int
+clover::GetPlatformInfo(cl_platform_id d_platform, cl_platform_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+
+ auto &platform = obj(d_platform);
+
+ switch (param) {
+ case CL_PLATFORM_PROFILE:
+ buf.as_string() = "FULL_PROFILE";
+ break;
+
+ case CL_PLATFORM_VERSION: {
+ static const std::string version_string =
+ debug_get_option("CLOVER_PLATFORM_VERSION_OVERRIDE", "1.1");
+
+ buf.as_string() = "OpenCL " + version_string + " Mesa " PACKAGE_VERSION MESA_GIT_SHA1;
+ break;
+ }
+ case CL_PLATFORM_NAME:
+ buf.as_string() = "Clover";
+ break;
+
+ case CL_PLATFORM_VENDOR:
+ buf.as_string() = "Mesa";
+ break;
+
+ case CL_PLATFORM_EXTENSIONS:
+ buf.as_string() = platform.supported_extensions();
+ break;
+
+ case CL_PLATFORM_ICD_SUFFIX_KHR:
+ buf.as_string() = "MESA";
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+void *
+clover::GetExtensionFunctionAddressForPlatform(cl_platform_id d_platform,
+ const char *p_name) try {
+ obj(d_platform);
+ return GetExtensionFunctionAddress(p_name);
+
+} catch (error &e) {
+ return NULL;
+}
+
+namespace {
+
+cl_int
+enqueueSVMFreeARM(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) {
+
+ return EnqueueSVMFree(command_queue, num_svm_pointers, svm_pointers,
+ pfn_free_func, user_data, num_events_in_wait_list,
+ event_wait_list, event, CL_COMMAND_SVM_FREE_ARM);
+}
+
+cl_int
+enqueueSVMMapARM(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) {
+
+ return EnqueueSVMMap(command_queue, blocking_map, map_flags, svm_ptr, size,
+ num_events_in_wait_list, event_wait_list, event,
+ CL_COMMAND_SVM_MAP_ARM);
+}
+
+cl_int
+enqueueSVMMemcpyARM(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) {
+
+ return EnqueueSVMMemcpy(command_queue, blocking_copy, dst_ptr, src_ptr,
+ size, num_events_in_wait_list, event_wait_list,
+ event, CL_COMMAND_SVM_MEMCPY_ARM);
+}
+
+cl_int
+enqueueSVMMemFillARM(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) {
+
+ return EnqueueSVMMemFill(command_queue, svm_ptr, pattern, pattern_size,
+ size, num_events_in_wait_list, event_wait_list,
+ event, CL_COMMAND_SVM_MEMFILL_ARM);
+}
+
+cl_int
+enqueueSVMUnmapARM(cl_command_queue command_queue,
+ void *svm_ptr,
+ cl_uint num_events_in_wait_list,
+ const cl_event *event_wait_list,
+ cl_event *event) {
+
+ return EnqueueSVMUnmap(command_queue, svm_ptr, num_events_in_wait_list,
+ event_wait_list, event, CL_COMMAND_SVM_UNMAP_ARM);
+}
+
+const std::unordered_map<std::string, void *>
+ext_funcs = {
+ // cl_arm_shared_virtual_memory
+ { "clEnqueueSVMFreeARM", reinterpret_cast<void *>(enqueueSVMFreeARM) },
+ { "clEnqueueSVMMapARM", reinterpret_cast<void *>(enqueueSVMMapARM) },
+ { "clEnqueueSVMMemcpyARM", reinterpret_cast<void *>(enqueueSVMMemcpyARM) },
+ { "clEnqueueSVMMemFillARM", reinterpret_cast<void *>(enqueueSVMMemFillARM) },
+ { "clEnqueueSVMUnmapARM", reinterpret_cast<void *>(enqueueSVMUnmapARM) },
+ { "clSetKernelArgSVMPointerARM", reinterpret_cast<void *>(clSetKernelArgSVMPointer) },
+ { "clSetKernelExecInfoARM", reinterpret_cast<void *>(clSetKernelExecInfo) },
+ { "clSVMAllocARM", reinterpret_cast<void *>(clSVMAlloc) },
+ { "clSVMFreeARM", reinterpret_cast<void *>(clSVMFree) },
+
+ // cl_khr_icd
+ { "clIcdGetPlatformIDsKHR", reinterpret_cast<void *>(IcdGetPlatformIDsKHR) },
+};
+
+} // anonymous namespace
+
+void *
+clover::GetExtensionFunctionAddress(const char *p_name) try {
+ return ext_funcs.at(p_name);
+} catch (...) {
+ return nullptr;
+}
+
+cl_int
+clover::IcdGetPlatformIDsKHR(cl_uint num_entries, cl_platform_id *rd_platforms,
+ cl_uint *rnum_platforms) {
+ return clGetPlatformIDs(num_entries, rd_platforms, rnum_platforms);
+}
+
+CLOVER_ICD_API cl_int
+clGetPlatformInfo(cl_platform_id d_platform, cl_platform_info param,
+ size_t size, void *r_buf, size_t *r_size) {
+ return GetPlatformInfo(d_platform, param, size, r_buf, r_size);
+}
+
+CLOVER_ICD_API void *
+clGetExtensionFunctionAddress(const char *p_name) {
+ return GetExtensionFunctionAddress(p_name);
+}
+
+CLOVER_ICD_API void *
+clGetExtensionFunctionAddressForPlatform(cl_platform_id d_platform,
+ const char *p_name) {
+ return GetExtensionFunctionAddressForPlatform(d_platform, p_name);
+}
+
+CLOVER_ICD_API cl_int
+clIcdGetPlatformIDsKHR(cl_uint num_entries, cl_platform_id *rd_platforms,
+ cl_uint *rnum_platforms) {
+ return IcdGetPlatformIDsKHR(num_entries, rd_platforms, rnum_platforms);
+}
diff --git a/src/gallium/frontends/clover/api/program.cpp b/src/gallium/frontends/clover/api/program.cpp
new file mode 100644
index 00000000000..33f843e9c87
--- /dev/null
+++ b/src/gallium/frontends/clover/api/program.cpp
@@ -0,0 +1,479 @@
+//
+// 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 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 "api/util.hpp"
+#include "core/program.hpp"
+#include "util/u_debug.h"
+
+#include <sstream>
+
+using namespace clover;
+
+namespace {
+ void
+ validate_build_common(const program &prog, cl_uint num_devs,
+ const cl_device_id *d_devs,
+ void (*pfn_notify)(cl_program, void *),
+ void *user_data) {
+ if (!pfn_notify && user_data)
+ throw error(CL_INVALID_VALUE);
+
+ if (prog.kernel_ref_count())
+ throw error(CL_INVALID_OPERATION);
+
+ if (any_of([&](const device &dev) {
+ return !count(dev, prog.devices());
+ }, objs<allow_empty_tag>(d_devs, num_devs)))
+ throw error(CL_INVALID_DEVICE);
+ }
+}
+
+CLOVER_API cl_program
+clCreateProgramWithSource(cl_context d_ctx, cl_uint count,
+ const char **strings, const size_t *lengths,
+ cl_int *r_errcode) try {
+ auto &ctx = obj(d_ctx);
+ std::string source;
+
+ if (!count || !strings ||
+ any_of(is_zero(), range(strings, count)))
+ throw error(CL_INVALID_VALUE);
+
+ // Concatenate all the provided fragments together
+ for (unsigned i = 0; i < count; ++i)
+ source += (lengths && lengths[i] ?
+ std::string(strings[i], strings[i] + lengths[i]) :
+ std::string(strings[i]));
+
+ // ...and create a program object for them.
+ ret_error(r_errcode, CL_SUCCESS);
+ return new program(ctx, source);
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_program
+clCreateProgramWithBinary(cl_context d_ctx, cl_uint n,
+ const cl_device_id *d_devs,
+ const size_t *lengths,
+ const unsigned char **binaries,
+ cl_int *r_status, cl_int *r_errcode) try {
+ auto &ctx = obj(d_ctx);
+ auto devs = objs(d_devs, n);
+
+ if (!lengths || !binaries)
+ throw error(CL_INVALID_VALUE);
+
+ if (any_of([&](const device &dev) {
+ return !count(dev, ctx.devices());
+ }, devs))
+ throw error(CL_INVALID_DEVICE);
+
+ // Deserialize the provided binaries,
+ std::vector<std::pair<cl_int, module>> result = map(
+ [](const unsigned char *p, size_t l) -> std::pair<cl_int, module> {
+ if (!p || !l)
+ return { CL_INVALID_VALUE, {} };
+
+ try {
+ std::stringbuf bin( { (char*)p, l } );
+ std::istream s(&bin);
+
+ return { CL_SUCCESS, module::deserialize(s) };
+
+ } catch (std::istream::failure &e) {
+ return { CL_INVALID_BINARY, {} };
+ }
+ },
+ range(binaries, n),
+ range(lengths, n));
+
+ // update the status array,
+ if (r_status)
+ copy(map(keys(), result), r_status);
+
+ if (any_of(key_equals(CL_INVALID_VALUE), result))
+ throw error(CL_INVALID_VALUE);
+
+ if (any_of(key_equals(CL_INVALID_BINARY), result))
+ throw error(CL_INVALID_BINARY);
+
+ // initialize a program object with them.
+ ret_error(r_errcode, CL_SUCCESS);
+ return new program(ctx, devs, map(values(), result));
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_program
+clCreateProgramWithBuiltInKernels(cl_context d_ctx, cl_uint n,
+ const cl_device_id *d_devs,
+ const char *kernel_names,
+ cl_int *r_errcode) try {
+ auto &ctx = obj(d_ctx);
+ auto devs = objs(d_devs, n);
+
+ if (any_of([&](const device &dev) {
+ return !count(dev, ctx.devices());
+ }, devs))
+ throw error(CL_INVALID_DEVICE);
+
+ // No currently supported built-in kernels.
+ throw error(CL_INVALID_VALUE);
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+
+CLOVER_API cl_int
+clRetainProgram(cl_program d_prog) try {
+ obj(d_prog).retain();
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clReleaseProgram(cl_program d_prog) try {
+ if (obj(d_prog).release())
+ delete pobj(d_prog);
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clBuildProgram(cl_program d_prog, cl_uint num_devs,
+ const cl_device_id *d_devs, const char *p_opts,
+ void (*pfn_notify)(cl_program, void *),
+ void *user_data) try {
+ auto &prog = obj(d_prog);
+ auto devs =
+ (d_devs ? objs(d_devs, num_devs) : ref_vector<device>(prog.devices()));
+ const auto opts = std::string(p_opts ? p_opts : "") + " " +
+ debug_get_option("CLOVER_EXTRA_BUILD_OPTIONS", "");
+
+ validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data);
+
+ if (prog.has_source) {
+ prog.compile(devs, opts);
+ prog.link(devs, opts, { prog });
+ } else if (any_of([&](const device &dev){
+ return prog.build(dev).binary_type() != CL_PROGRAM_BINARY_TYPE_EXECUTABLE;
+ }, devs)) {
+ // According to the OpenCL 1.2 specification, “if program is created
+ // with clCreateProgramWithBinary, then the program binary must be an
+ // executable binary (not a compiled binary or library).”
+ throw error(CL_INVALID_BINARY);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clCompileProgram(cl_program d_prog, cl_uint num_devs,
+ const cl_device_id *d_devs, const char *p_opts,
+ cl_uint num_headers, const cl_program *d_header_progs,
+ const char **header_names,
+ void (*pfn_notify)(cl_program, void *),
+ void *user_data) try {
+ auto &prog = obj(d_prog);
+ auto devs =
+ (d_devs ? objs(d_devs, num_devs) : ref_vector<device>(prog.devices()));
+ const auto opts = std::string(p_opts ? p_opts : "") + " " +
+ debug_get_option("CLOVER_EXTRA_COMPILE_OPTIONS", "");
+ header_map headers;
+
+ validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data);
+
+ if (bool(num_headers) != bool(header_names))
+ throw error(CL_INVALID_VALUE);
+
+ if (!prog.has_source)
+ throw error(CL_INVALID_OPERATION);
+
+ for_each([&](const char *name, const program &header) {
+ if (!header.has_source)
+ throw error(CL_INVALID_OPERATION);
+
+ if (!any_of(key_equals(name), headers))
+ headers.push_back(std::pair<std::string, std::string>(
+ name, header.source()));
+ },
+ range(header_names, num_headers),
+ objs<allow_empty_tag>(d_header_progs, num_headers));
+
+ prog.compile(devs, opts, headers);
+ return CL_SUCCESS;
+
+} catch (invalid_build_options_error &e) {
+ return CL_INVALID_COMPILER_OPTIONS;
+
+} catch (build_error &e) {
+ return CL_COMPILE_PROGRAM_FAILURE;
+
+} catch (error &e) {
+ return e.get();
+}
+
+namespace {
+ ref_vector<device>
+ validate_link_devices(const ref_vector<program> &progs,
+ const ref_vector<device> &all_devs,
+ const std::string &opts) {
+ std::vector<device *> devs;
+ const bool create_library =
+ opts.find("-create-library") != std::string::npos;
+ const bool enable_link_options =
+ opts.find("-enable-link-options") != std::string::npos;
+ const bool has_link_options =
+ opts.find("-cl-denorms-are-zero") != std::string::npos ||
+ opts.find("-cl-no-signed-zeroes") != std::string::npos ||
+ opts.find("-cl-unsafe-math-optimizations") != std::string::npos ||
+ opts.find("-cl-finite-math-only") != std::string::npos ||
+ opts.find("-cl-fast-relaxed-math") != std::string::npos ||
+ opts.find("-cl-no-subgroup-ifp") != std::string::npos;
+
+ // According to the OpenCL 1.2 specification, "[the
+ // -enable-link-options] option must be specified with the
+ // create-library option".
+ if (enable_link_options && !create_library)
+ throw error(CL_INVALID_LINKER_OPTIONS);
+
+ // According to the OpenCL 1.2 specification, "the
+ // [program linking options] can be specified when linking a program
+ // executable".
+ if (has_link_options && create_library)
+ throw error(CL_INVALID_LINKER_OPTIONS);
+
+ for (auto &dev : all_devs) {
+ const auto has_binary = [&](const program &prog) {
+ const auto t = prog.build(dev).binary_type();
+ return t == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT ||
+ t == CL_PROGRAM_BINARY_TYPE_LIBRARY;
+ };
+
+ // According to the OpenCL 1.2 specification, a library is made of
+ // “compiled binaries specified in input_programs argument to
+ // clLinkProgram“; compiled binaries does not refer to libraries:
+ // “input_programs is an array of program objects that are compiled
+ // binaries or libraries that are to be linked to create the program
+ // executable”.
+ if (create_library && any_of([&](const program &prog) {
+ const auto t = prog.build(dev).binary_type();
+ return t != CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT;
+ }, progs))
+ throw error(CL_INVALID_OPERATION);
+
+ // According to the CL 1.2 spec, when "all programs specified [..]
+ // contain a compiled binary or library for the device [..] a link is
+ // performed",
+ else if (all_of(has_binary, progs))
+ devs.push_back(&dev);
+
+ // otherwise if "none of the programs contain a compiled binary or
+ // library for that device [..] no link is performed. All other
+ // cases will return a CL_INVALID_OPERATION error."
+ else if (any_of(has_binary, progs))
+ throw error(CL_INVALID_OPERATION);
+
+ // According to the OpenCL 1.2 specification, "[t]he linker may apply
+ // [program linking options] to all compiled program objects
+ // specified to clLinkProgram. The linker may apply these options
+ // only to libraries which were created with the
+ // -enable-link-option."
+ else if (has_link_options && any_of([&](const program &prog) {
+ const auto t = prog.build(dev).binary_type();
+ return !(t == CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT ||
+ (t == CL_PROGRAM_BINARY_TYPE_LIBRARY &&
+ prog.build(dev).opts.find("-enable-link-options") !=
+ std::string::npos));
+ }, progs))
+ throw error(CL_INVALID_LINKER_OPTIONS);
+ }
+
+ return map(derefs(), devs);
+ }
+}
+
+CLOVER_API cl_program
+clLinkProgram(cl_context d_ctx, cl_uint num_devs, const cl_device_id *d_devs,
+ const char *p_opts, cl_uint num_progs, const cl_program *d_progs,
+ void (*pfn_notify) (cl_program, void *), void *user_data,
+ cl_int *r_errcode) try {
+ auto &ctx = obj(d_ctx);
+ const auto opts = std::string(p_opts ? p_opts : "") + " " +
+ debug_get_option("CLOVER_EXTRA_LINK_OPTIONS", "");
+ auto progs = objs(d_progs, num_progs);
+ auto all_devs =
+ (d_devs ? objs(d_devs, num_devs) : ref_vector<device>(ctx.devices()));
+ auto prog = create<program>(ctx, all_devs);
+ auto devs = validate_link_devices(progs, all_devs, opts);
+
+ validate_build_common(prog, num_devs, d_devs, pfn_notify, user_data);
+
+ try {
+ prog().link(devs, opts, progs);
+ ret_error(r_errcode, CL_SUCCESS);
+
+ } catch (build_error &e) {
+ ret_error(r_errcode, CL_LINK_PROGRAM_FAILURE);
+ }
+
+ return ret_object(prog);
+
+} catch (invalid_build_options_error &e) {
+ ret_error(r_errcode, CL_INVALID_LINKER_OPTIONS);
+ return NULL;
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_int
+clUnloadCompiler() {
+ return CL_SUCCESS;
+}
+
+CLOVER_API cl_int
+clUnloadPlatformCompiler(cl_platform_id d_platform) {
+ return CL_SUCCESS;
+}
+
+CLOVER_API cl_int
+clGetProgramInfo(cl_program d_prog, cl_program_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &prog = obj(d_prog);
+
+ switch (param) {
+ case CL_PROGRAM_REFERENCE_COUNT:
+ buf.as_scalar<cl_uint>() = prog.ref_count();
+ break;
+
+ case CL_PROGRAM_CONTEXT:
+ buf.as_scalar<cl_context>() = desc(prog.context());
+ break;
+
+ case CL_PROGRAM_NUM_DEVICES:
+ buf.as_scalar<cl_uint>() = (prog.devices().size() ?
+ prog.devices().size() :
+ prog.context().devices().size());
+ break;
+
+ case CL_PROGRAM_DEVICES:
+ buf.as_vector<cl_device_id>() = (prog.devices().size() ?
+ descs(prog.devices()) :
+ descs(prog.context().devices()));
+ break;
+
+ case CL_PROGRAM_SOURCE:
+ buf.as_string() = prog.source();
+ break;
+
+ case CL_PROGRAM_BINARY_SIZES:
+ buf.as_vector<size_t>() = map([&](const device &dev) {
+ return prog.build(dev).binary.size();
+ },
+ prog.devices());
+ break;
+
+ case CL_PROGRAM_BINARIES:
+ buf.as_matrix<unsigned char>() = map([&](const device &dev) {
+ std::stringbuf bin;
+ std::ostream s(&bin);
+ prog.build(dev).binary.serialize(s);
+ return bin.str();
+ },
+ prog.devices());
+ break;
+
+ case CL_PROGRAM_NUM_KERNELS:
+ buf.as_scalar<cl_uint>() = prog.symbols().size();
+ break;
+
+ case CL_PROGRAM_KERNEL_NAMES:
+ buf.as_string() = fold([](const std::string &a, const module::symbol &s) {
+ return ((a.empty() ? "" : a + ";") + s.name);
+ }, std::string(), prog.symbols());
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetProgramBuildInfo(cl_program d_prog, cl_device_id d_dev,
+ cl_program_build_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &prog = obj(d_prog);
+ auto &dev = obj(d_dev);
+
+ if (!count(dev, prog.context().devices()))
+ return CL_INVALID_DEVICE;
+
+ switch (param) {
+ case CL_PROGRAM_BUILD_STATUS:
+ buf.as_scalar<cl_build_status>() = prog.build(dev).status();
+ break;
+
+ case CL_PROGRAM_BUILD_OPTIONS:
+ buf.as_string() = prog.build(dev).opts;
+ break;
+
+ case CL_PROGRAM_BUILD_LOG:
+ buf.as_string() = prog.build(dev).log;
+ break;
+
+ case CL_PROGRAM_BINARY_TYPE:
+ buf.as_scalar<cl_program_binary_type>() = prog.build(dev).binary_type();
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
diff --git a/src/gallium/frontends/clover/api/queue.cpp b/src/gallium/frontends/clover/api/queue.cpp
new file mode 100644
index 00000000000..65b271b216f
--- /dev/null
+++ b/src/gallium/frontends/clover/api/queue.cpp
@@ -0,0 +1,135 @@
+//
+// 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 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 "api/util.hpp"
+#include "core/queue.hpp"
+
+using namespace clover;
+
+CLOVER_API cl_command_queue
+clCreateCommandQueue(cl_context d_ctx, cl_device_id d_dev,
+ cl_command_queue_properties props,
+ cl_int *r_errcode) try {
+ auto &ctx = obj(d_ctx);
+ auto &dev = obj(d_dev);
+
+ if (!count(dev, ctx.devices()))
+ throw error(CL_INVALID_DEVICE);
+
+ if (props & ~(CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE |
+ CL_QUEUE_PROFILING_ENABLE))
+ throw error(CL_INVALID_VALUE);
+
+ ret_error(r_errcode, CL_SUCCESS);
+ return new command_queue(ctx, dev, props);
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_int
+clRetainCommandQueue(cl_command_queue d_q) try {
+ obj(d_q).retain();
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clReleaseCommandQueue(cl_command_queue d_q) try {
+ auto &q = obj(d_q);
+
+ q.flush();
+
+ if (q.release())
+ delete pobj(d_q);
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetCommandQueueInfo(cl_command_queue d_q, cl_command_queue_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &q = obj(d_q);
+
+ switch (param) {
+ case CL_QUEUE_CONTEXT:
+ buf.as_scalar<cl_context>() = desc(q.context());
+ break;
+
+ case CL_QUEUE_DEVICE:
+ buf.as_scalar<cl_device_id>() = desc(q.device());
+ break;
+
+ case CL_QUEUE_REFERENCE_COUNT:
+ buf.as_scalar<cl_uint>() = q.ref_count();
+ break;
+
+ case CL_QUEUE_PROPERTIES:
+ buf.as_scalar<cl_command_queue_properties>() = q.properties();
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clFlush(cl_command_queue d_q) try {
+ obj(d_q).flush();
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_command_queue
+clCreateCommandQueueWithProperties(cl_context context, cl_device_id device,
+ const cl_queue_properties *properties,
+ cl_int *errcode_ret) try {
+ cl_command_queue_properties props = 0;
+ if (properties) {
+ for (auto idx = 0; properties[idx]; idx += 2) {
+ if (properties[idx] == CL_QUEUE_PROPERTIES)
+ props |= properties[idx + 1];
+ else
+ throw error(CL_INVALID_VALUE);
+ }
+ }
+
+ return clCreateCommandQueue(context, device, props, errcode_ret);
+
+} catch (error &e) {
+ ret_error(errcode_ret, e);
+ return NULL;
+}
diff --git a/src/gallium/frontends/clover/api/sampler.cpp b/src/gallium/frontends/clover/api/sampler.cpp
new file mode 100644
index 00000000000..482e55a9ce9
--- /dev/null
+++ b/src/gallium/frontends/clover/api/sampler.cpp
@@ -0,0 +1,100 @@
+//
+// 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 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 "api/util.hpp"
+#include "core/sampler.hpp"
+
+using namespace clover;
+
+CLOVER_API cl_sampler
+clCreateSampler(cl_context d_ctx, cl_bool norm_mode,
+ cl_addressing_mode addr_mode, cl_filter_mode filter_mode,
+ cl_int *r_errcode) try {
+ auto &ctx = obj(d_ctx);
+
+ if (!any_of(std::mem_fn(&device::image_support), ctx.devices()))
+ throw error(CL_INVALID_OPERATION);
+
+ ret_error(r_errcode, CL_SUCCESS);
+ return new sampler(ctx, norm_mode, addr_mode, filter_mode);
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_int
+clRetainSampler(cl_sampler d_s) try {
+ obj(d_s).retain();
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clReleaseSampler(cl_sampler d_s) try {
+ if (obj(d_s).release())
+ delete pobj(d_s);
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clGetSamplerInfo(cl_sampler d_s, cl_sampler_info param,
+ size_t size, void *r_buf, size_t *r_size) try {
+ property_buffer buf { r_buf, size, r_size };
+ auto &s = obj(d_s);
+
+ switch (param) {
+ case CL_SAMPLER_REFERENCE_COUNT:
+ buf.as_scalar<cl_uint>() = s.ref_count();
+ break;
+
+ case CL_SAMPLER_CONTEXT:
+ buf.as_scalar<cl_context>() = desc(s.context());
+ break;
+
+ case CL_SAMPLER_NORMALIZED_COORDS:
+ buf.as_scalar<cl_bool>() = s.norm_mode();
+ break;
+
+ case CL_SAMPLER_ADDRESSING_MODE:
+ buf.as_scalar<cl_addressing_mode>() = s.addr_mode();
+ break;
+
+ case CL_SAMPLER_FILTER_MODE:
+ buf.as_scalar<cl_filter_mode>() = s.filter_mode();
+ break;
+
+ default:
+ throw error(CL_INVALID_VALUE);
+ }
+
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
diff --git a/src/gallium/frontends/clover/api/transfer.cpp b/src/gallium/frontends/clover/api/transfer.cpp
new file mode 100644
index 00000000000..fa8741e02b4
--- /dev/null
+++ b/src/gallium/frontends/clover/api/transfer.cpp
@@ -0,0 +1,1059 @@
+//
+// 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 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 <cstring>
+
+#include "util/bitscan.h"
+
+#include "api/dispatch.hpp"
+#include "api/util.hpp"
+#include "core/event.hpp"
+#include "core/memory.hpp"
+
+using namespace clover;
+
+namespace {
+ typedef resource::vector vector_t;
+
+ vector_t
+ vector(const size_t *p) {
+ return range(p, 3);
+ }
+
+ vector_t
+ pitch(const vector_t &region, vector_t pitch) {
+ for (auto x : zip(tail(pitch),
+ map(multiplies(), region, pitch))) {
+ // The spec defines a value of zero as the natural pitch,
+ // i.e. the unaligned size of the previous dimension.
+ if (std::get<0>(x) == 0)
+ std::get<0>(x) = std::get<1>(x);
+ }
+
+ return pitch;
+ }
+
+ ///
+ /// Size of a region in bytes.
+ ///
+ size_t
+ size(const vector_t &pitch, const vector_t &region) {
+ if (any_of(is_zero(), region))
+ return 0;
+ else
+ return dot(pitch, region - vector_t{ 0, 1, 1 });
+ }
+
+ ///
+ /// Common argument checking shared by memory transfer commands.
+ ///
+ void
+ validate_common(command_queue &q,
+ const ref_vector<event> &deps) {
+ if (any_of([&](const event &ev) {
+ return ev.context() != q.context();
+ }, deps))
+ throw error(CL_INVALID_CONTEXT);
+ }
+
+ ///
+ /// Common error checking for a buffer object argument.
+ ///
+ void
+ validate_object(command_queue &q, buffer &mem, const vector_t &origin,
+ const vector_t &pitch, const vector_t &region) {
+ if (mem.context() != q.context())
+ throw error(CL_INVALID_CONTEXT);
+
+ // The region must fit within the specified pitch,
+ if (any_of(greater(), map(multiplies(), pitch, region), tail(pitch)))
+ throw error(CL_INVALID_VALUE);
+
+ // ...and within the specified object.
+ if (dot(pitch, origin) + size(pitch, region) > mem.size())
+ throw error(CL_INVALID_VALUE);
+
+ if (any_of(is_zero(), region))
+ throw error(CL_INVALID_VALUE);
+ }
+
+ ///
+ /// Common error checking for an image argument.
+ ///
+ void
+ validate_object(command_queue &q, image &img,
+ const vector_t &orig, const vector_t &region) {
+ vector_t size = { img.width(), img.height(), img.depth() };
+
+ if (!q.device().image_support())
+ throw error(CL_INVALID_OPERATION);
+
+ if (img.context() != q.context())
+ throw error(CL_INVALID_CONTEXT);
+
+ if (any_of(greater(), orig + region, size))
+ throw error(CL_INVALID_VALUE);
+
+ if (any_of(is_zero(), region))
+ throw error(CL_INVALID_VALUE);
+ }
+
+ ///
+ /// Common error checking for a host pointer argument.
+ ///
+ void
+ validate_object(command_queue &q, const void *ptr, const vector_t &orig,
+ const vector_t &pitch, const vector_t &region) {
+ if (!ptr)
+ throw error(CL_INVALID_VALUE);
+
+ // The region must fit within the specified pitch.
+ if (any_of(greater(), map(multiplies(), pitch, region), tail(pitch)))
+ throw error(CL_INVALID_VALUE);
+ }
+
+ ///
+ /// Common argument checking for a copy between two buffer objects.
+ ///
+ void
+ validate_copy(command_queue &q, buffer &dst_mem,
+ const vector_t &dst_orig, const vector_t &dst_pitch,
+ buffer &src_mem,
+ const vector_t &src_orig, const vector_t &src_pitch,
+ const vector_t &region) {
+ if (dst_mem == src_mem) {
+ auto dst_offset = dot(dst_pitch, dst_orig);
+ auto src_offset = dot(src_pitch, src_orig);
+
+ if (interval_overlaps()(
+ dst_offset, dst_offset + size(dst_pitch, region),
+ src_offset, src_offset + size(src_pitch, region)))
+ throw error(CL_MEM_COPY_OVERLAP);
+ }
+ }
+
+ ///
+ /// Common argument checking for a copy between two image objects.
+ ///
+ void
+ validate_copy(command_queue &q,
+ image &dst_img, const vector_t &dst_orig,
+ image &src_img, const vector_t &src_orig,
+ const vector_t &region) {
+ if (dst_img.format() != src_img.format())
+ throw error(CL_IMAGE_FORMAT_MISMATCH);
+
+ if (dst_img == src_img) {
+ if (all_of(interval_overlaps(),
+ dst_orig, dst_orig + region,
+ src_orig, src_orig + region))
+ throw error(CL_MEM_COPY_OVERLAP);
+ }
+ }
+
+ ///
+ /// Checks that the host access flags of the memory object are
+ /// within the allowed set \a flags.
+ ///
+ void
+ validate_object_access(const memory_obj &mem, const cl_mem_flags flags) {
+ if (mem.flags() & ~flags &
+ (CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_WRITE_ONLY |
+ CL_MEM_HOST_NO_ACCESS))
+ throw error(CL_INVALID_OPERATION);
+ }
+
+ ///
+ /// Checks that the mapping flags are correct.
+ ///
+ void
+ validate_map_flags(const memory_obj &mem, const cl_map_flags flags) {
+ if ((flags & (CL_MAP_WRITE | CL_MAP_READ)) &&
+ (flags & CL_MAP_WRITE_INVALIDATE_REGION))
+ throw error(CL_INVALID_VALUE);
+
+ if (flags & CL_MAP_READ)
+ validate_object_access(mem, CL_MEM_HOST_READ_ONLY);
+
+ if (flags & (CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION))
+ validate_object_access(mem, CL_MEM_HOST_WRITE_ONLY);
+ }
+
+ ///
+ /// Class that encapsulates the task of mapping an object of type
+ /// \a T. The return value of get() should be implicitly
+ /// convertible to \a void *.
+ ///
+ template<typename T>
+ struct _map {
+ static mapping
+ get(command_queue &q, T obj, cl_map_flags flags,
+ size_t offset, size_t size) {
+ return { q, obj->resource(q), flags, true,
+ {{ offset }}, {{ size, 1, 1 }} };
+ }
+ };
+
+ template<>
+ struct _map<void *> {
+ static void *
+ get(command_queue &q, void *obj, cl_map_flags flags,
+ size_t offset, size_t size) {
+ return (char *)obj + offset;
+ }
+ };
+
+ template<>
+ struct _map<const void *> {
+ static const void *
+ get(command_queue &q, const void *obj, cl_map_flags flags,
+ size_t offset, size_t size) {
+ return (const char *)obj + offset;
+ }
+ };
+
+ ///
+ /// Software copy from \a src_obj to \a dst_obj. They can be
+ /// either pointers or memory objects.
+ ///
+ template<typename T, typename S>
+ std::function<void (event &)>
+ soft_copy_op(command_queue &q,
+ T dst_obj, const vector_t &dst_orig, const vector_t &dst_pitch,
+ S src_obj, const vector_t &src_orig, const vector_t &src_pitch,
+ const vector_t &region) {
+ return [=, &q](event &) {
+ auto dst = _map<T>::get(q, dst_obj, CL_MAP_WRITE,
+ dot(dst_pitch, dst_orig),
+ size(dst_pitch, region));
+ auto src = _map<S>::get(q, src_obj, CL_MAP_READ,
+ dot(src_pitch, src_orig),
+ size(src_pitch, region));
+ vector_t v = {};
+
+ for (v[2] = 0; v[2] < region[2]; ++v[2]) {
+ for (v[1] = 0; v[1] < region[1]; ++v[1]) {
+ std::memcpy(
+ static_cast<char *>(dst) + dot(dst_pitch, v),
+ static_cast<const char *>(src) + dot(src_pitch, v),
+ src_pitch[0] * region[0]);
+ }
+ }
+ };
+ }
+
+ ///
+ /// Hardware copy from \a src_obj to \a dst_obj.
+ ///
+ template<typename T, typename S>
+ std::function<void (event &)>
+ hard_copy_op(command_queue &q, T dst_obj, const vector_t &dst_orig,
+ S src_obj, const vector_t &src_orig, const vector_t &region) {
+ return [=, &q](event &) {
+ dst_obj->resource(q).copy(q, dst_orig, region,
+ src_obj->resource(q), src_orig);
+ };
+ }
+}
+
+CLOVER_API cl_int
+clEnqueueReadBuffer(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
+ size_t offset, size_t size, void *ptr,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &mem = obj<buffer>(d_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ vector_t region = { size, 1, 1 };
+ vector_t obj_origin = { offset };
+ auto obj_pitch = pitch(region, {{ 1 }});
+
+ validate_common(q, deps);
+ validate_object(q, ptr, {}, obj_pitch, region);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
+ validate_object_access(mem, CL_MEM_HOST_READ_ONLY);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_READ_BUFFER, deps,
+ soft_copy_op(q, ptr, {}, obj_pitch,
+ &mem, obj_origin, obj_pitch,
+ region));
+
+ if (blocking)
+ hev().wait_signalled();
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueWriteBuffer(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
+ size_t offset, size_t size, const void *ptr,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &mem = obj<buffer>(d_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ vector_t region = { size, 1, 1 };
+ vector_t obj_origin = { offset };
+ auto obj_pitch = pitch(region, {{ 1 }});
+
+ validate_common(q, deps);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
+ validate_object(q, ptr, {}, obj_pitch, region);
+ validate_object_access(mem, CL_MEM_HOST_WRITE_ONLY);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_WRITE_BUFFER, deps,
+ soft_copy_op(q, &mem, obj_origin, obj_pitch,
+ ptr, {}, obj_pitch,
+ region));
+
+ if (blocking)
+ hev().wait_signalled();
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueReadBufferRect(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
+ const size_t *p_obj_origin,
+ const size_t *p_host_origin,
+ const size_t *p_region,
+ size_t obj_row_pitch, size_t obj_slice_pitch,
+ size_t host_row_pitch, size_t host_slice_pitch,
+ void *ptr,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &mem = obj<buffer>(d_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto obj_origin = vector(p_obj_origin);
+ auto obj_pitch = pitch(region, {{ 1, obj_row_pitch, obj_slice_pitch }});
+ auto host_origin = vector(p_host_origin);
+ auto host_pitch = pitch(region, {{ 1, host_row_pitch, host_slice_pitch }});
+
+ validate_common(q, deps);
+ validate_object(q, ptr, host_origin, host_pitch, region);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
+ validate_object_access(mem, CL_MEM_HOST_READ_ONLY);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_READ_BUFFER_RECT, deps,
+ soft_copy_op(q, ptr, host_origin, host_pitch,
+ &mem, obj_origin, obj_pitch,
+ region));
+
+ if (blocking)
+ hev().wait_signalled();
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueWriteBufferRect(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
+ const size_t *p_obj_origin,
+ const size_t *p_host_origin,
+ const size_t *p_region,
+ size_t obj_row_pitch, size_t obj_slice_pitch,
+ size_t host_row_pitch, size_t host_slice_pitch,
+ const void *ptr,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &mem = obj<buffer>(d_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto obj_origin = vector(p_obj_origin);
+ auto obj_pitch = pitch(region, {{ 1, obj_row_pitch, obj_slice_pitch }});
+ auto host_origin = vector(p_host_origin);
+ auto host_pitch = pitch(region, {{ 1, host_row_pitch, host_slice_pitch }});
+
+ validate_common(q, deps);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
+ validate_object(q, ptr, host_origin, host_pitch, region);
+ validate_object_access(mem, CL_MEM_HOST_WRITE_ONLY);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_WRITE_BUFFER_RECT, deps,
+ soft_copy_op(q, &mem, obj_origin, obj_pitch,
+ ptr, host_origin, host_pitch,
+ region));
+
+ if (blocking)
+ hev().wait_signalled();
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueCopyBuffer(cl_command_queue d_q, cl_mem d_src_mem, cl_mem d_dst_mem,
+ size_t src_offset, size_t dst_offset, size_t size,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &src_mem = obj<buffer>(d_src_mem);
+ auto &dst_mem = obj<buffer>(d_dst_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ vector_t region = { size, 1, 1 };
+ vector_t dst_origin = { dst_offset };
+ auto dst_pitch = pitch(region, {{ 1 }});
+ vector_t src_origin = { src_offset };
+ auto src_pitch = pitch(region, {{ 1 }});
+
+ validate_common(q, deps);
+ validate_object(q, dst_mem, dst_origin, dst_pitch, region);
+ validate_object(q, src_mem, src_origin, src_pitch, region);
+ validate_copy(q, dst_mem, dst_origin, dst_pitch,
+ src_mem, src_origin, src_pitch, region);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_COPY_BUFFER, deps,
+ hard_copy_op(q, &dst_mem, dst_origin,
+ &src_mem, src_origin, region));
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueCopyBufferRect(cl_command_queue d_q, cl_mem d_src_mem,
+ cl_mem d_dst_mem,
+ const size_t *p_src_origin, const size_t *p_dst_origin,
+ const size_t *p_region,
+ size_t src_row_pitch, size_t src_slice_pitch,
+ size_t dst_row_pitch, size_t dst_slice_pitch,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &src_mem = obj<buffer>(d_src_mem);
+ auto &dst_mem = obj<buffer>(d_dst_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto dst_origin = vector(p_dst_origin);
+ auto dst_pitch = pitch(region, {{ 1, dst_row_pitch, dst_slice_pitch }});
+ auto src_origin = vector(p_src_origin);
+ auto src_pitch = pitch(region, {{ 1, src_row_pitch, src_slice_pitch }});
+
+ validate_common(q, deps);
+ validate_object(q, dst_mem, dst_origin, dst_pitch, region);
+ validate_object(q, src_mem, src_origin, src_pitch, region);
+ validate_copy(q, dst_mem, dst_origin, dst_pitch,
+ src_mem, src_origin, src_pitch, region);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_COPY_BUFFER_RECT, deps,
+ soft_copy_op(q, &dst_mem, dst_origin, dst_pitch,
+ &src_mem, src_origin, src_pitch,
+ region));
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueReadImage(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
+ const size_t *p_origin, const size_t *p_region,
+ size_t row_pitch, size_t slice_pitch, void *ptr,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &img = obj<image>(d_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto dst_pitch = pitch(region, {{ img.pixel_size(),
+ row_pitch, slice_pitch }});
+ auto src_origin = vector(p_origin);
+ auto src_pitch = pitch(region, {{ img.pixel_size(),
+ img.row_pitch(), img.slice_pitch() }});
+
+ validate_common(q, deps);
+ validate_object(q, ptr, {}, dst_pitch, region);
+ validate_object(q, img, src_origin, region);
+ validate_object_access(img, CL_MEM_HOST_READ_ONLY);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_READ_IMAGE, deps,
+ soft_copy_op(q, ptr, {}, dst_pitch,
+ &img, src_origin, src_pitch,
+ region));
+
+ if (blocking)
+ hev().wait_signalled();
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueWriteImage(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
+ const size_t *p_origin, const size_t *p_region,
+ size_t row_pitch, size_t slice_pitch, const void *ptr,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &img = obj<image>(d_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto dst_origin = vector(p_origin);
+ auto dst_pitch = pitch(region, {{ img.pixel_size(),
+ img.row_pitch(), img.slice_pitch() }});
+ auto src_pitch = pitch(region, {{ img.pixel_size(),
+ row_pitch, slice_pitch }});
+
+ validate_common(q, deps);
+ validate_object(q, img, dst_origin, region);
+ validate_object(q, ptr, {}, src_pitch, region);
+ validate_object_access(img, CL_MEM_HOST_WRITE_ONLY);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_WRITE_IMAGE, deps,
+ soft_copy_op(q, &img, dst_origin, dst_pitch,
+ ptr, {}, src_pitch,
+ region));
+
+ if (blocking)
+ hev().wait_signalled();
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueCopyImage(cl_command_queue d_q, cl_mem d_src_mem, cl_mem d_dst_mem,
+ const size_t *p_src_origin, const size_t *p_dst_origin,
+ const size_t *p_region,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &src_img = obj<image>(d_src_mem);
+ auto &dst_img = obj<image>(d_dst_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto dst_origin = vector(p_dst_origin);
+ auto src_origin = vector(p_src_origin);
+
+ validate_common(q, deps);
+ validate_object(q, dst_img, dst_origin, region);
+ validate_object(q, src_img, src_origin, region);
+ validate_copy(q, dst_img, dst_origin, src_img, src_origin, region);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_COPY_IMAGE, deps,
+ hard_copy_op(q, &dst_img, dst_origin,
+ &src_img, src_origin,
+ region));
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueCopyImageToBuffer(cl_command_queue d_q,
+ cl_mem d_src_mem, cl_mem d_dst_mem,
+ const size_t *p_src_origin, const size_t *p_region,
+ size_t dst_offset,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &src_img = obj<image>(d_src_mem);
+ auto &dst_mem = obj<buffer>(d_dst_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ vector_t dst_origin = { dst_offset };
+ auto dst_pitch = pitch(region, {{ src_img.pixel_size() }});
+ auto src_origin = vector(p_src_origin);
+ auto src_pitch = pitch(region, {{ src_img.pixel_size(),
+ src_img.row_pitch(),
+ src_img.slice_pitch() }});
+
+ validate_common(q, deps);
+ validate_object(q, dst_mem, dst_origin, dst_pitch, region);
+ validate_object(q, src_img, src_origin, region);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_COPY_IMAGE_TO_BUFFER, deps,
+ soft_copy_op(q, &dst_mem, dst_origin, dst_pitch,
+ &src_img, src_origin, src_pitch,
+ region));
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueCopyBufferToImage(cl_command_queue d_q,
+ cl_mem d_src_mem, cl_mem d_dst_mem,
+ size_t src_offset,
+ const size_t *p_dst_origin, const size_t *p_region,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &src_mem = obj<buffer>(d_src_mem);
+ auto &dst_img = obj<image>(d_dst_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto dst_origin = vector(p_dst_origin);
+ auto dst_pitch = pitch(region, {{ dst_img.pixel_size(),
+ dst_img.row_pitch(),
+ dst_img.slice_pitch() }});
+ vector_t src_origin = { src_offset };
+ auto src_pitch = pitch(region, {{ dst_img.pixel_size() }});
+
+ validate_common(q, deps);
+ validate_object(q, dst_img, dst_origin, region);
+ validate_object(q, src_mem, src_origin, src_pitch, region);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_COPY_BUFFER_TO_IMAGE, deps,
+ soft_copy_op(q, &dst_img, dst_origin, dst_pitch,
+ &src_mem, src_origin, src_pitch,
+ region));
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API void *
+clEnqueueMapBuffer(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
+ cl_map_flags flags, size_t offset, size_t size,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev, cl_int *r_errcode) try {
+ auto &q = obj(d_q);
+ auto &mem = obj<buffer>(d_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ vector_t region = { size, 1, 1 };
+ vector_t obj_origin = { offset };
+ auto obj_pitch = pitch(region, {{ 1 }});
+
+ validate_common(q, deps);
+ validate_object(q, mem, obj_origin, obj_pitch, region);
+ validate_map_flags(mem, flags);
+
+ void *map = mem.resource(q).add_map(q, flags, blocking, obj_origin, region);
+
+ auto hev = create<hard_event>(q, CL_COMMAND_MAP_BUFFER, deps);
+ if (blocking)
+ hev().wait_signalled();
+
+ ret_object(rd_ev, hev);
+ ret_error(r_errcode, CL_SUCCESS);
+ return map;
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API void *
+clEnqueueMapImage(cl_command_queue d_q, cl_mem d_mem, cl_bool blocking,
+ cl_map_flags flags,
+ const size_t *p_origin, const size_t *p_region,
+ size_t *row_pitch, size_t *slice_pitch,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev, cl_int *r_errcode) try {
+ auto &q = obj(d_q);
+ auto &img = obj<image>(d_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+ auto region = vector(p_region);
+ auto origin = vector(p_origin);
+
+ validate_common(q, deps);
+ validate_object(q, img, origin, region);
+ validate_map_flags(img, flags);
+
+ void *map = img.resource(q).add_map(q, flags, blocking, origin, region);
+
+ auto hev = create<hard_event>(q, CL_COMMAND_MAP_IMAGE, deps);
+ if (blocking)
+ hev().wait_signalled();
+
+ ret_object(rd_ev, hev);
+ ret_error(r_errcode, CL_SUCCESS);
+ return map;
+
+} catch (error &e) {
+ ret_error(r_errcode, e);
+ return NULL;
+}
+
+CLOVER_API cl_int
+clEnqueueUnmapMemObject(cl_command_queue d_q, cl_mem d_mem, void *ptr,
+ cl_uint num_deps, const cl_event *d_deps,
+ cl_event *rd_ev) try {
+ auto &q = obj(d_q);
+ auto &mem = obj(d_mem);
+ auto deps = objs<wait_list_tag>(d_deps, num_deps);
+
+ validate_common(q, deps);
+
+ auto hev = create<hard_event>(
+ q, CL_COMMAND_UNMAP_MEM_OBJECT, deps,
+ [=, &q, &mem](event &) {
+ mem.resource(q).del_map(ptr);
+ });
+
+ ret_object(rd_ev, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueMigrateMemObjects(cl_command_queue command_queue,
+ cl_uint num_mem_objects,
+ const cl_mem *mem_objects,
+ cl_mem_migration_flags flags,
+ cl_uint num_events_in_wait_list,
+ const cl_event *event_wait_list,
+ cl_event *event) {
+ CLOVER_NOT_SUPPORTED_UNTIL("1.2");
+ return CL_INVALID_VALUE;
+}
+
+cl_int
+clover::EnqueueSVMFree(cl_command_queue d_q,
+ 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 cmd) try {
+
+ if (bool(num_svm_pointers) != bool(svm_pointers))
+ return CL_INVALID_VALUE;
+
+ auto &q = obj(d_q);
+ bool can_emulate = q.device().has_system_svm();
+ auto deps = objs<wait_list_tag>(event_wait_list, num_events_in_wait_list);
+
+ validate_common(q, deps);
+
+ std::vector<void *> svm_pointers_cpy(svm_pointers,
+ svm_pointers + num_svm_pointers);
+ if (!pfn_free_func) {
+ if (!can_emulate) {
+ CLOVER_NOT_SUPPORTED_UNTIL("2.0");
+ return CL_INVALID_VALUE;
+ }
+ pfn_free_func = [](cl_command_queue, cl_uint num_svm_pointers,
+ void *svm_pointers[], void *) {
+ for (void *p : range(svm_pointers, num_svm_pointers))
+ free(p);
+ };
+ }
+
+ auto hev = create<hard_event>(q, cmd, deps,
+ [=](clover::event &) mutable {
+ pfn_free_func(d_q, num_svm_pointers, svm_pointers_cpy.data(),
+ user_data);
+ });
+
+ ret_object(event, hev);
+ return CL_SUCCESS;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueSVMFree(cl_command_queue d_q,
+ 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) {
+
+ return EnqueueSVMFree(d_q, num_svm_pointers, svm_pointers,
+ pfn_free_func, user_data, num_events_in_wait_list,
+ event_wait_list, event, CL_COMMAND_SVM_FREE);
+}
+
+cl_int
+clover::EnqueueSVMMemcpy(cl_command_queue d_q,
+ 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 cmd) try {
+
+ if (dst_ptr == nullptr || src_ptr == nullptr)
+ return CL_INVALID_VALUE;
+
+ if (static_cast<size_t>(abs(reinterpret_cast<ptrdiff_t>(dst_ptr) -
+ reinterpret_cast<ptrdiff_t>(src_ptr))) < size)
+ return CL_MEM_COPY_OVERLAP;
+
+ auto &q = obj(d_q);
+ bool can_emulate = q.device().has_system_svm();
+ auto deps = objs<wait_list_tag>(event_wait_list, num_events_in_wait_list);
+
+ validate_common(q, deps);
+
+ if (can_emulate) {
+ auto hev = create<hard_event>(q, cmd, deps,
+ [=](clover::event &) {
+ memcpy(dst_ptr, src_ptr, size);
+ });
+
+ if (blocking_copy)
+ hev().wait();
+ ret_object(event, hev);
+ return CL_SUCCESS;
+ }
+
+ CLOVER_NOT_SUPPORTED_UNTIL("2.0");
+ return CL_INVALID_VALUE;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueSVMMemcpy(cl_command_queue d_q,
+ 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) {
+
+ return EnqueueSVMMemcpy(d_q, blocking_copy, dst_ptr, src_ptr,
+ size, num_events_in_wait_list, event_wait_list,
+ event, CL_COMMAND_SVM_MEMCPY);
+}
+
+cl_int
+clover::EnqueueSVMMemFill(cl_command_queue d_q,
+ 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 cmd) try {
+
+ if (svm_ptr == nullptr || pattern == nullptr ||
+ !util_is_power_of_two_nonzero(pattern_size) ||
+ pattern_size > 128 ||
+ !ptr_is_aligned(svm_ptr, pattern_size) ||
+ size % pattern_size)
+ return CL_INVALID_VALUE;
+
+ auto &q = obj(d_q);
+ bool can_emulate = q.device().has_system_svm();
+ auto deps = objs<wait_list_tag>(event_wait_list, num_events_in_wait_list);
+
+ validate_common(q, deps);
+
+ if (can_emulate) {
+ auto hev = create<hard_event>(q, cmd, deps,
+ [=](clover::event &) {
+ void *ptr = svm_ptr;
+ for (size_t s = size; s; s -= pattern_size) {
+ memcpy(ptr, pattern, pattern_size);
+ ptr = static_cast<uint8_t*>(ptr) + pattern_size;
+ }
+ });
+
+ ret_object(event, hev);
+ return CL_SUCCESS;
+ }
+
+ CLOVER_NOT_SUPPORTED_UNTIL("2.0");
+ return CL_INVALID_VALUE;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueSVMMemFill(cl_command_queue d_q,
+ 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) {
+
+ return EnqueueSVMMemFill(d_q, svm_ptr, pattern, pattern_size,
+ size, num_events_in_wait_list, event_wait_list,
+ event, CL_COMMAND_SVM_MEMFILL);
+}
+
+cl_int
+clover::EnqueueSVMMap(cl_command_queue d_q,
+ 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 cmd) try {
+
+ if (svm_ptr == nullptr || size == 0)
+ return CL_INVALID_VALUE;
+
+ auto &q = obj(d_q);
+ bool can_emulate = q.device().has_system_svm();
+ auto deps = objs<wait_list_tag>(event_wait_list, num_events_in_wait_list);
+
+ validate_common(q, deps);
+
+ if (can_emulate) {
+ auto hev = create<hard_event>(q, cmd, deps,
+ [](clover::event &) { });
+
+ ret_object(event, hev);
+ return CL_SUCCESS;
+ }
+
+ CLOVER_NOT_SUPPORTED_UNTIL("2.0");
+ return CL_INVALID_VALUE;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueSVMMap(cl_command_queue d_q,
+ 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) {
+
+ return EnqueueSVMMap(d_q, blocking_map, map_flags, svm_ptr, size,
+ num_events_in_wait_list, event_wait_list, event,
+ CL_COMMAND_SVM_MAP);
+}
+
+cl_int
+clover::EnqueueSVMUnmap(cl_command_queue d_q,
+ void *svm_ptr,
+ cl_uint num_events_in_wait_list,
+ const cl_event *event_wait_list,
+ cl_event *event,
+ cl_int cmd) try {
+
+ if (svm_ptr == nullptr)
+ return CL_INVALID_VALUE;
+
+ auto &q = obj(d_q);
+ bool can_emulate = q.device().has_system_svm();
+ auto deps = objs<wait_list_tag>(event_wait_list, num_events_in_wait_list);
+
+ validate_common(q, deps);
+
+ if (can_emulate) {
+ auto hev = create<hard_event>(q, cmd, deps,
+ [](clover::event &) { });
+
+ ret_object(event, hev);
+ return CL_SUCCESS;
+ }
+
+ CLOVER_NOT_SUPPORTED_UNTIL("2.0");
+ return CL_INVALID_VALUE;
+
+} catch (error &e) {
+ return e.get();
+}
+
+CLOVER_API cl_int
+clEnqueueSVMUnmap(cl_command_queue d_q,
+ void *svm_ptr,
+ cl_uint num_events_in_wait_list,
+ const cl_event *event_wait_list,
+ cl_event *event) {
+
+ return EnqueueSVMUnmap(d_q, svm_ptr, num_events_in_wait_list,
+ event_wait_list, event, CL_COMMAND_SVM_UNMAP);
+}
+
+CLOVER_API cl_int
+clEnqueueSVMMigrateMem(cl_command_queue d_q,
+ cl_uint num_svm_pointers,
+ const void **svm_pointers,
+ const size_t *sizes,
+ const cl_mem_migration_flags flags,
+ cl_uint num_events_in_wait_list,
+ const cl_event *event_wait_list,
+ cl_event *event) {
+ CLOVER_NOT_SUPPORTED_UNTIL("2.1");
+ return CL_INVALID_VALUE;
+}
diff --git a/src/gallium/frontends/clover/api/util.hpp b/src/gallium/frontends/clover/api/util.hpp
new file mode 100644
index 00000000000..66bd12597c6
--- /dev/null
+++ b/src/gallium/frontends/clover/api/util.hpp
@@ -0,0 +1,84 @@
+//
+// 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 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.
+//
+
+#ifndef CLOVER_API_UTIL_HPP
+#define CLOVER_API_UTIL_HPP
+
+#include <cassert>
+#include <iostream>
+
+#include "core/error.hpp"
+#include "core/property.hpp"
+#include "util/algorithm.hpp"
+
+#ifdef HAVE_CLOVER_ICD
+#define CLOVER_API
+#define CLOVER_ICD_API PUBLIC
+#else
+#define CLOVER_API PUBLIC
+#define CLOVER_ICD_API PUBLIC
+#endif
+
+#define CLOVER_NOT_SUPPORTED_UNTIL(version) \
+ do { \
+ std::cerr << "CL user error: " << __func__ \
+ << "() requires OpenCL version " << (version) \
+ << " or greater." << std::endl; \
+ } while (0)
+
+namespace clover {
+ ///
+ /// Return an error code in \a p if non-zero.
+ ///
+ inline void
+ ret_error(cl_int *p, const clover::error &e) {
+ if (p)
+ *p = e.get();
+ }
+
+ ///
+ /// Return a clover object in \a p if non-zero incrementing the
+ /// reference count of the object.
+ ///
+ template<typename T>
+ void
+ ret_object(typename T::descriptor_type **p,
+ const intrusive_ref<T> &v) {
+ if (p) {
+ v().retain();
+ *p = desc(v());
+ }
+ }
+
+ ///
+ /// Return an API object from an intrusive reference to a Clover object,
+ /// incrementing the reference count of the object.
+ ///
+ template<typename T>
+ typename T::descriptor_type *
+ ret_object(const intrusive_ref<T> &v) {
+ v().retain();
+ return desc(v());
+ }
+}
+
+#endif