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