• 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 removeTransformFeedbackEmulation : 1;
57     uint8_t reserved : 1;  // must initialize to zero
58     static constexpr uint32_t kPermutationCount = 0x1 << 7;
59 };
60 static_assert(sizeof(ProgramTransformOptions) == 1, "Size check failed");
61 static_assert(static_cast<int>(SurfaceRotation::EnumCount) <= 8, "Size check failed");
62 
63 class ProgramInfo final : angle::NonCopyable
64 {
65   public:
66     ProgramInfo();
67     ~ProgramInfo();
68 
69     angle::Result initProgram(ContextVk *contextVk,
70                               const gl::ShaderType shaderType,
71                               bool isLastPreFragmentStage,
72                               bool isTransformFeedbackProgram,
73                               const ShaderInfo &shaderInfo,
74                               ProgramTransformOptions optionBits,
75                               const ShaderInterfaceVariableInfoMap &variableInfoMap);
76     void release(ContextVk *contextVk);
77 
valid(const gl::ShaderType shaderType)78     ANGLE_INLINE bool valid(const gl::ShaderType shaderType) const
79     {
80         return mProgramHelper.valid(shaderType);
81     }
82 
getShaderProgram()83     vk::ShaderProgramHelper *getShaderProgram() { return &mProgramHelper; }
84 
85   private:
86     vk::ShaderProgramHelper mProgramHelper;
87     gl::ShaderMap<vk::RefCounted<vk::ShaderAndSerial>> mShaders;
88 };
89 
90 // State for the default uniform blocks.
91 struct DefaultUniformBlock final : private angle::NonCopyable
92 {
93     DefaultUniformBlock();
94     ~DefaultUniformBlock();
95 
96     // Shadow copies of the shader uniform data.
97     angle::MemoryBuffer uniformData;
98 
99     // Since the default blocks are laid out in std140, this tells us where to write on a call
100     // to a setUniform method. They are arranged in uniform location order.
101     std::vector<sh::BlockMemberInfo> uniformLayout;
102 };
103 
104 // Performance and resource counters.
105 using DescriptorSetCountList   = angle::PackedEnumMap<DescriptorSetIndex, uint32_t>;
106 using ImmutableSamplerIndexMap = angle::HashMap<vk::YcbcrConversionDesc, 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 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(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,
178                                        vk::CommandBuffer *commandBuffer,
179                                        PipelineType pipelineType);
180 
181     void updateEarlyFragmentTestsOptimization(ContextVk *contextVk);
182 
setProgram(ProgramVk * program)183     void setProgram(ProgramVk *program)
184     {
185         ASSERT(!mProgram && !mProgramPipeline);
186         mProgram = program;
187     }
setProgramPipeline(ProgramPipelineVk * pipeline)188     void setProgramPipeline(ProgramPipelineVk *pipeline)
189     {
190         ASSERT(!mProgram && !mProgramPipeline);
191         mProgramPipeline = pipeline;
192     }
193 
usesDynamicUniformBufferDescriptors()194     bool usesDynamicUniformBufferDescriptors() const
195     {
196         return mUniformBufferDescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
197     }
198 
areImmutableSamplersCompatible(const ImmutableSamplerIndexMap & immutableSamplerIndexMap)199     bool areImmutableSamplersCompatible(
200         const ImmutableSamplerIndexMap &immutableSamplerIndexMap) const
201     {
202         return (mImmutableSamplerIndexMap == immutableSamplerIndexMap);
203     }
204 
205     void accumulateCacheStats(VulkanCacheType cacheType, const CacheStats &cacheStats);
206     ProgramExecutablePerfCounters getAndResetObjectPerfCounters();
207 
208   private:
209     friend class ProgramVk;
210     friend class ProgramPipelineVk;
211 
212     angle::Result allocUniformAndXfbDescriptorSet(
213         ContextVk *contextVk,
214         const vk::UniformsAndXfbDescriptorDesc &xfbBufferDesc,
215         bool *newDescriptorSetAllocated);
216 
217     angle::Result allocateDescriptorSet(ContextVk *contextVk,
218                                         DescriptorSetIndex descriptorSetIndex);
219     angle::Result allocateDescriptorSetAndGetInfo(ContextVk *contextVk,
220                                                   DescriptorSetIndex descriptorSetIndex,
221                                                   bool *newPoolAllocatedOut);
222     void addInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> &blocks,
223                                             const gl::ShaderType shaderType,
224                                             VkDescriptorType descType,
225                                             vk::DescriptorSetLayoutDesc *descOut);
226     void addAtomicCounterBufferDescriptorSetDesc(
227         const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
228         const gl::ShaderType shaderType,
229         vk::DescriptorSetLayoutDesc *descOut);
230     void addImageDescriptorSetDesc(const gl::ProgramExecutable &executable,
231                                    vk::DescriptorSetLayoutDesc *descOut);
232     void addInputAttachmentDescriptorSetDesc(const gl::ProgramExecutable &executable,
233                                              const gl::ShaderType shaderType,
234                                              vk::DescriptorSetLayoutDesc *descOut);
235     void addTextureDescriptorSetDesc(ContextVk *contextVk,
236                                      const gl::ProgramState &programState,
237                                      const gl::ActiveTextureArray<vk::TextureUnit> *activeTextures,
238                                      vk::DescriptorSetLayoutDesc *descOut);
239 
240     void resolvePrecisionMismatch(const gl::ProgramMergedVaryings &mergedVaryings);
241     void updateDefaultUniformsDescriptorSet(const gl::ShaderType shaderType,
242                                             const DefaultUniformBlock &defaultUniformBlock,
243                                             vk::BufferHelper *defaultUniformBuffer,
244                                             ContextVk *contextVk);
245     void updateTransformFeedbackDescriptorSetImpl(const gl::ProgramState &programState,
246                                                   ContextVk *contextVk);
247     angle::Result getOrAllocateShaderResourcesDescriptorSet(
248         ContextVk *contextVk,
249         const vk::ShaderBuffersDescriptorDesc *shaderBuffersDesc,
250         VkDescriptorSet *descriptorSetOut);
251     angle::Result updateBuffersDescriptorSet(
252         ContextVk *contextVk,
253         const gl::ShaderType shaderType,
254         const vk::ShaderBuffersDescriptorDesc &shaderBuffersDesc,
255         const std::vector<gl::InterfaceBlock> &blocks,
256         VkDescriptorType descriptorType,
257         bool cacheHit);
258     angle::Result updateAtomicCounterBuffersDescriptorSet(
259         ContextVk *contextVk,
260         const gl::ProgramState &programState,
261         const gl::ShaderType shaderType,
262         const vk::ShaderBuffersDescriptorDesc &shaderBuffersDesc,
263         bool cacheHit);
264     angle::Result updateImagesDescriptorSet(ContextVk *contextVk,
265                                             const gl::ProgramExecutable &executable,
266                                             const gl::ShaderType shaderType);
267     angle::Result initDynamicDescriptorPools(ContextVk *contextVk,
268                                              vk::DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
269                                              DescriptorSetIndex descriptorSetIndex,
270                                              VkDescriptorSetLayout descriptorSetLayout);
271 
272     void outputCumulativePerfCounters();
273 
274     // Descriptor sets for uniform blocks and textures for this program.
275     vk::DescriptorSetArray<VkDescriptorSet> mDescriptorSets;
276     vk::DescriptorSetArray<VkDescriptorSet> mEmptyDescriptorSets;
277     uint32_t mNumDefaultUniformDescriptors;
278     vk::BufferSerial mCurrentDefaultUniformBufferSerial;
279 
280     DescriptorSetCache<vk::UniformsAndXfbDescriptorDesc, VulkanCacheType::UniformsAndXfbDescriptors>
281         mUniformsAndXfbDescriptorsCache;
282     DescriptorSetCache<vk::TextureDescriptorDesc, VulkanCacheType::TextureDescriptors>
283         mTextureDescriptorsCache;
284     DescriptorSetCache<vk::ShaderBuffersDescriptorDesc, VulkanCacheType::ShaderBuffersDescriptors>
285         mShaderBufferDescriptorsCache;
286 
287     // We keep a reference to the pipeline and descriptor set layouts. This ensures they don't get
288     // deleted while this program is in use.
289     uint32_t mImmutableSamplersMaxDescriptorCount;
290     ImmutableSamplerIndexMap mImmutableSamplerIndexMap;
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