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 // CLContextCL.cpp: Implements the class methods for CLContextCL.
7
8 #include "libANGLE/renderer/cl/CLContextCL.h"
9
10 #include "libANGLE/renderer/cl/CLCommandQueueCL.h"
11 #include "libANGLE/renderer/cl/CLDeviceCL.h"
12 #include "libANGLE/renderer/cl/CLEventCL.h"
13 #include "libANGLE/renderer/cl/CLMemoryCL.h"
14 #include "libANGLE/renderer/cl/CLPlatformCL.h"
15 #include "libANGLE/renderer/cl/CLProgramCL.h"
16 #include "libANGLE/renderer/cl/CLSamplerCL.h"
17
18 #include "libANGLE/CLBuffer.h"
19 #include "libANGLE/CLCommandQueue.h"
20 #include "libANGLE/CLContext.h"
21 #include "libANGLE/CLDevice.h"
22 #include "libANGLE/CLEvent.h"
23 #include "libANGLE/CLImage.h"
24 #include "libANGLE/CLMemory.h"
25 #include "libANGLE/CLPlatform.h"
26 #include "libANGLE/CLProgram.h"
27 #include "libANGLE/CLSampler.h"
28 #include "libANGLE/cl_utils.h"
29
30 namespace rx
31 {
32
CLContextCL(const cl::Context & context,cl_context native)33 CLContextCL::CLContextCL(const cl::Context &context, cl_context native)
34 : CLContextImpl(context), mNative(native)
35 {}
36
~CLContextCL()37 CLContextCL::~CLContextCL()
38 {
39 if (mNative->getDispatch().clReleaseContext(mNative) != CL_SUCCESS)
40 {
41 ERR() << "Error while releasing CL context";
42 }
43 }
44
getDevices(cl::DevicePtrs * devicePtrsOut) const45 angle::Result CLContextCL::getDevices(cl::DevicePtrs *devicePtrsOut) const
46 {
47 size_t valueSize = 0u;
48 ANGLE_CL_TRY(mNative->getDispatch().clGetContextInfo(mNative, CL_CONTEXT_DEVICES, 0u, nullptr,
49 &valueSize));
50 if ((valueSize % sizeof(cl_device_id)) == 0u)
51 {
52 std::vector<cl_device_id> nativeDevices(valueSize / sizeof(cl_device_id), nullptr);
53 ANGLE_CL_TRY(mNative->getDispatch().clGetContextInfo(mNative, CL_CONTEXT_DEVICES, valueSize,
54 nativeDevices.data(), nullptr));
55 const cl::DevicePtrs &platformDevices = mContext.getPlatform().getDevices();
56 devicePtrsOut->reserve(nativeDevices.size());
57 for (cl_device_id nativeDevice : nativeDevices)
58 {
59 auto it = platformDevices.cbegin();
60 while (it != platformDevices.cend() &&
61 (*it)->getImpl<CLDeviceCL>().getNative() != nativeDevice)
62 {
63 ++it;
64 }
65 if (it != platformDevices.cend())
66 {
67 devicePtrsOut->emplace_back(it->get());
68 }
69 else
70 {
71 ASSERT(false);
72 ERR() << "Device not found in platform list";
73 ANGLE_CL_RETURN_ERROR(CL_INVALID_DEVICE);
74 }
75 }
76 return angle::Result::Continue;
77 }
78 return angle::Result::Continue;
79 }
80
createCommandQueue(const cl::CommandQueue & commandQueue,CLCommandQueueImpl::Ptr * commandQueueOut)81 angle::Result CLContextCL::createCommandQueue(const cl::CommandQueue &commandQueue,
82 CLCommandQueueImpl::Ptr *commandQueueOut)
83 {
84 cl_int errorCode = CL_SUCCESS;
85 const cl::Device &device = commandQueue.getDevice();
86 const cl_device_id nativeDevice = device.getImpl<CLDeviceCL>().getNative();
87 cl_command_queue nativeQueue = nullptr;
88
89 if (!device.isVersionOrNewer(2u, 0u))
90 {
91 nativeQueue = mNative->getDispatch().clCreateCommandQueue(
92 mNative, nativeDevice, commandQueue.getProperties().get(), &errorCode);
93 }
94 else
95 {
96 const cl_queue_properties propArray[] = {
97 CL_QUEUE_PROPERTIES, commandQueue.getProperties().get(),
98 commandQueue.hasSize() ? CL_QUEUE_SIZE : 0u, commandQueue.getSize(), 0u};
99 nativeQueue = mNative->getDispatch().clCreateCommandQueueWithProperties(
100 mNative, nativeDevice, propArray, &errorCode);
101 }
102 ANGLE_CL_TRY(errorCode);
103
104 *commandQueueOut = CLCommandQueueImpl::Ptr(
105 nativeQueue != nullptr ? new CLCommandQueueCL(commandQueue, nativeQueue) : nullptr);
106 return angle::Result::Continue;
107 }
108
createBuffer(const cl::Buffer & buffer,void * hostPtr,CLMemoryImpl::Ptr * bufferOut)109 angle::Result CLContextCL::createBuffer(const cl::Buffer &buffer,
110 void *hostPtr,
111 CLMemoryImpl::Ptr *bufferOut)
112 {
113 cl_int errorCode = CL_SUCCESS;
114 cl_mem nativeBuffer = nullptr;
115
116 if (buffer.getProperties().empty())
117 {
118 nativeBuffer = mNative->getDispatch().clCreateBuffer(mNative, buffer.getFlags().get(),
119 buffer.getSize(), hostPtr, &errorCode);
120 }
121 else
122 {
123 nativeBuffer = mNative->getDispatch().clCreateBufferWithProperties(
124 mNative, buffer.getProperties().data(), buffer.getFlags().get(), buffer.getSize(),
125 hostPtr, &errorCode);
126 }
127 ANGLE_CL_TRY(errorCode);
128
129 *bufferOut =
130 CLMemoryImpl::Ptr(nativeBuffer != nullptr ? new CLMemoryCL(buffer, nativeBuffer) : nullptr);
131 return angle::Result::Continue;
132 }
133
createImage(const cl::Image & image,void * hostPtr,CLMemoryImpl::Ptr * imageOut)134 angle::Result CLContextCL::createImage(const cl::Image &image,
135 void *hostPtr,
136 CLMemoryImpl::Ptr *imageOut)
137 {
138 cl_int errorCode = CL_SUCCESS;
139 cl_mem nativeImage = nullptr;
140 cl::ImageDescriptor desc = image.getDescriptor();
141 cl::MemFlags flags = image.getFlags();
142 cl_image_format format = image.getFormat();
143
144 if (mContext.getPlatform().isVersionOrNewer(1u, 2u))
145 {
146 const cl_mem_object_type nativeType = cl::ToCLenum(desc.type);
147 const cl_mem nativeParent =
148 image.getParent() ? image.getParent()->getImpl<CLMemoryCL>().getNative() : nullptr;
149 const cl_image_desc nativeDesc = {
150 nativeType, desc.width, desc.height, desc.depth, desc.arraySize,
151 desc.rowPitch, desc.slicePitch, desc.numMipLevels, desc.numSamples, {nativeParent}};
152
153 if (image.getProperties().empty())
154 {
155 nativeImage = mNative->getDispatch().clCreateImage(mNative, flags.get(), &format,
156 &nativeDesc, hostPtr, &errorCode);
157 }
158 else
159 {
160 nativeImage = mNative->getDispatch().clCreateImageWithProperties(
161 mNative, image.getProperties().data(), flags.get(), &format, &nativeDesc, hostPtr,
162 &errorCode);
163 }
164 }
165 else
166 {
167 switch (desc.type)
168 {
169 case cl::MemObjectType::Image2D:
170 nativeImage = mNative->getDispatch().clCreateImage2D(
171 mNative, flags.get(), &format, desc.width, desc.height, desc.rowPitch, hostPtr,
172 &errorCode);
173 break;
174 case cl::MemObjectType::Image3D:
175 nativeImage = mNative->getDispatch().clCreateImage3D(
176 mNative, flags.get(), &format, desc.width, desc.height, desc.depth,
177 desc.rowPitch, desc.slicePitch, hostPtr, &errorCode);
178 break;
179 default:
180 ASSERT(false);
181 ERR() << "Failed to create unsupported image type";
182 break;
183 }
184 }
185 ANGLE_CL_TRY(errorCode);
186
187 *imageOut =
188 CLMemoryImpl::Ptr(nativeImage != nullptr ? new CLMemoryCL(image, nativeImage) : nullptr);
189 return angle::Result::Continue;
190 }
191
getSupportedImageFormats(cl::MemFlags flags,cl::MemObjectType imageType,cl_uint numEntries,cl_image_format * imageFormats,cl_uint * numImageFormats)192 angle::Result CLContextCL::getSupportedImageFormats(cl::MemFlags flags,
193 cl::MemObjectType imageType,
194 cl_uint numEntries,
195 cl_image_format *imageFormats,
196 cl_uint *numImageFormats)
197 {
198 // Fetch available image formats for given flags and image type.
199 cl_uint numFormats = 0u;
200 ANGLE_CL_TRY(mNative->getDispatch().clGetSupportedImageFormats(
201 mNative, flags.get(), cl::ToCLenum(imageType), 0u, nullptr, &numFormats));
202 std::vector<cl_image_format> formats(numFormats);
203 ANGLE_CL_TRY(mNative->getDispatch().clGetSupportedImageFormats(
204 mNative, flags.get(), cl::ToCLenum(imageType), numFormats, formats.data(), nullptr));
205
206 // Filter out formats which are not supported by front end.
207 const CLPlatformImpl::Info &info = mContext.getPlatform().getInfo();
208 std::vector<cl_image_format> supportedFormats;
209 supportedFormats.reserve(formats.size());
210 std::copy_if(
211 formats.cbegin(), formats.cend(), std::back_inserter(supportedFormats),
212 [&](const cl_image_format &format) { return cl::IsValidImageFormat(&format, info); });
213
214 if (imageFormats != nullptr)
215 {
216 auto formatIt = supportedFormats.cbegin();
217 while (numEntries-- != 0u && formatIt != supportedFormats.cend())
218 {
219 *imageFormats++ = *formatIt++;
220 }
221 }
222 if (numImageFormats != nullptr)
223 {
224 *numImageFormats = static_cast<cl_uint>(supportedFormats.size());
225 }
226 return angle::Result::Continue;
227 }
228
createSampler(const cl::Sampler & sampler,CLSamplerImpl::Ptr * samplerOut)229 angle::Result CLContextCL::createSampler(const cl::Sampler &sampler, CLSamplerImpl::Ptr *samplerOut)
230 {
231 cl_int errorCode = CL_SUCCESS;
232 cl_sampler nativeSampler = nullptr;
233
234 if (!mContext.getPlatform().isVersionOrNewer(2u, 0u))
235 {
236 nativeSampler = mNative->getDispatch().clCreateSampler(
237 mNative, sampler.getNormalizedCoords(), cl::ToCLenum(sampler.getAddressingMode()),
238 cl::ToCLenum(sampler.getFilterMode()), &errorCode);
239 }
240 else if (!sampler.getProperties().empty())
241 {
242 nativeSampler = mNative->getDispatch().clCreateSamplerWithProperties(
243 mNative, sampler.getProperties().data(), &errorCode);
244 }
245 else
246 {
247 const cl_sampler_properties propArray[] = {CL_SAMPLER_NORMALIZED_COORDS,
248 sampler.getNormalizedCoords(),
249 CL_SAMPLER_ADDRESSING_MODE,
250 cl::ToCLenum(sampler.getAddressingMode()),
251 CL_SAMPLER_FILTER_MODE,
252 cl::ToCLenum(sampler.getFilterMode()),
253 0u};
254 nativeSampler =
255 mNative->getDispatch().clCreateSamplerWithProperties(mNative, propArray, &errorCode);
256 }
257 ANGLE_CL_TRY(errorCode);
258
259 *samplerOut = CLSamplerImpl::Ptr(
260 nativeSampler != nullptr ? new CLSamplerCL(sampler, nativeSampler) : nullptr);
261 return angle::Result::Continue;
262 }
263
createProgramWithSource(const cl::Program & program,const std::string & source,CLProgramImpl::Ptr * programOut)264 angle::Result CLContextCL::createProgramWithSource(const cl::Program &program,
265 const std::string &source,
266 CLProgramImpl::Ptr *programOut)
267 {
268 cl_int errorCode = CL_SUCCESS;
269 const char *sourceStr = source.c_str();
270 const size_t length = source.length();
271
272 const cl_program nativeProgram = mNative->getDispatch().clCreateProgramWithSource(
273 mNative, 1u, &sourceStr, &length, &errorCode);
274 ANGLE_CL_TRY(errorCode);
275
276 *programOut = CLProgramImpl::Ptr(
277 nativeProgram != nullptr ? new CLProgramCL(program, nativeProgram) : nullptr);
278 return angle::Result::Continue;
279 }
280
createProgramWithIL(const cl::Program & program,const void * il,size_t length,CLProgramImpl::Ptr * programOut)281 angle::Result CLContextCL::createProgramWithIL(const cl::Program &program,
282 const void *il,
283 size_t length,
284 CLProgramImpl::Ptr *programOut)
285 {
286 cl_int errorCode = CL_SUCCESS;
287
288 const cl_program nativeProgram =
289 mNative->getDispatch().clCreateProgramWithIL(mNative, il, length, &errorCode);
290 ANGLE_CL_TRY(errorCode);
291
292 *programOut = CLProgramImpl::Ptr(
293 nativeProgram != nullptr ? new CLProgramCL(program, nativeProgram) : nullptr);
294 return angle::Result::Continue;
295 }
296
createProgramWithBinary(const cl::Program & program,const size_t * lengths,const unsigned char ** binaries,cl_int * binaryStatus,CLProgramImpl::Ptr * programOut)297 angle::Result CLContextCL::createProgramWithBinary(const cl::Program &program,
298 const size_t *lengths,
299 const unsigned char **binaries,
300 cl_int *binaryStatus,
301 CLProgramImpl::Ptr *programOut)
302 {
303 cl_int errorCode = CL_SUCCESS;
304 std::vector<cl_device_id> nativeDevices;
305 for (const cl::DevicePtr &device : program.getDevices())
306 {
307 nativeDevices.emplace_back(device->getImpl<CLDeviceCL>().getNative());
308 }
309
310 cl_program nativeProgram = mNative->getDispatch().clCreateProgramWithBinary(
311 mNative, static_cast<cl_uint>(nativeDevices.size()), nativeDevices.data(), lengths,
312 binaries, binaryStatus, &errorCode);
313 ANGLE_CL_TRY(errorCode);
314
315 *programOut = CLProgramImpl::Ptr(
316 nativeProgram != nullptr ? new CLProgramCL(program, nativeProgram) : nullptr);
317 return angle::Result::Continue;
318 }
319
createProgramWithBuiltInKernels(const cl::Program & program,const char * kernel_names,CLProgramImpl::Ptr * programOut)320 angle::Result CLContextCL::createProgramWithBuiltInKernels(const cl::Program &program,
321 const char *kernel_names,
322 CLProgramImpl::Ptr *programOut)
323 {
324 cl_int errorCode = CL_SUCCESS;
325 std::vector<cl_device_id> nativeDevices;
326 for (const cl::DevicePtr &device : program.getDevices())
327 {
328 nativeDevices.emplace_back(device->getImpl<CLDeviceCL>().getNative());
329 }
330
331 const cl_program nativeProgram = mNative->getDispatch().clCreateProgramWithBuiltInKernels(
332 mNative, static_cast<cl_uint>(nativeDevices.size()), nativeDevices.data(), kernel_names,
333 &errorCode);
334 ANGLE_CL_TRY(errorCode);
335
336 *programOut = CLProgramImpl::Ptr(
337 nativeProgram != nullptr ? new CLProgramCL(program, nativeProgram) : nullptr);
338 return angle::Result::Continue;
339 }
340
linkProgram(const cl::Program & program,const cl::DevicePtrs & devices,const char * options,const cl::ProgramPtrs & inputPrograms,cl::Program * notify,CLProgramImpl::Ptr * programOut)341 angle::Result CLContextCL::linkProgram(const cl::Program &program,
342 const cl::DevicePtrs &devices,
343 const char *options,
344 const cl::ProgramPtrs &inputPrograms,
345 cl::Program *notify,
346 CLProgramImpl::Ptr *programOut)
347 {
348 cl_int errorCode = CL_SUCCESS;
349 std::vector<cl_device_id> nativeDevices;
350 for (const cl::DevicePtr &device : devices)
351 {
352 nativeDevices.emplace_back(device->getImpl<CLDeviceCL>().getNative());
353 }
354 const cl_uint numDevices = static_cast<cl_uint>(nativeDevices.size());
355 const cl_device_id *const nativeDevicesPtr =
356 !nativeDevices.empty() ? nativeDevices.data() : nullptr;
357
358 std::vector<cl_program> nativePrograms;
359 for (const cl::ProgramPtr &inputProgram : inputPrograms)
360 {
361 nativePrograms.emplace_back(inputProgram->getImpl<CLProgramCL>().getNative());
362 }
363 const cl_uint numInputHeaders = static_cast<cl_uint>(nativePrograms.size());
364
365 const cl::ProgramCB callback = notify != nullptr ? CLProgramCL::Callback : nullptr;
366 const cl_program nativeProgram = mNative->getDispatch().clLinkProgram(
367 mNative, numDevices, nativeDevicesPtr, options, numInputHeaders, nativePrograms.data(),
368 callback, notify, &errorCode);
369 ANGLE_CL_TRY(errorCode);
370
371 *programOut = CLProgramImpl::Ptr(
372 nativeProgram != nullptr ? new CLProgramCL(program, nativeProgram) : nullptr);
373 return angle::Result::Continue;
374 }
375
createUserEvent(const cl::Event & event,CLEventImpl::Ptr * programOut)376 angle::Result CLContextCL::createUserEvent(const cl::Event &event, CLEventImpl::Ptr *programOut)
377 {
378 cl_int errorCode = CL_SUCCESS;
379
380 const cl_event nativeEvent = mNative->getDispatch().clCreateUserEvent(mNative, &errorCode);
381 ANGLE_CL_TRY(errorCode);
382
383 *programOut =
384 CLEventImpl::Ptr(nativeEvent != nullptr ? new CLEventCL(event, nativeEvent) : nullptr);
385 return angle::Result::Continue;
386 }
387
waitForEvents(const cl::EventPtrs & events)388 angle::Result CLContextCL::waitForEvents(const cl::EventPtrs &events)
389 {
390 const std::vector<cl_event> nativeEvents = CLEventCL::Cast(events);
391 ANGLE_CL_TRY(mNative->getDispatch().clWaitForEvents(static_cast<cl_uint>(nativeEvents.size()),
392 nativeEvents.data()));
393 return angle::Result::Continue;
394 }
395
396 } // namespace rx
397