| // |
| // 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. |
| // |
| // CLDevice.cpp: Implements the cl::Device class. |
| |
| #include "libANGLE/CLDevice.h" |
| |
| #include "libANGLE/CLPlatform.h" |
| |
| #include "common/string_utils.h" |
| |
| #include <cstring> |
| |
| namespace cl |
| { |
| |
| cl_int Device::getInfo(DeviceInfo name, size_t valueSize, void *value, size_t *valueSizeRet) const |
| { |
| static_assert(std::is_same<cl_uint, cl_bool>::value && |
| std::is_same<cl_uint, cl_device_mem_cache_type>::value && |
| std::is_same<cl_uint, cl_device_local_mem_type>::value && |
| std::is_same<cl_uint, cl_version>::value && |
| std::is_same<cl_ulong, cl_device_type>::value && |
| std::is_same<cl_ulong, cl_device_fp_config>::value && |
| std::is_same<cl_ulong, cl_device_exec_capabilities>::value && |
| std::is_same<cl_ulong, cl_command_queue_properties>::value && |
| std::is_same<cl_ulong, cl_device_affinity_domain>::value && |
| std::is_same<cl_ulong, cl_device_svm_capabilities>::value && |
| std::is_same<cl_ulong, cl_device_atomic_capabilities>::value && |
| std::is_same<cl_ulong, cl_device_device_enqueue_capabilities>::value, |
| "OpenCL type mismatch"); |
| |
| cl_uint valUInt = 0u; |
| cl_ulong valULong = 0u; |
| size_t valSizeT = 0u; |
| void *valPointer = nullptr; |
| std::vector<char> valString; |
| |
| const void *copyValue = nullptr; |
| size_t copySize = 0u; |
| cl_int result = CL_SUCCESS; |
| |
| // The info names are sorted within their type group in the order they appear in the OpenCL |
| // specification, so it is easier to compare them side-by-side when looking for changes. |
| // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clGetDeviceInfo |
| switch (name) |
| { |
| // Handle all cl_uint and aliased types |
| case DeviceInfo::VendorID: |
| case DeviceInfo::MaxComputeUnits: |
| case DeviceInfo::PreferredVectorWidthChar: |
| case DeviceInfo::PreferredVectorWidthShort: |
| case DeviceInfo::PreferredVectorWidthInt: |
| case DeviceInfo::PreferredVectorWidthLong: |
| case DeviceInfo::PreferredVectorWidthFloat: |
| case DeviceInfo::PreferredVectorWidthDouble: |
| 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::MaxClockFrequency: |
| case DeviceInfo::AddressBits: |
| case DeviceInfo::MaxReadImageArgs: |
| case DeviceInfo::MaxWriteImageArgs: |
| case DeviceInfo::MaxReadWriteImageArgs: |
| case DeviceInfo::MaxSamplers: |
| case DeviceInfo::MaxPipeArgs: |
| case DeviceInfo::PipeMaxActiveReservations: |
| case DeviceInfo::PipeMaxPacketSize: |
| case DeviceInfo::MinDataTypeAlignSize: |
| case DeviceInfo::GlobalMemCacheType: |
| case DeviceInfo::GlobalMemCachelineSize: |
| case DeviceInfo::MaxConstantArgs: |
| case DeviceInfo::LocalMemType: |
| case DeviceInfo::ErrorCorrectionSupport: |
| case DeviceInfo::HostUnifiedMemory: |
| case DeviceInfo::EndianLittle: |
| case DeviceInfo::Available: |
| case DeviceInfo::CompilerAvailable: |
| case DeviceInfo::LinkerAvailable: |
| case DeviceInfo::QueueOnDevicePreferredSize: |
| case DeviceInfo::MaxOnDeviceQueues: |
| case DeviceInfo::MaxOnDeviceEvents: |
| case DeviceInfo::PreferredInteropUserSync: |
| case DeviceInfo::PartitionMaxSubDevices: |
| case DeviceInfo::PreferredPlatformAtomicAlignment: |
| case DeviceInfo::PreferredGlobalAtomicAlignment: |
| case DeviceInfo::PreferredLocalAtomicAlignment: |
| case DeviceInfo::MaxNumSubGroups: |
| case DeviceInfo::SubGroupIndependentForwardProgress: |
| case DeviceInfo::NonUniformWorkGroupSupport: |
| case DeviceInfo::WorkGroupCollectiveFunctionsSupport: |
| case DeviceInfo::GenericAddressSpaceSupport: |
| case DeviceInfo::PipeSupport: |
| result = mImpl->getInfoUInt(name, &valUInt); |
| copyValue = &valUInt; |
| copySize = sizeof(valUInt); |
| break; |
| |
| // Handle all cl_ulong and aliased types |
| case DeviceInfo::SingleFpConfig: |
| case DeviceInfo::DoubleFpConfig: |
| case DeviceInfo::GlobalMemCacheSize: |
| case DeviceInfo::GlobalMemSize: |
| case DeviceInfo::MaxConstantBufferSize: |
| case DeviceInfo::LocalMemSize: |
| case DeviceInfo::QueueOnHostProperties: |
| case DeviceInfo::QueueOnDeviceProperties: |
| case DeviceInfo::PartitionAffinityDomain: |
| case DeviceInfo::SVM_Capabilities: |
| case DeviceInfo::AtomicMemoryCapabilities: |
| case DeviceInfo::AtomicFenceCapabilities: |
| case DeviceInfo::DeviceEnqueueCapabilities: |
| case DeviceInfo::HalfFpConfig: |
| result = mImpl->getInfoULong(name, &valULong); |
| copyValue = &valULong; |
| copySize = sizeof(valULong); |
| break; |
| |
| // Handle all size_t and aliased types |
| case DeviceInfo::MaxWorkGroupSize: |
| case DeviceInfo::MaxParameterSize: |
| case DeviceInfo::MaxGlobalVariableSize: |
| case DeviceInfo::GlobalVariablePreferredTotalSize: |
| case DeviceInfo::ProfilingTimerResolution: |
| case DeviceInfo::PrintfBufferSize: |
| case DeviceInfo::PreferredWorkGroupSizeMultiple: |
| result = mImpl->getInfoSizeT(name, &valSizeT); |
| copyValue = &valSizeT; |
| copySize = sizeof(valSizeT); |
| break; |
| |
| // Handle all string types |
| case DeviceInfo::Name: |
| case DeviceInfo::Vendor: |
| case DeviceInfo::DriverVersion: |
| case DeviceInfo::Profile: |
| case DeviceInfo::OpenCL_C_Version: |
| case DeviceInfo::LatestConformanceVersionPassed: |
| result = mImpl->getInfoStringLength(name, ©Size); |
| if (result != CL_SUCCESS) |
| { |
| return result; |
| } |
| valString.resize(copySize, '\0'); |
| result = mImpl->getInfoString(name, copySize, valString.data()); |
| copyValue = valString.data(); |
| break; |
| |
| // Handle all cached values |
| case DeviceInfo::Type: |
| copyValue = &mInfo.type; |
| copySize = sizeof(mInfo.type); |
| break; |
| case DeviceInfo::MaxWorkItemDimensions: |
| valUInt = static_cast<cl_uint>(mInfo.maxWorkItemSizes.size()); |
| copyValue = &valUInt; |
| copySize = sizeof(valUInt); |
| break; |
| case DeviceInfo::MaxWorkItemSizes: |
| copyValue = mInfo.maxWorkItemSizes.data(); |
| copySize = mInfo.maxWorkItemSizes.size() * |
| sizeof(decltype(mInfo.maxWorkItemSizes)::value_type); |
| break; |
| case DeviceInfo::MaxMemAllocSize: |
| copyValue = &mInfo.maxMemAllocSize; |
| copySize = sizeof(mInfo.maxMemAllocSize); |
| break; |
| case DeviceInfo::ImageSupport: |
| copyValue = &mInfo.imageSupport; |
| copySize = sizeof(mInfo.imageSupport); |
| break; |
| case DeviceInfo::IL_Version: |
| copyValue = mInfo.IL_Version.c_str(); |
| copySize = mInfo.IL_Version.length() + 1u; |
| break; |
| case DeviceInfo::ILsWithVersion: |
| copyValue = mInfo.ILsWithVersion.data(); |
| copySize = |
| mInfo.ILsWithVersion.size() * sizeof(decltype(mInfo.ILsWithVersion)::value_type); |
| break; |
| case DeviceInfo::Image2D_MaxWidth: |
| copyValue = &mInfo.image2D_MaxWidth; |
| copySize = sizeof(mInfo.image2D_MaxWidth); |
| break; |
| case DeviceInfo::Image2D_MaxHeight: |
| copyValue = &mInfo.image2D_MaxHeight; |
| copySize = sizeof(mInfo.image2D_MaxHeight); |
| break; |
| case DeviceInfo::Image3D_MaxWidth: |
| copyValue = &mInfo.image3D_MaxWidth; |
| copySize = sizeof(mInfo.image3D_MaxWidth); |
| break; |
| case DeviceInfo::Image3D_MaxHeight: |
| copyValue = &mInfo.image3D_MaxHeight; |
| copySize = sizeof(mInfo.image3D_MaxHeight); |
| break; |
| case DeviceInfo::Image3D_MaxDepth: |
| copyValue = &mInfo.image3D_MaxDepth; |
| copySize = sizeof(mInfo.image3D_MaxDepth); |
| break; |
| case DeviceInfo::ImageMaxBufferSize: |
| copyValue = &mInfo.imageMaxBufferSize; |
| copySize = sizeof(mInfo.imageMaxBufferSize); |
| break; |
| case DeviceInfo::ImageMaxArraySize: |
| copyValue = &mInfo.imageMaxArraySize; |
| copySize = sizeof(mInfo.imageMaxArraySize); |
| break; |
| case DeviceInfo::ImagePitchAlignment: |
| copyValue = &mInfo.imagePitchAlignment; |
| copySize = sizeof(mInfo.imagePitchAlignment); |
| break; |
| case DeviceInfo::ImageBaseAddressAlignment: |
| copyValue = &mInfo.imageBaseAddressAlignment; |
| copySize = sizeof(mInfo.imageBaseAddressAlignment); |
| break; |
| case DeviceInfo::MemBaseAddrAlign: |
| copyValue = &mInfo.memBaseAddrAlign; |
| copySize = sizeof(mInfo.memBaseAddrAlign); |
| break; |
| case DeviceInfo::ExecutionCapabilities: |
| copyValue = &mInfo.execCapabilities; |
| copySize = sizeof(mInfo.execCapabilities); |
| break; |
| case DeviceInfo::QueueOnDeviceMaxSize: |
| copyValue = &mInfo.queueOnDeviceMaxSize; |
| copySize = sizeof(mInfo.queueOnDeviceMaxSize); |
| break; |
| case DeviceInfo::BuiltInKernels: |
| copyValue = mInfo.builtInKernels.c_str(); |
| copySize = mInfo.builtInKernels.length() + 1u; |
| break; |
| case DeviceInfo::BuiltInKernelsWithVersion: |
| copyValue = mInfo.builtInKernelsWithVersion.data(); |
| copySize = mInfo.builtInKernelsWithVersion.size() * |
| sizeof(decltype(mInfo.builtInKernelsWithVersion)::value_type); |
| break; |
| case DeviceInfo::Version: |
| copyValue = mInfo.versionStr.c_str(); |
| copySize = mInfo.versionStr.length() + 1u; |
| break; |
| case DeviceInfo::NumericVersion: |
| copyValue = &mInfo.version; |
| copySize = sizeof(mInfo.version); |
| break; |
| case DeviceInfo::OpenCL_C_AllVersions: |
| copyValue = mInfo.OpenCL_C_AllVersions.data(); |
| copySize = mInfo.OpenCL_C_AllVersions.size() * |
| sizeof(decltype(mInfo.OpenCL_C_AllVersions)::value_type); |
| break; |
| case DeviceInfo::OpenCL_C_Features: |
| copyValue = mInfo.OpenCL_C_Features.data(); |
| copySize = mInfo.OpenCL_C_Features.size() * |
| sizeof(decltype(mInfo.OpenCL_C_Features)::value_type); |
| break; |
| case DeviceInfo::Extensions: |
| copyValue = mInfo.extensions.c_str(); |
| copySize = mInfo.extensions.length() + 1u; |
| break; |
| case DeviceInfo::ExtensionsWithVersion: |
| copyValue = mInfo.extensionsWithVersion.data(); |
| copySize = mInfo.extensionsWithVersion.size() * |
| sizeof(decltype(mInfo.extensionsWithVersion)::value_type); |
| break; |
| case DeviceInfo::PartitionProperties: |
| copyValue = mInfo.partitionProperties.data(); |
| copySize = mInfo.partitionProperties.size() * |
| sizeof(decltype(mInfo.partitionProperties)::value_type); |
| break; |
| case DeviceInfo::PartitionType: |
| copyValue = mInfo.partitionType.data(); |
| copySize = |
| mInfo.partitionType.size() * sizeof(decltype(mInfo.partitionType)::value_type); |
| break; |
| |
| // Handle all mapped values |
| case DeviceInfo::Platform: |
| valPointer = mPlatform.getNative(); |
| copyValue = &valPointer; |
| copySize = sizeof(valPointer); |
| break; |
| case DeviceInfo::ParentDevice: |
| valPointer = Device::CastNative(mParent.get()); |
| copyValue = &valPointer; |
| copySize = sizeof(valPointer); |
| break; |
| case DeviceInfo::ReferenceCount: |
| valUInt = isRoot() ? 1u : getRefCount(); |
| copyValue = &valUInt; |
| copySize = sizeof(valUInt); |
| break; |
| |
| default: |
| ASSERT(false); |
| return CL_INVALID_VALUE; |
| } |
| |
| if (result != CL_SUCCESS) |
| { |
| return result; |
| } |
| if (value != nullptr) |
| { |
| // CL_INVALID_VALUE if size in bytes specified by param_value_size is < size of return |
| // type as specified in the Device Queries table and param_value is not a NULL value |
| if (valueSize < copySize) |
| { |
| return CL_INVALID_VALUE; |
| } |
| if (copyValue != nullptr) |
| { |
| std::memcpy(value, copyValue, copySize); |
| } |
| } |
| if (valueSizeRet != nullptr) |
| { |
| *valueSizeRet = copySize; |
| } |
| return CL_SUCCESS; |
| } |
| |
| cl_int Device::createSubDevices(const cl_device_partition_property *properties, |
| cl_uint numDevices, |
| cl_device_id *subDevices, |
| cl_uint *numDevicesRet) |
| { |
| if (subDevices == nullptr) |
| { |
| numDevices = 0u; |
| } |
| rx::CLDeviceImpl::CreateFuncs subDeviceCreateFuncs; |
| const cl_int errorCode = |
| mImpl->createSubDevices(properties, numDevices, subDeviceCreateFuncs, numDevicesRet); |
| if (errorCode == CL_SUCCESS) |
| { |
| cl::DeviceType type = mInfo.type; |
| type.clear(CL_DEVICE_TYPE_DEFAULT); |
| DevicePtrs devices; |
| devices.reserve(subDeviceCreateFuncs.size()); |
| while (!subDeviceCreateFuncs.empty()) |
| { |
| devices.emplace_back(new Device(mPlatform, this, type, subDeviceCreateFuncs.front())); |
| // Release initialization reference, lifetime controlled by RefPointer. |
| devices.back()->release(); |
| if (!devices.back()->mInfo.isValid()) |
| { |
| return CL_INVALID_VALUE; |
| } |
| subDeviceCreateFuncs.pop_front(); |
| } |
| for (DevicePtr &subDevice : devices) |
| { |
| *subDevices++ = subDevice.release(); |
| } |
| } |
| return errorCode; |
| } |
| |
| Device::~Device() = default; |
| |
| bool Device::supportsBuiltInKernel(const std::string &name) const |
| { |
| return angle::ContainsToken(mInfo.builtInKernels, ';', name); |
| } |
| |
| bool Device::supportsNativeImageDimensions(const cl_image_desc &desc) const |
| { |
| switch (FromCLenum<MemObjectType>(desc.image_type)) |
| { |
| case MemObjectType::Image1D: |
| return desc.image_width <= mInfo.image2D_MaxWidth; |
| case MemObjectType::Image2D: |
| return desc.image_width <= mInfo.image2D_MaxWidth && |
| desc.image_height <= mInfo.image2D_MaxHeight; |
| case MemObjectType::Image3D: |
| return desc.image_width <= mInfo.image3D_MaxWidth && |
| desc.image_height <= mInfo.image3D_MaxHeight && |
| desc.image_depth <= mInfo.image3D_MaxDepth; |
| case MemObjectType::Image1D_Array: |
| return desc.image_width <= mInfo.image2D_MaxWidth && |
| desc.image_array_size <= mInfo.imageMaxArraySize; |
| case MemObjectType::Image2D_Array: |
| return desc.image_width <= mInfo.image2D_MaxWidth && |
| desc.image_height <= mInfo.image2D_MaxHeight && |
| desc.image_array_size <= mInfo.imageMaxArraySize; |
| case MemObjectType::Image1D_Buffer: |
| return desc.image_width <= mInfo.imageMaxBufferSize; |
| default: |
| ASSERT(false); |
| break; |
| } |
| return false; |
| } |
| |
| bool Device::supportsImageDimensions(const ImageDescriptor &desc) const |
| { |
| switch (desc.type) |
| { |
| case MemObjectType::Image1D: |
| return desc.width <= mInfo.image2D_MaxWidth; |
| case MemObjectType::Image2D: |
| return desc.width <= mInfo.image2D_MaxWidth && desc.height <= mInfo.image2D_MaxHeight; |
| case MemObjectType::Image3D: |
| return desc.width <= mInfo.image3D_MaxWidth && desc.height <= mInfo.image3D_MaxHeight && |
| desc.depth <= mInfo.image3D_MaxDepth; |
| case MemObjectType::Image1D_Array: |
| return desc.width <= mInfo.image2D_MaxWidth && |
| desc.arraySize <= mInfo.imageMaxArraySize; |
| case MemObjectType::Image2D_Array: |
| return desc.width <= mInfo.image2D_MaxWidth && desc.height <= mInfo.image2D_MaxHeight && |
| desc.arraySize <= mInfo.imageMaxArraySize; |
| case MemObjectType::Image1D_Buffer: |
| return desc.width <= mInfo.imageMaxBufferSize; |
| default: |
| ASSERT(false); |
| break; |
| } |
| return false; |
| } |
| |
| Device::Device(Platform &platform, |
| Device *parent, |
| DeviceType type, |
| const rx::CLDeviceImpl::CreateFunc &createFunc) |
| : mPlatform(platform), mParent(parent), mImpl(createFunc(*this)), mInfo(mImpl->createInfo(type)) |
| {} |
| |
| } // namespace cl |