1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 3 * ------------------------------------------------ 4 * 5 * Copyright 2015 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Shader .test file utilities. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "gluShaderLibrary.hpp" 25 26 #include "tcuStringTemplate.hpp" 27 #include "tcuResource.hpp" 28 #include "tcuTestLog.hpp" 29 30 #include "deStringUtil.hpp" 31 #include "deUniquePtr.hpp" 32 #include "deFilePath.hpp" 33 34 #include "glwEnums.hpp" 35 36 #include <sstream> 37 #include <map> 38 #include <cstdlib> 39 40 #if 0 41 # define PARSE_DBG(X) printf X 42 #else 43 # define PARSE_DBG(X) DE_NULL_STATEMENT 44 #endif 45 46 namespace glu 47 { 48 namespace sl 49 { 50 51 using namespace tcu; 52 53 using std::vector; 54 using std::string; 55 using std::map; 56 using std::ostringstream; 57 using std::pair; 58 using de::UniquePtr; 59 60 // Specification 61 62 bool isValid (const ValueBlock& block) 63 { 64 for (size_t storageNdx = 0; storageNdx < 3; ++storageNdx) 65 { 66 const vector<Value>& values = storageNdx == 0 ? block.inputs : 67 storageNdx == 1 ? block.outputs : 68 block.uniforms; 69 const size_t refArrayLen = values.empty() ? 0 : (values[0].elements.size() / (size_t)values[0].type.getScalarSize()); 70 71 for (size_t valNdx = 0; valNdx < values.size(); ++valNdx) 72 { 73 const Value& value = values[valNdx]; 74 75 if (!value.type.isBasicType()) 76 { 77 print("ERROR: Value '%s' is of unsupported type!\n", value.name.c_str()); 78 return false; 79 } 80 81 if (value.elements.size() != refArrayLen*(size_t)value.type.getScalarSize()) 82 { 83 print("ERROR: Value '%s' has invalid number of scalars!\n", value.name.c_str()); 84 return false; 85 } 86 } 87 } 88 89 return true; 90 } 91 92 bool isValid (const ShaderCaseSpecification& spec) 93 { 94 const deUint32 vtxFragMask = (1u << SHADERTYPE_VERTEX) 95 | (1u << SHADERTYPE_FRAGMENT); 96 const deUint32 tessCtrlEvalMask = (1u << SHADERTYPE_TESSELLATION_CONTROL) 97 | (1u << SHADERTYPE_TESSELLATION_EVALUATION); 98 const deUint32 supportedStageMask = vtxFragMask | tessCtrlEvalMask 99 | (1u << SHADERTYPE_GEOMETRY); 100 const bool isSeparable = !spec.programs.empty() && spec.programs[0].sources.separable; 101 102 if (spec.programs.empty()) 103 { 104 print("ERROR: No programs specified!\n"); 105 return false; 106 } 107 108 if (spec.fullGLSLES100Required) 109 { 110 if (spec.targetVersion != GLSL_VERSION_100_ES) 111 { 112 print("ERROR: Full GLSL ES 1.00 support requested for other GLSL version!\n"); 113 return false; 114 } 115 116 if (spec.expectResult != EXPECT_PASS && 117 spec.expectResult != EXPECT_VALIDATION_FAIL && 118 spec.expectResult != EXPECT_BUILD_SUCCESSFUL) 119 { 120 print("ERROR: Full GLSL ES 1.00 support doesn't make sense when expecting compile/link failure!\n"); 121 return false; 122 } 123 } 124 125 if (!de::inBounds(spec.caseType, (CaseType)0, CASETYPE_LAST)) 126 { 127 print("ERROR: Invalid case type!\n"); 128 return false; 129 } 130 131 if (!de::inBounds(spec.expectResult, (ExpectResult)0, EXPECT_LAST)) 132 { 133 print("ERROR: Invalid expected result!\n"); 134 return false; 135 } 136 137 if (!isValid(spec.values)) 138 return false; 139 140 if (!spec.values.inputs.empty() && !spec.values.outputs.empty() && 141 spec.values.inputs[0].elements.size() / spec.values.inputs[0].type.getScalarSize() != spec.values.outputs[0].elements.size() / spec.values.outputs[0].type.getScalarSize()) 142 { 143 print("ERROR: Number of input and output elements don't match!\n"); 144 return false; 145 } 146 147 if (isSeparable) 148 { 149 deUint32 usedStageMask = 0u; 150 151 if (spec.caseType != CASETYPE_COMPLETE) 152 { 153 print("ERROR: Separable shaders supported only for complete cases!\n"); 154 return false; 155 } 156 157 for (size_t progNdx = 0; progNdx < spec.programs.size(); ++progNdx) 158 { 159 for (int shaderStageNdx = 0; shaderStageNdx < SHADERTYPE_LAST; ++shaderStageNdx) 160 { 161 const deUint32 curStageMask = (1u << shaderStageNdx); 162 163 if (supportedStageMask & curStageMask) 164 { 165 const bool hasShader = !spec.programs[progNdx].sources.sources[shaderStageNdx].empty(); 166 const bool isEnabled = (spec.programs[progNdx].activeStages & curStageMask) != 0; 167 168 if (hasShader != isEnabled) 169 { 170 print("ERROR: Inconsistent source/enable for shader stage %s!\n", getShaderTypeName((ShaderType)shaderStageNdx)); 171 return false; 172 } 173 174 if (hasShader && (usedStageMask & curStageMask) != 0) 175 { 176 print("ERROR: Stage %s enabled on multiple programs!\n", getShaderTypeName((ShaderType)shaderStageNdx)); 177 return false; 178 } 179 180 if (isEnabled) 181 usedStageMask |= curStageMask; 182 } 183 else if (!spec.programs[progNdx].sources.sources[shaderStageNdx].empty()) 184 { 185 print("ERROR: Source specified for unsupported shader stage %s!\n", getShaderTypeName((ShaderType)shaderStageNdx)); 186 return false; 187 } 188 } 189 } 190 191 if ((usedStageMask & vtxFragMask) != vtxFragMask) 192 { 193 print("ERROR: Vertex and fragment shaders are mandatory!\n"); 194 return false; 195 } 196 197 if ((usedStageMask & tessCtrlEvalMask) != 0 && (usedStageMask & tessCtrlEvalMask) != tessCtrlEvalMask) 198 { 199 print("ERROR: Both tessellation control and eval shaders must be either enabled or disabled!\n"); 200 return false; 201 } 202 } 203 else 204 { 205 const bool hasVertex = !spec.programs[0].sources.sources[SHADERTYPE_VERTEX].empty(); 206 const bool hasFragment = !spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].empty(); 207 208 if (spec.programs.size() != 1) 209 { 210 print("ERROR: Only cases using separable programs can have multiple programs!\n"); 211 return false; 212 } 213 214 if (spec.caseType == CASETYPE_VERTEX_ONLY && (!hasVertex || hasFragment)) 215 { 216 print("ERROR: Vertex-only case must have only vertex shader!\n"); 217 return false; 218 } 219 220 if (spec.caseType == CASETYPE_FRAGMENT_ONLY && (hasVertex || !hasFragment)) 221 { 222 print("ERROR: Fragment-only case must have only fragment shader!\n"); 223 return false; 224 } 225 226 if (spec.caseType == CASETYPE_COMPLETE && (!hasVertex || !hasFragment)) 227 { 228 print("ERROR: Complete case must have at least vertex and fragment shaders\n"); 229 return false; 230 } 231 } 232 233 return true; 234 } 235 236 // Parser 237 238 static const glu::GLSLVersion DEFAULT_GLSL_VERSION = glu::GLSL_VERSION_100_ES; 239 240 DE_INLINE deBool isWhitespace (char c) 241 { 242 return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'); 243 } 244 245 DE_INLINE deBool isEOL (char c) 246 { 247 return (c == '\r') || (c == '\n'); 248 } 249 250 DE_INLINE deBool isNumeric (char c) 251 { 252 return deInRange32(c, '0', '9'); 253 } 254 255 DE_INLINE deBool isAlpha (char c) 256 { 257 return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z'); 258 } 259 260 DE_INLINE deBool isCaseNameChar (char c) 261 { 262 return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z') || deInRange32(c, '0', '9') || (c == '_') || (c == '-') || (c == '.'); 263 } 264 265 struct CaseRequirement 266 { 267 enum Type 268 { 269 TYPE_EXTENSION = 0, 270 TYPE_FULL_GLSL_ES_100_SUPPORT, 271 TYPE_IMPLEMENTATION_LIMIT, 272 273 TYPE_LAST 274 }; 275 276 Type type; 277 278 // TYPE_EXTENSION: 279 RequiredExtension extension; 280 281 // TYPE_IMPLEMENTATION_LIMIT 282 RequiredCapability requiredCap; 283 284 CaseRequirement (void) : type(TYPE_LAST) {} 285 286 static CaseRequirement createFullGLSLES100SpecificationRequirement (void) 287 { 288 CaseRequirement req; 289 req.type = TYPE_FULL_GLSL_ES_100_SUPPORT; 290 return req; 291 } 292 293 static CaseRequirement createAnyExtensionRequirement (const vector<string>& alternatives, deUint32 effectiveStages) 294 { 295 CaseRequirement req; 296 req.type = TYPE_EXTENSION; 297 req.extension = RequiredExtension(alternatives, effectiveStages); 298 return req; 299 } 300 301 static CaseRequirement createLimitRequirement (deUint32 enumName, int referenceValue) 302 { 303 CaseRequirement req; 304 req.type = TYPE_IMPLEMENTATION_LIMIT; 305 req.requiredCap = RequiredCapability(enumName, referenceValue); 306 return req; 307 } 308 }; 309 310 class ShaderParser 311 { 312 public: 313 ShaderParser (const tcu::Archive& archive, const std::string& filename, ShaderCaseFactory* caseFactory); 314 ~ShaderParser (void); 315 316 vector<tcu::TestNode*> parse (void); 317 318 private: 319 enum Token 320 { 321 TOKEN_INVALID = 0, 322 TOKEN_EOF, 323 TOKEN_STRING, 324 TOKEN_SHADER_SOURCE, 325 326 TOKEN_INT_LITERAL, 327 TOKEN_FLOAT_LITERAL, 328 329 // identifiers 330 TOKEN_IDENTIFIER, 331 TOKEN_TRUE, 332 TOKEN_FALSE, 333 TOKEN_DESC, 334 TOKEN_EXPECT, 335 TOKEN_GROUP, 336 TOKEN_CASE, 337 TOKEN_END, 338 TOKEN_VALUES, 339 TOKEN_BOTH, 340 TOKEN_VERTEX, 341 TOKEN_FRAGMENT, 342 TOKEN_UNIFORM, 343 TOKEN_INPUT, 344 TOKEN_OUTPUT, 345 TOKEN_FLOAT, 346 TOKEN_FLOAT_VEC2, 347 TOKEN_FLOAT_VEC3, 348 TOKEN_FLOAT_VEC4, 349 TOKEN_FLOAT_MAT2, 350 TOKEN_FLOAT_MAT2X3, 351 TOKEN_FLOAT_MAT2X4, 352 TOKEN_FLOAT_MAT3X2, 353 TOKEN_FLOAT_MAT3, 354 TOKEN_FLOAT_MAT3X4, 355 TOKEN_FLOAT_MAT4X2, 356 TOKEN_FLOAT_MAT4X3, 357 TOKEN_FLOAT_MAT4, 358 TOKEN_INT, 359 TOKEN_INT_VEC2, 360 TOKEN_INT_VEC3, 361 TOKEN_INT_VEC4, 362 TOKEN_UINT, 363 TOKEN_UINT_VEC2, 364 TOKEN_UINT_VEC3, 365 TOKEN_UINT_VEC4, 366 TOKEN_BOOL, 367 TOKEN_BOOL_VEC2, 368 TOKEN_BOOL_VEC3, 369 TOKEN_BOOL_VEC4, 370 TOKEN_VERSION, 371 TOKEN_TESSELLATION_CONTROL, 372 TOKEN_TESSELLATION_EVALUATION, 373 TOKEN_GEOMETRY, 374 TOKEN_REQUIRE, 375 TOKEN_IN, 376 TOKEN_IMPORT, 377 TOKEN_PIPELINE_PROGRAM, 378 TOKEN_ACTIVE_STAGES, 379 380 // symbols 381 TOKEN_ASSIGN, 382 TOKEN_PLUS, 383 TOKEN_MINUS, 384 TOKEN_COMMA, 385 TOKEN_VERTICAL_BAR, 386 TOKEN_SEMI_COLON, 387 TOKEN_LEFT_PAREN, 388 TOKEN_RIGHT_PAREN, 389 TOKEN_LEFT_BRACKET, 390 TOKEN_RIGHT_BRACKET, 391 TOKEN_LEFT_BRACE, 392 TOKEN_RIGHT_BRACE, 393 TOKEN_GREATER, 394 395 TOKEN_LAST 396 }; 397 398 void parseError (const std::string& errorStr); 399 float parseFloatLiteral (const char* str); 400 int parseIntLiteral (const char* str); 401 string parseStringLiteral (const char* str); 402 string parseShaderSource (const char* str); 403 void advanceToken (void); 404 void advanceToken (Token assumed); 405 void assumeToken (Token token); 406 DataType mapDataTypeToken (Token token); 407 const char* getTokenName (Token token); 408 deUint32 getShaderStageLiteralFlag (void); 409 deUint32 getGLEnumFromName (const std::string& enumName); 410 411 void parseValueElement (DataType dataType, Value& result); 412 void parseValue (ValueBlock& valueBlock); 413 void parseValueBlock (ValueBlock& valueBlock); 414 deUint32 parseShaderStageList (void); 415 void parseRequirement (CaseRequirement& valueBlock); 416 void parseExpectResult (ExpectResult& expectResult); 417 void parseGLSLVersion (glu::GLSLVersion& version); 418 void parsePipelineProgram (ProgramSpecification& program); 419 void parseShaderCase (vector<tcu::TestNode*>& shaderNodeList); 420 void parseShaderGroup (vector<tcu::TestNode*>& shaderNodeList); 421 void parseImport (vector<tcu::TestNode*>& shaderNodeList); 422 423 const tcu::Archive& m_archive; 424 const string m_filename; 425 ShaderCaseFactory* const m_caseFactory; 426 427 UniquePtr<tcu::Resource> m_resource; 428 vector<char> m_input; 429 430 const char* m_curPtr; 431 Token m_curToken; 432 std::string m_curTokenStr; 433 }; 434 435 ShaderParser::ShaderParser (const tcu::Archive& archive, const string& filename, ShaderCaseFactory* caseFactroy) 436 : m_archive (archive) 437 , m_filename (filename) 438 , m_caseFactory (caseFactroy) 439 , m_resource (archive.getResource(m_filename.c_str())) 440 , m_curPtr (DE_NULL) 441 , m_curToken (TOKEN_LAST) 442 { 443 } 444 445 ShaderParser::~ShaderParser (void) 446 { 447 } 448 449 void ShaderParser::parseError (const std::string& errorStr) 450 { 451 string atStr = string(m_curPtr, 80); 452 throw tcu::InternalError((string("Parser error: ") + errorStr + " near '" + atStr + " ...'").c_str(), DE_NULL, __FILE__, __LINE__); 453 } 454 455 float ShaderParser::parseFloatLiteral (const char* str) 456 { 457 return (float)atof(str); 458 } 459 460 int ShaderParser::parseIntLiteral (const char* str) 461 { 462 return atoi(str); 463 } 464 465 string ShaderParser::parseStringLiteral (const char* str) 466 { 467 const char* p = str; 468 char endChar = *p++; 469 ostringstream o; 470 471 while (*p != endChar && *p) 472 { 473 if (*p == '\\') 474 { 475 switch (p[1]) 476 { 477 case 0: DE_ASSERT(DE_FALSE); break; 478 case 'n': o << '\n'; break; 479 case 't': o << '\t'; break; 480 default: o << p[1]; break; 481 } 482 483 p += 2; 484 } 485 else 486 o << *p++; 487 } 488 489 return o.str(); 490 } 491 492 static string removeExtraIndentation (const string& source) 493 { 494 // Detect indentation from first line. 495 int numIndentChars = 0; 496 for (int ndx = 0; ndx < (int)source.length() && isWhitespace(source[ndx]); ndx++) 497 numIndentChars += source[ndx] == '\t' ? 4 : 1; 498 499 // Process all lines and remove preceding indentation. 500 ostringstream processed; 501 { 502 bool atLineStart = true; 503 int indentCharsOmitted = 0; 504 505 for (int pos = 0; pos < (int)source.length(); pos++) 506 { 507 char c = source[pos]; 508 509 if (atLineStart && indentCharsOmitted < numIndentChars && (c == ' ' || c == '\t')) 510 { 511 indentCharsOmitted += c == '\t' ? 4 : 1; 512 } 513 else if (isEOL(c)) 514 { 515 if (source[pos] == '\r' && source[pos+1] == '\n') 516 { 517 pos += 1; 518 processed << '\n'; 519 } 520 else 521 processed << c; 522 523 atLineStart = true; 524 indentCharsOmitted = 0; 525 } 526 else 527 { 528 processed << c; 529 atLineStart = false; 530 } 531 } 532 } 533 534 return processed.str(); 535 } 536 537 string ShaderParser::parseShaderSource (const char* str) 538 { 539 const char* p = str+2; 540 ostringstream o; 541 542 // Eat first empty line from beginning. 543 while (*p == ' ') p++; 544 if (*p == '\r') p++; 545 if (*p == '\n') p++; 546 547 while ((p[0] != '"') || (p[1] != '"')) 548 { 549 if (*p == '\\') 550 { 551 switch (p[1]) 552 { 553 case 0: DE_ASSERT(DE_FALSE); break; 554 case 'n': o << '\n'; break; 555 case 't': o << '\t'; break; 556 default: o << p[1]; break; 557 } 558 559 p += 2; 560 } 561 else 562 o << *p++; 563 } 564 565 return removeExtraIndentation(o.str()); 566 } 567 568 void ShaderParser::advanceToken (void) 569 { 570 // Skip old token. 571 m_curPtr += m_curTokenStr.length(); 572 573 // Reset token (for safety). 574 m_curToken = TOKEN_INVALID; 575 m_curTokenStr = ""; 576 577 // Eat whitespace & comments while they last. 578 for (;;) 579 { 580 while (isWhitespace(*m_curPtr)) 581 m_curPtr++; 582 583 // Check for EOL comment. 584 if (*m_curPtr == '#') 585 { 586 while (*m_curPtr && !isEOL(*m_curPtr)) 587 m_curPtr++; 588 } 589 else 590 break; 591 } 592 593 if (!*m_curPtr) 594 { 595 m_curToken = TOKEN_EOF; 596 m_curTokenStr = "<EOF>"; 597 } 598 else if (isAlpha(*m_curPtr)) 599 { 600 struct Named 601 { 602 const char* str; 603 Token token; 604 }; 605 606 static const Named s_named[] = 607 { 608 { "true", TOKEN_TRUE }, 609 { "false", TOKEN_FALSE }, 610 { "desc", TOKEN_DESC }, 611 { "expect", TOKEN_EXPECT }, 612 { "group", TOKEN_GROUP }, 613 { "case", TOKEN_CASE }, 614 { "end", TOKEN_END }, 615 { "values", TOKEN_VALUES }, 616 { "both", TOKEN_BOTH }, 617 { "vertex", TOKEN_VERTEX }, 618 { "fragment", TOKEN_FRAGMENT }, 619 { "uniform", TOKEN_UNIFORM }, 620 { "input", TOKEN_INPUT }, 621 { "output", TOKEN_OUTPUT }, 622 { "float", TOKEN_FLOAT }, 623 { "vec2", TOKEN_FLOAT_VEC2 }, 624 { "vec3", TOKEN_FLOAT_VEC3 }, 625 { "vec4", TOKEN_FLOAT_VEC4 }, 626 { "mat2", TOKEN_FLOAT_MAT2 }, 627 { "mat2x3", TOKEN_FLOAT_MAT2X3 }, 628 { "mat2x4", TOKEN_FLOAT_MAT2X4 }, 629 { "mat3x2", TOKEN_FLOAT_MAT3X2 }, 630 { "mat3", TOKEN_FLOAT_MAT3 }, 631 { "mat3x4", TOKEN_FLOAT_MAT3X4 }, 632 { "mat4x2", TOKEN_FLOAT_MAT4X2 }, 633 { "mat4x3", TOKEN_FLOAT_MAT4X3 }, 634 { "mat4", TOKEN_FLOAT_MAT4 }, 635 { "int", TOKEN_INT }, 636 { "ivec2", TOKEN_INT_VEC2 }, 637 { "ivec3", TOKEN_INT_VEC3 }, 638 { "ivec4", TOKEN_INT_VEC4 }, 639 { "uint", TOKEN_UINT }, 640 { "uvec2", TOKEN_UINT_VEC2 }, 641 { "uvec3", TOKEN_UINT_VEC3 }, 642 { "uvec4", TOKEN_UINT_VEC4 }, 643 { "bool", TOKEN_BOOL }, 644 { "bvec2", TOKEN_BOOL_VEC2 }, 645 { "bvec3", TOKEN_BOOL_VEC3 }, 646 { "bvec4", TOKEN_BOOL_VEC4 }, 647 { "version", TOKEN_VERSION }, 648 { "tessellation_control", TOKEN_TESSELLATION_CONTROL }, 649 { "tessellation_evaluation", TOKEN_TESSELLATION_EVALUATION }, 650 { "geometry", TOKEN_GEOMETRY }, 651 { "require", TOKEN_REQUIRE }, 652 { "in", TOKEN_IN }, 653 { "import", TOKEN_IMPORT }, 654 { "pipeline_program", TOKEN_PIPELINE_PROGRAM }, 655 { "active_stages", TOKEN_ACTIVE_STAGES }, 656 }; 657 658 const char* end = m_curPtr + 1; 659 while (isCaseNameChar(*end)) 660 end++; 661 m_curTokenStr = string(m_curPtr, end - m_curPtr); 662 663 m_curToken = TOKEN_IDENTIFIER; 664 665 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_named); ndx++) 666 { 667 if (m_curTokenStr == s_named[ndx].str) 668 { 669 m_curToken = s_named[ndx].token; 670 break; 671 } 672 } 673 } 674 else if (isNumeric(*m_curPtr)) 675 { 676 /* \todo [2010-03-31 petri] Hex? */ 677 const char* p = m_curPtr; 678 while (isNumeric(*p)) 679 p++; 680 if (*p == '.') 681 { 682 p++; 683 while (isNumeric(*p)) 684 p++; 685 686 if (*p == 'e' || *p == 'E') 687 { 688 p++; 689 if (*p == '+' || *p == '-') 690 p++; 691 DE_ASSERT(isNumeric(*p)); 692 while (isNumeric(*p)) 693 p++; 694 } 695 696 m_curToken = TOKEN_FLOAT_LITERAL; 697 m_curTokenStr = string(m_curPtr, p - m_curPtr); 698 } 699 else 700 { 701 m_curToken = TOKEN_INT_LITERAL; 702 m_curTokenStr = string(m_curPtr, p - m_curPtr); 703 } 704 } 705 else if (*m_curPtr == '"' && m_curPtr[1] == '"') 706 { 707 const char* p = m_curPtr + 2; 708 709 while ((p[0] != '"') || (p[1] != '"')) 710 { 711 DE_ASSERT(*p); 712 if (*p == '\\') 713 { 714 DE_ASSERT(p[1] != 0); 715 p += 2; 716 } 717 else 718 p++; 719 } 720 p += 2; 721 722 m_curToken = TOKEN_SHADER_SOURCE; 723 m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr)); 724 } 725 else if (*m_curPtr == '"' || *m_curPtr == '\'') 726 { 727 char endChar = *m_curPtr; 728 const char* p = m_curPtr + 1; 729 730 while (*p != endChar) 731 { 732 DE_ASSERT(*p); 733 if (*p == '\\') 734 { 735 DE_ASSERT(p[1] != 0); 736 p += 2; 737 } 738 else 739 p++; 740 } 741 p++; 742 743 m_curToken = TOKEN_STRING; 744 m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr)); 745 } 746 else 747 { 748 struct SimpleToken 749 { 750 const char* str; 751 Token token; 752 }; 753 754 static const SimpleToken s_simple[] = 755 { 756 { "=", TOKEN_ASSIGN }, 757 { "+", TOKEN_PLUS }, 758 { "-", TOKEN_MINUS }, 759 { ",", TOKEN_COMMA }, 760 { "|", TOKEN_VERTICAL_BAR }, 761 { ";", TOKEN_SEMI_COLON }, 762 { "(", TOKEN_LEFT_PAREN }, 763 { ")", TOKEN_RIGHT_PAREN }, 764 { "[", TOKEN_LEFT_BRACKET }, 765 { "]", TOKEN_RIGHT_BRACKET }, 766 { "{", TOKEN_LEFT_BRACE }, 767 { "}", TOKEN_RIGHT_BRACE }, 768 { ">", TOKEN_GREATER }, 769 }; 770 771 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_simple); ndx++) 772 { 773 if (strncmp(s_simple[ndx].str, m_curPtr, strlen(s_simple[ndx].str)) == 0) 774 { 775 m_curToken = s_simple[ndx].token; 776 m_curTokenStr = s_simple[ndx].str; 777 return; 778 } 779 } 780 781 // Otherwise invalid token. 782 m_curToken = TOKEN_INVALID; 783 m_curTokenStr = *m_curPtr; 784 } 785 } 786 787 void ShaderParser::advanceToken (Token assumed) 788 { 789 assumeToken(assumed); 790 advanceToken(); 791 } 792 793 void ShaderParser::assumeToken (Token token) 794 { 795 if (m_curToken != token) 796 parseError((string("unexpected token '") + m_curTokenStr + "', expecting '" + getTokenName(token) + "'").c_str()); 797 DE_TEST_ASSERT(m_curToken == token); 798 } 799 800 DataType ShaderParser::mapDataTypeToken (Token token) 801 { 802 switch (token) 803 { 804 case TOKEN_FLOAT: return TYPE_FLOAT; 805 case TOKEN_FLOAT_VEC2: return TYPE_FLOAT_VEC2; 806 case TOKEN_FLOAT_VEC3: return TYPE_FLOAT_VEC3; 807 case TOKEN_FLOAT_VEC4: return TYPE_FLOAT_VEC4; 808 case TOKEN_FLOAT_MAT2: return TYPE_FLOAT_MAT2; 809 case TOKEN_FLOAT_MAT2X3: return TYPE_FLOAT_MAT2X3; 810 case TOKEN_FLOAT_MAT2X4: return TYPE_FLOAT_MAT2X4; 811 case TOKEN_FLOAT_MAT3X2: return TYPE_FLOAT_MAT3X2; 812 case TOKEN_FLOAT_MAT3: return TYPE_FLOAT_MAT3; 813 case TOKEN_FLOAT_MAT3X4: return TYPE_FLOAT_MAT3X4; 814 case TOKEN_FLOAT_MAT4X2: return TYPE_FLOAT_MAT4X2; 815 case TOKEN_FLOAT_MAT4X3: return TYPE_FLOAT_MAT4X3; 816 case TOKEN_FLOAT_MAT4: return TYPE_FLOAT_MAT4; 817 case TOKEN_INT: return TYPE_INT; 818 case TOKEN_INT_VEC2: return TYPE_INT_VEC2; 819 case TOKEN_INT_VEC3: return TYPE_INT_VEC3; 820 case TOKEN_INT_VEC4: return TYPE_INT_VEC4; 821 case TOKEN_UINT: return TYPE_UINT; 822 case TOKEN_UINT_VEC2: return TYPE_UINT_VEC2; 823 case TOKEN_UINT_VEC3: return TYPE_UINT_VEC3; 824 case TOKEN_UINT_VEC4: return TYPE_UINT_VEC4; 825 case TOKEN_BOOL: return TYPE_BOOL; 826 case TOKEN_BOOL_VEC2: return TYPE_BOOL_VEC2; 827 case TOKEN_BOOL_VEC3: return TYPE_BOOL_VEC3; 828 case TOKEN_BOOL_VEC4: return TYPE_BOOL_VEC4; 829 default: return TYPE_INVALID; 830 } 831 } 832 833 const char* ShaderParser::getTokenName (Token token) 834 { 835 switch (token) 836 { 837 case TOKEN_INVALID: return "<invalid>"; 838 case TOKEN_EOF: return "<eof>"; 839 case TOKEN_STRING: return "<string>"; 840 case TOKEN_SHADER_SOURCE: return "source"; 841 842 case TOKEN_INT_LITERAL: return "<int>"; 843 case TOKEN_FLOAT_LITERAL: return "<float>"; 844 845 // identifiers 846 case TOKEN_IDENTIFIER: return "<identifier>"; 847 case TOKEN_TRUE: return "true"; 848 case TOKEN_FALSE: return "false"; 849 case TOKEN_DESC: return "desc"; 850 case TOKEN_EXPECT: return "expect"; 851 case TOKEN_GROUP: return "group"; 852 case TOKEN_CASE: return "case"; 853 case TOKEN_END: return "end"; 854 case TOKEN_VALUES: return "values"; 855 case TOKEN_BOTH: return "both"; 856 case TOKEN_VERTEX: return "vertex"; 857 case TOKEN_FRAGMENT: return "fragment"; 858 case TOKEN_TESSELLATION_CONTROL: return "tessellation_control"; 859 case TOKEN_TESSELLATION_EVALUATION: return "tessellation_evaluation"; 860 case TOKEN_GEOMETRY: return "geometry"; 861 case TOKEN_REQUIRE: return "require"; 862 case TOKEN_UNIFORM: return "uniform"; 863 case TOKEN_INPUT: return "input"; 864 case TOKEN_OUTPUT: return "output"; 865 case TOKEN_FLOAT: return "float"; 866 case TOKEN_FLOAT_VEC2: return "vec2"; 867 case TOKEN_FLOAT_VEC3: return "vec3"; 868 case TOKEN_FLOAT_VEC4: return "vec4"; 869 case TOKEN_FLOAT_MAT2: return "mat2"; 870 case TOKEN_FLOAT_MAT2X3: return "mat2x3"; 871 case TOKEN_FLOAT_MAT2X4: return "mat2x4"; 872 case TOKEN_FLOAT_MAT3X2: return "mat3x2"; 873 case TOKEN_FLOAT_MAT3: return "mat3"; 874 case TOKEN_FLOAT_MAT3X4: return "mat3x4"; 875 case TOKEN_FLOAT_MAT4X2: return "mat4x2"; 876 case TOKEN_FLOAT_MAT4X3: return "mat4x3"; 877 case TOKEN_FLOAT_MAT4: return "mat4"; 878 case TOKEN_INT: return "int"; 879 case TOKEN_INT_VEC2: return "ivec2"; 880 case TOKEN_INT_VEC3: return "ivec3"; 881 case TOKEN_INT_VEC4: return "ivec4"; 882 case TOKEN_UINT: return "uint"; 883 case TOKEN_UINT_VEC2: return "uvec2"; 884 case TOKEN_UINT_VEC3: return "uvec3"; 885 case TOKEN_UINT_VEC4: return "uvec4"; 886 case TOKEN_BOOL: return "bool"; 887 case TOKEN_BOOL_VEC2: return "bvec2"; 888 case TOKEN_BOOL_VEC3: return "bvec3"; 889 case TOKEN_BOOL_VEC4: return "bvec4"; 890 case TOKEN_IN: return "in"; 891 case TOKEN_IMPORT: return "import"; 892 case TOKEN_PIPELINE_PROGRAM: return "pipeline_program"; 893 case TOKEN_ACTIVE_STAGES: return "active_stages"; 894 895 case TOKEN_ASSIGN: return "="; 896 case TOKEN_PLUS: return "+"; 897 case TOKEN_MINUS: return "-"; 898 case TOKEN_COMMA: return ","; 899 case TOKEN_VERTICAL_BAR: return "|"; 900 case TOKEN_SEMI_COLON: return ";"; 901 case TOKEN_LEFT_PAREN: return "("; 902 case TOKEN_RIGHT_PAREN: return ")"; 903 case TOKEN_LEFT_BRACKET: return "["; 904 case TOKEN_RIGHT_BRACKET: return "]"; 905 case TOKEN_LEFT_BRACE: return "{"; 906 case TOKEN_RIGHT_BRACE: return "}"; 907 case TOKEN_GREATER: return ">"; 908 909 default: return "<unknown>"; 910 } 911 } 912 913 deUint32 ShaderParser::getShaderStageLiteralFlag (void) 914 { 915 switch (m_curToken) 916 { 917 case TOKEN_VERTEX: return (1 << glu::SHADERTYPE_VERTEX); 918 case TOKEN_FRAGMENT: return (1 << glu::SHADERTYPE_FRAGMENT); 919 case TOKEN_GEOMETRY: return (1 << glu::SHADERTYPE_GEOMETRY); 920 case TOKEN_TESSELLATION_CONTROL: return (1 << glu::SHADERTYPE_TESSELLATION_CONTROL); 921 case TOKEN_TESSELLATION_EVALUATION: return (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION); 922 923 default: 924 parseError(std::string() + "invalid shader stage name, got " + m_curTokenStr); 925 return 0; 926 } 927 } 928 929 deUint32 ShaderParser::getGLEnumFromName (const std::string& enumName) 930 { 931 static const struct 932 { 933 const char* name; 934 deUint32 value; 935 } names[] = 936 { 937 { "GL_MAX_VERTEX_IMAGE_UNIFORMS", GL_MAX_VERTEX_IMAGE_UNIFORMS }, 938 { "GL_MAX_VERTEX_ATOMIC_COUNTERS", GL_MAX_VERTEX_ATOMIC_COUNTERS }, 939 { "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS", GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS }, 940 { "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS", GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS }, 941 }; 942 943 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(names); ++ndx) 944 if (names[ndx].name == enumName) 945 return names[ndx].value; 946 947 parseError(std::string() + "unknown enum name, got " + enumName); 948 return 0; 949 } 950 951 void ShaderParser::parseValueElement (DataType expectedDataType, Value& result) 952 { 953 DataType scalarType = getDataTypeScalarType(expectedDataType); 954 int scalarSize = getDataTypeScalarSize(expectedDataType); 955 956 /* \todo [2010-04-19 petri] Support arrays. */ 957 Value::Element elems[16]; 958 959 if (scalarSize > 1) 960 { 961 DE_ASSERT(mapDataTypeToken(m_curToken) == expectedDataType); 962 advanceToken(); // data type (float, vec2, etc.) 963 advanceToken(TOKEN_LEFT_PAREN); 964 } 965 966 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 967 { 968 if (scalarType == TYPE_FLOAT) 969 { 970 float signMult = 1.0f; 971 if (m_curToken == TOKEN_MINUS) 972 { 973 signMult = -1.0f; 974 advanceToken(); 975 } 976 977 assumeToken(TOKEN_FLOAT_LITERAL); 978 elems[scalarNdx].float32 = signMult * parseFloatLiteral(m_curTokenStr.c_str()); 979 advanceToken(TOKEN_FLOAT_LITERAL); 980 } 981 else if (scalarType == TYPE_INT || scalarType == TYPE_UINT) 982 { 983 int signMult = 1; 984 if (m_curToken == TOKEN_MINUS) 985 { 986 signMult = -1; 987 advanceToken(); 988 } 989 990 assumeToken(TOKEN_INT_LITERAL); 991 elems[scalarNdx].int32 = signMult * parseIntLiteral(m_curTokenStr.c_str()); 992 advanceToken(TOKEN_INT_LITERAL); 993 } 994 else 995 { 996 DE_ASSERT(scalarType == TYPE_BOOL); 997 elems[scalarNdx].bool32 = (m_curToken == TOKEN_TRUE); 998 if (m_curToken != TOKEN_TRUE && m_curToken != TOKEN_FALSE) 999 parseError(string("unexpected token, expecting bool: " + m_curTokenStr)); 1000 advanceToken(); // true/false 1001 } 1002 1003 if (scalarNdx != (scalarSize - 1)) 1004 advanceToken(TOKEN_COMMA); 1005 } 1006 1007 if (scalarSize > 1) 1008 advanceToken(TOKEN_RIGHT_PAREN); 1009 1010 // Store results. 1011 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1012 result.elements.push_back(elems[scalarNdx]); 1013 } 1014 1015 void ShaderParser::parseValue (ValueBlock& valueBlock) 1016 { 1017 PARSE_DBG((" parseValue()\n")); 1018 1019 // Parsed results. 1020 vector<Value>* dstBlock = DE_NULL; 1021 DataType basicType = TYPE_LAST; 1022 std::string valueName; 1023 1024 // Parse storage. 1025 if (m_curToken == TOKEN_UNIFORM) 1026 dstBlock = &valueBlock.uniforms; 1027 else if (m_curToken == TOKEN_INPUT) 1028 dstBlock = &valueBlock.inputs; 1029 else if (m_curToken == TOKEN_OUTPUT) 1030 dstBlock = &valueBlock.outputs; 1031 else 1032 parseError(string("unexpected token encountered when parsing value classifier")); 1033 advanceToken(); 1034 1035 // Parse data type. 1036 basicType = mapDataTypeToken(m_curToken); 1037 if (basicType == TYPE_INVALID) 1038 parseError(string("unexpected token when parsing value data type: " + m_curTokenStr)); 1039 advanceToken(); 1040 1041 // Parse value name. 1042 if (m_curToken == TOKEN_IDENTIFIER || m_curToken == TOKEN_STRING) 1043 { 1044 if (m_curToken == TOKEN_IDENTIFIER) 1045 valueName = m_curTokenStr; 1046 else 1047 valueName = parseStringLiteral(m_curTokenStr.c_str()); 1048 } 1049 else 1050 parseError(string("unexpected token when parsing value name: " + m_curTokenStr)); 1051 advanceToken(); 1052 1053 // Parse assignment operator. 1054 advanceToken(TOKEN_ASSIGN); 1055 1056 { 1057 Value value; 1058 value.name = valueName; 1059 value.type = VarType(basicType, PRECISION_LAST); 1060 dstBlock->push_back(value); 1061 } 1062 1063 // Parse actual value. 1064 if (m_curToken == TOKEN_LEFT_BRACKET) // value list 1065 { 1066 int arrayLength = 0; // \todo [2015-08-03 pyry] Currently unused 1067 1068 advanceToken(TOKEN_LEFT_BRACKET); 1069 1070 for (;;) 1071 { 1072 parseValueElement(basicType, dstBlock->back()); 1073 arrayLength++; 1074 1075 if (m_curToken == TOKEN_RIGHT_BRACKET) 1076 break; 1077 else if (m_curToken == TOKEN_VERTICAL_BAR) 1078 { 1079 advanceToken(); 1080 continue; 1081 } 1082 else 1083 parseError(string("unexpected token in value element array: " + m_curTokenStr)); 1084 } 1085 1086 advanceToken(TOKEN_RIGHT_BRACKET); 1087 } 1088 else // single elements 1089 { 1090 parseValueElement(basicType, dstBlock->back()); 1091 } 1092 1093 advanceToken(TOKEN_SEMI_COLON); // end of declaration 1094 } 1095 1096 void ShaderParser::parseValueBlock (ValueBlock& valueBlock) 1097 { 1098 PARSE_DBG((" parseValueBlock()\n")); 1099 advanceToken(TOKEN_VALUES); 1100 advanceToken(TOKEN_LEFT_BRACE); 1101 1102 for (;;) 1103 { 1104 if (m_curToken == TOKEN_UNIFORM || m_curToken == TOKEN_INPUT || m_curToken == TOKEN_OUTPUT) 1105 parseValue(valueBlock); 1106 else if (m_curToken == TOKEN_RIGHT_BRACE) 1107 break; 1108 else 1109 parseError(string("unexpected token when parsing a value block: " + m_curTokenStr)); 1110 } 1111 1112 advanceToken(TOKEN_RIGHT_BRACE); 1113 } 1114 1115 deUint32 ShaderParser::parseShaderStageList (void) 1116 { 1117 deUint32 mask = 0; 1118 1119 assumeToken(TOKEN_LEFT_BRACE); 1120 1121 // don't allow 0-sized lists 1122 advanceToken(); 1123 mask |= getShaderStageLiteralFlag(); 1124 advanceToken(); 1125 1126 for (;;) 1127 { 1128 if (m_curToken == TOKEN_RIGHT_BRACE) 1129 break; 1130 else if (m_curToken == TOKEN_COMMA) 1131 { 1132 deUint32 stageFlag; 1133 advanceToken(); 1134 1135 stageFlag = getShaderStageLiteralFlag(); 1136 if (stageFlag & mask) 1137 parseError(string("stage already set in the shader stage set: " + m_curTokenStr)); 1138 1139 mask |= stageFlag; 1140 advanceToken(); 1141 } 1142 else 1143 parseError(string("invalid shader stage set token: " + m_curTokenStr)); 1144 } 1145 advanceToken(TOKEN_RIGHT_BRACE); 1146 1147 return mask; 1148 } 1149 1150 void ShaderParser::parseRequirement (CaseRequirement& valueBlock) 1151 { 1152 PARSE_DBG((" parseRequirement()\n")); 1153 1154 advanceToken(); 1155 assumeToken(TOKEN_IDENTIFIER); 1156 1157 if (m_curTokenStr == "extension") 1158 { 1159 std::vector<std::string> anyExtensionStringList; 1160 deUint32 affectedCasesFlags = -1; // by default all stages 1161 1162 advanceToken(); 1163 assumeToken(TOKEN_LEFT_BRACE); 1164 1165 advanceToken(); 1166 assumeToken(TOKEN_STRING); 1167 1168 anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str())); 1169 advanceToken(); 1170 1171 for (;;) 1172 { 1173 if (m_curToken == TOKEN_RIGHT_BRACE) 1174 break; 1175 else if (m_curToken == TOKEN_VERTICAL_BAR) 1176 { 1177 advanceToken(); 1178 assumeToken(TOKEN_STRING); 1179 1180 anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str())); 1181 advanceToken(); 1182 } 1183 else 1184 parseError(string("invalid extension list token: " + m_curTokenStr)); 1185 } 1186 advanceToken(TOKEN_RIGHT_BRACE); 1187 1188 if (m_curToken == TOKEN_IN) 1189 { 1190 advanceToken(); 1191 affectedCasesFlags = parseShaderStageList(); 1192 } 1193 1194 valueBlock = CaseRequirement::createAnyExtensionRequirement(anyExtensionStringList, affectedCasesFlags); 1195 } 1196 else if (m_curTokenStr == "limit") 1197 { 1198 deUint32 limitEnum; 1199 int limitValue; 1200 1201 advanceToken(); 1202 1203 assumeToken(TOKEN_STRING); 1204 limitEnum = getGLEnumFromName(parseStringLiteral(m_curTokenStr.c_str())); 1205 advanceToken(); 1206 1207 assumeToken(TOKEN_GREATER); 1208 advanceToken(); 1209 1210 assumeToken(TOKEN_INT_LITERAL); 1211 limitValue = parseIntLiteral(m_curTokenStr.c_str()); 1212 advanceToken(); 1213 1214 valueBlock = CaseRequirement::createLimitRequirement(limitEnum, limitValue); 1215 } 1216 else if (m_curTokenStr == "full_glsl_es_100_support") 1217 { 1218 advanceToken(); 1219 1220 valueBlock = CaseRequirement::createFullGLSLES100SpecificationRequirement(); 1221 } 1222 else 1223 parseError(string("invalid requirement value: " + m_curTokenStr)); 1224 } 1225 1226 void ShaderParser::parseExpectResult (ExpectResult& expectResult) 1227 { 1228 assumeToken(TOKEN_IDENTIFIER); 1229 1230 if (m_curTokenStr == "pass") 1231 expectResult = EXPECT_PASS; 1232 else if (m_curTokenStr == "compile_fail") 1233 expectResult = EXPECT_COMPILE_FAIL; 1234 else if (m_curTokenStr == "link_fail") 1235 expectResult = EXPECT_LINK_FAIL; 1236 else if (m_curTokenStr == "compile_or_link_fail") 1237 expectResult = EXPECT_COMPILE_LINK_FAIL; 1238 else if (m_curTokenStr == "validation_fail") 1239 expectResult = EXPECT_VALIDATION_FAIL; 1240 else if (m_curTokenStr == "build_successful") 1241 expectResult = EXPECT_BUILD_SUCCESSFUL; 1242 else 1243 parseError(string("invalid expected result value: " + m_curTokenStr)); 1244 1245 advanceToken(); 1246 } 1247 1248 void ShaderParser::parseGLSLVersion (glu::GLSLVersion& version) 1249 { 1250 int versionNum = 0; 1251 std::string postfix = ""; 1252 1253 assumeToken(TOKEN_INT_LITERAL); 1254 versionNum = parseIntLiteral(m_curTokenStr.c_str()); 1255 advanceToken(); 1256 1257 if (m_curToken == TOKEN_IDENTIFIER) 1258 { 1259 postfix = m_curTokenStr; 1260 advanceToken(); 1261 } 1262 1263 DE_STATIC_ASSERT(glu::GLSL_VERSION_LAST == 14); 1264 1265 if (versionNum == 100 && postfix == "es") version = glu::GLSL_VERSION_100_ES; 1266 else if (versionNum == 300 && postfix == "es") version = glu::GLSL_VERSION_300_ES; 1267 else if (versionNum == 310 && postfix == "es") version = glu::GLSL_VERSION_310_ES; 1268 else if (versionNum == 320 && postfix == "es") version = glu::GLSL_VERSION_320_ES; 1269 else if (versionNum == 130) version = glu::GLSL_VERSION_130; 1270 else if (versionNum == 140) version = glu::GLSL_VERSION_140; 1271 else if (versionNum == 150) version = glu::GLSL_VERSION_150; 1272 else if (versionNum == 330) version = glu::GLSL_VERSION_330; 1273 else if (versionNum == 400) version = glu::GLSL_VERSION_400; 1274 else if (versionNum == 410) version = glu::GLSL_VERSION_410; 1275 else if (versionNum == 420) version = glu::GLSL_VERSION_420; 1276 else if (versionNum == 430) version = glu::GLSL_VERSION_430; 1277 else if (versionNum == 440) version = glu::GLSL_VERSION_440; 1278 else if (versionNum == 450) version = glu::GLSL_VERSION_450; 1279 else 1280 parseError("Unknown GLSL version"); 1281 } 1282 1283 void ShaderParser::parsePipelineProgram (ProgramSpecification& program) 1284 { 1285 advanceToken(TOKEN_PIPELINE_PROGRAM); 1286 1287 for (;;) 1288 { 1289 if (m_curToken == TOKEN_END) 1290 break; 1291 else if (m_curToken == TOKEN_ACTIVE_STAGES) 1292 { 1293 advanceToken(); 1294 program.activeStages = parseShaderStageList(); 1295 } 1296 else if (m_curToken == TOKEN_REQUIRE) 1297 { 1298 CaseRequirement requirement; 1299 parseRequirement(requirement); 1300 1301 if (requirement.type == CaseRequirement::TYPE_EXTENSION) 1302 program.requiredExtensions.push_back(requirement.extension); 1303 else 1304 parseError("only extension requirements are allowed inside pipeline program"); 1305 } 1306 else if (m_curToken == TOKEN_VERTEX || 1307 m_curToken == TOKEN_FRAGMENT || 1308 m_curToken == TOKEN_TESSELLATION_CONTROL || 1309 m_curToken == TOKEN_TESSELLATION_EVALUATION || 1310 m_curToken == TOKEN_GEOMETRY) 1311 { 1312 const Token token = m_curToken; 1313 string source; 1314 1315 advanceToken(); 1316 assumeToken(TOKEN_SHADER_SOURCE); 1317 source = parseShaderSource(m_curTokenStr.c_str()); 1318 advanceToken(); 1319 1320 switch (token) 1321 { 1322 case TOKEN_VERTEX: program.sources.sources[SHADERTYPE_VERTEX].push_back(source); break; 1323 case TOKEN_FRAGMENT: program.sources.sources[SHADERTYPE_FRAGMENT].push_back(source); break; 1324 case TOKEN_TESSELLATION_CONTROL: program.sources.sources[SHADERTYPE_TESSELLATION_CONTROL].push_back(source); break; 1325 case TOKEN_TESSELLATION_EVALUATION: program.sources.sources[SHADERTYPE_TESSELLATION_EVALUATION].push_back(source); break; 1326 case TOKEN_GEOMETRY: program.sources.sources[SHADERTYPE_GEOMETRY].push_back(source); break; 1327 default: 1328 parseError(DE_FALSE); 1329 } 1330 } 1331 else 1332 parseError(string("invalid pipeline program value: " + m_curTokenStr)); 1333 } 1334 advanceToken(TOKEN_END); 1335 1336 if (program.activeStages == 0) 1337 parseError("program pipeline object must have active stages"); 1338 } 1339 1340 void ShaderParser::parseShaderCase (vector<tcu::TestNode*>& shaderNodeList) 1341 { 1342 // Parse 'case'. 1343 PARSE_DBG((" parseShaderCase()\n")); 1344 advanceToken(TOKEN_CASE); 1345 1346 // Parse case name. 1347 string caseName = m_curTokenStr; 1348 advanceToken(); // \note [pyry] All token types are allowed here. 1349 1350 // \todo [pyry] Optimize by parsing most stuff directly to ShaderCaseSpecification 1351 1352 // Setup case. 1353 GLSLVersion version = DEFAULT_GLSL_VERSION; 1354 ExpectResult expectResult = EXPECT_PASS; 1355 string description; 1356 string bothSource; 1357 vector<string> vertexSources; 1358 vector<string> fragmentSources; 1359 vector<string> tessellationCtrlSources; 1360 vector<string> tessellationEvalSources; 1361 vector<string> geometrySources; 1362 ValueBlock valueBlock; 1363 bool valueBlockSeen = false; 1364 vector<CaseRequirement> requirements; 1365 vector<ProgramSpecification> pipelinePrograms; 1366 1367 for (;;) 1368 { 1369 if (m_curToken == TOKEN_END) 1370 break; 1371 else if (m_curToken == TOKEN_DESC) 1372 { 1373 advanceToken(); 1374 assumeToken(TOKEN_STRING); 1375 description = parseStringLiteral(m_curTokenStr.c_str()); 1376 advanceToken(); 1377 } 1378 else if (m_curToken == TOKEN_EXPECT) 1379 { 1380 advanceToken(); 1381 parseExpectResult(expectResult); 1382 } 1383 else if (m_curToken == TOKEN_VALUES) 1384 { 1385 if (valueBlockSeen) 1386 parseError("multiple value blocks"); 1387 parseValueBlock(valueBlock); 1388 valueBlockSeen = true; 1389 } 1390 else if (m_curToken == TOKEN_BOTH || 1391 m_curToken == TOKEN_VERTEX || 1392 m_curToken == TOKEN_FRAGMENT || 1393 m_curToken == TOKEN_TESSELLATION_CONTROL || 1394 m_curToken == TOKEN_TESSELLATION_EVALUATION || 1395 m_curToken == TOKEN_GEOMETRY) 1396 { 1397 const Token token = m_curToken; 1398 string source; 1399 1400 advanceToken(); 1401 assumeToken(TOKEN_SHADER_SOURCE); 1402 source = parseShaderSource(m_curTokenStr.c_str()); 1403 advanceToken(); 1404 1405 switch (token) 1406 { 1407 case TOKEN_VERTEX: vertexSources.push_back(source); break; 1408 case TOKEN_FRAGMENT: fragmentSources.push_back(source); break; 1409 case TOKEN_TESSELLATION_CONTROL: tessellationCtrlSources.push_back(source); break; 1410 case TOKEN_TESSELLATION_EVALUATION: tessellationEvalSources.push_back(source); break; 1411 case TOKEN_GEOMETRY: geometrySources.push_back(source); break; 1412 case TOKEN_BOTH: 1413 { 1414 if (!bothSource.empty()) 1415 parseError("multiple 'both' blocks"); 1416 bothSource = source; 1417 break; 1418 } 1419 1420 default: 1421 parseError(DE_FALSE); 1422 } 1423 } 1424 else if (m_curToken == TOKEN_VERSION) 1425 { 1426 advanceToken(); 1427 parseGLSLVersion(version); 1428 } 1429 else if (m_curToken == TOKEN_REQUIRE) 1430 { 1431 CaseRequirement requirement; 1432 parseRequirement(requirement); 1433 requirements.push_back(requirement); 1434 } 1435 else if (m_curToken == TOKEN_PIPELINE_PROGRAM) 1436 { 1437 ProgramSpecification pipelineProgram; 1438 parsePipelineProgram(pipelineProgram); 1439 pipelineProgram.sources.separable = true; 1440 pipelinePrograms.push_back(pipelineProgram); 1441 } 1442 else 1443 parseError(string("unexpected token while parsing shader case: " + m_curTokenStr)); 1444 } 1445 1446 advanceToken(TOKEN_END); // case end 1447 1448 // \todo [pyry] Clean up 1449 vector<RequiredCapability> requiredCaps; 1450 vector<RequiredExtension> requiredExts; 1451 bool fullGLSLES100Required = false; 1452 1453 for (size_t reqNdx = 0; reqNdx < requirements.size(); ++reqNdx) 1454 { 1455 const CaseRequirement& requirement = requirements[reqNdx]; 1456 1457 if (requirement.type == CaseRequirement::TYPE_EXTENSION) 1458 requiredExts.push_back(requirement.extension); 1459 else if (requirement.type == CaseRequirement::TYPE_IMPLEMENTATION_LIMIT) 1460 requiredCaps.push_back(requirement.requiredCap); 1461 else if (requirement.type == CaseRequirement::TYPE_FULL_GLSL_ES_100_SUPPORT) 1462 fullGLSLES100Required = true; 1463 else 1464 DE_ASSERT(false); 1465 } 1466 1467 if (!bothSource.empty()) 1468 { 1469 if (!vertexSources.empty() || 1470 !fragmentSources.empty() || 1471 !tessellationCtrlSources.empty() || 1472 !tessellationEvalSources.empty() || 1473 !geometrySources.empty() || 1474 !pipelinePrograms.empty()) 1475 { 1476 parseError("'both' cannot be mixed with other shader stages"); 1477 } 1478 1479 // vertex 1480 { 1481 ShaderCaseSpecification spec; 1482 spec.caseType = CASETYPE_VERTEX_ONLY; 1483 spec.expectResult = expectResult; 1484 spec.targetVersion = version; 1485 spec.fullGLSLES100Required = fullGLSLES100Required; 1486 spec.requiredCaps = requiredCaps; 1487 spec.values = valueBlock; 1488 1489 spec.programs.resize(1); 1490 spec.programs[0].sources << VertexSource(bothSource); 1491 spec.programs[0].requiredExtensions = requiredExts; 1492 1493 shaderNodeList.push_back(m_caseFactory->createCase(caseName + "_vertex", description, ShaderCaseSpecification(spec))); 1494 } 1495 1496 // fragment 1497 { 1498 ShaderCaseSpecification spec; 1499 spec.caseType = CASETYPE_FRAGMENT_ONLY; 1500 spec.expectResult = expectResult; 1501 spec.targetVersion = version; 1502 spec.fullGLSLES100Required = fullGLSLES100Required; 1503 spec.requiredCaps = requiredCaps; 1504 spec.values = valueBlock; 1505 1506 spec.programs.resize(1); 1507 spec.programs[0].sources << FragmentSource(bothSource); 1508 spec.programs[0].requiredExtensions = requiredExts; 1509 1510 shaderNodeList.push_back(m_caseFactory->createCase(caseName + "_fragment", description, ShaderCaseSpecification(spec))); 1511 } 1512 } 1513 else if (pipelinePrograms.empty()) 1514 { 1515 ShaderCaseSpecification spec; 1516 spec.caseType = CASETYPE_COMPLETE; 1517 spec.expectResult = expectResult; 1518 spec.targetVersion = version; 1519 spec.fullGLSLES100Required = fullGLSLES100Required; 1520 spec.requiredCaps = requiredCaps; 1521 spec.values = valueBlock; 1522 1523 spec.programs.resize(1); 1524 spec.programs[0].sources.sources[SHADERTYPE_VERTEX].swap(vertexSources); 1525 spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].swap(fragmentSources); 1526 spec.programs[0].sources.sources[SHADERTYPE_TESSELLATION_CONTROL].swap(tessellationCtrlSources); 1527 spec.programs[0].sources.sources[SHADERTYPE_TESSELLATION_EVALUATION].swap(tessellationEvalSources); 1528 spec.programs[0].sources.sources[SHADERTYPE_GEOMETRY].swap(geometrySources); 1529 spec.programs[0].requiredExtensions.swap(requiredExts); 1530 1531 shaderNodeList.push_back(m_caseFactory->createCase(caseName, description, ShaderCaseSpecification(spec))); 1532 } 1533 else 1534 { 1535 if (!vertexSources.empty() || 1536 !fragmentSources.empty() || 1537 !tessellationCtrlSources.empty() || 1538 !tessellationEvalSources.empty() || 1539 !geometrySources.empty()) 1540 { 1541 parseError("pipeline programs cannot be mixed with complete programs"); 1542 } 1543 1544 if (!requiredExts.empty()) 1545 parseError("global extension requirements cannot be mixed with pipeline programs"); 1546 1547 // Pipeline case, multiple programs 1548 { 1549 ShaderCaseSpecification spec; 1550 spec.caseType = CASETYPE_COMPLETE; 1551 spec.expectResult = expectResult; 1552 spec.targetVersion = version; 1553 spec.fullGLSLES100Required = fullGLSLES100Required; 1554 spec.requiredCaps = requiredCaps; 1555 spec.values = valueBlock; 1556 1557 spec.programs.swap(pipelinePrograms); 1558 1559 shaderNodeList.push_back(m_caseFactory->createCase(caseName, description, ShaderCaseSpecification(spec))); 1560 } 1561 } 1562 } 1563 1564 void ShaderParser::parseShaderGroup (vector<tcu::TestNode*>& shaderNodeList) 1565 { 1566 // Parse 'case'. 1567 PARSE_DBG((" parseShaderGroup()\n")); 1568 advanceToken(TOKEN_GROUP); 1569 1570 // Parse case name. 1571 string name = m_curTokenStr; 1572 advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group. 1573 1574 // Parse description. 1575 assumeToken(TOKEN_STRING); 1576 string description = parseStringLiteral(m_curTokenStr.c_str()); 1577 advanceToken(TOKEN_STRING); 1578 1579 std::vector<tcu::TestNode*> children; 1580 1581 // Parse group children. 1582 for (;;) 1583 { 1584 if (m_curToken == TOKEN_END) 1585 break; 1586 else if (m_curToken == TOKEN_GROUP) 1587 parseShaderGroup(children); 1588 else if (m_curToken == TOKEN_CASE) 1589 parseShaderCase(children); 1590 else if (m_curToken == TOKEN_IMPORT) 1591 parseImport(children); 1592 else 1593 parseError(string("unexpected token while parsing shader group: " + m_curTokenStr)); 1594 } 1595 1596 advanceToken(TOKEN_END); // group end 1597 1598 // Create group node. 1599 tcu::TestCaseGroup* groupNode = m_caseFactory->createGroup(name, description, children); 1600 shaderNodeList.push_back(groupNode); 1601 } 1602 1603 void ShaderParser::parseImport (vector<tcu::TestNode*>& shaderNodeList) 1604 { 1605 std::string importFileName; 1606 1607 advanceToken(TOKEN_IMPORT); 1608 1609 assumeToken(TOKEN_STRING); 1610 importFileName = parseStringLiteral(m_curTokenStr.c_str()); 1611 advanceToken(TOKEN_STRING); 1612 1613 { 1614 ShaderParser subParser (m_archive, de::FilePath::join(de::FilePath(m_filename).getDirName(), importFileName).getPath(), m_caseFactory); 1615 const vector<tcu::TestNode*> importedCases = subParser.parse(); 1616 1617 // \todo [2015-08-03 pyry] Not exception safe 1618 shaderNodeList.insert(shaderNodeList.end(), importedCases.begin(), importedCases.end()); 1619 } 1620 } 1621 1622 vector<tcu::TestNode*> ShaderParser::parse (void) 1623 { 1624 const int dataLen = m_resource->getSize(); 1625 1626 m_input.resize(dataLen+1); 1627 m_resource->setPosition(0); 1628 m_resource->read((deUint8*)&m_input[0], dataLen); 1629 m_input[dataLen] = '\0'; 1630 1631 // Initialize parser. 1632 m_curPtr = &m_input[0]; 1633 m_curToken = TOKEN_INVALID; 1634 m_curTokenStr = ""; 1635 advanceToken(); 1636 1637 vector<tcu::TestNode*> nodeList; 1638 1639 // Parse all cases. 1640 PARSE_DBG(("parse()\n")); 1641 for (;;) 1642 { 1643 if (m_curToken == TOKEN_CASE) 1644 parseShaderCase(nodeList); 1645 else if (m_curToken == TOKEN_GROUP) 1646 parseShaderGroup(nodeList); 1647 else if (m_curToken == TOKEN_IMPORT) 1648 parseImport(nodeList); 1649 else if (m_curToken == TOKEN_EOF) 1650 break; 1651 else 1652 parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'"); 1653 } 1654 1655 assumeToken(TOKEN_EOF); 1656 // printf(" parsed %d test cases.\n", caseList.size()); 1657 return nodeList; 1658 } 1659 1660 std::vector<tcu::TestNode*> parseFile (const tcu::Archive& archive, const std::string& filename, ShaderCaseFactory* caseFactory) 1661 { 1662 sl::ShaderParser parser (archive, filename, caseFactory); 1663 1664 return parser.parse(); 1665 } 1666 1667 // Execution utilities 1668 1669 static void dumpValue (tcu::TestLog& log, const Value& val, const char* storageName, int arrayNdx) 1670 { 1671 const char* const valueName = val.name.c_str(); 1672 const DataType dataType = val.type.getBasicType(); 1673 int scalarSize = getDataTypeScalarSize(dataType); 1674 ostringstream result; 1675 1676 result << " " << storageName << " "; 1677 1678 result << getDataTypeName(dataType) << " " << valueName << ":"; 1679 1680 if (isDataTypeScalar(dataType)) 1681 result << " "; 1682 if (isDataTypeVector(dataType)) 1683 result << " [ "; 1684 else if (isDataTypeMatrix(dataType)) 1685 result << "\n"; 1686 1687 if (isDataTypeScalarOrVector(dataType)) 1688 { 1689 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1690 { 1691 int elemNdx = arrayNdx; 1692 const Value::Element& e = val.elements[elemNdx*scalarSize + scalarNdx]; 1693 result << ((scalarNdx != 0) ? ", " : ""); 1694 1695 if (isDataTypeFloatOrVec(dataType)) 1696 result << e.float32; 1697 else if (isDataTypeIntOrIVec(dataType)) 1698 result << e.int32; 1699 else if (isDataTypeUintOrUVec(dataType)) 1700 result << (deUint32)e.int32; 1701 else if (isDataTypeBoolOrBVec(dataType)) 1702 result << (e.bool32 ? "true" : "false"); 1703 } 1704 } 1705 else if (isDataTypeMatrix(dataType)) 1706 { 1707 int numRows = getDataTypeMatrixNumRows(dataType); 1708 int numCols = getDataTypeMatrixNumColumns(dataType); 1709 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 1710 { 1711 result << " [ "; 1712 for (int colNdx = 0; colNdx < numCols; colNdx++) 1713 { 1714 int elemNdx = arrayNdx; 1715 float v = val.elements[elemNdx*scalarSize + rowNdx*numCols + colNdx].float32; 1716 result << ((colNdx==0) ? "" : ", ") << v; 1717 } 1718 result << " ]\n"; 1719 } 1720 } 1721 1722 if (isDataTypeScalar(dataType)) 1723 result << "\n"; 1724 else if (isDataTypeVector(dataType)) 1725 result << " ]\n"; 1726 1727 log << TestLog::Message << result.str() << TestLog::EndMessage; 1728 } 1729 1730 static void dumpValues (tcu::TestLog& log, const vector<Value>& values, const char* storageName, int arrayNdx) 1731 { 1732 for (size_t valNdx = 0; valNdx < values.size(); valNdx++) 1733 dumpValue(log, values[valNdx], storageName, arrayNdx); 1734 } 1735 1736 void dumpValues (tcu::TestLog& log, const ValueBlock& values, int arrayNdx) 1737 { 1738 dumpValues(log, values.inputs, "input", arrayNdx); 1739 dumpValues(log, values.outputs, "expected", arrayNdx); 1740 dumpValues(log, values.uniforms, "uniform", arrayNdx); 1741 } 1742 1743 static void generateExtensionStatements (std::ostringstream& buf, const std::vector<RequiredExtension>& extensions, glu::ShaderType type) 1744 { 1745 for (size_t ndx = 0; ndx < extensions.size(); ++ndx) 1746 { 1747 DE_ASSERT(extensions[ndx].effectiveStages != 0u && 1748 extensions[ndx].alternatives.size() == 1); 1749 1750 if ((extensions[ndx].effectiveStages & (1u << (deUint32)type)) != 0) 1751 buf << "#extension " << extensions[ndx].alternatives[0] << " : require\n"; 1752 } 1753 } 1754 1755 // Injects #extension XXX : require lines after the last preprocessor directive in the shader code. Does not support line continuations 1756 std::string injectExtensionRequirements (const std::string& baseCode, const std::vector<RequiredExtension>& extensions, glu::ShaderType shaderType) 1757 { 1758 std::istringstream baseCodeBuf (baseCode); 1759 std::ostringstream resultBuf; 1760 std::string line; 1761 bool firstNonPreprocessorLine = true; 1762 std::ostringstream extStr; 1763 1764 generateExtensionStatements(extStr, extensions, shaderType); 1765 1766 // skip if no requirements 1767 if (extStr.str().empty()) 1768 return baseCode; 1769 1770 while (std::getline(baseCodeBuf, line)) 1771 { 1772 // begins with '#'? 1773 const std::string::size_type firstNonWhitespace = line.find_first_not_of("\t "); 1774 const bool isPreprocessorDirective = (firstNonWhitespace != std::string::npos && line.at(firstNonWhitespace) == '#'); 1775 1776 // Inject #extensions 1777 if (!isPreprocessorDirective && firstNonPreprocessorLine) 1778 { 1779 firstNonPreprocessorLine = false; 1780 resultBuf << extStr.str(); 1781 } 1782 1783 resultBuf << line << "\n"; 1784 } 1785 1786 return resultBuf.str(); 1787 } 1788 1789 void genCompareFunctions (ostringstream& stream, const ValueBlock& valueBlock, bool useFloatTypes) 1790 { 1791 bool cmpTypeFound[TYPE_LAST]; 1792 for (int i = 0; i < TYPE_LAST; i++) 1793 cmpTypeFound[i] = false; 1794 1795 for (size_t valueNdx = 0; valueNdx < valueBlock.outputs.size(); valueNdx++) 1796 { 1797 const Value& val = valueBlock.outputs[valueNdx]; 1798 cmpTypeFound[(size_t)val.type.getBasicType()] = true; 1799 } 1800 1801 if (useFloatTypes) 1802 { 1803 if (cmpTypeFound[TYPE_BOOL]) stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n"; 1804 if (cmpTypeFound[TYPE_BOOL_VEC2]) stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n"; 1805 if (cmpTypeFound[TYPE_BOOL_VEC3]) stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n"; 1806 if (cmpTypeFound[TYPE_BOOL_VEC4]) stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n"; 1807 if (cmpTypeFound[TYPE_INT]) stream << "bool isOk (float a, int b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1)); }\n"; 1808 if (cmpTypeFound[TYPE_INT_VEC2]) stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n"; 1809 if (cmpTypeFound[TYPE_INT_VEC3]) stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n"; 1810 if (cmpTypeFound[TYPE_INT_VEC4]) stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n"; 1811 if (cmpTypeFound[TYPE_UINT]) stream << "bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1u)); }\n"; 1812 if (cmpTypeFound[TYPE_UINT_VEC2]) stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n"; 1813 if (cmpTypeFound[TYPE_UINT_VEC3]) stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n"; 1814 if (cmpTypeFound[TYPE_UINT_VEC4]) stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n"; 1815 } 1816 else 1817 { 1818 if (cmpTypeFound[TYPE_BOOL]) stream << "bool isOk (bool a, bool b) { return (a == b); }\n"; 1819 if (cmpTypeFound[TYPE_BOOL_VEC2]) stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n"; 1820 if (cmpTypeFound[TYPE_BOOL_VEC3]) stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n"; 1821 if (cmpTypeFound[TYPE_BOOL_VEC4]) stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n"; 1822 if (cmpTypeFound[TYPE_INT]) stream << "bool isOk (int a, int b) { return (a == b); }\n"; 1823 if (cmpTypeFound[TYPE_INT_VEC2]) stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n"; 1824 if (cmpTypeFound[TYPE_INT_VEC3]) stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n"; 1825 if (cmpTypeFound[TYPE_INT_VEC4]) stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n"; 1826 if (cmpTypeFound[TYPE_UINT]) stream << "bool isOk (uint a, uint b) { return (a == b); }\n"; 1827 if (cmpTypeFound[TYPE_UINT_VEC2]) stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n"; 1828 if (cmpTypeFound[TYPE_UINT_VEC3]) stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n"; 1829 if (cmpTypeFound[TYPE_UINT_VEC4]) stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n"; 1830 } 1831 1832 if (cmpTypeFound[TYPE_FLOAT]) stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n"; 1833 if (cmpTypeFound[TYPE_FLOAT_VEC2]) stream << "bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n"; 1834 if (cmpTypeFound[TYPE_FLOAT_VEC3]) stream << "bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n"; 1835 if (cmpTypeFound[TYPE_FLOAT_VEC4]) stream << "bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n"; 1836 1837 if (cmpTypeFound[TYPE_FLOAT_MAT2]) stream << "bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec2(eps))); }\n"; 1838 if (cmpTypeFound[TYPE_FLOAT_MAT2X3]) stream << "bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec3(eps))); }\n"; 1839 if (cmpTypeFound[TYPE_FLOAT_MAT2X4]) stream << "bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec4(eps))); }\n"; 1840 if (cmpTypeFound[TYPE_FLOAT_MAT3X2]) stream << "bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n"; 1841 if (cmpTypeFound[TYPE_FLOAT_MAT3]) stream << "bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n"; 1842 if (cmpTypeFound[TYPE_FLOAT_MAT3X4]) stream << "bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n"; 1843 if (cmpTypeFound[TYPE_FLOAT_MAT4X2]) stream << "bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n"; 1844 if (cmpTypeFound[TYPE_FLOAT_MAT4X3]) stream << "bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n"; 1845 if (cmpTypeFound[TYPE_FLOAT_MAT4]) stream << "bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n"; 1846 } 1847 1848 } // sl 1849 } // glu 1850