• 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/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