1 //
2 // Copyright (c) 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 // UniformLinker.h: implements link-time checks for default block uniforms, and generates uniform
8 // locations. Populates data structures related to uniforms so that they can be stored in program
9 // state.
10 
11 #ifndef LIBANGLE_UNIFORMLINKER_H_
12 #define LIBANGLE_UNIFORMLINKER_H_
13 
14 #include "libANGLE/Program.h"
15 #include "libANGLE/Uniform.h"
16 #include "libANGLE/VaryingPacking.h"
17 
18 #include <functional>
19 
20 namespace gl
21 {
22 
23 class UniformLinker
24 {
25   public:
26     UniformLinker(const ProgramState &state);
27     ~UniformLinker();
28 
29     bool link(const Context *context,
30               InfoLog &infoLog,
31               const Program::Bindings &uniformLocationBindings);
32 
33     void getResults(std::vector<LinkedUniform> *uniforms,
34                     std::vector<VariableLocation> *uniformLocations);
35 
36   private:
37     struct ShaderUniformCount
38     {
ShaderUniformCountShaderUniformCount39         ShaderUniformCount() : vectorCount(0), samplerCount(0), imageCount(0), atomicCounterCount(0)
40         {
41         }
42         ShaderUniformCount(const ShaderUniformCount &other) = default;
43         ShaderUniformCount &operator=(const ShaderUniformCount &other) = default;
44 
45         ShaderUniformCount &operator+=(const ShaderUniformCount &other)
46         {
47             vectorCount += other.vectorCount;
48             samplerCount += other.samplerCount;
49             imageCount += other.imageCount;
50             atomicCounterCount += other.atomicCounterCount;
51             return *this;
52         }
53 
54         unsigned int vectorCount;
55         unsigned int samplerCount;
56         unsigned int imageCount;
57         unsigned int atomicCounterCount;
58     };
59 
60     bool validateVertexAndFragmentUniforms(const Context *context, InfoLog &infoLog) const;
61 
62     static bool linkValidateUniforms(InfoLog &infoLog,
63                                      const std::string &uniformName,
64                                      const sh::Uniform &vertexUniform,
65                                      const sh::Uniform &fragmentUniform);
66 
67     bool flattenUniformsAndCheckCapsForShader(const Context *context,
68                                               Shader *shader,
69                                               GLuint maxUniformComponents,
70                                               GLuint maxTextureImageUnits,
71                                               GLuint maxImageUnits,
72                                               GLuint maxAtomicCounters,
73                                               const std::string &componentsErrorMessage,
74                                               const std::string &samplerErrorMessage,
75                                               const std::string &imageErrorMessage,
76                                               const std::string &atomicCounterErrorMessage,
77                                               std::vector<LinkedUniform> &samplerUniforms,
78                                               std::vector<LinkedUniform> &imageUniforms,
79                                               std::vector<LinkedUniform> &atomicCounterUniforms,
80                                               InfoLog &infoLog);
81 
82     bool flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog);
83     bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog);
84 
85     ShaderUniformCount flattenUniform(const sh::Uniform &uniform,
86                                       std::vector<LinkedUniform> *samplerUniforms,
87                                       std::vector<LinkedUniform> *imageUniforms,
88                                       std::vector<LinkedUniform> *atomicCounterUniforms,
89                                       GLenum shaderType);
90 
91     ShaderUniformCount flattenArrayOfStructsUniform(
92         const sh::ShaderVariable &uniform,
93         unsigned int arrayNestingIndex,
94         const std::string &namePrefix,
95         const std::string &mappedNamePrefix,
96         std::vector<LinkedUniform> *samplerUniforms,
97         std::vector<LinkedUniform> *imageUniforms,
98         std::vector<LinkedUniform> *atomicCounterUniforms,
99         GLenum shaderType,
100         bool markStaticUse,
101         int binding,
102         int offset,
103         int *location);
104 
105     ShaderUniformCount flattenStructUniform(const std::vector<sh::ShaderVariable> &fields,
106                                             const std::string &namePrefix,
107                                             const std::string &mappedNamePrefix,
108                                             std::vector<LinkedUniform> *samplerUniforms,
109                                             std::vector<LinkedUniform> *imageUniforms,
110                                             std::vector<LinkedUniform> *atomicCounterUniforms,
111                                             GLenum shaderType,
112                                             bool markStaticUse,
113                                             int binding,
114                                             int offset,
115                                             int *location);
116 
117     ShaderUniformCount flattenArrayUniform(const sh::ShaderVariable &uniform,
118                                            const std::string &fullName,
119                                            const std::string &fullMappedName,
120                                            std::vector<LinkedUniform> *samplerUniforms,
121                                            std::vector<LinkedUniform> *imageUniforms,
122                                            std::vector<LinkedUniform> *atomicCounterUniforms,
123                                            GLenum shaderType,
124                                            bool markStaticUse,
125                                            int binding,
126                                            int offset,
127                                            int *location);
128 
129     // markStaticUse is given as a separate parameter because it is tracked here at struct
130     // granularity.
131     ShaderUniformCount flattenUniformImpl(const sh::ShaderVariable &uniform,
132                                           const std::string &fullName,
133                                           const std::string &fullMappedName,
134                                           std::vector<LinkedUniform> *samplerUniforms,
135                                           std::vector<LinkedUniform> *imageUniforms,
136                                           std::vector<LinkedUniform> *atomicCounterUniforms,
137                                           GLenum shaderType,
138                                           bool markStaticUse,
139                                           int binding,
140                                           int offset,
141                                           int *location);
142 
143     bool indexUniforms(InfoLog &infoLog, const Program::Bindings &uniformLocationBindings);
144     bool gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog,
145                                                  const Program::Bindings &uniformLocationBindings,
146                                                  std::set<GLuint> *reservedLocations,
147                                                  std::set<GLuint> *ignoredLocations,
148                                                  int *maxUniformLocation);
149     void pruneUnusedUniforms();
150 
151     const ProgramState &mState;
152     std::vector<LinkedUniform> mUniforms;
153     std::vector<VariableLocation> mUniformLocations;
154 };
155 
156 // This class is intended to be used during the link step to store interface block information.
157 // It is called by the Impl class during ProgramImpl::link so that it has access to the
158 // real block size and layout.
159 class InterfaceBlockLinker : angle::NonCopyable
160 {
161   public:
162     virtual ~InterfaceBlockLinker();
163 
164     using GetBlockSize = std::function<
165         bool(const std::string &blockName, const std::string &blockMappedName, size_t *sizeOut)>;
166     using GetBlockMemberInfo = std::function<
167         bool(const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut)>;
168 
169     // This is called once per shader stage. It stores a pointer to the block vector, so it's
170     // important that this class does not persist longer than the duration of Program::link.
171     void addShaderBlocks(GLenum shader, const std::vector<sh::InterfaceBlock> *blocks);
172 
173     // This is called once during a link operation, after all shader blocks are added.
174     void linkBlocks(const GetBlockSize &getBlockSize,
175                     const GetBlockMemberInfo &getMemberInfo) const;
176 
177   protected:
178     InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut);
179     void defineInterfaceBlock(const GetBlockSize &getBlockSize,
180                               const GetBlockMemberInfo &getMemberInfo,
181                               const sh::InterfaceBlock &interfaceBlock,
182                               GLenum shaderType) const;
183 
184     template <typename VarT>
185     void defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
186                             const std::vector<VarT> &fields,
187                             const std::string &prefix,
188                             const std::string &mappedPrefix,
189                             int blockIndex,
190                             bool singleEntryForTopLevelArray,
191                             int topLevelArraySize) const;
192     template <typename VarT>
193     void defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
194                            const VarT &field,
195                            const std::string &fullName,
196                            const std::string &fullMappedName,
197                            int blockIndex,
198                            bool singleEntryForTopLevelArray,
199                            int topLevelArraySize) const;
200 
201     virtual void defineBlockMemberImpl(const sh::ShaderVariable &field,
202                                        const std::string &fullName,
203                                        const std::string &fullMappedName,
204                                        int blockIndex,
205                                        const sh::BlockMemberInfo &memberInfo,
206                                        int topLevelArraySize) const             = 0;
207     virtual size_t getCurrentBlockMemberIndex() const                           = 0;
208 
209     using ShaderBlocks = std::pair<GLenum, const std::vector<sh::InterfaceBlock> *>;
210     std::vector<ShaderBlocks> mShaderBlocks;
211 
212     std::vector<InterfaceBlock> *mBlocksOut;
213 
214   private:
215     template <typename VarT>
216     void defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
217                                           const VarT &field,
218                                           unsigned int arrayNestingIndex,
219                                           const std::string &prefix,
220                                           const std::string &mappedPrefix,
221                                           int blockIndex,
222                                           bool singleEntryForTopLevelArray,
223                                           int topLevelArraySize) const;
224 };
225 
226 class UniformBlockLinker final : public InterfaceBlockLinker
227 {
228   public:
229     UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
230                        std::vector<LinkedUniform> *uniformsOut);
231     ~UniformBlockLinker() override;
232 
233   private:
234     void defineBlockMemberImpl(const sh::ShaderVariable &field,
235                                const std::string &fullName,
236                                const std::string &fullMappedName,
237                                int blockIndex,
238                                const sh::BlockMemberInfo &memberInfo,
239                                int topLevelArraySize) const override;
240     size_t getCurrentBlockMemberIndex() const override;
241     std::vector<LinkedUniform> *mUniformsOut;
242 };
243 
244 class ShaderStorageBlockLinker final : public InterfaceBlockLinker
245 {
246   public:
247     ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
248                              std::vector<BufferVariable> *bufferVariablesOut);
249     ~ShaderStorageBlockLinker() override;
250 
251   private:
252     void defineBlockMemberImpl(const sh::ShaderVariable &field,
253                                const std::string &fullName,
254                                const std::string &fullMappedName,
255                                int blockIndex,
256                                const sh::BlockMemberInfo &memberInfo,
257                                int topLevelArraySize) const override;
258     size_t getCurrentBlockMemberIndex() const override;
259     std::vector<BufferVariable> *mBufferVariablesOut;
260 };
261 
262 // The link operation is responsible for finishing the link of uniform and interface blocks.
263 // This way it can filter out unreferenced resources and still have access to the info.
264 // TODO(jmadill): Integrate uniform linking/filtering as well as interface blocks.
265 struct ProgramLinkedResources
266 {
267     VaryingPacking varyingPacking;
268     UniformBlockLinker uniformBlockLinker;
269     ShaderStorageBlockLinker shaderStorageBlockLinker;
270 };
271 
272 }  // namespace gl
273 
274 #endif  // LIBANGLE_UNIFORMLINKER_H_
275