• 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 // CLProgramVk.h: Defines the class interface for CLProgramVk, implementing CLProgramImpl.
7 
8 #ifndef LIBANGLE_RENDERER_VULKAN_CLPROGRAMVK_H_
9 #define LIBANGLE_RENDERER_VULKAN_CLPROGRAMVK_H_
10 
11 #include "common/SimpleMutex.h"
12 
13 #include "libANGLE/renderer/vulkan/CLContextVk.h"
14 #include "libANGLE/renderer/vulkan/CLKernelVk.h"
15 #include "libANGLE/renderer/vulkan/cl_types.h"
16 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
17 #include "libANGLE/renderer/vulkan/vk_helpers.h"
18 
19 #include "libANGLE/renderer/CLProgramImpl.h"
20 
21 #include "libANGLE/CLProgram.h"
22 
23 #include "clspv/Compiler.h"
24 
25 #include "vulkan/vulkan_core.h"
26 
27 #include "spirv-tools/libspirv.h"
28 
29 #include "spirv/unified1/NonSemanticClspvReflection.h"
30 
31 namespace rx
32 {
33 
34 class CLProgramVk : public CLProgramImpl
35 {
36   public:
37     using Ptr = std::unique_ptr<CLProgramVk>;
38     struct SpvReflectionData
39     {
40         angle::HashMap<uint32_t, uint32_t> spvIntLookup;
41         angle::HashMap<uint32_t, std::string> spvStrLookup;
42         angle::HashMap<uint32_t, CLKernelVk::ArgInfo> kernelArgInfos;
43         angle::HashMap<std::string, uint32_t> kernelFlags;
44         angle::HashMap<std::string, std::string> kernelAttributes;
45         angle::HashMap<std::string, std::array<uint32_t, 3>> kernelCompileWorkgroupSize;
46         angle::HashMap<uint32_t, VkPushConstantRange> pushConstants;
47         std::array<uint32_t, 3> specConstantWorkgroupSizeIDs{0, 0, 0};
48         CLKernelArgsMap kernelArgsMap;
49     };
50 
51     // Output binary structure (for CL_PROGRAM_BINARIES query)
52     static constexpr uint32_t kBinaryVersion = 2;
53     struct ProgramBinaryOutputHeader
54     {
55         uint32_t headerVersion{kBinaryVersion};
56         cl_program_binary_type binaryType{CL_PROGRAM_BINARY_TYPE_NONE};
57         cl_build_status buildStatus{CL_BUILD_NONE};
58     };
59 
60     struct ScopedClspvContext : angle::NonCopyable
61     {
62         ScopedClspvContext() = default;
~ScopedClspvContextScopedClspvContext63         ~ScopedClspvContext() { clspvFreeOutputBuildObjs(mOutputBin, mOutputBuildLog); }
64 
65         size_t mOutputBinSize{0};
66         char *mOutputBin{nullptr};
67         char *mOutputBuildLog{nullptr};
68     };
69 
70     struct ScopedProgramCallback : angle::NonCopyable
71     {
72         ScopedProgramCallback() = delete;
ScopedProgramCallbackScopedProgramCallback73         ScopedProgramCallback(cl::Program *notify) : mNotify(notify) {}
~ScopedProgramCallbackScopedProgramCallback74         ~ScopedProgramCallback()
75         {
76             if (mNotify)
77             {
78                 mNotify->callback();
79             }
80         }
81 
82         cl::Program *mNotify{nullptr};
83     };
84 
85     enum class BuildType
86     {
87         BUILD = 0,
88         COMPILE,
89         LINK,
90         BINARY
91     };
92 
93     struct DeviceProgramData
94     {
95         std::vector<char> IR;
96         std::string buildLog;
97         angle::spirv::Blob binary;
98         SpvReflectionData reflectionData;
99         VkPushConstantRange pushConstRange{};
100         cl_build_status buildStatus{CL_BUILD_NONE};
101         cl_program_binary_type binaryType{CL_PROGRAM_BINARY_TYPE_NONE};
102 
numKernelsDeviceProgramData103         size_t numKernels() const { return reflectionData.kernelArgsMap.size(); }
104 
numKernelArgsDeviceProgramData105         size_t numKernelArgs(const std::string &kernelName) const
106         {
107             return containsKernel(kernelName) ? getKernelArgsMap().at(kernelName).size() : 0;
108         }
109 
getKernelArgsMapDeviceProgramData110         const CLKernelArgsMap &getKernelArgsMap() const { return reflectionData.kernelArgsMap; }
111 
containsKernelDeviceProgramData112         bool containsKernel(const std::string &name) const
113         {
114             return reflectionData.kernelArgsMap.contains(name);
115         }
116 
getKernelNamesDeviceProgramData117         std::string getKernelNames() const
118         {
119             std::string names;
120             for (auto name = getKernelArgsMap().begin(); name != getKernelArgsMap().end(); ++name)
121             {
122                 names += name->first + (std::next(name) != getKernelArgsMap().end() ? ";" : "\0");
123             }
124             return names;
125         }
126 
getKernelArgumentsDeviceProgramData127         CLKernelArguments getKernelArguments(const std::string &kernelName) const
128         {
129             CLKernelArguments kargsCopy;
130             if (containsKernel(kernelName))
131             {
132                 const CLKernelArguments &kargs = getKernelArgsMap().at(kernelName);
133                 for (const CLKernelArgument &karg : kargs)
134                 {
135                     kargsCopy.push_back(karg);
136                 }
137             }
138             return kargsCopy;
139         }
140 
getCompiledWorkgroupSizeDeviceProgramData141         cl::WorkgroupSize getCompiledWorkgroupSize(const std::string &kernelName) const
142         {
143             cl::WorkgroupSize compiledWorkgroupSize{0, 0, 0};
144             if (reflectionData.kernelCompileWorkgroupSize.contains(kernelName))
145             {
146                 for (size_t i = 0; i < compiledWorkgroupSize.size(); ++i)
147                 {
148                     compiledWorkgroupSize[i] =
149                         reflectionData.kernelCompileWorkgroupSize.at(kernelName)[i];
150                 }
151             }
152             return compiledWorkgroupSize;
153         }
154 
getKernelAttributesDeviceProgramData155         std::string getKernelAttributes(const std::string &kernelName) const
156         {
157             if (containsKernel(kernelName))
158             {
159                 return reflectionData.kernelAttributes.at(kernelName.c_str());
160             }
161             return std::string{};
162         }
163 
getPushConstantRangeFromClspvReflectionTypeDeviceProgramData164         const VkPushConstantRange *getPushConstantRangeFromClspvReflectionType(
165             NonSemanticClspvReflectionInstructions type) const
166         {
167             const VkPushConstantRange *pushConstantRangePtr = nullptr;
168             if (reflectionData.pushConstants.contains(type))
169             {
170                 pushConstantRangePtr = &reflectionData.pushConstants.at(type);
171             }
172             return pushConstantRangePtr;
173         }
174 
getGlobalOffsetRangeDeviceProgramData175         inline const VkPushConstantRange *getGlobalOffsetRange() const
176         {
177             return getPushConstantRangeFromClspvReflectionType(
178                 NonSemanticClspvReflectionPushConstantGlobalOffset);
179         }
180 
getGlobalSizeRangeDeviceProgramData181         inline const VkPushConstantRange *getGlobalSizeRange() const
182         {
183             return getPushConstantRangeFromClspvReflectionType(
184                 NonSemanticClspvReflectionPushConstantGlobalSize);
185         }
186     };
187     using DevicePrograms   = angle::HashMap<const _cl_device_id *, DeviceProgramData>;
188     using LinkPrograms     = std::vector<const DeviceProgramData *>;
189     using LinkProgramsList = std::vector<LinkPrograms>;
190 
191     CLProgramVk(const cl::Program &program);
192 
193     ~CLProgramVk() override;
194 
195     angle::Result init();
196     angle::Result init(const size_t *lengths, const unsigned char **binaries, cl_int *binaryStatus);
197 
198     angle::Result build(const cl::DevicePtrs &devices,
199                         const char *options,
200                         cl::Program *notify) override;
201 
202     angle::Result compile(const cl::DevicePtrs &devices,
203                           const char *options,
204                           const cl::ProgramPtrs &inputHeaders,
205                           const char **headerIncludeNames,
206                           cl::Program *notify) override;
207 
208     angle::Result getInfo(cl::ProgramInfo name,
209                           size_t valueSize,
210                           void *value,
211                           size_t *valueSizeRet) const override;
212 
213     angle::Result getBuildInfo(const cl::Device &device,
214                                cl::ProgramBuildInfo name,
215                                size_t valueSize,
216                                void *value,
217                                size_t *valueSizeRet) const override;
218 
219     angle::Result createKernel(const cl::Kernel &kernel,
220                                const char *name,
221                                CLKernelImpl::Ptr *kernelOut) override;
222 
223     angle::Result createKernels(cl_uint numKernels,
224                                 CLKernelImpl::CreateFuncs &createFuncs,
225                                 cl_uint *numKernelsRet) override;
226 
227     const DeviceProgramData *getDeviceProgramData(const char *kernelName) const;
228     const DeviceProgramData *getDeviceProgramData(const _cl_device_id *device) const;
getPlatform()229     CLPlatformVk *getPlatform() { return mContext->getPlatform(); }
getShaderModule()230     vk::RefCounted<vk::ShaderModule> *getShaderModule() { return &mShader; }
231 
232     bool buildInternal(const cl::DevicePtrs &devices,
233                        std::string options,
234                        std::string internalOptions,
235                        BuildType buildType,
236                        const LinkProgramsList &LinkProgramsList);
237     angle::spirv::Blob stripReflection(const DeviceProgramData *deviceProgramData);
238 
239     angle::Result allocateDescriptorSet(const vk::DescriptorSetLayout &descriptorSetLayout,
240                                         VkDescriptorSet *descriptorSetOut);
241 
242   private:
243     CLContextVk *mContext;
244     std::string mProgramOpts;
245     vk::RefCounted<vk::ShaderModule> mShader;
246     DevicePrograms mAssociatedDevicePrograms;
247     PipelineLayoutCache mPipelineLayoutCache;
248     vk::MetaDescriptorPool mMetaDescriptorPool;
249     DescriptorSetLayoutCache mDescSetLayoutCache;
250     vk::DescriptorSetArray<vk::DescriptorPoolPointer> mDescriptorPools;
251     vk::RefCountedDescriptorPoolBinding mPoolBinding;
252     angle::SimpleMutex mProgramMutex;
253 };
254 
255 class CLAsyncBuildTask : public angle::Closure
256 {
257   public:
CLAsyncBuildTask(CLProgramVk * programVk,const cl::DevicePtrs & devices,std::string options,std::string internalOptions,CLProgramVk::BuildType buildType,const CLProgramVk::LinkProgramsList & LinkProgramsList,cl::Program * notify)258     CLAsyncBuildTask(CLProgramVk *programVk,
259                      const cl::DevicePtrs &devices,
260                      std::string options,
261                      std::string internalOptions,
262                      CLProgramVk::BuildType buildType,
263                      const CLProgramVk::LinkProgramsList &LinkProgramsList,
264                      cl::Program *notify)
265         : mProgramVk(programVk),
266           mDevices(devices),
267           mOptions(options),
268           mInternalOptions(internalOptions),
269           mBuildType(buildType),
270           mLinkProgramsList(LinkProgramsList),
271           mNotify(notify)
272     {}
273 
274     void operator()() override;
275 
276   private:
277     CLProgramVk *mProgramVk;
278     const cl::DevicePtrs mDevices;
279     std::string mOptions;
280     std::string mInternalOptions;
281     CLProgramVk::BuildType mBuildType;
282     const CLProgramVk::LinkProgramsList mLinkProgramsList;
283     cl::Program *mNotify;
284 };
285 
286 }  // namespace rx
287 
288 #endif  // LIBANGLE_RENDERER_VULKAN_CLPROGRAMVK_H_
289