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