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