1 // 2 // Copyright 2020 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 7 // ProgramExecutableVk.h: Collects the information and interfaces common to both ProgramVks and 8 // ProgramPipelineVks in order to execute/draw with either. 9 10 #ifndef LIBANGLE_RENDERER_VULKAN_PROGRAMEXECUTABLEVK_H_ 11 #define LIBANGLE_RENDERER_VULKAN_PROGRAMEXECUTABLEVK_H_ 12 13 #include "common/bitset_utils.h" 14 #include "common/mathutil.h" 15 #include "common/utilities.h" 16 #include "libANGLE/Context.h" 17 #include "libANGLE/InfoLog.h" 18 #include "libANGLE/renderer/vulkan/ContextVk.h" 19 #include "libANGLE/renderer/vulkan/ShaderInterfaceVariableInfoMap.h" 20 #include "libANGLE/renderer/vulkan/spv_utils.h" 21 #include "libANGLE/renderer/vulkan/vk_cache_utils.h" 22 #include "libANGLE/renderer/vulkan/vk_helpers.h" 23 24 namespace rx 25 { 26 27 class ShaderInfo final : angle::NonCopyable 28 { 29 public: 30 ShaderInfo(); 31 ~ShaderInfo(); 32 33 angle::Result initShaders(ContextVk *contextVk, 34 const gl::ShaderBitSet &linkedShaderStages, 35 const gl::ShaderMap<const angle::spirv::Blob *> &spirvBlobs, 36 const ShaderInterfaceVariableInfoMap &variableInfoMap); 37 void initShaderFromProgram(gl::ShaderType shaderType, const ShaderInfo &programShaderInfo); 38 void clear(); 39 valid()40 ANGLE_INLINE bool valid() const { return mIsInitialized; } 41 getSpirvBlobs()42 const gl::ShaderMap<angle::spirv::Blob> &getSpirvBlobs() const { return mSpirvBlobs; } 43 44 // Save and load implementation for GLES Program Binary support. 45 void load(gl::BinaryInputStream *stream); 46 void save(gl::BinaryOutputStream *stream); 47 48 private: 49 gl::ShaderMap<angle::spirv::Blob> mSpirvBlobs; 50 bool mIsInitialized = false; 51 }; 52 53 struct ProgramTransformOptions final 54 { 55 uint8_t surfaceRotation : 1; 56 uint8_t removeTransformFeedbackEmulation : 1; 57 uint8_t multiSampleFramebufferFetch : 1; 58 uint8_t enableSampleShading : 1; 59 uint8_t reserved : 4; // must initialize to zero 60 static constexpr uint32_t kPermutationCount = 0x1 << 4; 61 }; 62 static_assert(sizeof(ProgramTransformOptions) == 1, "Size check failed"); 63 static_assert(static_cast<int>(SurfaceRotation::EnumCount) <= 8, "Size check failed"); 64 65 class ProgramInfo final : angle::NonCopyable 66 { 67 public: 68 ProgramInfo(); 69 ~ProgramInfo(); 70 71 angle::Result initProgram(ContextVk *contextVk, 72 gl::ShaderType shaderType, 73 bool isLastPreFragmentStage, 74 bool isTransformFeedbackProgram, 75 const ShaderInfo &shaderInfo, 76 ProgramTransformOptions optionBits, 77 const ShaderInterfaceVariableInfoMap &variableInfoMap); 78 void release(ContextVk *contextVk); 79 valid(gl::ShaderType shaderType)80 ANGLE_INLINE bool valid(gl::ShaderType shaderType) const 81 { 82 return mProgramHelper.valid(shaderType); 83 } 84 getShaderProgram()85 vk::ShaderProgramHelper *getShaderProgram() { return &mProgramHelper; } 86 87 private: 88 vk::ShaderProgramHelper mProgramHelper; 89 gl::ShaderMap<vk::RefCounted<vk::ShaderModule>> mShaders; 90 }; 91 92 // State for the default uniform blocks. 93 struct DefaultUniformBlock final : private angle::NonCopyable 94 { 95 DefaultUniformBlock(); 96 ~DefaultUniformBlock(); 97 98 // Shadow copies of the shader uniform data. 99 angle::MemoryBuffer uniformData; 100 101 // Since the default blocks are laid out in std140, this tells us where to write on a call 102 // to a setUniform method. They are arranged in uniform location order. 103 std::vector<sh::BlockMemberInfo> uniformLayout; 104 }; 105 106 // Performance and resource counters. 107 using DescriptorSetCountList = angle::PackedEnumMap<DescriptorSetIndex, uint32_t>; 108 using ImmutableSamplerIndexMap = angle::HashMap<vk::YcbcrConversionDesc, uint32_t>; 109 110 using DefaultUniformBlockMap = gl::ShaderMap<std::shared_ptr<DefaultUniformBlock>>; 111 112 class ProgramExecutableVk 113 { 114 public: 115 ProgramExecutableVk(); 116 virtual ~ProgramExecutableVk(); 117 118 void reset(ContextVk *contextVk); 119 120 void save(ContextVk *contextVk, bool isSeparable, gl::BinaryOutputStream *stream); 121 std::unique_ptr<rx::LinkEvent> load(ContextVk *contextVk, 122 const gl::ProgramExecutable &glExecutable, 123 bool isSeparable, 124 gl::BinaryInputStream *stream); 125 126 void clearVariableInfoMap(); 127 getCurrentDefaultUniformBufferSerial()128 vk::BufferSerial getCurrentDefaultUniformBufferSerial() const 129 { 130 return mCurrentDefaultUniformBufferSerial; 131 } 132 133 // Get the graphics pipeline if already created. 134 angle::Result getGraphicsPipeline(ContextVk *contextVk, 135 vk::GraphicsPipelineSubset pipelineSubset, 136 const vk::GraphicsPipelineDesc &desc, 137 const gl::ProgramExecutable &glExecutable, 138 const vk::GraphicsPipelineDesc **descPtrOut, 139 vk::PipelineHelper **pipelineOut); 140 141 angle::Result createGraphicsPipeline(ContextVk *contextVk, 142 vk::GraphicsPipelineSubset pipelineSubset, 143 vk::PipelineCacheAccess *pipelineCache, 144 PipelineSource source, 145 const vk::GraphicsPipelineDesc &desc, 146 const gl::ProgramExecutable &glExecutable, 147 const vk::GraphicsPipelineDesc **descPtrOut, 148 vk::PipelineHelper **pipelineOut); 149 150 angle::Result linkGraphicsPipelineLibraries(ContextVk *contextVk, 151 vk::PipelineCacheAccess *pipelineCache, 152 const vk::GraphicsPipelineDesc &desc, 153 const gl::ProgramExecutable &glExecutable, 154 vk::PipelineHelper *vertexInputPipeline, 155 vk::PipelineHelper *shadersPipeline, 156 vk::PipelineHelper *fragmentOutputPipeline, 157 const vk::GraphicsPipelineDesc **descPtrOut, 158 vk::PipelineHelper **pipelineOut); 159 160 angle::Result getOrCreateComputePipeline(ContextVk *contextVk, 161 vk::PipelineCacheAccess *pipelineCache, 162 PipelineSource source, 163 const gl::ProgramExecutable &glExecutable, 164 vk::PipelineHelper **pipelineOut); 165 getPipelineLayout()166 const vk::PipelineLayout &getPipelineLayout() const { return mPipelineLayout.get(); } 167 angle::Result createPipelineLayout(ContextVk *contextVk, 168 const gl::ProgramExecutable &glExecutable, 169 gl::ActiveTextureArray<TextureVk *> *activeTextures); 170 171 angle::Result updateTexturesDescriptorSet(vk::Context *context, 172 const gl::ProgramExecutable &executable, 173 const gl::ActiveTextureArray<TextureVk *> &textures, 174 const gl::SamplerBindingVector &samplers, 175 bool emulateSeamfulCubeMapSampling, 176 PipelineType pipelineType, 177 UpdateDescriptorSetsBuilder *updateBuilder, 178 vk::CommandBufferHelperCommon *commandBufferHelper, 179 const vk::DescriptorSetDesc &texturesDesc); 180 181 angle::Result updateShaderResourcesDescriptorSet( 182 vk::Context *context, 183 UpdateDescriptorSetsBuilder *updateBuilder, 184 const vk::WriteDescriptorDescs &writeDescriptorDescs, 185 vk::CommandBufferHelperCommon *commandBufferHelper, 186 const vk::DescriptorSetDescBuilder &shaderResourcesDesc, 187 vk::SharedDescriptorSetCacheKey *newSharedCacheKeyOut); 188 189 angle::Result updateUniformsAndXfbDescriptorSet( 190 vk::Context *context, 191 UpdateDescriptorSetsBuilder *updateBuilder, 192 const vk::WriteDescriptorDescs &writeDescriptorDescs, 193 vk::CommandBufferHelperCommon *commandBufferHelper, 194 vk::BufferHelper *defaultUniformBuffer, 195 vk::DescriptorSetDescBuilder *uniformsAndXfbDesc, 196 vk::SharedDescriptorSetCacheKey *sharedCacheKeyOut); 197 198 template <typename CommandBufferT> 199 angle::Result bindDescriptorSets(vk::Context *context, 200 vk::CommandBufferHelperCommon *commandBufferHelper, 201 CommandBufferT *commandBuffer, 202 PipelineType pipelineType); 203 usesDynamicUniformBufferDescriptors()204 bool usesDynamicUniformBufferDescriptors() const 205 { 206 return mUniformBufferDescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 207 } getUniformBufferDescriptorType()208 VkDescriptorType getUniformBufferDescriptorType() const { return mUniformBufferDescriptorType; } usesDynamicShaderStorageBufferDescriptors()209 bool usesDynamicShaderStorageBufferDescriptors() const { return false; } getStorageBufferDescriptorType()210 VkDescriptorType getStorageBufferDescriptorType() const 211 { 212 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 213 } getAtomicCounterBufferDescriptorType()214 VkDescriptorType getAtomicCounterBufferDescriptorType() const 215 { 216 return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 217 } usesDynamicAtomicCounterBufferDescriptors()218 bool usesDynamicAtomicCounterBufferDescriptors() const { return false; } 219 areImmutableSamplersCompatible(const ImmutableSamplerIndexMap & immutableSamplerIndexMap)220 bool areImmutableSamplersCompatible( 221 const ImmutableSamplerIndexMap &immutableSamplerIndexMap) const 222 { 223 return (mImmutableSamplerIndexMap == immutableSamplerIndexMap); 224 } 225 getDefaultUniformAlignedSize(vk::Context * context,gl::ShaderType shaderType)226 size_t getDefaultUniformAlignedSize(vk::Context *context, gl::ShaderType shaderType) const 227 { 228 RendererVk *renderer = context->getRenderer(); 229 size_t alignment = static_cast<size_t>( 230 renderer->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment); 231 return roundUp(mDefaultUniformBlocks[shaderType]->uniformData.size(), alignment); 232 } 233 getSharedDefaultUniformBlock(gl::ShaderType shaderType)234 std::shared_ptr<DefaultUniformBlock> &getSharedDefaultUniformBlock(gl::ShaderType shaderType) 235 { 236 return mDefaultUniformBlocks[shaderType]; 237 } 238 hasDirtyUniforms()239 bool hasDirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); } 240 241 void setAllDefaultUniformsDirty(const gl::ProgramExecutable &executable); 242 angle::Result updateUniforms(vk::Context *context, 243 UpdateDescriptorSetsBuilder *updateBuilder, 244 vk::CommandBufferHelperCommon *commandBufferHelper, 245 vk::BufferHelper *emptyBuffer, 246 const gl::ProgramExecutable &glExecutable, 247 vk::DynamicBuffer *defaultUniformStorage, 248 bool isTransformFeedbackActiveUnpaused, 249 TransformFeedbackVk *transformFeedbackVk); 250 void onProgramBind(const gl::ProgramExecutable &glExecutable); 251 getVariableInfoMap()252 const ShaderInterfaceVariableInfoMap &getVariableInfoMap() const { return mVariableInfoMap; } 253 254 angle::Result warmUpPipelineCache(ContextVk *contextVk, 255 const gl::ProgramExecutable &glExecutable); 256 getShaderResourceWriteDescriptorDescs()257 const vk::WriteDescriptorDescs &getShaderResourceWriteDescriptorDescs() const 258 { 259 return mShaderResourceWriteDescriptorDescs; 260 } getDefaultUniformWriteDescriptorDescs(TransformFeedbackVk * transformFeedbackVk)261 const vk::WriteDescriptorDescs &getDefaultUniformWriteDescriptorDescs( 262 TransformFeedbackVk *transformFeedbackVk) const 263 { 264 return transformFeedbackVk == nullptr ? mDefaultUniformWriteDescriptorDescs 265 : mDefaultUniformAndXfbWriteDescriptorDescs; 266 } 267 getTextureWriteDescriptorDescs()268 const vk::WriteDescriptorDescs &getTextureWriteDescriptorDescs() const 269 { 270 return mTextureWriteDescriptorDescs; 271 } getDirtyBits()272 const gl::Program::DirtyBits &getDirtyBits() const { return mDirtyBits; } resetUniformBufferDirtyBits()273 void resetUniformBufferDirtyBits() { mDirtyBits.reset(); } 274 275 private: 276 friend class ProgramVk; 277 friend class ProgramPipelineVk; 278 279 void addInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> &blocks, 280 gl::ShaderBitSet shaderTypes, 281 VkDescriptorType descType, 282 vk::DescriptorSetLayoutDesc *descOut); 283 void addAtomicCounterBufferDescriptorSetDesc( 284 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers, 285 vk::DescriptorSetLayoutDesc *descOut); 286 void addImageDescriptorSetDesc(const gl::ProgramExecutable &executable, 287 vk::DescriptorSetLayoutDesc *descOut); 288 void addInputAttachmentDescriptorSetDesc(const gl::ProgramExecutable &executable, 289 vk::DescriptorSetLayoutDesc *descOut); 290 angle::Result addTextureDescriptorSetDesc( 291 ContextVk *contextVk, 292 const gl::ProgramExecutable &executable, 293 const gl::ActiveTextureArray<TextureVk *> *activeTextures, 294 vk::DescriptorSetLayoutDesc *descOut); 295 296 void resolvePrecisionMismatch(const gl::ProgramMergedVaryings &mergedVaryings); 297 298 size_t calcUniformUpdateRequiredSpace(vk::Context *context, 299 const gl::ProgramExecutable &glExecutable, 300 gl::ShaderMap<VkDeviceSize> *uniformOffsets) const; 301 initProgram(ContextVk * contextVk,gl::ShaderType shaderType,bool isLastPreFragmentStage,bool isTransformFeedbackProgram,ProgramTransformOptions optionBits,ProgramInfo * programInfo,const ShaderInterfaceVariableInfoMap & variableInfoMap)302 ANGLE_INLINE angle::Result initProgram(ContextVk *contextVk, 303 gl::ShaderType shaderType, 304 bool isLastPreFragmentStage, 305 bool isTransformFeedbackProgram, 306 ProgramTransformOptions optionBits, 307 ProgramInfo *programInfo, 308 const ShaderInterfaceVariableInfoMap &variableInfoMap) 309 { 310 ASSERT(mOriginalShaderInfo.valid()); 311 312 // Create the program pipeline. This is done lazily and once per combination of 313 // specialization constants. 314 if (!programInfo->valid(shaderType)) 315 { 316 ANGLE_TRY(programInfo->initProgram(contextVk, shaderType, isLastPreFragmentStage, 317 isTransformFeedbackProgram, mOriginalShaderInfo, 318 optionBits, variableInfoMap)); 319 } 320 ASSERT(programInfo->valid(shaderType)); 321 322 return angle::Result::Continue; 323 } 324 initGraphicsShaderProgram(ContextVk * contextVk,gl::ShaderType shaderType,bool isLastPreFragmentStage,bool isTransformFeedbackProgram,ProgramTransformOptions optionBits,ProgramInfo * programInfo,const ShaderInterfaceVariableInfoMap & variableInfoMap)325 ANGLE_INLINE angle::Result initGraphicsShaderProgram( 326 ContextVk *contextVk, 327 gl::ShaderType shaderType, 328 bool isLastPreFragmentStage, 329 bool isTransformFeedbackProgram, 330 ProgramTransformOptions optionBits, 331 ProgramInfo *programInfo, 332 const ShaderInterfaceVariableInfoMap &variableInfoMap) 333 { 334 return initProgram(contextVk, shaderType, isLastPreFragmentStage, 335 isTransformFeedbackProgram, optionBits, programInfo, variableInfoMap); 336 } 337 initComputeProgram(ContextVk * contextVk,ProgramInfo * programInfo,const ShaderInterfaceVariableInfoMap & variableInfoMap)338 ANGLE_INLINE angle::Result initComputeProgram( 339 ContextVk *contextVk, 340 ProgramInfo *programInfo, 341 const ShaderInterfaceVariableInfoMap &variableInfoMap) 342 { 343 ProgramTransformOptions optionBits = {}; 344 return initProgram(contextVk, gl::ShaderType::Compute, false, false, optionBits, 345 programInfo, variableInfoMap); 346 } 347 348 ProgramTransformOptions getTransformOptions(ContextVk *contextVk, 349 const vk::GraphicsPipelineDesc &desc, 350 const gl::ProgramExecutable &glExecutable); 351 angle::Result initGraphicsShaderPrograms(ContextVk *contextVk, 352 ProgramTransformOptions transformOptions, 353 const gl::ProgramExecutable &glExecutable, 354 vk::ShaderProgramHelper **shaderProgramOut); 355 angle::Result createGraphicsPipelineImpl(ContextVk *contextVk, 356 ProgramTransformOptions transformOptions, 357 vk::GraphicsPipelineSubset pipelineSubset, 358 vk::PipelineCacheAccess *pipelineCache, 359 PipelineSource source, 360 const vk::GraphicsPipelineDesc &desc, 361 const gl::ProgramExecutable &glExecutable, 362 const vk::GraphicsPipelineDesc **descPtrOut, 363 vk::PipelineHelper **pipelineOut); 364 365 angle::Result resizeUniformBlockMemory(ContextVk *contextVk, 366 const gl::ProgramExecutable &glExecutable, 367 const gl::ShaderMap<size_t> &requiredBufferSize); 368 369 angle::Result getOrAllocateDescriptorSet(vk::Context *context, 370 UpdateDescriptorSetsBuilder *updateBuilder, 371 vk::CommandBufferHelperCommon *commandBufferHelper, 372 const vk::DescriptorSetDescBuilder &descriptorSetDesc, 373 const vk::WriteDescriptorDescs &writeDescriptorDescs, 374 DescriptorSetIndex setIndex, 375 vk::SharedDescriptorSetCacheKey *newSharedCacheKeyOut); 376 377 // When loading from cache / binary, initialize the pipeline cache with given data. Otherwise 378 // the cache is lazily created as needed. 379 angle::Result initializePipelineCache(ContextVk *contextVk, 380 bool compressed, 381 const std::vector<uint8_t> &pipelineData); 382 angle::Result ensurePipelineCacheInitialized(ContextVk *contextVk); 383 384 void resetLayout(ContextVk *contextVk); 385 void initializeWriteDescriptorDesc(ContextVk *contextVk, 386 const gl::ProgramExecutable &glExecutable); 387 388 // Descriptor sets and pools for shader resources for this program. 389 vk::DescriptorSetArray<VkDescriptorSet> mDescriptorSets; 390 vk::DescriptorSetArray<vk::DescriptorPoolPointer> mDescriptorPools; 391 vk::DescriptorSetArray<vk::RefCountedDescriptorPoolBinding> mDescriptorPoolBindings; 392 uint32_t mNumDefaultUniformDescriptors; 393 vk::BufferSerial mCurrentDefaultUniformBufferSerial; 394 395 // We keep a reference to the pipeline and descriptor set layouts. This ensures they don't get 396 // deleted while this program is in use. 397 uint32_t mImmutableSamplersMaxDescriptorCount; 398 ImmutableSamplerIndexMap mImmutableSamplerIndexMap; 399 vk::BindingPointer<vk::PipelineLayout> mPipelineLayout; 400 vk::DescriptorSetLayoutPointerArray mDescriptorSetLayouts; 401 402 // A set of dynamic offsets used with vkCmdBindDescriptorSets for the default uniform buffers. 403 VkDescriptorType mUniformBufferDescriptorType; 404 gl::ShaderVector<uint32_t> mDynamicUniformDescriptorOffsets; 405 std::vector<uint32_t> mDynamicShaderResourceDescriptorOffsets; 406 407 ShaderInterfaceVariableInfoMap mVariableInfoMap; 408 409 // We store all permutations of surface rotation and transformed SPIR-V programs here. We may 410 // need some LRU algorithm to free least used programs to reduce the number of programs. 411 ProgramInfo mGraphicsProgramInfos[ProgramTransformOptions::kPermutationCount]; 412 ProgramInfo mComputeProgramInfo; 413 414 // Pipeline caches. The pipelines are tightly coupled with the shaders they are created for, so 415 // they live in the program executable. With VK_EXT_graphics_pipeline_library, the pipeline is 416 // divided in subsets; the "shaders" subset is created based on the shaders, so its cache lives 417 // in the program executable. The "vertex input" and "fragment output" pipelines are 418 // independent, and live in the context. 419 CompleteGraphicsPipelineCache 420 mCompleteGraphicsPipelines[ProgramTransformOptions::kPermutationCount]; 421 ShadersGraphicsPipelineCache 422 mShadersGraphicsPipelines[ProgramTransformOptions::kPermutationCount]; 423 vk::ComputePipelineCache mComputePipelines; 424 425 DefaultUniformBlockMap mDefaultUniformBlocks; 426 gl::ShaderBitSet mDefaultUniformBlocksDirty; 427 428 ShaderInfo mOriginalShaderInfo; 429 430 // The pipeline cache specific to this program executable. Currently: 431 // 432 // - This is used during warm up (at link time) 433 // - The contents are merged to RendererVk's pipeline cache immediately after warm up 434 // - The contents are returned as part of program binary 435 // - Draw-time pipeline creation uses RendererVk's cache 436 // 437 // Without VK_EXT_graphics_pipeline_library, this cache is not used for draw-time pipeline 438 // creations to allow reuse of other blobs that are independent of the actual shaders; vertex 439 // input fetch, fragment output and blend. 440 // 441 // With VK_EXT_graphics_pipeline_library, this cache is used for the "shaders" subset of the 442 // pipeline. 443 vk::PipelineCache mPipelineCache; 444 445 // The "layout" information for descriptorSets 446 vk::WriteDescriptorDescs mShaderResourceWriteDescriptorDescs; 447 vk::WriteDescriptorDescs mTextureWriteDescriptorDescs; 448 vk::WriteDescriptorDescs mDefaultUniformWriteDescriptorDescs; 449 vk::WriteDescriptorDescs mDefaultUniformAndXfbWriteDescriptorDescs; 450 451 gl::Program::DirtyBits mDirtyBits; 452 }; 453 454 } // namespace rx 455 456 #endif // LIBANGLE_RENDERER_VULKAN_PROGRAMEXECUTABLEVK_H_ 457