xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/CLContextVk.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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/CLSamplerVk.h"
14 #include "libANGLE/renderer/vulkan/DisplayVk.h"
15 #include "libANGLE/renderer/vulkan/vk_renderer.h"
16 #include "libANGLE/renderer/vulkan/vk_utils.h"
17 
18 #include "libANGLE/CLBuffer.h"
19 #include "libANGLE/CLContext.h"
20 #include "libANGLE/CLEvent.h"
21 #include "libANGLE/CLImage.h"
22 #include "libANGLE/CLProgram.h"
23 #include "libANGLE/cl_utils.h"
24 
25 namespace rx
26 {
27 
CLContextVk(const cl::Context & context,const cl::DevicePtrs devicePtrs)28 CLContextVk::CLContextVk(const cl::Context &context, const cl::DevicePtrs devicePtrs)
29     : CLContextImpl(context),
30       vk::Context(getPlatform()->getRenderer()),
31       mAssociatedDevices(devicePtrs)
32 {
33     mDeviceQueueIndex = mRenderer->getDefaultDeviceQueueIndex();
34 }
35 
~CLContextVk()36 CLContextVk::~CLContextVk()
37 {
38     mDescriptorSetLayoutCache.destroy(getRenderer());
39     mPipelineLayoutCache.destroy(getRenderer());
40 }
41 
handleError(VkResult errorCode,const char * file,const char * function,unsigned int line)42 void CLContextVk::handleError(VkResult errorCode,
43                               const char *file,
44                               const char *function,
45                               unsigned int line)
46 {
47     ASSERT(errorCode != VK_SUCCESS);
48 
49     CLenum clErrorCode = CL_SUCCESS;
50     switch (errorCode)
51     {
52         case VK_ERROR_TOO_MANY_OBJECTS:
53         case VK_ERROR_OUT_OF_HOST_MEMORY:
54         case VK_ERROR_OUT_OF_DEVICE_MEMORY:
55             clErrorCode = CL_OUT_OF_HOST_MEMORY;
56             break;
57         default:
58             clErrorCode = CL_INVALID_OPERATION;
59     }
60     ERR() << "Internal Vulkan error (" << errorCode << "): " << VulkanResultString(errorCode);
61     ERR() << "  CL error (" << clErrorCode << ")";
62 
63     if (errorCode == VK_ERROR_DEVICE_LOST)
64     {
65         handleDeviceLost();
66     }
67     ANGLE_CL_SET_ERROR(clErrorCode);
68 }
69 
handleDeviceLost() const70 void CLContextVk::handleDeviceLost() const
71 {
72     // For now just notify the renderer
73     getRenderer()->notifyDeviceLost();
74 }
75 
getDevices(cl::DevicePtrs * devicePtrsOut) const76 angle::Result CLContextVk::getDevices(cl::DevicePtrs *devicePtrsOut) const
77 {
78     ASSERT(!mAssociatedDevices.empty());
79     *devicePtrsOut = mAssociatedDevices;
80     return angle::Result::Continue;
81 }
82 
createCommandQueue(const cl::CommandQueue & commandQueue,CLCommandQueueImpl::Ptr * commandQueueOut)83 angle::Result CLContextVk::createCommandQueue(const cl::CommandQueue &commandQueue,
84                                               CLCommandQueueImpl::Ptr *commandQueueOut)
85 {
86     CLCommandQueueVk *queueImpl = new CLCommandQueueVk(commandQueue);
87     if (queueImpl == nullptr)
88     {
89         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
90     }
91     ANGLE_TRY(queueImpl->init());
92     *commandQueueOut = CLCommandQueueVk::Ptr(std::move(queueImpl));
93     return angle::Result::Continue;
94 }
95 
createBuffer(const cl::Buffer & buffer,void * hostPtr,CLMemoryImpl::Ptr * bufferOut)96 angle::Result CLContextVk::createBuffer(const cl::Buffer &buffer,
97                                         void *hostPtr,
98                                         CLMemoryImpl::Ptr *bufferOut)
99 {
100     CLBufferVk *memory = new (std::nothrow) CLBufferVk(buffer);
101     if (memory == nullptr)
102     {
103         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
104     }
105     ANGLE_TRY(memory->create(hostPtr));
106     *bufferOut = CLMemoryImpl::Ptr(memory);
107     mAssociatedObjects->mMemories.emplace(buffer.getNative());
108     return angle::Result::Continue;
109 }
110 
createImage(const cl::Image & image,void * hostPtr,CLMemoryImpl::Ptr * imageOut)111 angle::Result CLContextVk::createImage(const cl::Image &image,
112                                        void *hostPtr,
113                                        CLMemoryImpl::Ptr *imageOut)
114 {
115     CLImageVk *memory = new (std::nothrow) CLImageVk(image);
116     if (memory == nullptr)
117     {
118         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
119     }
120     ANGLE_TRY(memory->create(hostPtr));
121     *imageOut = CLMemoryImpl::Ptr(memory);
122     mAssociatedObjects->mMemories.emplace(image.getNative());
123     return angle::Result::Continue;
124 }
125 
getVkFormatFromCL(cl_image_format format)126 VkFormat CLContextVk::getVkFormatFromCL(cl_image_format format)
127 {
128     angle::FormatID formatID;
129     switch (format.image_channel_order)
130     {
131         case CL_R:
132             formatID = angle::Format::CLRFormatToID(format.image_channel_data_type);
133             break;
134         case CL_RG:
135             formatID = angle::Format::CLRGFormatToID(format.image_channel_data_type);
136             break;
137         case CL_RGB:
138             formatID = angle::Format::CLRGBFormatToID(format.image_channel_data_type);
139             break;
140         case CL_RGBA:
141             formatID = angle::Format::CLRGBAFormatToID(format.image_channel_data_type);
142             break;
143         case CL_BGRA:
144             formatID = angle::Format::CLBGRAFormatToID(format.image_channel_data_type);
145             break;
146         case CL_sRGBA:
147             formatID = angle::Format::CLsRGBAFormatToID(format.image_channel_data_type);
148             break;
149         default:
150             return VK_FORMAT_UNDEFINED;
151     }
152     return getPlatform()->getRenderer()->getFormat(formatID).getActualRenderableImageVkFormat(
153         getPlatform()->getRenderer());
154 }
155 
getSupportedImageFormats(cl::MemFlags flags,cl::MemObjectType imageType,cl_uint numEntries,cl_image_format * imageFormats,cl_uint * numImageFormats)156 angle::Result CLContextVk::getSupportedImageFormats(cl::MemFlags flags,
157                                                     cl::MemObjectType imageType,
158                                                     cl_uint numEntries,
159                                                     cl_image_format *imageFormats,
160                                                     cl_uint *numImageFormats)
161 {
162     VkPhysicalDevice physicalDevice = getPlatform()->getRenderer()->getPhysicalDevice();
163     std::vector<cl_image_format> supportedFormats;
164     std::vector<cl_image_format> minSupportedFormats;
165     if (flags.intersects((CL_MEM_READ_ONLY | CL_MEM_WRITE_ONLY)))
166     {
167         minSupportedFormats.insert(minSupportedFormats.end(),
168                                    std::begin(kMinSupportedFormatsReadOrWrite),
169                                    std::end(kMinSupportedFormatsReadOrWrite));
170     }
171     else
172     {
173         minSupportedFormats.insert(minSupportedFormats.end(),
174                                    std::begin(kMinSupportedFormatsReadAndWrite),
175                                    std::end(kMinSupportedFormatsReadAndWrite));
176     }
177     for (cl_image_format format : minSupportedFormats)
178     {
179         VkFormatProperties formatProperties;
180         VkFormat vkFormat = getVkFormatFromCL(format);
181         ASSERT(vkFormat != VK_FORMAT_UNDEFINED);
182         vkGetPhysicalDeviceFormatProperties(physicalDevice, vkFormat, &formatProperties);
183         if (formatProperties.optimalTilingFeatures != 0)
184         {
185             supportedFormats.push_back(format);
186         }
187     }
188     if (numImageFormats != nullptr)
189     {
190         *numImageFormats = static_cast<cl_uint>(supportedFormats.size());
191     }
192     if (imageFormats != nullptr)
193     {
194         memcpy(imageFormats, supportedFormats.data(),
195                sizeof(cl_image_format) *
196                    std::min(static_cast<cl_uint>(supportedFormats.size()), numEntries));
197     }
198 
199     return angle::Result::Continue;
200 }
201 
createSampler(const cl::Sampler & sampler,CLSamplerImpl::Ptr * samplerOut)202 angle::Result CLContextVk::createSampler(const cl::Sampler &sampler, CLSamplerImpl::Ptr *samplerOut)
203 {
204     CLSamplerVk *samplerVk = new (std::nothrow) CLSamplerVk(sampler);
205     if (samplerVk == nullptr)
206     {
207         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
208     }
209     ANGLE_TRY(samplerVk->create());
210     *samplerOut = CLSamplerImpl::Ptr(samplerVk);
211     return angle::Result::Continue;
212 }
213 
createProgramWithSource(const cl::Program & program,const std::string & source,CLProgramImpl::Ptr * programOut)214 angle::Result CLContextVk::createProgramWithSource(const cl::Program &program,
215                                                    const std::string &source,
216                                                    CLProgramImpl::Ptr *programOut)
217 {
218     CLProgramVk *programVk = new (std::nothrow) CLProgramVk(program);
219     if (programVk == nullptr)
220     {
221         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
222     }
223     ANGLE_TRY(programVk->init());
224     *programOut = CLProgramImpl::Ptr(std::move(programVk));
225 
226     return angle::Result::Continue;
227 }
228 
createProgramWithIL(const cl::Program & program,const void * il,size_t length,CLProgramImpl::Ptr * programOut)229 angle::Result CLContextVk::createProgramWithIL(const cl::Program &program,
230                                                const void *il,
231                                                size_t length,
232                                                CLProgramImpl::Ptr *programOut)
233 {
234     UNIMPLEMENTED();
235     ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
236 }
237 
createProgramWithBinary(const cl::Program & program,const size_t * lengths,const unsigned char ** binaries,cl_int * binaryStatus,CLProgramImpl::Ptr * programOut)238 angle::Result CLContextVk::createProgramWithBinary(const cl::Program &program,
239                                                    const size_t *lengths,
240                                                    const unsigned char **binaries,
241                                                    cl_int *binaryStatus,
242                                                    CLProgramImpl::Ptr *programOut)
243 {
244     CLProgramVk *programVk = new (std::nothrow) CLProgramVk(program);
245     if (programVk == nullptr)
246     {
247         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
248     }
249     ANGLE_TRY(programVk->init(lengths, binaries, binaryStatus));
250     *programOut = CLProgramImpl::Ptr(std::move(programVk));
251 
252     return angle::Result::Continue;
253 }
254 
createProgramWithBuiltInKernels(const cl::Program & program,const char * kernel_names,CLProgramImpl::Ptr * programOut)255 angle::Result CLContextVk::createProgramWithBuiltInKernels(const cl::Program &program,
256                                                            const char *kernel_names,
257                                                            CLProgramImpl::Ptr *programOut)
258 {
259     UNIMPLEMENTED();
260     ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
261 }
262 
linkProgram(const cl::Program & program,const cl::DevicePtrs & devices,const char * options,const cl::ProgramPtrs & inputPrograms,cl::Program * notify,CLProgramImpl::Ptr * programOut)263 angle::Result CLContextVk::linkProgram(const cl::Program &program,
264                                        const cl::DevicePtrs &devices,
265                                        const char *options,
266                                        const cl::ProgramPtrs &inputPrograms,
267                                        cl::Program *notify,
268                                        CLProgramImpl::Ptr *programOut)
269 {
270     const cl::DevicePtrs &devicePtrs = !devices.empty() ? devices : mContext.getDevices();
271 
272     CLProgramVk::Ptr programImpl = CLProgramVk::Ptr(new (std::nothrow) CLProgramVk(program));
273     if (programImpl == nullptr)
274     {
275         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
276     }
277     ANGLE_TRY(programImpl->init());
278 
279     cl::DevicePtrs linkDeviceList;
280     CLProgramVk::LinkProgramsList linkProgramsList;
281     cl::BitField libraryOrObject(CL_PROGRAM_BINARY_TYPE_LIBRARY |
282                                  CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT);
283     for (const cl::DevicePtr &devicePtr : devicePtrs)
284     {
285         CLProgramVk::LinkPrograms linkPrograms;
286         for (const cl::ProgramPtr &inputProgram : inputPrograms)
287         {
288             const CLProgramVk::DeviceProgramData *deviceProgramData =
289                 inputProgram->getImpl<CLProgramVk>().getDeviceProgramData(devicePtr->getNative());
290 
291             // Should be valid at this point
292             ASSERT(deviceProgramData != nullptr);
293 
294             if (libraryOrObject.intersects(deviceProgramData->binaryType))
295             {
296                 linkPrograms.push_back(deviceProgramData);
297             }
298         }
299         if (!linkPrograms.empty())
300         {
301             linkDeviceList.push_back(devicePtr);
302             linkProgramsList.push_back(linkPrograms);
303         }
304     }
305 
306     programImpl->setBuildStatus(linkDeviceList, CL_BUILD_IN_PROGRESS);
307 
308     // Perform link
309     if (notify)
310     {
311         std::shared_ptr<angle::WaitableEvent> asyncEvent =
312             mContext.getPlatform().getMultiThreadPool()->postWorkerTask(
313                 std::make_shared<CLAsyncBuildTask>(
314                     programImpl.get(), linkDeviceList, std::string(options ? options : ""), "",
315                     CLProgramVk::BuildType::LINK, linkProgramsList, notify));
316         ASSERT(asyncEvent != nullptr);
317     }
318     else
319     {
320         if (!programImpl->buildInternal(linkDeviceList, std::string(options ? options : ""), "",
321                                         CLProgramVk::BuildType::LINK, linkProgramsList))
322         {
323             ANGLE_CL_RETURN_ERROR(CL_LINK_PROGRAM_FAILURE);
324         }
325     }
326 
327     *programOut = std::move(programImpl);
328     return angle::Result::Continue;
329 }
330 
createUserEvent(const cl::Event & event,CLEventImpl::Ptr * eventOut)331 angle::Result CLContextVk::createUserEvent(const cl::Event &event, CLEventImpl::Ptr *eventOut)
332 {
333     *eventOut = CLEventImpl::Ptr(new (std::nothrow) CLEventVk(event));
334     if (*eventOut == nullptr)
335     {
336         ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
337     }
338     return angle::Result::Continue;
339 }
340 
waitForEvents(const cl::EventPtrs & events)341 angle::Result CLContextVk::waitForEvents(const cl::EventPtrs &events)
342 {
343     for (auto &event : events)
344     {
345         CLEventVk *eventVk = &event.get()->getImpl<CLEventVk>();
346         if (eventVk->isUserEvent())
347         {
348             ANGLE_TRY(eventVk->waitForUserEventStatus());
349         }
350         else
351         {
352             // TODO rework this to instead (flush w/ ResourceUse serial wait) once we move away from
353             // spawning a submit-thread/Task for flush routine
354             // https://anglebug.com/42267107
355             ANGLE_TRY(event->getCommandQueue()->finish());
356         }
357     }
358 
359     return angle::Result::Continue;
360 }
361 
362 }  // namespace rx
363