1 // 2 // Copyright 2015 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 // VaryingPacking: 7 // Class which describes a mapping from varyings to registers, according 8 // to the spec, or using custom packing algorithms. We also keep a register 9 // allocation list for the D3D renderer. 10 // 11 12 #ifndef LIBANGLE_VARYINGPACKING_H_ 13 #define LIBANGLE_VARYINGPACKING_H_ 14 15 #include <GLSLANG/ShaderVars.h> 16 17 #include "angle_gl.h" 18 #include "common/angleutils.h" 19 #include "libANGLE/angletypes.h" 20 21 #include <map> 22 23 namespace gl 24 { 25 class InfoLog; 26 class ProgramExecutable; 27 struct Caps; 28 struct LinkingVariables; 29 struct ProgramVaryingRef; 30 31 using ProgramMergedVaryings = std::vector<ProgramVaryingRef>; 32 33 // A varying can have different names between stages if matched by the location layout qualifier. 34 // Additionally, same name varyings could still be of two identical struct types with different 35 // names. This struct contains information on the varying in one of the two stages. PackedVarying 36 // will thus contain two copies of this along with common information, such as interpolation or 37 // field index. 38 struct VaryingInShaderRef : angle::NonCopyable 39 { 40 VaryingInShaderRef(ShaderType stageIn, const sh::ShaderVariable *varyingIn); 41 VaryingInShaderRef(VaryingInShaderRef &&other); 42 ~VaryingInShaderRef(); 43 44 VaryingInShaderRef &operator=(VaryingInShaderRef &&other); 45 46 const sh::ShaderVariable *varying; 47 48 ShaderType stage; 49 50 // Struct name 51 std::string parentStructName; 52 }; 53 54 struct PackedVarying : angle::NonCopyable 55 { 56 // Throughout this file, the "front" stage refers to the stage that outputs the varying, and the 57 // "back" stage refers to the stage that takes the varying as input. Note that this struct 58 // contains linked varyings, which means both front and back stage varyings are valid, except 59 // for the following which may have only one valid stage. 60 // 61 // - transform-feedback-captured varyings 62 // - builtins 63 // - separable program stages, 64 // 65 PackedVarying(VaryingInShaderRef &&frontVaryingIn, 66 VaryingInShaderRef &&backVaryingIn, 67 sh::InterpolationType interpolationIn); 68 PackedVarying(VaryingInShaderRef &&frontVaryingIn, 69 VaryingInShaderRef &&backVaryingIn, 70 sh::InterpolationType interpolationIn, 71 GLuint arrayIndexIn, 72 GLuint fieldIndexIn, 73 GLuint secondaryFieldIndexIn); 74 PackedVarying(PackedVarying &&other); 75 ~PackedVarying(); 76 77 PackedVarying &operator=(PackedVarying &&other); 78 isStructFieldPackedVarying79 bool isStructField() const 80 { 81 return frontVarying.varying ? !frontVarying.parentStructName.empty() 82 : !backVarying.parentStructName.empty(); 83 } 84 isTransformFeedbackArrayElementPackedVarying85 bool isTransformFeedbackArrayElement() const 86 { 87 return isTransformFeedback && arrayIndex != GL_INVALID_INDEX; 88 } 89 90 // Return either front or back varying, whichever is available. Only used when the name of the 91 // varying is not important, but only the type is interesting. varyingPackedVarying92 const sh::ShaderVariable &varying() const 93 { 94 return frontVarying.varying ? *frontVarying.varying : *backVarying.varying; 95 } 96 getParentStructNamePackedVarying97 const std::string &getParentStructName() const 98 { 99 ASSERT(isStructField()); 100 return frontVarying.varying ? frontVarying.parentStructName : backVarying.parentStructName; 101 } 102 fullNamePackedVarying103 std::string fullName(ShaderType stage) const 104 { 105 ASSERT(stage == frontVarying.stage || stage == backVarying.stage); 106 const VaryingInShaderRef &varying = 107 stage == frontVarying.stage ? frontVarying : backVarying; 108 109 std::stringstream fullNameStr; 110 if (isStructField()) 111 { 112 fullNameStr << varying.parentStructName << "."; 113 } 114 115 fullNameStr << varying.varying->name; 116 if (arrayIndex != GL_INVALID_INDEX) 117 { 118 fullNameStr << "[" << arrayIndex << "]"; 119 } 120 return fullNameStr.str(); 121 } 122 123 // Transform feedback varyings can be only referenced in the VS. vertexOnlyPackedVarying124 bool vertexOnly() const 125 { 126 return frontVarying.stage == ShaderType::Vertex && backVarying.varying == nullptr; 127 } 128 129 // Special handling for GS/TS array inputs. 130 unsigned int getBasicTypeElementCount() const; 131 132 VaryingInShaderRef frontVarying; 133 VaryingInShaderRef backVarying; 134 135 // Cached so we can store sh::ShaderVariable to point to varying fields. 136 sh::InterpolationType interpolation; 137 138 // Used by varyings that are captured with transform feedback, xor arrays of shader I/O blocks, 139 // distinguished by isTransformFeedback; 140 GLuint arrayIndex; 141 bool isTransformFeedback; 142 143 // Field index in the struct. In Vulkan, this is used to assign a 144 // struct-typed varying location to the location of its first field. 145 GLuint fieldIndex; 146 GLuint secondaryFieldIndex; 147 }; 148 149 struct PackedVaryingRegister final 150 { PackedVaryingRegisterfinal151 PackedVaryingRegister() 152 : packedVarying(nullptr), 153 varyingArrayIndex(0), 154 varyingRowIndex(0), 155 registerRow(0), 156 registerColumn(0) 157 {} 158 159 PackedVaryingRegister(const PackedVaryingRegister &) = default; 160 PackedVaryingRegister &operator=(const PackedVaryingRegister &) = default; 161 162 bool operator<(const PackedVaryingRegister &other) const 163 { 164 return sortOrder() < other.sortOrder(); 165 } 166 sortOrderfinal167 unsigned int sortOrder() const 168 { 169 // TODO(jmadill): Handle interpolation types 170 return registerRow * 4 + registerColumn; 171 } 172 tfVaryingNamefinal173 std::string tfVaryingName() const 174 { 175 return packedVarying->fullName(packedVarying->frontVarying.stage); 176 } 177 178 // Index to the array of varyings. 179 const PackedVarying *packedVarying; 180 181 // The array element of the packed varying. 182 unsigned int varyingArrayIndex; 183 184 // The row of the array element of the packed varying. 185 unsigned int varyingRowIndex; 186 187 // The register row to which we've assigned this packed varying. 188 unsigned int registerRow; 189 190 // The column of the register row into which we've packed this varying. 191 unsigned int registerColumn; 192 }; 193 194 // Supported packing modes: 195 enum class PackMode 196 { 197 // We treat mat2 arrays as taking two full rows. 198 WEBGL_STRICT, 199 200 // We allow mat2 to take a 2x2 chunk. 201 ANGLE_RELAXED, 202 203 // Each varying takes a separate register. No register sharing. 204 ANGLE_NON_CONFORMANT_D3D9, 205 }; 206 207 enum class PerVertexMember 208 { 209 // The gl_Pervertex struct is defined as: 210 // 211 // out gl_PerVertex 212 // { 213 // vec4 gl_Position; 214 // float gl_PointSize; 215 // float gl_ClipDistance[]; 216 // float gl_CullDistance[]; 217 // }; 218 Position, 219 PointSize, 220 ClipDistance, 221 CullDistance, 222 223 EnumCount, 224 InvalidEnum = EnumCount, 225 }; 226 using PerVertexMemberBitSet = angle::PackedEnumBitSet<PerVertexMember, uint8_t>; 227 228 class VaryingPacking final : angle::NonCopyable 229 { 230 public: 231 VaryingPacking(); 232 ~VaryingPacking(); 233 234 [[nodiscard]] bool collectAndPackUserVaryings(InfoLog &infoLog, 235 GLint maxVaryingVectors, 236 PackMode packMode, 237 ShaderType frontShaderStage, 238 ShaderType backShaderStage, 239 const ProgramMergedVaryings &mergedVaryings, 240 const std::vector<std::string> &tfVaryings, 241 const bool isSeparableProgram); 242 243 struct Register 244 { RegisterRegister245 Register() { data[0] = data[1] = data[2] = data[3] = false; } 246 247 bool &operator[](unsigned int index) { return data[index]; } 248 bool operator[](unsigned int index) const { return data[index]; } 249 250 bool data[4]; 251 }; 252 253 Register &operator[](unsigned int index) { return mRegisterMap[index]; } 254 const Register &operator[](unsigned int index) const { return mRegisterMap[index]; } 255 getRegisterList()256 const std::vector<PackedVaryingRegister> &getRegisterList() const { return mRegisterList; } getMaxSemanticIndex()257 unsigned int getMaxSemanticIndex() const 258 { 259 return static_cast<unsigned int>(mRegisterList.size()); 260 } 261 getInactiveVaryingIds()262 const ShaderMap<std::vector<uint32_t>> &getInactiveVaryingIds() const 263 { 264 return mInactiveVaryingIds; 265 } 266 getOutputPerVertexActiveMembers()267 const ShaderMap<PerVertexMemberBitSet> &getOutputPerVertexActiveMembers() const 268 { 269 return mOutputPerVertexActiveMembers; 270 } 271 272 void reset(); 273 274 private: 275 using VaryingUniqueFullNames = ShaderMap<std::set<std::string>>; 276 277 // Register map functions. 278 bool packUserVaryings(InfoLog &infoLog, 279 GLint maxVaryingVectors, 280 PackMode packMode, 281 const std::vector<PackedVarying> &packedVaryings); 282 bool packVaryingIntoRegisterMap(PackMode packMode, const PackedVarying &packedVarying); 283 bool isRegisterRangeFree(unsigned int registerRow, 284 unsigned int registerColumn, 285 unsigned int varyingRows, 286 unsigned int varyingColumns) const; 287 void insertVaryingIntoRegisterMap(unsigned int registerRow, 288 unsigned int registerColumn, 289 unsigned int varyingColumns, 290 const PackedVarying &packedVarying); 291 void clearRegisterMap(); 292 293 // Collection functions. 294 void collectUserVarying(const ProgramVaryingRef &ref, VaryingUniqueFullNames *uniqueFullNames); 295 void collectUserVaryingField(const ProgramVaryingRef &ref, 296 GLuint arrayIndex, 297 GLuint fieldIndex, 298 GLuint secondaryFieldIndex, 299 VaryingUniqueFullNames *uniqueFullNames); 300 void collectUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript); 301 void collectUserVaryingFieldTF(const ProgramVaryingRef &ref, 302 const sh::ShaderVariable &field, 303 GLuint fieldIndex, 304 GLuint secondaryFieldIndex); 305 void collectVarying(const sh::ShaderVariable &varying, 306 const ProgramVaryingRef &ref, 307 PackMode packMode, 308 VaryingUniqueFullNames *uniqueFullNames); 309 void collectTFVarying(const std::string &tfVarying, 310 const ProgramVaryingRef &ref, 311 VaryingUniqueFullNames *uniqueFullNames); 312 313 std::vector<Register> mRegisterMap; 314 std::vector<PackedVaryingRegister> mRegisterList; 315 std::vector<PackedVarying> mPackedVaryings; 316 ShaderMap<std::vector<uint32_t>> mInactiveVaryingIds; 317 ShaderMap<PerVertexMemberBitSet> mOutputPerVertexActiveMembers; 318 }; 319 320 class ProgramVaryingPacking final : angle::NonCopyable 321 { 322 public: 323 ProgramVaryingPacking(); 324 ~ProgramVaryingPacking(); 325 326 const VaryingPacking &getInputPacking(ShaderType backShaderStage) const; 327 const VaryingPacking &getOutputPacking(ShaderType frontShaderStage) const; 328 329 [[nodiscard]] bool collectAndPackUserVaryings(InfoLog &infoLog, 330 const Caps &caps, 331 PackMode packMode, 332 const ShaderBitSet &activeShadersMask, 333 const ProgramMergedVaryings &mergedVaryings, 334 const std::vector<std::string> &tfVaryings, 335 bool isSeparableProgram); 336 337 private: 338 // Indexed by the front shader. 339 ShaderMap<VaryingPacking> mVaryingPackings; 340 341 // Looks up the front stage from the back stage. 342 ShaderMap<ShaderType> mBackToFrontStageMap; 343 }; 344 345 ProgramMergedVaryings GetMergedVaryingsFromLinkingVariables( 346 const LinkingVariables &linkingVariables); 347 } // namespace gl 348 349 #endif // LIBANGLE_VARYINGPACKING_H_ 350