1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // CLDevice.cpp: Implements the cl::Device class.
7
8 #include "libANGLE/CLDevice.h"
9
10 #include "libANGLE/CLPlatform.h"
11 #include "libANGLE/cl_utils.h"
12
13 #include "common/string_utils.h"
14
15 #include <cstring>
16
17 namespace cl
18 {
19
getInfo(DeviceInfo name,size_t valueSize,void * value,size_t * valueSizeRet) const20 angle::Result Device::getInfo(DeviceInfo name,
21 size_t valueSize,
22 void *value,
23 size_t *valueSizeRet) const
24 {
25 static_assert(std::is_same<cl_uint, cl_bool>::value &&
26 std::is_same<cl_uint, cl_device_mem_cache_type>::value &&
27 std::is_same<cl_uint, cl_device_local_mem_type>::value &&
28 std::is_same<cl_uint, cl_version>::value &&
29 std::is_same<cl_ulong, cl_device_type>::value &&
30 std::is_same<cl_ulong, cl_device_fp_config>::value &&
31 std::is_same<cl_ulong, cl_device_exec_capabilities>::value &&
32 std::is_same<cl_ulong, cl_command_queue_properties>::value &&
33 std::is_same<cl_ulong, cl_device_affinity_domain>::value &&
34 std::is_same<cl_ulong, cl_device_svm_capabilities>::value &&
35 std::is_same<cl_ulong, cl_device_atomic_capabilities>::value &&
36 std::is_same<cl_ulong, cl_device_device_enqueue_capabilities>::value,
37 "OpenCL type mismatch");
38
39 cl_uint valUInt = 0u;
40 cl_ulong valULong = 0u;
41 size_t valSizeT = 0u;
42 void *valPointer = nullptr;
43 std::vector<char> valString;
44
45 const void *copyValue = nullptr;
46 size_t copySize = 0u;
47
48 // The info names are sorted within their type group in the order they appear in the OpenCL
49 // specification, so it is easier to compare them side-by-side when looking for changes.
50 // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clGetDeviceInfo
51 switch (name)
52 {
53 // Handle all cl_uint and aliased types
54 case DeviceInfo::VendorID:
55 case DeviceInfo::MaxComputeUnits:
56 case DeviceInfo::PreferredVectorWidthChar:
57 case DeviceInfo::PreferredVectorWidthShort:
58 case DeviceInfo::PreferredVectorWidthInt:
59 case DeviceInfo::PreferredVectorWidthLong:
60 case DeviceInfo::PreferredVectorWidthFloat:
61 case DeviceInfo::PreferredVectorWidthDouble:
62 case DeviceInfo::PreferredVectorWidthHalf:
63 case DeviceInfo::NativeVectorWidthChar:
64 case DeviceInfo::NativeVectorWidthShort:
65 case DeviceInfo::NativeVectorWidthInt:
66 case DeviceInfo::NativeVectorWidthLong:
67 case DeviceInfo::NativeVectorWidthFloat:
68 case DeviceInfo::NativeVectorWidthDouble:
69 case DeviceInfo::NativeVectorWidthHalf:
70 case DeviceInfo::MaxClockFrequency:
71 case DeviceInfo::AddressBits:
72 case DeviceInfo::MaxReadImageArgs:
73 case DeviceInfo::MaxWriteImageArgs:
74 case DeviceInfo::MaxReadWriteImageArgs:
75 case DeviceInfo::MaxSamplers:
76 case DeviceInfo::MaxPipeArgs:
77 case DeviceInfo::PipeMaxActiveReservations:
78 case DeviceInfo::PipeMaxPacketSize:
79 case DeviceInfo::MinDataTypeAlignSize:
80 case DeviceInfo::GlobalMemCacheType:
81 case DeviceInfo::GlobalMemCachelineSize:
82 case DeviceInfo::MaxConstantArgs:
83 case DeviceInfo::LocalMemType:
84 case DeviceInfo::ErrorCorrectionSupport:
85 case DeviceInfo::HostUnifiedMemory:
86 case DeviceInfo::EndianLittle:
87 case DeviceInfo::Available:
88 case DeviceInfo::CompilerAvailable:
89 case DeviceInfo::LinkerAvailable:
90 case DeviceInfo::QueueOnDevicePreferredSize:
91 case DeviceInfo::MaxOnDeviceQueues:
92 case DeviceInfo::MaxOnDeviceEvents:
93 case DeviceInfo::PreferredInteropUserSync:
94 case DeviceInfo::PartitionMaxSubDevices:
95 case DeviceInfo::PreferredPlatformAtomicAlignment:
96 case DeviceInfo::PreferredGlobalAtomicAlignment:
97 case DeviceInfo::PreferredLocalAtomicAlignment:
98 case DeviceInfo::MaxNumSubGroups:
99 case DeviceInfo::SubGroupIndependentForwardProgress:
100 case DeviceInfo::NonUniformWorkGroupSupport:
101 case DeviceInfo::WorkGroupCollectiveFunctionsSupport:
102 case DeviceInfo::GenericAddressSpaceSupport:
103 case DeviceInfo::PipeSupport:
104 ANGLE_TRY(mImpl->getInfoUInt(name, &valUInt));
105 copyValue = &valUInt;
106 copySize = sizeof(valUInt);
107 break;
108
109 // Handle all cl_ulong and aliased types
110 case DeviceInfo::SingleFpConfig:
111 case DeviceInfo::DoubleFpConfig:
112 case DeviceInfo::GlobalMemCacheSize:
113 case DeviceInfo::GlobalMemSize:
114 case DeviceInfo::MaxConstantBufferSize:
115 case DeviceInfo::LocalMemSize:
116 case DeviceInfo::QueueOnHostProperties:
117 case DeviceInfo::QueueOnDeviceProperties:
118 case DeviceInfo::PartitionAffinityDomain:
119 case DeviceInfo::SVM_Capabilities:
120 case DeviceInfo::AtomicMemoryCapabilities:
121 case DeviceInfo::AtomicFenceCapabilities:
122 case DeviceInfo::DeviceEnqueueCapabilities:
123 case DeviceInfo::HalfFpConfig:
124 ANGLE_TRY(mImpl->getInfoULong(name, &valULong));
125 copyValue = &valULong;
126 copySize = sizeof(valULong);
127 break;
128
129 // Handle all size_t and aliased types
130 case DeviceInfo::MaxWorkGroupSize:
131 case DeviceInfo::MaxParameterSize:
132 case DeviceInfo::MaxGlobalVariableSize:
133 case DeviceInfo::GlobalVariablePreferredTotalSize:
134 case DeviceInfo::ProfilingTimerResolution:
135 case DeviceInfo::PrintfBufferSize:
136 case DeviceInfo::PreferredWorkGroupSizeMultiple:
137 ANGLE_TRY(mImpl->getInfoSizeT(name, &valSizeT));
138 copyValue = &valSizeT;
139 copySize = sizeof(valSizeT);
140 break;
141
142 // Handle all string types
143 case DeviceInfo::Name:
144 case DeviceInfo::Vendor:
145 case DeviceInfo::DriverVersion:
146 case DeviceInfo::Profile:
147 case DeviceInfo::OpenCL_C_Version:
148 case DeviceInfo::LatestConformanceVersionPassed:
149 ANGLE_TRY(mImpl->getInfoStringLength(name, ©Size));
150 valString.resize(copySize, '\0');
151 ANGLE_TRY(mImpl->getInfoString(name, copySize, valString.data()));
152 copyValue = valString.data();
153 break;
154
155 // Handle all cached values
156 case DeviceInfo::Type:
157 copyValue = &mInfo.type;
158 copySize = sizeof(mInfo.type);
159 break;
160 case DeviceInfo::MaxWorkItemDimensions:
161 valUInt = static_cast<cl_uint>(mInfo.maxWorkItemSizes.size());
162 copyValue = &valUInt;
163 copySize = sizeof(valUInt);
164 break;
165 case DeviceInfo::MaxWorkItemSizes:
166 copyValue = mInfo.maxWorkItemSizes.data();
167 copySize = mInfo.maxWorkItemSizes.size() *
168 sizeof(decltype(mInfo.maxWorkItemSizes)::value_type);
169 break;
170 case DeviceInfo::MaxMemAllocSize:
171 copyValue = &mInfo.maxMemAllocSize;
172 copySize = sizeof(mInfo.maxMemAllocSize);
173 break;
174 case DeviceInfo::ImageSupport:
175 copyValue = &mInfo.imageSupport;
176 copySize = sizeof(mInfo.imageSupport);
177 break;
178 case DeviceInfo::IL_Version:
179 copyValue = mInfo.IL_Version.c_str();
180 copySize = mInfo.IL_Version.length() + 1u;
181 break;
182 case DeviceInfo::ILsWithVersion:
183 copyValue = mInfo.ILsWithVersion.data();
184 copySize =
185 mInfo.ILsWithVersion.size() * sizeof(decltype(mInfo.ILsWithVersion)::value_type);
186 break;
187 case DeviceInfo::Image2D_MaxWidth:
188 copyValue = &mInfo.image2D_MaxWidth;
189 copySize = sizeof(mInfo.image2D_MaxWidth);
190 break;
191 case DeviceInfo::Image2D_MaxHeight:
192 copyValue = &mInfo.image2D_MaxHeight;
193 copySize = sizeof(mInfo.image2D_MaxHeight);
194 break;
195 case DeviceInfo::Image3D_MaxWidth:
196 copyValue = &mInfo.image3D_MaxWidth;
197 copySize = sizeof(mInfo.image3D_MaxWidth);
198 break;
199 case DeviceInfo::Image3D_MaxHeight:
200 copyValue = &mInfo.image3D_MaxHeight;
201 copySize = sizeof(mInfo.image3D_MaxHeight);
202 break;
203 case DeviceInfo::Image3D_MaxDepth:
204 copyValue = &mInfo.image3D_MaxDepth;
205 copySize = sizeof(mInfo.image3D_MaxDepth);
206 break;
207 case DeviceInfo::ImageMaxBufferSize:
208 copyValue = &mInfo.imageMaxBufferSize;
209 copySize = sizeof(mInfo.imageMaxBufferSize);
210 break;
211 case DeviceInfo::ImageMaxArraySize:
212 copyValue = &mInfo.imageMaxArraySize;
213 copySize = sizeof(mInfo.imageMaxArraySize);
214 break;
215 case DeviceInfo::ImagePitchAlignment:
216 copyValue = &mInfo.imagePitchAlignment;
217 copySize = sizeof(mInfo.imagePitchAlignment);
218 break;
219 case DeviceInfo::ImageBaseAddressAlignment:
220 copyValue = &mInfo.imageBaseAddressAlignment;
221 copySize = sizeof(mInfo.imageBaseAddressAlignment);
222 break;
223 case DeviceInfo::MemBaseAddrAlign:
224 copyValue = &mInfo.memBaseAddrAlign;
225 copySize = sizeof(mInfo.memBaseAddrAlign);
226 break;
227 case DeviceInfo::ExecutionCapabilities:
228 copyValue = &mInfo.execCapabilities;
229 copySize = sizeof(mInfo.execCapabilities);
230 break;
231 case DeviceInfo::QueueOnDeviceMaxSize:
232 copyValue = &mInfo.queueOnDeviceMaxSize;
233 copySize = sizeof(mInfo.queueOnDeviceMaxSize);
234 break;
235 case DeviceInfo::BuiltInKernels:
236 copyValue = mInfo.builtInKernels.c_str();
237 copySize = mInfo.builtInKernels.length() + 1u;
238 break;
239 case DeviceInfo::BuiltInKernelsWithVersion:
240 copyValue = mInfo.builtInKernelsWithVersion.data();
241 copySize = mInfo.builtInKernelsWithVersion.size() *
242 sizeof(decltype(mInfo.builtInKernelsWithVersion)::value_type);
243 break;
244 case DeviceInfo::Version:
245 copyValue = mInfo.versionStr.c_str();
246 copySize = mInfo.versionStr.length() + 1u;
247 break;
248 case DeviceInfo::NumericVersion:
249 copyValue = &mInfo.version;
250 copySize = sizeof(mInfo.version);
251 break;
252 case DeviceInfo::OpenCL_C_AllVersions:
253 copyValue = mInfo.OpenCL_C_AllVersions.data();
254 copySize = mInfo.OpenCL_C_AllVersions.size() *
255 sizeof(decltype(mInfo.OpenCL_C_AllVersions)::value_type);
256 break;
257 case DeviceInfo::OpenCL_C_Features:
258 copyValue = mInfo.OpenCL_C_Features.data();
259 copySize = mInfo.OpenCL_C_Features.size() *
260 sizeof(decltype(mInfo.OpenCL_C_Features)::value_type);
261 break;
262 case DeviceInfo::Extensions:
263 copyValue = mInfo.extensions.c_str();
264 copySize = mInfo.extensions.length() + 1u;
265 break;
266 case DeviceInfo::ExtensionsWithVersion:
267 copyValue = mInfo.extensionsWithVersion.data();
268 copySize = mInfo.extensionsWithVersion.size() *
269 sizeof(decltype(mInfo.extensionsWithVersion)::value_type);
270 break;
271 case DeviceInfo::PartitionProperties:
272 copyValue = mInfo.partitionProperties.data();
273 copySize = mInfo.partitionProperties.size() *
274 sizeof(decltype(mInfo.partitionProperties)::value_type);
275 break;
276 case DeviceInfo::PartitionType:
277 copyValue = mInfo.partitionType.data();
278 copySize =
279 mInfo.partitionType.size() * sizeof(decltype(mInfo.partitionType)::value_type);
280 break;
281
282 // Handle all mapped values
283 case DeviceInfo::Platform:
284 valPointer = mPlatform.getNative();
285 copyValue = &valPointer;
286 copySize = sizeof(valPointer);
287 break;
288 case DeviceInfo::ParentDevice:
289 valPointer = Device::CastNative(mParent.get());
290 copyValue = &valPointer;
291 copySize = sizeof(valPointer);
292 break;
293 case DeviceInfo::ReferenceCount:
294 valUInt = isRoot() ? 1u : getRefCount();
295 copyValue = &valUInt;
296 copySize = sizeof(valUInt);
297 break;
298
299 default:
300 ASSERT(false);
301 ANGLE_CL_RETURN_ERROR(CL_INVALID_VALUE);
302 }
303
304 if (value != nullptr)
305 {
306 // CL_INVALID_VALUE if size in bytes specified by param_value_size is < size of return
307 // type as specified in the Device Queries table and param_value is not a NULL value
308 if (valueSize < copySize)
309 {
310 ANGLE_CL_RETURN_ERROR(CL_INVALID_VALUE);
311 }
312 if (copyValue != nullptr)
313 {
314 std::memcpy(value, copyValue, copySize);
315 }
316 }
317 if (valueSizeRet != nullptr)
318 {
319 *valueSizeRet = copySize;
320 }
321 return angle::Result::Continue;
322 }
323
createSubDevices(const cl_device_partition_property * properties,cl_uint numDevices,cl_device_id * subDevices,cl_uint * numDevicesRet)324 angle::Result Device::createSubDevices(const cl_device_partition_property *properties,
325 cl_uint numDevices,
326 cl_device_id *subDevices,
327 cl_uint *numDevicesRet)
328 {
329 if (subDevices == nullptr)
330 {
331 numDevices = 0u;
332 }
333 rx::CLDeviceImpl::CreateFuncs subDeviceCreateFuncs;
334 ANGLE_TRY(mImpl->createSubDevices(properties, numDevices, subDeviceCreateFuncs, numDevicesRet));
335 cl::DeviceType type = mInfo.type;
336 type.clear(CL_DEVICE_TYPE_DEFAULT);
337 DevicePtrs devices;
338 devices.reserve(subDeviceCreateFuncs.size());
339 while (!subDeviceCreateFuncs.empty())
340 {
341 devices.emplace_back(new Device(mPlatform, this, type, subDeviceCreateFuncs.front()));
342 // Release initialization reference, lifetime controlled by RefPointer.
343 devices.back()->release();
344 if (!devices.back()->mInfo.isValid())
345 {
346 return angle::Result::Stop;
347 }
348 subDeviceCreateFuncs.pop_front();
349 }
350 for (DevicePtr &subDevice : devices)
351 {
352 *subDevices++ = subDevice.release();
353 }
354 return angle::Result::Continue;
355 }
356
357 Device::~Device() = default;
358
supportsBuiltInKernel(const std::string & name) const359 bool Device::supportsBuiltInKernel(const std::string &name) const
360 {
361 return angle::ContainsToken(mInfo.builtInKernels, ';', name);
362 }
363
supportsNativeImageDimensions(const cl_image_desc & desc) const364 bool Device::supportsNativeImageDimensions(const cl_image_desc &desc) const
365 {
366 switch (FromCLenum<MemObjectType>(desc.image_type))
367 {
368 case MemObjectType::Image1D:
369 return desc.image_width <= mInfo.image2D_MaxWidth;
370 case MemObjectType::Image2D:
371 return desc.image_width <= mInfo.image2D_MaxWidth &&
372 desc.image_height <= mInfo.image2D_MaxHeight;
373 case MemObjectType::Image3D:
374 return desc.image_width <= mInfo.image3D_MaxWidth &&
375 desc.image_height <= mInfo.image3D_MaxHeight &&
376 desc.image_depth <= mInfo.image3D_MaxDepth;
377 case MemObjectType::Image1D_Array:
378 return desc.image_width <= mInfo.image2D_MaxWidth &&
379 desc.image_array_size <= mInfo.imageMaxArraySize;
380 case MemObjectType::Image2D_Array:
381 return desc.image_width <= mInfo.image2D_MaxWidth &&
382 desc.image_height <= mInfo.image2D_MaxHeight &&
383 desc.image_array_size <= mInfo.imageMaxArraySize;
384 case MemObjectType::Image1D_Buffer:
385 return desc.image_width <= mInfo.imageMaxBufferSize;
386 default:
387 ASSERT(false);
388 break;
389 }
390 return false;
391 }
392
supportsImageDimensions(const ImageDescriptor & desc) const393 bool Device::supportsImageDimensions(const ImageDescriptor &desc) const
394 {
395 switch (desc.type)
396 {
397 case MemObjectType::Image1D:
398 return desc.width <= mInfo.image2D_MaxWidth;
399 case MemObjectType::Image2D:
400 return desc.width <= mInfo.image2D_MaxWidth && desc.height <= mInfo.image2D_MaxHeight;
401 case MemObjectType::Image3D:
402 return desc.width <= mInfo.image3D_MaxWidth && desc.height <= mInfo.image3D_MaxHeight &&
403 desc.depth <= mInfo.image3D_MaxDepth;
404 case MemObjectType::Image1D_Array:
405 return desc.width <= mInfo.image2D_MaxWidth &&
406 desc.arraySize <= mInfo.imageMaxArraySize;
407 case MemObjectType::Image2D_Array:
408 return desc.width <= mInfo.image2D_MaxWidth && desc.height <= mInfo.image2D_MaxHeight &&
409 desc.arraySize <= mInfo.imageMaxArraySize;
410 case MemObjectType::Image1D_Buffer:
411 return desc.width <= mInfo.imageMaxBufferSize;
412 default:
413 ASSERT(false);
414 break;
415 }
416 return false;
417 }
418
hasDeviceEnqueueCaps() const419 bool Device::hasDeviceEnqueueCaps() const
420 {
421 return mInfo.queueOnDeviceMaxSize > 0;
422 }
423
supportsNonUniformWorkGroups() const424 bool Device::supportsNonUniformWorkGroups() const
425 {
426 cl_bool support = false;
427
428 if (IsError(mImpl->getInfoUInt(DeviceInfo::NonUniformWorkGroupSupport, &support)))
429 {
430 UNREACHABLE();
431 }
432 return support;
433 }
434
Device(Platform & platform,Device * parent,DeviceType type,const rx::CLDeviceImpl::CreateFunc & createFunc)435 Device::Device(Platform &platform,
436 Device *parent,
437 DeviceType type,
438 const rx::CLDeviceImpl::CreateFunc &createFunc)
439 : mPlatform(platform), mParent(parent), mImpl(createFunc(*this)), mInfo(mImpl->createInfo(type))
440 {}
441
442 } // namespace cl
443