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