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