VaryingPacking.cpp (44791B)
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 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 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 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 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 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 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 188 VaryingInShaderRef::VaryingInShaderRef(ShaderType stageIn, const sh::ShaderVariable *varyingIn) 189 : varying(varyingIn), stage(stageIn) 190 {} 191 192 VaryingInShaderRef::~VaryingInShaderRef() = default; 193 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 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 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 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 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 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 263 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 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 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. 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 453 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 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 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 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 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 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 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 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 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. 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 981 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 995 const VaryingPacking &ProgramVaryingPacking::getOutputPacking(ShaderType frontShaderStage) const 996 { 997 return mVaryingPackings[frontShaderStage]; 998 } 999 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 ShaderType emulatedFrontShaderStage = ShaderType::Vertex; 1020 ShaderType backShaderStage = frontShaderStage; 1021 1022 if (!mVaryingPackings[emulatedFrontShaderStage].collectAndPackUserVaryings( 1023 infoLog, GetMaxShaderInputVectors(caps, backShaderStage), packMode, 1024 ShaderType::InvalidEnum, backShaderStage, mergedVaryings, tfVaryings, 1025 isSeparableProgram)) 1026 { 1027 return false; 1028 } 1029 mBackToFrontStageMap[backShaderStage] = emulatedFrontShaderStage; 1030 } 1031 1032 // Process input/output shader pairs. 1033 for (ShaderType backShaderStage : activeShaders) 1034 { 1035 GLint maxVaryingVectors; 1036 if (frontShaderStage == ShaderType::Vertex && backShaderStage == ShaderType::Fragment) 1037 { 1038 maxVaryingVectors = caps.maxVaryingVectors; 1039 } 1040 else 1041 { 1042 GLint outputVaryingsMax = GetMaxShaderOutputVectors(caps, frontShaderStage); 1043 GLint inputVaryingsMax = GetMaxShaderInputVectors(caps, backShaderStage); 1044 maxVaryingVectors = std::min(inputVaryingsMax, outputVaryingsMax); 1045 } 1046 1047 ASSERT(maxVaryingVectors > 0 && maxVaryingVectors < std::numeric_limits<GLint>::max()); 1048 1049 if (!mVaryingPackings[frontShaderStage].collectAndPackUserVaryings( 1050 infoLog, maxVaryingVectors, packMode, frontShaderStage, backShaderStage, 1051 mergedVaryings, tfVaryings, isSeparableProgram)) 1052 { 1053 return false; 1054 } 1055 1056 mBackToFrontStageMap[backShaderStage] = frontShaderStage; 1057 frontShaderStage = backShaderStage; 1058 } 1059 1060 // Special case for stop-before-fragment. 1061 if (frontShaderStage != ShaderType::Fragment) 1062 { 1063 if (!mVaryingPackings[frontShaderStage].collectAndPackUserVaryings( 1064 infoLog, GetMaxShaderOutputVectors(caps, frontShaderStage), packMode, 1065 frontShaderStage, ShaderType::InvalidEnum, mergedVaryings, tfVaryings, 1066 isSeparableProgram)) 1067 { 1068 return false; 1069 } 1070 1071 ShaderType emulatedBackShaderStage = ShaderType::Fragment; 1072 mBackToFrontStageMap[emulatedBackShaderStage] = frontShaderStage; 1073 } 1074 1075 return true; 1076 } 1077 1078 ProgramMergedVaryings GetMergedVaryingsFromLinkingVariables( 1079 const LinkingVariables &linkingVariables) 1080 { 1081 ShaderType frontShaderType = ShaderType::InvalidEnum; 1082 ProgramMergedVaryings merged; 1083 1084 for (ShaderType backShaderType : kAllGraphicsShaderTypes) 1085 { 1086 if (!linkingVariables.isShaderStageUsedBitset[backShaderType]) 1087 { 1088 continue; 1089 } 1090 const std::vector<sh::ShaderVariable> &backShaderOutputVaryings = 1091 linkingVariables.outputVaryings[backShaderType]; 1092 const std::vector<sh::ShaderVariable> &backShaderInputVaryings = 1093 linkingVariables.inputVaryings[backShaderType]; 1094 1095 // Add outputs. These are always unmatched since we walk shader stages sequentially. 1096 for (const sh::ShaderVariable &frontVarying : backShaderOutputVaryings) 1097 { 1098 ProgramVaryingRef ref; 1099 ref.frontShader = &frontVarying; 1100 ref.frontShaderStage = backShaderType; 1101 merged.push_back(ref); 1102 } 1103 1104 if (frontShaderType == ShaderType::InvalidEnum) 1105 { 1106 // If this is our first shader stage, and not a VS, we might have unmatched inputs. 1107 for (const sh::ShaderVariable &backVarying : backShaderInputVaryings) 1108 { 1109 ProgramVaryingRef ref; 1110 ref.backShader = &backVarying; 1111 ref.backShaderStage = backShaderType; 1112 merged.push_back(ref); 1113 } 1114 } 1115 else 1116 { 1117 // Match inputs with the prior shader stage outputs. 1118 for (const sh::ShaderVariable &backVarying : backShaderInputVaryings) 1119 { 1120 bool found = false; 1121 for (ProgramVaryingRef &ref : merged) 1122 { 1123 if (ref.frontShader && ref.frontShaderStage == frontShaderType && 1124 InterfaceVariablesMatch(*ref.frontShader, backVarying)) 1125 { 1126 ASSERT(ref.backShader == nullptr); 1127 1128 ref.backShader = &backVarying; 1129 ref.backShaderStage = backShaderType; 1130 found = true; 1131 break; 1132 } 1133 } 1134 1135 // Some outputs are never matched, e.g. some builtin variables. 1136 if (!found) 1137 { 1138 ProgramVaryingRef ref; 1139 ref.backShader = &backVarying; 1140 ref.backShaderStage = backShaderType; 1141 merged.push_back(ref); 1142 } 1143 } 1144 } 1145 1146 // Save the current back shader to use as the next front shader. 1147 frontShaderType = backShaderType; 1148 } 1149 1150 return merged; 1151 } 1152 } // namespace gl