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