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