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