xref: /aosp_15_r20/external/angle/src/libANGLE/CLPlatform.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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