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