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 // CLContextVk.cpp: Implements the class methods for CLContextVk.
7
8 #include "libANGLE/renderer/vulkan/CLContextVk.h"
9 #include "libANGLE/renderer/vulkan/CLCommandQueueVk.h"
10 #include "libANGLE/renderer/vulkan/CLEventVk.h"
11 #include "libANGLE/renderer/vulkan/CLMemoryVk.h"
12 #include "libANGLE/renderer/vulkan/CLProgramVk.h"
13 #include "libANGLE/renderer/vulkan/vk_renderer.h"
14 #include "libANGLE/renderer/vulkan/vk_utils.h"
15
16 #include "libANGLE/CLBuffer.h"
17 #include "libANGLE/CLContext.h"
18 #include "libANGLE/CLEvent.h"
19 #include "libANGLE/CLProgram.h"
20 #include "libANGLE/cl_utils.h"
21
22 namespace rx
23 {
24
CLContextVk(const cl::Context & context,const cl::DevicePtrs devicePtrs)25 CLContextVk::CLContextVk(const cl::Context &context, const cl::DevicePtrs devicePtrs)
26 : CLContextImpl(context),
27 vk::Context(getPlatform()->getRenderer()),
28 mAssociatedDevices(devicePtrs)
29 {
30 mDeviceQueueIndex = mRenderer->getDefaultDeviceQueueIndex();
31 }
32
33 CLContextVk::~CLContextVk() = default;
34
handleError(VkResult errorCode,const char * file,const char * function,unsigned int line)35 void CLContextVk::handleError(VkResult errorCode,
36 const char *file,
37 const char *function,
38 unsigned int line)
39 {
40 ASSERT(errorCode != VK_SUCCESS);
41
42 CLenum clErrorCode = CL_SUCCESS;
43 switch (errorCode)
44 {
45 case VK_ERROR_TOO_MANY_OBJECTS:
46 case VK_ERROR_OUT_OF_HOST_MEMORY:
47 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
48 clErrorCode = CL_OUT_OF_HOST_MEMORY;
49 break;
50 default:
51 clErrorCode = CL_INVALID_OPERATION;
52 }
53 ERR() << "Internal Vulkan error (" << errorCode << "): " << VulkanResultString(errorCode);
54 ERR() << " CL error (" << clErrorCode << ")";
55
56 if (errorCode == VK_ERROR_DEVICE_LOST)
57 {
58 handleDeviceLost();
59 }
60 ANGLE_CL_SET_ERROR(clErrorCode);
61 }
62
handleDeviceLost() const63 void CLContextVk::handleDeviceLost() const
64 {
65 // For now just notify the renderer
66 getRenderer()->notifyDeviceLost();
67 }
68
getDevices(cl::DevicePtrs * devicePtrsOut) const69 angle::Result CLContextVk::getDevices(cl::DevicePtrs *devicePtrsOut) const
70 {
71 ASSERT(!mAssociatedDevices.empty());
72 *devicePtrsOut = mAssociatedDevices;
73 return angle::Result::Continue;
74 }
75
createCommandQueue(const cl::CommandQueue & commandQueue,CLCommandQueueImpl::Ptr * commandQueueOut)76 angle::Result CLContextVk::createCommandQueue(const cl::CommandQueue &commandQueue,
77 CLCommandQueueImpl::Ptr *commandQueueOut)
78 {
79 CLCommandQueueVk *queueImpl = new CLCommandQueueVk(commandQueue);
80 if (queueImpl == nullptr)
81 {
82 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
83 }
84 ANGLE_TRY(queueImpl->init());
85 *commandQueueOut = CLCommandQueueVk::Ptr(std::move(queueImpl));
86 return angle::Result::Continue;
87 }
88
createBuffer(const cl::Buffer & buffer,void * hostPtr,CLMemoryImpl::Ptr * bufferOut)89 angle::Result CLContextVk::createBuffer(const cl::Buffer &buffer,
90 void *hostPtr,
91 CLMemoryImpl::Ptr *bufferOut)
92 {
93 CLBufferVk *memory = new (std::nothrow) CLBufferVk(buffer);
94 if (memory == nullptr)
95 {
96 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
97 }
98 ANGLE_TRY(memory->create(hostPtr));
99 *bufferOut = CLMemoryImpl::Ptr(memory);
100 mAssociatedObjects->mMemories.emplace(buffer.getNative());
101 return angle::Result::Continue;
102 }
103
createImage(const cl::Image & image,cl::MemFlags flags,const cl_image_format & format,const cl::ImageDescriptor & desc,void * hostPtr,CLMemoryImpl::Ptr * imageOut)104 angle::Result CLContextVk::createImage(const cl::Image &image,
105 cl::MemFlags flags,
106 const cl_image_format &format,
107 const cl::ImageDescriptor &desc,
108 void *hostPtr,
109 CLMemoryImpl::Ptr *imageOut)
110 {
111 UNIMPLEMENTED();
112 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
113 }
114
getSupportedImageFormats(cl::MemFlags flags,cl::MemObjectType imageType,cl_uint numEntries,cl_image_format * imageFormats,cl_uint * numImageFormats)115 angle::Result CLContextVk::getSupportedImageFormats(cl::MemFlags flags,
116 cl::MemObjectType imageType,
117 cl_uint numEntries,
118 cl_image_format *imageFormats,
119 cl_uint *numImageFormats)
120 {
121 UNIMPLEMENTED();
122 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
123 }
124
createSampler(const cl::Sampler & sampler,CLSamplerImpl::Ptr * samplerOut)125 angle::Result CLContextVk::createSampler(const cl::Sampler &sampler, CLSamplerImpl::Ptr *samplerOut)
126 {
127 UNIMPLEMENTED();
128 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
129 }
130
createProgramWithSource(const cl::Program & program,const std::string & source,CLProgramImpl::Ptr * programOut)131 angle::Result CLContextVk::createProgramWithSource(const cl::Program &program,
132 const std::string &source,
133 CLProgramImpl::Ptr *programOut)
134 {
135 CLProgramVk *programVk = new (std::nothrow) CLProgramVk(program);
136 if (programVk == nullptr)
137 {
138 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
139 }
140 ANGLE_TRY(programVk->init());
141 *programOut = CLProgramImpl::Ptr(std::move(programVk));
142
143 return angle::Result::Continue;
144 }
145
createProgramWithIL(const cl::Program & program,const void * il,size_t length,CLProgramImpl::Ptr * programOut)146 angle::Result CLContextVk::createProgramWithIL(const cl::Program &program,
147 const void *il,
148 size_t length,
149 CLProgramImpl::Ptr *programOut)
150 {
151 UNIMPLEMENTED();
152 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
153 }
154
createProgramWithBinary(const cl::Program & program,const size_t * lengths,const unsigned char ** binaries,cl_int * binaryStatus,CLProgramImpl::Ptr * programOut)155 angle::Result CLContextVk::createProgramWithBinary(const cl::Program &program,
156 const size_t *lengths,
157 const unsigned char **binaries,
158 cl_int *binaryStatus,
159 CLProgramImpl::Ptr *programOut)
160 {
161 CLProgramVk *programVk = new (std::nothrow) CLProgramVk(program);
162 if (programVk == nullptr)
163 {
164 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
165 }
166 ANGLE_TRY(programVk->init(lengths, binaries, binaryStatus));
167 *programOut = CLProgramImpl::Ptr(std::move(programVk));
168
169 return angle::Result::Continue;
170 }
171
createProgramWithBuiltInKernels(const cl::Program & program,const char * kernel_names,CLProgramImpl::Ptr * programOut)172 angle::Result CLContextVk::createProgramWithBuiltInKernels(const cl::Program &program,
173 const char *kernel_names,
174 CLProgramImpl::Ptr *programOut)
175 {
176 UNIMPLEMENTED();
177 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
178 }
179
linkProgram(const cl::Program & program,const cl::DevicePtrs & devices,const char * options,const cl::ProgramPtrs & inputPrograms,cl::Program * notify,CLProgramImpl::Ptr * programOut)180 angle::Result CLContextVk::linkProgram(const cl::Program &program,
181 const cl::DevicePtrs &devices,
182 const char *options,
183 const cl::ProgramPtrs &inputPrograms,
184 cl::Program *notify,
185 CLProgramImpl::Ptr *programOut)
186 {
187 const cl::DevicePtrs &devicePtrs = !devices.empty() ? devices : mContext.getDevices();
188
189 CLProgramVk::Ptr programImpl = CLProgramVk::Ptr(new (std::nothrow) CLProgramVk(program));
190 if (programImpl == nullptr)
191 {
192 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
193 }
194
195 cl::DevicePtrs linkDeviceList;
196 CLProgramVk::LinkProgramsList linkProgramsList;
197 cl::BitField libraryOrObject(CL_PROGRAM_BINARY_TYPE_LIBRARY |
198 CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT);
199 for (const cl::DevicePtr &devicePtr : devicePtrs)
200 {
201 CLProgramVk::LinkPrograms linkPrograms;
202 for (const cl::ProgramPtr &inputProgram : inputPrograms)
203 {
204 const CLProgramVk::DeviceProgramData *deviceProgramData =
205 inputProgram->getImpl<CLProgramVk>().getDeviceProgramData(devicePtr->getNative());
206
207 // Should be valid at this point
208 ASSERT(deviceProgramData != nullptr);
209
210 if (libraryOrObject.isSet(deviceProgramData->binaryType))
211 {
212 linkPrograms.push_back(deviceProgramData);
213 }
214 }
215 if (!linkPrograms.empty())
216 {
217 linkDeviceList.push_back(devicePtr);
218 linkProgramsList.push_back(linkPrograms);
219 }
220 }
221
222 // Perform link
223 if (notify)
224 {
225 std::shared_ptr<angle::WaitableEvent> asyncEvent =
226 mContext.getPlatform().getMultiThreadPool()->postWorkerTask(
227 std::make_shared<CLAsyncBuildTask>(
228 programImpl.get(), linkDeviceList, std::string(options ? options : ""), "",
229 CLProgramVk::BuildType::LINK, linkProgramsList, notify));
230 ASSERT(asyncEvent != nullptr);
231 }
232 else
233 {
234 if (!programImpl->buildInternal(linkDeviceList, std::string(options ? options : ""), "",
235 CLProgramVk::BuildType::LINK, linkProgramsList))
236 {
237 ANGLE_CL_RETURN_ERROR(CL_LINK_PROGRAM_FAILURE);
238 }
239 }
240
241 *programOut = std::move(programImpl);
242 return angle::Result::Continue;
243 }
244
createUserEvent(const cl::Event & event,CLEventImpl::Ptr * eventOut)245 angle::Result CLContextVk::createUserEvent(const cl::Event &event, CLEventImpl::Ptr *eventOut)
246 {
247 *eventOut = CLEventImpl::Ptr(new (std::nothrow) CLEventVk(event));
248 if (*eventOut == nullptr)
249 {
250 ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
251 }
252 return angle::Result::Continue;
253 }
254
waitForEvents(const cl::EventPtrs & events)255 angle::Result CLContextVk::waitForEvents(const cl::EventPtrs &events)
256 {
257 for (auto &event : events)
258 {
259 CLEventVk *eventVk = &event.get()->getImpl<CLEventVk>();
260 if (eventVk->isUserEvent())
261 {
262 ANGLE_TRY(eventVk->waitForUserEventStatus());
263 }
264 else
265 {
266 // TODO rework this to instead (flush w/ ResourceUse serial wait) once we move away from
267 // spawning a submit-thread/Task for flush routine
268 // https://anglebug.com/8669
269 ANGLE_TRY(event->getCommandQueue()->finish());
270 }
271 }
272
273 return angle::Result::Continue;
274 }
275
276 } // namespace rx
277