blob: 76981fca15c23d5297f716e2fe060f72d453ce68 [file] [log] [blame]
//
// 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, &copySize);
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