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