// // 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 #include "angle_gl.h" #include "common/angleutils.h" #include "libANGLE/angletypes.h" #include namespace gl { class HasAttachedShaders; class InfoLog; class ProgramExecutable; struct Caps; struct ProgramVaryingRef; using ProgramMergedVaryings = std::vector; // 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 &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 &getRegisterList() const { return mRegisterList; } unsigned int getMaxSemanticIndex() const { return static_cast(mRegisterList.size()); } const ShaderMap> &getInactiveVaryingMappedNames() const { return mInactiveVaryingMappedNames; } const ShaderMap> &getActiveOutputBuiltInNames() const { return mActiveOutputBuiltIns; } void reset(); private: using VaryingUniqueFullNames = ShaderMap>; // Register map functions. bool packUserVaryings(InfoLog &infoLog, GLint maxVaryingVectors, PackMode packMode, const std::vector &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 mRegisterMap; std::vector mRegisterList; std::vector mPackedVaryings; ShaderMap> mInactiveVaryingMappedNames; ShaderMap> 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 &tfVaryings, bool isSeparableProgram); private: // Indexed by the front shader. ShaderMap mVaryingPackings; // Looks up the front stage from the back stage. ShaderMap mBackToFrontStageMap; }; // Takes an abstract handle to a program or pipeline. ProgramMergedVaryings GetMergedVaryingsFromShaders(const HasAttachedShaders &programOrPipeline, const ProgramExecutable &programExecutable); } // namespace gl #endif // LIBANGLE_VARYINGPACKING_H_