• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 // ProgramVk.h:
7 //    Defines the class interface for ProgramVk, implementing ProgramImpl.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_VULKAN_PROGRAMVK_H_
11 #define LIBANGLE_RENDERER_VULKAN_PROGRAMVK_H_
12 
13 #include <array>
14 
15 #include "common/utilities.h"
16 #include "libANGLE/renderer/ProgramImpl.h"
17 #include "libANGLE/renderer/vulkan/ContextVk.h"
18 #include "libANGLE/renderer/vulkan/RendererVk.h"
19 #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
20 #include "libANGLE/renderer/vulkan/vk_helpers.h"
21 
22 namespace rx
23 {
UseLineRaster(const ContextVk * contextVk,gl::PrimitiveMode mode)24 ANGLE_INLINE bool UseLineRaster(const ContextVk *contextVk, gl::PrimitiveMode mode)
25 {
26     return contextVk->getFeatures().basicGLLineRasterization.enabled && gl::IsLineMode(mode);
27 }
28 
29 class ProgramVk : public ProgramImpl
30 {
31   public:
32     ProgramVk(const gl::ProgramState &state);
33     ~ProgramVk() override;
34     void destroy(const gl::Context *context) override;
35 
36     std::unique_ptr<LinkEvent> load(const gl::Context *context,
37                                     gl::BinaryInputStream *stream,
38                                     gl::InfoLog &infoLog) override;
39     void save(const gl::Context *context, gl::BinaryOutputStream *stream) override;
40     void setBinaryRetrievableHint(bool retrievable) override;
41     void setSeparable(bool separable) override;
42 
43     std::unique_ptr<LinkEvent> link(const gl::Context *context,
44                                     const gl::ProgramLinkedResources &resources,
45                                     gl::InfoLog &infoLog) override;
46     GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
47 
48     void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
49     void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) override;
50     void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) override;
51     void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) override;
52     void setUniform1iv(GLint location, GLsizei count, const GLint *v) override;
53     void setUniform2iv(GLint location, GLsizei count, const GLint *v) override;
54     void setUniform3iv(GLint location, GLsizei count, const GLint *v) override;
55     void setUniform4iv(GLint location, GLsizei count, const GLint *v) override;
56     void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) override;
57     void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) override;
58     void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) override;
59     void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) override;
60     void setUniformMatrix2fv(GLint location,
61                              GLsizei count,
62                              GLboolean transpose,
63                              const GLfloat *value) override;
64     void setUniformMatrix3fv(GLint location,
65                              GLsizei count,
66                              GLboolean transpose,
67                              const GLfloat *value) override;
68     void setUniformMatrix4fv(GLint location,
69                              GLsizei count,
70                              GLboolean transpose,
71                              const GLfloat *value) override;
72     void setUniformMatrix2x3fv(GLint location,
73                                GLsizei count,
74                                GLboolean transpose,
75                                const GLfloat *value) override;
76     void setUniformMatrix3x2fv(GLint location,
77                                GLsizei count,
78                                GLboolean transpose,
79                                const GLfloat *value) override;
80     void setUniformMatrix2x4fv(GLint location,
81                                GLsizei count,
82                                GLboolean transpose,
83                                const GLfloat *value) override;
84     void setUniformMatrix4x2fv(GLint location,
85                                GLsizei count,
86                                GLboolean transpose,
87                                const GLfloat *value) override;
88     void setUniformMatrix3x4fv(GLint location,
89                                GLsizei count,
90                                GLboolean transpose,
91                                const GLfloat *value) override;
92     void setUniformMatrix4x3fv(GLint location,
93                                GLsizei count,
94                                GLboolean transpose,
95                                const GLfloat *value) override;
96 
97     void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override;
98     void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
99     void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
100 
101     void setPathFragmentInputGen(const std::string &inputName,
102                                  GLenum genMode,
103                                  GLint components,
104                                  const GLfloat *coeffs) override;
105 
106     // Also initializes the pipeline layout, descriptor set layouts, and used descriptor ranges.
107 
108     angle::Result updateUniforms(ContextVk *contextVk);
109     angle::Result updateTexturesDescriptorSet(ContextVk *contextVk);
110     angle::Result updateShaderResourcesDescriptorSet(ContextVk *contextVk,
111                                                      vk::CommandGraphResource *recorder);
112     angle::Result updateTransformFeedbackDescriptorSet(ContextVk *contextVk,
113                                                        vk::FramebufferHelper *framebuffer);
114 
115     angle::Result updateDescriptorSets(ContextVk *contextVk, vk::CommandBuffer *commandBuffer);
116 
117     // For testing only.
118     void setDefaultUniformBlocksMinSizeForTesting(size_t minSize);
119 
getPipelineLayout()120     const vk::PipelineLayout &getPipelineLayout() const { return mPipelineLayout.get(); }
121 
hasTextures()122     bool hasTextures() const { return !mState.getSamplerBindings().empty(); }
hasUniformBuffers()123     bool hasUniformBuffers() const { return !mState.getUniformBlocks().empty(); }
hasStorageBuffers()124     bool hasStorageBuffers() const { return !mState.getShaderStorageBlocks().empty(); }
hasAtomicCounterBuffers()125     bool hasAtomicCounterBuffers() const { return !mState.getAtomicCounterBuffers().empty(); }
hasTransformFeedbackOutput()126     bool hasTransformFeedbackOutput() const
127     {
128         return !mState.getLinkedTransformFeedbackVaryings().empty();
129     }
130 
dirtyUniforms()131     bool dirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); }
132 
getGraphicsPipeline(ContextVk * contextVk,gl::PrimitiveMode mode,const vk::GraphicsPipelineDesc & desc,const gl::AttributesMask & activeAttribLocations,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)133     angle::Result getGraphicsPipeline(ContextVk *contextVk,
134                                       gl::PrimitiveMode mode,
135                                       const vk::GraphicsPipelineDesc &desc,
136                                       const gl::AttributesMask &activeAttribLocations,
137                                       const vk::GraphicsPipelineDesc **descPtrOut,
138                                       vk::PipelineHelper **pipelineOut)
139     {
140         vk::ShaderProgramHelper *shaderProgram;
141         ANGLE_TRY(initGraphicsShaders(contextVk, mode, &shaderProgram));
142         ASSERT(shaderProgram->isGraphicsProgram());
143         RendererVk *renderer = contextVk->getRenderer();
144         vk::PipelineCache *pipelineCache = nullptr;
145         ANGLE_TRY(renderer->getPipelineCache(&pipelineCache));
146         return shaderProgram->getGraphicsPipeline(
147             contextVk, &contextVk->getRenderPassCache(), *pipelineCache,
148             contextVk->getCurrentQueueSerial(), mPipelineLayout.get(), desc, activeAttribLocations,
149             mState.getAttributesTypeMask(), descPtrOut, pipelineOut);
150     }
151 
getComputePipeline(ContextVk * contextVk,vk::PipelineAndSerial ** pipelineOut)152     angle::Result getComputePipeline(ContextVk *contextVk, vk::PipelineAndSerial **pipelineOut)
153     {
154         vk::ShaderProgramHelper *shaderProgram;
155         ANGLE_TRY(initComputeShader(contextVk, &shaderProgram));
156         ASSERT(!shaderProgram->isGraphicsProgram());
157         return shaderProgram->getComputePipeline(contextVk, mPipelineLayout.get(), pipelineOut);
158     }
159 
160     // Used in testing only.
getDynamicDescriptorPool(uint32_t poolIndex)161     vk::DynamicDescriptorPool *getDynamicDescriptorPool(uint32_t poolIndex)
162     {
163         return &mDynamicDescriptorPools[poolIndex];
164     }
165 
166   private:
167     template <int cols, int rows>
168     void setUniformMatrixfv(GLint location,
169                             GLsizei count,
170                             GLboolean transpose,
171                             const GLfloat *value);
172 
173     void reset(ContextVk *contextVk);
174     angle::Result allocateDescriptorSet(ContextVk *contextVk, uint32_t descriptorSetIndex);
175     angle::Result allocateDescriptorSetAndGetInfo(ContextVk *contextVk,
176                                                   uint32_t descriptorSetIndex,
177                                                   bool *newPoolAllocatedOut);
178     angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
179     void generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap,
180                                       gl::ShaderMap<size_t> &requiredBufferSize);
181     void initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap);
182     angle::Result resizeUniformBlockMemory(ContextVk *contextVk,
183                                            gl::ShaderMap<size_t> &requiredBufferSize);
184 
185     void updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
186     void updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk);
187     void updateBuffersDescriptorSet(ContextVk *contextVk,
188                                     vk::CommandGraphResource *recorder,
189                                     const std::vector<gl::InterfaceBlock> &blocks,
190                                     VkDescriptorType descriptorType);
191     void updateAtomicCounterBuffersDescriptorSet(ContextVk *contextVk,
192                                                  vk::CommandGraphResource *recorder);
193 
194     template <class T>
195     void getUniformImpl(GLint location, T *v, GLenum entryPointType) const;
196 
197     template <typename T>
198     void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType);
199     angle::Result linkImpl(const gl::Context *glContext, gl::InfoLog &infoLog);
200     void linkResources(const gl::ProgramLinkedResources &resources);
201 
202     void updateBindingOffsets();
getUniformBlockBindingsOffset()203     uint32_t getUniformBlockBindingsOffset() const { return 0; }
getStorageBlockBindingsOffset()204     uint32_t getStorageBlockBindingsOffset() const { return mStorageBlockBindingsOffset; }
getAtomicCounterBufferBindingsOffset()205     uint32_t getAtomicCounterBufferBindingsOffset() const
206     {
207         return mAtomicCounterBufferBindingsOffset;
208     }
209 
210     class ShaderInfo;
initShaders(ContextVk * contextVk,bool enableLineRasterEmulation,ShaderInfo * shaderInfo,vk::ShaderProgramHelper ** shaderProgramOut)211     ANGLE_INLINE angle::Result initShaders(ContextVk *contextVk,
212                                            bool enableLineRasterEmulation,
213                                            ShaderInfo *shaderInfo,
214                                            vk::ShaderProgramHelper **shaderProgramOut)
215     {
216         if (!shaderInfo->valid())
217         {
218             ANGLE_TRY(
219                 shaderInfo->initShaders(contextVk, mShaderSources, enableLineRasterEmulation));
220         }
221 
222         ASSERT(shaderInfo->valid());
223         *shaderProgramOut = &shaderInfo->getShaderProgram();
224 
225         return angle::Result::Continue;
226     }
227 
initGraphicsShaders(ContextVk * contextVk,gl::PrimitiveMode mode,vk::ShaderProgramHelper ** shaderProgramOut)228     ANGLE_INLINE angle::Result initGraphicsShaders(ContextVk *contextVk,
229                                                    gl::PrimitiveMode mode,
230                                                    vk::ShaderProgramHelper **shaderProgramOut)
231     {
232         bool enableLineRasterEmulation = UseLineRaster(contextVk, mode);
233 
234         ShaderInfo &shaderInfo =
235             enableLineRasterEmulation ? mLineRasterShaderInfo : mDefaultShaderInfo;
236 
237         return initShaders(contextVk, enableLineRasterEmulation, &shaderInfo, shaderProgramOut);
238     }
239 
initComputeShader(ContextVk * contextVk,vk::ShaderProgramHelper ** shaderProgramOut)240     ANGLE_INLINE angle::Result initComputeShader(ContextVk *contextVk,
241                                                  vk::ShaderProgramHelper **shaderProgramOut)
242     {
243         return initShaders(contextVk, false, &mDefaultShaderInfo, shaderProgramOut);
244     }
245 
246     // Save and load implementation for GLES Program Binary support.
247     angle::Result loadShaderSource(ContextVk *contextVk, gl::BinaryInputStream *stream);
248     void saveShaderSource(gl::BinaryOutputStream *stream);
249 
250     // State for the default uniform blocks.
251     struct DefaultUniformBlock final : private angle::NonCopyable
252     {
253         DefaultUniformBlock();
254         ~DefaultUniformBlock();
255 
256         vk::DynamicBuffer storage;
257 
258         // Shadow copies of the shader uniform data.
259         angle::MemoryBuffer uniformData;
260 
261         // Since the default blocks are laid out in std140, this tells us where to write on a call
262         // to a setUniform method. They are arranged in uniform location order.
263         std::vector<sh::BlockMemberInfo> uniformLayout;
264     };
265 
266     gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks;
267     gl::ShaderBitSet mDefaultUniformBlocksDirty;
268 
269     gl::ShaderVector<uint32_t> mDynamicBufferOffsets;
270 
271     // This is a special "empty" placeholder buffer for when a shader has no uniforms or doesn't
272     // use all slots in the atomic counter buffer array.
273     //
274     // It is necessary because we want to keep a compatible pipeline layout in all cases,
275     // and Vulkan does not tolerate having null handles in a descriptor set.
276     vk::BufferHelper mEmptyBuffer;
277 
278     // Descriptor sets for uniform blocks and textures for this program.
279     std::vector<VkDescriptorSet> mDescriptorSets;
280     vk::DescriptorSetLayoutArray<VkDescriptorSet> mEmptyDescriptorSets;
281 
282     std::unordered_map<vk::TextureDescriptorDesc, VkDescriptorSet> mTextureDescriptorsCache;
283 
284     // We keep a reference to the pipeline and descriptor set layouts. This ensures they don't get
285     // deleted while this program is in use.
286     vk::BindingPointer<vk::PipelineLayout> mPipelineLayout;
287     vk::DescriptorSetLayoutPointerArray mDescriptorSetLayouts;
288 
289     // Keep bindings to the descriptor pools. This ensures the pools stay valid while the Program
290     // is in use.
291     vk::DescriptorSetLayoutArray<vk::RefCountedDescriptorPoolBinding> mDescriptorPoolBindings;
292 
293     class ShaderInfo final : angle::NonCopyable
294     {
295       public:
296         ShaderInfo();
297         ~ShaderInfo();
298 
299         angle::Result initShaders(ContextVk *contextVk,
300                                   const gl::ShaderMap<std::string> &shaderSources,
301                                   bool enableLineRasterEmulation);
302         void release(ContextVk *contextVk);
303 
valid()304         ANGLE_INLINE bool valid() const
305         {
306             return mShaders[gl::ShaderType::Vertex].get().valid() ||
307                    mShaders[gl::ShaderType::Compute].get().valid();
308         }
309 
getShaderProgram()310         vk::ShaderProgramHelper &getShaderProgram() { return mProgramHelper; }
311 
312       private:
313         vk::ShaderProgramHelper mProgramHelper;
314         gl::ShaderMap<vk::RefCounted<vk::ShaderAndSerial>> mShaders;
315     };
316 
317     ShaderInfo mDefaultShaderInfo;
318     ShaderInfo mLineRasterShaderInfo;
319 
320     // We keep the translated linked shader sources to use with shader draw call patching.
321     gl::ShaderMap<std::string> mShaderSources;
322 
323     // In their descriptor set, uniform buffers are placed first, then storage buffers, then atomic
324     // counter buffers.  These cached values contain the offsets where storage buffer and atomic
325     // counter buffer bindings start.
326     uint32_t mStorageBlockBindingsOffset;
327     uint32_t mAtomicCounterBufferBindingsOffset;
328 
329     // Store descriptor pools here. We store the descriptors in the Program to facilitate descriptor
330     // cache management. It can also allow fewer descriptors for shaders which use fewer
331     // textures/buffers.
332     vk::DescriptorSetLayoutArray<vk::DynamicDescriptorPool> mDynamicDescriptorPools;
333 };
334 
335 }  // namespace rx
336 
337 #endif  // LIBANGLE_RENDERER_VULKAN_PROGRAMVK_H_
338