• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 struct ProgramVaryingRef;
27 
28 using ProgramMergedVaryings = std::vector<ProgramVaryingRef>;
29 
30 // A varying can have different names between stages if matched by the location layout qualifier.
31 // Additionally, same name varyings could still be of two identical struct types with different
32 // names.  This struct contains information on the varying in one of the two stages.  PackedVarying
33 // will thus contain two copies of this along with common information, such as interpolation or
34 // field index.
35 struct VaryingInShaderRef : angle::NonCopyable
36 {
37     VaryingInShaderRef(ShaderType stageIn, const sh::ShaderVariable *varyingIn);
38     VaryingInShaderRef(VaryingInShaderRef &&other);
39     ~VaryingInShaderRef();
40 
41     VaryingInShaderRef &operator=(VaryingInShaderRef &&other);
42 
43     const sh::ShaderVariable *varying;
44 
45     ShaderType stage;
46 
47     // Struct name
48     std::string parentStructName;
49     std::string parentStructMappedName;
50 };
51 
52 struct PackedVarying : angle::NonCopyable
53 {
54     // Throughout this file, the "front" stage refers to the stage that outputs the varying, and the
55     // "back" stage refers to the stage that takes the varying as input.  Note that this struct
56     // contains linked varyings, which means both front and back stage varyings are valid, except
57     // for the following which may have only one valid stage.
58     //
59     //  - transform-feedback-captured varyings
60     //  - builtins
61     //  - separable program stages,
62     //
63     PackedVarying(VaryingInShaderRef &&frontVaryingIn,
64                   VaryingInShaderRef &&backVaryingIn,
65                   sh::InterpolationType interpolationIn);
66     PackedVarying(VaryingInShaderRef &&frontVaryingIn,
67                   VaryingInShaderRef &&backVaryingIn,
68                   sh::InterpolationType interpolationIn,
69                   GLuint fieldIndexIn);
70     PackedVarying(PackedVarying &&other);
71     ~PackedVarying();
72 
73     PackedVarying &operator=(PackedVarying &&other);
74 
isStructFieldPackedVarying75     bool isStructField() const
76     {
77         return frontVarying.varying ? !frontVarying.parentStructName.empty()
78                                     : !backVarying.parentStructName.empty();
79     }
80 
isArrayElementPackedVarying81     bool isArrayElement() const { return arrayIndex != GL_INVALID_INDEX; }
82 
83     // Return either front or back varying, whichever is available.  Only used when the name of the
84     // varying is not important, but only the type is interesting.
varyingPackedVarying85     const sh::ShaderVariable &varying() const
86     {
87         return frontVarying.varying ? *frontVarying.varying : *backVarying.varying;
88     }
89 
fullNamePackedVarying90     std::string fullName(ShaderType stage) const
91     {
92         ASSERT(stage == frontVarying.stage || stage == backVarying.stage);
93         const VaryingInShaderRef &varying =
94             stage == frontVarying.stage ? frontVarying : backVarying;
95 
96         std::stringstream fullNameStr;
97         if (isStructField())
98         {
99             fullNameStr << varying.parentStructName << ".";
100         }
101 
102         fullNameStr << varying.varying->name;
103         if (arrayIndex != GL_INVALID_INDEX)
104         {
105             fullNameStr << "[" << arrayIndex << "]";
106         }
107         return fullNameStr.str();
108     }
109 
110     // Transform feedback varyings can be only referenced in the VS.
vertexOnlyPackedVarying111     bool vertexOnly() const
112     {
113         return frontVarying.stage == ShaderType::Vertex && backVarying.varying == nullptr;
114     }
115 
116     VaryingInShaderRef frontVarying;
117     VaryingInShaderRef backVarying;
118 
119     // Cached so we can store sh::ShaderVariable to point to varying fields.
120     sh::InterpolationType interpolation;
121 
122     GLuint arrayIndex;
123 
124     // Field index in the struct.  In Vulkan, this is used to assign a
125     // struct-typed varying location to the location of its first field.
126     GLuint fieldIndex;
127 };
128 
129 struct PackedVaryingRegister final
130 {
PackedVaryingRegisterfinal131     PackedVaryingRegister()
132         : packedVarying(nullptr),
133           varyingArrayIndex(0),
134           varyingRowIndex(0),
135           registerRow(0),
136           registerColumn(0)
137     {}
138 
139     PackedVaryingRegister(const PackedVaryingRegister &) = default;
140     PackedVaryingRegister &operator=(const PackedVaryingRegister &) = default;
141 
142     bool operator<(const PackedVaryingRegister &other) const
143     {
144         return sortOrder() < other.sortOrder();
145     }
146 
sortOrderfinal147     unsigned int sortOrder() const
148     {
149         // TODO(jmadill): Handle interpolation types
150         return registerRow * 4 + registerColumn;
151     }
152 
tfVaryingNamefinal153     std::string tfVaryingName() const
154     {
155         return packedVarying->fullName(packedVarying->frontVarying.stage);
156     }
157 
158     // Index to the array of varyings.
159     const PackedVarying *packedVarying;
160 
161     // The array element of the packed varying.
162     unsigned int varyingArrayIndex;
163 
164     // The row of the array element of the packed varying.
165     unsigned int varyingRowIndex;
166 
167     // The register row to which we've assigned this packed varying.
168     unsigned int registerRow;
169 
170     // The column of the register row into which we've packed this varying.
171     unsigned int registerColumn;
172 };
173 
174 // Supported packing modes:
175 enum class PackMode
176 {
177     // We treat mat2 arrays as taking two full rows.
178     WEBGL_STRICT,
179 
180     // We allow mat2 to take a 2x2 chunk.
181     ANGLE_RELAXED,
182 
183     // Each varying takes a separate register. No register sharing.
184     ANGLE_NON_CONFORMANT_D3D9,
185 };
186 
187 class VaryingPacking final : angle::NonCopyable
188 {
189   public:
190     VaryingPacking(GLuint maxVaryingVectors, PackMode packMode);
191     ~VaryingPacking();
192 
193     bool packUserVaryings(gl::InfoLog &infoLog, const std::vector<PackedVarying> &packedVaryings);
194 
195     bool collectAndPackUserVaryings(gl::InfoLog &infoLog,
196                                     const ProgramMergedVaryings &mergedVaryings,
197                                     const std::vector<std::string> &tfVaryings,
198                                     const bool isSeparableProgram);
199 
200     struct Register
201     {
RegisterRegister202         Register() { data[0] = data[1] = data[2] = data[3] = false; }
203 
204         bool &operator[](unsigned int index) { return data[index]; }
205         bool operator[](unsigned int index) const { return data[index]; }
206 
207         bool data[4];
208     };
209 
210     Register &operator[](unsigned int index) { return mRegisterMap[index]; }
211     const Register &operator[](unsigned int index) const { return mRegisterMap[index]; }
212 
getRegisterList()213     const std::vector<PackedVaryingRegister> &getRegisterList() const { return mRegisterList; }
getMaxSemanticIndex()214     unsigned int getMaxSemanticIndex() const
215     {
216         return static_cast<unsigned int>(mRegisterList.size());
217     }
218 
getInactiveVaryingMappedNames()219     const ShaderMap<std::vector<std::string>> &getInactiveVaryingMappedNames() const
220     {
221         return mInactiveVaryingMappedNames;
222     }
223 
224     void reset();
225 
226   private:
227     bool packVarying(const PackedVarying &packedVarying);
228     bool isFree(unsigned int registerRow,
229                 unsigned int registerColumn,
230                 unsigned int varyingRows,
231                 unsigned int varyingColumns) const;
232     void insert(unsigned int registerRow,
233                 unsigned int registerColumn,
234                 const PackedVarying &packedVarying);
235 
236     using VaryingUniqueFullNames = ShaderMap<std::set<std::string>>;
237     void packUserVarying(const ProgramVaryingRef &ref, VaryingUniqueFullNames *uniqueFullNames);
238     void packUserVaryingField(const ProgramVaryingRef &ref,
239                               GLuint fieldIndex,
240                               VaryingUniqueFullNames *uniqueFullNames);
241     void packUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript);
242     void packUserVaryingFieldTF(const ProgramVaryingRef &ref,
243                                 const sh::ShaderVariable &field,
244                                 GLuint fieldIndex);
245 
246     void clearRegisterMap();
247 
248     std::vector<Register> mRegisterMap;
249     std::vector<PackedVaryingRegister> mRegisterList;
250     std::vector<PackedVarying> mPackedVaryings;
251     ShaderMap<std::vector<std::string>> mInactiveVaryingMappedNames;
252 
253     PackMode mPackMode;
254 };
255 
256 }  // namespace gl
257 
258 #endif  // LIBANGLE_VARYINGPACKING_H_
259