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