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/ShaderInterfaceVariableInfoMap.h" 19 #include "libANGLE/renderer/glslang_wrapper_utils.h" 20 #include "libANGLE/renderer/vulkan/ContextVk.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(const gl::ShaderBitSet &linkedShaderStages, 34 const gl::ShaderMap<const angle::spirv::Blob *> &spirvBlobs, 35 const ShaderInterfaceVariableInfoMap &variableInfoMap); 36 void initShaderFromProgram(gl::ShaderType shaderType, const ShaderInfo &programShaderInfo); 37 void clear(); 38 valid()39 ANGLE_INLINE bool valid() const { return mIsInitialized; } 40 getSpirvBlobs()41 const gl::ShaderMap<angle::spirv::Blob> &getSpirvBlobs() const { return mSpirvBlobs; } 42 43 // Save and load implementation for GLES Program Binary support. 44 void load(gl::BinaryInputStream *stream); 45 void save(gl::BinaryOutputStream *stream); 46 47 private: 48 gl::ShaderMap<angle::spirv::Blob> mSpirvBlobs; 49 bool mIsInitialized = false; 50 }; 51 52 struct ProgramTransformOptions final 53 { 54 uint8_t enableLineRasterEmulation : 1; 55 uint8_t removeEarlyFragmentTestsOptimization : 1; 56 uint8_t surfaceRotation : 3; 57 uint8_t enableDepthCorrection : 1; 58 uint8_t removeTransformFeedbackEmulation : 1; 59 uint8_t reserved : 1; // must initialize to zero 60 static constexpr uint32_t kPermutationCount = 0x1 << 7; 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::ShaderAndSerial>> 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 struct ProgramExecutablePerfCounters 111 { 112 angle::PackedEnumMap<DescriptorSetIndex, CacheStats> cacheStats; 113 DescriptorSetCountList descriptorSetCacheKeySizesBytes; 114 }; 115 116 using DefaultUniformBlockMap = gl::ShaderMap<std::shared_ptr<DefaultUniformBlock>>; 117 118 class ProgramExecutableVk 119 { 120 public: 121 ProgramExecutableVk(); 122 virtual ~ProgramExecutableVk(); 123 124 void reset(ContextVk *contextVk); 125 126 void save(gl::BinaryOutputStream *stream); 127 std::unique_ptr<rx::LinkEvent> load(ContextVk *contextVk, 128 const gl::ProgramExecutable &glExecutable, 129 gl::BinaryInputStream *stream); 130 131 void clearVariableInfoMap(); 132 getGraphicsDefaultProgramInfo()133 ProgramInfo &getGraphicsDefaultProgramInfo() { return mGraphicsProgramInfos[0]; } getGraphicsProgramInfo(ProgramTransformOptions option)134 ProgramInfo &getGraphicsProgramInfo(ProgramTransformOptions option) 135 { 136 uint8_t index = gl::bitCast<uint8_t, ProgramTransformOptions>(option); 137 return mGraphicsProgramInfos[index]; 138 } getComputeProgramInfo()139 ProgramInfo &getComputeProgramInfo() { return mComputeProgramInfo; } getCurrentDefaultUniformBufferSerial()140 vk::BufferSerial getCurrentDefaultUniformBufferSerial() const 141 { 142 return mCurrentDefaultUniformBufferSerial; 143 } 144 145 angle::Result getGraphicsPipeline(ContextVk *contextVk, 146 gl::PrimitiveMode mode, 147 const vk::GraphicsPipelineDesc &desc, 148 const gl::ProgramExecutable &glExecutable, 149 const vk::GraphicsPipelineDesc **descPtrOut, 150 vk::PipelineHelper **pipelineOut); 151 152 angle::Result getComputePipeline(ContextVk *contextVk, vk::PipelineHelper **pipelineOut); 153 getPipelineLayout()154 const vk::PipelineLayout &getPipelineLayout() const { return mPipelineLayout.get(); } 155 angle::Result createPipelineLayout(ContextVk *contextVk, 156 const gl::ProgramExecutable &glExecutable, 157 gl::ActiveTextureArray<vk::TextureUnit> *activeTextures); 158 159 angle::Result updateTexturesDescriptorSet( 160 vk::Context *context, 161 UpdateDescriptorSetsBuilder *updateBuilder, 162 vk::ResourceUseList *resourceUseList, 163 const gl::ProgramExecutable &executable, 164 const gl::ActiveTextureArray<vk::TextureUnit> &activeTextures, 165 const vk::DescriptorSetDesc &texturesDesc, 166 bool emulateSeamfulCubeMapSampling); 167 angle::Result updateShaderResourcesDescriptorSet( 168 ContextVk *contextVk, 169 const gl::ProgramExecutable *executable, 170 UpdateDescriptorSetsBuilder *updateBuilder, 171 vk::BufferHelper *emptyBuffer, 172 vk::ResourceUseList *resourceUseList, 173 FramebufferVk *framebufferVk, 174 const vk::DescriptorSetDesc &shaderResourcesDesc); 175 angle::Result updateUniformsAndXfbDescriptorSet(vk::Context *context, 176 UpdateDescriptorSetsBuilder *updateBuilder, 177 vk::ResourceUseList *resourceUseList, 178 vk::BufferHelper *emptyBuffer, 179 const gl::ProgramExecutable &executable, 180 vk::BufferHelper *defaultUniformBuffer, 181 const vk::DescriptorSetDesc &uniformsAndXfbDesc, 182 bool isTransformFeedbackActiveUnpaused, 183 TransformFeedbackVk *transformFeedbackVk); 184 angle::Result updateInputAttachmentDescriptorSet(vk::Context *context, 185 vk::ResourceUseList *resourceUseList, 186 UpdateDescriptorSetsBuilder *updateBuilder, 187 const gl::ProgramExecutable &executable, 188 gl::ShaderType shaderType, 189 FramebufferVk *framebufferVk); 190 191 template <typename CommandBufferT> 192 angle::Result updateDescriptorSets(vk::Context *context, 193 vk::ResourceUseList *resourceUseList, 194 CommandBufferT *commandBuffer, 195 PipelineType pipelineType); 196 197 void updateEarlyFragmentTestsOptimization(ContextVk *contextVk, 198 const gl::ProgramExecutable &glExecutable); 199 usesDynamicUniformBufferDescriptors()200 bool usesDynamicUniformBufferDescriptors() const 201 { 202 return mUniformBufferDescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 203 } usesDynamicShaderStorageBufferDescriptors()204 bool usesDynamicShaderStorageBufferDescriptors() const { return false; } usesDynamicAtomicCounterBufferDescriptors()205 bool usesDynamicAtomicCounterBufferDescriptors() const { return false; } 206 areImmutableSamplersCompatible(const ImmutableSamplerIndexMap & immutableSamplerIndexMap)207 bool areImmutableSamplersCompatible( 208 const ImmutableSamplerIndexMap &immutableSamplerIndexMap) const 209 { 210 return (mImmutableSamplerIndexMap == immutableSamplerIndexMap); 211 } 212 213 void accumulateCacheStats(VulkanCacheType cacheType, const CacheStats &cacheStats); 214 ProgramExecutablePerfCounters getDescriptorSetPerfCounters(); 215 void resetDescriptorSetPerfCounters(); 216 getDefaultUniformAlignedSize(vk::Context * context,gl::ShaderType shaderType)217 size_t getDefaultUniformAlignedSize(vk::Context *context, gl::ShaderType shaderType) const 218 { 219 RendererVk *renderer = context->getRenderer(); 220 size_t alignment = static_cast<size_t>( 221 renderer->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment); 222 return roundUp(mDefaultUniformBlocks[shaderType]->uniformData.size(), alignment); 223 } 224 getSharedDefaultUniformBlock(gl::ShaderType shaderType)225 std::shared_ptr<DefaultUniformBlock> &getSharedDefaultUniformBlock(gl::ShaderType shaderType) 226 { 227 return mDefaultUniformBlocks[shaderType]; 228 } 229 hasDirtyUniforms()230 bool hasDirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); } 231 232 void setAllDefaultUniformsDirty(const gl::ProgramExecutable &executable); 233 angle::Result updateUniforms(vk::Context *context, 234 UpdateDescriptorSetsBuilder *updateBuilder, 235 vk::ResourceUseList *resourceUseList, 236 vk::BufferHelper *emptyBuffer, 237 const gl::ProgramExecutable &glExecutable, 238 vk::DynamicBuffer *defaultUniformStorage, 239 bool isTransformFeedbackActiveUnpaused, 240 TransformFeedbackVk *transformFeedbackVk); 241 void onProgramBind(const gl::ProgramExecutable &glExecutable); 242 243 private: 244 friend class ProgramVk; 245 friend class ProgramPipelineVk; 246 247 angle::Result allocUniformAndXfbDescriptorSet(vk::Context *context, 248 vk::ResourceUseList *resourceUseList, 249 vk::BufferHelper *defaultUniformBuffer, 250 const vk::DescriptorSetDesc &xfbBufferDesc, 251 bool *newDescriptorSetAllocated); 252 253 angle::Result allocateDescriptorSet(vk::Context *context, 254 vk::ResourceUseList *resourceUseList, 255 DescriptorSetIndex descriptorSetIndex); 256 angle::Result allocateDescriptorSetAndGetInfo(vk::Context *context, 257 vk::ResourceUseList *resourceUseList, 258 DescriptorSetIndex descriptorSetIndex, 259 bool *newPoolAllocatedOut); 260 void addInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> &blocks, 261 gl::ShaderType shaderType, 262 ShaderVariableType variableType, 263 VkDescriptorType descType, 264 vk::DescriptorSetLayoutDesc *descOut); 265 void addAtomicCounterBufferDescriptorSetDesc( 266 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers, 267 gl::ShaderType shaderType, 268 vk::DescriptorSetLayoutDesc *descOut); 269 void addImageDescriptorSetDesc(const gl::ProgramExecutable &executable, 270 vk::DescriptorSetLayoutDesc *descOut); 271 void addInputAttachmentDescriptorSetDesc(const gl::ProgramExecutable &executable, 272 gl::ShaderType shaderType, 273 vk::DescriptorSetLayoutDesc *descOut); 274 angle::Result addTextureDescriptorSetDesc( 275 ContextVk *contextVk, 276 const gl::ProgramExecutable &executable, 277 const gl::ActiveTextureArray<vk::TextureUnit> *activeTextures, 278 vk::DescriptorSetLayoutDesc *descOut); 279 280 void resolvePrecisionMismatch(const gl::ProgramMergedVaryings &mergedVaryings); 281 void updateDefaultUniformsDescriptorSet(vk::Context *context, 282 UpdateDescriptorSetsBuilder *updateBuilder, 283 vk::BufferHelper *emptyBuffer, 284 vk::ResourceUseList *resourceUseList, 285 gl::ShaderType shaderType, 286 const DefaultUniformBlock &defaultUniformBlock, 287 vk::BufferHelper *defaultUniformBuffer); 288 void updateTransformFeedbackDescriptorSetImpl(vk::Context *context, 289 UpdateDescriptorSetsBuilder *updateBuilder, 290 vk::BufferHelper *emptyBuffer, 291 const gl::ProgramExecutable &executable, 292 bool isTransformFeedbackActiveUnpaused, 293 TransformFeedbackVk *transformFeedbackVk); 294 angle::Result allocateShaderResourcesDescriptorSet( 295 vk::Context *context, 296 vk::ResourceUseList *resourceUseList, 297 const vk::DescriptorSetDesc *shaderResourcesDesc); 298 angle::Result updateBuffersDescriptorSet(vk::Context *context, 299 UpdateDescriptorSetsBuilder *updateBuilder, 300 vk::BufferHelper *emptyBuffer, 301 vk::ResourceUseList *resourceUseList, 302 gl::ShaderType shaderType, 303 const vk::DescriptorSetDesc &shaderResourcesDesc, 304 const gl::BufferVector &buffers, 305 const std::vector<gl::InterfaceBlock> &blocks, 306 ShaderVariableType variableType, 307 VkDescriptorType descriptorType, 308 VkDeviceSize maxBoundBufferRange, 309 bool cacheHit); 310 angle::Result updateAtomicCounterBuffersDescriptorSet( 311 vk::Context *context, 312 UpdateDescriptorSetsBuilder *updateBuilder, 313 vk::BufferHelper *emptyBuffer, 314 vk::ResourceUseList *resourceUseList, 315 const gl::BufferVector &atomicCounterBufferBindings, 316 const gl::ProgramExecutable &executable, 317 gl::ShaderType shaderType, 318 const vk::DescriptorSetDesc &shaderResourcesDesc, 319 bool cacheHit); 320 angle::Result updateImagesDescriptorSet(vk::Context *context, 321 vk::ResourceUseList *resourceUseList, 322 UpdateDescriptorSetsBuilder *updateBuilder, 323 const gl::ActiveTextureArray<TextureVk *> &activeImages, 324 const std::vector<gl::ImageUnit> &imageUnits, 325 const gl::ProgramExecutable &executable, 326 gl::ShaderType shaderType); 327 328 static angle::Result InitDynamicDescriptorPool( 329 vk::Context *context, 330 vk::DescriptorSetLayoutDesc &descriptorSetLayoutDesc, 331 VkDescriptorSetLayout descriptorSetLayout, 332 uint32_t descriptorCountMultiplier, 333 vk::DynamicDescriptorPool *dynamicDescriptorPool); 334 335 size_t calcUniformUpdateRequiredSpace(vk::Context *context, 336 const gl::ProgramExecutable &glExecutable, 337 gl::ShaderMap<VkDeviceSize> *uniformOffsets) const; 338 initProgram(ContextVk * contextVk,gl::ShaderType shaderType,bool isLastPreFragmentStage,bool isTransformFeedbackProgram,ProgramTransformOptions optionBits,ProgramInfo * programInfo,const ShaderInterfaceVariableInfoMap & variableInfoMap)339 ANGLE_INLINE angle::Result initProgram(ContextVk *contextVk, 340 gl::ShaderType shaderType, 341 bool isLastPreFragmentStage, 342 bool isTransformFeedbackProgram, 343 ProgramTransformOptions optionBits, 344 ProgramInfo *programInfo, 345 const ShaderInterfaceVariableInfoMap &variableInfoMap) 346 { 347 ASSERT(mOriginalShaderInfo.valid()); 348 349 // Create the program pipeline. This is done lazily and once per combination of 350 // specialization constants. 351 if (!programInfo->valid(shaderType)) 352 { 353 ANGLE_TRY(programInfo->initProgram(contextVk, shaderType, isLastPreFragmentStage, 354 isTransformFeedbackProgram, mOriginalShaderInfo, 355 optionBits, variableInfoMap)); 356 } 357 ASSERT(programInfo->valid(shaderType)); 358 359 return angle::Result::Continue; 360 } 361 initGraphicsShaderProgram(ContextVk * contextVk,gl::ShaderType shaderType,bool isLastPreFragmentStage,bool isTransformFeedbackProgram,ProgramTransformOptions optionBits,ProgramInfo * programInfo,const ShaderInterfaceVariableInfoMap & variableInfoMap)362 ANGLE_INLINE angle::Result initGraphicsShaderProgram( 363 ContextVk *contextVk, 364 gl::ShaderType shaderType, 365 bool isLastPreFragmentStage, 366 bool isTransformFeedbackProgram, 367 ProgramTransformOptions optionBits, 368 ProgramInfo *programInfo, 369 const ShaderInterfaceVariableInfoMap &variableInfoMap) 370 { 371 return initProgram(contextVk, shaderType, isLastPreFragmentStage, 372 isTransformFeedbackProgram, optionBits, programInfo, variableInfoMap); 373 } 374 initComputeProgram(ContextVk * contextVk,ProgramInfo * programInfo,const ShaderInterfaceVariableInfoMap & variableInfoMap)375 ANGLE_INLINE angle::Result initComputeProgram( 376 ContextVk *contextVk, 377 ProgramInfo *programInfo, 378 const ShaderInterfaceVariableInfoMap &variableInfoMap) 379 { 380 ProgramTransformOptions optionBits = {}; 381 return initProgram(contextVk, gl::ShaderType::Compute, false, false, optionBits, 382 programInfo, variableInfoMap); 383 } 384 385 angle::Result resizeUniformBlockMemory(ContextVk *contextVk, 386 const gl::ProgramExecutable &glExecutable, 387 const gl::ShaderMap<size_t> &requiredBufferSize); 388 389 // Descriptor sets for uniform blocks and textures for this program. 390 vk::DescriptorSetArray<VkDescriptorSet> mDescriptorSets; 391 vk::DescriptorSetArray<VkDescriptorSet> mEmptyDescriptorSets; 392 uint32_t mNumDefaultUniformDescriptors; 393 vk::BufferSerial mCurrentDefaultUniformBufferSerial; 394 395 DescriptorSetCache mUniformsAndXfbDescriptorsCache; 396 DescriptorSetCache mTextureDescriptorsCache; 397 DescriptorSetCache mShaderBufferDescriptorsCache; 398 399 // We keep a reference to the pipeline and descriptor set layouts. This ensures they don't get 400 // deleted while this program is in use. 401 uint32_t mImmutableSamplersMaxDescriptorCount; 402 ImmutableSamplerIndexMap mImmutableSamplerIndexMap; 403 vk::BindingPointer<vk::PipelineLayout> mPipelineLayout; 404 vk::DescriptorSetLayoutPointerArray mDescriptorSetLayouts; 405 406 // Keep bindings to the descriptor pools. This ensures the pools stay valid while the Program 407 // is in use. 408 vk::DescriptorSetArray<vk::RefCountedDescriptorPoolBinding> mDescriptorPoolBindings; 409 410 // Store descriptor pools here. We store the descriptors in the Program to facilitate descriptor 411 // cache management. It can also allow fewer descriptors for shaders which use fewer 412 // textures/buffers. 413 vk::DescriptorSetArray<vk::DynamicDescriptorPool> mDynamicDescriptorPools; 414 415 // A set of dynamic offsets used with vkCmdBindDescriptorSets for the default uniform buffers. 416 VkDescriptorType mUniformBufferDescriptorType; 417 gl::ShaderVector<uint32_t> mDynamicUniformDescriptorOffsets; 418 std::vector<uint32_t> mDynamicShaderBufferDescriptorOffsets; 419 420 ShaderInterfaceVariableInfoMap mVariableInfoMap; 421 422 // We store all permutations of surface rotation and transformed SPIR-V programs here. We may 423 // need some LRU algorithm to free least used programs to reduce the number of programs. 424 ProgramInfo mGraphicsProgramInfos[ProgramTransformOptions::kPermutationCount]; 425 ProgramInfo mComputeProgramInfo; 426 427 ProgramTransformOptions mTransformOptions; 428 429 DefaultUniformBlockMap mDefaultUniformBlocks; 430 gl::ShaderBitSet mDefaultUniformBlocksDirty; 431 432 ShaderInfo mOriginalShaderInfo; 433 434 ProgramExecutablePerfCounters mPerfCounters; 435 ProgramExecutablePerfCounters mCumulativePerfCounters; 436 }; 437 438 } // namespace rx 439 440 #endif // LIBANGLE_RENDERER_VULKAN_PROGRAMEXECUTABLEVK_H_ 441