| // |
| // Copyright 2015 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. |
| // |
| // VaryingPacking: |
| // Class which describes a mapping from varyings to registers, according |
| // to the spec, or using custom packing algorithms. We also keep a register |
| // allocation list for the D3D renderer. |
| // |
| |
| #ifndef LIBANGLE_VARYINGPACKING_H_ |
| #define LIBANGLE_VARYINGPACKING_H_ |
| |
| #include <GLSLANG/ShaderVars.h> |
| |
| #include "angle_gl.h" |
| #include "common/angleutils.h" |
| #include "libANGLE/angletypes.h" |
| |
| #include <map> |
| |
| namespace gl |
| { |
| class InfoLog; |
| class ProgramExecutable; |
| struct Caps; |
| struct LinkingVariables; |
| struct ProgramVaryingRef; |
| |
| using ProgramMergedVaryings = std::vector<ProgramVaryingRef>; |
| |
| // A varying can have different names between stages if matched by the location layout qualifier. |
| // Additionally, same name varyings could still be of two identical struct types with different |
| // names. This struct contains information on the varying in one of the two stages. PackedVarying |
| // will thus contain two copies of this along with common information, such as interpolation or |
| // field index. |
| struct VaryingInShaderRef : angle::NonCopyable |
| { |
| VaryingInShaderRef(ShaderType stageIn, const sh::ShaderVariable *varyingIn); |
| VaryingInShaderRef(VaryingInShaderRef &&other); |
| ~VaryingInShaderRef(); |
| |
| VaryingInShaderRef &operator=(VaryingInShaderRef &&other); |
| |
| const sh::ShaderVariable *varying; |
| |
| ShaderType stage; |
| |
| // Struct name |
| std::string parentStructName; |
| std::string parentStructMappedName; |
| }; |
| |
| struct PackedVarying : angle::NonCopyable |
| { |
| // Throughout this file, the "front" stage refers to the stage that outputs the varying, and the |
| // "back" stage refers to the stage that takes the varying as input. Note that this struct |
| // contains linked varyings, which means both front and back stage varyings are valid, except |
| // for the following which may have only one valid stage. |
| // |
| // - transform-feedback-captured varyings |
| // - builtins |
| // - separable program stages, |
| // |
| PackedVarying(VaryingInShaderRef &&frontVaryingIn, |
| VaryingInShaderRef &&backVaryingIn, |
| sh::InterpolationType interpolationIn); |
| PackedVarying(VaryingInShaderRef &&frontVaryingIn, |
| VaryingInShaderRef &&backVaryingIn, |
| sh::InterpolationType interpolationIn, |
| GLuint arrayIndexIn, |
| GLuint fieldIndexIn, |
| GLuint secondaryFieldIndexIn); |
| PackedVarying(PackedVarying &&other); |
| ~PackedVarying(); |
| |
| PackedVarying &operator=(PackedVarying &&other); |
| |
| bool isStructField() const |
| { |
| return frontVarying.varying ? !frontVarying.parentStructName.empty() |
| : !backVarying.parentStructName.empty(); |
| } |
| |
| bool isTransformFeedbackArrayElement() const |
| { |
| return isTransformFeedback && arrayIndex != GL_INVALID_INDEX; |
| } |
| |
| // Return either front or back varying, whichever is available. Only used when the name of the |
| // varying is not important, but only the type is interesting. |
| const sh::ShaderVariable &varying() const |
| { |
| return frontVarying.varying ? *frontVarying.varying : *backVarying.varying; |
| } |
| |
| const std::string &getParentStructName() const |
| { |
| ASSERT(isStructField()); |
| return frontVarying.varying ? frontVarying.parentStructName : backVarying.parentStructName; |
| } |
| |
| std::string fullName(ShaderType stage) const |
| { |
| ASSERT(stage == frontVarying.stage || stage == backVarying.stage); |
| const VaryingInShaderRef &varying = |
| stage == frontVarying.stage ? frontVarying : backVarying; |
| |
| std::stringstream fullNameStr; |
| if (isStructField()) |
| { |
| fullNameStr << varying.parentStructName << "."; |
| } |
| |
| fullNameStr << varying.varying->name; |
| if (arrayIndex != GL_INVALID_INDEX) |
| { |
| fullNameStr << "[" << arrayIndex << "]"; |
| } |
| return fullNameStr.str(); |
| } |
| |
| // Transform feedback varyings can be only referenced in the VS. |
| bool vertexOnly() const |
| { |
| return frontVarying.stage == ShaderType::Vertex && backVarying.varying == nullptr; |
| } |
| |
| // Special handling for GS/TS array inputs. |
| unsigned int getBasicTypeElementCount() const; |
| |
| VaryingInShaderRef frontVarying; |
| VaryingInShaderRef backVarying; |
| |
| // Cached so we can store sh::ShaderVariable to point to varying fields. |
| sh::InterpolationType interpolation; |
| |
| // Used by varyings that are captured with transform feedback, xor arrays of shader I/O blocks, |
| // distinguished by isTransformFeedback; |
| GLuint arrayIndex; |
| bool isTransformFeedback; |
| |
| // Field index in the struct. In Vulkan, this is used to assign a |
| // struct-typed varying location to the location of its first field. |
| GLuint fieldIndex; |
| GLuint secondaryFieldIndex; |
| }; |
| |
| struct PackedVaryingRegister final |
| { |
| PackedVaryingRegister() |
| : packedVarying(nullptr), |
| varyingArrayIndex(0), |
| varyingRowIndex(0), |
| registerRow(0), |
| registerColumn(0) |
| {} |
| |
| PackedVaryingRegister(const PackedVaryingRegister &) = default; |
| PackedVaryingRegister &operator=(const PackedVaryingRegister &) = default; |
| |
| bool operator<(const PackedVaryingRegister &other) const |
| { |
| return sortOrder() < other.sortOrder(); |
| } |
| |
| unsigned int sortOrder() const |
| { |
| // TODO(jmadill): Handle interpolation types |
| return registerRow * 4 + registerColumn; |
| } |
| |
| std::string tfVaryingName() const |
| { |
| return packedVarying->fullName(packedVarying->frontVarying.stage); |
| } |
| |
| // Index to the array of varyings. |
| const PackedVarying *packedVarying; |
| |
| // The array element of the packed varying. |
| unsigned int varyingArrayIndex; |
| |
| // The row of the array element of the packed varying. |
| unsigned int varyingRowIndex; |
| |
| // The register row to which we've assigned this packed varying. |
| unsigned int registerRow; |
| |
| // The column of the register row into which we've packed this varying. |
| unsigned int registerColumn; |
| }; |
| |
| // Supported packing modes: |
| enum class PackMode |
| { |
| // We treat mat2 arrays as taking two full rows. |
| WEBGL_STRICT, |
| |
| // We allow mat2 to take a 2x2 chunk. |
| ANGLE_RELAXED, |
| |
| // Each varying takes a separate register. No register sharing. |
| ANGLE_NON_CONFORMANT_D3D9, |
| }; |
| |
| class VaryingPacking final : angle::NonCopyable |
| { |
| public: |
| VaryingPacking(); |
| ~VaryingPacking(); |
| |
| ANGLE_NO_DISCARD bool collectAndPackUserVaryings(InfoLog &infoLog, |
| GLint maxVaryingVectors, |
| PackMode packMode, |
| ShaderType frontShaderStage, |
| ShaderType backShaderStage, |
| const ProgramMergedVaryings &mergedVaryings, |
| const std::vector<std::string> &tfVaryings, |
| const bool isSeparableProgram); |
| |
| struct Register |
| { |
| Register() { data[0] = data[1] = data[2] = data[3] = false; } |
| |
| bool &operator[](unsigned int index) { return data[index]; } |
| bool operator[](unsigned int index) const { return data[index]; } |
| |
| bool data[4]; |
| }; |
| |
| Register &operator[](unsigned int index) { return mRegisterMap[index]; } |
| const Register &operator[](unsigned int index) const { return mRegisterMap[index]; } |
| |
| const std::vector<PackedVaryingRegister> &getRegisterList() const { return mRegisterList; } |
| unsigned int getMaxSemanticIndex() const |
| { |
| return static_cast<unsigned int>(mRegisterList.size()); |
| } |
| |
| const ShaderMap<std::vector<std::string>> &getInactiveVaryingMappedNames() const |
| { |
| return mInactiveVaryingMappedNames; |
| } |
| |
| const ShaderMap<std::vector<std::string>> &getActiveOutputBuiltInNames() const |
| { |
| return mActiveOutputBuiltIns; |
| } |
| |
| void reset(); |
| |
| private: |
| using VaryingUniqueFullNames = ShaderMap<std::set<std::string>>; |
| |
| // Register map functions. |
| bool packUserVaryings(InfoLog &infoLog, |
| GLint maxVaryingVectors, |
| PackMode packMode, |
| const std::vector<PackedVarying> &packedVaryings); |
| bool packVaryingIntoRegisterMap(PackMode packMode, const PackedVarying &packedVarying); |
| bool isRegisterRangeFree(unsigned int registerRow, |
| unsigned int registerColumn, |
| unsigned int varyingRows, |
| unsigned int varyingColumns) const; |
| void insertVaryingIntoRegisterMap(unsigned int registerRow, |
| unsigned int registerColumn, |
| unsigned int varyingColumns, |
| const PackedVarying &packedVarying); |
| void clearRegisterMap(); |
| |
| // Collection functions. |
| void collectUserVarying(const ProgramVaryingRef &ref, VaryingUniqueFullNames *uniqueFullNames); |
| void collectUserVaryingField(const ProgramVaryingRef &ref, |
| GLuint arrayIndex, |
| GLuint fieldIndex, |
| GLuint secondaryFieldIndex, |
| VaryingUniqueFullNames *uniqueFullNames); |
| void collectUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript); |
| void collectUserVaryingFieldTF(const ProgramVaryingRef &ref, |
| const sh::ShaderVariable &field, |
| GLuint fieldIndex, |
| GLuint secondaryFieldIndex); |
| void collectVarying(const sh::ShaderVariable &varying, |
| const ProgramVaryingRef &ref, |
| PackMode packMode, |
| VaryingUniqueFullNames *uniqueFullNames); |
| void collectTFVarying(const std::string &tfVarying, |
| const ProgramVaryingRef &ref, |
| VaryingUniqueFullNames *uniqueFullNames); |
| |
| std::vector<Register> mRegisterMap; |
| std::vector<PackedVaryingRegister> mRegisterList; |
| std::vector<PackedVarying> mPackedVaryings; |
| ShaderMap<std::vector<std::string>> mInactiveVaryingMappedNames; |
| ShaderMap<std::vector<std::string>> mActiveOutputBuiltIns; |
| }; |
| |
| class ProgramVaryingPacking final : angle::NonCopyable |
| { |
| public: |
| ProgramVaryingPacking(); |
| ~ProgramVaryingPacking(); |
| |
| const VaryingPacking &getInputPacking(ShaderType backShaderStage) const; |
| const VaryingPacking &getOutputPacking(ShaderType frontShaderStage) const; |
| |
| ANGLE_NO_DISCARD bool collectAndPackUserVaryings(InfoLog &infoLog, |
| const Caps &caps, |
| PackMode packMode, |
| const ShaderBitSet &activeShadersMask, |
| const ProgramMergedVaryings &mergedVaryings, |
| const std::vector<std::string> &tfVaryings, |
| bool isSeparableProgram); |
| |
| private: |
| // Indexed by the front shader. |
| ShaderMap<VaryingPacking> mVaryingPackings; |
| |
| // Looks up the front stage from the back stage. |
| ShaderMap<ShaderType> mBackToFrontStageMap; |
| }; |
| |
| ProgramMergedVaryings GetMergedVaryingsFromLinkingVariables( |
| const LinkingVariables &linkingVariables); |
| } // namespace gl |
| |
| #endif // LIBANGLE_VARYINGPACKING_H_ |