• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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