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