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