Merge branch 'origin/pghafari/opencl' into lmoriche/amd-master-next
[ROCm/clr commit: d4c39b88c5]
This commit is contained in:
@@ -0,0 +1,404 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "cl_common.hpp"
|
||||
|
||||
#include "platform/object.hpp"
|
||||
#include "platform/context.hpp"
|
||||
#include "platform/command.hpp"
|
||||
#include "platform/agent.hpp"
|
||||
|
||||
/*! \addtogroup API
|
||||
* @{
|
||||
*
|
||||
* \addtogroup CL_Queues
|
||||
*
|
||||
* OpenCL objects such as memory objects, program and kernel objects are
|
||||
* created using a context. Operations on these objects are performed using
|
||||
* a command-queue. The command-queue can be used to queue a set of operations
|
||||
* (referred to as commands) in order. Having multiple command-queues allows
|
||||
* applications to queue multiple independent commands without requiring
|
||||
* synchronization. Note that this should work as long as these objects are
|
||||
* not being shared. Sharing of objects across multiple command-queues will
|
||||
* require the application to perform appropriate synchronization.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \brief Create a command-queue on a specific device.
|
||||
*
|
||||
* \param context must be a valid OpenCL context.
|
||||
*
|
||||
* \param device must be a device associated with context. It can either be
|
||||
* in the list of devices specified when context is created using
|
||||
* clCreateContext or have the same device type as device type specified wheni
|
||||
* context is created using clCreateContextFromType.
|
||||
*
|
||||
* \param properties specifies a list of properties for the command-queue.
|
||||
*
|
||||
* \param errcode_ret will return an appropriate error code. If \a errcode_ret
|
||||
* is NULL, no error code is returned.
|
||||
*
|
||||
* \return A valid non-zero command-queue and \a errcode_ret is set to
|
||||
* CL_SUCCESS if the command-queue is created successfully or a NULL value
|
||||
* with one of the following error values returned \a in errcode_ret:
|
||||
* - CL_INVALID_CONTEXT if context is not a valid.
|
||||
* - CL_INVALID_DEVICE if device is not a valid device or is not associated
|
||||
* with context
|
||||
* - CL_INVALID_VALUE if values specified in properties are not valid.
|
||||
* - CL_INVALID_QUEUE_PROPERTIES if values specified in properties are valid
|
||||
* but are not supported by the device.
|
||||
* - CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources
|
||||
* required by the runtime.
|
||||
*
|
||||
* \version 1.0r33
|
||||
*/
|
||||
RUNTIME_ENTRY_RET(cl_command_queue, clCreateCommandQueueWithProperties,
|
||||
(cl_context context, cl_device_id device,
|
||||
const cl_queue_properties* queue_properties, cl_int* errcode_ret)) {
|
||||
if (!is_valid(context)) {
|
||||
*not_null(errcode_ret) = CL_INVALID_CONTEXT;
|
||||
return (cl_command_queue)0;
|
||||
}
|
||||
|
||||
amd::Context& amdContext = *as_amd(context);
|
||||
amd::Device& amdDevice = *as_amd(device);
|
||||
|
||||
if (!is_valid(device) || !amdContext.containsDevice(&amdDevice)) {
|
||||
*not_null(errcode_ret) = CL_INVALID_DEVICE;
|
||||
return (cl_command_queue)0;
|
||||
}
|
||||
|
||||
cl_command_queue_properties properties = 0;
|
||||
const struct QueueProperty {
|
||||
cl_queue_properties name;
|
||||
union {
|
||||
cl_queue_properties raw;
|
||||
// FIXME_lmoriche: Check with Khronos. cl_queue_properties is an intptr,
|
||||
// but cl_command_queue_properties is a bitfield (truncate?).
|
||||
// cl_command_queue_properties properties;
|
||||
cl_uint size;
|
||||
} value;
|
||||
}* p = reinterpret_cast<const QueueProperty*>(queue_properties);
|
||||
|
||||
uint queueSize = amdDevice.info().queueOnDevicePreferredSize_;
|
||||
uint queueRTCUs = amd::CommandQueue::RealTimeDisabled;
|
||||
amd::CommandQueue::Priority priority = amd::CommandQueue::Priority::Normal;
|
||||
if (p != NULL)
|
||||
while (p->name != 0) {
|
||||
switch (p->name) {
|
||||
case CL_QUEUE_PROPERTIES:
|
||||
// FIXME_lmoriche: See comment above.
|
||||
// properties = p->value.properties;
|
||||
properties = static_cast<cl_command_queue_properties>(p->value.raw);
|
||||
break;
|
||||
case CL_QUEUE_SIZE:
|
||||
queueSize = p->value.size;
|
||||
break;
|
||||
#define CL_QUEUE_REAL_TIME_COMPUTE_UNITS_AMD 0x404f
|
||||
case CL_QUEUE_REAL_TIME_COMPUTE_UNITS_AMD:
|
||||
queueRTCUs = p->value.size;
|
||||
break;
|
||||
#define CL_QUEUE_MEDIUM_PRIORITY_AMD 0x4050
|
||||
case CL_QUEUE_MEDIUM_PRIORITY_AMD:
|
||||
priority = amd::CommandQueue::Priority::Medium;
|
||||
if (p->value.size != 0) {
|
||||
queueRTCUs = p->value.size;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*not_null(errcode_ret) = CL_INVALID_QUEUE_PROPERTIES;
|
||||
LogWarning("invalid property name");
|
||||
return (cl_command_queue)0;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
|
||||
if (queueSize > amdDevice.info().queueOnDeviceMaxSize_) {
|
||||
*not_null(errcode_ret) = CL_INVALID_VALUE;
|
||||
return (cl_command_queue)0;
|
||||
}
|
||||
|
||||
if ((queueRTCUs != amd::CommandQueue::RealTimeDisabled) &&
|
||||
((queueRTCUs > amdDevice.info().numRTCUs_) || (queueRTCUs == 0))) {
|
||||
*not_null(errcode_ret) = CL_INVALID_VALUE;
|
||||
return (cl_command_queue)0;
|
||||
}
|
||||
|
||||
amd::CommandQueue* queue = NULL;
|
||||
{
|
||||
amd::ScopedLock lock(amdContext.lock());
|
||||
|
||||
// Check if the app creates a host queue
|
||||
if (!(properties & CL_QUEUE_ON_DEVICE)) {
|
||||
queue = new amd::HostQueue(amdContext, amdDevice, properties, queueRTCUs, priority);
|
||||
} else {
|
||||
// Is it a device default queue
|
||||
if (properties & CL_QUEUE_ON_DEVICE_DEFAULT) {
|
||||
queue = amdContext.defDeviceQueue(amdDevice);
|
||||
// If current context has one already then return it
|
||||
if (NULL != queue) {
|
||||
queue->retain();
|
||||
*not_null(errcode_ret) = CL_SUCCESS;
|
||||
return as_cl(queue);
|
||||
}
|
||||
}
|
||||
// Check if runtime can allocate a new device queue on this context
|
||||
if (amdContext.isDevQueuePossible(amdDevice)) {
|
||||
queue = new amd::DeviceQueue(amdContext, amdDevice, properties, queueSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (queue == NULL || !queue->create()) {
|
||||
*not_null(errcode_ret) = CL_OUT_OF_HOST_MEMORY;
|
||||
delete queue;
|
||||
return (cl_command_queue)0;
|
||||
}
|
||||
}
|
||||
|
||||
if (amd::Agent::shouldPostCommandQueueEvents()) {
|
||||
amd::Agent::postCommandQueueCreate(as_cl(queue->asCommandQueue()));
|
||||
}
|
||||
|
||||
*not_null(errcode_ret) = CL_SUCCESS;
|
||||
return as_cl(queue);
|
||||
}
|
||||
RUNTIME_EXIT
|
||||
|
||||
RUNTIME_ENTRY_RET(cl_command_queue, clCreateCommandQueue,
|
||||
(cl_context context, cl_device_id device, cl_command_queue_properties properties,
|
||||
cl_int* errcode_ret)) {
|
||||
const cl_queue_properties cprops[] = {CL_QUEUE_PROPERTIES,
|
||||
static_cast<cl_queue_properties>(properties), 0};
|
||||
return clCreateCommandQueueWithProperties(context, device, properties ? cprops : NULL,
|
||||
errcode_ret);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (!is_valid(command_queue)) {
|
||||
return CL_INVALID_COMMAND_QUEUE;
|
||||
}
|
||||
|
||||
amd::Context* amdContext = as_amd(context);
|
||||
amd::Device* amdDevice = as_amd(device);
|
||||
if (!is_valid(device) || !amdContext->containsDevice(amdDevice)) {
|
||||
return CL_INVALID_DEVICE;
|
||||
}
|
||||
|
||||
amd::DeviceQueue* deviceQueue = as_amd(command_queue)->asDeviceQueue();
|
||||
if ((deviceQueue == NULL) || (amdContext != &deviceQueue->context()) ||
|
||||
(amdDevice != &deviceQueue->device())) {
|
||||
return CL_INVALID_COMMAND_QUEUE;
|
||||
}
|
||||
|
||||
{
|
||||
amd::ScopedLock lock(amdContext->lock());
|
||||
amdContext->setDefDeviceQueue(*amdDevice, deviceQueue);
|
||||
}
|
||||
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
RUNTIME_EXIT
|
||||
|
||||
/*! \brief Increment the \a command_queue reference count.
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* clCreateCommandQueue performs an implicit retain. This is very helpful for
|
||||
* 3rd party libraries, which typically get a command-queue passed to them
|
||||
* by the application. However, it is possible that the application may delete
|
||||
* the command-queue without informing the library. Allowing functions to
|
||||
* attach to (i.e. retain) and release a command-queue solves the problem of a
|
||||
* command-queue being used by a library no longer being valid.
|
||||
*
|
||||
* \version 1.0r33
|
||||
*/
|
||||
RUNTIME_ENTRY(cl_int, clRetainCommandQueue, (cl_command_queue command_queue)) {
|
||||
if (!is_valid(command_queue)) {
|
||||
return CL_INVALID_COMMAND_QUEUE;
|
||||
}
|
||||
as_amd(command_queue)->retain();
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
RUNTIME_EXIT
|
||||
|
||||
/*! \brief Decrement the \a command_queue reference count.
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* After the command_queue reference count becomes zero and all commands queued
|
||||
* to \a command_queue have finished (eg. kernel executions, memory object
|
||||
* updates etc.), the command-queue is deleted.
|
||||
*
|
||||
* \version 1.0r33
|
||||
*/
|
||||
RUNTIME_ENTRY(cl_int, clReleaseCommandQueue, (cl_command_queue command_queue)) {
|
||||
if (!is_valid(command_queue)) {
|
||||
return CL_INVALID_COMMAND_QUEUE;
|
||||
}
|
||||
as_amd(command_queue)->release();
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
RUNTIME_EXIT
|
||||
|
||||
/*! \brief Query information about a command-queue.
|
||||
*
|
||||
* \param command_queue specifies the command-queue being queried.
|
||||
*
|
||||
* \param param_name specifies the information to query.
|
||||
*
|
||||
* \param param_value is a pointer to memory where the appropriate result
|
||||
* being queried is returned. If \a param_value is NULL, it is ignored.
|
||||
*
|
||||
* \param param_value_size is used to specify the size in bytes of memory
|
||||
* pointed to by \a param_value. This size must be >= size of return type.
|
||||
* If param_value is NULL, it is ignored.
|
||||
*
|
||||
* \param param_value_size_ret returns the actual size in bytes of data being
|
||||
* queried by \a param_value. If \a param_value_size_ret is NULL,
|
||||
* it is ignored.
|
||||
*
|
||||
* \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 \a param_name is not one of the supported
|
||||
* values or if size in bytes specified by \a param_value_size is < size of
|
||||
* return type and \a param_value is not a NULL value.
|
||||
*
|
||||
* \version 1.0r33
|
||||
*/
|
||||
RUNTIME_ENTRY(cl_int, clGetCommandQueueInfo,
|
||||
(cl_command_queue command_queue, cl_command_queue_info param_name,
|
||||
size_t param_value_size, void* param_value, size_t* param_value_size_ret)) {
|
||||
if (!is_valid(command_queue)) {
|
||||
return CL_INVALID_COMMAND_QUEUE;
|
||||
}
|
||||
|
||||
switch (param_name) {
|
||||
case CL_QUEUE_CONTEXT: {
|
||||
cl_context context = const_cast<cl_context>(as_cl(&as_amd(command_queue)->context()));
|
||||
return amd::clGetInfo(context, param_value_size, param_value, param_value_size_ret);
|
||||
}
|
||||
case CL_QUEUE_DEVICE: {
|
||||
cl_device_id device = const_cast<cl_device_id>(as_cl(&as_amd(command_queue)->device()));
|
||||
return amd::clGetInfo(device, param_value_size, param_value, param_value_size_ret);
|
||||
}
|
||||
case CL_QUEUE_PROPERTIES: {
|
||||
cl_command_queue_properties properties = as_amd(command_queue)->properties().value_;
|
||||
return amd::clGetInfo(properties, param_value_size, param_value, param_value_size_ret);
|
||||
}
|
||||
case CL_QUEUE_REFERENCE_COUNT: {
|
||||
cl_uint count = as_amd(command_queue)->referenceCount();
|
||||
return amd::clGetInfo(count, param_value_size, param_value, param_value_size_ret);
|
||||
}
|
||||
case CL_QUEUE_SIZE: {
|
||||
const amd::DeviceQueue* deviceQueue = as_amd(command_queue)->asDeviceQueue();
|
||||
if (NULL == deviceQueue) {
|
||||
return CL_INVALID_COMMAND_QUEUE;
|
||||
}
|
||||
cl_uint size = deviceQueue->size();
|
||||
return amd::clGetInfo(size, param_value_size, param_value, param_value_size_ret);
|
||||
}
|
||||
case CL_QUEUE_THREAD_HANDLE_AMD: {
|
||||
const amd::HostQueue* hostQueue = as_amd(command_queue)->asHostQueue();
|
||||
if (NULL == hostQueue) {
|
||||
return CL_INVALID_COMMAND_QUEUE;
|
||||
}
|
||||
const void* handle = hostQueue->thread().handle();
|
||||
return amd::clGetInfo(handle, param_value_size, param_value, param_value_size_ret);
|
||||
}
|
||||
case CL_QUEUE_DEVICE_DEFAULT: {
|
||||
const amd::Device& device = as_amd(command_queue)->device();
|
||||
amd::CommandQueue* defQueue = as_amd(command_queue)->context().defDeviceQueue(device);
|
||||
cl_command_queue queue = defQueue ? as_cl(defQueue) : NULL;
|
||||
return amd::clGetInfo(queue, param_value_size, param_value, param_value_size_ret);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CL_INVALID_VALUE;
|
||||
}
|
||||
RUNTIME_EXIT
|
||||
|
||||
/*! \brief Enable or disable the properties of a command-queue.
|
||||
*
|
||||
* \param command_queue specifies the command-queue being queried.
|
||||
*
|
||||
* \param properties specifies the new command-queue properties to be applied
|
||||
* to \a command_queue .
|
||||
*
|
||||
* \param enable determines whether the values specified by properties are
|
||||
* enabled (if enable is CL_TRUE) or disabled (if enable is CL_FALSE) for the
|
||||
* command-queue .
|
||||
*
|
||||
* \param old_properties returns the command-queue properties before they were
|
||||
* changed by clSetCommandQueueProperty. If \a old_properties is NULL,
|
||||
* it is ignored.
|
||||
*
|
||||
* \return One of the following values:
|
||||
* - CL_SUCCESS if the command-queue properties are successfully updated.
|
||||
* - CL_INVALID_COMMAND_QUEUE if command_queue is not a valid command-queue.
|
||||
* - CL_INVALID_VALUE if the values specified in properties are not valid.
|
||||
* - CL_INVALID_QUEUE_PROPERTIES if values specified in properties are
|
||||
* not supported by the device.
|
||||
*
|
||||
* \version 1.0r33
|
||||
*/
|
||||
RUNTIME_ENTRY(cl_int, clSetCommandQueueProperty,
|
||||
(cl_command_queue command_queue, cl_command_queue_properties properties,
|
||||
cl_bool enable, cl_command_queue_properties* old_properties)) {
|
||||
if (!is_valid(command_queue)) {
|
||||
return CL_INVALID_COMMAND_QUEUE;
|
||||
}
|
||||
|
||||
*not_null(old_properties) = as_amd(command_queue)->properties().value_;
|
||||
|
||||
if (properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) {
|
||||
clFinish(command_queue);
|
||||
}
|
||||
|
||||
bool success;
|
||||
if (enable == CL_TRUE) {
|
||||
success = as_amd(command_queue)->properties().set(properties);
|
||||
} else {
|
||||
success = as_amd(command_queue)->properties().clear(properties);
|
||||
}
|
||||
|
||||
return success ? CL_SUCCESS : CL_INVALID_QUEUE_PROPERTIES;
|
||||
}
|
||||
RUNTIME_EXIT
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
Reference in New Issue
Block a user