| // |
| // 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 |