Hash :
8409b41e
Author :
Date :
2024-11-20T14:38:30
Report error on unsized interface block array
GLSL of forms:
uniform S{...} a[];
in R{...} b[];
out Q{...} c[];
Should produce error unless the shader is tesselation or geometry
shader.
Fix the errors for VS and FS. GS and TS likely need more work.
Bug: angleproject:379996129
Change-Id: Ib31c9a81717a8cd1c984eb4ce2e993d563bb3c4f
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6038333
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Auto-Submit: Kimmo Kinnunen <kkinnunen@apple.com>
Commit-Queue: Kimmo Kinnunen <kkinnunen@apple.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
//
// Copyright 2002 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_PARSECONTEXT_H_
#define COMPILER_TRANSLATOR_PARSECONTEXT_H_
#include "compiler/preprocessor/Preprocessor.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/Declarator.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/DirectiveHandler.h"
#include "compiler/translator/FunctionLookup.h"
#include "compiler/translator/QualifierTypes.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
struct TMatrixFields
{
bool wholeRow;
bool wholeCol;
int row;
int col;
};
//
// The following are extra variables needed during parsing, grouped together so
// they can be passed to the parser without needing a global.
//
class TParseContext : angle::NonCopyable
{
public:
TParseContext(TSymbolTable &symt,
TExtensionBehavior &ext,
sh::GLenum type,
ShShaderSpec spec,
const ShCompileOptions &options,
TDiagnostics *diagnostics,
const ShBuiltInResources &resources,
ShShaderOutput outputType);
~TParseContext();
bool anyMultiviewExtensionAvailable();
const angle::pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
angle::pp::Preprocessor &getPreprocessor() { return mPreprocessor; }
void *getScanner() const { return mScanner; }
void setScanner(void *scanner) { mScanner = scanner; }
int getShaderVersion() const { return mShaderVersion; }
sh::GLenum getShaderType() const { return mShaderType; }
ShShaderSpec getShaderSpec() const { return mShaderSpec; }
int numErrors() const { return mDiagnostics->numErrors(); }
void error(const TSourceLoc &loc, const char *reason, const char *token);
void error(const TSourceLoc &loc, const char *reason, const ImmutableString &token);
void warning(const TSourceLoc &loc, const char *reason, const char *token);
// If isError is false, a warning will be reported instead.
void outOfRangeError(bool isError,
const TSourceLoc &loc,
const char *reason,
const char *token);
TIntermBlock *getTreeRoot() const { return mTreeRoot; }
void setTreeRoot(TIntermBlock *treeRoot);
bool getFragmentPrecisionHigh() const
{
return mFragmentPrecisionHighOnESSL1 || mShaderVersion >= 300;
}
void setFragmentPrecisionHighOnESSL1(bool fragmentPrecisionHigh)
{
mFragmentPrecisionHighOnESSL1 = fragmentPrecisionHigh;
}
bool usesDerivatives() const { return mUsesDerivatives; }
bool isEarlyFragmentTestsSpecified() const { return mEarlyFragmentTestsSpecified; }
bool hasDiscard() const { return mHasDiscard; }
bool isSampleQualifierSpecified() const { return mSampleQualifierSpecified; }
void setLoopNestingLevel(int loopNestintLevel) { mLoopNestingLevel = loopNestintLevel; }
void incrLoopNestingLevel(const TSourceLoc &line)
{
++mLoopNestingLevel;
checkNestingLevel(line);
}
void decrLoopNestingLevel() { --mLoopNestingLevel; }
void incrSwitchNestingLevel(const TSourceLoc &line)
{
++mSwitchNestingLevel;
checkNestingLevel(line);
}
void decrSwitchNestingLevel() { --mSwitchNestingLevel; }
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
sh::WorkGroupSize getComputeShaderLocalSize() const;
int getNumViews() const { return mNumViews; }
const std::map<int, ShPixelLocalStorageFormat> &pixelLocalStorageFormats() const
{
return mPLSFormats;
}
void enterFunctionDeclaration() { mDeclaringFunction = true; }
void exitFunctionDeclaration() { mDeclaringFunction = false; }
bool declaringFunction() const { return mDeclaringFunction; }
TIntermConstantUnion *addScalarLiteral(const TConstantUnion *constantUnion,
const TSourceLoc &line);
// This method is guaranteed to succeed, even if no variable with 'name' exists.
const TVariable *getNamedVariable(const TSourceLoc &location,
const ImmutableString &name,
const TSymbol *symbol);
TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
const ImmutableString &name,
const TSymbol *symbol);
// Look at a '.' field selector string and change it into offsets for a vector.
bool parseVectorFields(const TSourceLoc &line,
const ImmutableString &compString,
int vecSize,
TVector<int> *fieldOffsets);
void assignError(const TSourceLoc &line, const char *op, const TType &left, const TType &right);
void unaryOpError(const TSourceLoc &line, const char *op, const TType &operand);
void binaryOpError(const TSourceLoc &line,
const char *op,
const TType &left,
const TType &right);
// Check functions - the ones that return bool return false if an error was generated.
void checkIsValidExpressionStatement(const TSourceLoc &line, TIntermTyped *expr);
bool checkIsNotReserved(const TSourceLoc &line, const ImmutableString &identifier);
void checkPrecisionSpecified(const TSourceLoc &line, TPrecision precision, TBasicType type);
bool checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node);
void checkIsConst(TIntermTyped *node);
void checkIsScalarInteger(TIntermTyped *node, const char *token);
bool checkIsAtGlobalLevel(const TSourceLoc &line, const char *token);
bool checkConstructorArguments(const TSourceLoc &line,
const TIntermSequence &arguments,
const TType &type);
// Returns a sanitized array size to use (the size is at least 1).
unsigned int checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr);
bool checkIsValidArrayDimension(const TSourceLoc &line, TVector<unsigned int> *arraySizes);
bool checkIsValidQualifierForArray(const TSourceLoc &line, const TPublicType &elementQualifier);
bool checkArrayElementIsNotArray(const TSourceLoc &line, const TPublicType &elementType);
bool checkArrayOfArraysInOut(const TSourceLoc &line,
const TPublicType &elementType,
const TType &arrayType);
bool checkIsNonVoid(const TSourceLoc &line,
const ImmutableString &identifier,
const TBasicType &type);
bool checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type);
void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType);
bool checkIsNotOpaqueType(const TSourceLoc &line,
const TTypeSpecifierNonArray &pType,
const char *reason);
void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType);
void checkLocationIsNotSpecified(const TSourceLoc &location,
const TLayoutQualifier &layoutQualifier);
void checkStd430IsForShaderStorageBlock(const TSourceLoc &location,
const TLayoutBlockStorage &blockStorage,
const TQualifier &qualifier);
// Check if at least one of the specified extensions can be used, and generate error/warning as
// appropriate according to the spec.
// This function is only needed for a few different small constant sizes of extension array, and
// we want to avoid unnecessary dynamic allocations. That's why checkCanUseOneOfExtensions is a
// template function rather than one taking a vector.
template <size_t size>
bool checkCanUseOneOfExtensions(const TSourceLoc &line,
const std::array<TExtension, size> &extensions);
bool checkCanUseExtension(const TSourceLoc &line, TExtension extension);
// Done for all declarations, whether empty or not.
void declarationQualifierErrorCheck(const sh::TQualifier qualifier,
const sh::TLayoutQualifier &layoutQualifier,
const TSourceLoc &location);
// Done for the first non-empty declarator in a declaration.
void nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
const TSourceLoc &identifierLocation);
// Done only for empty declarations.
void emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location);
void checkCanUseLayoutQualifier(const TSourceLoc &location);
bool checkLayoutQualifierSupported(const TSourceLoc &location,
const ImmutableString &layoutQualifierName,
int versionRequired);
bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
const TLayoutQualifier &layoutQualifier);
void functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall);
void checkInvariantVariableQualifier(bool invariant,
const TQualifier qualifier,
const TSourceLoc &invariantLocation);
void checkInputOutputTypeIsValidES3(const TQualifier qualifier,
const TPublicType &type,
const TSourceLoc &qualifierLocation);
void checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier);
void checkTCSOutVarIndexIsValid(TIntermBinary *binaryExpression, const TSourceLoc &location);
void checkAdvancedBlendEquationsNotSpecified(
const TSourceLoc &location,
const AdvancedBlendEquations &advancedBlendEquations,
const TQualifier &qualifier);
const TPragma &pragma() const { return mDirectiveHandler.pragma(); }
const TExtensionBehavior &extensionBehavior() const
{
return mDirectiveHandler.extensionBehavior();
}
bool isExtensionEnabled(TExtension extension) const;
void handleExtensionDirective(const TSourceLoc &loc, const char *extName, const char *behavior);
void handlePragmaDirective(const TSourceLoc &loc,
const char *name,
const char *value,
bool stdgl);
// For built-ins that can be redeclared, adjusts the type qualifier so transformations can
// identify them correctly.
void adjustRedeclaredBuiltInType(const TSourceLoc &line,
const ImmutableString &identifier,
TType *type);
// Returns true on success. *initNode may still be nullptr on success in case the initialization
// is not needed in the AST.
bool executeInitializer(const TSourceLoc &line,
const ImmutableString &identifier,
TType *type,
TIntermTyped *initializer,
TIntermBinary **initNode);
TIntermNode *addConditionInitializer(const TPublicType &pType,
const ImmutableString &identifier,
TIntermTyped *initializer,
const TSourceLoc &loc);
TIntermNode *addLoop(TLoopType type,
TIntermNode *init,
TIntermNode *cond,
TIntermTyped *expr,
TIntermNode *body,
const TSourceLoc &loc);
// For "if" test nodes. There are three children: a condition, a true path, and a false path.
// The two paths are in TIntermNodePair code.
TIntermNode *addIfElse(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &loc);
void addFullySpecifiedType(TPublicType *typeSpecifier);
TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
const TPublicType &typeSpecifier);
TIntermDeclaration *parseSingleDeclaration(TPublicType &publicType,
const TSourceLoc &identifierOrTypeLocation,
const ImmutableString &identifier);
TIntermDeclaration *parseSingleArrayDeclaration(TPublicType &elementType,
const TSourceLoc &identifierLocation,
const ImmutableString &identifier,
const TSourceLoc &indexLocation,
const TVector<unsigned int> &arraySizes);
TIntermDeclaration *parseSingleInitDeclaration(const TPublicType &publicType,
const TSourceLoc &identifierLocation,
const ImmutableString &identifier,
const TSourceLoc &initLocation,
TIntermTyped *initializer);
// Parse a declaration like "type a[n] = initializer"
// Note that this does not apply to declarations like "type[n] a = initializer"
TIntermDeclaration *parseSingleArrayInitDeclaration(TPublicType &elementType,
const TSourceLoc &identifierLocation,
const ImmutableString &identifier,
const TSourceLoc &indexLocation,
const TVector<unsigned int> &arraySizes,
const TSourceLoc &initLocation,
TIntermTyped *initializer);
TIntermGlobalQualifierDeclaration *parseGlobalQualifierDeclaration(
const TTypeQualifierBuilder &typeQualifierBuilder,
const TSourceLoc &identifierLoc,
const ImmutableString &identifier,
const TSymbol *symbol);
void parseDeclarator(TPublicType &publicType,
const TSourceLoc &identifierLocation,
const ImmutableString &identifier,
TIntermDeclaration *declarationOut);
void parseArrayDeclarator(TPublicType &elementType,
const TSourceLoc &identifierLocation,
const ImmutableString &identifier,
const TSourceLoc &arrayLocation,
const TVector<unsigned int> &arraySizes,
TIntermDeclaration *declarationOut);
void parseInitDeclarator(const TPublicType &publicType,
const TSourceLoc &identifierLocation,
const ImmutableString &identifier,
const TSourceLoc &initLocation,
TIntermTyped *initializer,
TIntermDeclaration *declarationOut);
// Parse a declarator like "a[n] = initializer"
void parseArrayInitDeclarator(const TPublicType &elementType,
const TSourceLoc &identifierLocation,
const ImmutableString &identifier,
const TSourceLoc &indexLocation,
const TVector<unsigned int> &arraySizes,
const TSourceLoc &initLocation,
TIntermTyped *initializer,
TIntermDeclaration *declarationOut);
TIntermNode *addEmptyStatement(const TSourceLoc &location);
void parseDefaultPrecisionQualifier(const TPrecision precision,
const TPublicType &type,
const TSourceLoc &loc);
void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder);
TIntermFunctionPrototype *addFunctionPrototypeDeclaration(const TFunction &parsedFunction,
const TSourceLoc &location);
TIntermFunctionDefinition *addFunctionDefinition(TIntermFunctionPrototype *functionPrototype,
TIntermBlock *functionBody,
const TSourceLoc &location);
void parseFunctionDefinitionHeader(const TSourceLoc &location,
const TFunction *function,
TIntermFunctionPrototype **prototypeOut);
TFunction *parseFunctionDeclarator(const TSourceLoc &location, TFunction *function);
TFunction *parseFunctionHeader(const TPublicType &type,
const ImmutableString &name,
const TSourceLoc &location);
TFunctionLookup *addNonConstructorFunc(const ImmutableString &name, const TSymbol *symbol);
TFunctionLookup *addConstructorFunc(const TPublicType &publicType);
TParameter parseParameterDeclarator(const TPublicType &type,
const ImmutableString &name,
const TSourceLoc &nameLoc);
TParameter parseParameterArrayDeclarator(const TPublicType &elementType,
const ImmutableString &name,
const TSourceLoc &nameLoc,
TVector<unsigned int> *arraySizes,
const TSourceLoc &arrayLoc);
void parseParameterQualifier(const TSourceLoc &line,
const TTypeQualifierBuilder &typeQualifierBuilder,
TPublicType &type);
TIntermTyped *addIndexExpression(TIntermTyped *baseExpression,
const TSourceLoc &location,
TIntermTyped *indexExpression);
TIntermTyped *addFieldSelectionExpression(TIntermTyped *baseExpression,
const TSourceLoc &dotLocation,
const ImmutableString &fieldString,
const TSourceLoc &fieldLocation);
// Parse declarator for a single field
TDeclarator *parseStructDeclarator(const ImmutableString &identifier, const TSourceLoc &loc);
TDeclarator *parseStructArrayDeclarator(const ImmutableString &identifier,
const TSourceLoc &loc,
const TVector<unsigned int> *arraySizes);
void checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields, const TSourceLoc &location);
void checkDoesNotHaveTooManyFields(const ImmutableString &name,
const TFieldList *fields,
const TSourceLoc &location);
TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location);
TFieldList *combineStructFieldLists(TFieldList *processedFields,
const TFieldList *newlyAddedFields,
const TSourceLoc &location);
TFieldList *addStructDeclaratorListWithQualifiers(
const TTypeQualifierBuilder &typeQualifierBuilder,
TPublicType *typeSpecifier,
const TDeclaratorList *declaratorList);
TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier,
const TDeclaratorList *declaratorList);
TTypeSpecifierNonArray addStructure(const TSourceLoc &structLine,
const TSourceLoc &nameLine,
const ImmutableString &structName,
TFieldList *fieldList);
TIntermDeclaration *addInterfaceBlock(const TTypeQualifierBuilder &typeQualifierBuilder,
const TSourceLoc &nameLine,
const ImmutableString &blockName,
TFieldList *fieldList,
const ImmutableString &instanceName,
const TSourceLoc &instanceLine,
const TVector<unsigned int> *arraySizes,
const TSourceLoc &arraySizesLine);
void parseLocalSize(const ImmutableString &qualifierType,
const TSourceLoc &qualifierTypeLine,
int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
size_t index,
sh::WorkGroupSize *localSize);
void parseNumViews(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numViews);
void parseInvocations(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numInvocations);
void parseMaxVertices(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numMaxVertices);
void parseVertices(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numVertices);
void parseIndexLayoutQualifier(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *index);
TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType,
const TSourceLoc &qualifierTypeLine);
TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType,
const TSourceLoc &qualifierTypeLine,
int intValue,
const TSourceLoc &intValueLine);
TTypeQualifierBuilder *createTypeQualifierBuilder(const TSourceLoc &loc);
TStorageQualifierWrapper *parseGlobalStorageQualifier(TQualifier qualifier,
const TSourceLoc &loc);
TStorageQualifierWrapper *parseVaryingQualifier(const TSourceLoc &loc);
TStorageQualifierWrapper *parseInQualifier(const TSourceLoc &loc);
TStorageQualifierWrapper *parseOutQualifier(const TSourceLoc &loc);
TStorageQualifierWrapper *parseInOutQualifier(const TSourceLoc &loc);
TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier,
TLayoutQualifier rightQualifier,
const TSourceLoc &rightQualifierLocation);
// Performs an error check for embedded struct declarations.
void enterStructDeclaration(const TSourceLoc &line, const ImmutableString &identifier);
void exitStructDeclaration();
void checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field);
TIntermSwitch *addSwitch(TIntermTyped *init,
TIntermBlock *statementList,
const TSourceLoc &loc);
TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc);
TIntermCase *addDefault(const TSourceLoc &loc);
TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc);
TIntermTyped *addBinaryMath(TOperator op,
TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &loc);
TIntermTyped *addBinaryMathBooleanResult(TOperator op,
TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &loc);
TIntermTyped *addAssign(TOperator op,
TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &loc);
TIntermTyped *addComma(TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, TIntermTyped *expression, const TSourceLoc &loc);
void appendStatement(TIntermBlock *block, TIntermNode *statement);
void checkTextureGather(TIntermAggregate *functionCall);
void checkTextureOffset(TIntermAggregate *functionCall);
void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall);
void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition,
const TIntermAggregate *functionCall);
void checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall);
void checkInterpolationFS(TIntermAggregate *functionCall);
// fnCall is only storing the built-in op, and function name or constructor type. arguments
// has the arguments.
TIntermTyped *addFunctionCallOrMethod(TFunctionLookup *fnCall, const TSourceLoc &loc);
TIntermTyped *addTernarySelection(TIntermTyped *cond,
TIntermTyped *trueExpression,
TIntermTyped *falseExpression,
const TSourceLoc &line);
int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; }
int getGeometryShaderInvocations() const
{
return (mGeometryShaderInvocations > 0) ? mGeometryShaderInvocations : 1;
}
TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const
{
return mGeometryShaderInputPrimitiveType;
}
TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const
{
return mGeometryShaderOutputPrimitiveType;
}
int getTessControlShaderOutputVertices() const { return mTessControlShaderOutputVertices; }
TLayoutTessEvaluationType getTessEvaluationShaderInputPrimitiveType() const
{
return mTessEvaluationShaderInputPrimitiveType;
}
TLayoutTessEvaluationType getTessEvaluationShaderInputVertexSpacingType() const
{
return mTessEvaluationShaderInputVertexSpacingType;
}
TLayoutTessEvaluationType getTessEvaluationShaderInputOrderingType() const
{
return mTessEvaluationShaderInputOrderingType;
}
TLayoutTessEvaluationType getTessEvaluationShaderInputPointType() const
{
return mTessEvaluationShaderInputPointType;
}
const TVector<TType *> &getDeferredArrayTypesToSize() const
{
return mDeferredArrayTypesToSize;
}
void markShaderHasPrecise() { mHasAnyPreciseType = true; }
bool hasAnyPreciseType() const { return mHasAnyPreciseType; }
AdvancedBlendEquations getAdvancedBlendEquations() const { return mAdvancedBlendEquations; }
ShShaderOutput getOutputType() const { return mOutputType; }
size_t getMaxExpressionComplexity() const { return mMaxExpressionComplexity; }
size_t getMaxStatementDepth() const { return mMaxStatementDepth; }
// TODO(jmadill): make this private
TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed
private:
class AtomicCounterBindingState;
constexpr static size_t kAtomicCounterSize = 4;
// UNIFORM_ARRAY_STRIDE for atomic counter arrays is an implementation-dependent value which
// can be queried after a program is linked according to ES 3.10 section 7.7.1. This is
// controversial with the offset inheritance as described in ESSL 3.10 section 4.4.6. Currently
// we treat it as always 4 in favour of the original interpretation in
// "ARB_shader_atomic_counters".
// TODO(jie.a.chen@intel.com): Double check this once the spec vagueness is resolved.
// Note that there may be tests in AtomicCounter_test that will need to be updated as well.
constexpr static size_t kAtomicCounterArrayStride = 4;
void markStaticReadIfSymbol(TIntermNode *node);
// Returns a clamped index. If it prints out an error message, the token is "[]".
int checkIndexLessThan(bool outOfRangeIndexIsError,
const TSourceLoc &location,
int index,
unsigned int arraySize,
const char *reason);
bool declareVariable(const TSourceLoc &line,
const ImmutableString &identifier,
const TType *type,
TVariable **variable);
void checkNestingLevel(const TSourceLoc &line);
void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line,
const ImmutableString &identifier,
TType *type);
void checkDeclarationIsValidArraySize(const TSourceLoc &line,
const ImmutableString &identifier,
TType *type);
bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation,
const TPublicType &elementType);
// Done for all atomic counter declarations, whether empty or not.
void atomicCounterQualifierErrorCheck(const TPublicType &publicType,
const TSourceLoc &location);
// Assumes that multiplication op has already been set based on the types.
bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right);
void checkInternalFormatIsNotSpecified(const TSourceLoc &location,
TLayoutImageInternalFormat internalFormat);
void checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier,
const TSourceLoc &location);
void checkAtomicCounterOffsetIsValid(bool forceAppend, const TSourceLoc &loc, TType *type);
void checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend,
const TSourceLoc &loc,
TType *type);
void checkAtomicCounterOffsetAlignment(const TSourceLoc &location, const TType &type);
void checkAtomicCounterOffsetLimit(const TSourceLoc &location, const TType &type);
void checkIndexIsNotSpecified(const TSourceLoc &location, int index);
void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type);
void checkBindingIsNotSpecified(const TSourceLoc &location, int binding);
void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset);
void checkImageBindingIsValid(const TSourceLoc &location,
int binding,
int arrayTotalElementCount);
void checkSamplerBindingIsValid(const TSourceLoc &location,
int binding,
int arrayTotalElementCount);
void checkBlockBindingIsValid(const TSourceLoc &location,
const TQualifier &qualifier,
int binding,
int arraySize);
void checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding);
void checkPixelLocalStorageBindingIsValid(const TSourceLoc &, const TType &);
void checkUniformLocationInRange(const TSourceLoc &location,
int objectLocationCount,
const TLayoutQualifier &layoutQualifier);
void checkAttributeLocationInRange(const TSourceLoc &location,
int objectLocationCount,
const TLayoutQualifier &layoutQualifier);
void checkDepthIsNotSpecified(const TSourceLoc &location, TLayoutDepth depth);
void checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv);
void checkEarlyFragmentTestsIsNotSpecified(const TSourceLoc &location, bool earlyFragmentTests);
void checkNoncoherentIsSpecified(const TSourceLoc &location, bool noncoherent);
void checkNoncoherentIsNotSpecified(const TSourceLoc &location, bool noncoherent);
bool checkUnsizedArrayConstructorArgumentDimensionality(const TIntermSequence &arguments,
TType type,
const TSourceLoc &line);
// Check texture offset is within range.
void checkSingleTextureOffset(const TSourceLoc &line,
const TConstantUnion *values,
size_t size,
int minOffsetValue,
int maxOffsetValue);
// Will set the size of the outermost array according to geometry shader input layout.
void checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location,
const ImmutableString &token,
TType *type);
// Similar, for tessellation shaders.
void checkTessellationShaderUnsizedArraysAndSetSize(const TSourceLoc &location,
const ImmutableString &token,
TType *type);
// Will size any unsized array type so unsized arrays won't need to be taken into account
// further along the line in parsing.
void checkIsNotUnsizedArray(const TSourceLoc &line,
const char *errorMessage,
const ImmutableString &token,
TType *arrayType);
TIntermTyped *addBinaryMathInternal(TOperator op,
TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &loc);
TIntermTyped *createUnaryMath(TOperator op,
TIntermTyped *child,
const TSourceLoc &loc,
const TFunction *func);
TIntermTyped *addMethod(TFunctionLookup *fnCall, const TSourceLoc &loc);
TIntermTyped *addConstructor(TFunctionLookup *fnCall, const TSourceLoc &line);
TIntermTyped *addNonConstructorFunctionCallImpl(TFunctionLookup *fnCall, const TSourceLoc &loc);
TIntermTyped *addNonConstructorFunctionCall(TFunctionLookup *fnCall, const TSourceLoc &loc);
// Return either the original expression or the folded version of the expression in case the
// folded node will validate the same way during subsequent parsing.
TIntermTyped *expressionOrFoldedResult(TIntermTyped *expression);
// Return true if the checks pass
bool binaryOpCommonCheck(TOperator op,
TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &loc);
TIntermFunctionPrototype *createPrototypeNodeFromFunction(const TFunction &function,
const TSourceLoc &location,
bool insertParametersToSymbolTable);
void setAtomicCounterBindingDefaultOffset(const TPublicType &declaration,
const TSourceLoc &location);
bool checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier);
bool parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier);
bool parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier);
void setGeometryShaderInputArraySize(unsigned int inputArraySize, const TSourceLoc &line);
bool parseTessControlShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier);
bool parseTessEvaluationShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier);
// Certain operations become illegal only iff the shader declares pixel local storage uniforms.
enum class PLSIllegalOperations
{
// When polyfilled with shader images, pixel local storage requires early_fragment_tests,
// which causes discard to interact differently with the depth and stencil tests.
//
// To ensure identical behavior across all backends (some of which may not have access to
// early_fragment_tests), we disallow discard if pixel local storage uniforms have been
// declared.
Discard,
// ARB_fragment_shader_interlock functions cannot be called within flow control, which
// includes any code that might execute after a return statement. To keep things simple, and
// since these "interlock" calls are automatically injected by the compiler inside of
// main(), we disallow return from main() if pixel local storage uniforms have been
// declared.
ReturnFromMain,
// When polyfilled with shader images, pixel local storage requires early_fragment_tests,
// which causes assignments to gl_FragDepth(EXT) and gl_SampleMask to be ignored.
//
// To ensure identical behavior across all backends, we disallow assignment to these values
// if pixel local storage uniforms have been declared.
AssignFragDepth,
AssignSampleMask,
// EXT_blend_func_extended may restrict the number of draw buffers with a nonzero output
// index, which can invalidate a PLS implementation.
FragDataIndexNonzero,
// KHR_blend_equation_advanced is incompatible with multiple draw buffers, which is a
// required feature for many PLS implementations.
EnableAdvancedBlendEquation,
};
// Generates an error if any pixel local storage uniforms have been declared (more specifically,
// if mPLSFormats is not empty).
//
// If no pixel local storage uniforms have been declared, and if the PLS extension is enabled,
// saves the potential error to mPLSPotentialErrors in case we encounter a PLS uniform later.
void errorIfPLSDeclared(const TSourceLoc &, PLSIllegalOperations);
// Set to true when the last/current declarator list was started with an empty declaration. The
// non-empty declaration error check will need to be performed if the empty declaration is
// followed by a declarator.
bool mDeferredNonEmptyDeclarationErrorCheck;
sh::GLenum mShaderType; // vertex/fragment/geometry/etc shader
ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES/WebGL/etc.
ShCompileOptions mCompileOptions; // Options passed to TCompiler
int mShaderVersion;
TIntermBlock *mTreeRoot; // root of parse tree being created
int mLoopNestingLevel; // 0 if outside all loops
int mStructNestingLevel; // incremented while parsing a struct declaration
int mSwitchNestingLevel; // 0 if outside all switch statements
const TType
*mCurrentFunctionType; // the return type of the function that's currently being parsed
bool mFunctionReturnsValue; // true if a non-void function has a return
bool mFragmentPrecisionHighOnESSL1; // true if highp precision is supported when compiling
// ESSL1.
bool mEarlyFragmentTestsSpecified; // true if layout(early_fragment_tests) in; is specified.
bool mHasDiscard; // true if |discard| is encountered in the shader.
bool mSampleQualifierSpecified; // true if the |sample| qualifier is used
bool mPositionRedeclaredForSeparateShaderObject; // true if EXT_separate_shader_objects is
// enabled and gl_Position is redefined.
bool mPointSizeRedeclaredForSeparateShaderObject; // true if EXT_separate_shader_objects is
// enabled and gl_PointSize is redefined.
bool mPositionOrPointSizeUsedForSeparateShaderObject; // true if gl_Position or gl_PointSize
// has been referenced.
bool mUsesDerivatives; // true if screen-space derivatives are used implicitly or explicitly
TLayoutMatrixPacking mDefaultUniformMatrixPacking;
TLayoutBlockStorage mDefaultUniformBlockStorage;
TLayoutMatrixPacking mDefaultBufferMatrixPacking;
TLayoutBlockStorage mDefaultBufferBlockStorage;
TString mHashErrMsg;
TDiagnostics *mDiagnostics;
TDirectiveHandler mDirectiveHandler;
angle::pp::Preprocessor mPreprocessor;
void *mScanner;
const size_t mMaxExpressionComplexity;
const size_t mMaxStatementDepth;
int mMinProgramTexelOffset;
int mMaxProgramTexelOffset;
int mMinProgramTextureGatherOffset;
int mMaxProgramTextureGatherOffset;
// keep track of local group size declared in layout. It should be declared only once.
bool mComputeShaderLocalSizeDeclared;
sh::WorkGroupSize mComputeShaderLocalSize;
// keep track of number of views declared in layout.
int mNumViews;
int mMaxNumViews;
int mMaxImageUnits;
int mMaxCombinedTextureImageUnits;
int mMaxUniformLocations;
int mMaxUniformBufferBindings;
int mMaxVertexAttribs;
int mMaxAtomicCounterBindings;
int mMaxAtomicCounterBufferSize;
int mMaxShaderStorageBufferBindings;
int mMaxPixelLocalStoragePlanes;
// keeps track whether we are declaring / defining a function
bool mDeclaringFunction;
// keeps track whether we are declaring / defining the function main().
bool mDeclaringMain;
// Track the state of each atomic counter binding.
std::map<int, AtomicCounterBindingState> mAtomicCounterBindingStates;
// Track the format of each pixel local storage binding.
std::map<int, ShPixelLocalStorageFormat> mPLSFormats;
// Potential errors to generate immediately upon encountering a pixel local storage uniform.
std::vector<std::tuple<const TSourceLoc, PLSIllegalOperations>> mPLSPotentialErrors;
// Track the geometry shader global parameters declared in layout.
TLayoutPrimitiveType mGeometryShaderInputPrimitiveType;
TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType;
int mGeometryShaderInvocations;
int mGeometryShaderMaxVertices;
int mMaxGeometryShaderInvocations;
int mMaxGeometryShaderMaxVertices;
unsigned int mGeometryInputArraySize;
int mMaxPatchVertices;
int mTessControlShaderOutputVertices;
TLayoutTessEvaluationType mTessEvaluationShaderInputPrimitiveType;
TLayoutTessEvaluationType mTessEvaluationShaderInputVertexSpacingType;
TLayoutTessEvaluationType mTessEvaluationShaderInputOrderingType;
TLayoutTessEvaluationType mTessEvaluationShaderInputPointType;
// List of array declarations without an explicit size that have come before layout(vertices=N).
// Once the vertex count is specified, these arrays are sized.
TVector<TType *> mDeferredArrayTypesToSize;
// Whether the |precise| keyword has been seen in the shader.
bool mHasAnyPreciseType;
AdvancedBlendEquations mAdvancedBlendEquations;
// Track when we add new scope for func body in ESSL 1.00 spec
bool mFunctionBodyNewScope;
ShShaderOutput mOutputType;
};
int PaParseStrings(size_t count,
const char *const string[],
const int length[],
TParseContext *context);
} // namespace sh
#endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_