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 HasAttachedShaders; 26 class InfoLog; 27 class ProgramExecutable; 28 struct Caps; 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 std::string parentStructMappedName; 53 }; 54 55 struct PackedVarying : angle::NonCopyable 56 { 57 // Throughout this file, the "front" stage refers to the stage that outputs the varying, and the 58 // "back" stage refers to the stage that takes the varying as input. Note that this struct 59 // contains linked varyings, which means both front and back stage varyings are valid, except 60 // for the following which may have only one valid stage. 61 // 62 // - transform-feedback-captured varyings 63 // - builtins 64 // - separable program stages, 65 // 66 PackedVarying(VaryingInShaderRef &&frontVaryingIn, 67 VaryingInShaderRef &&backVaryingIn, 68 sh::InterpolationType interpolationIn); 69 PackedVarying(VaryingInShaderRef &&frontVaryingIn, 70 VaryingInShaderRef &&backVaryingIn, 71 sh::InterpolationType interpolationIn, 72 GLuint arrayIndexIn, 73 GLuint fieldIndexIn, 74 GLuint secondaryFieldIndexIn); 75 PackedVarying(PackedVarying &&other); 76 ~PackedVarying(); 77 78 PackedVarying &operator=(PackedVarying &&other); 79 isStructFieldPackedVarying80 bool isStructField() const 81 { 82 return frontVarying.varying ? !frontVarying.parentStructName.empty() 83 : !backVarying.parentStructName.empty(); 84 } 85 isTransformFeedbackArrayElementPackedVarying86 bool isTransformFeedbackArrayElement() const 87 { 88 return isTransformFeedback && arrayIndex != GL_INVALID_INDEX; 89 } 90 91 // Return either front or back varying, whichever is available. Only used when the name of the 92 // varying is not important, but only the type is interesting. varyingPackedVarying93 const sh::ShaderVariable &varying() const 94 { 95 return frontVarying.varying ? *frontVarying.varying : *backVarying.varying; 96 } 97 getParentStructNamePackedVarying98 const std::string &getParentStructName() const 99 { 100 ASSERT(isStructField()); 101 return frontVarying.varying ? frontVarying.parentStructName : backVarying.parentStructName; 102 } 103 fullNamePackedVarying104 std::string fullName(ShaderType stage) const 105 { 106 ASSERT(stage == frontVarying.stage || stage == backVarying.stage); 107 const VaryingInShaderRef &varying = 108 stage == frontVarying.stage ? frontVarying : backVarying; 109 110 std::stringstream fullNameStr; 111 if (isStructField()) 112 { 113 fullNameStr << varying.parentStructName << "."; 114 } 115 116 fullNameStr << varying.varying->name; 117 if (arrayIndex != GL_INVALID_INDEX) 118 { 119 fullNameStr << "[" << arrayIndex << "]"; 120 } 121 return fullNameStr.str(); 122 } 123 124 // Transform feedback varyings can be only referenced in the VS. vertexOnlyPackedVarying125 bool vertexOnly() const 126 { 127 return frontVarying.stage == ShaderType::Vertex && backVarying.varying == nullptr; 128 } 129 130 // Special handling for GS/TS array inputs. 131 unsigned int getBasicTypeElementCount() const; 132 133 VaryingInShaderRef frontVarying; 134 VaryingInShaderRef backVarying; 135 136 // Cached so we can store sh::ShaderVariable to point to varying fields. 137 sh::InterpolationType interpolation; 138 139 // Used by varyings that are captured with transform feedback, xor arrays of shader I/O blocks, 140 // distinguished by isTransformFeedback; 141 GLuint arrayIndex; 142 bool isTransformFeedback; 143 144 // Field index in the struct. In Vulkan, this is used to assign a 145 // struct-typed varying location to the location of its first field. 146 GLuint fieldIndex; 147 GLuint secondaryFieldIndex; 148 }; 149 150 struct PackedVaryingRegister final 151 { PackedVaryingRegisterfinal152 PackedVaryingRegister() 153 : packedVarying(nullptr), 154 varyingArrayIndex(0), 155 varyingRowIndex(0), 156 registerRow(0), 157 registerColumn(0) 158 {} 159 160 PackedVaryingRegister(const PackedVaryingRegister &) = default; 161 PackedVaryingRegister &operator=(const PackedVaryingRegister &) = default; 162 163 bool operator<(const PackedVaryingRegister &other) const 164 { 165 return sortOrder() < other.sortOrder(); 166 } 167 sortOrderfinal168 unsigned int sortOrder() const 169 { 170 // TODO(jmadill): Handle interpolation types 171 return registerRow * 4 + registerColumn; 172 } 173 tfVaryingNamefinal174 std::string tfVaryingName() const 175 { 176 return packedVarying->fullName(packedVarying->frontVarying.stage); 177 } 178 179 // Index to the array of varyings. 180 const PackedVarying *packedVarying; 181 182 // The array element of the packed varying. 183 unsigned int varyingArrayIndex; 184 185 // The row of the array element of the packed varying. 186 unsigned int varyingRowIndex; 187 188 // The register row to which we've assigned this packed varying. 189 unsigned int registerRow; 190 191 // The column of the register row into which we've packed this varying. 192 unsigned int registerColumn; 193 }; 194 195 // Supported packing modes: 196 enum class PackMode 197 { 198 // We treat mat2 arrays as taking two full rows. 199 WEBGL_STRICT, 200 201 // We allow mat2 to take a 2x2 chunk. 202 ANGLE_RELAXED, 203 204 // Each varying takes a separate register. No register sharing. 205 ANGLE_NON_CONFORMANT_D3D9, 206 }; 207 208 class VaryingPacking final : angle::NonCopyable 209 { 210 public: 211 VaryingPacking(); 212 ~VaryingPacking(); 213 214 ANGLE_NO_DISCARD bool collectAndPackUserVaryings(InfoLog &infoLog, 215 GLint maxVaryingVectors, 216 PackMode packMode, 217 ShaderType frontShaderStage, 218 ShaderType backShaderStage, 219 const ProgramMergedVaryings &mergedVaryings, 220 const std::vector<std::string> &tfVaryings, 221 const bool isSeparableProgram); 222 223 struct Register 224 { RegisterRegister225 Register() { data[0] = data[1] = data[2] = data[3] = false; } 226 227 bool &operator[](unsigned int index) { return data[index]; } 228 bool operator[](unsigned int index) const { return data[index]; } 229 230 bool data[4]; 231 }; 232 233 Register &operator[](unsigned int index) { return mRegisterMap[index]; } 234 const Register &operator[](unsigned int index) const { return mRegisterMap[index]; } 235 getRegisterList()236 const std::vector<PackedVaryingRegister> &getRegisterList() const { return mRegisterList; } getMaxSemanticIndex()237 unsigned int getMaxSemanticIndex() const 238 { 239 return static_cast<unsigned int>(mRegisterList.size()); 240 } 241 getInactiveVaryingMappedNames()242 const ShaderMap<std::vector<std::string>> &getInactiveVaryingMappedNames() const 243 { 244 return mInactiveVaryingMappedNames; 245 } 246 getActiveOutputBuiltInNames()247 const ShaderMap<std::vector<std::string>> &getActiveOutputBuiltInNames() const 248 { 249 return mActiveOutputBuiltIns; 250 } 251 252 void reset(); 253 254 private: 255 using VaryingUniqueFullNames = ShaderMap<std::set<std::string>>; 256 257 // Register map functions. 258 bool packUserVaryings(InfoLog &infoLog, 259 GLint maxVaryingVectors, 260 PackMode packMode, 261 const std::vector<PackedVarying> &packedVaryings); 262 bool packVaryingIntoRegisterMap(PackMode packMode, const PackedVarying &packedVarying); 263 bool isRegisterRangeFree(unsigned int registerRow, 264 unsigned int registerColumn, 265 unsigned int varyingRows, 266 unsigned int varyingColumns) const; 267 void insertVaryingIntoRegisterMap(unsigned int registerRow, 268 unsigned int registerColumn, 269 unsigned int varyingColumns, 270 const PackedVarying &packedVarying); 271 void clearRegisterMap(); 272 273 // Collection functions. 274 void collectUserVarying(const ProgramVaryingRef &ref, VaryingUniqueFullNames *uniqueFullNames); 275 void collectUserVaryingField(const ProgramVaryingRef &ref, 276 GLuint arrayIndex, 277 GLuint fieldIndex, 278 GLuint secondaryFieldIndex, 279 VaryingUniqueFullNames *uniqueFullNames); 280 void collectUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript); 281 void collectUserVaryingFieldTF(const ProgramVaryingRef &ref, 282 const sh::ShaderVariable &field, 283 GLuint fieldIndex, 284 GLuint secondaryFieldIndex); 285 void collectVarying(const sh::ShaderVariable &varying, 286 const ProgramVaryingRef &ref, 287 PackMode packMode, 288 VaryingUniqueFullNames *uniqueFullNames); 289 void collectTFVarying(const std::string &tfVarying, 290 const ProgramVaryingRef &ref, 291 VaryingUniqueFullNames *uniqueFullNames); 292 293 std::vector<Register> mRegisterMap; 294 std::vector<PackedVaryingRegister> mRegisterList; 295 std::vector<PackedVarying> mPackedVaryings; 296 ShaderMap<std::vector<std::string>> mInactiveVaryingMappedNames; 297 ShaderMap<std::vector<std::string>> mActiveOutputBuiltIns; 298 }; 299 300 class ProgramVaryingPacking final : angle::NonCopyable 301 { 302 public: 303 ProgramVaryingPacking(); 304 ~ProgramVaryingPacking(); 305 306 const VaryingPacking &getInputPacking(ShaderType backShaderStage) const; 307 const VaryingPacking &getOutputPacking(ShaderType frontShaderStage) const; 308 309 ANGLE_NO_DISCARD bool collectAndPackUserVaryings(InfoLog &infoLog, 310 const Caps &caps, 311 PackMode packMode, 312 const ShaderBitSet &activeShadersMask, 313 const ProgramMergedVaryings &mergedVaryings, 314 const std::vector<std::string> &tfVaryings, 315 bool isSeparableProgram); 316 317 private: 318 // Indexed by the front shader. 319 ShaderMap<VaryingPacking> mVaryingPackings; 320 321 // Looks up the front stage from the back stage. 322 ShaderMap<ShaderType> mBackToFrontStageMap; 323 }; 324 325 // Takes an abstract handle to a program or pipeline. 326 ProgramMergedVaryings GetMergedVaryingsFromShaders(const HasAttachedShaders &programOrPipeline, 327 const ProgramExecutable &programExecutable); 328 } // namespace gl 329 330 #endif // LIBANGLE_VARYINGPACKING_H_ 331