• 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 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