// // Copyright 2013 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. // // blocklayout.h: // Methods and classes related to uniform layout and packing in GLSL and HLSL. // #ifndef COMMON_BLOCKLAYOUT_H_ #define COMMON_BLOCKLAYOUT_H_ #include #include #include #include #include "angle_gl.h" namespace sh { struct ShaderVariable; struct InterfaceBlock; struct BlockMemberInfo { constexpr BlockMemberInfo() = default; constexpr BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix) : offset(offset), arrayStride(arrayStride), matrixStride(matrixStride), isRowMajorMatrix(isRowMajorMatrix) {} constexpr BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix, int topLevelArrayStride) : offset(offset), arrayStride(arrayStride), matrixStride(matrixStride), isRowMajorMatrix(isRowMajorMatrix), topLevelArrayStride(topLevelArrayStride) {} // A single integer identifying the offset of an active variable. int offset = -1; // A single integer identifying the stride between array elements in an active variable. int arrayStride = -1; // A single integer identifying the stride between columns of a column-major matrix or rows of a // row-major matrix. int matrixStride = -1; // A single integer identifying whether an active variable is a row-major matrix. bool isRowMajorMatrix = false; // A single integer identifying the number of active array elements of the top-level shader // storage block member containing the active variable. int topLevelArrayStride = -1; }; constexpr size_t ComponentAlignment(size_t numComponents) { return (numComponents == 3u ? 4u : numComponents); } constexpr BlockMemberInfo kDefaultBlockMemberInfo; class BlockLayoutEncoder { public: BlockLayoutEncoder(); virtual ~BlockLayoutEncoder() {} BlockMemberInfo encodeType(GLenum type, const std::vector &arraySizes, bool isRowMajorMatrix); // Advance the offset based on struct size and array dimensions. Size can be calculated with // getShaderVariableSize() or equivalent. |enterAggregateType|/|exitAggregateType| is necessary // around this call. BlockMemberInfo encodeArrayOfPreEncodedStructs(size_t size, const std::vector &arraySizes); size_t getCurrentOffset() const; size_t getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor); // Called when entering/exiting a structure variable. virtual void enterAggregateType(const ShaderVariable &structVar) = 0; virtual void exitAggregateType(const ShaderVariable &structVar) = 0; static constexpr size_t kBytesPerComponent = 4u; static constexpr unsigned int kComponentsPerRegister = 4u; static size_t GetBlockRegister(const BlockMemberInfo &info); static size_t GetBlockRegisterElement(const BlockMemberInfo &info); protected: void align(size_t baseAlignment); virtual void getBlockLayoutInfo(GLenum type, const std::vector &arraySizes, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0; virtual void advanceOffset(GLenum type, const std::vector &arraySizes, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0; size_t mCurrentOffset; }; // Will return default values for everything. class StubBlockEncoder : public BlockLayoutEncoder { public: StubBlockEncoder() = default; void enterAggregateType(const ShaderVariable &structVar) override {} void exitAggregateType(const ShaderVariable &structVar) override {} protected: void getBlockLayoutInfo(GLenum type, const std::vector &arraySizes, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) override; void advanceOffset(GLenum type, const std::vector &arraySizes, bool isRowMajorMatrix, int arrayStride, int matrixStride) override {} }; // Block layout according to the std140 block layout // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification class Std140BlockEncoder : public BlockLayoutEncoder { public: Std140BlockEncoder(); void enterAggregateType(const ShaderVariable &structVar) override; void exitAggregateType(const ShaderVariable &structVar) override; protected: void getBlockLayoutInfo(GLenum type, const std::vector &arraySizes, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) override; void advanceOffset(GLenum type, const std::vector &arraySizes, bool isRowMajorMatrix, int arrayStride, int matrixStride) override; virtual size_t getBaseAlignment(const ShaderVariable &variable) const; virtual size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const; }; class Std430BlockEncoder : public Std140BlockEncoder { public: Std430BlockEncoder(); protected: size_t getBaseAlignment(const ShaderVariable &variable) const override; size_t getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const override; }; using BlockLayoutMap = std::map; void GetInterfaceBlockInfo(const std::vector &fields, const std::string &prefix, BlockLayoutEncoder *encoder, BlockLayoutMap *blockInfoOut); // Used for laying out the default uniform block on the Vulkan backend. void GetActiveUniformBlockInfo(const std::vector &uniforms, const std::string &prefix, BlockLayoutEncoder *encoder, BlockLayoutMap *blockInfoOut); class ShaderVariableVisitor { public: virtual ~ShaderVariableVisitor() {} virtual void enterStruct(const ShaderVariable &structVar) {} virtual void exitStruct(const ShaderVariable &structVar) {} virtual void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) {} virtual void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) {} virtual void enterArray(const ShaderVariable &arrayVar) {} virtual void exitArray(const ShaderVariable &arrayVar) {} virtual void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {} virtual void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {} virtual void visitOpaqueObject(const sh::ShaderVariable &variable) {} virtual void visitVariable(const ShaderVariable &variable, bool isRowMajor) = 0; protected: ShaderVariableVisitor() {} }; class VariableNameVisitor : public ShaderVariableVisitor { public: VariableNameVisitor(const std::string &namePrefix, const std::string &mappedNamePrefix); ~VariableNameVisitor() override; void enterStruct(const ShaderVariable &structVar) override; void exitStruct(const ShaderVariable &structVar) override; void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override; void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override; void enterArray(const ShaderVariable &arrayVar) override; void exitArray(const ShaderVariable &arrayVar) override; void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override; void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override; protected: virtual void visitNamedOpaqueObject(const sh::ShaderVariable &variable, const std::string &name, const std::string &mappedName, const std::vector &arraySizes) {} virtual void visitNamedVariable(const ShaderVariable &variable, bool isRowMajor, const std::string &name, const std::string &mappedName, const std::vector &arraySizes) = 0; std::string collapseNameStack() const; std::string collapseMappedNameStack() const; private: void visitOpaqueObject(const sh::ShaderVariable &variable) final; void visitVariable(const ShaderVariable &variable, bool isRowMajor) final; std::vector mNameStack; std::vector mMappedNameStack; std::vector mArraySizeStack; }; class BlockEncoderVisitor : public VariableNameVisitor { public: BlockEncoderVisitor(const std::string &namePrefix, const std::string &mappedNamePrefix, BlockLayoutEncoder *encoder); ~BlockEncoderVisitor() override; void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override; void exitStructAccess(const ShaderVariable &structVar, bool isRowMajor) override; void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override; void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override; void visitNamedVariable(const ShaderVariable &variable, bool isRowMajor, const std::string &name, const std::string &mappedName, const std::vector &arraySizes) override; virtual void encodeVariable(const ShaderVariable &variable, const BlockMemberInfo &variableInfo, const std::string &name, const std::string &mappedName) {} protected: int mTopLevelArraySize = 1; int mTopLevelArrayStride = 0; bool mIsTopLevelArrayStrideReady = true; bool mSkipEnabled = false; private: BlockLayoutEncoder *mEncoder; unsigned int mStructStackSize = 0; }; void TraverseShaderVariable(const ShaderVariable &variable, bool isRowMajorLayout, ShaderVariableVisitor *visitor); template void TraverseShaderVariables(const std::vector &vars, bool isRowMajorLayout, ShaderVariableVisitor *visitor) { for (const T &var : vars) { TraverseShaderVariable(var, isRowMajorLayout, visitor); } } template void TraverseActiveShaderVariables(const std::vector &vars, bool isRowMajorLayout, ShaderVariableVisitor *visitor) { for (const T &var : vars) { if (var.active) { TraverseShaderVariable(var, isRowMajorLayout, visitor); } } } } // namespace sh #endif // COMMON_BLOCKLAYOUT_H_