xref: /aosp_15_r20/external/angle/src/libANGLE/ProgramLinkedResources.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 AtomicCounterBuffer;
49 struct VariableLocation;
50 struct Version;
51 
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<std::string> *uniformNames,
128                     std::vector<std::string> *uniformMappedNames,
129                     std::vector<UnusedUniform> *unusedUniformsOutOrNull,
130                     std::vector<VariableLocation> *uniformLocationsOutOrNull);
131 
132   private:
133     bool validateGraphicsUniforms(InfoLog &infoLog) const;
134     bool validateGraphicsUniformsPerShader(ShaderType shaderToLink,
135                                            bool extendLinkedUniforms,
136                                            std::map<std::string, ShaderUniform> *linkedUniforms,
137                                            InfoLog &infoLog) const;
138     bool flattenUniformsAndCheckCapsForShader(ShaderType shaderType,
139                                               const Caps &caps,
140                                               std::vector<UsedUniform> &samplerUniforms,
141                                               std::vector<UsedUniform> &imageUniforms,
142                                               std::vector<UsedUniform> &atomicCounterUniforms,
143                                               std::vector<UsedUniform> &inputAttachmentUniforms,
144                                               std::vector<UnusedUniform> &unusedUniforms,
145                                               InfoLog &infoLog);
146 
147     bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog);
148     bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog);
149 
150     bool indexUniforms(InfoLog &infoLog, const ProgramAliasedBindings &uniformLocationBindings);
151     bool gatherUniformLocationsAndCheckConflicts(
152         InfoLog &infoLog,
153         const ProgramAliasedBindings &uniformLocationBindings,
154         std::set<GLuint> *ignoredLocations,
155         int *maxUniformLocation);
156     void pruneUnusedUniforms();
157 
158     ShaderBitSet mActiveShaderStages;
159     const ShaderMap<std::vector<sh::ShaderVariable>> &mShaderUniforms;
160     std::vector<UsedUniform> mUniforms;
161     std::vector<UnusedUniform> mUnusedUniforms;
162     std::vector<VariableLocation> mUniformLocations;
163 };
164 
165 using GetBlockSizeFunc = std::function<
166     bool(const std::string &blockName, const std::string &blockMappedName, size_t *sizeOut)>;
167 using GetBlockMemberInfoFunc = std::function<
168     bool(const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut)>;
169 
170 // This class is intended to be used during the link step to store interface block information.
171 // It is called by the Impl class during ProgramImpl::link so that it has access to the
172 // real block size and layout.
173 class InterfaceBlockLinker : angle::NonCopyable
174 {
175   public:
176     virtual ~InterfaceBlockLinker();
177 
178     // This is called once per shader stage. It stores a pointer to the block vector, so it's
179     // important that this class does not persist longer than the duration of Program::link.
180     void addShaderBlocks(ShaderType shader, const std::vector<sh::InterfaceBlock> *blocks);
181 
182     // This is called once during a link operation, after all shader blocks are added.
183     void linkBlocks(const GetBlockSizeFunc &getBlockSize,
184                     const GetBlockMemberInfoFunc &getMemberInfo) const;
185 
getShaderBlocks(ShaderType shaderType)186     const std::vector<sh::InterfaceBlock> &getShaderBlocks(ShaderType shaderType) const
187     {
188         ASSERT(mShaderBlocks[shaderType]);
189         return *mShaderBlocks[shaderType];
190     }
191 
192   protected:
193     InterfaceBlockLinker();
194     void init(std::vector<InterfaceBlock> *blocksOut,
195               std::vector<std::string> *unusedInterfaceBlocksOut);
196     void defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
197                               const GetBlockMemberInfoFunc &getMemberInfo,
198                               const sh::InterfaceBlock &interfaceBlock,
199                               ShaderType shaderType) const;
200 
201     virtual size_t getCurrentBlockMemberIndex() const = 0;
202 
203     virtual sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
204                                                   const std::string &namePrefix,
205                                                   const std::string &mappedNamePrefix,
206                                                   ShaderType shaderType,
207                                                   int blockIndex) const = 0;
208 
209     ShaderMap<const std::vector<sh::InterfaceBlock> *> mShaderBlocks = {};
210 
211     std::vector<InterfaceBlock> *mBlocksOut             = nullptr;
212     std::vector<std::string> *mUnusedInterfaceBlocksOut = nullptr;
213 };
214 
215 class UniformBlockLinker final : public InterfaceBlockLinker
216 {
217   public:
218     UniformBlockLinker();
219     ~UniformBlockLinker() override;
220 
221     void init(std::vector<InterfaceBlock> *blocksOut,
222               std::vector<LinkedUniform> *uniformsOut,
223               std::vector<std::string> *uniformNamesOut,
224               std::vector<std::string> *uniformMappedNamesOut,
225               std::vector<std::string> *unusedInterfaceBlocksOut);
226 
227   private:
228     size_t getCurrentBlockMemberIndex() const override;
229 
230     sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
231                                           const std::string &namePrefix,
232                                           const std::string &mappedNamePrefix,
233                                           ShaderType shaderType,
234                                           int blockIndex) const override;
235 
236     std::vector<LinkedUniform> *mUniformsOut         = nullptr;
237     std::vector<std::string> *mUniformNamesOut       = nullptr;
238     std::vector<std::string> *mUniformMappedNamesOut = nullptr;
239 };
240 
241 class ShaderStorageBlockLinker final : public InterfaceBlockLinker
242 {
243   public:
244     ShaderStorageBlockLinker();
245     ~ShaderStorageBlockLinker() override;
246 
247     void init(std::vector<InterfaceBlock> *blocksOut,
248               std::vector<BufferVariable> *bufferVariablesOut,
249               std::vector<std::string> *unusedInterfaceBlocksOut);
250 
251   private:
252     size_t getCurrentBlockMemberIndex() const override;
253 
254     sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
255                                           const std::string &namePrefix,
256                                           const std::string &mappedNamePrefix,
257                                           ShaderType shaderType,
258                                           int blockIndex) const override;
259 
260     std::vector<BufferVariable> *mBufferVariablesOut = nullptr;
261 };
262 
263 class AtomicCounterBufferLinker final : angle::NonCopyable
264 {
265   public:
266     AtomicCounterBufferLinker();
267     ~AtomicCounterBufferLinker();
268 
269     void init(std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut);
270     void link(const std::map<int, unsigned int> &sizeMap) const;
271 
272   private:
273     std::vector<AtomicCounterBuffer> *mAtomicCounterBuffersOut = nullptr;
274 };
275 
276 class PixelLocalStorageLinker final : angle::NonCopyable
277 {
278   public:
279     PixelLocalStorageLinker();
280     ~PixelLocalStorageLinker();
281 
282     void init(std::vector<ShPixelLocalStorageFormat> *pixelLocalStorageFormatsOut);
283     void link(const std::vector<ShPixelLocalStorageFormat> &pixelLocalStorageFormats) const;
284 
285   private:
286     std::vector<ShPixelLocalStorageFormat> *mPixelLocalStorageFormatsOut = nullptr;
287 };
288 
289 struct ProgramLinkedResources
290 {
291     ProgramLinkedResources();
292     ~ProgramLinkedResources();
293 
294     void init(std::vector<InterfaceBlock> *uniformBlocksOut,
295               std::vector<LinkedUniform> *uniformsOut,
296               std::vector<std::string> *uniformNamesOut,
297               std::vector<std::string> *uniformMappedNamesOut,
298               std::vector<InterfaceBlock> *shaderStorageBlocksOut,
299               std::vector<BufferVariable> *bufferVariablesOut,
300               std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut,
301               std::vector<ShPixelLocalStorageFormat> *pixelLocalStorageFormatsOut);
302 
303     ProgramVaryingPacking varyingPacking;
304     UniformBlockLinker uniformBlockLinker;
305     ShaderStorageBlockLinker shaderStorageBlockLinker;
306     AtomicCounterBufferLinker atomicCounterBufferLinker;
307     PixelLocalStorageLinker pixelLocalStorageLinker;
308     std::vector<UnusedUniform> unusedUniforms;
309     std::vector<std::string> unusedInterfaceBlocks;
310 };
311 
312 struct LinkingVariables final : private angle::NonCopyable
313 {
314     LinkingVariables();
315     ~LinkingVariables();
316 
317     void initForProgram(const ProgramState &state);
318     void initForProgramPipeline(const ProgramPipelineState &state);
319 
320     ShaderMap<std::vector<sh::ShaderVariable>> outputVaryings;
321     ShaderMap<std::vector<sh::ShaderVariable>> inputVaryings;
322     ShaderMap<std::vector<sh::ShaderVariable>> uniforms;
323     ShaderMap<std::vector<sh::InterfaceBlock>> uniformBlocks;
324     ShaderBitSet isShaderStageUsedBitset;
325 };
326 
327 class CustomBlockLayoutEncoderFactory : angle::NonCopyable
328 {
329   public:
~CustomBlockLayoutEncoderFactory()330     virtual ~CustomBlockLayoutEncoderFactory() {}
331 
332     virtual sh::BlockLayoutEncoder *makeEncoder() = 0;
333 };
334 
335 // Used by the backends in Program*::linkResources to parse interface blocks and provide
336 // information to ProgramLinkedResources' linkers.
337 class ProgramLinkedResourcesLinker final : angle::NonCopyable
338 {
339   public:
ProgramLinkedResourcesLinker(CustomBlockLayoutEncoderFactory * customEncoderFactory)340     ProgramLinkedResourcesLinker(CustomBlockLayoutEncoderFactory *customEncoderFactory)
341         : mCustomEncoderFactory(customEncoderFactory)
342     {}
343 
344     void linkResources(const ProgramState &programState,
345                        const ProgramLinkedResources &resources) const;
346 
347   private:
348     void getAtomicCounterBufferSizeMap(const ProgramExecutable &executable,
349                                        std::map<int, unsigned int> &sizeMapOut) const;
350 
351     CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
352 };
353 
354 using ShaderInterfaceBlock = std::pair<ShaderType, const sh::InterfaceBlock *>;
355 using InterfaceBlockMap    = std::map<std::string, ShaderInterfaceBlock>;
356 
357 bool LinkValidateProgramGlobalNames(InfoLog &infoLog,
358                                     const ProgramExecutable &executable,
359                                     const LinkingVariables &linkingVariables);
360 bool LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> &outputVaryings,
361                                          const std::vector<sh::ShaderVariable> &inputVaryings,
362                                          ShaderType frontShaderType,
363                                          ShaderType backShaderType,
364                                          int frontShaderVersion,
365                                          int backShaderVersion,
366                                          bool isSeparable,
367                                          InfoLog &infoLog);
368 bool LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> &vertexVaryings,
369                                           const std::vector<sh::ShaderVariable> &fragmentVaryings,
370                                           int vertexShaderVersion,
371                                           InfoLog &infoLog);
372 bool LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &inputVaryings,
373                                  const std::vector<sh::ShaderVariable> &outputVaryings,
374                                  ShaderType inputShaderType,
375                                  ShaderType outputShaderType,
376                                  int inputShaderVersion,
377                                  int outputShaderVersion,
378                                  InfoLog &infoLog);
379 LinkMismatchError LinkValidateProgramVariables(const sh::ShaderVariable &variable1,
380                                                const sh::ShaderVariable &variable2,
381                                                bool validatePrecision,
382                                                bool treatVariable1AsNonArray,
383                                                bool treatVariable2AsNonArray,
384                                                std::string *mismatchedStructOrBlockMemberName);
385 void AddProgramVariableParentPrefix(const std::string &parentName,
386                                     std::string *mismatchedFieldName);
387 bool LinkValidateProgramInterfaceBlocks(const Caps &caps,
388                                         const Version &clientVersion,
389                                         bool webglCompatibility,
390                                         ShaderBitSet activeProgramStages,
391                                         const ProgramLinkedResources &resources,
392                                         InfoLog &infoLog,
393                                         GLuint *combinedShaderStorageBlocksCountOut);
394 }  // namespace gl
395 
396 #endif  // LIBANGLE_UNIFORMLINKER_H_
397