• 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 #include "libANGLE/VaryingPacking.h"
13 
14 #include "common/CompiledShaderState.h"
15 #include "common/utilities.h"
16 #include "libANGLE/Program.h"
17 #include "libANGLE/ProgramExecutable.h"
18 #include "libANGLE/Shader.h"
19 
20 namespace gl
21 {
22 
23 namespace
24 {
25 // true if varying x has a higher priority in packing than y
ComparePackedVarying(const PackedVarying & x,const PackedVarying & y)26 bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
27 {
28     // If the PackedVarying 'x' or 'y' to be compared is an array element for transform feedback,
29     // this clones an equivalent non-array shader variable 'vx' or 'vy' for actual comparison
30     // instead.  For I/O block arrays, the array index is used in the comparison.
31     sh::ShaderVariable vx, vy;
32     const sh::ShaderVariable *px, *py;
33 
34     px = &x.varying();
35     py = &y.varying();
36 
37     if (x.isTransformFeedbackArrayElement())
38     {
39         vx = *px;
40         vx.arraySizes.clear();
41         px = &vx;
42     }
43 
44     if (y.isTransformFeedbackArrayElement())
45     {
46         vy = *py;
47         vy.arraySizes.clear();
48         py = &vy;
49     }
50 
51     // Make sure struct fields end up together.
52     if (x.isStructField() != y.isStructField())
53     {
54         return x.isStructField();
55     }
56 
57     if (x.isStructField())
58     {
59         ASSERT(y.isStructField());
60 
61         if (x.getParentStructName() != y.getParentStructName())
62         {
63             return x.getParentStructName() < y.getParentStructName();
64         }
65     }
66 
67     // For I/O block fields, order first by array index:
68     if (!x.isTransformFeedbackArrayElement() && !y.isTransformFeedbackArrayElement())
69     {
70         if (x.arrayIndex != y.arrayIndex)
71         {
72             return x.arrayIndex < y.arrayIndex;
73         }
74     }
75 
76     // Then order by field index
77     if (x.fieldIndex != y.fieldIndex)
78     {
79         return x.fieldIndex < y.fieldIndex;
80     }
81 
82     // Then order by secondary field index
83     if (x.secondaryFieldIndex != y.secondaryFieldIndex)
84     {
85         return x.secondaryFieldIndex < y.secondaryFieldIndex;
86     }
87 
88     // Otherwise order by variable
89     return gl::CompareShaderVar(*px, *py);
90 }
91 
InterfaceVariablesMatch(const sh::ShaderVariable & front,const sh::ShaderVariable & back)92 bool InterfaceVariablesMatch(const sh::ShaderVariable &front, const sh::ShaderVariable &back)
93 {
94     // Matching ruels from 7.4.1 Shader Interface Matching from the GLES 3.2 spec:
95     // - the two variables match in name, type, and qualification; or
96     // - the two variables are declared with the same location qualifier and match in type and
97     // qualification. Note that we use a more permissive check here thanks to front-end validation.
98     if (back.location != -1 && back.location == front.location)
99     {
100         return true;
101     }
102 
103     if (front.isShaderIOBlock != back.isShaderIOBlock)
104     {
105         return false;
106     }
107 
108     // Compare names, or if shader I/O blocks, block names.
109     const std::string &backName  = back.isShaderIOBlock ? back.structOrBlockName : back.name;
110     const std::string &frontName = front.isShaderIOBlock ? front.structOrBlockName : front.name;
111     return backName == frontName;
112 }
113 
GetMaxShaderInputVectors(const Caps & caps,ShaderType shaderStage)114 GLint GetMaxShaderInputVectors(const Caps &caps, ShaderType shaderStage)
115 {
116     switch (shaderStage)
117     {
118         case ShaderType::TessControl:
119             return caps.maxTessControlInputComponents / 4;
120         case ShaderType::TessEvaluation:
121             return caps.maxTessEvaluationInputComponents / 4;
122         case ShaderType::Geometry:
123             return caps.maxGeometryInputComponents / 4;
124         case ShaderType::Fragment:
125             return caps.maxFragmentInputComponents / 4;
126         default:
127             return std::numeric_limits<GLint>::max();
128     }
129 }
130 
GetMaxShaderOutputVectors(const Caps & caps,ShaderType shaderStage)131 GLint GetMaxShaderOutputVectors(const Caps &caps, ShaderType shaderStage)
132 {
133     switch (shaderStage)
134     {
135         case ShaderType::Vertex:
136             return caps.maxVertexOutputComponents / 4;
137         case ShaderType::TessControl:
138             return caps.maxTessControlOutputComponents / 4;
139         case ShaderType::TessEvaluation:
140             return caps.maxTessEvaluationOutputComponents / 4;
141         case ShaderType::Geometry:
142             return caps.maxGeometryOutputComponents / 4;
143         default:
144             return std::numeric_limits<GLint>::max();
145     }
146 }
147 
ShouldSkipPackedVarying(const sh::ShaderVariable & varying,PackMode packMode)148 bool ShouldSkipPackedVarying(const sh::ShaderVariable &varying, PackMode packMode)
149 {
150     // Don't pack gl_Position. Also don't count gl_PointSize for D3D9.
151     return varying.name == "gl_Position" ||
152            (varying.name == "gl_PointSize" && packMode == PackMode::ANGLE_NON_CONFORMANT_D3D9);
153 }
154 
StripVaryingArrayDimension(const sh::ShaderVariable * frontVarying,ShaderType frontShaderStage,const sh::ShaderVariable * backVarying,ShaderType backShaderStage,bool isStructField)155 std::vector<unsigned int> StripVaryingArrayDimension(const sh::ShaderVariable *frontVarying,
156                                                      ShaderType frontShaderStage,
157                                                      const sh::ShaderVariable *backVarying,
158                                                      ShaderType backShaderStage,
159                                                      bool isStructField)
160 {
161     // "Geometry shader inputs, tessellation control shader inputs and outputs, and tessellation
162     // evaluation inputs all have an additional level of arrayness relative to other shader inputs
163     // and outputs. This outer array level is removed from the type before considering how many
164     // locations the type consumes."
165 
166     if (backVarying && backVarying->isArray() && !backVarying->isPatch && !isStructField &&
167         (backShaderStage == ShaderType::Geometry || backShaderStage == ShaderType::TessEvaluation ||
168          backShaderStage == ShaderType::TessControl))
169     {
170         std::vector<unsigned int> arr = backVarying->arraySizes;
171         arr.pop_back();
172         return arr;
173     }
174 
175     if (frontVarying && frontVarying->isArray() && !frontVarying->isPatch && !isStructField &&
176         frontShaderStage == ShaderType::TessControl)
177     {
178         std::vector<unsigned int> arr = frontVarying->arraySizes;
179         arr.pop_back();
180         return arr;
181     }
182 
183     return frontVarying ? frontVarying->arraySizes : backVarying->arraySizes;
184 }
185 
GetPerVertexMember(const std::string & name)186 PerVertexMember GetPerVertexMember(const std::string &name)
187 {
188     if (name == "gl_Position")
189     {
190         return PerVertexMember::Position;
191     }
192     if (name == "gl_PointSize")
193     {
194         return PerVertexMember::PointSize;
195     }
196     if (name == "gl_ClipDistance")
197     {
198         return PerVertexMember::ClipDistance;
199     }
200     if (name == "gl_CullDistance")
201     {
202         return PerVertexMember::CullDistance;
203     }
204     return PerVertexMember::InvalidEnum;
205 }
206 
SetActivePerVertexMembers(const sh::ShaderVariable * var,PerVertexMemberBitSet * bitset)207 void SetActivePerVertexMembers(const sh::ShaderVariable *var, PerVertexMemberBitSet *bitset)
208 {
209     ASSERT(var->isBuiltIn() && var->active);
210 
211     // Only process gl_Position, gl_PointSize, gl_ClipDistance, gl_CullDistance and the fields of
212     // gl_in/out.
213     if (var->fields.empty())
214     {
215         PerVertexMember member = GetPerVertexMember(var->name);
216         // Skip gl_TessLevelInner/Outer etc.
217         if (member != PerVertexMember::InvalidEnum)
218         {
219             bitset->set(member);
220         }
221         return;
222     }
223 
224     // This must be gl_out.  Note that only `out gl_PerVertex` is processed; the input of the
225     // next stage is implicitly identically active.
226     ASSERT(var->name == "gl_out");
227     for (const sh::ShaderVariable &field : var->fields)
228     {
229         bitset->set(GetPerVertexMember(field.name));
230     }
231 }
232 }  // anonymous namespace
233 
234 // Implementation of VaryingInShaderRef
VaryingInShaderRef(ShaderType stageIn,const sh::ShaderVariable * varyingIn)235 VaryingInShaderRef::VaryingInShaderRef(ShaderType stageIn, const sh::ShaderVariable *varyingIn)
236     : varying(varyingIn), stage(stageIn)
237 {}
238 
239 VaryingInShaderRef::~VaryingInShaderRef() = default;
240 
VaryingInShaderRef(VaryingInShaderRef && other)241 VaryingInShaderRef::VaryingInShaderRef(VaryingInShaderRef &&other)
242     : varying(other.varying),
243       stage(other.stage),
244       parentStructName(std::move(other.parentStructName))
245 {}
246 
operator =(VaryingInShaderRef && other)247 VaryingInShaderRef &VaryingInShaderRef::operator=(VaryingInShaderRef &&other)
248 {
249     std::swap(varying, other.varying);
250     std::swap(stage, other.stage);
251     std::swap(parentStructName, other.parentStructName);
252 
253     return *this;
254 }
255 
256 // Implementation of PackedVarying
PackedVarying(VaryingInShaderRef && frontVaryingIn,VaryingInShaderRef && backVaryingIn,sh::InterpolationType interpolationIn)257 PackedVarying::PackedVarying(VaryingInShaderRef &&frontVaryingIn,
258                              VaryingInShaderRef &&backVaryingIn,
259                              sh::InterpolationType interpolationIn)
260     : PackedVarying(std::move(frontVaryingIn),
261                     std::move(backVaryingIn),
262                     interpolationIn,
263                     GL_INVALID_INDEX,
264                     0,
265                     0)
266 {}
267 
PackedVarying(VaryingInShaderRef && frontVaryingIn,VaryingInShaderRef && backVaryingIn,sh::InterpolationType interpolationIn,GLuint arrayIndexIn,GLuint fieldIndexIn,GLuint secondaryFieldIndexIn)268 PackedVarying::PackedVarying(VaryingInShaderRef &&frontVaryingIn,
269                              VaryingInShaderRef &&backVaryingIn,
270                              sh::InterpolationType interpolationIn,
271                              GLuint arrayIndexIn,
272                              GLuint fieldIndexIn,
273                              GLuint secondaryFieldIndexIn)
274     : frontVarying(std::move(frontVaryingIn)),
275       backVarying(std::move(backVaryingIn)),
276       interpolation(interpolationIn),
277       arrayIndex(arrayIndexIn),
278       isTransformFeedback(false),
279       fieldIndex(fieldIndexIn),
280       secondaryFieldIndex(secondaryFieldIndexIn)
281 {}
282 
283 PackedVarying::~PackedVarying() = default;
284 
PackedVarying(PackedVarying && other)285 PackedVarying::PackedVarying(PackedVarying &&other)
286     : frontVarying(std::move(other.frontVarying)),
287       backVarying(std::move(other.backVarying)),
288       interpolation(other.interpolation),
289       arrayIndex(other.arrayIndex),
290       isTransformFeedback(other.isTransformFeedback),
291       fieldIndex(other.fieldIndex),
292       secondaryFieldIndex(other.secondaryFieldIndex)
293 {}
294 
operator =(PackedVarying && other)295 PackedVarying &PackedVarying::operator=(PackedVarying &&other)
296 {
297     std::swap(frontVarying, other.frontVarying);
298     std::swap(backVarying, other.backVarying);
299     std::swap(interpolation, other.interpolation);
300     std::swap(arrayIndex, other.arrayIndex);
301     std::swap(isTransformFeedback, other.isTransformFeedback);
302     std::swap(fieldIndex, other.fieldIndex);
303     std::swap(secondaryFieldIndex, other.secondaryFieldIndex);
304 
305     return *this;
306 }
307 
getBasicTypeElementCount() const308 unsigned int PackedVarying::getBasicTypeElementCount() const
309 {
310     // "Geometry shader inputs, tessellation control shader inputs and outputs, and tessellation
311     // evaluation inputs all have an additional level of arrayness relative to other shader inputs
312     // and outputs. This outer array level is removed from the type before considering how many
313     // locations the type consumes."
314     std::vector<unsigned int> arr =
315         StripVaryingArrayDimension(frontVarying.varying, frontVarying.stage, backVarying.varying,
316                                    backVarying.stage, isStructField());
317     return arr.empty() ? 1u : arr.back();
318 }
319 
320 // Implementation of VaryingPacking
321 VaryingPacking::VaryingPacking() = default;
322 
323 VaryingPacking::~VaryingPacking() = default;
324 
reset()325 void VaryingPacking::reset()
326 {
327     clearRegisterMap();
328     mRegisterList.clear();
329     mPackedVaryings.clear();
330 
331     for (std::vector<uint32_t> &inactiveVaryingIds : mInactiveVaryingIds)
332     {
333         inactiveVaryingIds.clear();
334     }
335 
336     std::fill(mOutputPerVertexActiveMembers.begin(), mOutputPerVertexActiveMembers.end(),
337               gl::PerVertexMemberBitSet{});
338 }
339 
clearRegisterMap()340 void VaryingPacking::clearRegisterMap()
341 {
342     std::fill(mRegisterMap.begin(), mRegisterMap.end(), Register());
343 }
344 
345 // Packs varyings into generic varying registers, using the algorithm from
346 // See [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
347 // Also [OpenGL ES Shading Language 3.00 rev. 4] Section 11 page 119
348 // Returns false if unsuccessful.
packVaryingIntoRegisterMap(PackMode packMode,const PackedVarying & packedVarying)349 bool VaryingPacking::packVaryingIntoRegisterMap(PackMode packMode,
350                                                 const PackedVarying &packedVarying)
351 {
352     const sh::ShaderVariable &varying = packedVarying.varying();
353 
354     // "Non - square matrices of type matCxR consume the same space as a square matrix of type matN
355     // where N is the greater of C and R."
356     // Here we are a bit more conservative and allow packing non-square matrices more tightly.
357     // Make sure we use transposed matrix types to count registers correctly.
358     ASSERT(!varying.isStruct());
359     GLenum transposedType       = gl::TransposeMatrixType(varying.type);
360     unsigned int varyingRows    = gl::VariableRowCount(transposedType);
361     unsigned int varyingColumns = gl::VariableColumnCount(transposedType);
362 
363     // Special pack mode for D3D9. Each varying takes a full register, no sharing.
364     // TODO(jmadill): Implement more sophisticated component packing in D3D9.
365     if (packMode == PackMode::ANGLE_NON_CONFORMANT_D3D9)
366     {
367         varyingColumns = 4;
368     }
369 
370     // "Variables of type mat2 occupies 2 complete rows."
371     // For non-WebGL contexts, we allow mat2 to occupy only two columns per row.
372     else if (packMode == PackMode::WEBGL_STRICT && varying.type == GL_FLOAT_MAT2)
373     {
374         varyingColumns = 4;
375     }
376 
377     // "Arrays of size N are assumed to take N times the size of the base type"
378     // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
379     // structures, so we may use getBasicTypeElementCount().
380     const unsigned int elementCount = packedVarying.getBasicTypeElementCount();
381     varyingRows *= (packedVarying.isTransformFeedbackArrayElement() ? 1 : elementCount);
382 
383     unsigned int maxVaryingVectors = static_cast<unsigned int>(mRegisterMap.size());
384 
385     // Fail if we are packing a single over-large varying.
386     if (varyingRows > maxVaryingVectors)
387     {
388         return false;
389     }
390 
391     // "For 2, 3 and 4 component variables packing is started using the 1st column of the 1st row.
392     // Variables are then allocated to successive rows, aligning them to the 1st column."
393     if (varyingColumns >= 2 && varyingColumns <= 4)
394     {
395         for (unsigned int row = 0; row <= maxVaryingVectors - varyingRows; ++row)
396         {
397             if (isRegisterRangeFree(row, 0, varyingRows, varyingColumns))
398             {
399                 insertVaryingIntoRegisterMap(row, 0, varyingColumns, packedVarying);
400                 return true;
401             }
402         }
403 
404         // "For 2 component variables, when there are no spare rows, the strategy is switched to
405         // using the highest numbered row and the lowest numbered column where the variable will
406         // fit."
407         if (varyingColumns == 2)
408         {
409             for (unsigned int r = maxVaryingVectors - varyingRows + 1; r-- >= 1;)
410             {
411                 if (isRegisterRangeFree(r, 2, varyingRows, 2))
412                 {
413                     insertVaryingIntoRegisterMap(r, 2, varyingColumns, packedVarying);
414                     return true;
415                 }
416             }
417         }
418 
419         return false;
420     }
421 
422     // "1 component variables have their own packing rule. They are packed in order of size, largest
423     // first. Each variable is placed in the column that leaves the least amount of space in the
424     // column and aligned to the lowest available rows within that column."
425     ASSERT(varyingColumns == 1);
426     unsigned int contiguousSpace[4]     = {0};
427     unsigned int bestContiguousSpace[4] = {0};
428     unsigned int totalSpace[4]          = {0};
429 
430     for (unsigned int row = 0; row < maxVaryingVectors; ++row)
431     {
432         for (unsigned int column = 0; column < 4; ++column)
433         {
434             if (mRegisterMap[row][column])
435             {
436                 contiguousSpace[column] = 0;
437             }
438             else
439             {
440                 contiguousSpace[column]++;
441                 totalSpace[column]++;
442 
443                 if (contiguousSpace[column] > bestContiguousSpace[column])
444                 {
445                     bestContiguousSpace[column] = contiguousSpace[column];
446                 }
447             }
448         }
449     }
450 
451     unsigned int bestColumn = 0;
452     for (unsigned int column = 1; column < 4; ++column)
453     {
454         if (bestContiguousSpace[column] >= varyingRows &&
455             (bestContiguousSpace[bestColumn] < varyingRows ||
456              totalSpace[column] < totalSpace[bestColumn]))
457         {
458             bestColumn = column;
459         }
460     }
461 
462     if (bestContiguousSpace[bestColumn] >= varyingRows)
463     {
464         for (unsigned int row = 0; row < maxVaryingVectors; row++)
465         {
466             if (isRegisterRangeFree(row, bestColumn, varyingRows, 1))
467             {
468                 for (unsigned int arrayIndex = 0; arrayIndex < varyingRows; ++arrayIndex)
469                 {
470                     // If varyingRows > 1, it must be an array.
471                     PackedVaryingRegister registerInfo;
472                     registerInfo.packedVarying  = &packedVarying;
473                     registerInfo.registerRow    = row + arrayIndex;
474                     registerInfo.registerColumn = bestColumn;
475                     registerInfo.varyingArrayIndex =
476                         (packedVarying.isTransformFeedbackArrayElement() ? packedVarying.arrayIndex
477                                                                          : arrayIndex);
478                     registerInfo.varyingRowIndex = 0;
479                     // Do not record register info for builtins.
480                     // TODO(jmadill): Clean this up.
481                     if (!varying.isBuiltIn())
482                     {
483                         mRegisterList.push_back(registerInfo);
484                     }
485                     mRegisterMap[row + arrayIndex][bestColumn] = true;
486                 }
487                 break;
488             }
489         }
490         return true;
491     }
492 
493     return false;
494 }
495 
isRegisterRangeFree(unsigned int registerRow,unsigned int registerColumn,unsigned int varyingRows,unsigned int varyingColumns) const496 bool VaryingPacking::isRegisterRangeFree(unsigned int registerRow,
497                                          unsigned int registerColumn,
498                                          unsigned int varyingRows,
499                                          unsigned int varyingColumns) const
500 {
501     for (unsigned int row = 0; row < varyingRows; ++row)
502     {
503         ASSERT(registerRow + row < mRegisterMap.size());
504         for (unsigned int column = 0; column < varyingColumns; ++column)
505         {
506             ASSERT(registerColumn + column < 4);
507             if (mRegisterMap[registerRow + row][registerColumn + column])
508             {
509                 return false;
510             }
511         }
512     }
513 
514     return true;
515 }
516 
insertVaryingIntoRegisterMap(unsigned int registerRow,unsigned int registerColumn,unsigned int varyingColumns,const PackedVarying & packedVarying)517 void VaryingPacking::insertVaryingIntoRegisterMap(unsigned int registerRow,
518                                                   unsigned int registerColumn,
519                                                   unsigned int varyingColumns,
520                                                   const PackedVarying &packedVarying)
521 {
522     unsigned int varyingRows = 0;
523 
524     const sh::ShaderVariable &varying = packedVarying.varying();
525     ASSERT(!varying.isStruct());
526     GLenum transposedType = gl::TransposeMatrixType(varying.type);
527     varyingRows           = gl::VariableRowCount(transposedType);
528 
529     PackedVaryingRegister registerInfo;
530     registerInfo.packedVarying  = &packedVarying;
531     registerInfo.registerColumn = registerColumn;
532 
533     // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
534     // structures, so we may use getBasicTypeElementCount().
535     const unsigned int arrayElementCount = packedVarying.getBasicTypeElementCount();
536     for (unsigned int arrayElement = 0; arrayElement < arrayElementCount; ++arrayElement)
537     {
538         if (packedVarying.isTransformFeedbackArrayElement() &&
539             arrayElement != packedVarying.arrayIndex)
540         {
541             continue;
542         }
543         for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow)
544         {
545             registerInfo.registerRow     = registerRow + (arrayElement * varyingRows) + varyingRow;
546             registerInfo.varyingRowIndex = varyingRow;
547             registerInfo.varyingArrayIndex = arrayElement;
548             // Do not record register info for builtins.
549             // TODO(jmadill): Clean this up.
550             if (!varying.isBuiltIn())
551             {
552                 mRegisterList.push_back(registerInfo);
553             }
554 
555             for (unsigned int columnIndex = 0; columnIndex < varyingColumns; ++columnIndex)
556             {
557                 mRegisterMap[registerInfo.registerRow][registerColumn + columnIndex] = true;
558             }
559         }
560     }
561 }
562 
collectUserVarying(const ProgramVaryingRef & ref,VaryingUniqueFullNames * uniqueFullNames)563 void VaryingPacking::collectUserVarying(const ProgramVaryingRef &ref,
564                                         VaryingUniqueFullNames *uniqueFullNames)
565 {
566     const sh::ShaderVariable *input  = ref.frontShader;
567     const sh::ShaderVariable *output = ref.backShader;
568 
569     // Will get the vertex shader interpolation by default.
570     sh::InterpolationType interpolation = input ? input->interpolation : output->interpolation;
571 
572     VaryingInShaderRef frontVarying(ref.frontShaderStage, input);
573     VaryingInShaderRef backVarying(ref.backShaderStage, output);
574 
575     mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying), interpolation);
576     if (input && !input->isBuiltIn())
577     {
578         (*uniqueFullNames)[ref.frontShaderStage].insert(
579             mPackedVaryings.back().fullName(ref.frontShaderStage));
580     }
581     if (output && !output->isBuiltIn())
582     {
583         (*uniqueFullNames)[ref.backShaderStage].insert(
584             mPackedVaryings.back().fullName(ref.backShaderStage));
585     }
586 }
587 
collectUserVaryingField(const ProgramVaryingRef & ref,GLuint arrayIndex,GLuint fieldIndex,GLuint secondaryFieldIndex,VaryingUniqueFullNames * uniqueFullNames)588 void VaryingPacking::collectUserVaryingField(const ProgramVaryingRef &ref,
589                                              GLuint arrayIndex,
590                                              GLuint fieldIndex,
591                                              GLuint secondaryFieldIndex,
592                                              VaryingUniqueFullNames *uniqueFullNames)
593 {
594     const sh::ShaderVariable *input  = ref.frontShader;
595     const sh::ShaderVariable *output = ref.backShader;
596 
597     // Will get the vertex shader interpolation by default.
598     sh::InterpolationType interpolation = input ? input->interpolation : output->interpolation;
599 
600     const sh::ShaderVariable *frontField = input ? &input->fields[fieldIndex] : nullptr;
601     const sh::ShaderVariable *backField  = output ? &output->fields[fieldIndex] : nullptr;
602 
603     if (secondaryFieldIndex != GL_INVALID_INDEX)
604     {
605         frontField = frontField ? &frontField->fields[secondaryFieldIndex] : nullptr;
606         backField  = backField ? &backField->fields[secondaryFieldIndex] : nullptr;
607     }
608 
609     VaryingInShaderRef frontVarying(ref.frontShaderStage, frontField);
610     VaryingInShaderRef backVarying(ref.backShaderStage, backField);
611 
612     if (input)
613     {
614         if (frontField->isShaderIOBlock)
615         {
616             frontVarying.parentStructName = input->structOrBlockName;
617         }
618         else
619         {
620             ASSERT(!frontField->isStruct() && !frontField->isArray());
621             frontVarying.parentStructName = input->name;
622         }
623     }
624     if (output)
625     {
626         if (backField->isShaderIOBlock)
627         {
628             backVarying.parentStructName = output->structOrBlockName;
629         }
630         else
631         {
632             ASSERT(!backField->isStruct() && !backField->isArray());
633             backVarying.parentStructName = output->name;
634         }
635     }
636 
637     mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying), interpolation,
638                                  arrayIndex, fieldIndex,
639                                  secondaryFieldIndex == GL_INVALID_INDEX ? 0 : secondaryFieldIndex);
640 
641     if (input)
642     {
643         (*uniqueFullNames)[ref.frontShaderStage].insert(
644             mPackedVaryings.back().fullName(ref.frontShaderStage));
645     }
646     if (output)
647     {
648         (*uniqueFullNames)[ref.backShaderStage].insert(
649             mPackedVaryings.back().fullName(ref.backShaderStage));
650     }
651 }
652 
collectUserVaryingTF(const ProgramVaryingRef & ref,size_t subscript)653 void VaryingPacking::collectUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript)
654 {
655     const sh::ShaderVariable *input = ref.frontShader;
656 
657     VaryingInShaderRef frontVarying(ref.frontShaderStage, input);
658     VaryingInShaderRef backVarying(ref.backShaderStage, nullptr);
659 
660     mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying),
661                                  input->interpolation);
662     mPackedVaryings.back().arrayIndex          = static_cast<GLuint>(subscript);
663     mPackedVaryings.back().isTransformFeedback = true;
664 }
665 
collectUserVaryingFieldTF(const ProgramVaryingRef & ref,const sh::ShaderVariable & field,GLuint fieldIndex,GLuint secondaryFieldIndex)666 void VaryingPacking::collectUserVaryingFieldTF(const ProgramVaryingRef &ref,
667                                                const sh::ShaderVariable &field,
668                                                GLuint fieldIndex,
669                                                GLuint secondaryFieldIndex)
670 {
671     const sh::ShaderVariable *input = ref.frontShader;
672 
673     const sh::ShaderVariable *frontField = &field;
674     if (secondaryFieldIndex != GL_INVALID_INDEX)
675     {
676         frontField = &frontField->fields[secondaryFieldIndex];
677     }
678 
679     VaryingInShaderRef frontVarying(ref.frontShaderStage, frontField);
680     VaryingInShaderRef backVarying(ref.backShaderStage, nullptr);
681 
682     if (frontField->isShaderIOBlock)
683     {
684         frontVarying.parentStructName = input->structOrBlockName;
685     }
686     else
687     {
688         ASSERT(!frontField->isStruct() && !frontField->isArray());
689         frontVarying.parentStructName = input->name;
690     }
691 
692     mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying),
693                                  input->interpolation, GL_INVALID_INDEX, fieldIndex,
694                                  secondaryFieldIndex == GL_INVALID_INDEX ? 0 : secondaryFieldIndex);
695 }
696 
collectVarying(const sh::ShaderVariable & varying,const ProgramVaryingRef & ref,PackMode packMode,VaryingUniqueFullNames * uniqueFullNames)697 void VaryingPacking::collectVarying(const sh::ShaderVariable &varying,
698                                     const ProgramVaryingRef &ref,
699                                     PackMode packMode,
700                                     VaryingUniqueFullNames *uniqueFullNames)
701 {
702     const sh::ShaderVariable *input  = ref.frontShader;
703     const sh::ShaderVariable *output = ref.backShader;
704 
705     if (varying.isStruct())
706     {
707         std::vector<unsigned int> arraySizes = StripVaryingArrayDimension(
708             ref.frontShader, ref.frontShaderStage, ref.backShader, ref.backShaderStage, false);
709         const bool isArray     = !arraySizes.empty();
710         const GLuint arraySize = isArray ? arraySizes[0] : 1;
711 
712         for (GLuint arrayIndex = 0; arrayIndex < arraySize; ++arrayIndex)
713         {
714             const GLuint effectiveArrayIndex = isArray ? arrayIndex : GL_INVALID_INDEX;
715             for (GLuint fieldIndex = 0; fieldIndex < varying.fields.size(); ++fieldIndex)
716             {
717                 const sh::ShaderVariable &fieldVarying = varying.fields[fieldIndex];
718                 if (ShouldSkipPackedVarying(fieldVarying, packMode))
719                 {
720                     continue;
721                 }
722 
723                 if (fieldVarying.isStruct())
724                 {
725                     if (fieldVarying.isArray())
726                     {
727                         unsigned int structFieldArraySize = fieldVarying.arraySizes[0];
728                         for (unsigned int fieldArrayIndex = 0;
729                              fieldArrayIndex < structFieldArraySize; ++fieldArrayIndex)
730                         {
731                             for (GLuint nestedIndex = 0; nestedIndex < fieldVarying.fields.size();
732                                  nestedIndex++)
733                             {
734                                 collectUserVaryingField(ref, effectiveArrayIndex, fieldIndex,
735                                                         nestedIndex, uniqueFullNames);
736                             }
737                         }
738                     }
739                     else
740                     {
741                         for (GLuint nestedIndex = 0; nestedIndex < fieldVarying.fields.size();
742                              nestedIndex++)
743                         {
744                             collectUserVaryingField(ref, effectiveArrayIndex, fieldIndex,
745                                                     nestedIndex, uniqueFullNames);
746                         }
747                     }
748                 }
749                 else
750                 {
751                     collectUserVaryingField(ref, effectiveArrayIndex, fieldIndex, GL_INVALID_INDEX,
752                                             uniqueFullNames);
753                 }
754             }
755         }
756         if (input)
757         {
758             (*uniqueFullNames)[ref.frontShaderStage].insert(input->name);
759             if (input->isShaderIOBlock)
760             {
761                 (*uniqueFullNames)[ref.frontShaderStage].insert(input->structOrBlockName);
762             }
763         }
764         if (output)
765         {
766             (*uniqueFullNames)[ref.backShaderStage].insert(output->name);
767         }
768     }
769     else
770     {
771         collectUserVarying(ref, uniqueFullNames);
772     }
773 }
774 
collectTFVarying(const std::string & tfVarying,const ProgramVaryingRef & ref,VaryingUniqueFullNames * uniqueFullNames)775 void VaryingPacking::collectTFVarying(const std::string &tfVarying,
776                                       const ProgramVaryingRef &ref,
777                                       VaryingUniqueFullNames *uniqueFullNames)
778 {
779     const sh::ShaderVariable *input = ref.frontShader;
780 
781     std::vector<unsigned int> subscripts;
782     std::string baseName = ParseResourceName(tfVarying, &subscripts);
783 
784     // Already packed as active varying.
785     if ((*uniqueFullNames)[ref.frontShaderStage].count(tfVarying) > 0 ||
786         (*uniqueFullNames)[ref.frontShaderStage].count(baseName) > 0 ||
787         (input->isShaderIOBlock &&
788          (*uniqueFullNames)[ref.frontShaderStage].count(input->structOrBlockName) > 0))
789     {
790         return;
791     }
792 
793     if (input->isStruct())
794     {
795         GLuint fieldIndex               = 0;
796         const sh::ShaderVariable *field = input->findField(tfVarying, &fieldIndex);
797         if (field != nullptr)
798         {
799             ASSERT(input->isShaderIOBlock || (!field->isStruct() && !field->isArray()));
800 
801             // If it's an I/O block whose member is being captured, pack every member of the
802             // block.  Currently, we pack either all or none of an I/O block.
803             if (input->isShaderIOBlock)
804             {
805                 for (fieldIndex = 0; fieldIndex < input->fields.size(); ++fieldIndex)
806                 {
807                     if (input->fields[fieldIndex].isStruct())
808                     {
809 
810                         for (GLuint nestedIndex = 0;
811                              nestedIndex < input->fields[fieldIndex].fields.size(); nestedIndex++)
812                         {
813                             collectUserVaryingFieldTF(ref, input->fields[fieldIndex], fieldIndex,
814                                                       nestedIndex);
815                         }
816                     }
817                     else
818                     {
819                         collectUserVaryingFieldTF(ref, input->fields[fieldIndex], fieldIndex,
820                                                   GL_INVALID_INDEX);
821                     }
822                 }
823 
824                 (*uniqueFullNames)[ref.frontShaderStage].insert(input->structOrBlockName);
825             }
826             else
827             {
828                 collectUserVaryingFieldTF(ref, *field, fieldIndex, GL_INVALID_INDEX);
829             }
830             (*uniqueFullNames)[ref.frontShaderStage].insert(tfVarying);
831             (*uniqueFullNames)[ref.frontShaderStage].insert(input->name);
832         }
833     }
834     // Array as a whole and array element conflict has already been checked in
835     // linkValidateTransformFeedback.
836     else if (baseName == input->name)
837     {
838         size_t subscript = GL_INVALID_INDEX;
839         if (!subscripts.empty())
840         {
841             subscript = subscripts.back();
842         }
843 
844         // only pack varyings that are not builtins.
845         if (tfVarying.compare(0, 3, "gl_") != 0)
846         {
847             collectUserVaryingTF(ref, subscript);
848             (*uniqueFullNames)[ref.frontShaderStage].insert(tfVarying);
849         }
850     }
851 }
852 
collectAndPackUserVaryings(gl::InfoLog & infoLog,GLint maxVaryingVectors,PackMode packMode,ShaderType frontShaderStage,ShaderType backShaderStage,const ProgramMergedVaryings & mergedVaryings,const std::vector<std::string> & tfVaryings,const bool isSeparableProgram)853 bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
854                                                 GLint maxVaryingVectors,
855                                                 PackMode packMode,
856                                                 ShaderType frontShaderStage,
857                                                 ShaderType backShaderStage,
858                                                 const ProgramMergedVaryings &mergedVaryings,
859                                                 const std::vector<std::string> &tfVaryings,
860                                                 const bool isSeparableProgram)
861 {
862     VaryingUniqueFullNames uniqueFullNames;
863 
864     reset();
865 
866     for (const ProgramVaryingRef &ref : mergedVaryings)
867     {
868         const sh::ShaderVariable *input  = ref.frontShader;
869         const sh::ShaderVariable *output = ref.backShader;
870 
871         if ((input && ref.frontShaderStage != frontShaderStage) ||
872             (output && ref.backShaderStage != backShaderStage))
873         {
874             continue;
875         }
876 
877         const bool isActiveBuiltInInput  = input && input->isBuiltIn() && input->active;
878         const bool isActiveBuiltInOutput = output && output->isBuiltIn() && output->active;
879 
880         if (isActiveBuiltInInput)
881         {
882             SetActivePerVertexMembers(input, &mOutputPerVertexActiveMembers[frontShaderStage]);
883         }
884 
885         // Only pack statically used varyings that have a matched input or output, plus special
886         // builtins. Note that we pack all statically used user-defined varyings even if they are
887         // not active. GLES specs are a bit vague on whether it's allowed to only pack active
888         // varyings, though GLES 3.1 spec section 11.1.2.1 says that "device-dependent
889         // optimizations" may be used to make vertex shader outputs fit.
890         //
891         // When separable programs are linked, varyings at the separable program's boundary are
892         // treated as active. See section 7.4.1 in
893         // https://www.khronos.org/registry/OpenGL/specs/es/3.2/es_spec_3.2.pdf
894         bool matchedInputOutputStaticUse = (input && output && output->staticUse);
895         bool activeBuiltIn               = (isActiveBuiltInInput || isActiveBuiltInOutput);
896 
897         // Output variable in TCS can be read as input in another invocation by barrier.
898         // See section 11.2.1.2.4 Tessellation Control Shader Execution Order in OpenGL ES 3.2.
899         bool staticUseInTCS =
900             (input && input->staticUse && ref.frontShaderStage == ShaderType::TessControl);
901 
902         // Separable program requirements
903         bool separableActiveInput  = (input && (input->active || !output));
904         bool separableActiveOutput = (output && (output->active || !input));
905         bool separableActiveVarying =
906             (isSeparableProgram && (separableActiveInput || separableActiveOutput));
907 
908         if (matchedInputOutputStaticUse || activeBuiltIn || separableActiveVarying ||
909             staticUseInTCS)
910         {
911             const sh::ShaderVariable *varying = output ? output : input;
912 
913             if (!ShouldSkipPackedVarying(*varying, packMode))
914             {
915                 collectVarying(*varying, ref, packMode, &uniqueFullNames);
916                 continue;
917             }
918         }
919 
920         // If the varying is not used in the input, we know it is inactive, unless it's a separable
921         // program, in which case the input shader may not exist in this program.
922         if (!input && !isSeparableProgram)
923         {
924             if (!output->isBuiltIn() && output->id != 0)
925             {
926                 mInactiveVaryingIds[ref.backShaderStage].push_back(output->id);
927             }
928             continue;
929         }
930 
931         // Keep Transform FB varyings in the merged list always.
932         for (const std::string &tfVarying : tfVaryings)
933         {
934             collectTFVarying(tfVarying, ref, &uniqueFullNames);
935         }
936 
937         if (input && !input->isBuiltIn())
938         {
939             const std::string &name =
940                 input->isShaderIOBlock ? input->structOrBlockName : input->name;
941             if (uniqueFullNames[ref.frontShaderStage].count(name) == 0 && input->id != 0)
942             {
943                 mInactiveVaryingIds[ref.frontShaderStage].push_back(input->id);
944             }
945         }
946         if (output && !output->isBuiltIn())
947         {
948             const std::string &name =
949                 output->isShaderIOBlock ? output->structOrBlockName : output->name;
950             if (uniqueFullNames[ref.backShaderStage].count(name) == 0 && output->id != 0)
951             {
952                 mInactiveVaryingIds[ref.backShaderStage].push_back(output->id);
953             }
954         }
955     }
956 
957     std::sort(mPackedVaryings.begin(), mPackedVaryings.end(), ComparePackedVarying);
958 
959     return packUserVaryings(infoLog, maxVaryingVectors, packMode, mPackedVaryings);
960 }
961 
962 // See comment on packVarying.
packUserVaryings(gl::InfoLog & infoLog,GLint maxVaryingVectors,PackMode packMode,const std::vector<PackedVarying> & packedVaryings)963 bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
964                                       GLint maxVaryingVectors,
965                                       PackMode packMode,
966                                       const std::vector<PackedVarying> &packedVaryings)
967 {
968     clearRegisterMap();
969     mRegisterMap.resize(maxVaryingVectors);
970 
971     // "Variables are packed into the registers one at a time so that they each occupy a contiguous
972     // subrectangle. No splitting of variables is permitted."
973     for (const PackedVarying &packedVarying : packedVaryings)
974     {
975         if (!packVaryingIntoRegisterMap(packMode, packedVarying))
976         {
977             ShaderType eitherStage = packedVarying.frontVarying.varying
978                                          ? packedVarying.frontVarying.stage
979                                          : packedVarying.backVarying.stage;
980             infoLog << "Could not pack varying " << packedVarying.fullName(eitherStage);
981 
982             // TODO(jmadill): Implement more sophisticated component packing in D3D9.
983             if (packMode == PackMode::ANGLE_NON_CONFORMANT_D3D9)
984             {
985                 infoLog << "Note: Additional non-conformant packing restrictions are enforced on "
986                            "D3D9.";
987             }
988 
989             return false;
990         }
991     }
992 
993     // Sort the packed register list
994     std::sort(mRegisterList.begin(), mRegisterList.end());
995 
996     return true;
997 }
998 
999 // ProgramVaryingPacking implementation.
1000 ProgramVaryingPacking::ProgramVaryingPacking() = default;
1001 
1002 ProgramVaryingPacking::~ProgramVaryingPacking() = default;
1003 
getInputPacking(ShaderType backShaderStage) const1004 const VaryingPacking &ProgramVaryingPacking::getInputPacking(ShaderType backShaderStage) const
1005 {
1006     ShaderType frontShaderStage = mBackToFrontStageMap[backShaderStage];
1007 
1008     // If there's a missing shader stage, return the compute shader packing which is always empty.
1009     if (frontShaderStage == ShaderType::InvalidEnum)
1010     {
1011         ASSERT(mVaryingPackings[ShaderType::Compute].getMaxSemanticIndex() == 0);
1012         return mVaryingPackings[ShaderType::Compute];
1013     }
1014 
1015     return mVaryingPackings[frontShaderStage];
1016 }
1017 
getOutputPacking(ShaderType frontShaderStage) const1018 const VaryingPacking &ProgramVaryingPacking::getOutputPacking(ShaderType frontShaderStage) const
1019 {
1020     return mVaryingPackings[frontShaderStage];
1021 }
1022 
collectAndPackUserVaryings(InfoLog & infoLog,const Caps & caps,PackMode packMode,const ShaderBitSet & activeShadersMask,const ProgramMergedVaryings & mergedVaryings,const std::vector<std::string> & tfVaryings,bool isSeparableProgram)1023 bool ProgramVaryingPacking::collectAndPackUserVaryings(InfoLog &infoLog,
1024                                                        const Caps &caps,
1025                                                        PackMode packMode,
1026                                                        const ShaderBitSet &activeShadersMask,
1027                                                        const ProgramMergedVaryings &mergedVaryings,
1028                                                        const std::vector<std::string> &tfVaryings,
1029                                                        bool isSeparableProgram)
1030 {
1031     mBackToFrontStageMap.fill(ShaderType::InvalidEnum);
1032 
1033     ShaderBitSet activeShaders = activeShadersMask;
1034 
1035     ASSERT(activeShaders.any());
1036     ShaderType frontShaderStage     = activeShaders.first();
1037     activeShaders[frontShaderStage] = false;
1038 
1039     // Special case for start-after-vertex.
1040     if (frontShaderStage != ShaderType::Vertex)
1041     {
1042         ShaderType emulatedFrontShaderStage = ShaderType::Vertex;
1043         ShaderType backShaderStage          = frontShaderStage;
1044 
1045         if (!mVaryingPackings[emulatedFrontShaderStage].collectAndPackUserVaryings(
1046                 infoLog, GetMaxShaderInputVectors(caps, backShaderStage), packMode,
1047                 ShaderType::InvalidEnum, backShaderStage, mergedVaryings, tfVaryings,
1048                 isSeparableProgram))
1049         {
1050             return false;
1051         }
1052         mBackToFrontStageMap[backShaderStage] = emulatedFrontShaderStage;
1053     }
1054 
1055     // Process input/output shader pairs.
1056     for (ShaderType backShaderStage : activeShaders)
1057     {
1058         GLint maxVaryingVectors;
1059         if (frontShaderStage == ShaderType::Vertex && backShaderStage == ShaderType::Fragment)
1060         {
1061             maxVaryingVectors = caps.maxVaryingVectors;
1062         }
1063         else
1064         {
1065             GLint outputVaryingsMax = GetMaxShaderOutputVectors(caps, frontShaderStage);
1066             GLint inputVaryingsMax  = GetMaxShaderInputVectors(caps, backShaderStage);
1067             maxVaryingVectors       = std::min(inputVaryingsMax, outputVaryingsMax);
1068         }
1069 
1070         ASSERT(maxVaryingVectors > 0 && maxVaryingVectors < std::numeric_limits<GLint>::max());
1071 
1072         if (!mVaryingPackings[frontShaderStage].collectAndPackUserVaryings(
1073                 infoLog, maxVaryingVectors, packMode, frontShaderStage, backShaderStage,
1074                 mergedVaryings, tfVaryings, isSeparableProgram))
1075         {
1076             return false;
1077         }
1078 
1079         mBackToFrontStageMap[backShaderStage] = frontShaderStage;
1080         frontShaderStage                      = backShaderStage;
1081     }
1082 
1083     // Special case for stop-before-fragment.
1084     if (frontShaderStage != ShaderType::Fragment)
1085     {
1086         if (!mVaryingPackings[frontShaderStage].collectAndPackUserVaryings(
1087                 infoLog, GetMaxShaderOutputVectors(caps, frontShaderStage), packMode,
1088                 frontShaderStage, ShaderType::InvalidEnum, mergedVaryings, tfVaryings,
1089                 isSeparableProgram))
1090         {
1091             return false;
1092         }
1093 
1094         ShaderType emulatedBackShaderStage            = ShaderType::Fragment;
1095         mBackToFrontStageMap[emulatedBackShaderStage] = frontShaderStage;
1096     }
1097 
1098     return true;
1099 }
1100 
GetMergedVaryingsFromLinkingVariables(const LinkingVariables & linkingVariables)1101 ProgramMergedVaryings GetMergedVaryingsFromLinkingVariables(
1102     const LinkingVariables &linkingVariables)
1103 {
1104     ShaderType frontShaderType = ShaderType::InvalidEnum;
1105     ProgramMergedVaryings merged;
1106 
1107     for (ShaderType backShaderType : kAllGraphicsShaderTypes)
1108     {
1109         if (!linkingVariables.isShaderStageUsedBitset[backShaderType])
1110         {
1111             continue;
1112         }
1113         const std::vector<sh::ShaderVariable> &backShaderOutputVaryings =
1114             linkingVariables.outputVaryings[backShaderType];
1115         const std::vector<sh::ShaderVariable> &backShaderInputVaryings =
1116             linkingVariables.inputVaryings[backShaderType];
1117 
1118         // Add outputs. These are always unmatched since we walk shader stages sequentially.
1119         for (const sh::ShaderVariable &frontVarying : backShaderOutputVaryings)
1120         {
1121             ProgramVaryingRef ref;
1122             ref.frontShader      = &frontVarying;
1123             ref.frontShaderStage = backShaderType;
1124             merged.push_back(ref);
1125         }
1126 
1127         if (frontShaderType == ShaderType::InvalidEnum)
1128         {
1129             // If this is our first shader stage, and not a VS, we might have unmatched inputs.
1130             for (const sh::ShaderVariable &backVarying : backShaderInputVaryings)
1131             {
1132                 ProgramVaryingRef ref;
1133                 ref.backShader      = &backVarying;
1134                 ref.backShaderStage = backShaderType;
1135                 merged.push_back(ref);
1136             }
1137         }
1138         else
1139         {
1140             // Match inputs with the prior shader stage outputs.
1141             for (const sh::ShaderVariable &backVarying : backShaderInputVaryings)
1142             {
1143                 bool found = false;
1144                 for (ProgramVaryingRef &ref : merged)
1145                 {
1146                     if (ref.frontShader && ref.frontShaderStage == frontShaderType &&
1147                         InterfaceVariablesMatch(*ref.frontShader, backVarying))
1148                     {
1149                         ASSERT(ref.backShader == nullptr);
1150 
1151                         ref.backShader      = &backVarying;
1152                         ref.backShaderStage = backShaderType;
1153                         found               = true;
1154                         break;
1155                     }
1156                 }
1157 
1158                 // Some outputs are never matched, e.g. some builtin variables.
1159                 if (!found)
1160                 {
1161                     ProgramVaryingRef ref;
1162                     ref.backShader      = &backVarying;
1163                     ref.backShaderStage = backShaderType;
1164                     merged.push_back(ref);
1165                 }
1166             }
1167         }
1168 
1169         // Save the current back shader to use as the next front shader.
1170         frontShaderType = backShaderType;
1171     }
1172 
1173     return merged;
1174 }
1175 }  // namespace gl
1176