3648 lines
130 KiB
C++
3648 lines
130 KiB
C++
//
|
|
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
// validationCL.cpp: Validation functions for generic CL entry point parameters
|
|
// based on the OpenCL Specification V3.0.7, see https://www.khronos.org/registry/OpenCL/
|
|
// Each used CL error code is preceeded by a citation of the relevant rule in the spec.
|
|
|
|
#include "libANGLE/validationCL_autogen.h"
|
|
|
|
#include "libANGLE/cl_utils.h"
|
|
|
|
#define ANGLE_VALIDATE_VERSION(version, major, minor) \
|
|
do \
|
|
{ \
|
|
if (version < CL_MAKE_VERSION(major##u, minor##u, 0u)) \
|
|
{ \
|
|
return CL_INVALID_VALUE; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define ANGLE_VALIDATE_EXTENSION(extension) \
|
|
do \
|
|
{ \
|
|
if (!extension) \
|
|
{ \
|
|
return CL_INVALID_VALUE; \
|
|
} \
|
|
} while (0)
|
|
|
|
namespace cl
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
cl_int ValidateContextProperties(const cl_context_properties *properties, const Platform *&platform)
|
|
{
|
|
platform = nullptr;
|
|
bool hasUserSync = false;
|
|
if (properties != nullptr)
|
|
{
|
|
while (*properties != 0)
|
|
{
|
|
switch (*properties++)
|
|
{
|
|
case CL_CONTEXT_PLATFORM:
|
|
{
|
|
// CL_INVALID_PROPERTY if the same property name is specified more than once.
|
|
if (platform != nullptr)
|
|
{
|
|
return CL_INVALID_PROPERTY;
|
|
}
|
|
cl_platform_id nativePlatform = reinterpret_cast<cl_platform_id>(*properties++);
|
|
// CL_INVALID_PLATFORM if platform value specified in properties
|
|
// is not a valid platform.
|
|
if (!Platform::IsValid(nativePlatform))
|
|
{
|
|
return CL_INVALID_PLATFORM;
|
|
}
|
|
platform = &nativePlatform->cast<Platform>();
|
|
break;
|
|
}
|
|
case CL_CONTEXT_INTEROP_USER_SYNC:
|
|
{
|
|
// CL_INVALID_PROPERTY if the value specified for a supported property name
|
|
// is not valid, or if the same property name is specified more than once.
|
|
if ((*properties != CL_FALSE && *properties != CL_TRUE) || hasUserSync)
|
|
{
|
|
return CL_INVALID_PROPERTY;
|
|
}
|
|
++properties;
|
|
hasUserSync = true;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
// CL_INVALID_PROPERTY if context property name in properties
|
|
// is not a supported property name.
|
|
return CL_INVALID_PROPERTY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (platform == nullptr)
|
|
{
|
|
platform = Platform::GetDefault();
|
|
// CL_INVALID_PLATFORM if properties is NULL and no platform could be selected.
|
|
if (platform == nullptr)
|
|
{
|
|
return CL_INVALID_PLATFORM;
|
|
}
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
bool ValidateMemoryFlags(MemFlags flags, const Platform &platform)
|
|
{
|
|
// CL_MEM_READ_WRITE, CL_MEM_WRITE_ONLY, and CL_MEM_READ_ONLY are mutually exclusive.
|
|
MemFlags allowedFlags(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY);
|
|
if (!flags.areMutuallyExclusive(CL_MEM_READ_WRITE, CL_MEM_WRITE_ONLY, CL_MEM_READ_ONLY))
|
|
{
|
|
return false;
|
|
}
|
|
// CL_MEM_USE_HOST_PTR is mutually exclusive with either of the other two flags.
|
|
allowedFlags.set(CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR);
|
|
if (!flags.areMutuallyExclusive(CL_MEM_USE_HOST_PTR,
|
|
CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR))
|
|
{
|
|
return false;
|
|
}
|
|
if (platform.isVersionOrNewer(1u, 2u))
|
|
{
|
|
// CL_MEM_HOST_WRITE_ONLY, CL_MEM_HOST_READ_ONLY,
|
|
// and CL_MEM_HOST_NO_ACCESS are mutually exclusive.
|
|
allowedFlags.set(CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS);
|
|
if (!flags.areMutuallyExclusive(CL_MEM_HOST_WRITE_ONLY, CL_MEM_HOST_READ_ONLY,
|
|
CL_MEM_HOST_NO_ACCESS))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if (platform.isVersionOrNewer(2u, 0u))
|
|
{
|
|
allowedFlags.set(CL_MEM_KERNEL_READ_AND_WRITE);
|
|
}
|
|
if (flags.hasOtherBitsThan(allowedFlags))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ValidateMapFlags(MapFlags flags, const Platform &platform)
|
|
{
|
|
MemFlags allowedFlags(CL_MAP_READ | CL_MAP_WRITE);
|
|
if (platform.isVersionOrNewer(1u, 2u))
|
|
{
|
|
// CL_MAP_READ or CL_MAP_WRITE and CL_MAP_WRITE_INVALIDATE_REGION are mutually exclusive.
|
|
allowedFlags.set(CL_MAP_WRITE_INVALIDATE_REGION);
|
|
if (!flags.areMutuallyExclusive(CL_MAP_WRITE_INVALIDATE_REGION, CL_MAP_READ | CL_MAP_WRITE))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if (flags.hasOtherBitsThan(allowedFlags))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ValidateMemoryProperties(const cl_mem_properties *properties)
|
|
{
|
|
if (properties != nullptr)
|
|
{
|
|
// OpenCL 3.0 does not define any optional properties.
|
|
// This function is reserved for extensions and future use.
|
|
if (*properties != 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
cl_int ValidateCommandQueueAndEventWaitList(cl_command_queue commandQueue,
|
|
bool validateImageSupport,
|
|
cl_uint numEvents,
|
|
const cl_event *events)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
|
|
if (!CommandQueue::IsValid(commandQueue))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
const CommandQueue &queue = commandQueue->cast<CommandQueue>();
|
|
if (!queue.isOnHost())
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
if (validateImageSupport)
|
|
{
|
|
// CL_INVALID_OPERATION if the device associated with command_queue does not support images.
|
|
if (queue.getDevice().getInfo().imageSupport == CL_FALSE)
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
}
|
|
|
|
// 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, ...
|
|
if ((events == nullptr) != (numEvents == 0u))
|
|
{
|
|
return CL_INVALID_EVENT_WAIT_LIST;
|
|
}
|
|
while (numEvents-- != 0u)
|
|
{
|
|
// or if event objects in event_wait_list are not valid events.
|
|
if (!Event::IsValid(*events))
|
|
{
|
|
return CL_INVALID_EVENT_WAIT_LIST;
|
|
}
|
|
|
|
// CL_INVALID_CONTEXT if the context associated with command_queue
|
|
// and events in event_wait_list are not the same.
|
|
if (&queue.getContext() != &(*events++)->cast<Event>().getContext())
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueBuffer(const CommandQueue &queue,
|
|
cl_mem buffer,
|
|
bool hostRead,
|
|
bool hostWrite)
|
|
{
|
|
// CL_INVALID_MEM_OBJECT if buffer is not a valid buffer object.
|
|
if (!Buffer::IsValid(buffer))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
const Buffer &buf = buffer->cast<Buffer>();
|
|
|
|
// CL_INVALID_CONTEXT if the context associated with command_queue and buffer are not the same.
|
|
if (&queue.getContext() != &buf.getContext())
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_MISALIGNED_SUB_BUFFER_OFFSET if buffer is a sub-buffer object and offset specified
|
|
// when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN
|
|
// value (which is in bits!) for device associated with queue.
|
|
if (buf.isSubBuffer() &&
|
|
(buf.getOffset() % (queue.getDevice().getInfo().memBaseAddrAlign / 8u)) != 0u)
|
|
{
|
|
return CL_MISALIGNED_SUB_BUFFER_OFFSET;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if a read function is called on buffer which
|
|
// has been created with CL_MEM_HOST_WRITE_ONLY or CL_MEM_HOST_NO_ACCESS.
|
|
if (hostRead && buf.getFlags().isSet(CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS))
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if a write function is called on buffer which
|
|
// has been created with CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_NO_ACCESS.
|
|
if (hostWrite && buf.getFlags().isSet(CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS))
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateBufferRect(const Buffer &buffer,
|
|
const size_t *origin,
|
|
const size_t *region,
|
|
size_t rowPitch,
|
|
size_t slicePitch)
|
|
{
|
|
// CL_INVALID_VALUE if origin or region is NULL.
|
|
if (origin == nullptr || region == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if any region array element is 0.
|
|
if (region[0] == 0u || region[1] == 0u || region[2] == 0u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if row_pitch is not 0 and is less than region[0].
|
|
if (rowPitch == 0u)
|
|
{
|
|
rowPitch = region[0];
|
|
}
|
|
else if (rowPitch < region[0])
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if slice_pitch is not 0 and is less than
|
|
// region[1] x row_pitch and not a multiple of row_pitch.
|
|
if (slicePitch == 0u)
|
|
{
|
|
slicePitch = region[1] * rowPitch;
|
|
}
|
|
else if (slicePitch < region[1] * rowPitch || (slicePitch % rowPitch) != 0u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if the region being read or written specified
|
|
// by (origin, region, row_pitch, slice_pitch) is out of bounds.
|
|
if (!buffer.isRegionValid(
|
|
origin[2] * slicePitch + origin[1] * rowPitch + origin[0],
|
|
(region[2] - 1u) * slicePitch + (region[1] - 1u) * rowPitch + region[0]))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateHostRect(const size_t *hostOrigin,
|
|
const size_t *region,
|
|
size_t hostRowPitch,
|
|
size_t hostSlicePitch,
|
|
const void *ptr)
|
|
{
|
|
// CL_INVALID_VALUE if host_origin or region is NULL.
|
|
if (hostOrigin == nullptr || region == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if any region array element is 0.
|
|
if (region[0] == 0u || region[1] == 0u || region[2] == 0u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if host_row_pitch is not 0 and is less than region[0].
|
|
if (hostRowPitch == 0u)
|
|
{
|
|
hostRowPitch = region[0];
|
|
}
|
|
else if (hostRowPitch < region[0])
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if host_slice_pitch is not 0 and is less than
|
|
// region[1] x host_row_pitch and not a multiple of host_row_pitch.
|
|
if (hostSlicePitch != 0u &&
|
|
(hostSlicePitch < region[1] * hostRowPitch || (hostSlicePitch % hostRowPitch) != 0u))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if ptr is NULL.
|
|
if (ptr == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueImage(const CommandQueue &queue, cl_mem image, bool hostRead, bool hostWrite)
|
|
{
|
|
// CL_INVALID_MEM_OBJECT if image is not a valid image object.
|
|
if (!Image::IsValid(image))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
const Image &img = image->cast<Image>();
|
|
|
|
// CL_INVALID_CONTEXT if the context associated with command_queue and image are not the same.
|
|
if (&queue.getContext() != &img.getContext())
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if a read function is called on image which
|
|
// has been created with CL_MEM_HOST_WRITE_ONLY or CL_MEM_HOST_NO_ACCESS.
|
|
if (hostRead && img.getFlags().isSet(CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS))
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if a write function is called on image which
|
|
// has been created with CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_NO_ACCESS.
|
|
if (hostWrite && img.getFlags().isSet(CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS))
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateImageForDevice(const Image &image,
|
|
const Device &device,
|
|
const size_t *origin,
|
|
const size_t *region)
|
|
{
|
|
// CL_INVALID_VALUE if origin or region is NULL.
|
|
if (origin == nullptr || region == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if values in origin and region do not follow rules
|
|
// described in the argument description for origin and region.
|
|
// The values in region cannot be 0.
|
|
if (region[0] == 0u || region[1] == 0u || region[2] == 0u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
switch (image.getType())
|
|
{
|
|
// If image is a 1D image or 1D image buffer object,
|
|
// origin[1] and origin[2] must be 0 and region[1] and region[2] must be 1.
|
|
case MemObjectType::Image1D:
|
|
case MemObjectType::Image1D_Buffer:
|
|
if (origin[1] != 0u || origin[2] != 0u || region[1] != 1u || region[2] != 1u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
break;
|
|
// If image is a 2D image object or a 1D image array object,
|
|
// origin[2] must be 0 and region[2] must be 1.
|
|
case MemObjectType::Image2D:
|
|
case MemObjectType::Image1D_Array:
|
|
if (origin[2] != 0u || region[2] != 1u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
break;
|
|
case MemObjectType::Image3D:
|
|
case MemObjectType::Image2D_Array:
|
|
break;
|
|
default:
|
|
ASSERT(false);
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if the region being read or written
|
|
// specified by origin and region is out of bounds.
|
|
if (!image.isRegionValid(origin, region))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_IMAGE_SIZE if image dimensions (image width, height, specified or compute
|
|
// row and/or slice pitch) for image are not supported by device associated with queue.
|
|
if (!device.supportsImageDimensions(image.getDescriptor()))
|
|
{
|
|
return CL_INVALID_IMAGE_SIZE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateHostRegionForImage(const Image &image,
|
|
const size_t region[3],
|
|
size_t rowPitch,
|
|
size_t slicePitch,
|
|
const void *ptr)
|
|
{
|
|
// CL_INVALID_VALUE if row_pitch is not 0 and is less than the element size in bytes x width.
|
|
if (rowPitch == 0u)
|
|
{
|
|
rowPitch = image.getElementSize() * region[0];
|
|
}
|
|
else if (rowPitch < image.getElementSize() * region[0])
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
if (slicePitch != 0u)
|
|
{
|
|
// TODO(jplate) Follow up with https://github.com/KhronosGroup/OpenCL-Docs/issues/624
|
|
// This error is missing in the OpenCL spec.
|
|
// slice_pitch must be 0 if image is a 1D or 2D image.
|
|
if (image.getType() == MemObjectType::Image1D ||
|
|
image.getType() == MemObjectType::Image1D_Buffer ||
|
|
image.getType() == MemObjectType::Image2D)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
// CL_INVALID_VALUE if slice_pitch is not 0 and is less than row_pitch x height.
|
|
if (slicePitch < rowPitch * region[1])
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_VALUE if ptr is NULL.
|
|
if (ptr == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// CL 1.0
|
|
cl_int ValidateGetPlatformIDs(cl_uint num_entries,
|
|
const cl_platform_id *platforms,
|
|
const cl_uint *num_platforms)
|
|
{
|
|
// CL_INVALID_VALUE if num_entries is equal to zero and platforms is not NULL
|
|
// or if both num_platforms and platforms are NULL.
|
|
if ((num_entries == 0u && platforms != nullptr) ||
|
|
(platforms == nullptr && num_platforms == nullptr))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetPlatformInfo(cl_platform_id platform,
|
|
PlatformInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_PLATFORM if platform is not a valid platform.
|
|
if (!Platform::IsValidOrDefault(platform))
|
|
{
|
|
return CL_INVALID_PLATFORM;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not one of the supported values.
|
|
const cl_version version = platform->cast<Platform>().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case PlatformInfo::HostTimerResolution:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 1);
|
|
break;
|
|
case PlatformInfo::NumericVersion:
|
|
case PlatformInfo::ExtensionsWithVersion:
|
|
ANGLE_VALIDATE_VERSION(version, 3, 0);
|
|
break;
|
|
case PlatformInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetDeviceIDs(cl_platform_id platform,
|
|
DeviceType device_type,
|
|
cl_uint num_entries,
|
|
const cl_device_id *devices,
|
|
const cl_uint *num_devices)
|
|
{
|
|
// CL_INVALID_PLATFORM if platform is not a valid platform.
|
|
if (!Platform::IsValidOrDefault(platform))
|
|
{
|
|
return CL_INVALID_PLATFORM;
|
|
}
|
|
|
|
// CL_INVALID_DEVICE_TYPE if device_type is not a valid value.
|
|
if (!Device::IsValidType(device_type))
|
|
{
|
|
return CL_INVALID_DEVICE_TYPE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if num_entries is equal to zero and devices is not NULL
|
|
// or if both num_devices and devices are NULL.
|
|
if ((num_entries == 0u && devices != nullptr) || (num_devices == nullptr && devices == nullptr))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetDeviceInfo(cl_device_id device,
|
|
DeviceInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_DEVICE if device is not a valid device.
|
|
if (!Device::IsValid(device))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
const Device &dev = device->cast<Device>();
|
|
|
|
// CL_INVALID_VALUE if param_name is not one of the supported values
|
|
// or if param_name is a value that is available as an extension
|
|
// and the corresponding extension is not supported by the device.
|
|
const cl_version version = dev.getVersion();
|
|
const rx::CLDeviceImpl::Info &info = dev.getInfo();
|
|
// Enums ordered within their version block as they appear in the OpenCL spec V3.0.7, table 5
|
|
switch (param_name)
|
|
{
|
|
case DeviceInfo::PreferredVectorWidthHalf:
|
|
case DeviceInfo::NativeVectorWidthChar:
|
|
case DeviceInfo::NativeVectorWidthShort:
|
|
case DeviceInfo::NativeVectorWidthInt:
|
|
case DeviceInfo::NativeVectorWidthLong:
|
|
case DeviceInfo::NativeVectorWidthFloat:
|
|
case DeviceInfo::NativeVectorWidthDouble:
|
|
case DeviceInfo::NativeVectorWidthHalf:
|
|
case DeviceInfo::HostUnifiedMemory:
|
|
case DeviceInfo::OpenCL_C_Version:
|
|
ANGLE_VALIDATE_VERSION(version, 1, 1);
|
|
break;
|
|
|
|
case DeviceInfo::ImageMaxBufferSize:
|
|
case DeviceInfo::ImageMaxArraySize:
|
|
case DeviceInfo::LinkerAvailable:
|
|
case DeviceInfo::BuiltInKernels:
|
|
case DeviceInfo::PrintfBufferSize:
|
|
case DeviceInfo::PreferredInteropUserSync:
|
|
case DeviceInfo::ParentDevice:
|
|
case DeviceInfo::PartitionMaxSubDevices:
|
|
case DeviceInfo::PartitionProperties:
|
|
case DeviceInfo::PartitionAffinityDomain:
|
|
case DeviceInfo::PartitionType:
|
|
case DeviceInfo::ReferenceCount:
|
|
ANGLE_VALIDATE_VERSION(version, 1, 2);
|
|
break;
|
|
|
|
case DeviceInfo::MaxReadWriteImageArgs:
|
|
case DeviceInfo::ImagePitchAlignment:
|
|
case DeviceInfo::ImageBaseAddressAlignment:
|
|
case DeviceInfo::MaxPipeArgs:
|
|
case DeviceInfo::PipeMaxActiveReservations:
|
|
case DeviceInfo::PipeMaxPacketSize:
|
|
case DeviceInfo::MaxGlobalVariableSize:
|
|
case DeviceInfo::GlobalVariablePreferredTotalSize:
|
|
case DeviceInfo::QueueOnDeviceProperties:
|
|
case DeviceInfo::QueueOnDevicePreferredSize:
|
|
case DeviceInfo::QueueOnDeviceMaxSize:
|
|
case DeviceInfo::MaxOnDeviceQueues:
|
|
case DeviceInfo::MaxOnDeviceEvents:
|
|
case DeviceInfo::SVM_Capabilities:
|
|
case DeviceInfo::PreferredPlatformAtomicAlignment:
|
|
case DeviceInfo::PreferredGlobalAtomicAlignment:
|
|
case DeviceInfo::PreferredLocalAtomicAlignment:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 0);
|
|
break;
|
|
|
|
case DeviceInfo::IL_Version:
|
|
case DeviceInfo::MaxNumSubGroups:
|
|
case DeviceInfo::SubGroupIndependentForwardProgress:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 1);
|
|
break;
|
|
|
|
case DeviceInfo::ILsWithVersion:
|
|
case DeviceInfo::BuiltInKernelsWithVersion:
|
|
case DeviceInfo::NumericVersion:
|
|
case DeviceInfo::OpenCL_C_AllVersions:
|
|
case DeviceInfo::OpenCL_C_Features:
|
|
case DeviceInfo::ExtensionsWithVersion:
|
|
case DeviceInfo::AtomicMemoryCapabilities:
|
|
case DeviceInfo::AtomicFenceCapabilities:
|
|
case DeviceInfo::NonUniformWorkGroupSupport:
|
|
case DeviceInfo::WorkGroupCollectiveFunctionsSupport:
|
|
case DeviceInfo::GenericAddressSpaceSupport:
|
|
case DeviceInfo::DeviceEnqueueCapabilities:
|
|
case DeviceInfo::PipeSupport:
|
|
case DeviceInfo::PreferredWorkGroupSizeMultiple:
|
|
case DeviceInfo::LatestConformanceVersionPassed:
|
|
ANGLE_VALIDATE_VERSION(version, 3, 0);
|
|
break;
|
|
|
|
case DeviceInfo::DoubleFpConfig:
|
|
ANGLE_VALIDATE_EXTENSION(info.khrFP64);
|
|
break;
|
|
|
|
case DeviceInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateContext(const cl_context_properties *properties,
|
|
cl_uint num_devices,
|
|
const cl_device_id *devices,
|
|
void(CL_CALLBACK *pfn_notify)(const char *errinfo,
|
|
const void *private_info,
|
|
size_t cb,
|
|
void *user_data),
|
|
const void *user_data)
|
|
{
|
|
const Platform *platform = nullptr;
|
|
ANGLE_CL_TRY(ValidateContextProperties(properties, platform));
|
|
|
|
// CL_INVALID_VALUE if devices is NULL or if num_devices is equal to zero
|
|
// or if pfn_notify is NULL but user_data is not NULL.
|
|
if (devices == nullptr || num_devices == 0u || (pfn_notify == nullptr && user_data != nullptr))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_DEVICE if any device in devices is not a valid device.
|
|
while (num_devices-- > 0u)
|
|
{
|
|
if (!Device::IsValid(*devices) || &(*devices)->cast<Device>().getPlatform() != platform)
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
++devices;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateContextFromType(const cl_context_properties *properties,
|
|
DeviceType device_type,
|
|
void(CL_CALLBACK *pfn_notify)(const char *errinfo,
|
|
const void *private_info,
|
|
size_t cb,
|
|
void *user_data),
|
|
const void *user_data)
|
|
{
|
|
const Platform *platform = nullptr;
|
|
ANGLE_CL_TRY(ValidateContextProperties(properties, platform));
|
|
|
|
// CL_INVALID_DEVICE_TYPE if device_type is not a valid value.
|
|
if (!Device::IsValidType(device_type))
|
|
{
|
|
return CL_INVALID_DEVICE_TYPE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if pfn_notify is NULL but user_data is not NULL.
|
|
if (pfn_notify == nullptr && user_data != nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateRetainContext(cl_context context)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid OpenCL context.
|
|
return Context::IsValid(context) ? CL_SUCCESS : CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
cl_int ValidateReleaseContext(cl_context context)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid OpenCL context.
|
|
return Context::IsValid(context) ? CL_SUCCESS : CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
cl_int ValidateGetContextInfo(cl_context context,
|
|
ContextInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValid(context))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not one of the supported values.
|
|
if (param_name == ContextInfo::InvalidEnum)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateRetainCommandQueue(cl_command_queue command_queue)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid command-queue.
|
|
return CommandQueue::IsValid(command_queue) ? CL_SUCCESS : CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
cl_int ValidateReleaseCommandQueue(cl_command_queue command_queue)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid command-queue.
|
|
return CommandQueue::IsValid(command_queue) ? CL_SUCCESS : CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
cl_int ValidateGetCommandQueueInfo(cl_command_queue command_queue,
|
|
CommandQueueInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid command-queue ...
|
|
if (!CommandQueue::IsValid(command_queue))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
// or if command_queue is not a valid command-queue for param_name.
|
|
if (param_name == CommandQueueInfo::Size && queue.isOnDevice())
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not one of the supported values.
|
|
const cl_version version = queue.getDevice().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case CommandQueueInfo::Size:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 0);
|
|
break;
|
|
case CommandQueueInfo::DeviceDefault:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 1);
|
|
break;
|
|
case CommandQueueInfo::PropertiesArray:
|
|
ANGLE_VALIDATE_VERSION(version, 3, 0);
|
|
break;
|
|
case CommandQueueInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateBuffer(cl_context context, MemFlags flags, size_t size, const void *host_ptr)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValid(context))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
const Context &ctx = context->cast<Context>();
|
|
|
|
// CL_INVALID_VALUE if values specified in flags are not valid
|
|
// as defined in the Memory Flags table.
|
|
if (!ValidateMemoryFlags(flags, ctx.getPlatform()))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_BUFFER_SIZE if size is 0 ...
|
|
if (size == 0u)
|
|
{
|
|
CL_INVALID_BUFFER_SIZE;
|
|
}
|
|
for (const DevicePtr &device : ctx.getDevices())
|
|
{
|
|
// or if size is greater than CL_DEVICE_MAX_MEM_ALLOC_SIZE for all devices in context.
|
|
if (size > device->getInfo().maxMemAllocSize)
|
|
{
|
|
return CL_INVALID_BUFFER_SIZE;
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_HOST_PTR
|
|
// if host_ptr is NULL and CL_MEM_USE_HOST_PTR or CL_MEM_COPY_HOST_PTR are set in flags or
|
|
// if host_ptr is not NULL but CL_MEM_COPY_HOST_PTR or CL_MEM_USE_HOST_PTR are not set in flags.
|
|
if ((host_ptr != nullptr) != flags.isSet(CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR))
|
|
{
|
|
return CL_INVALID_HOST_PTR;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateRetainMemObject(cl_mem memobj)
|
|
{
|
|
// CL_INVALID_MEM_OBJECT if memobj is not a valid memory object.
|
|
return Memory::IsValid(memobj) ? CL_SUCCESS : CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
cl_int ValidateReleaseMemObject(cl_mem memobj)
|
|
{
|
|
// CL_INVALID_MEM_OBJECT if memobj is not a valid memory object.
|
|
return Memory::IsValid(memobj) ? CL_SUCCESS : CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
cl_int ValidateGetSupportedImageFormats(cl_context context,
|
|
MemFlags flags,
|
|
MemObjectType image_type,
|
|
cl_uint num_entries,
|
|
const cl_image_format *image_formats,
|
|
const cl_uint *num_image_formats)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValid(context))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
const Context &ctx = context->cast<Context>();
|
|
|
|
// CL_INVALID_VALUE if flags or image_type are not valid,
|
|
if (!ValidateMemoryFlags(flags, ctx.getPlatform()) || !Image::IsTypeValid(image_type))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
// or if num_entries is 0 and image_formats is not NULL.
|
|
if (num_entries == 0u && image_formats != nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetMemObjectInfo(cl_mem memobj,
|
|
MemInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_MEM_OBJECT if memobj is a not a valid memory object.
|
|
if (!Memory::IsValid(memobj))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
const cl_version version = memobj->cast<Memory>().getContext().getPlatform().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case MemInfo::AssociatedMemObject:
|
|
case MemInfo::Offset:
|
|
ANGLE_VALIDATE_VERSION(version, 1, 1);
|
|
break;
|
|
case MemInfo::UsesSVM_Pointer:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 0);
|
|
break;
|
|
case MemInfo::Properties:
|
|
ANGLE_VALIDATE_VERSION(version, 3, 0);
|
|
break;
|
|
case MemInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetImageInfo(cl_mem image,
|
|
ImageInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_MEM_OBJECT if image is a not a valid image object.
|
|
if (!Image::IsValid(image))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
const cl_version version = image->cast<Image>().getContext().getPlatform().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case ImageInfo::ArraySize:
|
|
case ImageInfo::Buffer:
|
|
case ImageInfo::NumMipLevels:
|
|
case ImageInfo::NumSamples:
|
|
ANGLE_VALIDATE_VERSION(version, 1, 2);
|
|
break;
|
|
case ImageInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateRetainSampler(cl_sampler sampler)
|
|
{
|
|
// CL_INVALID_SAMPLER if sampler is not a valid sampler object.
|
|
return Sampler::IsValid(sampler) ? CL_SUCCESS : CL_INVALID_SAMPLER;
|
|
}
|
|
|
|
cl_int ValidateReleaseSampler(cl_sampler sampler)
|
|
{
|
|
// CL_INVALID_SAMPLER if sampler is not a valid sampler object.
|
|
return Sampler::IsValid(sampler) ? CL_SUCCESS : CL_INVALID_SAMPLER;
|
|
}
|
|
|
|
cl_int ValidateGetSamplerInfo(cl_sampler sampler,
|
|
SamplerInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_SAMPLER if sampler is a not a valid sampler object.
|
|
if (!Sampler::IsValid(sampler))
|
|
{
|
|
return CL_INVALID_SAMPLER;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
const cl_version version = sampler->cast<Sampler>().getContext().getPlatform().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case SamplerInfo::Properties:
|
|
ANGLE_VALIDATE_VERSION(version, 3, 0);
|
|
break;
|
|
case SamplerInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateProgramWithSource(cl_context context,
|
|
cl_uint count,
|
|
const char **strings,
|
|
const size_t *lengths)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValid(context))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if count is zero or if strings or any entry in strings is NULL.
|
|
if (count == 0u || strings == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
while (count-- != 0u)
|
|
{
|
|
if (*strings++ == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateProgramWithBinary(cl_context context,
|
|
cl_uint num_devices,
|
|
const cl_device_id *device_list,
|
|
const size_t *lengths,
|
|
const unsigned char **binaries,
|
|
const cl_int *binary_status)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValid(context))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
const Context &ctx = context->cast<Context>();
|
|
|
|
// CL_INVALID_VALUE if device_list is NULL or num_devices is zero.
|
|
// CL_INVALID_VALUE if lengths or binaries is NULL.
|
|
if (device_list == nullptr || num_devices == 0u || lengths == nullptr || binaries == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
while (num_devices-- != 0u)
|
|
{
|
|
// CL_INVALID_DEVICE if any device in device_list
|
|
// is not in the list of devices associated with context.
|
|
if (!ctx.hasDevice(*device_list++))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if any entry in lengths[i] is zero or binaries[i] is NULL.
|
|
if (*lengths++ == 0u || *binaries++ == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateRetainProgram(cl_program program)
|
|
{
|
|
// CL_INVALID_PROGRAM if program is not a valid program object.
|
|
return Program::IsValid(program) ? CL_SUCCESS : CL_INVALID_PROGRAM;
|
|
}
|
|
|
|
cl_int ValidateReleaseProgram(cl_program program)
|
|
{
|
|
// CL_INVALID_PROGRAM if program is not a valid program object.
|
|
return Program::IsValid(program) ? CL_SUCCESS : CL_INVALID_PROGRAM;
|
|
}
|
|
|
|
cl_int ValidateBuildProgram(cl_program program,
|
|
cl_uint num_devices,
|
|
const cl_device_id *device_list,
|
|
const char *options,
|
|
void(CL_CALLBACK *pfn_notify)(cl_program program, void *user_data),
|
|
const void *user_data)
|
|
{
|
|
// CL_INVALID_PROGRAM if program is not a valid program object.
|
|
if (!Program::IsValid(program))
|
|
{
|
|
return CL_INVALID_PROGRAM;
|
|
}
|
|
const Program &prog = program->cast<Program>();
|
|
|
|
// CL_INVALID_VALUE if device_list is NULL and num_devices is greater than zero,
|
|
// or if device_list is not NULL and num_devices is zero.
|
|
if ((device_list != nullptr) != (num_devices != 0u))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_DEVICE if any device in device_list
|
|
// is not in the list of devices associated with program.
|
|
while (num_devices-- != 0u)
|
|
{
|
|
if (!prog.hasDevice(*device_list++))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_VALUE if pfn_notify is NULL but user_data is not NULL.
|
|
if (pfn_notify == nullptr && user_data != nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if the build of a program executable for any of the devices listed
|
|
// in device_list by a previous call to clBuildProgram for program has not completed.
|
|
if (prog.isBuilding())
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if there are kernel objects attached to program.
|
|
if (prog.hasAttachedKernels())
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetProgramInfo(cl_program program,
|
|
ProgramInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_PROGRAM if program is not a valid program object.
|
|
if (!Program::IsValid(program))
|
|
{
|
|
return CL_INVALID_PROGRAM;
|
|
}
|
|
const Program &prog = program->cast<Program>();
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
const cl_version version = prog.getContext().getPlatform().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case ProgramInfo::NumKernels:
|
|
case ProgramInfo::KernelNames:
|
|
ANGLE_VALIDATE_VERSION(version, 1, 2);
|
|
break;
|
|
case ProgramInfo::IL:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 1);
|
|
break;
|
|
case ProgramInfo::ScopeGlobalCtorsPresent:
|
|
case ProgramInfo::ScopeGlobalDtorsPresent:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 2);
|
|
break;
|
|
case ProgramInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetProgramBuildInfo(cl_program program,
|
|
cl_device_id device,
|
|
ProgramBuildInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_PROGRAM if program is not a valid program object.
|
|
if (!Program::IsValid(program))
|
|
{
|
|
return CL_INVALID_PROGRAM;
|
|
}
|
|
const Program &prog = program->cast<Program>();
|
|
|
|
// CL_INVALID_DEVICE if device is not in the list of devices associated with program.
|
|
if (!prog.hasDevice(device))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
const cl_version version = prog.getContext().getPlatform().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case ProgramBuildInfo::BinaryType:
|
|
ANGLE_VALIDATE_VERSION(version, 1, 2);
|
|
break;
|
|
case ProgramBuildInfo::GlobalVariableTotalSize:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 0);
|
|
break;
|
|
case ProgramBuildInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateKernel(cl_program program, const char *kernel_name)
|
|
{
|
|
// CL_INVALID_PROGRAM if program is not a valid program object.
|
|
if (!Program::IsValid(program))
|
|
{
|
|
return CL_INVALID_PROGRAM;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if kernel_name is NULL.
|
|
if (kernel_name == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateKernelsInProgram(cl_program program,
|
|
cl_uint num_kernels,
|
|
const cl_kernel *kernels,
|
|
const cl_uint *num_kernels_ret)
|
|
{
|
|
// CL_INVALID_PROGRAM if program is not a valid program object.
|
|
if (!Program::IsValid(program))
|
|
{
|
|
return CL_INVALID_PROGRAM;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateRetainKernel(cl_kernel kernel)
|
|
{
|
|
// CL_INVALID_KERNEL if kernel is not a valid kernel object.
|
|
return Kernel::IsValid(kernel) ? CL_SUCCESS : CL_INVALID_KERNEL;
|
|
}
|
|
|
|
cl_int ValidateReleaseKernel(cl_kernel kernel)
|
|
{
|
|
// CL_INVALID_KERNEL if kernel is not a valid kernel object.
|
|
return Kernel::IsValid(kernel) ? CL_SUCCESS : CL_INVALID_KERNEL;
|
|
}
|
|
|
|
cl_int ValidateSetKernelArg(cl_kernel kernel,
|
|
cl_uint arg_index,
|
|
size_t arg_size,
|
|
const void *arg_value)
|
|
{
|
|
// CL_INVALID_KERNEL if kernel is not a valid kernel object.
|
|
if (!Kernel::IsValid(kernel))
|
|
{
|
|
return CL_INVALID_KERNEL;
|
|
}
|
|
const Kernel &krnl = kernel->cast<Kernel>();
|
|
|
|
// CL_INVALID_ARG_INDEX if arg_index is not a valid argument index.
|
|
if (arg_index >= krnl.getInfo().args.size())
|
|
{
|
|
return CL_INVALID_ARG_INDEX;
|
|
}
|
|
|
|
if (arg_size == sizeof(cl_mem) && arg_value != nullptr)
|
|
{
|
|
const std::string &typeName = krnl.getInfo().args[arg_index].typeName;
|
|
|
|
// CL_INVALID_MEM_OBJECT for an argument declared to be a memory object
|
|
// when the specified arg_value is not a valid memory object.
|
|
if (typeName == "image1d_t")
|
|
{
|
|
const cl_mem image = *static_cast<const cl_mem *>(arg_value);
|
|
if (!Image::IsValid(image) || image->cast<Image>().getType() != MemObjectType::Image1D)
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
}
|
|
else if (typeName == "image2d_t")
|
|
{
|
|
const cl_mem image = *static_cast<const cl_mem *>(arg_value);
|
|
if (!Image::IsValid(image) || image->cast<Image>().getType() != MemObjectType::Image2D)
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
}
|
|
else if (typeName == "image3d_t")
|
|
{
|
|
const cl_mem image = *static_cast<const cl_mem *>(arg_value);
|
|
if (!Image::IsValid(image) || image->cast<Image>().getType() != MemObjectType::Image3D)
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
}
|
|
else if (typeName == "image1d_array_t")
|
|
{
|
|
const cl_mem image = *static_cast<const cl_mem *>(arg_value);
|
|
if (!Image::IsValid(image) ||
|
|
image->cast<Image>().getType() != MemObjectType::Image1D_Array)
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
}
|
|
else if (typeName == "image2d_array_t")
|
|
{
|
|
const cl_mem image = *static_cast<const cl_mem *>(arg_value);
|
|
if (!Image::IsValid(image) ||
|
|
image->cast<Image>().getType() != MemObjectType::Image2D_Array)
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
}
|
|
else if (typeName == "image1d_buffer_t")
|
|
{
|
|
const cl_mem image = *static_cast<const cl_mem *>(arg_value);
|
|
if (!Image::IsValid(image) ||
|
|
image->cast<Image>().getType() != MemObjectType::Image1D_Buffer)
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
}
|
|
// CL_INVALID_SAMPLER for an argument declared to be of type sampler_t
|
|
// when the specified arg_value is not a valid sampler object.
|
|
else if (typeName == "sampler_t")
|
|
{
|
|
if (!Sampler::IsValid(*static_cast<const cl_sampler *>(arg_value)))
|
|
{
|
|
return CL_INVALID_SAMPLER;
|
|
}
|
|
}
|
|
// CL_INVALID_DEVICE_QUEUE for an argument declared to be of type queue_t
|
|
// when the specified arg_value is not a valid device queue object.
|
|
else if (typeName == "queue_t")
|
|
{
|
|
const cl_command_queue queue = *static_cast<const cl_command_queue *>(arg_value);
|
|
if (!CommandQueue::IsValid(queue) || !queue->cast<CommandQueue>().isOnDevice())
|
|
{
|
|
return CL_INVALID_DEVICE_QUEUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetKernelInfo(cl_kernel kernel,
|
|
KernelInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_KERNEL if kernel is a not a valid kernel object.
|
|
if (!Kernel::IsValid(kernel))
|
|
{
|
|
return CL_INVALID_KERNEL;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
const cl_version version =
|
|
kernel->cast<Kernel>().getProgram().getContext().getPlatform().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case KernelInfo::Attributes:
|
|
ANGLE_VALIDATE_VERSION(version, 1, 2);
|
|
break;
|
|
case KernelInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetKernelWorkGroupInfo(cl_kernel kernel,
|
|
cl_device_id device,
|
|
KernelWorkGroupInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_KERNEL if kernel is a not a valid kernel object.
|
|
if (!Kernel::IsValid(kernel))
|
|
{
|
|
return CL_INVALID_KERNEL;
|
|
}
|
|
const Kernel &krnl = kernel->cast<Kernel>();
|
|
|
|
const Device *dev = nullptr;
|
|
if (device != nullptr)
|
|
{
|
|
// CL_INVALID_DEVICE if device is not in the list of devices associated with kernel ...
|
|
if (krnl.getProgram().getContext().hasDevice(device))
|
|
{
|
|
dev = &device->cast<Device>();
|
|
}
|
|
else
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// or if device is NULL but there is more than one device associated with kernel.
|
|
if (krnl.getProgram().getContext().getDevices().size() == 1u)
|
|
{
|
|
dev = krnl.getProgram().getContext().getDevices().front().get();
|
|
}
|
|
else
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
const cl_version version = krnl.getProgram().getContext().getPlatform().getInfo().version;
|
|
switch (param_name)
|
|
{
|
|
case KernelWorkGroupInfo::GlobalWorkSize:
|
|
ANGLE_VALIDATE_VERSION(version, 1, 2);
|
|
// CL_INVALID_VALUE if param_name is CL_KERNEL_GLOBAL_WORK_SIZE and
|
|
// device is not a custom device and kernel is not a built-in kernel.
|
|
if (!dev->supportsBuiltInKernel(krnl.getInfo().functionName))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
break;
|
|
case KernelWorkGroupInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateWaitForEvents(cl_uint num_events, const cl_event *event_list)
|
|
{
|
|
// CL_INVALID_VALUE if num_events is zero or event_list is NULL.
|
|
if (num_events == 0u || event_list == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
const Context *context = nullptr;
|
|
while (num_events-- != 0u)
|
|
{
|
|
// CL_INVALID_EVENT if event objects specified in event_list are not valid event objects.
|
|
if (!Event::IsValid(*event_list))
|
|
{
|
|
return CL_INVALID_EVENT;
|
|
}
|
|
|
|
// CL_INVALID_CONTEXT if events specified in event_list do not belong to the same context.
|
|
const Context *eventContext = &(*event_list++)->cast<Event>().getContext();
|
|
if (context == nullptr)
|
|
{
|
|
context = eventContext;
|
|
}
|
|
else if (context != eventContext)
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetEventInfo(cl_event event,
|
|
EventInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_EVENT if event is a not a valid event object.
|
|
if (!Event::IsValid(event))
|
|
{
|
|
return CL_INVALID_EVENT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
const cl_version version = event->cast<Event>().getContext().getPlatform().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case EventInfo::Context:
|
|
ANGLE_VALIDATE_VERSION(version, 1, 1);
|
|
break;
|
|
case EventInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateRetainEvent(cl_event event)
|
|
{
|
|
// CL_INVALID_EVENT if event is not a valid event object.
|
|
return Event::IsValid(event) ? CL_SUCCESS : CL_INVALID_EVENT;
|
|
}
|
|
|
|
cl_int ValidateReleaseEvent(cl_event event)
|
|
{
|
|
// CL_INVALID_EVENT if event is not a valid event object.
|
|
return Event::IsValid(event) ? CL_SUCCESS : CL_INVALID_EVENT;
|
|
}
|
|
|
|
cl_int ValidateGetEventProfilingInfo(cl_event event,
|
|
ProfilingInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_EVENT if event is a not a valid event object.
|
|
if (!Event::IsValid(event))
|
|
{
|
|
return CL_INVALID_EVENT;
|
|
}
|
|
const Event &evt = event->cast<Event>();
|
|
|
|
// CL_PROFILING_INFO_NOT_AVAILABLE if event is a user event object,
|
|
if (evt.getCommandType() == CL_COMMAND_USER)
|
|
{
|
|
return CL_PROFILING_INFO_NOT_AVAILABLE;
|
|
}
|
|
// or if the CL_QUEUE_PROFILING_ENABLE flag is not set for the command-queue.
|
|
if (evt.getCommandQueue()->getProperties().isNotSet(CL_QUEUE_PROFILING_ENABLE))
|
|
{
|
|
return CL_PROFILING_INFO_NOT_AVAILABLE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
const cl_version version = evt.getContext().getPlatform().getVersion();
|
|
switch (param_name)
|
|
{
|
|
case ProfilingInfo::CommandComplete:
|
|
ANGLE_VALIDATE_VERSION(version, 2, 0);
|
|
break;
|
|
case ProfilingInfo::InvalidEnum:
|
|
return CL_INVALID_VALUE;
|
|
default:
|
|
// All remaining possible values for param_name are valid for all versions.
|
|
break;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateFlush(cl_command_queue command_queue)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
|
|
if (!CommandQueue::IsValid(command_queue) || !command_queue->cast<CommandQueue>().isOnHost())
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateFinish(cl_command_queue command_queue)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
|
|
if (!CommandQueue::IsValid(command_queue) || !command_queue->cast<CommandQueue>().isOnHost())
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueReadBuffer(cl_command_queue command_queue,
|
|
cl_mem buffer,
|
|
cl_bool blocking_read,
|
|
size_t offset,
|
|
size_t size,
|
|
const void *ptr,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(command_queue->cast<CommandQueue>(), buffer, true, false));
|
|
|
|
// CL_INVALID_VALUE if the region being read or written specified
|
|
// by (offset, size) is out of bounds or if ptr is a NULL value.
|
|
if (!buffer->cast<Buffer>().isRegionValid(offset, size) || ptr == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueWriteBuffer(cl_command_queue command_queue,
|
|
cl_mem buffer,
|
|
cl_bool blocking_write,
|
|
size_t offset,
|
|
size_t size,
|
|
const void *ptr,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(command_queue->cast<CommandQueue>(), buffer, false, true));
|
|
|
|
// CL_INVALID_VALUE if the region being read or written specified
|
|
// by (offset, size) is out of bounds or if ptr is a NULL value.
|
|
if (!buffer->cast<Buffer>().isRegionValid(offset, size) || ptr == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueCopyBuffer(cl_command_queue command_queue,
|
|
cl_mem src_buffer,
|
|
cl_mem dst_buffer,
|
|
size_t src_offset,
|
|
size_t dst_offset,
|
|
size_t size,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(queue, src_buffer, false, false));
|
|
const Buffer &src = src_buffer->cast<Buffer>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(queue, dst_buffer, false, false));
|
|
const Buffer &dst = dst_buffer->cast<Buffer>();
|
|
|
|
// CL_INVALID_VALUE if src_offset, dst_offset, size, src_offset + size or dst_offset + size
|
|
// require accessing elements outside the src_buffer and dst_buffer buffer objects respectively.
|
|
if (!src.isRegionValid(src_offset, size) || !dst.isRegionValid(dst_offset, size))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_MEM_COPY_OVERLAP if src_buffer and dst_buffer are the same buffer or sub-buffer object
|
|
// and the source and destination regions overlap or if src_buffer and dst_buffer are
|
|
// different sub-buffers of the same associated buffer object and they overlap.
|
|
if ((src.isSubBuffer() ? src.getParent().get() : &src) ==
|
|
(dst.isSubBuffer() ? dst.getParent().get() : &dst))
|
|
{
|
|
// Only sub-buffers have offsets larger than zero
|
|
src_offset += src.getOffset();
|
|
dst_offset += dst.getOffset();
|
|
|
|
if (OverlapRegions(src_offset, dst_offset, size))
|
|
{
|
|
return CL_MEM_COPY_OVERLAP;
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueReadImage(cl_command_queue command_queue,
|
|
cl_mem image,
|
|
cl_bool blocking_read,
|
|
const size_t *origin,
|
|
const size_t *region,
|
|
size_t row_pitch,
|
|
size_t slice_pitch,
|
|
const void *ptr,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, true, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueImage(queue, image, true, false));
|
|
const Image &img = image->cast<Image>();
|
|
|
|
ANGLE_CL_TRY(ValidateImageForDevice(img, queue.getDevice(), origin, region));
|
|
ANGLE_CL_TRY(ValidateHostRegionForImage(img, region, row_pitch, slice_pitch, ptr));
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueWriteImage(cl_command_queue command_queue,
|
|
cl_mem image,
|
|
cl_bool blocking_write,
|
|
const size_t *origin,
|
|
const size_t *region,
|
|
size_t input_row_pitch,
|
|
size_t input_slice_pitch,
|
|
const void *ptr,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, true, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueImage(queue, image, false, true));
|
|
const Image &img = image->cast<Image>();
|
|
|
|
ANGLE_CL_TRY(ValidateImageForDevice(img, queue.getDevice(), origin, region));
|
|
ANGLE_CL_TRY(ValidateHostRegionForImage(img, region, input_row_pitch, input_slice_pitch, ptr));
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueCopyImage(cl_command_queue command_queue,
|
|
cl_mem src_image,
|
|
cl_mem dst_image,
|
|
const size_t *src_origin,
|
|
const size_t *dst_origin,
|
|
const size_t *region,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, true, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueImage(queue, src_image, false, false));
|
|
const Image &src = src_image->cast<Image>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueImage(queue, dst_image, false, false));
|
|
const Image &dst = dst_image->cast<Image>();
|
|
|
|
// CL_IMAGE_FORMAT_MISMATCH if src_image and dst_image do not use the same image format.
|
|
if (src.getFormat().image_channel_order != dst.getFormat().image_channel_order ||
|
|
src.getFormat().image_channel_data_type != dst.getFormat().image_channel_data_type)
|
|
{
|
|
return CL_IMAGE_FORMAT_MISMATCH;
|
|
}
|
|
|
|
ANGLE_CL_TRY(ValidateImageForDevice(src, queue.getDevice(), src_origin, region));
|
|
ANGLE_CL_TRY(ValidateImageForDevice(dst, queue.getDevice(), dst_origin, region));
|
|
|
|
// CL_MEM_COPY_OVERLAP if src_image and dst_image are the same image object
|
|
// and the source and destination regions overlap.
|
|
if (&src == &dst)
|
|
{
|
|
const MemObjectType type = src.getType();
|
|
// Check overlap in first dimension
|
|
if (OverlapRegions(src_origin[0], dst_origin[0], region[0]))
|
|
{
|
|
if (type == MemObjectType::Image1D || type == MemObjectType::Image1D_Buffer)
|
|
{
|
|
return CL_MEM_COPY_OVERLAP;
|
|
}
|
|
|
|
// Check overlap in second dimension
|
|
if (OverlapRegions(src_origin[1], dst_origin[1], region[1]))
|
|
{
|
|
if (type == MemObjectType::Image2D || type == MemObjectType::Image1D_Array)
|
|
{
|
|
return CL_MEM_COPY_OVERLAP;
|
|
}
|
|
|
|
// Check overlap in third dimension
|
|
if (OverlapRegions(src_origin[2], dst_origin[2], region[2]))
|
|
{
|
|
return CL_MEM_COPY_OVERLAP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueCopyImageToBuffer(cl_command_queue command_queue,
|
|
cl_mem src_image,
|
|
cl_mem dst_buffer,
|
|
const size_t *src_origin,
|
|
const size_t *region,
|
|
size_t dst_offset,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, true, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueImage(queue, src_image, false, false));
|
|
const Image &src = src_image->cast<Image>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(queue, dst_buffer, false, false));
|
|
const Buffer &dst = dst_buffer->cast<Buffer>();
|
|
|
|
// CL_INVALID_MEM_OBJECT if src_image is a 1D image buffer object created from dst_buffer.
|
|
if (src.getType() == MemObjectType::Image1D_Buffer && src.getParent() == &dst)
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
ANGLE_CL_TRY(ValidateImageForDevice(src, queue.getDevice(), src_origin, region));
|
|
|
|
// CL_INVALID_VALUE if the region specified by dst_offset and dst_offset + dst_cb
|
|
// refer to a region outside dst_buffer.
|
|
const MemObjectType type = src.getType();
|
|
size_t dst_cb = src.getElementSize() * region[0];
|
|
if (type != MemObjectType::Image1D && type != MemObjectType::Image1D_Buffer)
|
|
{
|
|
dst_cb *= region[1];
|
|
if (type != MemObjectType::Image2D && type != MemObjectType::Image1D_Array)
|
|
{
|
|
dst_cb *= region[2];
|
|
}
|
|
}
|
|
if (!dst.isRegionValid(dst_offset, dst_cb))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueCopyBufferToImage(cl_command_queue command_queue,
|
|
cl_mem src_buffer,
|
|
cl_mem dst_image,
|
|
size_t src_offset,
|
|
const size_t *dst_origin,
|
|
const size_t *region,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, true, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(queue, src_buffer, false, false));
|
|
const Buffer &src = src_buffer->cast<Buffer>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueImage(queue, dst_image, false, false));
|
|
const Image &dst = dst_image->cast<Image>();
|
|
|
|
// CL_INVALID_MEM_OBJECT if dst_image is a 1D image buffer object created from src_buffer.
|
|
if (dst.getType() == MemObjectType::Image1D_Buffer && dst.getParent() == &src)
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
ANGLE_CL_TRY(ValidateImageForDevice(dst, queue.getDevice(), dst_origin, region));
|
|
|
|
// CL_INVALID_VALUE if the region specified by src_offset and src_offset + src_cb
|
|
// refer to a region outside src_buffer.
|
|
const MemObjectType type = dst.getType();
|
|
size_t src_cb = dst.getElementSize() * region[0];
|
|
if (type != MemObjectType::Image1D && type != MemObjectType::Image1D_Buffer)
|
|
{
|
|
src_cb *= region[1];
|
|
if (type != MemObjectType::Image2D && type != MemObjectType::Image1D_Array)
|
|
{
|
|
src_cb *= region[2];
|
|
}
|
|
}
|
|
if (!src.isRegionValid(src_offset, src_cb))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueMapBuffer(cl_command_queue command_queue,
|
|
cl_mem buffer,
|
|
cl_bool blocking_map,
|
|
MapFlags map_flags,
|
|
size_t offset,
|
|
size_t size,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
// CL_INVALID_OPERATION if buffer has been created with CL_MEM_HOST_WRITE_ONLY or
|
|
// CL_MEM_HOST_NO_ACCESS and CL_MAP_READ is set in map_flags
|
|
// or if buffer has been created with CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_NO_ACCESS
|
|
// and CL_MAP_WRITE or CL_MAP_WRITE_INVALIDATE_REGION is set in map_flags.
|
|
ANGLE_CL_TRY(
|
|
ValidateEnqueueBuffer(queue, buffer, map_flags.isSet(CL_MAP_READ),
|
|
map_flags.isSet(CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION)));
|
|
|
|
// CL_INVALID_VALUE if region being mapped given by (offset, size) is out of bounds
|
|
// or if size is 0 or if values specified in map_flags are not valid.
|
|
if (!buffer->cast<Buffer>().isRegionValid(offset, size) || size == 0u ||
|
|
!ValidateMapFlags(map_flags, queue.getContext().getPlatform()))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueMapImage(cl_command_queue command_queue,
|
|
cl_mem image,
|
|
cl_bool blocking_map,
|
|
MapFlags map_flags,
|
|
const size_t *origin,
|
|
const size_t *region,
|
|
const size_t *image_row_pitch,
|
|
const size_t *image_slice_pitch,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, true, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
// CL_INVALID_OPERATION if image has been created with CL_MEM_HOST_WRITE_ONLY or
|
|
// CL_MEM_HOST_NO_ACCESS and CL_MAP_READ is set in map_flags
|
|
// or if image has been created with CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_NO_ACCESS
|
|
// and CL_MAP_WRITE or CL_MAP_WRITE_INVALIDATE_REGION is set in map_flags.
|
|
ANGLE_CL_TRY(
|
|
ValidateEnqueueImage(queue, image, map_flags.isSet(CL_MAP_READ),
|
|
map_flags.isSet(CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION)));
|
|
const Image &img = image->cast<Image>();
|
|
|
|
ANGLE_CL_TRY(ValidateImageForDevice(img, queue.getDevice(), origin, region));
|
|
|
|
// CL_INVALID_VALUE if values specified in map_flags are not valid.
|
|
if (!ValidateMapFlags(map_flags, queue.getContext().getPlatform()))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if image_row_pitch is NULL.
|
|
if (image_row_pitch == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if image is a 3D image, 1D or 2D image array object
|
|
// and image_slice_pitch is NULL.
|
|
if ((img.getType() == MemObjectType::Image3D || img.getType() == MemObjectType::Image1D_Array ||
|
|
img.getType() == MemObjectType::Image2D_Array) &&
|
|
image_slice_pitch == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueUnmapMemObject(cl_command_queue command_queue,
|
|
cl_mem memobj,
|
|
const void *mapped_ptr,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
// CL_INVALID_MEM_OBJECT if memobj is not a valid memory object or is a pipe object.
|
|
if (!Memory::IsValid(memobj))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
const Memory &memory = memobj->cast<Memory>();
|
|
if (memory.getType() == MemObjectType::Pipe)
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
// CL_INVALID_CONTEXT if context associated with command_queue and memobj are not the same.
|
|
if (&queue.getContext() != &memory.getContext())
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueNDRangeKernel(cl_command_queue command_queue,
|
|
cl_kernel kernel,
|
|
cl_uint work_dim,
|
|
const size_t *global_work_offset,
|
|
const size_t *global_work_size,
|
|
const size_t *local_work_size,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
const Device &device = queue.getDevice();
|
|
|
|
// CL_INVALID_KERNEL if kernel is not a valid kernel object.
|
|
if (!Kernel::IsValid(kernel))
|
|
{
|
|
return CL_INVALID_KERNEL;
|
|
}
|
|
const Kernel &krnl = kernel->cast<Kernel>();
|
|
|
|
// CL_INVALID_CONTEXT if context associated with command_queue and kernel are not the same.
|
|
if (&queue.getContext() != &krnl.getProgram().getContext())
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_WORK_DIMENSION if work_dim is not a valid value.
|
|
if (work_dim == 0u || work_dim > device.getInfo().maxWorkItemSizes.size())
|
|
{
|
|
return CL_INVALID_WORK_DIMENSION;
|
|
}
|
|
|
|
// CL_INVALID_GLOBAL_OFFSET if global_work_offset is non-NULL before version 1.1.
|
|
if (!queue.getContext().getPlatform().isVersionOrNewer(1u, 1u) && global_work_offset != nullptr)
|
|
{
|
|
return CL_INVALID_GLOBAL_OFFSET;
|
|
}
|
|
|
|
// CL_INVALID_GLOBAL_WORK_SIZE if global_work_size is NULL or if any of the values
|
|
// specified in global_work_size[0] ... global_work_size[work_dim - 1] are 0.
|
|
// Returning this error code under these circumstances is deprecated by version 2.1.
|
|
if (!queue.getContext().getPlatform().isVersionOrNewer(2u, 1u))
|
|
{
|
|
if (global_work_size == nullptr)
|
|
{
|
|
return CL_INVALID_GLOBAL_WORK_SIZE;
|
|
}
|
|
for (cl_uint dim = 0u; dim < work_dim; ++dim)
|
|
{
|
|
if (global_work_size[dim] == 0u)
|
|
{
|
|
return CL_INVALID_GLOBAL_WORK_SIZE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (local_work_size != nullptr)
|
|
{
|
|
size_t numWorkItems = 1u; // Initialize with neutral element for multiplication
|
|
|
|
// CL_INVALID_WORK_ITEM_SIZE if the number of work-items specified
|
|
// in any of local_work_size[0] ... local_work_size[work_dim - 1]
|
|
// is greater than the corresponding values specified by
|
|
// CL_DEVICE_MAX_WORK_ITEM_SIZES[0] ... CL_DEVICE_MAX_WORK_ITEM_SIZES[work_dim - 1].
|
|
for (cl_uint dim = 0u; dim < work_dim; ++dim)
|
|
{
|
|
if (local_work_size[dim] > device.getInfo().maxWorkItemSizes[dim])
|
|
{
|
|
return CL_INVALID_WORK_ITEM_SIZE;
|
|
}
|
|
numWorkItems *= local_work_size[dim];
|
|
}
|
|
|
|
// CL_INVALID_WORK_GROUP_SIZE if local_work_size is specified
|
|
// and the total number of work-items in the work-group computed as
|
|
// local_work_size[0] x ... local_work_size[work_dim - 1] is greater than the value
|
|
// specified by CL_KERNEL_WORK_GROUP_SIZE in the Kernel Object Device Queries table.
|
|
if (numWorkItems > krnl.getInfo().workGroups[queue.getDeviceIndex()].workGroupSize)
|
|
{
|
|
return CL_INVALID_WORK_GROUP_SIZE;
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueNativeKernel(cl_command_queue command_queue,
|
|
void(CL_CALLBACK *user_func)(void *),
|
|
const void *args,
|
|
size_t cb_args,
|
|
cl_uint num_mem_objects,
|
|
const cl_mem *mem_list,
|
|
const void **args_mem_loc,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
|
|
// CL_INVALID_OPERATION if the device associated with command_queue
|
|
// cannot execute the native kernel.
|
|
if (queue.getDevice().getInfo().execCapabilities.isNotSet(CL_EXEC_NATIVE_KERNEL))
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if user_func is NULL.
|
|
if (user_func == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
if (args == nullptr)
|
|
{
|
|
// CL_INVALID_VALUE if args is a NULL value and cb_args > 0 or num_mem_objects > 0.
|
|
if (cb_args > 0u || num_mem_objects > 0u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// CL_INVALID_VALUE if args is not NULL and cb_args is 0.
|
|
if (cb_args == 0u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
}
|
|
|
|
if (num_mem_objects == 0u)
|
|
{
|
|
// CL_INVALID_VALUE if num_mem_objects = 0 and mem_list or args_mem_loc are not NULL.
|
|
if (mem_list != nullptr || args_mem_loc != nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// CL_INVALID_VALUE if num_mem_objects > 0 and mem_list or args_mem_loc are NULL.
|
|
if (mem_list == nullptr || args_mem_loc == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_MEM_OBJECT if one or more memory objects
|
|
// specified in mem_list are not valid or are not buffer objects.
|
|
while (num_mem_objects-- != 0u)
|
|
{
|
|
if (!Buffer::IsValid(*mem_list++))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateSetCommandQueueProperty(cl_command_queue command_queue,
|
|
CommandQueueProperties properties,
|
|
cl_bool enable,
|
|
const cl_command_queue_properties *old_properties)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid command-queue.
|
|
if (!CommandQueue::IsValid(command_queue))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if values specified in properties are not valid.
|
|
if (properties.hasOtherBitsThan(CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE |
|
|
CL_QUEUE_PROFILING_ENABLE))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateImage2D(cl_context context,
|
|
MemFlags flags,
|
|
const cl_image_format *image_format,
|
|
size_t image_width,
|
|
size_t image_height,
|
|
size_t image_row_pitch,
|
|
const void *host_ptr)
|
|
{
|
|
const cl_image_desc desc = {CL_MEM_OBJECT_IMAGE2D, image_width, image_height, 0u, 0u,
|
|
image_row_pitch, 0u, 0u, 0u, {nullptr}};
|
|
return ValidateCreateImage(context, flags, image_format, &desc, host_ptr);
|
|
}
|
|
|
|
cl_int ValidateCreateImage3D(cl_context context,
|
|
MemFlags flags,
|
|
const cl_image_format *image_format,
|
|
size_t image_width,
|
|
size_t image_height,
|
|
size_t image_depth,
|
|
size_t image_row_pitch,
|
|
size_t image_slice_pitch,
|
|
const void *host_ptr)
|
|
{
|
|
const cl_image_desc desc = {
|
|
CL_MEM_OBJECT_IMAGE3D, image_width, image_height, image_depth, 0u,
|
|
image_row_pitch, image_slice_pitch, 0u, 0u, {nullptr}};
|
|
return ValidateCreateImage(context, flags, image_format, &desc, host_ptr);
|
|
}
|
|
|
|
cl_int ValidateEnqueueMarker(cl_command_queue command_queue, const cl_event *event)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
|
|
if (!CommandQueue::IsValid(command_queue) || !command_queue->cast<CommandQueue>().isOnHost())
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if event is NULL.
|
|
if (event == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueWaitForEvents(cl_command_queue command_queue,
|
|
cl_uint num_events,
|
|
const cl_event *event_list)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
|
|
if (!CommandQueue::IsValid(command_queue))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
if (!queue.isOnHost())
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if num_events is 0 or event_list is NULL.
|
|
if (num_events == 0u || event_list == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
while (num_events-- != 0u)
|
|
{
|
|
// The documentation for invalid events is missing.
|
|
if (!Event::IsValid(*event_list))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_CONTEXT if context associated with command_queue
|
|
// and events in event_list are not the same.
|
|
if (&queue.getContext() != &(*event_list++)->cast<Event>().getContext())
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueBarrier(cl_command_queue command_queue)
|
|
{
|
|
// CL_INVALID_COMMAND_QUEUE if command_queue is not a valid host command-queue.
|
|
if (!CommandQueue::IsValid(command_queue) || !command_queue->cast<CommandQueue>().isOnHost())
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateUnloadCompiler()
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetExtensionFunctionAddress(const char *func_name)
|
|
{
|
|
return func_name != nullptr && *func_name != '\0' ? CL_SUCCESS : CL_INVALID_VALUE;
|
|
}
|
|
|
|
cl_int ValidateCreateCommandQueue(cl_context context,
|
|
cl_device_id device,
|
|
CommandQueueProperties properties)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValid(context))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_DEVICE if device is not a valid device or is not associated with context.
|
|
if (!context->cast<Context>().hasDevice(device))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if values specified in properties are not valid.
|
|
if (properties.hasOtherBitsThan(CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE |
|
|
CL_QUEUE_PROFILING_ENABLE))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateSampler(cl_context context,
|
|
cl_bool normalized_coords,
|
|
AddressingMode addressing_mode,
|
|
FilterMode filter_mode)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValid(context))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if addressing_mode, filter_mode, normalized_coords
|
|
// or a combination of these arguements are not valid.
|
|
if ((normalized_coords != CL_FALSE && normalized_coords != CL_TRUE) ||
|
|
addressing_mode == AddressingMode::InvalidEnum || filter_mode == FilterMode::InvalidEnum)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if images are not supported by any device associated with context.
|
|
if (!context->cast<Context>().supportsImages())
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueTask(cl_command_queue command_queue,
|
|
cl_kernel kernel,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
|
|
// CL_INVALID_KERNEL if kernel is not a valid kernel object.
|
|
if (!Kernel::IsValid(kernel))
|
|
{
|
|
return CL_INVALID_KERNEL;
|
|
}
|
|
|
|
// CL_INVALID_CONTEXT if context associated with command_queue and kernel are not the same.
|
|
if (&command_queue->cast<CommandQueue>().getContext() !=
|
|
&kernel->cast<Kernel>().getProgram().getContext())
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
// CL 1.1
|
|
cl_int ValidateCreateSubBuffer(cl_mem buffer,
|
|
MemFlags flags,
|
|
cl_buffer_create_type buffer_create_type,
|
|
const void *buffer_create_info)
|
|
{
|
|
// CL_INVALID_MEM_OBJECT if buffer is not a valid buffer object or is a sub-buffer object.
|
|
if (!Buffer::IsValid(buffer))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
const Buffer &buf = buffer->cast<Buffer>();
|
|
if (buf.isSubBuffer() || !buf.getContext().getPlatform().isVersionOrNewer(1u, 1u))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
if (!ValidateMemoryFlags(flags, buf.getContext().getPlatform()))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
const MemFlags bufFlags = buf.getFlags();
|
|
// CL_INVALID_VALUE if buffer was created with CL_MEM_WRITE_ONLY
|
|
// and flags specifies CL_MEM_READ_WRITE or CL_MEM_READ_ONLY,
|
|
if ((bufFlags.isSet(CL_MEM_WRITE_ONLY) && flags.isSet(CL_MEM_READ_WRITE | CL_MEM_READ_ONLY)) ||
|
|
// or if buffer was created with CL_MEM_READ_ONLY
|
|
// and flags specifies CL_MEM_READ_WRITE or CL_MEM_WRITE_ONLY,
|
|
(bufFlags.isSet(CL_MEM_READ_ONLY) && flags.isSet(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY)) ||
|
|
// or if flags specifies CL_MEM_USE_HOST_PTR, CL_MEM_ALLOC_HOST_PTR or CL_MEM_COPY_HOST_PTR.
|
|
flags.isSet(CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if buffer was created with CL_MEM_HOST_WRITE_ONLY
|
|
// and flags specify CL_MEM_HOST_READ_ONLY,
|
|
if ((bufFlags.isSet(CL_MEM_HOST_WRITE_ONLY) && flags.isSet(CL_MEM_HOST_READ_ONLY)) ||
|
|
// or if buffer was created with CL_MEM_HOST_READ_ONLY
|
|
// and flags specify CL_MEM_HOST_WRITE_ONLY,
|
|
(bufFlags.isSet(CL_MEM_HOST_READ_ONLY) && flags.isSet(CL_MEM_HOST_WRITE_ONLY)) ||
|
|
// or if buffer was created with CL_MEM_HOST_NO_ACCESS
|
|
// and flags specify CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_WRITE_ONLY.
|
|
(bufFlags.isSet(CL_MEM_HOST_NO_ACCESS) &&
|
|
flags.isSet(CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_WRITE_ONLY)))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if the value specified in buffer_create_type is not valid.
|
|
if (buffer_create_type != CL_BUFFER_CREATE_TYPE_REGION)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if value(s) specified in buffer_create_info
|
|
// (for a given buffer_create_type) is not valid or if buffer_create_info is NULL.
|
|
// CL_INVALID_VALUE if the region specified by the cl_buffer_region structure
|
|
// passed in buffer_create_info is out of bounds in buffer.
|
|
const cl_buffer_region *region = static_cast<const cl_buffer_region *>(buffer_create_info);
|
|
if (region == nullptr || !buf.isRegionValid(*region))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_BUFFER_SIZE if the size field of the cl_buffer_region structure
|
|
// passed in buffer_create_info is 0.
|
|
if (region->size == 0u)
|
|
{
|
|
return CL_INVALID_BUFFER_SIZE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateSetMemObjectDestructorCallback(cl_mem memobj,
|
|
void(CL_CALLBACK *pfn_notify)(cl_mem memobj,
|
|
void *user_data),
|
|
const void *user_data)
|
|
{
|
|
// CL_INVALID_MEM_OBJECT if memobj is not a valid memory object.
|
|
if (!Memory::IsValid(memobj))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if pfn_notify is NULL.
|
|
if (pfn_notify == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateUserEvent(cl_context context)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
return Context::IsValidAndVersionOrNewer(context, 1u, 1u) ? CL_SUCCESS : CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
cl_int ValidateSetUserEventStatus(cl_event event, cl_int execution_status)
|
|
{
|
|
// CL_INVALID_EVENT if event is not a valid user event object.
|
|
if (!Event::IsValid(event))
|
|
{
|
|
return CL_INVALID_EVENT;
|
|
}
|
|
const Event &evt = event->cast<Event>();
|
|
if (!evt.getContext().getPlatform().isVersionOrNewer(1u, 1u) ||
|
|
evt.getCommandType() != CL_COMMAND_USER)
|
|
{
|
|
return CL_INVALID_EVENT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if the execution_status is not CL_COMPLETE or a negative integer value.
|
|
if (execution_status != CL_COMPLETE && execution_status >= 0)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if the execution_status for event has already been changed
|
|
// by a previous call to clSetUserEventStatus.
|
|
if (evt.wasStatusChanged())
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateSetEventCallback(cl_event event,
|
|
cl_int command_exec_callback_type,
|
|
void(CL_CALLBACK *pfn_notify)(cl_event event,
|
|
cl_int event_command_status,
|
|
void *user_data),
|
|
const void *user_data)
|
|
{
|
|
// CL_INVALID_EVENT if event is not a valid event object.
|
|
if (!Event::IsValid(event) ||
|
|
!event->cast<Event>().getContext().getPlatform().isVersionOrNewer(1u, 1u))
|
|
{
|
|
return CL_INVALID_EVENT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if pfn_event_notify is NULL
|
|
// or if command_exec_callback_type is not CL_SUBMITTED, CL_RUNNING, or CL_COMPLETE.
|
|
if (pfn_notify == nullptr ||
|
|
(command_exec_callback_type != CL_SUBMITTED && command_exec_callback_type != CL_RUNNING &&
|
|
command_exec_callback_type != CL_COMPLETE))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueReadBufferRect(cl_command_queue command_queue,
|
|
cl_mem buffer,
|
|
cl_bool blocking_read,
|
|
const size_t *buffer_origin,
|
|
const size_t *host_origin,
|
|
const size_t *region,
|
|
size_t buffer_row_pitch,
|
|
size_t buffer_slice_pitch,
|
|
size_t host_row_pitch,
|
|
size_t host_slice_pitch,
|
|
const void *ptr,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
if (!queue.getContext().getPlatform().isVersionOrNewer(1u, 1u))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(queue, buffer, true, false));
|
|
ANGLE_CL_TRY(ValidateBufferRect(buffer->cast<Buffer>(), buffer_origin, region, buffer_row_pitch,
|
|
buffer_slice_pitch));
|
|
ANGLE_CL_TRY(ValidateHostRect(host_origin, region, host_row_pitch, host_slice_pitch, ptr));
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueWriteBufferRect(cl_command_queue command_queue,
|
|
cl_mem buffer,
|
|
cl_bool blocking_write,
|
|
const size_t *buffer_origin,
|
|
const size_t *host_origin,
|
|
const size_t *region,
|
|
size_t buffer_row_pitch,
|
|
size_t buffer_slice_pitch,
|
|
size_t host_row_pitch,
|
|
size_t host_slice_pitch,
|
|
const void *ptr,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
if (!queue.getContext().getPlatform().isVersionOrNewer(1u, 1u))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(queue, buffer, false, true));
|
|
ANGLE_CL_TRY(ValidateBufferRect(buffer->cast<Buffer>(), buffer_origin, region, buffer_row_pitch,
|
|
buffer_slice_pitch));
|
|
ANGLE_CL_TRY(ValidateHostRect(host_origin, region, host_row_pitch, host_slice_pitch, ptr));
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueCopyBufferRect(cl_command_queue command_queue,
|
|
cl_mem src_buffer,
|
|
cl_mem dst_buffer,
|
|
const size_t *src_origin,
|
|
const size_t *dst_origin,
|
|
const size_t *region,
|
|
size_t src_row_pitch,
|
|
size_t src_slice_pitch,
|
|
size_t dst_row_pitch,
|
|
size_t dst_slice_pitch,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
if (!queue.getContext().getPlatform().isVersionOrNewer(1u, 1u))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(queue, src_buffer, false, false));
|
|
const Buffer &src = src_buffer->cast<Buffer>();
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(queue, dst_buffer, false, false));
|
|
const Buffer &dst = dst_buffer->cast<Buffer>();
|
|
|
|
ANGLE_CL_TRY(ValidateBufferRect(src, src_origin, region, src_row_pitch, src_slice_pitch));
|
|
ANGLE_CL_TRY(ValidateBufferRect(dst, dst_origin, region, dst_row_pitch, dst_slice_pitch));
|
|
|
|
// CL_INVALID_VALUE if src_buffer and dst_buffer are the same buffer object and src_slice_pitch
|
|
// is not equal to dst_slice_pitch or src_row_pitch is not equal to dst_row_pitch.
|
|
if (&src == &dst && (src_slice_pitch != dst_slice_pitch || src_row_pitch != dst_row_pitch))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
// CL 1.2
|
|
cl_int ValidateCreateSubDevices(cl_device_id in_device,
|
|
const cl_device_partition_property *properties,
|
|
cl_uint num_devices,
|
|
const cl_device_id *out_devices,
|
|
const cl_uint *num_devices_ret)
|
|
{
|
|
// CL_INVALID_DEVICE if in_device is not a valid device.
|
|
if (!Device::IsValid(in_device))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
const Device &device = in_device->cast<Device>();
|
|
if (!device.isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if values specified in properties are not valid
|
|
// or if values specified in properties are valid but not supported by the device
|
|
const std::vector<cl_device_partition_property> &devProps =
|
|
device.getInfo().partitionProperties;
|
|
if (properties == nullptr ||
|
|
std::find(devProps.cbegin(), devProps.cend(), *properties) == devProps.cend())
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateRetainDevice(cl_device_id device)
|
|
{
|
|
// CL_INVALID_DEVICE if device is not a valid device.
|
|
if (!Device::IsValid(device) || !device->cast<Device>().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateReleaseDevice(cl_device_id device)
|
|
{
|
|
// CL_INVALID_DEVICE if device is not a valid device.
|
|
if (!Device::IsValid(device) || !device->cast<Device>().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateImage(cl_context context,
|
|
MemFlags flags,
|
|
const cl_image_format *image_format,
|
|
const cl_image_desc *image_desc,
|
|
const void *host_ptr)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValidAndVersionOrNewer(context, 1u, 2u))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
const Context &ctx = context->cast<Context>();
|
|
|
|
// CL_INVALID_VALUE if values specified in flags are not valid.
|
|
if (!ValidateMemoryFlags(flags, ctx.getPlatform()))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_IMAGE_FORMAT_DESCRIPTOR if values specified in image_format are not valid
|
|
// or if image_format is NULL.
|
|
if (!IsValidImageFormat(image_format, ctx.getPlatform().getInfo()))
|
|
{
|
|
return CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
|
|
}
|
|
|
|
// CL_INVALID_IMAGE_DESCRIPTOR if image_desc is NULL.
|
|
if (image_desc == nullptr)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
|
|
const size_t elemSize = GetElementSize(*image_format);
|
|
if (elemSize == 0u)
|
|
{
|
|
ASSERT(false);
|
|
ERR() << "Failed to calculate image element size";
|
|
return CL_INVALID_IMAGE_FORMAT_DESCRIPTOR;
|
|
}
|
|
const size_t rowPitch = image_desc->image_row_pitch != 0u ? image_desc->image_row_pitch
|
|
: image_desc->image_width * elemSize;
|
|
const size_t imageHeight =
|
|
image_desc->image_type == CL_MEM_OBJECT_IMAGE1D_ARRAY ? 1u : image_desc->image_height;
|
|
const size_t sliceSize = imageHeight * rowPitch;
|
|
|
|
// CL_INVALID_IMAGE_DESCRIPTOR if values specified in image_desc are not valid.
|
|
switch (FromCLenum<MemObjectType>(image_desc->image_type))
|
|
{
|
|
case MemObjectType::Image1D:
|
|
if (image_desc->image_width == 0u)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
break;
|
|
case MemObjectType::Image2D:
|
|
if (image_desc->image_width == 0u || image_desc->image_height == 0u)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
break;
|
|
case MemObjectType::Image3D:
|
|
if (image_desc->image_width == 0u || image_desc->image_height == 0u ||
|
|
image_desc->image_depth == 0u)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
break;
|
|
case MemObjectType::Image1D_Array:
|
|
if (image_desc->image_width == 0u || image_desc->image_array_size == 0u)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
break;
|
|
case MemObjectType::Image2D_Array:
|
|
if (image_desc->image_width == 0u || image_desc->image_height == 0u ||
|
|
image_desc->image_array_size == 0u)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
break;
|
|
case MemObjectType::Image1D_Buffer:
|
|
if (image_desc->image_width == 0u)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
break;
|
|
default:
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
if (image_desc->image_row_pitch != 0u)
|
|
{
|
|
// image_row_pitch must be 0 if host_ptr is NULL.
|
|
if (host_ptr == nullptr)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
// image_row_pitch can be either 0
|
|
// or >= image_width * size of element in bytes if host_ptr is not NULL.
|
|
if (image_desc->image_row_pitch < image_desc->image_width * elemSize)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
// If image_row_pitch is not 0, it must be a multiple of the image element size in bytes.
|
|
if ((image_desc->image_row_pitch % elemSize) != 0u)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
}
|
|
if (image_desc->image_slice_pitch != 0u)
|
|
{
|
|
// image_slice_pitch must be 0 if host_ptr is NULL.
|
|
if (host_ptr == nullptr)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
// If host_ptr is not NULL, image_slice_pitch can be either 0
|
|
// or >= image_row_pitch * image_height for a 2D image array or 3D image
|
|
// and can be either 0 or >= image_row_pitch for a 1D image array.
|
|
if (image_desc->image_slice_pitch < sliceSize)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
// If image_slice_pitch is not 0, it must be a multiple of the image_row_pitch.
|
|
if ((image_desc->image_slice_pitch % rowPitch) != 0u)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
}
|
|
// num_mip_levels and num_samples must be 0.
|
|
if (image_desc->num_mip_levels != 0u || image_desc->num_samples != 0u)
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
// buffer can be a buffer memory object if image_type is CL_MEM_OBJECT_IMAGE1D_BUFFER or
|
|
// CL_MEM_OBJECT_IMAGE2D. buffer can be an image object if image_type is CL_MEM_OBJECT_IMAGE2D.
|
|
// Otherwise it must be NULL.
|
|
if (image_desc->buffer != nullptr &&
|
|
(!Buffer::IsValid(image_desc->buffer) ||
|
|
(image_desc->image_type != CL_MEM_OBJECT_IMAGE1D_BUFFER &&
|
|
image_desc->image_type != CL_MEM_OBJECT_IMAGE2D)) &&
|
|
(!Image::IsValid(image_desc->buffer) || image_desc->image_type != CL_MEM_OBJECT_IMAGE2D))
|
|
{
|
|
return CL_INVALID_IMAGE_DESCRIPTOR;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if there are no devices in context that support images.
|
|
if (!ctx.supportsImages())
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
// CL_INVALID_IMAGE_SIZE if image dimensions specified in image_desc exceed the maximum
|
|
// image dimensions described in the Device Queries table for all devices in context.
|
|
const DevicePtrs &devices = ctx.getDevices();
|
|
if (std::find_if(devices.cbegin(), devices.cend(), [&](const DevicePtr &ptr) {
|
|
return ptr->supportsNativeImageDimensions(*image_desc);
|
|
}) == devices.cend())
|
|
{
|
|
return CL_INVALID_IMAGE_SIZE;
|
|
}
|
|
|
|
// CL_INVALID_HOST_PTR
|
|
// if host_ptr is NULL and CL_MEM_USE_HOST_PTR or CL_MEM_COPY_HOST_PTR are set in flags or
|
|
// if host_ptr is not NULL but CL_MEM_COPY_HOST_PTR or CL_MEM_USE_HOST_PTR are not set in flags.
|
|
if ((host_ptr != nullptr) != flags.isSet(CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR))
|
|
{
|
|
return CL_INVALID_HOST_PTR;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateProgramWithBuiltInKernels(cl_context context,
|
|
cl_uint num_devices,
|
|
const cl_device_id *device_list,
|
|
const char *kernel_names)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValidAndVersionOrNewer(context, 1u, 2u))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
const Context &ctx = context->cast<Context>();
|
|
|
|
// CL_INVALID_VALUE if device_list is NULL or num_devices is zero or if kernel_names is NULL.
|
|
if (device_list == nullptr || num_devices == 0u || kernel_names == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_DEVICE if any device in device_list
|
|
// is not in the list of devices associated with context.
|
|
for (size_t index = 0u; index < num_devices; ++index)
|
|
{
|
|
if (!ctx.hasDevice(device_list[index]))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_VALUE if kernel_names contains a kernel name
|
|
// that is not supported by any of the devices in device_list.
|
|
const char *start = kernel_names;
|
|
do
|
|
{
|
|
const char *end = start;
|
|
while (*end != '\0' && *end != ';')
|
|
{
|
|
++end;
|
|
}
|
|
const size_t length = end - start;
|
|
if (length != 0u && !ctx.supportsBuiltInKernel(std::string(start, length)))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
start = end;
|
|
} while (*start++ != '\0');
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCompileProgram(cl_program program,
|
|
cl_uint num_devices,
|
|
const cl_device_id *device_list,
|
|
const char *options,
|
|
cl_uint num_input_headers,
|
|
const cl_program *input_headers,
|
|
const char **header_include_names,
|
|
void(CL_CALLBACK *pfn_notify)(cl_program program, void *user_data),
|
|
const void *user_data)
|
|
{
|
|
// CL_INVALID_PROGRAM if program is not a valid program object.
|
|
if (!Program::IsValid(program))
|
|
{
|
|
return CL_INVALID_PROGRAM;
|
|
}
|
|
const Program &prog = program->cast<Program>();
|
|
if (!prog.getContext().getPlatform().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_PROGRAM;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if device_list is NULL and num_devices is greater than zero,
|
|
// or if device_list is not NULL and num_devices is zero.
|
|
if ((device_list != nullptr) != (num_devices != 0u))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_DEVICE if any device in device_list
|
|
// is not in the list of devices associated with program.
|
|
while (num_devices-- != 0u)
|
|
{
|
|
if (!prog.hasDevice(*device_list++))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_VALUE if num_input_headers is zero and header_include_names
|
|
// or input_headers are not NULL
|
|
// or if num_input_headers is not zero and header_include_names or input_headers are NULL.
|
|
if ((num_input_headers != 0u) != (header_include_names != nullptr) ||
|
|
(num_input_headers != 0u) != (input_headers != nullptr))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if pfn_notify is NULL but user_data is not NULL.
|
|
if (pfn_notify == nullptr && user_data != nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if the build of a program executable for any of the devices listed
|
|
// in device_list by a previous call to clBuildProgram for program has not completed.
|
|
if (prog.isBuilding())
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if there are kernel objects attached to program.
|
|
if (prog.hasAttachedKernels())
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateLinkProgram(cl_context context,
|
|
cl_uint num_devices,
|
|
const cl_device_id *device_list,
|
|
const char *options,
|
|
cl_uint num_input_programs,
|
|
const cl_program *input_programs,
|
|
void(CL_CALLBACK *pfn_notify)(cl_program program, void *user_data),
|
|
const void *user_data)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValidAndVersionOrNewer(context, 1u, 2u))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
const Context &ctx = context->cast<Context>();
|
|
|
|
// CL_INVALID_VALUE if device_list is NULL and num_devices is greater than zero,
|
|
// or if device_list is not NULL and num_devices is zero.
|
|
if ((device_list != nullptr) != (num_devices != 0u))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_DEVICE if any device in device_list
|
|
// is not in the list of devices associated with context.
|
|
while (num_devices-- != 0u)
|
|
{
|
|
if (!ctx.hasDevice(*device_list++))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_VALUE if num_input_programs is zero or input_programs is NULL.
|
|
if (num_input_programs == 0u || input_programs == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_PROGRAM if programs specified in input_programs are not valid program objects.
|
|
while (num_input_programs-- != 0u)
|
|
{
|
|
if (!Program::IsValid(*input_programs++))
|
|
{
|
|
return CL_INVALID_PROGRAM;
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_VALUE if pfn_notify is NULL but user_data is not NULL.
|
|
if (pfn_notify == nullptr && user_data != nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateUnloadPlatformCompiler(cl_platform_id platform)
|
|
{
|
|
// CL_INVALID_PLATFORM if platform is not a valid platform.
|
|
if (!Platform::IsValid(platform) || !platform->cast<Platform>().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_PLATFORM;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetKernelArgInfo(cl_kernel kernel,
|
|
cl_uint arg_index,
|
|
KernelArgInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
// CL_INVALID_KERNEL if kernel is a not a valid kernel object.
|
|
if (!Kernel::IsValid(kernel))
|
|
{
|
|
return CL_INVALID_KERNEL;
|
|
}
|
|
const Kernel &krnl = kernel->cast<Kernel>();
|
|
if (!krnl.getProgram().getContext().getPlatform().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_KERNEL;
|
|
}
|
|
|
|
// CL_INVALID_ARG_INDEX if arg_index is not a valid argument index.
|
|
if (arg_index >= krnl.getInfo().args.size())
|
|
{
|
|
return CL_INVALID_ARG_INDEX;
|
|
}
|
|
|
|
// CL_KERNEL_ARG_INFO_NOT_AVAILABLE if the argument information is not available for kernel.
|
|
if (!krnl.getInfo().args[arg_index].isAvailable())
|
|
{
|
|
return CL_KERNEL_ARG_INFO_NOT_AVAILABLE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if param_name is not valid.
|
|
if (param_name == KernelArgInfo::InvalidEnum)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueFillBuffer(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,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
if (!queue.getContext().getPlatform().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueBuffer(queue, buffer, false, false));
|
|
|
|
// CL_INVALID_VALUE if offset or offset + size require accessing
|
|
// elements outside the buffer object respectively.
|
|
if (!buffer->cast<Buffer>().isRegionValid(offset, size))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if pattern is NULL or if pattern_size is 0 or
|
|
// if pattern_size is not one of { 1, 2, 4, 8, 16, 32, 64, 128 }.
|
|
if (pattern == nullptr || pattern_size == 0u || pattern_size > 128u ||
|
|
(pattern_size & (pattern_size - 1u)) != 0u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if offset and size are not a multiple of pattern_size.
|
|
if ((offset % pattern_size) != 0u || (size % pattern_size) != 0u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueFillImage(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,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, true, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
if (!queue.getContext().getPlatform().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
ANGLE_CL_TRY(ValidateEnqueueImage(queue, image, false, false));
|
|
const Image &img = image->cast<Image>();
|
|
|
|
ANGLE_CL_TRY(ValidateImageForDevice(img, queue.getDevice(), origin, region));
|
|
|
|
// CL_INVALID_VALUE if fill_color is NULL.
|
|
if (fill_color == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueMigrateMemObjects(cl_command_queue command_queue,
|
|
cl_uint num_mem_objects,
|
|
const cl_mem *mem_objects,
|
|
MemMigrationFlags flags,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
const CommandQueue &queue = command_queue->cast<CommandQueue>();
|
|
if (!queue.getContext().getPlatform().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if num_mem_objects is zero or if mem_objects is NULL.
|
|
if (num_mem_objects == 0u || mem_objects == nullptr)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
while (num_mem_objects-- != 0u)
|
|
{
|
|
// CL_INVALID_MEM_OBJECT if any of the memory objects
|
|
// in mem_objects is not a valid memory object.
|
|
if (!Memory::IsValid(*mem_objects))
|
|
{
|
|
return CL_INVALID_MEM_OBJECT;
|
|
}
|
|
|
|
// CL_INVALID_CONTEXT if the context associated with command_queue
|
|
// and memory objects in mem_objects are not the same.
|
|
if (&queue.getContext() != &(*mem_objects++)->cast<Memory>().getContext())
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_VALUE if flags is not 0 or is not any of the values described in the table.
|
|
const MemMigrationFlags allowedFlags(CL_MIGRATE_MEM_OBJECT_HOST |
|
|
CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED);
|
|
if (flags.hasOtherBitsThan(allowedFlags))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueMarkerWithWaitList(cl_command_queue command_queue,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
if (!command_queue->cast<CommandQueue>().getContext().getPlatform().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueBarrierWithWaitList(cl_command_queue command_queue,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCommandQueueAndEventWaitList(command_queue, false, num_events_in_wait_list,
|
|
event_wait_list));
|
|
if (!command_queue->cast<CommandQueue>().getContext().getPlatform().isVersionOrNewer(1u, 2u))
|
|
{
|
|
return CL_INVALID_COMMAND_QUEUE;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetExtensionFunctionAddressForPlatform(cl_platform_id platform,
|
|
const char *func_name)
|
|
{
|
|
if (!Platform::IsValid(platform) || func_name == nullptr || *func_name == '\0')
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
// CL 2.0
|
|
cl_int ValidateCreateCommandQueueWithProperties(cl_context context,
|
|
cl_device_id device,
|
|
const cl_queue_properties *properties)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValidAndVersionOrNewer(context, 2u, 0u))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_DEVICE if device is not a valid device or is not associated with context.
|
|
if (!context->cast<Context>().hasDevice(device) ||
|
|
!device->cast<Device>().isVersionOrNewer(2u, 0u))
|
|
{
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if values specified in properties are not valid.
|
|
if (properties != nullptr)
|
|
{
|
|
bool isQueueOnDevice = false;
|
|
bool hasQueueSize = false;
|
|
while (*properties != 0)
|
|
{
|
|
switch (*properties++)
|
|
{
|
|
case CL_QUEUE_PROPERTIES:
|
|
{
|
|
const CommandQueueProperties props(*properties++);
|
|
const CommandQueueProperties validProps(
|
|
CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE | CL_QUEUE_PROFILING_ENABLE |
|
|
CL_QUEUE_ON_DEVICE | CL_QUEUE_ON_DEVICE_DEFAULT);
|
|
if (props.hasOtherBitsThan(validProps) ||
|
|
// If CL_QUEUE_ON_DEVICE is set, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE
|
|
// must also be set.
|
|
(props.isSet(CL_QUEUE_ON_DEVICE) &&
|
|
!props.isSet(CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE)) ||
|
|
// CL_QUEUE_ON_DEVICE_DEFAULT can only be used with CL_QUEUE_ON_DEVICE.
|
|
(props.isSet(CL_QUEUE_ON_DEVICE_DEFAULT) &&
|
|
!props.isSet(CL_QUEUE_ON_DEVICE)))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
isQueueOnDevice = props.isSet(CL_QUEUE_ON_DEVICE);
|
|
break;
|
|
}
|
|
case CL_QUEUE_SIZE:
|
|
{
|
|
// CL_QUEUE_SIZE must be a value <= CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE.
|
|
if (*properties++ > device->cast<Device>().getInfo().queueOnDeviceMaxSize)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
hasQueueSize = true;
|
|
break;
|
|
}
|
|
default:
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
}
|
|
|
|
// CL_QUEUE_SIZE can only be specified if CL_QUEUE_ON_DEVICE is set in CL_QUEUE_PROPERTIES.
|
|
if (hasQueueSize && !isQueueOnDevice)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreatePipe(cl_context context,
|
|
MemFlags flags,
|
|
cl_uint pipe_packet_size,
|
|
cl_uint pipe_max_packets,
|
|
const cl_pipe_properties *properties)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetPipeInfo(cl_mem pipe,
|
|
PipeInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateSVMAlloc(cl_context context, SVM_MemFlags flags, size_t size, cl_uint alignment)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateSVMFree(cl_context context, const void *svm_pointer)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateSamplerWithProperties(cl_context context,
|
|
const cl_sampler_properties *sampler_properties)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValidAndVersionOrNewer(context, 2u, 0u))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if the property name in sampler_properties is not a supported property name,
|
|
// if the value specified for a supported property name is not valid,
|
|
// or if the same property name is specified more than once.
|
|
if (sampler_properties != nullptr)
|
|
{
|
|
bool hasNormalizedCoords = false;
|
|
bool hasAddressingMode = false;
|
|
bool hasFilterMode = false;
|
|
const cl_sampler_properties *propIt = sampler_properties;
|
|
while (*propIt != 0)
|
|
{
|
|
switch (*propIt++)
|
|
{
|
|
case CL_SAMPLER_NORMALIZED_COORDS:
|
|
if (hasNormalizedCoords || (*propIt != CL_FALSE && *propIt != CL_TRUE))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
hasNormalizedCoords = true;
|
|
++propIt;
|
|
break;
|
|
case CL_SAMPLER_ADDRESSING_MODE:
|
|
if (hasAddressingMode || FromCLenum<AddressingMode>(static_cast<CLenum>(
|
|
*propIt++)) == AddressingMode::InvalidEnum)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
hasAddressingMode = true;
|
|
break;
|
|
case CL_SAMPLER_FILTER_MODE:
|
|
if (hasFilterMode || FromCLenum<FilterMode>(static_cast<CLenum>(*propIt++)) ==
|
|
FilterMode::InvalidEnum)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
hasFilterMode = true;
|
|
break;
|
|
default:
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// CL_INVALID_OPERATION if images are not supported by any device associated with context.
|
|
if (!context->cast<Context>().supportsImages())
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateSetKernelArgSVMPointer(cl_kernel kernel, cl_uint arg_index, const void *arg_value)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateSetKernelExecInfo(cl_kernel kernel,
|
|
KernelExecInfo param_name,
|
|
size_t param_value_size,
|
|
const void *param_value)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueSVMFree(cl_command_queue command_queue,
|
|
cl_uint num_svm_pointers,
|
|
void *const svm_pointers[],
|
|
void(CL_CALLBACK *pfn_free_func)(cl_command_queue queue,
|
|
cl_uint num_svm_pointers,
|
|
void *svm_pointers[],
|
|
void *user_data),
|
|
const void *user_data,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueSVMMemcpy(cl_command_queue command_queue,
|
|
cl_bool blocking_copy,
|
|
const void *dst_ptr,
|
|
const void *src_ptr,
|
|
size_t size,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueSVMMemFill(cl_command_queue command_queue,
|
|
const 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,
|
|
const cl_event *event)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueSVMMap(cl_command_queue command_queue,
|
|
cl_bool blocking_map,
|
|
MapFlags flags,
|
|
const void *svm_ptr,
|
|
size_t size,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueSVMUnmap(cl_command_queue command_queue,
|
|
const void *svm_ptr,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
// CL 2.1
|
|
cl_int ValidateSetDefaultDeviceCommandQueue(cl_context context,
|
|
cl_device_id device,
|
|
cl_command_queue command_queue)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetDeviceAndHostTimer(cl_device_id device,
|
|
const cl_ulong *device_timestamp,
|
|
const cl_ulong *host_timestamp)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetHostTimer(cl_device_id device, const cl_ulong *host_timestamp)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateProgramWithIL(cl_context context, const void *il, size_t length)
|
|
{
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!Context::IsValidAndVersionOrNewer(context, 2u, 1u))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
const Context &ctx = context->cast<Context>();
|
|
|
|
// CL_INVALID_OPERATION if no devices in context support intermediate language programs.
|
|
if (!ctx.supportsIL())
|
|
{
|
|
return CL_INVALID_OPERATION;
|
|
}
|
|
|
|
// CL_INVALID_VALUE if il is NULL or if length is zero.
|
|
if (il == nullptr || length == 0u)
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCloneKernel(cl_kernel source_kernel)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateGetKernelSubGroupInfo(cl_kernel kernel,
|
|
cl_device_id device,
|
|
KernelSubGroupInfo param_name,
|
|
size_t input_value_size,
|
|
const void *input_value,
|
|
size_t param_value_size,
|
|
const void *param_value,
|
|
const size_t *param_value_size_ret)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateEnqueueSVMMigrateMem(cl_command_queue command_queue,
|
|
cl_uint num_svm_pointers,
|
|
const void **svm_pointers,
|
|
const size_t *sizes,
|
|
MemMigrationFlags flags,
|
|
cl_uint num_events_in_wait_list,
|
|
const cl_event *event_wait_list,
|
|
const cl_event *event)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
// CL 2.2
|
|
cl_int ValidateSetProgramReleaseCallback(cl_program program,
|
|
void(CL_CALLBACK *pfn_notify)(cl_program program,
|
|
void *user_data),
|
|
const void *user_data)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateSetProgramSpecializationConstant(cl_program program,
|
|
cl_uint spec_id,
|
|
size_t spec_size,
|
|
const void *spec_value)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
// CL 3.0
|
|
cl_int ValidateSetContextDestructorCallback(cl_context context,
|
|
void(CL_CALLBACK *pfn_notify)(cl_context context,
|
|
void *user_data),
|
|
const void *user_data)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateBufferWithProperties(cl_context context,
|
|
const cl_mem_properties *properties,
|
|
MemFlags flags,
|
|
size_t size,
|
|
const void *host_ptr)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCreateBuffer(context, flags, size, host_ptr));
|
|
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!context->cast<Context>().getPlatform().isVersionOrNewer(3u, 0u))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_PROPERTY if a property name in properties is not a supported property name,
|
|
// if the value specified for a supported property name is not valid,
|
|
// or if the same property name is specified more than once.
|
|
if (!ValidateMemoryProperties(properties))
|
|
{
|
|
return CL_INVALID_PROPERTY;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_int ValidateCreateImageWithProperties(cl_context context,
|
|
const cl_mem_properties *properties,
|
|
MemFlags flags,
|
|
const cl_image_format *image_format,
|
|
const cl_image_desc *image_desc,
|
|
const void *host_ptr)
|
|
{
|
|
ANGLE_CL_TRY(ValidateCreateImage(context, flags, image_format, image_desc, host_ptr));
|
|
|
|
// CL_INVALID_CONTEXT if context is not a valid context.
|
|
if (!context->cast<Context>().getPlatform().isVersionOrNewer(3u, 0u))
|
|
{
|
|
return CL_INVALID_CONTEXT;
|
|
}
|
|
|
|
// CL_INVALID_PROPERTY if a property name in properties is not a supported property name,
|
|
// if the value specified for a supported property name is not valid,
|
|
// or if the same property name is specified more than once.
|
|
if (!ValidateMemoryProperties(properties))
|
|
{
|
|
return CL_INVALID_PROPERTY;
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
// cl_khr_icd
|
|
cl_int ValidateIcdGetPlatformIDsKHR(cl_uint num_entries,
|
|
const cl_platform_id *platforms,
|
|
const cl_uint *num_platforms)
|
|
{
|
|
if ((num_entries == 0u && platforms != nullptr) ||
|
|
(platforms == nullptr && num_platforms == nullptr))
|
|
{
|
|
return CL_INVALID_VALUE;
|
|
}
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
} // namespace cl
|