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