From 3b050288ad138681bac6b6e512ab9c61c3edeb53 Mon Sep 17 00:00:00 2001
From: foreman
Date: Mon, 11 Sep 2017 17:58:22 -0400
Subject: [PATCH] P4 to Git Change 1457530 by wchau@wchau_WIN_OCL_HSA on
2017/09/11 17:14:57
SWDEV-126884 - OCL 2.1 Platform APIs
Affected files ...
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/amdocl.def.in#17 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/amdocl.map#4 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/amdocl.map.in#19 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_command.cpp#14 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_context.cpp#56 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_execute.cpp#24 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_icd.cpp#30 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_icd_amd.h#20 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_program.cpp#42 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_svm.cpp#21 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/khronos/headers/opencl2.1/CL/cl.h#5 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/khronos/headers/opencl2.2/CL/cl.h#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/command.hpp#86 edit
[ROCm/clr commit: 86f90851e9ad9335fe7773a3094994df5821aa76]
---
.../opencl/api/opencl/amdocl/amdocl.def.in | 10 ++
.../clr/opencl/api/opencl/amdocl/amdocl.map | 11 ++
.../opencl/api/opencl/amdocl/amdocl.map.in | 6 +
.../opencl/api/opencl/amdocl/cl_command.cpp | 61 +++++++
.../opencl/api/opencl/amdocl/cl_context.cpp | 4 +-
.../opencl/api/opencl/amdocl/cl_execute.cpp | 94 ++++++++++
.../clr/opencl/api/opencl/amdocl/cl_icd.cpp | 10 +-
.../clr/opencl/api/opencl/amdocl/cl_icd_amd.h | 2 +-
.../opencl/api/opencl/amdocl/cl_program.cpp | 84 ++++++++-
.../clr/opencl/api/opencl/amdocl/cl_svm.cpp | 166 ++++++++++++++++++
.../opencl/khronos/headers/opencl2.1/CL/cl.h | 1 +
.../opencl/khronos/headers/opencl2.2/CL/cl.h | 1 +
12 files changed, 442 insertions(+), 8 deletions(-)
diff --git a/projects/clr/opencl/api/opencl/amdocl/amdocl.def.in b/projects/clr/opencl/api/opencl/amdocl/amdocl.def.in
index cc631e3ca2..78df2030fd 100644
--- a/projects/clr/opencl/api/opencl/amdocl/amdocl.def.in
+++ b/projects/clr/opencl/api/opencl/amdocl/amdocl.def.in
@@ -118,6 +118,16 @@ clEnqueueSVMMap
clEnqueueSVMUnmap
#endif
+#if (OPENCL_MAJOR > 2) || (OPENCL_MAJOR == 2 && OPENCL_MINOR >= 1)
+clCloneKernel
+clCreateProgramWithIL
+clEnqueueSVMMigrateMem
+clGetDeviceAndHostTimer
+clGetHostTimer
+clGetKernelSubGroupInfo
+clSetDefaultDeviceCommandQueue
+#endif
+
#if !defined(WITH_LIGHTNING_COMPILER)
aclCompilerInit
aclCompilerFini
diff --git a/projects/clr/opencl/api/opencl/amdocl/amdocl.map b/projects/clr/opencl/api/opencl/amdocl/amdocl.map
index 4186970f4a..8e45fba1c0 100644
--- a/projects/clr/opencl/api/opencl/amdocl/amdocl.map
+++ b/projects/clr/opencl/api/opencl/amdocl/amdocl.map
@@ -152,3 +152,14 @@ global:
clEnqueueSVMMap;
clEnqueueSVMUnmap;
} OPENCL_1.2;
+
+OPENCL_2.1 {
+global:
+ clCloneKernel;
+ clCreateProgramWithIL
+ clEnqueueSVMMigrateMem
+ clGetDeviceAndHostTimer
+ clGetHostTimer
+ clGetKernelSubGroupInfo
+ clSetDefaultDeviceCommandQueue
+} OPENCL_2.0;
diff --git a/projects/clr/opencl/api/opencl/amdocl/amdocl.map.in b/projects/clr/opencl/api/opencl/amdocl/amdocl.map.in
index 8861832f92..507d14b7d6 100644
--- a/projects/clr/opencl/api/opencl/amdocl/amdocl.map.in
+++ b/projects/clr/opencl/api/opencl/amdocl/amdocl.map.in
@@ -161,7 +161,13 @@ global:
#if (OPENCL_MAJOR > 2) || (OPENCL_MAJOR == 2 && OPENCL_MINOR >= 1)
OPENCL_2.1 {
global:
+ clCloneKernel;
clCreateProgramWithIL;
+ clEnqueueSVMMigrateMem;
+ clGetDeviceAndHostTimer;
+ clGetHostTimer;
+ clGetKernelSubGroupInfo;
+ clSetDefaultDeviceCommandQueue;
} OPENCL_2.1;
#endif
diff --git a/projects/clr/opencl/api/opencl/amdocl/cl_command.cpp b/projects/clr/opencl/api/opencl/amdocl/cl_command.cpp
index 82dcdf8025..c7ccfb4ce4 100644
--- a/projects/clr/opencl/api/opencl/amdocl/cl_command.cpp
+++ b/projects/clr/opencl/api/opencl/amdocl/cl_command.cpp
@@ -173,6 +173,67 @@ RUNTIME_ENTRY_RET(cl_command_queue, clCreateCommandQueue,
}
RUNTIME_EXIT
+/*! \brief Replaces the default command queue on the device
+ *
+ * \param context must be a valid OpenCL context.
+ *
+ * \param device must be a device associated with context.
+ *
+ * \param command_queue specifies the default command-queue.
+ *
+ * \reture One of the following values:
+ * - CL_SUCCESS if the function executed successfully.
+ * - CL_INVALID_CONTEXT if \a context is not a valid context.
+ * - CL_INVALID_DEVICE if \a device is not a valid device or is not
+ * associated with context.
+ * - CL_INVALID_COMMAND_QUEUE if \a command_queue is not a valid command-
+ * queue for device.
+ */
+RUNTIME_ENTRY(cl_int, clSetDefaultDeviceCommandQueue,
+ (cl_context context, cl_device_id device, cl_command_queue command_queue)) {
+ if (!is_valid(context)) {
+ return CL_INVALID_CONTEXT;
+ }
+
+ amd::Context& amdContext = *as_amd(context);
+ amd::Device& amdDevice = *as_amd(device);
+ amd::DeviceQueue* deviceQueue = as_amd(command_queue)->asDeviceQueue();
+
+ if (!is_valid(device) || !amdContext.containsDevice(&amdDevice)) {
+ return CL_INVALID_DEVICE;
+ }
+
+ if (!is_valid(command_queue)) {
+ return CL_INVALID_VALUE;
+ }
+
+
+ //TODO: implemente the set default device command queue logic
+ LogWarning("Device support for clSetDefaultDeviceCommandQueue() has not been implemented");
+
+#if 0
+ // implementation of the set default device command queue logic - unverified
+
+ //TODO: Need to update the clGetCommandQueueInfo to support CL_QUEUE_DEVICE_DEFAULT
+ //
+ {
+ amd::ScopedLock lock(amdContext.lock());
+
+ amd::DeviceQueue* queue = amdContext.defDeviceQueue(amdDevice);
+ if (NULL != queue) {
+ amdContext.removeDeviceQueue(amdDevice, queue);
+ queue->release();
+ }
+
+ amdContext.addDeviceQueue(amdDevice, deviceQueue, true);
+ deviceQueue->retain();
+ }
+#endif
+
+ return CL_INVALID_VALUE;
+}
+RUNTIME_EXIT
+
/*! \brief Increment the \a command_queue reference count.
*
* \return One of the following values:
diff --git a/projects/clr/opencl/api/opencl/amdocl/cl_context.cpp b/projects/clr/opencl/api/opencl/amdocl/cl_context.cpp
index 2148e4b2b1..b74e32b094 100644
--- a/projects/clr/opencl/api/opencl/amdocl/cl_context.cpp
+++ b/projects/clr/opencl/api/opencl/amdocl/cl_context.cpp
@@ -477,7 +477,7 @@ CL_API_ENTRY void* CL_API_CALL clGetExtensionFunctionAddress(const char* func_na
CL_EXTENSION_ENTRYPOINT_CHECK(clConvertImageAMD);
CL_EXTENSION_ENTRYPOINT_CHECK(clCreateBufferFromImageAMD);
#if defined(cl_khr_il_program) || defined(CL_VERSION_2_1)
- CL_EXTENSION_ENTRYPOINT_CHECK(clCreateProgramWithILKHR)
+ CL_EXTENSION_ENTRYPOINT_CHECK2(clCreateProgramWithILKHR,clCreateProgramWithIL);
#endif // defined(cl_khr_il_program) || defined(CL_VERSION_2_1)
#if cl_amd_liquid_flash
CL_EXTENSION_ENTRYPOINT_CHECK(clCreateSsgFileObjectAMD);
@@ -522,7 +522,7 @@ CL_API_ENTRY void* CL_API_CALL clGetExtensionFunctionAddress(const char* func_na
CL_EXTENSION_ENTRYPOINT_CHECK(clGetPlaneFromImageAMD);
#endif //_WIN32
#if defined(cl_khr_sub_groups) || defined(CL_VERSION_2_1)
- CL_EXTENSION_ENTRYPOINT_CHECK(clGetKernelSubGroupInfoKHR);
+ CL_EXTENSION_ENTRYPOINT_CHECK2(clGetKernelSubGroupInfoKHR,clGetKernelSubGroupInfo);
#endif // defined(cl_khr_sub_groups) || defined(CL_VERSION_2_1)
#if cl_amd_liquid_flash
CL_EXTENSION_ENTRYPOINT_CHECK(clGetSsgFileObjectInfoAMD);
diff --git a/projects/clr/opencl/api/opencl/amdocl/cl_execute.cpp b/projects/clr/opencl/api/opencl/amdocl/cl_execute.cpp
index 32488871f8..b6d1bf2de0 100644
--- a/projects/clr/opencl/api/opencl/amdocl/cl_execute.cpp
+++ b/projects/clr/opencl/api/opencl/amdocl/cl_execute.cpp
@@ -924,6 +924,100 @@ RUNTIME_ENTRY(cl_int, clGetEventProfilingInfo,
}
RUNTIME_EXIT
+/*! \brief Returns a reasonably synchronized pair of timestamps from the device
+ * timer and the host timer as seen by device.
+ *
+ * \param device a device returned by clGetDeviceIDs.
+ *
+ * \param device_timestamp will be updated with the value of the current timer
+ * in nanoseconds. The resolution of the timer is the same as the device
+ * profiling timer returned by clGetDeviceInfo and the
+ * CL_DEVICE_PROFILING_TIMER_RESOLUTION query.
+ *
+ * \param host_timestamp will be updated with the value of the current timer
+ * in nanoseconds at the closest possible point in time to that at which
+ * device_timer was returned. The resolution of the timer may be queried
+ * via clGetPlatformInfo and the flag CL_PLATFORM_HOST_TIMER_RESOLUTION.
+ *
+ * Returns a reasonably synchronized pair of timestamps from the device
+ * timer and the host timer as seen by device. Implementations may need
+ * to execute this query with a high latency in order to provide reasonable
+ * synchronization of the timestamps. The host timestamp and device timestamp
+ * returned by this function and clGetHostTimer each have an implementation
+ * defined timebase. The timestamps will always be in their respective timebases
+ * regardless of which query function is used. The timestamp returned from
+ * clGetEventProfilingInfo for an event on a device and a device timestamp
+ * queried from the same device will always be in the same timebase.
+ *
+ * \return One of the following values:
+ * - CL_SUCCESS if a time value in host_timestamp is provided
+ * - CL_INVALID_DEVICE if device is not a valid OpenCL device.
+ * - CL_INVALID_VALUE if host_timestamp is NULL.
+ * - CL_OUT_OF_RESOURCES if there is a failure to allocate resources required
+ * by the OpenCL implementation on the device.
+ * - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required
+ * by the OpenCL implementation on the host.
+ *
+ */
+RUNTIME_ENTRY(cl_int, clGetDeviceAndHostTimer,
+ (cl_device_id device, cl_ulong * device_timestamp,
+ cl_ulong * host_timestamp)) {
+
+ if (!is_valid(device)) {
+ return CL_INVALID_DEVICE;
+ }
+
+ // TODO: Implement get device and host timer logic
+ LogWarning("Device support for clGetDeviceAndHostTimer() has not been implemented.");
+
+ return CL_INVALID_VALUE;
+}
+RUNTIME_EXIT
+
+/*! \brief Return the current value of the host clock as seen by device.
+ *
+ * \param device a device returned by clGetDeviceIDs.
+ *
+ * \param host_timestamp will be updated with the value of the current timer
+ * in nanoseconds. The resolution of the timer may be queried via
+ * clGetPlatformInfo and the flag CL_PLATFORM_HOST_TIMER_RESOLUTION.
+ *
+ * Return the current value of the host clock as seen by device. This value
+ * is in the same timebase as the host_timestamp returned from
+ * clGetDeviceAndHostTimer. The implementation will return with as low a
+ * latency as possible to allow a correlation with a subsequent application
+ * sampled time. The host timestamp and device timestamp returned by this
+ * function and clGetDeviceAndHostTimer each have an implementation defined
+ * timebase. The timestamps will always be in their respective timebases
+ * regardless of which query function is used. The timestamp returned from
+ * clGetEventProfilingInfo for an event on a device and a device timestamp
+ * queried from the same device will always be in the same timebase.
+ *
+ * \return One of the following values:
+ *
+ * - CL_SUCCESS if a time value in host_timestamp is provided
+ * - CL_INVALID_DEVICE if device is not a valid OpenCL device.
+ * - CL_INVALID_VALUE if host_timestamp is NULL.
+ * - CL_OUT_OF_RESOURCES if there is a failure to allocate resources required
+ * by the OpenCL implementation on the device.
+ * - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required
+ * by the OpenCL implementation on the host.
+ *
+ */
+RUNTIME_ENTRY(cl_int, clGetHostTimer,
+ (cl_device_id device, cl_ulong * host_timestamp)) {
+
+ if (!is_valid(device)) {
+ return CL_INVALID_DEVICE;
+ }
+
+ // TODO: Implement get host timer logic
+ LogWarning("Device support for clGetHostTimer() has not been implemented.");
+
+ return CL_INVALID_VALUE;
+}
+RUNTIME_EXIT
+
/*! @}
* \addtogroup CL_FlushFinish Flush and Finish
* @{
diff --git a/projects/clr/opencl/api/opencl/amdocl/cl_icd.cpp b/projects/clr/opencl/api/opencl/amdocl/cl_icd.cpp
index 2174e7fdd0..bbf19f7d9e 100644
--- a/projects/clr/opencl/api/opencl/amdocl/cl_icd.cpp
+++ b/projects/clr/opencl/api/opencl/amdocl/cl_icd.cpp
@@ -99,8 +99,14 @@ KHRicdVendorDispatch amd::ICDDispatchedObject::icdVendorDispatch_[] = {
clCreateCommandQueueWithProperties, clCreatePipe, clGetPipeInfo, clSVMAlloc, clSVMFree,
clEnqueueSVMFree, clEnqueueSVMMemcpy, clEnqueueSVMMemFill, clEnqueueSVMMap, clEnqueueSVMUnmap,
clCreateSamplerWithProperties, clSetKernelArgSVMPointer, clSetKernelExecInfo,
-
- clGetKernelSubGroupInfoKHR}};
+ clGetKernelSubGroupInfo,
+ clCloneKernel,
+ clCreateProgramWithIL,
+ clEnqueueSVMMigrateMem,
+ clGetDeviceAndHostTimer,
+ clGetHostTimer,
+ clGetKernelSubGroupInfo,
+ clSetDefaultDeviceCommandQueue}};
#if defined(ATI_OS_WIN)
#include
diff --git a/projects/clr/opencl/api/opencl/amdocl/cl_icd_amd.h b/projects/clr/opencl/api/opencl/amdocl/cl_icd_amd.h
index 26a167652e..d5ce82349c 100644
--- a/projects/clr/opencl/api/opencl/amdocl/cl_icd_amd.h
+++ b/projects/clr/opencl/api/opencl/amdocl/cl_icd_amd.h
@@ -154,7 +154,7 @@ typedef cl_program(CL_API_CALL* clCreateProgramWithSource_fn)(
const size_t* /* lengths */, cl_int* /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0;
extern CL_API_ENTRY cl_program CL_API_CALL
-clCreateProgramWithILKHR(cl_context /* context */,
+clCreateProgramWithIL(cl_context /* context */,
const void * /* strings */, size_t /* lengths */,
cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_2_0;
diff --git a/projects/clr/opencl/api/opencl/amdocl/cl_program.cpp b/projects/clr/opencl/api/opencl/amdocl/cl_program.cpp
index 34fff72907..8a7229dc6e 100644
--- a/projects/clr/opencl/api/opencl/amdocl/cl_program.cpp
+++ b/projects/clr/opencl/api/opencl/amdocl/cl_program.cpp
@@ -184,7 +184,7 @@ RUNTIME_EXIT
*
* \version 1.0r33
*/
-RUNTIME_ENTRY_RET(cl_program, clCreateProgramWithILKHR,
+RUNTIME_ENTRY_RET(cl_program, clCreateProgramWithIL,
(cl_context context, const void* il, size_t length, cl_int* errcode_ret)) {
if (!is_valid(context)) {
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
@@ -1291,6 +1291,78 @@ RUNTIME_ENTRY(cl_int, clReleaseKernel, (cl_kernel kernel)) {
}
RUNTIME_EXIT
+/*! \brief Makes a shallow copy of the kernel object, its arguments and any
+ * information passed to the kernel object using \a clSetKernelExecInfo. If
+ * the kernel object was ready to be enqueued before copying it, the clone of
+ * the kernel object is ready to enqueue.
+ *
+ * \param source_kernel is a valid cl_kernel object that will be copied.
+ * source_kernel will not be modified in any way by this function.
+ *
+ * \param errcode_ret will be assigned an appropriate error code. If
+ * errcode_ret is NULL, no error code is returned.
+ *
+ * \return a valid non-zero kernel object and errcode_ret is set to
+ * CL_SUCCESS if the kernel is successfully copied. Otherwise it returns a
+ * NULL value with one of the following error values returned in errcode_ret:
+ * - CL_INVALID_KERNEL if kernel is not a valid kernel object.
+ * - CL_OUT_OF_RESOURCES if there is a failure to allocate resources required
+ * by the OpenCL implementation on the device.
+ * - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources
+ * required by the OpenCL implementation on the host.
+ *
+ * \version 2.1r01
+ */
+RUNTIME_ENTRY_RET(cl_kernel, clCloneKernel,
+ (cl_kernel source_kernel, cl_int* errcode_ret)) {
+ if (!is_valid(source_kernel)) {
+ *not_null(errcode_ret) = CL_INVALID_KERNEL;
+ return (cl_kernel)0;
+ }
+
+ amd::Kernel* srcKernel = as_amd(source_kernel);
+ amd::Program* program = &(srcKernel->program());
+ const char* kernelName = srcKernel->name().c_str();
+ const amd::Symbol* symbol = program->findSymbol(kernelName);
+ if (symbol == NULL) {
+ *not_null(errcode_ret) = CL_INVALID_KERNEL_NAME;
+ return (cl_kernel)0;
+ }
+
+ amd::Kernel* kernel = new amd::Kernel(*program, *symbol, kernelName);
+ if (kernel == NULL) {
+ *not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
+ return (cl_kernel)0;
+ }
+
+ //TODO: implemente the clone kernel logic
+ LogWarning("Device support for clCloneKernel() has not been implemented");
+
+#if 0
+ // clone kernel logic - unverified
+
+ // clone the parameter values_, defined_, svmBound_ arrays
+ amd::KernelParameters* srcParameters = &(srcKernel->parameters());
+ amd::KernelParameters* parameters = &(kernel->parameters());
+ const amd::KernelSignature& signature = kernel->signature();
+ size_t size = signature.paramsSize() + signature.numParameters() * sizeof(bool) * 2;
+ ::memcpy(parameters->values(), srcParameters->values(), size);
+
+ // clone the exec info
+ parameters->setExecInfoOffset(srcParameters->getExecInfoOffset());
+
+ parameters->addSvmPtr(srcParameters->getExecSvmPtr(), srcParameters->getNumberOfSvmPtr());
+ parameters->setSvmSystemPointersSupport(srcParameters->getSvmSystemPointersSupport());
+ parameters->setValidated(srcParameters->getValidated());
+ parameters->setExecNewVcop(srcParameters->getExecNewVcop());
+ parameters->setExecPfpaVcop(srcParameters->getExecPfpaVcop());
+#endif
+
+ *not_null(errcode_ret) = CL_INVALID_VALUE;
+ return as_cl(kernel);
+}
+RUNTIME_EXIT
+
/*! @}
* \addtogroup CL_SettingArgs
* @{
@@ -1662,7 +1734,7 @@ RUNTIME_EXIT
*
* \param param_name specifies the information to query. The list of supported
* param_name types and the information returned in param_value by
- * clGetKernelSubGroupInfoKHR is described in the table below.
+ * clGetKernelSubGroupInfo is described in the table below.
*
* \param input_value_size is used to specify the size in bytes of memory
* pointed to by input_value. This size must be == size of input type as
@@ -1702,7 +1774,7 @@ RUNTIME_EXIT
*
* \version 2.0r12
*/
-RUNTIME_ENTRY(cl_int, clGetKernelSubGroupInfoKHR,
+RUNTIME_ENTRY(cl_int, clGetKernelSubGroupInfo,
(cl_kernel kernel, cl_device_id device, cl_kernel_sub_group_info param_name,
size_t input_value_size, const void* input_value, size_t param_value_size,
void* param_value, size_t* param_value_size_ret)) {
@@ -1756,6 +1828,12 @@ RUNTIME_ENTRY(cl_int, clGetKernelSubGroupInfoKHR,
: numSubGroups,
param_value_size, param_value, param_value_size_ret);
}
+ case CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT:
+ case CL_KERNEL_MAX_NUM_SUB_GROUPS:
+ case CL_KERNEL_COMPILE_NUM_SUB_GROUPS:
+ //TODO: implemente the kernel subgroup info query
+ LogWarning("Device support for clGetKernelSubGroupInfo() query has not been implemented.");
+ return CL_INVALID_VALUE;
default:
return CL_INVALID_VALUE;
}
diff --git a/projects/clr/opencl/api/opencl/amdocl/cl_svm.cpp b/projects/clr/opencl/api/opencl/amdocl/cl_svm.cpp
index a602c736d8..3416beeb92 100644
--- a/projects/clr/opencl/api/opencl/amdocl/cl_svm.cpp
+++ b/projects/clr/opencl/api/opencl/amdocl/cl_svm.cpp
@@ -1036,6 +1036,172 @@ RUNTIME_ENTRY(cl_int, clSetKernelExecInfo, (cl_kernel kernel, cl_kernel_exec_inf
}
RUNTIME_EXIT
+/*! \brief Enqueues a command to indicate which device a set of ranges of SVM
+ * allocations should be associated with. Once the event returned by
+ * \a clEnqueueSVMMigrateMem has become CL_COMPLETE, the ranges specified by
+ * svm pointers and sizes have been successfully migrated to the device
+ * associated with command queue.
+ * The user is responsible for managing the event dependencies associated with
+ * this command in order to avoid overlapping access to SVM allocations.
+ * Improperly specified event dependencies passed to clEnqueueSVMMigrateMem
+ * could result in undefined results
+ *
+ * \param command_queue is a valid host command queue. The specified set of
+ * allocation ranges will be migrated to the OpenCL device associated with
+ * command_queue.
+ *
+ * \param num_svm_pointers is the number of pointers in the specified
+ * svm_pointers array, and the number of sizes in the sizes array, if sizes
+ * is not NULL.
+ *
+ * \param svm_pointers is a pointer to an array of pointers. Each pointer in
+ * this array must be within an allocation produced by a call to clSVMAlloc.
+ *
+ * \param sizes is an array of sizes. The pair svm_pointers[i] and sizes[i]
+ * together define the starting address and number of bytes in a range to be
+ * migrated. sizes may be NULL indicating that every allocation containing
+ * any svm_pointer[i] is to be migrated. Also, if sizes[i] is zero, then the
+ * entire allocation containing svm_pointer[i] is migrated.
+ *
+ * \param flags is a bit-field that is used to specify migration options.
+ * Table 5.12 describes the possible values for flags.
+ *
+ * \param num_events_in_wait_list specifies the number of event objects in
+ * \a event_wait_list.
+ *
+ * \param event_wait_list specifies events that need to complete before this
+ * particular command can be executed. If event_wait_list is NULL, then this
+ * particular command does not wait on any event to complete. If
+ * event_wait_list is NULL, num_events_in_wait_list must be 0. If
+ * event_wait_list is not NULL, the list of events pointed to by
+ * event_wait_list must be valid and num_events_in_wait_list must be greater
+ * than 0. The events specified in event_wait_list act as synchronization
+ * points. The context associated with events in event_wait_list and
+ * command_queue must be the same. The memory associated with
+ * event_wait_list can be reused or freed after the function returns.
+ *
+ * \param event an returned event object that identifies this particular write
+ * command and can be used to query or queue a wait for this particular
+ * command to complete. event can be NULL in which case it will not be
+ * possible for the application to query the status of this command or queue
+ * another command that waits for this command to complete. If the
+ * event_wait_list and the event arguments are not NULL, the event argument
+ * should not refer to an element of the event_wait_list array.
+ *
+ * \return One of the following values:
+ * - CL_SUCCESS if the function is executed successfully
+ * - CL_INVALID_COMMAND_QUEUE if \a command_queue is not a valid command-queue
+ * - CL_INVALID_VALUE if num_svm_pointers is zero or svm_pointers is NULL
+ * - CL_INVALID_VALUE if sizes[i] is non-zero range [svm_pointers[i],
+ * svm_pointers[i]+sizes[i]) is not contained within an existing clSVMAlloc
+ * allocation
+ * - CL_INVALID_EVENT_WAIT_LIST if event_wait_list is NULL and
+ * num_events_in_wait_list > 0, or event_wait_list is not NULL and
+ * num_events_in_wait_list is 0, or if event objects in event_wait_list are
+ * not valid events
+ * - CL_OUT_OF_RESOURCES if there is a failure to allocate resources required
+ * by the OpenCL implementation on the device.
+ * - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required
+ * by the OpenCL implementation on the host.
+ *
+ * \version 2.1r00
+ */
+RUNTIME_ENTRY(cl_int, clEnqueueSVMMigrateMem,
+ (cl_command_queue command_queue, cl_uint num_svm_pointers, const void **svm_pointers,
+ const size_t *size, cl_mem_migration_flags flags, cl_uint num_events_in_wait_list,
+ const cl_event* event_wait_list, cl_event* event)) {
+
+ if (!is_valid(command_queue)) {
+ return CL_INVALID_COMMAND_QUEUE;
+ }
+
+ amd::HostQueue* queue = as_amd(command_queue)->asHostQueue();
+ if (NULL == queue) {
+ return CL_INVALID_COMMAND_QUEUE;
+ }
+ amd::HostQueue& hostQueue = *queue;
+
+ if (num_svm_pointers == 0) {
+ LogWarning("invalid parameter \"num_svm_pointers = 0\"");
+ return CL_INVALID_VALUE;
+ }
+
+ if (svm_pointers == NULL) {
+ LogWarning("invalid parameter \"svm_pointers = NULL\"");
+ return CL_INVALID_VALUE;
+ }
+
+ for (cl_uint i = 0; i < num_svm_pointers; i++) {
+ if (svm_pointers[i] == NULL) {
+ LogWarning("Null pointers are not allowed");
+ return CL_INVALID_VALUE;
+ }
+ }
+
+ if (flags & ~(CL_MIGRATE_MEM_OBJECT_HOST | CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED)) {
+ LogWarning("Invalid flag is specified");
+ return CL_INVALID_VALUE;
+ }
+
+ //TODO: implemente the svm migration memory logic
+ LogWarning("Device support for clEnqueueSVMMigrateMem() has not been implemented");
+
+#if 0
+ // implementation of the svm migration memory logic - unverified
+
+ for (int i = 0; i < num_svm_pointers; i++) {
+ const void* svm_ptr = svm_pointers[i];
+
+ amd::Memory* svmMem = amd::SvmManager::FindSvmBuffer(svm_ptr);
+ if (NULL != svmMem) {
+ // make sure the context is the same as the context of creation of svm space
+ if (hostQueue.context() != svmMem->getContext()) {
+ LogWarning("different contexts");
+ return CL_INVALID_CONTEXT;
+ }
+
+ // Make sure the specified size[i] is within a valid range
+ size_t svm_size = (size == NULL) ? 0 : size[i];
+ size_t offset = reinterpret_cast(svm_ptr) - reinterpret_cast(svmMem->getSvmPtr());
+ if (offset < 0 || (offset + svm_size) > svmMem->getSize()) {
+ LogWarning("wrong svm address ");
+ return CL_INVALID_VALUE;
+ }
+
+ // Make sure we have memory for the command execution
+ device::Memory* mem = svmMem->getDeviceMemory(queue->device());
+ if (NULL == mem) {
+ LogPrintfError("Can't allocate memory size - 0x%08X bytes!", svmMem->getSize());
+ return CL_OUT_OF_RESOURCES;
+ }
+ }
+ }
+
+ amd::Command::EventWaitList eventWaitList;
+ cl_int err = amd::clSetEventWaitList(eventWaitList, hostQueue.context(), num_events_in_wait_list,
+ event_wait_list);
+ if (err != CL_SUCCESS) {
+ return err;
+ }
+
+ amd::Command* command = new amd::SvmMigrateMemCommand(hostQueue, eventWaitList, num_svm_pointers,
+ svm_pointers, size, flags);
+
+ if (command == NULL) {
+ return CL_OUT_OF_HOST_MEMORY;
+ }
+
+ command->enqueue();
+
+ *not_null(event) = as_cl(&command->event());
+ if (event == NULL) {
+ command->release();
+ }
+#endif
+
+ return CL_INVALID_VALUE;
+}
+RUNTIME_EXIT
/*! @}
* @}
*/
diff --git a/projects/clr/opencl/api/opencl/khronos/headers/opencl2.1/CL/cl.h b/projects/clr/opencl/api/opencl/khronos/headers/opencl2.1/CL/cl.h
index 4dab53a935..706e944545 100644
--- a/projects/clr/opencl/api/opencl/khronos/headers/opencl2.1/CL/cl.h
+++ b/projects/clr/opencl/api/opencl/khronos/headers/opencl2.1/CL/cl.h
@@ -637,6 +637,7 @@ typedef struct _cl_buffer_region {
#define CL_COMMAND_SVM_MEMFILL 0x120B
#define CL_COMMAND_SVM_MAP 0x120C
#define CL_COMMAND_SVM_UNMAP 0x120D
+#define CL_COMMAND_SVM_MIGRATE_MEM 0x120E
/* command execution status */
#define CL_COMPLETE 0x0
diff --git a/projects/clr/opencl/api/opencl/khronos/headers/opencl2.2/CL/cl.h b/projects/clr/opencl/api/opencl/khronos/headers/opencl2.2/CL/cl.h
index 1e164eb839..43ac8ab1ea 100644
--- a/projects/clr/opencl/api/opencl/khronos/headers/opencl2.2/CL/cl.h
+++ b/projects/clr/opencl/api/opencl/khronos/headers/opencl2.2/CL/cl.h
@@ -642,6 +642,7 @@ typedef struct _cl_buffer_region {
#define CL_COMMAND_SVM_MEMFILL 0x120B
#define CL_COMMAND_SVM_MAP 0x120C
#define CL_COMMAND_SVM_UNMAP 0x120D
+#define CL_COMMAND_SVM_MIGRATE_MEM 0x120E
/* command execution status */
#define CL_COMPLETE 0x0