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