1 //
2 // Copyright 2017 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 // ProgramLinkedResources.h: implements link-time checks for default block uniforms, and generates
8 // uniform locations. Populates data structures related to uniforms so that they can be stored in
9 // program state.
10 
11 #ifndef LIBANGLE_UNIFORMLINKER_H_
12 #define LIBANGLE_UNIFORMLINKER_H_
13 
14 #include "angle_gl.h"
15 #include "common/PackedEnums.h"
16 #include "common/angleutils.h"
17 #include "libANGLE/VaryingPacking.h"
18 
19 #include <functional>
20 
21 namespace sh
22 {
23 class BlockLayoutEncoder;
24 struct BlockMemberInfo;
25 struct InterfaceBlock;
26 struct ShaderVariable;
27 class BlockEncoderVisitor;
28 class ShaderVariableVisitor;
29 struct ShaderVariable;
30 }  // namespace sh
31 
32 namespace gl
33 {
34 struct BufferVariable;
35 struct Caps;
36 class Context;
37 class InfoLog;
38 struct InterfaceBlock;
39 enum class LinkMismatchError;
40 struct LinkedUniform;
41 class ProgramState;
42 class ProgramBindings;
43 class ProgramAliasedBindings;
44 class Shader;
45 struct ShaderVariableBuffer;
46 struct UnusedUniform;
47 struct VariableLocation;
48 
49 using AtomicCounterBuffer = ShaderVariableBuffer;
50 
51 class UniformLinker final : angle::NonCopyable
52 {
53   public:
54     UniformLinker(const ProgramState &state);
55     ~UniformLinker();
56 
57     bool link(const Caps &caps,
58               InfoLog &infoLog,
59               const ProgramAliasedBindings &uniformLocationBindings);
60 
61     void getResults(std::vector<LinkedUniform> *uniforms,
62                     std::vector<UnusedUniform> *unusedUniforms,
63                     std::vector<VariableLocation> *uniformLocations);
64 
65   private:
66     bool validateGraphicsUniforms(InfoLog &infoLog) const;
67 
68     bool flattenUniformsAndCheckCapsForShader(Shader *shader,
69                                               const Caps &caps,
70                                               std::vector<LinkedUniform> &samplerUniforms,
71                                               std::vector<LinkedUniform> &imageUniforms,
72                                               std::vector<LinkedUniform> &atomicCounterUniforms,
73                                               std::vector<LinkedUniform> &inputAttachmentUniforms,
74                                               std::vector<UnusedUniform> &unusedUniforms,
75                                               InfoLog &infoLog);
76 
77     bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog);
78     bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog);
79 
80     bool indexUniforms(InfoLog &infoLog, const ProgramAliasedBindings &uniformLocationBindings);
81     bool gatherUniformLocationsAndCheckConflicts(
82         InfoLog &infoLog,
83         const ProgramAliasedBindings &uniformLocationBindings,
84         std::set<GLuint> *ignoredLocations,
85         int *maxUniformLocation);
86     void pruneUnusedUniforms();
87 
88     const ProgramState &mState;
89     std::vector<LinkedUniform> mUniforms;
90     std::vector<UnusedUniform> mUnusedUniforms;
91     std::vector<VariableLocation> mUniformLocations;
92 };
93 
94 using GetBlockSizeFunc = std::function<
95     bool(const std::string &blockName, const std::string &blockMappedName, size_t *sizeOut)>;
96 using GetBlockMemberInfoFunc = std::function<
97     bool(const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut)>;
98 
99 // This class is intended to be used during the link step to store interface block information.
100 // It is called by the Impl class during ProgramImpl::link so that it has access to the
101 // real block size and layout.
102 class InterfaceBlockLinker : angle::NonCopyable
103 {
104   public:
105     virtual ~InterfaceBlockLinker();
106 
107     // This is called once per shader stage. It stores a pointer to the block vector, so it's
108     // important that this class does not persist longer than the duration of Program::link.
109     void addShaderBlocks(ShaderType shader, const std::vector<sh::InterfaceBlock> *blocks);
110 
111     // This is called once during a link operation, after all shader blocks are added.
112     void linkBlocks(const GetBlockSizeFunc &getBlockSize,
113                     const GetBlockMemberInfoFunc &getMemberInfo) const;
114 
115   protected:
116     InterfaceBlockLinker();
117     void init(std::vector<InterfaceBlock> *blocksOut,
118               std::vector<std::string> *unusedInterfaceBlocksOut);
119     void defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
120                               const GetBlockMemberInfoFunc &getMemberInfo,
121                               const sh::InterfaceBlock &interfaceBlock,
122                               ShaderType shaderType) const;
123 
124     virtual size_t getCurrentBlockMemberIndex() const = 0;
125 
126     virtual sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
127                                                   const std::string &namePrefix,
128                                                   const std::string &mappedNamePrefix,
129                                                   ShaderType shaderType,
130                                                   int blockIndex) const = 0;
131 
132     ShaderMap<const std::vector<sh::InterfaceBlock> *> mShaderBlocks = {};
133 
134     std::vector<InterfaceBlock> *mBlocksOut             = nullptr;
135     std::vector<std::string> *mUnusedInterfaceBlocksOut = nullptr;
136 };
137 
138 class UniformBlockLinker final : public InterfaceBlockLinker
139 {
140   public:
141     UniformBlockLinker();
142     ~UniformBlockLinker() override;
143 
144     void init(std::vector<InterfaceBlock> *blocksOut,
145               std::vector<LinkedUniform> *uniformsOut,
146               std::vector<std::string> *unusedInterfaceBlocksOut);
147 
148   private:
149     size_t getCurrentBlockMemberIndex() const override;
150 
151     sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
152                                           const std::string &namePrefix,
153                                           const std::string &mappedNamePrefix,
154                                           ShaderType shaderType,
155                                           int blockIndex) const override;
156 
157     std::vector<LinkedUniform> *mUniformsOut = nullptr;
158 };
159 
160 class ShaderStorageBlockLinker final : public InterfaceBlockLinker
161 {
162   public:
163     ShaderStorageBlockLinker();
164     ~ShaderStorageBlockLinker() override;
165 
166     void init(std::vector<InterfaceBlock> *blocksOut,
167               std::vector<BufferVariable> *bufferVariablesOut,
168               std::vector<std::string> *unusedInterfaceBlocksOut);
169 
170   private:
171     size_t getCurrentBlockMemberIndex() const override;
172 
173     sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
174                                           const std::string &namePrefix,
175                                           const std::string &mappedNamePrefix,
176                                           ShaderType shaderType,
177                                           int blockIndex) const override;
178 
179     std::vector<BufferVariable> *mBufferVariablesOut = nullptr;
180 };
181 
182 class AtomicCounterBufferLinker final : angle::NonCopyable
183 {
184   public:
185     AtomicCounterBufferLinker();
186     ~AtomicCounterBufferLinker();
187 
188     void init(std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut);
189     void link(const std::map<int, unsigned int> &sizeMap) const;
190 
191   private:
192     std::vector<AtomicCounterBuffer> *mAtomicCounterBuffersOut = nullptr;
193 };
194 
195 // The link operation is responsible for finishing the link of uniform and interface blocks.
196 // This way it can filter out unreferenced resources and still have access to the info.
197 // TODO(jmadill): Integrate uniform linking/filtering as well as interface blocks.
198 struct UnusedUniform
199 {
UnusedUniformUnusedUniform200     UnusedUniform(std::string name,
201                   bool isSampler,
202                   bool isImage,
203                   bool isAtomicCounter,
204                   bool isFragmentInOut)
205     {
206         this->name            = name;
207         this->isSampler       = isSampler;
208         this->isImage         = isImage;
209         this->isAtomicCounter = isAtomicCounter;
210         this->isFragmentInOut = isFragmentInOut;
211     }
212 
213     std::string name;
214     bool isSampler;
215     bool isImage;
216     bool isAtomicCounter;
217     bool isFragmentInOut;
218 };
219 
220 struct ProgramLinkedResources
221 {
222     ProgramLinkedResources();
223     ~ProgramLinkedResources();
224 
225     void init(std::vector<InterfaceBlock> *uniformBlocksOut,
226               std::vector<LinkedUniform> *uniformsOut,
227               std::vector<InterfaceBlock> *shaderStorageBlocksOut,
228               std::vector<BufferVariable> *bufferVariablesOut,
229               std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut);
230 
231     ProgramVaryingPacking varyingPacking;
232     UniformBlockLinker uniformBlockLinker;
233     ShaderStorageBlockLinker shaderStorageBlockLinker;
234     AtomicCounterBufferLinker atomicCounterBufferLinker;
235     std::vector<UnusedUniform> unusedUniforms;
236     std::vector<std::string> unusedInterfaceBlocks;
237 };
238 
239 class CustomBlockLayoutEncoderFactory : angle::NonCopyable
240 {
241   public:
~CustomBlockLayoutEncoderFactory()242     virtual ~CustomBlockLayoutEncoderFactory() {}
243 
244     virtual sh::BlockLayoutEncoder *makeEncoder() = 0;
245 };
246 
247 // Used by the backends in Program*::linkResources to parse interface blocks and provide
248 // information to ProgramLinkedResources' linkers.
249 class ProgramLinkedResourcesLinker final : angle::NonCopyable
250 {
251   public:
ProgramLinkedResourcesLinker(CustomBlockLayoutEncoderFactory * customEncoderFactory)252     ProgramLinkedResourcesLinker(CustomBlockLayoutEncoderFactory *customEncoderFactory)
253         : mCustomEncoderFactory(customEncoderFactory)
254     {}
255 
256     void linkResources(const ProgramState &programState,
257                        const ProgramLinkedResources &resources) const;
258 
259   private:
260     void getAtomicCounterBufferSizeMap(const ProgramState &programState,
261                                        std::map<int, unsigned int> &sizeMapOut) const;
262 
263     CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
264 };
265 
266 bool LinkValidateProgramGlobalNames(InfoLog &infoLog, const HasAttachedShaders &programOrPipeline);
267 bool LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> &outputVaryings,
268                                          const std::vector<sh::ShaderVariable> &inputVaryings,
269                                          ShaderType frontShaderType,
270                                          ShaderType backShaderType,
271                                          int frontShaderVersion,
272                                          int backShaderVersion,
273                                          bool isSeparable,
274                                          InfoLog &infoLog);
275 bool LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> &vertexVaryings,
276                                           const std::vector<sh::ShaderVariable> &fragmentVaryings,
277                                           int vertexShaderVersion,
278                                           InfoLog &infoLog);
279 bool LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &inputVaryings,
280                                  const std::vector<sh::ShaderVariable> &outputVaryings,
281                                  ShaderType inputShaderType,
282                                  ShaderType outputShaderType,
283                                  int inputShaderVersion,
284                                  int outputShaderVersion,
285                                  InfoLog &infoLog);
286 LinkMismatchError LinkValidateProgramVariables(const sh::ShaderVariable &variable1,
287                                                const sh::ShaderVariable &variable2,
288                                                bool validatePrecision,
289                                                bool treatVariable1AsNonArray,
290                                                bool treatVariable2AsNonArray,
291                                                std::string *mismatchedStructOrBlockMemberName);
292 void AddProgramVariableParentPrefix(const std::string &parentName,
293                                     std::string *mismatchedFieldName);
294 }  // namespace gl
295 
296 #endif  // LIBANGLE_UNIFORMLINKER_H_
297