• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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