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 // CLPlatform.cpp: Implements the cl::Platform class.
7
8 #include "libANGLE/CLPlatform.h"
9
10 #include "libANGLE/CLContext.h"
11 #include "libANGLE/CLDevice.h"
12 #include "libANGLE/cl_utils.h"
13
14 #include <cstring>
15
16 namespace cl
17 {
18
19 namespace
20 {
21
IsDeviceTypeMatch(DeviceType select,DeviceType type)22 bool IsDeviceTypeMatch(DeviceType select, DeviceType type)
23 {
24 // The type 'DeviceType' is a bitfield, so it matches if any selected bit is set.
25 // A custom device is an exception, which only matches if it was explicitely selected, see:
26 // https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#clGetDeviceIDs
27 return type == CL_DEVICE_TYPE_CUSTOM ? select == CL_DEVICE_TYPE_CUSTOM
28 : type.intersects(select);
29 }
30
ParseContextProperties(const cl_context_properties * properties,Platform * & platform,bool & userSync)31 Context::PropArray ParseContextProperties(const cl_context_properties *properties,
32 Platform *&platform,
33 bool &userSync)
34 {
35 Context::PropArray propArray;
36 if (properties != nullptr)
37 {
38 const cl_context_properties *propIt = properties;
39 while (*propIt != 0)
40 {
41 switch (*propIt++)
42 {
43 case CL_CONTEXT_PLATFORM:
44 platform = &reinterpret_cast<cl_platform_id>(*propIt++)->cast<Platform>();
45 break;
46 case CL_CONTEXT_INTEROP_USER_SYNC:
47 userSync = *propIt++ != CL_FALSE;
48 break;
49 }
50 }
51 // Include the trailing zero
52 ++propIt;
53 propArray.reserve(propIt - properties);
54 propArray.insert(propArray.cend(), properties, propIt);
55 }
56 return propArray;
57 }
58
59 } // namespace
60
Initialize(const cl_icd_dispatch & dispatch,rx::CLPlatformImpl::CreateFuncs && createFuncs)61 void Platform::Initialize(const cl_icd_dispatch &dispatch,
62 rx::CLPlatformImpl::CreateFuncs &&createFuncs)
63 {
64 PlatformPtrs &platforms = GetPointers();
65 ASSERT(_cl_platform_id::sDispatch == nullptr && platforms.empty());
66 if (_cl_platform_id::sDispatch != nullptr || !platforms.empty())
67 {
68 ERR() << "Already initialized";
69 return;
70 }
71 Dispatch::sDispatch = &dispatch;
72
73 platforms.reserve(createFuncs.size());
74 while (!createFuncs.empty())
75 {
76 platforms.emplace_back(new Platform(createFuncs.front()));
77
78 // Release initialization reference, lifetime controlled by RefPointer.
79 platforms.back()->release();
80
81 // Remove platform on any errors
82 if (!platforms.back()->mInfo.isValid() || platforms.back()->mDevices.empty())
83 {
84 platforms.pop_back();
85 }
86
87 createFuncs.pop_front();
88 }
89 }
90
GetPlatformIDs(cl_uint numEntries,cl_platform_id * platforms,cl_uint * numPlatforms)91 angle::Result Platform::GetPlatformIDs(cl_uint numEntries,
92 cl_platform_id *platforms,
93 cl_uint *numPlatforms)
94 {
95 const PlatformPtrs &availPlatforms = GetPlatforms();
96 if (numPlatforms != nullptr)
97 {
98 *numPlatforms = static_cast<cl_uint>(availPlatforms.size());
99 }
100 if (platforms != nullptr)
101 {
102 cl_uint entry = 0u;
103 auto platformIt = availPlatforms.cbegin();
104 while (entry < numEntries && platformIt != availPlatforms.cend())
105 {
106 platforms[entry++] = (*platformIt++).get();
107 }
108 }
109 return angle::Result::Continue;
110 }
111
getInfo(PlatformInfo name,size_t valueSize,void * value,size_t * valueSizeRet) const112 angle::Result Platform::getInfo(PlatformInfo name,
113 size_t valueSize,
114 void *value,
115 size_t *valueSizeRet) const
116 {
117 const void *copyValue = nullptr;
118 size_t copySize = 0u;
119
120 switch (name)
121 {
122 case PlatformInfo::Profile:
123 copyValue = mInfo.profile.c_str();
124 copySize = mInfo.profile.length() + 1u;
125 break;
126 case PlatformInfo::Version:
127 copyValue = mInfo.versionStr.c_str();
128 copySize = mInfo.versionStr.length() + 1u;
129 break;
130 case PlatformInfo::NumericVersion:
131 copyValue = &mInfo.version;
132 copySize = sizeof(mInfo.version);
133 break;
134 case PlatformInfo::Name:
135 copyValue = mInfo.name.c_str();
136 copySize = mInfo.name.length() + 1u;
137 break;
138 case PlatformInfo::Vendor:
139 copyValue = kVendor;
140 copySize = sizeof(kVendor);
141 break;
142 case PlatformInfo::Extensions:
143 copyValue = mInfo.extensions.c_str();
144 copySize = mInfo.extensions.length() + 1u;
145 break;
146 case PlatformInfo::ExtensionsWithVersion:
147 copyValue = mInfo.extensionsWithVersion.data();
148 copySize = mInfo.extensionsWithVersion.size() *
149 sizeof(decltype(mInfo.extensionsWithVersion)::value_type);
150 break;
151 case PlatformInfo::HostTimerResolution:
152 copyValue = &mInfo.hostTimerRes;
153 copySize = sizeof(mInfo.hostTimerRes);
154 break;
155 case PlatformInfo::IcdSuffix:
156 copyValue = kIcdSuffix;
157 copySize = sizeof(kIcdSuffix);
158 break;
159 default:
160 ASSERT(false);
161 ANGLE_CL_RETURN_ERROR(CL_INVALID_VALUE);
162 }
163
164 if (value != nullptr)
165 {
166 // CL_INVALID_VALUE if size in bytes specified by param_value_size is < size of return type
167 // as specified in the OpenCL Platform Queries table, and param_value is not a NULL value.
168 if (valueSize < copySize)
169 {
170 ANGLE_CL_RETURN_ERROR(CL_INVALID_VALUE);
171 }
172 if (copyValue != nullptr)
173 {
174 std::memcpy(value, copyValue, copySize);
175 }
176 }
177 if (valueSizeRet != nullptr)
178 {
179 *valueSizeRet = copySize;
180 }
181 return angle::Result::Continue;
182 }
183
getDeviceIDs(DeviceType deviceType,cl_uint numEntries,cl_device_id * devices,cl_uint * numDevices) const184 angle::Result Platform::getDeviceIDs(DeviceType deviceType,
185 cl_uint numEntries,
186 cl_device_id *devices,
187 cl_uint *numDevices) const
188 {
189 cl_uint found = 0u;
190 for (const DevicePtr &device : mDevices)
191 {
192 if (IsDeviceTypeMatch(deviceType, device->getInfo().type))
193 {
194 if (devices != nullptr && found < numEntries)
195 {
196 devices[found] = device.get();
197 }
198 ++found;
199 }
200 }
201 if (numDevices != nullptr)
202 {
203 *numDevices = found;
204 }
205
206 // CL_DEVICE_NOT_FOUND if no OpenCL devices that matched device_type were found.
207 if (found == 0u)
208 {
209 ANGLE_CL_RETURN_ERROR(CL_DEVICE_NOT_FOUND);
210 }
211
212 return angle::Result::Continue;
213 }
214
hasDeviceType(DeviceType deviceType) const215 bool Platform::hasDeviceType(DeviceType deviceType) const
216 {
217 for (const DevicePtr &device : mDevices)
218 {
219 if (IsDeviceTypeMatch(deviceType, device->getInfo().type))
220 {
221 return true;
222 }
223 }
224 return false;
225 }
226
CreateContext(const cl_context_properties * properties,cl_uint numDevices,const cl_device_id * devices,ContextErrorCB notify,void * userData)227 cl_context Platform::CreateContext(const cl_context_properties *properties,
228 cl_uint numDevices,
229 const cl_device_id *devices,
230 ContextErrorCB notify,
231 void *userData)
232 {
233 DevicePtrs devs;
234 devs.reserve(numDevices);
235 while (numDevices-- != 0u)
236 {
237 devs.emplace_back(&(*devices++)->cast<Device>());
238 }
239
240 Platform *platform = nullptr;
241 bool userSync = false;
242 Context::PropArray propArray = ParseContextProperties(properties, platform, userSync);
243 if (platform == nullptr)
244 {
245 // All devices in the list have already been validated at this point to contain the same
246 // platform - just use/select the first device's platform.
247 platform = &devs.front()->getPlatform();
248 }
249
250 return Object::Create<Context>(*platform, std::move(propArray), std::move(devs), notify,
251 userData, userSync);
252 }
253
CreateContextFromType(const cl_context_properties * properties,DeviceType deviceType,ContextErrorCB notify,void * userData)254 cl_context Platform::CreateContextFromType(const cl_context_properties *properties,
255 DeviceType deviceType,
256 ContextErrorCB notify,
257 void *userData)
258 {
259 Platform *platform = nullptr;
260 bool userSync = false;
261 Context::PropArray propArray = ParseContextProperties(properties, platform, userSync);
262
263 // Choose default platform if user does not specify in the context properties field
264 if (platform == nullptr)
265 {
266 platform = Platform::GetDefault();
267 }
268
269 return Object::Create<Context>(*platform, std::move(propArray), deviceType, notify, userData,
270 userSync);
271 }
272
unloadCompiler()273 angle::Result Platform::unloadCompiler()
274 {
275 return mImpl->unloadCompiler();
276 }
277
278 Platform::~Platform() = default;
279
Platform(const rx::CLPlatformImpl::CreateFunc & createFunc)280 Platform::Platform(const rx::CLPlatformImpl::CreateFunc &createFunc)
281 : mImpl(createFunc(*this)),
282 mInfo(mImpl ? mImpl->createInfo() : rx::CLPlatformImpl::Info{}),
283 mDevices(mImpl ? createDevices(mImpl->createDevices()) : DevicePtrs{}),
284 mMultiThreadPool(mImpl ? angle::WorkerThreadPool::Create(0, ANGLEPlatformCurrent()) : nullptr)
285 {}
286
createDevices(rx::CLDeviceImpl::CreateDatas && createDatas)287 DevicePtrs Platform::createDevices(rx::CLDeviceImpl::CreateDatas &&createDatas)
288 {
289 DevicePtrs devices;
290 devices.reserve(createDatas.size());
291 while (!createDatas.empty())
292 {
293 devices.emplace_back(
294 new Device(*this, nullptr, createDatas.front().first, createDatas.front().second));
295 // Release initialization reference, lifetime controlled by RefPointer.
296 devices.back()->release();
297 if (!devices.back()->mInfo.isValid())
298 {
299 devices.pop_back();
300 }
301 createDatas.pop_front();
302 }
303 return devices;
304 }
305
306 constexpr char Platform::kVendor[];
307 constexpr char Platform::kIcdSuffix[];
308
309 } // namespace cl
310