// // Copyright (c) 2017 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // ProgramLinkedResources.h: implements link-time checks for default block uniforms, and generates // uniform locations. Populates data structures related to uniforms so that they can be stored in // program state. #ifndef LIBANGLE_UNIFORMLINKER_H_ #define LIBANGLE_UNIFORMLINKER_H_ #include "angle_gl.h" #include "common/PackedEnums.h" #include "common/angleutils.h" #include "libANGLE/VaryingPacking.h" #include namespace sh { class BlockLayoutEncoder; struct BlockMemberInfo; struct InterfaceBlock; struct ShaderVariable; class BlockEncoderVisitor; class ShaderVariableVisitor; struct Uniform; } // namespace sh namespace gl { struct BufferVariable; struct Caps; class Context; class InfoLog; struct InterfaceBlock; enum class LinkMismatchError; struct LinkedUniform; class ProgramState; class ProgramBindings; class Shader; struct ShaderVariableBuffer; struct UnusedUniform; struct VariableLocation; using AtomicCounterBuffer = ShaderVariableBuffer; class UniformLinker final : angle::NonCopyable { public: UniformLinker(const ProgramState &state); ~UniformLinker(); bool link(const Caps &caps, InfoLog &infoLog, const ProgramBindings &uniformLocationBindings); void getResults(std::vector *uniforms, std::vector *unusedUniforms, std::vector *uniformLocations); private: bool validateGraphicsUniforms(InfoLog &infoLog) const; bool flattenUniformsAndCheckCapsForShader(Shader *shader, const Caps &caps, std::vector &samplerUniforms, std::vector &imageUniforms, std::vector &atomicCounterUniforms, std::vector &unusedUniforms, InfoLog &infoLog); bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog); bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog); bool indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings); bool gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings, std::set *ignoredLocations, int *maxUniformLocation); void pruneUnusedUniforms(); const ProgramState &mState; std::vector mUniforms; std::vector mUnusedUniforms; std::vector mUniformLocations; }; using GetBlockSizeFunc = std::function< bool(const std::string &blockName, const std::string &blockMappedName, size_t *sizeOut)>; using GetBlockMemberInfoFunc = std::function< bool(const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut)>; // This class is intended to be used during the link step to store interface block information. // It is called by the Impl class during ProgramImpl::link so that it has access to the // real block size and layout. class InterfaceBlockLinker : angle::NonCopyable { public: virtual ~InterfaceBlockLinker(); // This is called once per shader stage. It stores a pointer to the block vector, so it's // important that this class does not persist longer than the duration of Program::link. void addShaderBlocks(ShaderType shader, const std::vector *blocks); // This is called once during a link operation, after all shader blocks are added. void linkBlocks(const GetBlockSizeFunc &getBlockSize, const GetBlockMemberInfoFunc &getMemberInfo) const; protected: InterfaceBlockLinker(std::vector *blocksOut, std::vector *unusedInterfaceBlocksOut); void defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize, const GetBlockMemberInfoFunc &getMemberInfo, const sh::InterfaceBlock &interfaceBlock, ShaderType shaderType) const; virtual size_t getCurrentBlockMemberIndex() const = 0; ShaderMap *> mShaderBlocks; std::vector *mBlocksOut; std::vector *mUnusedInterfaceBlocksOut; virtual sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo, const std::string &namePrefix, const std::string &mappedNamePrefix, ShaderType shaderType, int blockIndex) const = 0; }; class UniformBlockLinker final : public InterfaceBlockLinker { public: UniformBlockLinker(std::vector *blocksOut, std::vector *uniformsOut, std::vector *unusedInterfaceBlocksOut); ~UniformBlockLinker() override; private: size_t getCurrentBlockMemberIndex() const override; sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo, const std::string &namePrefix, const std::string &mappedNamePrefix, ShaderType shaderType, int blockIndex) const override; std::vector *mUniformsOut; }; class ShaderStorageBlockLinker final : public InterfaceBlockLinker { public: ShaderStorageBlockLinker(std::vector *blocksOut, std::vector *bufferVariablesOut, std::vector *unusedInterfaceBlocksOut); ~ShaderStorageBlockLinker() override; private: size_t getCurrentBlockMemberIndex() const override; sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo, const std::string &namePrefix, const std::string &mappedNamePrefix, ShaderType shaderType, int blockIndex) const override; std::vector *mBufferVariablesOut; }; class AtomicCounterBufferLinker final : angle::NonCopyable { public: AtomicCounterBufferLinker(std::vector *atomicCounterBuffersOut); ~AtomicCounterBufferLinker(); void link(const std::map &sizeMap) const; private: std::vector *mAtomicCounterBuffersOut; }; // The link operation is responsible for finishing the link of uniform and interface blocks. // This way it can filter out unreferenced resources and still have access to the info. // TODO(jmadill): Integrate uniform linking/filtering as well as interface blocks. struct UnusedUniform { UnusedUniform(std::string name, bool isSampler) { this->name = name; this->isSampler = isSampler; } std::string name; bool isSampler; }; struct ProgramLinkedResources { ProgramLinkedResources(GLuint maxVaryingVectors, PackMode packMode, std::vector *uniformBlocksOut, std::vector *uniformsOut, std::vector *shaderStorageBlocksOut, std::vector *bufferVariablesOut, std::vector *atomicCounterBuffersOut); ~ProgramLinkedResources(); VaryingPacking varyingPacking; UniformBlockLinker uniformBlockLinker; ShaderStorageBlockLinker shaderStorageBlockLinker; AtomicCounterBufferLinker atomicCounterBufferLinker; std::vector unusedUniforms; std::vector unusedInterfaceBlocks; }; class CustomBlockLayoutEncoderFactory : angle::NonCopyable { public: virtual ~CustomBlockLayoutEncoderFactory() {} virtual sh::BlockLayoutEncoder *makeEncoder() = 0; }; // Used by the backends in Program*::linkResources to parse interface blocks and provide // information to ProgramLinkedResources' linkers. class ProgramLinkedResourcesLinker final : angle::NonCopyable { public: ProgramLinkedResourcesLinker(CustomBlockLayoutEncoderFactory *customEncoderFactory) : mCustomEncoderFactory(customEncoderFactory) {} void linkResources(const ProgramState &programState, const ProgramLinkedResources &resources) const; private: void getAtomicCounterBufferSizeMap(const ProgramState &programState, std::map &sizeMapOut) const; CustomBlockLayoutEncoderFactory *mCustomEncoderFactory; }; } // namespace gl #endif // LIBANGLE_UNIFORMLINKER_H_