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 // CLProgram.cpp: Implements the cl::Program class.
7
8 #include "libANGLE/CLProgram.h"
9
10 #include "libANGLE/CLContext.h"
11 #include "libANGLE/CLPlatform.h"
12 #include "libANGLE/cl_utils.h"
13
14 #include <cstring>
15
16 namespace cl
17 {
18
build(cl_uint numDevices,const cl_device_id * deviceList,const char * options,ProgramCB pfnNotify,void * userData)19 angle::Result Program::build(cl_uint numDevices,
20 const cl_device_id *deviceList,
21 const char *options,
22 ProgramCB pfnNotify,
23 void *userData)
24 {
25 DevicePtrs devices;
26 devices.reserve(numDevices);
27 while (numDevices-- != 0u)
28 {
29 devices.emplace_back(&(*deviceList++)->cast<Device>());
30 }
31 Program *notify = nullptr;
32 if (pfnNotify != nullptr)
33 {
34 // This program has to be retained until the notify callback is called.
35 retain();
36 *mCallback = CallbackData(pfnNotify, userData);
37 notify = this;
38 }
39 return mImpl->build(devices, options, notify);
40 }
41
compile(cl_uint numDevices,const cl_device_id * deviceList,const char * options,cl_uint numInputHeaders,const cl_program * inputHeaders,const char ** headerIncludeNames,ProgramCB pfnNotify,void * userData)42 angle::Result Program::compile(cl_uint numDevices,
43 const cl_device_id *deviceList,
44 const char *options,
45 cl_uint numInputHeaders,
46 const cl_program *inputHeaders,
47 const char **headerIncludeNames,
48 ProgramCB pfnNotify,
49 void *userData)
50 {
51 DevicePtrs devices;
52 devices.reserve(numDevices);
53 while (numDevices-- != 0u)
54 {
55 devices.emplace_back(&(*deviceList++)->cast<Device>());
56 }
57 ProgramPtrs programs;
58 programs.reserve(numInputHeaders);
59 while (numInputHeaders-- != 0u)
60 {
61 programs.emplace_back(&(*inputHeaders++)->cast<Program>());
62 }
63 Program *notify = nullptr;
64 if (pfnNotify != nullptr)
65 {
66 // This program has to be retained until the notify callback is called.
67 retain();
68 *mCallback = CallbackData(pfnNotify, userData);
69 notify = this;
70 }
71 return mImpl->compile(devices, options, programs, headerIncludeNames, notify);
72 }
73
getInfo(ProgramInfo name,size_t valueSize,void * value,size_t * valueSizeRet) const74 angle::Result Program::getInfo(ProgramInfo name,
75 size_t valueSize,
76 void *value,
77 size_t *valueSizeRet) const
78 {
79 std::vector<cl_device_id> devices;
80 cl_uint valUInt = 0u;
81 void *valPointer = nullptr;
82 const void *copyValue = nullptr;
83 size_t copySize = 0u;
84
85 switch (name)
86 {
87 case ProgramInfo::ReferenceCount:
88 valUInt = getRefCount();
89 copyValue = &valUInt;
90 copySize = sizeof(valUInt);
91 break;
92 case ProgramInfo::Context:
93 valPointer = mContext->getNative();
94 copyValue = &valPointer;
95 copySize = sizeof(valPointer);
96 break;
97 case ProgramInfo::NumDevices:
98 valUInt = static_cast<decltype(valUInt)>(mDevices.size());
99 copyValue = &valUInt;
100 copySize = sizeof(valUInt);
101 break;
102 case ProgramInfo::Devices:
103 devices.reserve(mDevices.size());
104 for (const DevicePtr &device : mDevices)
105 {
106 devices.emplace_back(device->getNative());
107 }
108 copyValue = devices.data();
109 copySize = devices.size() * sizeof(decltype(devices)::value_type);
110 break;
111 case ProgramInfo::Source:
112 if (!mSource.empty())
113 {
114 copyValue = mSource.c_str();
115 copySize = mSource.length() + 1u;
116 }
117 break;
118 case ProgramInfo::IL:
119 if (!mIL.empty())
120 {
121 copyValue = mIL.c_str();
122 copySize = mIL.length() + 1u;
123 }
124 break;
125 case ProgramInfo::BinarySizes:
126 case ProgramInfo::Binaries:
127 case ProgramInfo::NumKernels:
128 case ProgramInfo::KernelNames:
129 case ProgramInfo::ScopeGlobalCtorsPresent:
130 case ProgramInfo::ScopeGlobalDtorsPresent:
131 return mImpl->getInfo(name, valueSize, value, valueSizeRet);
132 default:
133 ANGLE_CL_RETURN_ERROR(CL_INVALID_VALUE);
134 }
135
136 if (value != nullptr)
137 {
138 // CL_INVALID_VALUE if size in bytes specified by param_value_size is < size of return type
139 // as described in the Program Object Queries table and param_value is not NULL.
140 if (valueSize < copySize)
141 {
142 ANGLE_CL_RETURN_ERROR(CL_INVALID_VALUE);
143 }
144 if (copyValue != nullptr)
145 {
146 std::memcpy(value, copyValue, copySize);
147 }
148 }
149 if (valueSizeRet != nullptr)
150 {
151 *valueSizeRet = copySize;
152 }
153 return angle::Result::Continue;
154 }
155
getBuildInfo(cl_device_id device,ProgramBuildInfo name,size_t valueSize,void * value,size_t * valueSizeRet) const156 angle::Result Program::getBuildInfo(cl_device_id device,
157 ProgramBuildInfo name,
158 size_t valueSize,
159 void *value,
160 size_t *valueSizeRet) const
161 {
162 return mImpl->getBuildInfo(device->cast<Device>(), name, valueSize, value, valueSizeRet);
163 }
164
createKernel(const char * kernel_name)165 cl_kernel Program::createKernel(const char *kernel_name)
166 {
167 return Object::Create<Kernel>(*this, kernel_name);
168 }
169
createKernels(cl_uint numKernels,cl_kernel * kernels,cl_uint * numKernelsRet)170 angle::Result Program::createKernels(cl_uint numKernels, cl_kernel *kernels, cl_uint *numKernelsRet)
171 {
172 if (kernels == nullptr)
173 {
174 numKernels = 0u;
175 }
176 rx::CLKernelImpl::CreateFuncs createFuncs;
177 ANGLE_TRY(mImpl->createKernels(numKernels, createFuncs, numKernelsRet));
178 KernelPtrs krnls;
179 krnls.reserve(createFuncs.size());
180 while (!createFuncs.empty())
181 {
182 krnls.emplace_back(new Kernel(*this, createFuncs.front()));
183 if (krnls.back()->mImpl == nullptr)
184 {
185 return angle::Result::Stop;
186 }
187 createFuncs.pop_front();
188 }
189 for (KernelPtr &kernel : krnls)
190 {
191 *kernels++ = kernel.release();
192 }
193 return angle::Result::Continue;
194 }
195
196 Program::~Program() = default;
197
callback()198 void Program::callback()
199 {
200 CallbackData callbackData;
201 mCallback->swap(callbackData);
202 const ProgramCB callback = callbackData.first;
203 void *const userData = callbackData.second;
204 ASSERT(callback != nullptr);
205 callback(this, userData);
206 // This program can be released after the callback was called.
207 if (release())
208 {
209 delete this;
210 }
211 }
212
Program(Context & context,std::string && source)213 Program::Program(Context &context, std::string &&source)
214 : mContext(&context),
215 mDevices(context.getDevices()),
216 mNumAttachedKernels(0u),
217 mImpl(nullptr),
218 mSource(std::move(source))
219 {
220 ANGLE_CL_IMPL_TRY(context.getImpl().createProgramWithSource(*this, mSource, &mImpl));
221 }
222
Program(Context & context,const void * il,size_t length)223 Program::Program(Context &context, const void *il, size_t length)
224 : mContext(&context),
225 mDevices(context.getDevices()),
226 mIL(static_cast<const char *>(il), length),
227 mNumAttachedKernels(0u),
228 mImpl(nullptr)
229 {
230 ANGLE_CL_IMPL_TRY(context.getImpl().createProgramWithIL(*this, il, length, &mImpl));
231 }
232
Program(Context & context,DevicePtrs && devices,const size_t * lengths,const unsigned char ** binaries,cl_int * binaryStatus)233 Program::Program(Context &context,
234 DevicePtrs &&devices,
235 const size_t *lengths,
236 const unsigned char **binaries,
237 cl_int *binaryStatus)
238 : mContext(&context), mDevices(std::move(devices)), mNumAttachedKernels(0u), mImpl(nullptr)
239 {
240 ANGLE_CL_IMPL_TRY(
241 context.getImpl().createProgramWithBinary(*this, lengths, binaries, binaryStatus, &mImpl));
242 }
243
Program(Context & context,DevicePtrs && devices,const char * kernelNames)244 Program::Program(Context &context, DevicePtrs &&devices, const char *kernelNames)
245 : mContext(&context), mDevices(std::move(devices)), mNumAttachedKernels(0u), mImpl(nullptr)
246 {
247 ANGLE_CL_IMPL_TRY(
248 context.getImpl().createProgramWithBuiltInKernels(*this, kernelNames, &mImpl));
249 }
250
Program(Context & context,const DevicePtrs & devices,const char * options,const cl::ProgramPtrs & inputPrograms,ProgramCB pfnNotify,void * userData)251 Program::Program(Context &context,
252 const DevicePtrs &devices,
253 const char *options,
254 const cl::ProgramPtrs &inputPrograms,
255 ProgramCB pfnNotify,
256 void *userData)
257 : mContext(&context),
258 mDevices(!devices.empty() ? devices : context.getDevices()),
259 mNumAttachedKernels(0u),
260 mImpl(nullptr)
261 {
262 if (pfnNotify != nullptr)
263 {
264 // This program has to be retained until the notify callback is called.
265 retain();
266 *mCallback = CallbackData(pfnNotify, userData);
267 }
268 else
269 {
270 *mCallback = CallbackData();
271 }
272 ANGLE_CL_IMPL_TRY(context.getImpl().linkProgram(*this, mDevices, options, inputPrograms,
273 pfnNotify != nullptr ? this : nullptr, &mImpl));
274 }
275
276 } // namespace cl
277