• 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 <cstdint>
12 
13 #include "common/SimpleMutex.h"
14 #include "common/hash_containers.h"
15 
16 #include "libANGLE/CLSampler.h"
17 #include "libANGLE/renderer/vulkan/CLContextVk.h"
18 #include "libANGLE/renderer/vulkan/CLKernelVk.h"
19 #include "libANGLE/renderer/vulkan/cl_types.h"
20 #include "libANGLE/renderer/vulkan/clspv_utils.h"
21 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
22 #include "libANGLE/renderer/vulkan/vk_helpers.h"
23 
24 #include "libANGLE/renderer/CLProgramImpl.h"
25 
26 #include "libANGLE/CLProgram.h"
27 
28 #include "clspv/Compiler.h"
29 
30 #include "vulkan/vulkan_core.h"
31 
32 #include "spirv/unified1/NonSemanticClspvReflection.h"
33 
34 namespace rx
35 {
36 
37 class CLProgramVk : public CLProgramImpl
38 {
39   public:
40     using Ptr = std::unique_ptr<CLProgramVk>;
41     // TODO: Look into moving this information in CLKernelArgument
42     // https://anglebug.com/378514267
43     struct ImagePushConstant
44     {
45         VkPushConstantRange pcRange;
46         uint32_t ordinal;
47     };
48     struct SpvReflectionData
49     {
50         angle::HashMap<uint32_t, uint32_t> spvIntLookup;
51         angle::HashMap<uint32_t, std::string> spvStrLookup;
52         angle::HashMap<uint32_t, CLKernelVk::ArgInfo> kernelArgInfos;
53         angle::HashMap<std::string, uint32_t> kernelFlags;
54         angle::HashMap<std::string, std::string> kernelAttributes;
55         angle::HashMap<std::string, std::array<uint32_t, 3>> kernelCompileWorkgroupSize;
56         angle::HashMap<uint32_t, VkPushConstantRange> pushConstants;
57         angle::PackedEnumMap<SpecConstantType, uint32_t> specConstantIDs;
58         angle::PackedEnumBitSet<SpecConstantType, uint32_t> specConstantsUsed;
59         angle::HashMap<uint32_t, std::vector<ImagePushConstant>> imagePushConstants;
60         CLKernelArgsMap kernelArgsMap;
61         angle::HashMap<std::string, CLKernelArgument> kernelArgMap;
62         angle::HashSet<uint32_t> kernelIDs;
63         ClspvPrintfBufferStorage printfBufferStorage;
64         angle::HashMap<uint32_t, ClspvPrintfInfo> printfInfoMap;
65         std::vector<ClspvLiteralSampler> literalSamplers;
66     };
67 
68     // Output binary structure (for CL_PROGRAM_BINARIES query)
69     static constexpr uint32_t kBinaryVersion = 2;
70     struct ProgramBinaryOutputHeader
71     {
72         uint32_t headerVersion{kBinaryVersion};
73         cl_program_binary_type binaryType{CL_PROGRAM_BINARY_TYPE_NONE};
74         cl_build_status buildStatus{CL_BUILD_NONE};
75     };
76 
77     struct ScopedClspvContext : angle::NonCopyable
78     {
79         ScopedClspvContext() = default;
~ScopedClspvContextScopedClspvContext80         ~ScopedClspvContext() { clspvFreeOutputBuildObjs(mOutputBin, mOutputBuildLog); }
81 
82         size_t mOutputBinSize{0};
83         char *mOutputBin{nullptr};
84         char *mOutputBuildLog{nullptr};
85     };
86 
87     struct ScopedProgramCallback : angle::NonCopyable
88     {
89         ScopedProgramCallback() = delete;
ScopedProgramCallbackScopedProgramCallback90         ScopedProgramCallback(cl::Program *notify) : mNotify(notify) {}
~ScopedProgramCallbackScopedProgramCallback91         ~ScopedProgramCallback()
92         {
93             if (mNotify)
94             {
95                 mNotify->callback();
96             }
97         }
98 
99         cl::Program *mNotify{nullptr};
100     };
101 
102     enum class BuildType
103     {
104         BUILD = 0,
105         COMPILE,
106         LINK,
107         BINARY
108     };
109 
110     struct DeviceProgramData
111     {
112         std::vector<char> IR;
113         std::string buildLog;
114         angle::spirv::Blob binary;
115         SpvReflectionData reflectionData;
116         VkPushConstantRange pushConstRange{};
117         cl_build_status buildStatus{CL_BUILD_NONE};
118         cl_program_binary_type binaryType{CL_PROGRAM_BINARY_TYPE_NONE};
119         spv_target_env spirvVersion;
120 
numKernelsDeviceProgramData121         size_t numKernels() const { return reflectionData.kernelArgsMap.size(); }
122 
numKernelArgsDeviceProgramData123         size_t numKernelArgs(const std::string &kernelName) const
124         {
125             return containsKernel(kernelName) ? getKernelArgsMap().at(kernelName).size() : 0;
126         }
127 
getKernelArgsMapDeviceProgramData128         const CLKernelArgsMap &getKernelArgsMap() const { return reflectionData.kernelArgsMap; }
129 
containsKernelDeviceProgramData130         bool containsKernel(const std::string &name) const
131         {
132             return reflectionData.kernelArgsMap.contains(name);
133         }
134 
getKernelNamesDeviceProgramData135         std::string getKernelNames() const
136         {
137             std::string names;
138             for (auto name = getKernelArgsMap().begin(); name != getKernelArgsMap().end(); ++name)
139             {
140                 names += name->first + (std::next(name) != getKernelArgsMap().end() ? ";" : "\0");
141             }
142             return names;
143         }
144 
getKernelFlagsDeviceProgramData145         uint32_t getKernelFlags(const std::string &kernelName) const
146         {
147             if (containsKernel(kernelName))
148             {
149                 return reflectionData.kernelFlags.at(kernelName);
150             }
151             return 0;
152         }
153 
getKernelArgumentsDeviceProgramData154         CLKernelArguments getKernelArguments(const std::string &kernelName) const
155         {
156             CLKernelArguments kargsCopy;
157             if (containsKernel(kernelName))
158             {
159                 const CLKernelArguments &kargs = getKernelArgsMap().at(kernelName);
160                 for (const CLKernelArgument &karg : kargs)
161                 {
162                     kargsCopy.push_back(karg);
163                 }
164             }
165             return kargsCopy;
166         }
167 
getCompiledWorkgroupSizeDeviceProgramData168         cl::WorkgroupSize getCompiledWorkgroupSize(const std::string &kernelName) const
169         {
170             cl::WorkgroupSize compiledWorkgroupSize{0, 0, 0};
171             if (reflectionData.kernelCompileWorkgroupSize.contains(kernelName))
172             {
173                 for (size_t i = 0; i < compiledWorkgroupSize.size(); ++i)
174                 {
175                     compiledWorkgroupSize[i] =
176                         reflectionData.kernelCompileWorkgroupSize.at(kernelName)[i];
177                 }
178             }
179             return compiledWorkgroupSize;
180         }
181 
getKernelAttributesDeviceProgramData182         std::string getKernelAttributes(const std::string &kernelName) const
183         {
184             if (containsKernel(kernelName))
185             {
186                 return reflectionData.kernelAttributes.at(kernelName.c_str());
187             }
188             return std::string{};
189         }
190 
getPushConstantRangeFromClspvReflectionTypeDeviceProgramData191         const VkPushConstantRange *getPushConstantRangeFromClspvReflectionType(
192             NonSemanticClspvReflectionInstructions type) const
193         {
194             const VkPushConstantRange *pushConstantRangePtr = nullptr;
195             if (reflectionData.pushConstants.contains(type))
196             {
197                 pushConstantRangePtr = &reflectionData.pushConstants.at(type);
198             }
199             return pushConstantRangePtr;
200         }
201 
getGlobalOffsetRangeDeviceProgramData202         inline const VkPushConstantRange *getGlobalOffsetRange() const
203         {
204             return getPushConstantRangeFromClspvReflectionType(
205                 NonSemanticClspvReflectionPushConstantGlobalOffset);
206         }
207 
getGlobalSizeRangeDeviceProgramData208         inline const VkPushConstantRange *getGlobalSizeRange() const
209         {
210             return getPushConstantRangeFromClspvReflectionType(
211                 NonSemanticClspvReflectionPushConstantGlobalSize);
212         }
213 
getEnqueuedLocalSizeRangeDeviceProgramData214         inline const VkPushConstantRange *getEnqueuedLocalSizeRange() const
215         {
216             return getPushConstantRangeFromClspvReflectionType(
217                 NonSemanticClspvReflectionPushConstantEnqueuedLocalSize);
218         }
219 
getNumWorkgroupsRangeDeviceProgramData220         inline const VkPushConstantRange *getNumWorkgroupsRange() const
221         {
222             return getPushConstantRangeFromClspvReflectionType(
223                 NonSemanticClspvReflectionPushConstantNumWorkgroups);
224         }
225 
getRegionOffsetRangeDeviceProgramData226         inline const VkPushConstantRange *getRegionOffsetRange() const
227         {
228             return getPushConstantRangeFromClspvReflectionType(
229                 NonSemanticClspvReflectionPushConstantRegionOffset);
230         }
231 
getRegionGroupOffsetRangeDeviceProgramData232         inline const VkPushConstantRange *getRegionGroupOffsetRange() const
233         {
234             return getPushConstantRangeFromClspvReflectionType(
235                 NonSemanticClspvReflectionPushConstantRegionGroupOffset);
236         }
237 
getImageDataChannelOrderRangeDeviceProgramData238         const VkPushConstantRange *getImageDataChannelOrderRange(size_t ordinal) const
239         {
240             const VkPushConstantRange *pushConstantRangePtr = nullptr;
241             if (reflectionData.imagePushConstants.contains(
242                     NonSemanticClspvReflectionImageArgumentInfoChannelOrderPushConstant))
243             {
244                 for (const auto &imageConstant : reflectionData.imagePushConstants.at(
245                          NonSemanticClspvReflectionImageArgumentInfoChannelOrderPushConstant))
246                 {
247                     if (static_cast<size_t>(imageConstant.ordinal) == ordinal)
248                     {
249                         pushConstantRangePtr = &imageConstant.pcRange;
250                     }
251                 }
252             }
253             return pushConstantRangePtr;
254         }
255 
getImageDataChannelDataTypeRangeDeviceProgramData256         const VkPushConstantRange *getImageDataChannelDataTypeRange(size_t ordinal) const
257         {
258             const VkPushConstantRange *pushConstantRangePtr = nullptr;
259             if (reflectionData.imagePushConstants.contains(
260                     NonSemanticClspvReflectionImageArgumentInfoChannelDataTypePushConstant))
261             {
262                 for (const auto &imageConstant : reflectionData.imagePushConstants.at(
263                          NonSemanticClspvReflectionImageArgumentInfoChannelDataTypePushConstant))
264                 {
265                     if (static_cast<size_t>(imageConstant.ordinal) == ordinal)
266                     {
267                         pushConstantRangePtr = &imageConstant.pcRange;
268                     }
269                 }
270             }
271             return pushConstantRangePtr;
272         }
273 
getNormalizedSamplerMaskRangeDeviceProgramData274         const VkPushConstantRange *getNormalizedSamplerMaskRange(size_t ordinal) const
275         {
276             const VkPushConstantRange *pushConstantRangePtr = nullptr;
277             if (reflectionData.imagePushConstants.contains(
278                     NonSemanticClspvReflectionNormalizedSamplerMaskPushConstant))
279             {
280                 for (const auto &imageConstant : reflectionData.imagePushConstants.at(
281                          NonSemanticClspvReflectionNormalizedSamplerMaskPushConstant))
282                 {
283                     if (static_cast<size_t>(imageConstant.ordinal) == ordinal)
284                     {
285                         pushConstantRangePtr = &imageConstant.pcRange;
286                     }
287                 }
288             }
289             return pushConstantRangePtr;
290         }
291     };
292     using DevicePrograms   = angle::HashMap<const _cl_device_id *, DeviceProgramData>;
293     using LinkPrograms     = std::vector<const DeviceProgramData *>;
294     using LinkProgramsList = std::vector<LinkPrograms>;
295 
296     CLProgramVk(const cl::Program &program);
297 
298     ~CLProgramVk() override;
299 
300     angle::Result init();
301     angle::Result init(const size_t *lengths, const unsigned char **binaries, cl_int *binaryStatus);
302 
303     angle::Result build(const cl::DevicePtrs &devices,
304                         const char *options,
305                         cl::Program *notify) override;
306 
307     angle::Result compile(const cl::DevicePtrs &devices,
308                           const char *options,
309                           const cl::ProgramPtrs &inputHeaders,
310                           const char **headerIncludeNames,
311                           cl::Program *notify) override;
312 
313     angle::Result getInfo(cl::ProgramInfo name,
314                           size_t valueSize,
315                           void *value,
316                           size_t *valueSizeRet) const override;
317 
318     angle::Result getBuildInfo(const cl::Device &device,
319                                cl::ProgramBuildInfo name,
320                                size_t valueSize,
321                                void *value,
322                                size_t *valueSizeRet) const override;
323 
324     angle::Result createKernel(const cl::Kernel &kernel,
325                                const char *name,
326                                CLKernelImpl::Ptr *kernelOut) override;
327 
328     angle::Result createKernels(cl_uint numKernels,
329                                 CLKernelImpl::CreateFuncs &createFuncs,
330                                 cl_uint *numKernelsRet) override;
331 
332     const DeviceProgramData *getDeviceProgramData(const char *kernelName) const;
333     const DeviceProgramData *getDeviceProgramData(const _cl_device_id *device) const;
getPlatform()334     CLPlatformVk *getPlatform() { return mContext->getPlatform(); }
getShaderModule()335     const vk::ShaderModulePtr &getShaderModule() const { return mShader; }
336 
337     bool buildInternal(const cl::DevicePtrs &devices,
338                        std::string options,
339                        std::string internalOptions,
340                        BuildType buildType,
341                        const LinkProgramsList &LinkProgramsList);
342     angle::spirv::Blob stripReflection(const DeviceProgramData *deviceProgramData);
343 
344     // Sets the status for given associated device programs
345     void setBuildStatus(const cl::DevicePtrs &devices, cl_build_status status);
346 
347     const angle::HashMap<uint32_t, ClspvPrintfInfo> *getPrintfDescriptors(
348         const std::string &kernelName) const;
349 
350   private:
351     CLContextVk *mContext;
352     std::string mProgramOpts;
353     vk::ShaderModulePtr mShader;
354     DevicePrograms mAssociatedDevicePrograms;
355     angle::SimpleMutex mProgramMutex;
356 
357     std::shared_ptr<angle::WaitableEvent> mAsyncBuildEvent;
358 };
359 
360 class CLAsyncBuildTask : public angle::Closure
361 {
362   public:
CLAsyncBuildTask(CLProgramVk * programVk,const cl::DevicePtrs & devices,std::string options,std::string internalOptions,CLProgramVk::BuildType buildType,const CLProgramVk::LinkProgramsList & LinkProgramsList,cl::Program * notify)363     CLAsyncBuildTask(CLProgramVk *programVk,
364                      const cl::DevicePtrs &devices,
365                      std::string options,
366                      std::string internalOptions,
367                      CLProgramVk::BuildType buildType,
368                      const CLProgramVk::LinkProgramsList &LinkProgramsList,
369                      cl::Program *notify)
370         : mProgramVk(programVk),
371           mDevices(devices),
372           mOptions(options),
373           mInternalOptions(internalOptions),
374           mBuildType(buildType),
375           mLinkProgramsList(LinkProgramsList),
376           mNotify(notify)
377     {}
378 
379     void operator()() override;
380 
381   private:
382     CLProgramVk *mProgramVk;
383     const cl::DevicePtrs mDevices;
384     std::string mOptions;
385     std::string mInternalOptions;
386     CLProgramVk::BuildType mBuildType;
387     const CLProgramVk::LinkProgramsList mLinkProgramsList;
388     cl::Program *mNotify;
389 };
390 
391 }  // namespace rx
392 
393 #endif  // LIBANGLE_RENDERER_VULKAN_CLPROGRAMVK_H_
394