• 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/glslang_wrapper_utils.h"
19 #include "libANGLE/renderer/vulkan/ContextVk.h"
20 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
21 #include "libANGLE/renderer/vulkan/vk_helpers.h"
22 
23 namespace rx
24 {
25 
26 class ShaderInfo final : angle::NonCopyable
27 {
28   public:
29     ShaderInfo();
30     ~ShaderInfo();
31 
32     angle::Result initShaders(const gl::ShaderBitSet &linkedShaderStages,
33                               const gl::ShaderMap<const angle::spirv::Blob *> &spirvBlobs,
34                               const ShaderInterfaceVariableInfoMap &variableInfoMap);
35     void release(ContextVk *contextVk);
36 
valid()37     ANGLE_INLINE bool valid() const { return mIsInitialized; }
38 
getSpirvBlobs()39     const gl::ShaderMap<angle::spirv::Blob> &getSpirvBlobs() const { return mSpirvBlobs; }
40 
41     // Save and load implementation for GLES Program Binary support.
42     void load(gl::BinaryInputStream *stream);
43     void save(gl::BinaryOutputStream *stream);
44 
45   private:
46     gl::ShaderMap<angle::spirv::Blob> mSpirvBlobs;
47     bool mIsInitialized = false;
48 };
49 
50 struct ProgramTransformOptions final
51 {
52     uint8_t enableLineRasterEmulation : 1;
53     uint8_t removeEarlyFragmentTestsOptimization : 1;
54     uint8_t surfaceRotation : 3;
55     uint8_t enableDepthCorrection : 1;
56     uint8_t reserved : 2;  // must initialize to zero
57     static constexpr uint32_t kPermutationCount = 0x1 << 6;
58 };
59 static_assert(sizeof(ProgramTransformOptions) == 1, "Size check failed");
60 static_assert(static_cast<int>(SurfaceRotation::EnumCount) <= 8, "Size check failed");
61 
62 class ProgramInfo final : angle::NonCopyable
63 {
64   public:
65     ProgramInfo();
66     ~ProgramInfo();
67 
68     angle::Result initProgram(ContextVk *contextVk,
69                               const gl::ShaderType shaderType,
70                               bool isLastPreFragmentStage,
71                               bool isTransformFeedbackProgram,
72                               const ShaderInfo &shaderInfo,
73                               ProgramTransformOptions optionBits,
74                               const ShaderInterfaceVariableInfoMap &variableInfoMap);
75     void release(ContextVk *contextVk);
76 
valid(const gl::ShaderType shaderType)77     ANGLE_INLINE bool valid(const gl::ShaderType shaderType) const
78     {
79         return mProgramHelper.valid(shaderType);
80     }
81 
getShaderProgram()82     vk::ShaderProgramHelper *getShaderProgram() { return &mProgramHelper; }
83 
84   private:
85     vk::ShaderProgramHelper mProgramHelper;
86     gl::ShaderMap<vk::RefCounted<vk::ShaderAndSerial>> mShaders;
87 };
88 
89 // State for the default uniform blocks.
90 struct DefaultUniformBlock final : private angle::NonCopyable
91 {
92     DefaultUniformBlock();
93     ~DefaultUniformBlock();
94 
95     // Shadow copies of the shader uniform data.
96     angle::MemoryBuffer uniformData;
97 
98     // Since the default blocks are laid out in std140, this tells us where to write on a call
99     // to a setUniform method. They are arranged in uniform location order.
100     std::vector<sh::BlockMemberInfo> uniformLayout;
101 };
102 
103 // Performance and resource counters.
104 using DescriptorSetCountList = angle::PackedEnumMap<DescriptorSetIndex, uint32_t>;
105 template <typename T>
106 using FormatIndexMap = angle::HashMap<T, uint32_t>;
107 
108 struct ProgramExecutablePerfCounters
109 {
110     DescriptorSetCountList descriptorSetAllocations;
111     DescriptorSetCountList descriptorSetCacheHits;
112     DescriptorSetCountList descriptorSetCacheMisses;
113 };
114 
115 class ProgramExecutableVk
116 {
117   public:
118     ProgramExecutableVk();
119     virtual ~ProgramExecutableVk();
120 
121     void reset(ContextVk *contextVk);
122 
123     void save(gl::BinaryOutputStream *stream);
124     std::unique_ptr<rx::LinkEvent> load(gl::BinaryInputStream *stream);
125 
126     void clearVariableInfoMap();
127 
128     ProgramVk *getShaderProgram(const gl::State &glState, gl::ShaderType shaderType) const;
129 
130     void fillProgramStateMap(const ContextVk *contextVk,
131                              gl::ShaderMap<const gl::ProgramState *> *programStatesOut);
132     const gl::ProgramExecutable &getGlExecutable();
133 
getGraphicsDefaultProgramInfo()134     ProgramInfo &getGraphicsDefaultProgramInfo() { return mGraphicsProgramInfos[0]; }
getGraphicsProgramInfo(ProgramTransformOptions option)135     ProgramInfo &getGraphicsProgramInfo(ProgramTransformOptions option)
136     {
137         uint8_t index = gl::bitCast<uint8_t, ProgramTransformOptions>(option);
138         return mGraphicsProgramInfos[index];
139     }
getComputeProgramInfo()140     ProgramInfo &getComputeProgramInfo() { return mComputeProgramInfo; }
getCurrentDefaultUniformBufferSerial()141     vk::BufferSerial getCurrentDefaultUniformBufferSerial() const
142     {
143         return mCurrentDefaultUniformBufferSerial;
144     }
145 
146     angle::Result getGraphicsPipeline(ContextVk *contextVk,
147                                       gl::PrimitiveMode mode,
148                                       const vk::GraphicsPipelineDesc &desc,
149                                       const gl::AttributesMask &activeAttribLocations,
150                                       const vk::GraphicsPipelineDesc **descPtrOut,
151                                       vk::PipelineHelper **pipelineOut);
152 
153     angle::Result getComputePipeline(ContextVk *contextVk, vk::PipelineAndSerial **pipelineOut);
154 
getPipelineLayout()155     const vk::PipelineLayout &getPipelineLayout() const { return mPipelineLayout.get(); }
156     angle::Result createPipelineLayout(const gl::Context *glContext,
157                                        gl::ActiveTextureArray<vk::TextureUnit> *activeTextures);
158 
159     angle::Result updateTexturesDescriptorSet(ContextVk *contextVk,
160                                               const vk::TextureDescriptorDesc &texturesDesc);
161     angle::Result updateShaderResourcesDescriptorSet(
162         ContextVk *contextVk,
163         FramebufferVk *framebufferVk,
164         const vk::ShaderBuffersDescriptorDesc &shaderBuffersDesc,
165         vk::CommandBufferHelper *commandBufferHelper);
166     angle::Result updateTransformFeedbackDescriptorSet(
167         const gl::ProgramState &programState,
168         gl::ShaderMap<DefaultUniformBlock> &defaultUniformBlocks,
169         vk::BufferHelper *defaultUniformBuffer,
170         ContextVk *contextVk,
171         const vk::UniformsAndXfbDescriptorDesc &xfbBufferDesc);
172     angle::Result updateInputAttachmentDescriptorSet(const gl::ProgramExecutable &executable,
173                                                      const gl::ShaderType shaderType,
174                                                      ContextVk *contextVk,
175                                                      FramebufferVk *framebufferVk);
176 
177     angle::Result updateDescriptorSets(ContextVk *contextVk, vk::CommandBuffer *commandBuffer);
178 
179     void updateEarlyFragmentTestsOptimization(ContextVk *contextVk);
180 
setProgram(ProgramVk * program)181     void setProgram(ProgramVk *program)
182     {
183         ASSERT(!mProgram && !mProgramPipeline);
184         mProgram = program;
185     }
setProgramPipeline(ProgramPipelineVk * pipeline)186     void setProgramPipeline(ProgramPipelineVk *pipeline)
187     {
188         ASSERT(!mProgram && !mProgramPipeline);
189         mProgramPipeline = pipeline;
190     }
191 
usesDynamicUniformBufferDescriptors()192     bool usesDynamicUniformBufferDescriptors() const
193     {
194         return mUniformBufferDescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
195     }
196 
isImmutableSamplerFormatCompatible(const FormatIndexMap<uint64_t> & externalFormatIndexMap,const FormatIndexMap<VkFormat> & vkFormatIndexMap)197     bool isImmutableSamplerFormatCompatible(const FormatIndexMap<uint64_t> &externalFormatIndexMap,
198                                             const FormatIndexMap<VkFormat> &vkFormatIndexMap) const
199     {
200         return (mExternalFormatIndexMap == externalFormatIndexMap &&
201                 mVkFormatIndexMap == vkFormatIndexMap);
202     }
203 
204     void accumulateCacheStats(VulkanCacheType cacheType, const CacheStats &cacheStats);
205     ProgramExecutablePerfCounters getAndResetObjectPerfCounters();
206 
207   private:
208     friend class ProgramVk;
209     friend class ProgramPipelineVk;
210 
211     angle::Result allocUniformAndXfbDescriptorSet(
212         ContextVk *contextVk,
213         const vk::UniformsAndXfbDescriptorDesc &xfbBufferDesc,
214         bool *newDescriptorSetAllocated);
215 
216     angle::Result allocateDescriptorSet(ContextVk *contextVk,
217                                         DescriptorSetIndex descriptorSetIndex);
218     angle::Result allocateDescriptorSetAndGetInfo(ContextVk *contextVk,
219                                                   DescriptorSetIndex descriptorSetIndex,
220                                                   bool *newPoolAllocatedOut);
221     void addInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> &blocks,
222                                             const gl::ShaderType shaderType,
223                                             VkDescriptorType descType,
224                                             vk::DescriptorSetLayoutDesc *descOut);
225     void addAtomicCounterBufferDescriptorSetDesc(
226         const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
227         const gl::ShaderType shaderType,
228         vk::DescriptorSetLayoutDesc *descOut);
229     void addImageDescriptorSetDesc(const gl::ProgramExecutable &executable,
230                                    vk::DescriptorSetLayoutDesc *descOut);
231     void addInputAttachmentDescriptorSetDesc(const gl::ProgramExecutable &executable,
232                                              const gl::ShaderType shaderType,
233                                              vk::DescriptorSetLayoutDesc *descOut);
234     void addTextureDescriptorSetDesc(ContextVk *contextVk,
235                                      const gl::ProgramState &programState,
236                                      const gl::ActiveTextureArray<vk::TextureUnit> *activeTextures,
237                                      vk::DescriptorSetLayoutDesc *descOut);
238 
239     void resolvePrecisionMismatch(const gl::ProgramMergedVaryings &mergedVaryings);
240     void updateDefaultUniformsDescriptorSet(const gl::ShaderType shaderType,
241                                             const DefaultUniformBlock &defaultUniformBlock,
242                                             vk::BufferHelper *defaultUniformBuffer,
243                                             ContextVk *contextVk);
244     void updateTransformFeedbackDescriptorSetImpl(const gl::ProgramState &programState,
245                                                   ContextVk *contextVk);
246     angle::Result getOrAllocateShaderResourcesDescriptorSet(
247         ContextVk *contextVk,
248         const vk::ShaderBuffersDescriptorDesc *shaderBuffersDesc,
249         VkDescriptorSet *descriptorSetOut);
250     angle::Result updateBuffersDescriptorSet(
251         ContextVk *contextVk,
252         const gl::ShaderType shaderType,
253         const vk::ShaderBuffersDescriptorDesc &shaderBuffersDesc,
254         const std::vector<gl::InterfaceBlock> &blocks,
255         VkDescriptorType descriptorType,
256         bool cacheHit);
257     angle::Result updateAtomicCounterBuffersDescriptorSet(
258         ContextVk *contextVk,
259         const gl::ProgramState &programState,
260         const gl::ShaderType shaderType,
261         const vk::ShaderBuffersDescriptorDesc &shaderBuffersDesc,
262         bool cacheHit);
263     angle::Result updateImagesDescriptorSet(ContextVk *contextVk,
264                                             const gl::ProgramExecutable &executable,
265                                             const gl::ShaderType shaderType);
266     angle::Result initDynamicDescriptorPools(ContextVk *contextVk,
267                                              vk::DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
268                                              DescriptorSetIndex descriptorSetIndex,
269                                              VkDescriptorSetLayout descriptorSetLayout);
270 
271     void outputCumulativePerfCounters();
272 
273     // Descriptor sets for uniform blocks and textures for this program.
274     vk::DescriptorSetArray<VkDescriptorSet> mDescriptorSets;
275     vk::DescriptorSetArray<VkDescriptorSet> mEmptyDescriptorSets;
276     uint32_t mNumDefaultUniformDescriptors;
277     vk::BufferSerial mCurrentDefaultUniformBufferSerial;
278 
279     DescriptorSetCache<vk::UniformsAndXfbDescriptorDesc, VulkanCacheType::UniformsAndXfbDescriptors>
280         mUniformsAndXfbDescriptorsCache;
281     DescriptorSetCache<vk::TextureDescriptorDesc, VulkanCacheType::TextureDescriptors>
282         mTextureDescriptorsCache;
283     DescriptorSetCache<vk::ShaderBuffersDescriptorDesc, VulkanCacheType::ShaderBuffersDescriptors>
284         mShaderBufferDescriptorsCache;
285 
286     // We keep a reference to the pipeline and descriptor set layouts. This ensures they don't get
287     // deleted while this program is in use.
288     uint32_t mImmutableSamplersMaxDescriptorCount;
289     FormatIndexMap<uint64_t> mExternalFormatIndexMap;
290     FormatIndexMap<VkFormat> mVkFormatIndexMap;
291     vk::BindingPointer<vk::PipelineLayout> mPipelineLayout;
292     vk::DescriptorSetLayoutPointerArray mDescriptorSetLayouts;
293 
294     // Keep bindings to the descriptor pools. This ensures the pools stay valid while the Program
295     // is in use.
296     vk::DescriptorSetArray<vk::RefCountedDescriptorPoolBinding> mDescriptorPoolBindings;
297 
298     // Store descriptor pools here. We store the descriptors in the Program to facilitate descriptor
299     // cache management. It can also allow fewer descriptors for shaders which use fewer
300     // textures/buffers.
301     vk::DescriptorSetArray<vk::DynamicDescriptorPool> mDynamicDescriptorPools;
302 
303     // A set of dynamic offsets used with vkCmdBindDescriptorSets for the default uniform buffers.
304     VkDescriptorType mUniformBufferDescriptorType;
305     gl::ShaderVector<uint32_t> mDynamicUniformDescriptorOffsets;
306     std::vector<uint32_t> mDynamicShaderBufferDescriptorOffsets;
307 
308     // TODO: http://anglebug.com/4524: Need a different hash key than a string,
309     // since that's slow to calculate.
310     ShaderInterfaceVariableInfoMap mVariableInfoMap;
311 
312     // We store all permutations of surface rotation and transformed SPIR-V programs here. We may
313     // need some LRU algorithm to free least used programs to reduce the number of programs.
314     ProgramInfo mGraphicsProgramInfos[ProgramTransformOptions::kPermutationCount];
315     ProgramInfo mComputeProgramInfo;
316 
317     ProgramTransformOptions mTransformOptions;
318 
319     ProgramVk *mProgram;
320     ProgramPipelineVk *mProgramPipeline;
321 
322     ProgramExecutablePerfCounters mPerfCounters;
323     ProgramExecutablePerfCounters mCumulativePerfCounters;
324 };
325 
326 }  // namespace rx
327 
328 #endif  // LIBANGLE_RENDERER_VULKAN_PROGRAMEXECUTABLEVK_H_
329