• 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 <GLSLANG/ShaderVars.h>
15 
16 #include "angle_gl.h"
17 #include "common/PackedEnums.h"
18 #include "common/angleutils.h"
19 #include "libANGLE/Uniform.h"
20 #include "libANGLE/VaryingPacking.h"
21 
22 #include <functional>
23 
24 namespace sh
25 {
26 class BlockLayoutEncoder;
27 struct BlockMemberInfo;
28 struct InterfaceBlock;
29 struct ShaderVariable;
30 class BlockEncoderVisitor;
31 class ShaderVariableVisitor;
32 struct ShaderVariable;
33 }  // namespace sh
34 
35 namespace gl
36 {
37 struct BufferVariable;
38 struct Caps;
39 class Context;
40 class InfoLog;
41 struct InterfaceBlock;
42 enum class LinkMismatchError;
43 class ProgramState;
44 class ProgramPipelineState;
45 class ProgramBindings;
46 class ProgramAliasedBindings;
47 class Shader;
48 struct ShaderVariableBuffer;
49 struct VariableLocation;
50 
51 using AtomicCounterBuffer = ShaderVariableBuffer;
52 using ShaderUniform       = std::pair<ShaderType, const sh::ShaderVariable *>;
53 
54 // The link operation is responsible for finishing the link of uniform and interface blocks.
55 // This way it can filter out unreferenced resources and still have access to the info.
56 // TODO(jmadill): Integrate uniform linking/filtering as well as interface blocks.
57 struct UnusedUniform
58 {
UnusedUniformUnusedUniform59     UnusedUniform(std::string name,
60                   bool isSampler,
61                   bool isImage,
62                   bool isAtomicCounter,
63                   bool isFragmentInOut)
64     {
65         this->name            = name;
66         this->isSampler       = isSampler;
67         this->isImage         = isImage;
68         this->isAtomicCounter = isAtomicCounter;
69         this->isFragmentInOut = isFragmentInOut;
70     }
71 
72     std::string name;
73     bool isSampler;
74     bool isImage;
75     bool isAtomicCounter;
76     bool isFragmentInOut;
77 };
78 
79 struct UsedUniform : public sh::ShaderVariable
80 {
81     UsedUniform();
82     UsedUniform(GLenum type,
83                 GLenum precision,
84                 const std::string &name,
85                 const std::vector<unsigned int> &arraySizes,
86                 const int binding,
87                 const int offset,
88                 const int location,
89                 const int bufferIndex,
90                 const sh::BlockMemberInfo &blockInfo);
91     UsedUniform(const UsedUniform &other);
92     UsedUniform &operator=(const UsedUniform &other);
93     ~UsedUniform();
94 
isSamplerUsedUniform95     bool isSampler() const { return typeInfo->isSampler; }
isImageUsedUniform96     bool isImage() const { return typeInfo->isImageType; }
isAtomicCounterUsedUniform97     bool isAtomicCounter() const { return IsAtomicCounterType(type); }
getElementSizeUsedUniform98     size_t getElementSize() const { return typeInfo->externalSize; }
99 
setActiveUsedUniform100     void setActive(ShaderType shaderType, bool used, uint32_t _id)
101     {
102         activeVariable.setActive(shaderType, used, _id);
103     }
104 
105     ActiveVariable activeVariable;
106     const UniformTypeInfo *typeInfo;
107 
108     // Identifies the containing buffer backed resource -- interface block or atomic counter buffer.
109     int bufferIndex;
110     sh::BlockMemberInfo blockInfo;
111     std::vector<unsigned int> outerArraySizes;
112     unsigned int outerArrayOffset;
113 };
114 
115 class UniformLinker final : angle::NonCopyable
116 {
117   public:
118     UniformLinker(const ShaderBitSet &activeShaderStages,
119                   const ShaderMap<std::vector<sh::ShaderVariable>> &shaderUniforms);
120     ~UniformLinker();
121 
122     bool link(const Caps &caps,
123               InfoLog &infoLog,
124               const ProgramAliasedBindings &uniformLocationBindings);
125 
126     void getResults(std::vector<LinkedUniform> *uniforms,
127                     std::vector<UnusedUniform> *unusedUniformsOutOrNull,
128                     std::vector<VariableLocation> *uniformLocationsOutOrNull);
129 
130   private:
131     bool validateGraphicsUniforms(InfoLog &infoLog) const;
132     bool validateGraphicsUniformsPerShader(ShaderType shaderToLink,
133                                            bool extendLinkedUniforms,
134                                            std::map<std::string, ShaderUniform> *linkedUniforms,
135                                            InfoLog &infoLog) const;
136     bool flattenUniformsAndCheckCapsForShader(ShaderType shaderType,
137                                               const Caps &caps,
138                                               std::vector<UsedUniform> &samplerUniforms,
139                                               std::vector<UsedUniform> &imageUniforms,
140                                               std::vector<UsedUniform> &atomicCounterUniforms,
141                                               std::vector<UsedUniform> &inputAttachmentUniforms,
142                                               std::vector<UnusedUniform> &unusedUniforms,
143                                               InfoLog &infoLog);
144 
145     bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog);
146     bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog);
147 
148     bool indexUniforms(InfoLog &infoLog, const ProgramAliasedBindings &uniformLocationBindings);
149     bool gatherUniformLocationsAndCheckConflicts(
150         InfoLog &infoLog,
151         const ProgramAliasedBindings &uniformLocationBindings,
152         std::set<GLuint> *ignoredLocations,
153         int *maxUniformLocation);
154     void pruneUnusedUniforms();
155 
156     ShaderBitSet mActiveShaderStages;
157     const ShaderMap<std::vector<sh::ShaderVariable>> &mShaderUniforms;
158     std::vector<UsedUniform> mUniforms;
159     std::vector<UnusedUniform> mUnusedUniforms;
160     std::vector<VariableLocation> mUniformLocations;
161 };
162 
163 using GetBlockSizeFunc = std::function<
164     bool(const std::string &blockName, const std::string &blockMappedName, size_t *sizeOut)>;
165 using GetBlockMemberInfoFunc = std::function<
166     bool(const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut)>;
167 
168 // This class is intended to be used during the link step to store interface block information.
169 // It is called by the Impl class during ProgramImpl::link so that it has access to the
170 // real block size and layout.
171 class InterfaceBlockLinker : angle::NonCopyable
172 {
173   public:
174     virtual ~InterfaceBlockLinker();
175 
176     // This is called once per shader stage. It stores a pointer to the block vector, so it's
177     // important that this class does not persist longer than the duration of Program::link.
178     void addShaderBlocks(ShaderType shader, const std::vector<sh::InterfaceBlock> *blocks);
179 
180     // This is called once during a link operation, after all shader blocks are added.
181     void linkBlocks(const GetBlockSizeFunc &getBlockSize,
182                     const GetBlockMemberInfoFunc &getMemberInfo) const;
183 
getShaderBlocks(ShaderType shaderType)184     const std::vector<sh::InterfaceBlock> &getShaderBlocks(ShaderType shaderType) const
185     {
186         ASSERT(mShaderBlocks[shaderType]);
187         return *mShaderBlocks[shaderType];
188     }
189 
190   protected:
191     InterfaceBlockLinker();
192     void init(std::vector<InterfaceBlock> *blocksOut,
193               std::vector<std::string> *unusedInterfaceBlocksOut);
194     void defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
195                               const GetBlockMemberInfoFunc &getMemberInfo,
196                               const sh::InterfaceBlock &interfaceBlock,
197                               ShaderType shaderType) const;
198 
199     virtual size_t getCurrentBlockMemberIndex() const = 0;
200 
201     virtual sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
202                                                   const std::string &namePrefix,
203                                                   const std::string &mappedNamePrefix,
204                                                   ShaderType shaderType,
205                                                   int blockIndex) const = 0;
206 
207     ShaderMap<const std::vector<sh::InterfaceBlock> *> mShaderBlocks = {};
208 
209     std::vector<InterfaceBlock> *mBlocksOut             = nullptr;
210     std::vector<std::string> *mUnusedInterfaceBlocksOut = nullptr;
211 };
212 
213 class UniformBlockLinker final : public InterfaceBlockLinker
214 {
215   public:
216     UniformBlockLinker();
217     ~UniformBlockLinker() override;
218 
219     void init(std::vector<InterfaceBlock> *blocksOut,
220               std::vector<LinkedUniform> *uniformsOut,
221               std::vector<std::string> *unusedInterfaceBlocksOut);
222 
223   private:
224     size_t getCurrentBlockMemberIndex() const override;
225 
226     sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
227                                           const std::string &namePrefix,
228                                           const std::string &mappedNamePrefix,
229                                           ShaderType shaderType,
230                                           int blockIndex) const override;
231 
232     std::vector<LinkedUniform> *mUniformsOut = nullptr;
233 };
234 
235 class ShaderStorageBlockLinker final : public InterfaceBlockLinker
236 {
237   public:
238     ShaderStorageBlockLinker();
239     ~ShaderStorageBlockLinker() override;
240 
241     void init(std::vector<InterfaceBlock> *blocksOut,
242               std::vector<BufferVariable> *bufferVariablesOut,
243               std::vector<std::string> *unusedInterfaceBlocksOut);
244 
245   private:
246     size_t getCurrentBlockMemberIndex() const override;
247 
248     sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
249                                           const std::string &namePrefix,
250                                           const std::string &mappedNamePrefix,
251                                           ShaderType shaderType,
252                                           int blockIndex) const override;
253 
254     std::vector<BufferVariable> *mBufferVariablesOut = nullptr;
255 };
256 
257 class AtomicCounterBufferLinker final : angle::NonCopyable
258 {
259   public:
260     AtomicCounterBufferLinker();
261     ~AtomicCounterBufferLinker();
262 
263     void init(std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut);
264     void link(const std::map<int, unsigned int> &sizeMap) const;
265 
266   private:
267     std::vector<AtomicCounterBuffer> *mAtomicCounterBuffersOut = nullptr;
268 };
269 
270 struct ProgramLinkedResources
271 {
272     ProgramLinkedResources();
273     ~ProgramLinkedResources();
274 
275     void init(std::vector<InterfaceBlock> *uniformBlocksOut,
276               std::vector<LinkedUniform> *uniformsOut,
277               std::vector<InterfaceBlock> *shaderStorageBlocksOut,
278               std::vector<BufferVariable> *bufferVariablesOut,
279               std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut);
280 
281     ProgramVaryingPacking varyingPacking;
282     UniformBlockLinker uniformBlockLinker;
283     ShaderStorageBlockLinker shaderStorageBlockLinker;
284     AtomicCounterBufferLinker atomicCounterBufferLinker;
285     std::vector<UnusedUniform> unusedUniforms;
286     std::vector<std::string> unusedInterfaceBlocks;
287 };
288 
289 struct LinkingVariables final : private angle::NonCopyable
290 {
291     LinkingVariables(const Context *context, const ProgramState &state);
292     LinkingVariables(const ProgramPipelineState &state);
293     ~LinkingVariables();
294 
295     ShaderMap<std::vector<sh::ShaderVariable>> outputVaryings;
296     ShaderMap<std::vector<sh::ShaderVariable>> inputVaryings;
297     ShaderMap<std::vector<sh::ShaderVariable>> uniforms;
298     ShaderMap<std::vector<sh::InterfaceBlock>> uniformBlocks;
299     ShaderBitSet isShaderStageUsedBitset;
300 };
301 
302 class CustomBlockLayoutEncoderFactory : angle::NonCopyable
303 {
304   public:
~CustomBlockLayoutEncoderFactory()305     virtual ~CustomBlockLayoutEncoderFactory() {}
306 
307     virtual sh::BlockLayoutEncoder *makeEncoder() = 0;
308 };
309 
310 // Used by the backends in Program*::linkResources to parse interface blocks and provide
311 // information to ProgramLinkedResources' linkers.
312 class ProgramLinkedResourcesLinker final : angle::NonCopyable
313 {
314   public:
ProgramLinkedResourcesLinker(CustomBlockLayoutEncoderFactory * customEncoderFactory)315     ProgramLinkedResourcesLinker(CustomBlockLayoutEncoderFactory *customEncoderFactory)
316         : mCustomEncoderFactory(customEncoderFactory)
317     {}
318 
319     void linkResources(const Context *context,
320                        const ProgramState &programState,
321                        const ProgramLinkedResources &resources) const;
322 
323   private:
324     void getAtomicCounterBufferSizeMap(const ProgramState &programState,
325                                        std::map<int, unsigned int> &sizeMapOut) const;
326 
327     CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
328 };
329 
330 using ShaderInterfaceBlock = std::pair<ShaderType, const sh::InterfaceBlock *>;
331 using InterfaceBlockMap    = std::map<std::string, ShaderInterfaceBlock>;
332 
333 bool LinkValidateProgramGlobalNames(InfoLog &infoLog,
334                                     const ProgramExecutable &executable,
335                                     const LinkingVariables &linkingVariables);
336 bool LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> &outputVaryings,
337                                          const std::vector<sh::ShaderVariable> &inputVaryings,
338                                          ShaderType frontShaderType,
339                                          ShaderType backShaderType,
340                                          int frontShaderVersion,
341                                          int backShaderVersion,
342                                          bool isSeparable,
343                                          InfoLog &infoLog);
344 bool LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> &vertexVaryings,
345                                           const std::vector<sh::ShaderVariable> &fragmentVaryings,
346                                           int vertexShaderVersion,
347                                           InfoLog &infoLog);
348 bool LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &inputVaryings,
349                                  const std::vector<sh::ShaderVariable> &outputVaryings,
350                                  ShaderType inputShaderType,
351                                  ShaderType outputShaderType,
352                                  int inputShaderVersion,
353                                  int outputShaderVersion,
354                                  InfoLog &infoLog);
355 LinkMismatchError LinkValidateProgramVariables(const sh::ShaderVariable &variable1,
356                                                const sh::ShaderVariable &variable2,
357                                                bool validatePrecision,
358                                                bool treatVariable1AsNonArray,
359                                                bool treatVariable2AsNonArray,
360                                                std::string *mismatchedStructOrBlockMemberName);
361 void AddProgramVariableParentPrefix(const std::string &parentName,
362                                     std::string *mismatchedFieldName);
363 bool LinkValidateProgramInterfaceBlocks(const Context *context,
364                                         ShaderBitSet activeProgramStages,
365                                         const ProgramLinkedResources &resources,
366                                         InfoLog &infoLog,
367                                         GLuint *combinedShaderStorageBlocksCountOut);
368 }  // namespace gl
369 
370 #endif  // LIBANGLE_UNIFORMLINKER_H_
371