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 // CLContext.cpp: Implements the cl::Context class.
7
8 #include "libANGLE/CLContext.h"
9
10 #include "libANGLE/CLBuffer.h"
11 #include "libANGLE/CLCommandQueue.h"
12 #include "libANGLE/CLEvent.h"
13 #include "libANGLE/CLImage.h"
14 #include "libANGLE/CLMemory.h"
15 #include "libANGLE/CLProgram.h"
16 #include "libANGLE/CLSampler.h"
17
18 #include <cstring>
19
20 namespace cl
21 {
22
getInfo(ContextInfo name,size_t valueSize,void * value,size_t * valueSizeRet) const23 angle::Result Context::getInfo(ContextInfo name,
24 size_t valueSize,
25 void *value,
26 size_t *valueSizeRet) const
27 {
28 std::vector<cl_device_id> devices;
29 cl_uint valUInt = 0u;
30 const void *copyValue = nullptr;
31 size_t copySize = 0u;
32
33 switch (name)
34 {
35 case ContextInfo::ReferenceCount:
36 valUInt = getRefCount();
37 copyValue = &valUInt;
38 copySize = sizeof(valUInt);
39 break;
40 case ContextInfo::NumDevices:
41 valUInt = static_cast<decltype(valUInt)>(mDevices.size());
42 copyValue = &valUInt;
43 copySize = sizeof(valUInt);
44 break;
45 case ContextInfo::Devices:
46 devices.reserve(mDevices.size());
47 for (const DevicePtr &device : mDevices)
48 {
49 devices.emplace_back(device->getNative());
50 }
51 copyValue = devices.data();
52 copySize = devices.size() * sizeof(decltype(devices)::value_type);
53 break;
54 case ContextInfo::Properties:
55 copyValue = mProperties.data();
56 copySize = mProperties.size() * sizeof(decltype(mProperties)::value_type);
57 break;
58 default:
59 ASSERT(false);
60 ANGLE_CL_RETURN_ERROR(CL_INVALID_VALUE);
61 }
62
63 if (value != nullptr)
64 {
65 // CL_INVALID_VALUE if size in bytes specified by param_value_size is < size of return type
66 // as specified in the Context Attributes table and param_value is not a NULL value.
67 if (valueSize < copySize)
68 {
69 ANGLE_CL_RETURN_ERROR(CL_INVALID_VALUE);
70 }
71 if (copyValue != nullptr)
72 {
73 std::memcpy(value, copyValue, copySize);
74 }
75 }
76 if (valueSizeRet != nullptr)
77 {
78 *valueSizeRet = copySize;
79 }
80 return angle::Result::Continue;
81 }
82
createCommandQueueWithProperties(cl_device_id device,const cl_queue_properties * properties)83 cl_command_queue Context::createCommandQueueWithProperties(cl_device_id device,
84 const cl_queue_properties *properties)
85 {
86 CommandQueue::PropArray propArray;
87 CommandQueueProperties props;
88 cl_uint size = CommandQueue::kNoSize;
89 if (properties != nullptr)
90 {
91 const cl_queue_properties *propIt = properties;
92 while (*propIt != 0)
93 {
94 switch (*propIt++)
95 {
96 case CL_QUEUE_PROPERTIES:
97 props = static_cast<cl_command_queue_properties>(*propIt++);
98 break;
99 case CL_QUEUE_SIZE:
100 size = static_cast<decltype(size)>(*propIt++);
101 break;
102 }
103 }
104 // Include the trailing zero
105 ++propIt;
106 propArray.reserve(propIt - properties);
107 propArray.insert(propArray.cend(), properties, propIt);
108 }
109 return Object::Create<CommandQueue>(*this, device->cast<Device>(), std::move(propArray), props,
110 size);
111 }
112
createCommandQueue(cl_device_id device,CommandQueueProperties properties)113 cl_command_queue Context::createCommandQueue(cl_device_id device, CommandQueueProperties properties)
114 {
115 return Object::Create<CommandQueue>(*this, device->cast<Device>(), properties);
116 }
117
createBuffer(const cl_mem_properties * properties,MemFlags flags,size_t size,void * hostPtr)118 cl_mem Context::createBuffer(const cl_mem_properties *properties,
119 MemFlags flags,
120 size_t size,
121 void *hostPtr)
122 {
123 // If the properties argument specified in clCreateBufferWithProperties or
124 // clCreateImageWithProperties used to create memobj was not NULL, the implementation must
125 // return the values specified in the properties argument in the same order and without
126 // including additional properties. So pass them as is.
127 Memory::PropArray propArray;
128 if (properties != nullptr)
129 {
130 const cl_mem_properties *propIt = properties;
131 while (*propIt != 0)
132 {
133 propArray.push_back(*propIt);
134 ++propIt;
135 }
136 // there is at least one property - special property 0
137 propArray.push_back(0);
138 }
139 return Object::Create<Buffer>(*this, std::move(propArray), flags, size, hostPtr);
140 }
141
createImage(const cl_mem_properties * properties,MemFlags flags,const cl_image_format * format,const cl_image_desc * desc,void * hostPtr)142 cl_mem Context::createImage(const cl_mem_properties *properties,
143 MemFlags flags,
144 const cl_image_format *format,
145 const cl_image_desc *desc,
146 void *hostPtr)
147 {
148 const ImageDescriptor imageDesc = {FromCLenum<MemObjectType>(desc->image_type),
149 desc->image_width,
150 desc->image_height,
151 desc->image_depth,
152 desc->image_array_size,
153 desc->image_row_pitch,
154 desc->image_slice_pitch,
155 desc->num_mip_levels,
156 desc->num_samples};
157 Memory::PropArray propArray;
158
159 // If the properties argument specified in clCreateBufferWithProperties or
160 // clCreateImageWithProperties used to create memobj was not NULL, the implementation must
161 // return the values specified in the properties argument in the same order and without
162 // including additional properties. So Pass them as is.
163 if (properties != nullptr)
164 {
165 const cl_mem_properties *propIt = properties;
166 while (*propIt != 0)
167 {
168 propArray.push_back(*propIt);
169 ++propIt;
170 }
171 // there is at least one property - special property 0
172 propArray.push_back(0);
173 }
174 return Object::Create<Image>(*this, std::move(propArray), flags, *format, imageDesc,
175 Memory::Cast(desc->buffer), hostPtr);
176 }
177
createImage2D(MemFlags flags,const cl_image_format * format,size_t width,size_t height,size_t rowPitch,void * hostPtr)178 cl_mem Context::createImage2D(MemFlags flags,
179 const cl_image_format *format,
180 size_t width,
181 size_t height,
182 size_t rowPitch,
183 void *hostPtr)
184 {
185 const ImageDescriptor imageDesc(MemObjectType::Image2D, width, height, 0u, 0u, rowPitch, 0u, 0u,
186 0u);
187 return Object::Create<Image>(*this, Memory::PropArray{}, flags, *format, imageDesc, nullptr,
188 hostPtr);
189 }
190
createImage3D(MemFlags flags,const cl_image_format * format,size_t width,size_t height,size_t depth,size_t rowPitch,size_t slicePitch,void * hostPtr)191 cl_mem Context::createImage3D(MemFlags flags,
192 const cl_image_format *format,
193 size_t width,
194 size_t height,
195 size_t depth,
196 size_t rowPitch,
197 size_t slicePitch,
198 void *hostPtr)
199 {
200 const ImageDescriptor imageDesc(MemObjectType::Image3D, width, height, depth, 0u, rowPitch,
201 slicePitch, 0u, 0u);
202 return Object::Create<Image>(*this, Memory::PropArray{}, flags, *format, imageDesc, nullptr,
203 hostPtr);
204 }
205
getSupportedImageFormats(MemFlags flags,MemObjectType imageType,cl_uint numEntries,cl_image_format * imageFormats,cl_uint * numImageFormats)206 angle::Result Context::getSupportedImageFormats(MemFlags flags,
207 MemObjectType imageType,
208 cl_uint numEntries,
209 cl_image_format *imageFormats,
210 cl_uint *numImageFormats)
211 {
212 return mImpl->getSupportedImageFormats(flags, imageType, numEntries, imageFormats,
213 numImageFormats);
214 }
215
createSamplerWithProperties(const cl_sampler_properties * properties)216 cl_sampler Context::createSamplerWithProperties(const cl_sampler_properties *properties)
217 {
218 Sampler::PropArray propArray;
219 cl_bool normalizedCoords = CL_TRUE;
220 AddressingMode addressingMode = AddressingMode::Clamp;
221 FilterMode filterMode = FilterMode::Nearest;
222
223 if (properties != nullptr)
224 {
225 const cl_sampler_properties *propIt = properties;
226 while (*propIt != 0)
227 {
228 switch (*propIt++)
229 {
230 case CL_SAMPLER_NORMALIZED_COORDS:
231 normalizedCoords = static_cast<decltype(normalizedCoords)>(*propIt++);
232 break;
233 case CL_SAMPLER_ADDRESSING_MODE:
234 addressingMode = FromCLenum<AddressingMode>(static_cast<CLenum>(*propIt++));
235 break;
236 case CL_SAMPLER_FILTER_MODE:
237 filterMode = FromCLenum<FilterMode>(static_cast<CLenum>(*propIt++));
238 break;
239 }
240 }
241 // Include the trailing zero
242 ++propIt;
243 propArray.reserve(propIt - properties);
244 propArray.insert(propArray.cend(), properties, propIt);
245 }
246
247 return Object::Create<Sampler>(*this, std::move(propArray), normalizedCoords, addressingMode,
248 filterMode);
249 }
250
createSampler(cl_bool normalizedCoords,AddressingMode addressingMode,FilterMode filterMode)251 cl_sampler Context::createSampler(cl_bool normalizedCoords,
252 AddressingMode addressingMode,
253 FilterMode filterMode)
254 {
255 return Object::Create<Sampler>(*this, Sampler::PropArray{}, normalizedCoords, addressingMode,
256 filterMode);
257 }
258
createProgramWithSource(cl_uint count,const char ** strings,const size_t * lengths)259 cl_program Context::createProgramWithSource(cl_uint count,
260 const char **strings,
261 const size_t *lengths)
262 {
263 std::string source;
264 if (lengths == nullptr)
265 {
266 while (count-- != 0u)
267 {
268 source.append(*strings++);
269 }
270 }
271 else
272 {
273 while (count-- != 0u)
274 {
275 if (*lengths != 0u)
276 {
277 source.append(*strings++, *lengths);
278 }
279 else
280 {
281 source.append(*strings++);
282 }
283 ++lengths;
284 }
285 }
286 return Object::Create<Program>(*this, std::move(source));
287 }
288
createProgramWithIL(const void * il,size_t length)289 cl_program Context::createProgramWithIL(const void *il, size_t length)
290 {
291 return Object::Create<Program>(*this, il, length);
292 }
293
createProgramWithBinary(cl_uint numDevices,const cl_device_id * devices,const size_t * lengths,const unsigned char ** binaries,cl_int * binaryStatus)294 cl_program Context::createProgramWithBinary(cl_uint numDevices,
295 const cl_device_id *devices,
296 const size_t *lengths,
297 const unsigned char **binaries,
298 cl_int *binaryStatus)
299 {
300 DevicePtrs devs;
301 devs.reserve(numDevices);
302 while (numDevices-- != 0u)
303 {
304 devs.emplace_back(&(*devices++)->cast<Device>());
305 }
306 return Object::Create<Program>(*this, std::move(devs), lengths, binaries, binaryStatus);
307 }
308
createProgramWithBuiltInKernels(cl_uint numDevices,const cl_device_id * devices,const char * kernelNames)309 cl_program Context::createProgramWithBuiltInKernels(cl_uint numDevices,
310 const cl_device_id *devices,
311 const char *kernelNames)
312 {
313 DevicePtrs devs;
314 devs.reserve(numDevices);
315 while (numDevices-- != 0u)
316 {
317 devs.emplace_back(&(*devices++)->cast<Device>());
318 }
319 return Object::Create<Program>(*this, std::move(devs), kernelNames);
320 }
321
linkProgram(cl_uint numDevices,const cl_device_id * deviceList,const char * options,cl_uint numInputPrograms,const cl_program * inputPrograms,ProgramCB pfnNotify,void * userData)322 cl_program Context::linkProgram(cl_uint numDevices,
323 const cl_device_id *deviceList,
324 const char *options,
325 cl_uint numInputPrograms,
326 const cl_program *inputPrograms,
327 ProgramCB pfnNotify,
328 void *userData)
329 {
330 DevicePtrs devices;
331 devices.reserve(numDevices);
332 while (numDevices-- != 0u)
333 {
334 devices.emplace_back(&(*deviceList++)->cast<Device>());
335 }
336 ProgramPtrs programs;
337 programs.reserve(numInputPrograms);
338 while (numInputPrograms-- != 0u)
339 {
340 programs.emplace_back(&(*inputPrograms++)->cast<Program>());
341 }
342 return Object::Create<Program>(*this, devices, options, programs, pfnNotify, userData);
343 }
344
createUserEvent()345 cl_event Context::createUserEvent()
346 {
347 return Object::Create<Event>(*this);
348 }
349
waitForEvents(cl_uint numEvents,const cl_event * eventList)350 angle::Result Context::waitForEvents(cl_uint numEvents, const cl_event *eventList)
351 {
352 return mImpl->waitForEvents(Event::Cast(numEvents, eventList));
353 }
354
355 Context::~Context() = default;
356
ErrorCallback(const char * errinfo,const void * privateInfo,size_t cb,void * userData)357 void Context::ErrorCallback(const char *errinfo, const void *privateInfo, size_t cb, void *userData)
358 {
359 Context *const context = static_cast<Context *>(userData);
360 if (!Context::IsValid(context))
361 {
362 WARN() << "Context error for invalid context";
363 return;
364 }
365 if (context->mNotify != nullptr)
366 {
367 context->mNotify(errinfo, privateInfo, cb, context->mUserData);
368 }
369 }
370
Context(Platform & platform,PropArray && properties,DevicePtrs && devices,ContextErrorCB notify,void * userData,bool userSync)371 Context::Context(Platform &platform,
372 PropArray &&properties,
373 DevicePtrs &&devices,
374 ContextErrorCB notify,
375 void *userData,
376 bool userSync)
377 : mPlatform(platform),
378 mProperties(std::move(properties)),
379 mNotify(notify),
380 mUserData(userData),
381 mImpl(nullptr),
382 mDevices(std::move(devices))
383 {
384 ANGLE_CL_IMPL_TRY(platform.getImpl().createContext(*this, mDevices, userSync, &mImpl));
385 }
386
Context(Platform & platform,PropArray && properties,DeviceType deviceType,ContextErrorCB notify,void * userData,bool userSync)387 Context::Context(Platform &platform,
388 PropArray &&properties,
389 DeviceType deviceType,
390 ContextErrorCB notify,
391 void *userData,
392 bool userSync)
393 : mPlatform(platform),
394 mProperties(std::move(properties)),
395 mNotify(notify),
396 mUserData(userData),
397 mImpl(nullptr)
398 {
399 if (!IsError(platform.getImpl().createContextFromType(*this, deviceType, userSync, &mImpl)))
400 {
401 ANGLE_CL_IMPL_TRY(mImpl->getDevices(&mDevices));
402 }
403 }
404
405 } // namespace cl
406