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