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