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