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 // CLDeviceCL.cpp: Implements the class methods for CLDeviceCL.
7
8 #include "libANGLE/renderer/cl/CLDeviceCL.h"
9
10 #include "libANGLE/renderer/cl/cl_util.h"
11
12 #include "libANGLE/CLDevice.h"
13
14 namespace rx
15 {
16
17 namespace
18 {
19
20 // Object information is queried in OpenCL by providing allocated memory into which the requested
21 // data is copied. If the size of the data is unknown, it can be queried first with an additional
22 // call to the same function, but without requesting the data itself. This function provides the
23 // functionality to request and validate the size and the data.
24 template <typename T>
GetDeviceInfo(cl_device_id device,cl::DeviceInfo name,std::vector<T> & vector)25 bool GetDeviceInfo(cl_device_id device, cl::DeviceInfo name, std::vector<T> &vector)
26 {
27 size_t size = 0u;
28 if (device->getDispatch().clGetDeviceInfo(device, cl::ToCLenum(name), 0u, nullptr, &size) ==
29 CL_SUCCESS &&
30 (size % sizeof(T)) == 0u) // size has to be a multiple of the data type
31 {
32 vector.resize(size / sizeof(T));
33 if (device->getDispatch().clGetDeviceInfo(device, cl::ToCLenum(name), size, vector.data(),
34 nullptr) == CL_SUCCESS)
35 {
36 return true;
37 }
38 }
39 ERR() << "Failed to query CL device info for " << name;
40 return false;
41 }
42
43 // This queries the OpenCL device info for value types with known size
44 template <typename T>
GetDeviceInfo(cl_device_id device,cl::DeviceInfo name,T & value)45 bool GetDeviceInfo(cl_device_id device, cl::DeviceInfo name, T &value)
46 {
47 if (device->getDispatch().clGetDeviceInfo(device, cl::ToCLenum(name), sizeof(T), &value,
48 nullptr) != CL_SUCCESS)
49 {
50 ERR() << "Failed to query CL device info for " << name;
51 return false;
52 }
53 return true;
54 }
55
56 } // namespace
57
~CLDeviceCL()58 CLDeviceCL::~CLDeviceCL()
59 {
60 if (!mDevice.isRoot() && mNative->getDispatch().clReleaseDevice(mNative) != CL_SUCCESS)
61 {
62 ERR() << "Error while releasing CL device";
63 }
64 }
65
createInfo(cl::DeviceType type) const66 CLDeviceImpl::Info CLDeviceCL::createInfo(cl::DeviceType type) const
67 {
68 Info info(type);
69 std::vector<char> valString;
70
71 if (!GetDeviceInfo(mNative, cl::DeviceInfo::MaxWorkItemSizes, info.maxWorkItemSizes))
72 {
73 return Info{};
74 }
75 // From the OpenCL specification for info name CL_DEVICE_MAX_WORK_ITEM_SIZES:
76 // "The minimum value is (1, 1, 1) for devices that are not of type CL_DEVICE_TYPE_CUSTOM."
77 // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clGetDeviceInfo
78 // Custom devices are currently not supported by this back end.
79 if (info.maxWorkItemSizes.size() < 3u || info.maxWorkItemSizes[0] == 0u ||
80 info.maxWorkItemSizes[1] == 0u || info.maxWorkItemSizes[2] == 0u)
81 {
82 ERR() << "Invalid CL_DEVICE_MAX_WORK_ITEM_SIZES";
83 return Info{};
84 }
85
86 if (!GetDeviceInfo(mNative, cl::DeviceInfo::MaxMemAllocSize, info.maxMemAllocSize) ||
87 !GetDeviceInfo(mNative, cl::DeviceInfo::ImageSupport, info.imageSupport) ||
88 !GetDeviceInfo(mNative, cl::DeviceInfo::Image2D_MaxWidth, info.image2D_MaxWidth) ||
89 !GetDeviceInfo(mNative, cl::DeviceInfo::Image2D_MaxHeight, info.image2D_MaxHeight) ||
90 !GetDeviceInfo(mNative, cl::DeviceInfo::Image3D_MaxWidth, info.image3D_MaxWidth) ||
91 !GetDeviceInfo(mNative, cl::DeviceInfo::Image3D_MaxHeight, info.image3D_MaxHeight) ||
92 !GetDeviceInfo(mNative, cl::DeviceInfo::Image3D_MaxDepth, info.image3D_MaxDepth) ||
93 !GetDeviceInfo(mNative, cl::DeviceInfo::MemBaseAddrAlign, info.memBaseAddrAlign) ||
94 !GetDeviceInfo(mNative, cl::DeviceInfo::ExecutionCapabilities, info.execCapabilities))
95 {
96 return Info{};
97 }
98
99 if (!GetDeviceInfo(mNative, cl::DeviceInfo::Version, valString))
100 {
101 return Info{};
102 }
103 info.versionStr.assign(valString.data());
104
105 if (!GetDeviceInfo(mNative, cl::DeviceInfo::Extensions, valString))
106 {
107 return Info{};
108 }
109 std::string extensionStr(valString.data());
110
111 // TODO(jplate) Remove workaround after bug is fixed http://anglebug.com/6053
112 if (info.versionStr.compare(0u, 15u, "OpenCL 3.0 CUDA", 15u) == 0)
113 {
114 extensionStr.append(" cl_khr_depth_images cl_khr_image2d_from_buffer");
115 }
116
117 // Limit version number to supported version
118 if (info.versionStr[7] != '1')
119 {
120 info.versionStr[7] = '1';
121 info.versionStr[9] = '2';
122 }
123
124 info.version = ExtractCLVersion(info.versionStr);
125 if (info.version == 0u)
126 {
127 return Info{};
128 }
129
130 RemoveUnsupportedCLExtensions(extensionStr);
131 info.initializeExtensions(std::move(extensionStr));
132
133 if (info.version >= CL_MAKE_VERSION(1, 2, 0))
134 {
135 if (!GetDeviceInfo(mNative, cl::DeviceInfo::ImageMaxBufferSize, info.imageMaxBufferSize) ||
136 !GetDeviceInfo(mNative, cl::DeviceInfo::ImageMaxArraySize, info.imageMaxArraySize) ||
137 !GetDeviceInfo(mNative, cl::DeviceInfo::BuiltInKernels, valString))
138 {
139 return Info{};
140 }
141 info.builtInKernels.assign(valString.data());
142 if (!GetDeviceInfo(mNative, cl::DeviceInfo::PartitionProperties,
143 info.partitionProperties) ||
144 !GetDeviceInfo(mNative, cl::DeviceInfo::PartitionType, info.partitionType))
145 {
146 return Info{};
147 }
148 }
149
150 if (info.version >= CL_MAKE_VERSION(2, 0, 0) &&
151 (!GetDeviceInfo(mNative, cl::DeviceInfo::ImagePitchAlignment, info.imagePitchAlignment) ||
152 !GetDeviceInfo(mNative, cl::DeviceInfo::ImageBaseAddressAlignment,
153 info.imageBaseAddressAlignment) ||
154 !GetDeviceInfo(mNative, cl::DeviceInfo::QueueOnDeviceMaxSize, info.queueOnDeviceMaxSize)))
155 {
156 return Info{};
157 }
158
159 if (info.version >= CL_MAKE_VERSION(2, 1, 0))
160 {
161 if (!GetDeviceInfo(mNative, cl::DeviceInfo::IL_Version, valString))
162 {
163 return Info{};
164 }
165 info.IL_Version.assign(valString.data());
166 }
167
168 if (info.version >= CL_MAKE_VERSION(3, 0, 0) &&
169 (!GetDeviceInfo(mNative, cl::DeviceInfo::ILsWithVersion, info.ILsWithVersion) ||
170 !GetDeviceInfo(mNative, cl::DeviceInfo::BuiltInKernelsWithVersion,
171 info.builtInKernelsWithVersion) ||
172 !GetDeviceInfo(mNative, cl::DeviceInfo::OpenCL_C_AllVersions, info.OpenCL_C_AllVersions) ||
173 !GetDeviceInfo(mNative, cl::DeviceInfo::OpenCL_C_Features, info.OpenCL_C_Features) ||
174 !GetDeviceInfo(mNative, cl::DeviceInfo::ExtensionsWithVersion,
175 info.extensionsWithVersion)))
176 {
177 return Info{};
178 }
179 RemoveUnsupportedCLExtensions(info.extensionsWithVersion);
180
181 return info;
182 }
183
getInfoUInt(cl::DeviceInfo name,cl_uint * value) const184 cl_int CLDeviceCL::getInfoUInt(cl::DeviceInfo name, cl_uint *value) const
185 {
186 return mNative->getDispatch().clGetDeviceInfo(mNative, cl::ToCLenum(name), sizeof(*value),
187 value, nullptr);
188 }
189
getInfoULong(cl::DeviceInfo name,cl_ulong * value) const190 cl_int CLDeviceCL::getInfoULong(cl::DeviceInfo name, cl_ulong *value) const
191 {
192 return mNative->getDispatch().clGetDeviceInfo(mNative, cl::ToCLenum(name), sizeof(*value),
193 value, nullptr);
194 }
195
getInfoSizeT(cl::DeviceInfo name,size_t * value) const196 cl_int CLDeviceCL::getInfoSizeT(cl::DeviceInfo name, size_t *value) const
197 {
198 return mNative->getDispatch().clGetDeviceInfo(mNative, cl::ToCLenum(name), sizeof(*value),
199 value, nullptr);
200 }
201
getInfoStringLength(cl::DeviceInfo name,size_t * value) const202 cl_int CLDeviceCL::getInfoStringLength(cl::DeviceInfo name, size_t *value) const
203 {
204 return mNative->getDispatch().clGetDeviceInfo(mNative, cl::ToCLenum(name), 0u, nullptr, value);
205 }
206
getInfoString(cl::DeviceInfo name,size_t size,char * value) const207 cl_int CLDeviceCL::getInfoString(cl::DeviceInfo name, size_t size, char *value) const
208 {
209 return mNative->getDispatch().clGetDeviceInfo(mNative, cl::ToCLenum(name), size, value,
210 nullptr);
211 }
212
createSubDevices(const cl_device_partition_property * properties,cl_uint numDevices,CreateFuncs & createFuncs,cl_uint * numDevicesRet)213 cl_int CLDeviceCL::createSubDevices(const cl_device_partition_property *properties,
214 cl_uint numDevices,
215 CreateFuncs &createFuncs,
216 cl_uint *numDevicesRet)
217 {
218 if (numDevices == 0u)
219 {
220 return mNative->getDispatch().clCreateSubDevices(mNative, properties, 0u, nullptr,
221 numDevicesRet);
222 }
223
224 std::vector<cl_device_id> nativeSubDevices(numDevices, nullptr);
225 const cl_int errorCode = mNative->getDispatch().clCreateSubDevices(
226 mNative, properties, numDevices, nativeSubDevices.data(), nullptr);
227 if (errorCode == CL_SUCCESS)
228 {
229 for (cl_device_id nativeSubDevice : nativeSubDevices)
230 {
231 createFuncs.emplace_back([nativeSubDevice](const cl::Device &device) {
232 return Ptr(new CLDeviceCL(device, nativeSubDevice));
233 });
234 }
235 }
236 return errorCode;
237 }
238
CLDeviceCL(const cl::Device & device,cl_device_id native)239 CLDeviceCL::CLDeviceCL(const cl::Device &device, cl_device_id native)
240 : CLDeviceImpl(device), mNative(native)
241 {}
242
243 } // namespace rx
244