1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2016 Google Inc. 6 * Copyright (c) 2016 The Khronos Group Inc. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ /*! 21 * \file 22 * \brief Compiler test case. 23 */ /*-------------------------------------------------------------------*/ 24 25 #include "glcShaderLibrary.hpp" 26 #include "glcShaderLibraryCase.hpp" 27 #include "gluShaderUtil.hpp" 28 #include "tcuResource.hpp" 29 30 #include "deInt32.h" 31 32 #include <fstream> 33 #include <sstream> 34 #include <string> 35 #include <vector> 36 37 #include <stdarg.h> 38 #include <stdlib.h> 39 #include <string.h> 40 41 using std::string; 42 using std::vector; 43 using std::ostringstream; 44 45 using namespace glu; 46 47 #if 0 48 #define PARSE_DBG(X) printf X 49 #else 50 #define PARSE_DBG(X) DE_NULL_STATEMENT 51 #endif 52 53 namespace deqp 54 { 55 namespace sl 56 { 57 58 static const glu::GLSLVersion DEFAULT_GLSL_VERSION = glu::GLSL_VERSION_100_ES; 59 60 DE_INLINE deBool isWhitespace(char c) 61 { 62 return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'); 63 } 64 65 DE_INLINE deBool isEOL(char c) 66 { 67 return (c == '\r') || (c == '\n'); 68 } 69 70 DE_INLINE deBool isNumeric(char c) 71 { 72 return deInRange32(c, '0', '9'); 73 } 74 75 DE_INLINE deBool isAlpha(char c) 76 { 77 return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z'); 78 } 79 80 DE_INLINE deBool isCaseNameChar(char c) 81 { 82 return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z') || deInRange32(c, '0', '9') || (c == '_') || 83 (c == '-') || (c == '.'); 84 } 85 86 // \todo [2011-02-11 pyry] Should not depend on Context or TestContext! 87 class ShaderParser 88 { 89 public: 90 ShaderParser(tcu::TestContext& testCtx, RenderContext& renderCtx); 91 ~ShaderParser(void); 92 93 vector<tcu::TestNode*> parse(const char* input); 94 95 private: 96 enum Token 97 { 98 TOKEN_INVALID = 0, 99 TOKEN_EOF, 100 TOKEN_STRING, 101 TOKEN_SHADER_SOURCE, 102 103 TOKEN_INT_LITERAL, 104 TOKEN_FLOAT_LITERAL, 105 106 // identifiers 107 TOKEN_IDENTIFIER, 108 TOKEN_TRUE, 109 TOKEN_FALSE, 110 TOKEN_DESC, 111 TOKEN_EXPECT, 112 TOKEN_GROUP, 113 TOKEN_CASE, 114 TOKEN_END, 115 TOKEN_VALUES, 116 TOKEN_BOTH, 117 TOKEN_VERTEX, 118 TOKEN_FRAGMENT, 119 TOKEN_UNIFORM, 120 TOKEN_INPUT, 121 TOKEN_OUTPUT, 122 TOKEN_FLOAT, 123 TOKEN_FLOAT_VEC2, 124 TOKEN_FLOAT_VEC3, 125 TOKEN_FLOAT_VEC4, 126 TOKEN_FLOAT_MAT2, 127 TOKEN_FLOAT_MAT2X3, 128 TOKEN_FLOAT_MAT2X4, 129 TOKEN_FLOAT_MAT3X2, 130 TOKEN_FLOAT_MAT3, 131 TOKEN_FLOAT_MAT3X4, 132 TOKEN_FLOAT_MAT4X2, 133 TOKEN_FLOAT_MAT4X3, 134 TOKEN_FLOAT_MAT4, 135 TOKEN_INT, 136 TOKEN_INT_VEC2, 137 TOKEN_INT_VEC3, 138 TOKEN_INT_VEC4, 139 TOKEN_UINT, 140 TOKEN_UINT_VEC2, 141 TOKEN_UINT_VEC3, 142 TOKEN_UINT_VEC4, 143 TOKEN_BOOL, 144 TOKEN_BOOL_VEC2, 145 TOKEN_BOOL_VEC3, 146 TOKEN_BOOL_VEC4, 147 TOKEN_VERSION, 148 149 // symbols 150 TOKEN_ASSIGN, 151 TOKEN_PLUS, 152 TOKEN_MINUS, 153 TOKEN_COMMA, 154 TOKEN_VERTICAL_BAR, 155 TOKEN_SEMI_COLON, 156 TOKEN_LEFT_PAREN, 157 TOKEN_RIGHT_PAREN, 158 TOKEN_LEFT_BRACKET, 159 TOKEN_RIGHT_BRACKET, 160 TOKEN_LEFT_BRACE, 161 TOKEN_RIGHT_BRACE, 162 163 TOKEN_LAST 164 }; 165 166 void parseError(const std::string& errorStr); 167 float parseFloatLiteral(const char* str); 168 long long int parseIntLiteral(const char* str); 169 string parseStringLiteral(const char* str); 170 string parseShaderSource(const char* str); 171 void advanceToken(void); 172 void advanceToken(Token assumed); 173 void assumeToken(Token token); 174 DataType mapDataTypeToken(Token token); 175 const char* getTokenName(Token token); 176 177 void parseValueElement(DataType dataType, ShaderCase::Value& result); 178 void parseValue(ShaderCase::ValueBlock& valueBlock); 179 void parseValueBlock(ShaderCase::ValueBlock& valueBlock); 180 void parseShaderCase(vector<tcu::TestNode*>& shaderNodeList); 181 void parseShaderGroup(vector<tcu::TestNode*>& shaderNodeList); 182 183 // Member variables. 184 tcu::TestContext& m_testCtx; 185 RenderContext& m_renderCtx; 186 std::string m_input; 187 const char* m_curPtr; 188 Token m_curToken; 189 std::string m_curTokenStr; 190 }; 191 192 ShaderParser::ShaderParser(tcu::TestContext& testCtx, RenderContext& renderCtx) 193 : m_testCtx(testCtx), m_renderCtx(renderCtx), m_curPtr(DE_NULL), m_curToken(TOKEN_LAST) 194 { 195 } 196 197 ShaderParser::~ShaderParser(void) 198 { 199 // nada 200 } 201 202 void ShaderParser::parseError(const std::string& errorStr) 203 { 204 string atStr = string(m_curPtr, 80); 205 throw tcu::InternalError((string("Parser error: ") + errorStr + " near '" + atStr + " ...'").c_str(), "", __FILE__, 206 __LINE__); 207 } 208 209 float ShaderParser::parseFloatLiteral(const char* str) 210 { 211 return (float)atof(str); 212 } 213 214 long long int ShaderParser::parseIntLiteral(const char* str) 215 { 216 return strtoll(str, NULL, 0); 217 } 218 219 string ShaderParser::parseStringLiteral(const char* str) 220 { 221 const char* p = str; 222 char endChar = *p++; 223 ostringstream o; 224 225 while (*p != endChar && *p) 226 { 227 if (*p == '\\') 228 { 229 switch (p[1]) 230 { 231 case 0: 232 DE_ASSERT(DE_FALSE); 233 break; 234 case 'n': 235 o << '\n'; 236 break; 237 case 't': 238 o << '\t'; 239 break; 240 default: 241 o << p[1]; 242 break; 243 } 244 245 p += 2; 246 } 247 else 248 o << *p++; 249 } 250 251 return o.str(); 252 } 253 254 static string removeExtraIndentation(const string& source) 255 { 256 // Detect indentation from first line. 257 int numIndentChars = 0; 258 for (int ndx = 0; isWhitespace(source[ndx]) && ndx < (int)source.length(); ndx++) 259 numIndentChars += source[ndx] == '\t' ? 4 : 1; 260 261 // Process all lines and remove preceding indentation. 262 ostringstream processed; 263 { 264 bool atLineStart = true; 265 int indentCharsOmitted = 0; 266 267 for (int pos = 0; pos < (int)source.length(); pos++) 268 { 269 char c = source[pos]; 270 271 if (atLineStart && indentCharsOmitted < numIndentChars && (c == ' ' || c == '\t')) 272 { 273 indentCharsOmitted += c == '\t' ? 4 : 1; 274 } 275 else if (isEOL(c)) 276 { 277 if (source[pos] == '\r' && source[pos + 1] == '\n') 278 { 279 pos += 1; 280 processed << '\n'; 281 } 282 else 283 processed << c; 284 285 atLineStart = true; 286 indentCharsOmitted = 0; 287 } 288 else 289 { 290 processed << c; 291 atLineStart = false; 292 } 293 } 294 } 295 296 return processed.str(); 297 } 298 299 string ShaderParser::parseShaderSource(const char* str) 300 { 301 const char* p = str + 2; 302 ostringstream o; 303 304 // Eat first empty line from beginning. 305 while (*p == ' ') 306 p++; 307 while (isEOL(*p)) 308 p++; 309 310 while ((p[0] != '"') || (p[1] != '"')) 311 { 312 if (*p == '\\') 313 { 314 switch (p[1]) 315 { 316 case 0: 317 DE_ASSERT(DE_FALSE); 318 break; 319 case 'n': 320 o << '\n'; 321 break; 322 case 't': 323 o << '\t'; 324 break; 325 default: 326 o << p[1]; 327 break; 328 } 329 330 p += 2; 331 } 332 else 333 o << *p++; 334 } 335 336 return removeExtraIndentation(o.str()); 337 } 338 339 void ShaderParser::advanceToken(void) 340 { 341 // Skip old token. 342 m_curPtr += m_curTokenStr.length(); 343 344 // Reset token (for safety). 345 m_curToken = TOKEN_INVALID; 346 m_curTokenStr = ""; 347 348 // Eat whitespace & comments while they last. 349 for (;;) 350 { 351 while (isWhitespace(*m_curPtr)) 352 m_curPtr++; 353 354 // Check for EOL comment. 355 if (*m_curPtr == '#') 356 { 357 while (*m_curPtr && !isEOL(*m_curPtr)) 358 m_curPtr++; 359 } 360 else 361 break; 362 } 363 364 if (!*m_curPtr) 365 { 366 m_curToken = TOKEN_EOF; 367 m_curTokenStr = "<EOF>"; 368 } 369 else if (isAlpha(*m_curPtr)) 370 { 371 struct Named 372 { 373 const char* str; 374 Token token; 375 }; 376 377 static const Named s_named[] = { { "true", TOKEN_TRUE }, 378 { "false", TOKEN_FALSE }, 379 { "desc", TOKEN_DESC }, 380 { "expect", TOKEN_EXPECT }, 381 { "group", TOKEN_GROUP }, 382 { "case", TOKEN_CASE }, 383 { "end", TOKEN_END }, 384 { "values", TOKEN_VALUES }, 385 { "both", TOKEN_BOTH }, 386 { "vertex", TOKEN_VERTEX }, 387 { "fragment", TOKEN_FRAGMENT }, 388 { "uniform", TOKEN_UNIFORM }, 389 { "input", TOKEN_INPUT }, 390 { "output", TOKEN_OUTPUT }, 391 { "float", TOKEN_FLOAT }, 392 { "vec2", TOKEN_FLOAT_VEC2 }, 393 { "vec3", TOKEN_FLOAT_VEC3 }, 394 { "vec4", TOKEN_FLOAT_VEC4 }, 395 { "mat2", TOKEN_FLOAT_MAT2 }, 396 { "mat2x3", TOKEN_FLOAT_MAT2X3 }, 397 { "mat2x4", TOKEN_FLOAT_MAT2X4 }, 398 { "mat3x2", TOKEN_FLOAT_MAT3X2 }, 399 { "mat3", TOKEN_FLOAT_MAT3 }, 400 { "mat3x4", TOKEN_FLOAT_MAT3X4 }, 401 { "mat4x2", TOKEN_FLOAT_MAT4X2 }, 402 { "mat4x3", TOKEN_FLOAT_MAT4X3 }, 403 { "mat4", TOKEN_FLOAT_MAT4 }, 404 { "int", TOKEN_INT }, 405 { "ivec2", TOKEN_INT_VEC2 }, 406 { "ivec3", TOKEN_INT_VEC3 }, 407 { "ivec4", TOKEN_INT_VEC4 }, 408 { "uint", TOKEN_UINT }, 409 { "uvec2", TOKEN_UINT_VEC2 }, 410 { "uvec3", TOKEN_UINT_VEC3 }, 411 { "uvec4", TOKEN_UINT_VEC4 }, 412 { "bool", TOKEN_BOOL }, 413 { "bvec2", TOKEN_BOOL_VEC2 }, 414 { "bvec3", TOKEN_BOOL_VEC3 }, 415 { "bvec4", TOKEN_BOOL_VEC4 }, 416 { "version", TOKEN_VERSION } }; 417 418 const char* end = m_curPtr + 1; 419 while (isCaseNameChar(*end)) 420 end++; 421 m_curTokenStr = string(m_curPtr, end - m_curPtr); 422 423 m_curToken = TOKEN_IDENTIFIER; 424 425 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_named); ndx++) 426 { 427 if (m_curTokenStr == s_named[ndx].str) 428 { 429 m_curToken = s_named[ndx].token; 430 break; 431 } 432 } 433 } 434 else if (isNumeric(*m_curPtr)) 435 { 436 /* \todo [2010-03-31 petri] Hex? */ 437 const char* p = m_curPtr; 438 while (isNumeric(*p)) 439 p++; 440 if (*p == '.') 441 { 442 p++; 443 while (isNumeric(*p)) 444 p++; 445 446 if (*p == 'e' || *p == 'E') 447 { 448 p++; 449 if (*p == '+' || *p == '-') 450 p++; 451 DE_ASSERT(isNumeric(*p)); 452 while (isNumeric(*p)) 453 p++; 454 } 455 456 m_curToken = TOKEN_FLOAT_LITERAL; 457 m_curTokenStr = string(m_curPtr, p - m_curPtr); 458 } 459 else 460 { 461 m_curToken = TOKEN_INT_LITERAL; 462 m_curTokenStr = string(m_curPtr, p - m_curPtr); 463 } 464 } 465 else if (*m_curPtr == '"' && m_curPtr[1] == '"') 466 { 467 const char* p = m_curPtr + 2; 468 469 while ((p[0] != '"') || (p[1] != '"')) 470 { 471 DE_ASSERT(*p); 472 if (*p == '\\') 473 { 474 DE_ASSERT(p[1] != 0); 475 p += 2; 476 } 477 else 478 p++; 479 } 480 p += 2; 481 482 m_curToken = TOKEN_SHADER_SOURCE; 483 m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr)); 484 } 485 else if (*m_curPtr == '"' || *m_curPtr == '\'') 486 { 487 char endChar = *m_curPtr; 488 const char* p = m_curPtr + 1; 489 490 while (*p != endChar) 491 { 492 DE_ASSERT(*p); 493 if (*p == '\\') 494 { 495 DE_ASSERT(p[1] != 0); 496 p += 2; 497 } 498 else 499 p++; 500 } 501 p++; 502 503 m_curToken = TOKEN_STRING; 504 m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr)); 505 } 506 else 507 { 508 struct SimpleToken 509 { 510 const char* str; 511 Token token; 512 }; 513 514 static const SimpleToken s_simple[] = { { "=", TOKEN_ASSIGN }, { "+", TOKEN_PLUS }, 515 { "-", TOKEN_MINUS }, { ",", TOKEN_COMMA }, 516 { "|", TOKEN_VERTICAL_BAR }, { ";", TOKEN_SEMI_COLON }, 517 { "(", TOKEN_LEFT_PAREN }, { ")", TOKEN_RIGHT_PAREN }, 518 { "[", TOKEN_LEFT_BRACKET }, { "]", TOKEN_RIGHT_BRACKET }, 519 { "{", TOKEN_LEFT_BRACE }, { "}", TOKEN_RIGHT_BRACE } }; 520 521 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_simple); ndx++) 522 { 523 if (strncmp(s_simple[ndx].str, m_curPtr, strlen(s_simple[ndx].str)) == 0) 524 { 525 m_curToken = s_simple[ndx].token; 526 m_curTokenStr = s_simple[ndx].str; 527 return; 528 } 529 } 530 531 // Otherwise invalid token. 532 m_curToken = TOKEN_INVALID; 533 m_curTokenStr = *m_curPtr; 534 } 535 } 536 537 void ShaderParser::advanceToken(Token assumed) 538 { 539 assumeToken(assumed); 540 advanceToken(); 541 } 542 543 void ShaderParser::assumeToken(Token token) 544 { 545 if (m_curToken != token) 546 parseError( 547 (string("unexpected token '") + m_curTokenStr + "', expecting '" + getTokenName(token) + "'").c_str()); 548 DE_TEST_ASSERT(m_curToken == token); 549 } 550 551 DataType ShaderParser::mapDataTypeToken(Token token) 552 { 553 switch (token) 554 { 555 case TOKEN_FLOAT: 556 return TYPE_FLOAT; 557 case TOKEN_FLOAT_VEC2: 558 return TYPE_FLOAT_VEC2; 559 case TOKEN_FLOAT_VEC3: 560 return TYPE_FLOAT_VEC3; 561 case TOKEN_FLOAT_VEC4: 562 return TYPE_FLOAT_VEC4; 563 case TOKEN_FLOAT_MAT2: 564 return TYPE_FLOAT_MAT2; 565 case TOKEN_FLOAT_MAT2X3: 566 return TYPE_FLOAT_MAT2X3; 567 case TOKEN_FLOAT_MAT2X4: 568 return TYPE_FLOAT_MAT2X4; 569 case TOKEN_FLOAT_MAT3X2: 570 return TYPE_FLOAT_MAT3X2; 571 case TOKEN_FLOAT_MAT3: 572 return TYPE_FLOAT_MAT3; 573 case TOKEN_FLOAT_MAT3X4: 574 return TYPE_FLOAT_MAT3X4; 575 case TOKEN_FLOAT_MAT4X2: 576 return TYPE_FLOAT_MAT4X2; 577 case TOKEN_FLOAT_MAT4X3: 578 return TYPE_FLOAT_MAT4X3; 579 case TOKEN_FLOAT_MAT4: 580 return TYPE_FLOAT_MAT4; 581 case TOKEN_INT: 582 return TYPE_INT; 583 case TOKEN_INT_VEC2: 584 return TYPE_INT_VEC2; 585 case TOKEN_INT_VEC3: 586 return TYPE_INT_VEC3; 587 case TOKEN_INT_VEC4: 588 return TYPE_INT_VEC4; 589 case TOKEN_UINT: 590 return TYPE_UINT; 591 case TOKEN_UINT_VEC2: 592 return TYPE_UINT_VEC2; 593 case TOKEN_UINT_VEC3: 594 return TYPE_UINT_VEC3; 595 case TOKEN_UINT_VEC4: 596 return TYPE_UINT_VEC4; 597 case TOKEN_BOOL: 598 return TYPE_BOOL; 599 case TOKEN_BOOL_VEC2: 600 return TYPE_BOOL_VEC2; 601 case TOKEN_BOOL_VEC3: 602 return TYPE_BOOL_VEC3; 603 case TOKEN_BOOL_VEC4: 604 return TYPE_BOOL_VEC4; 605 default: 606 return TYPE_INVALID; 607 } 608 } 609 610 const char* ShaderParser::getTokenName(Token token) 611 { 612 switch (token) 613 { 614 case TOKEN_INVALID: 615 return "<invalid>"; 616 case TOKEN_EOF: 617 return "<eof>"; 618 case TOKEN_STRING: 619 return "<string>"; 620 case TOKEN_SHADER_SOURCE: 621 return "source"; 622 623 case TOKEN_INT_LITERAL: 624 return "<int>"; 625 case TOKEN_FLOAT_LITERAL: 626 return "<float>"; 627 628 // identifiers 629 case TOKEN_IDENTIFIER: 630 return "<identifier>"; 631 case TOKEN_TRUE: 632 return "true"; 633 case TOKEN_FALSE: 634 return "false"; 635 case TOKEN_DESC: 636 return "desc"; 637 case TOKEN_EXPECT: 638 return "expect"; 639 case TOKEN_GROUP: 640 return "group"; 641 case TOKEN_CASE: 642 return "case"; 643 case TOKEN_END: 644 return "end"; 645 case TOKEN_VALUES: 646 return "values"; 647 case TOKEN_BOTH: 648 return "both"; 649 case TOKEN_VERTEX: 650 return "vertex"; 651 case TOKEN_FRAGMENT: 652 return "fragment"; 653 case TOKEN_UNIFORM: 654 return "uniform"; 655 case TOKEN_INPUT: 656 return "input"; 657 case TOKEN_OUTPUT: 658 return "output"; 659 case TOKEN_FLOAT: 660 return "float"; 661 case TOKEN_FLOAT_VEC2: 662 return "vec2"; 663 case TOKEN_FLOAT_VEC3: 664 return "vec3"; 665 case TOKEN_FLOAT_VEC4: 666 return "vec4"; 667 case TOKEN_FLOAT_MAT2: 668 return "mat2"; 669 case TOKEN_FLOAT_MAT2X3: 670 return "mat2x3"; 671 case TOKEN_FLOAT_MAT2X4: 672 return "mat2x4"; 673 case TOKEN_FLOAT_MAT3X2: 674 return "mat3x2"; 675 case TOKEN_FLOAT_MAT3: 676 return "mat3"; 677 case TOKEN_FLOAT_MAT3X4: 678 return "mat3x4"; 679 case TOKEN_FLOAT_MAT4X2: 680 return "mat4x2"; 681 case TOKEN_FLOAT_MAT4X3: 682 return "mat4x3"; 683 case TOKEN_FLOAT_MAT4: 684 return "mat4"; 685 case TOKEN_INT: 686 return "int"; 687 case TOKEN_INT_VEC2: 688 return "ivec2"; 689 case TOKEN_INT_VEC3: 690 return "ivec3"; 691 case TOKEN_INT_VEC4: 692 return "ivec4"; 693 case TOKEN_UINT: 694 return "uint"; 695 case TOKEN_UINT_VEC2: 696 return "uvec2"; 697 case TOKEN_UINT_VEC3: 698 return "uvec3"; 699 case TOKEN_UINT_VEC4: 700 return "uvec4"; 701 case TOKEN_BOOL: 702 return "bool"; 703 case TOKEN_BOOL_VEC2: 704 return "bvec2"; 705 case TOKEN_BOOL_VEC3: 706 return "bvec3"; 707 case TOKEN_BOOL_VEC4: 708 return "bvec4"; 709 710 case TOKEN_ASSIGN: 711 return "="; 712 case TOKEN_PLUS: 713 return "+"; 714 case TOKEN_MINUS: 715 return "-"; 716 case TOKEN_COMMA: 717 return ","; 718 case TOKEN_VERTICAL_BAR: 719 return "|"; 720 case TOKEN_SEMI_COLON: 721 return ";"; 722 case TOKEN_LEFT_PAREN: 723 return "("; 724 case TOKEN_RIGHT_PAREN: 725 return ")"; 726 case TOKEN_LEFT_BRACKET: 727 return "["; 728 case TOKEN_RIGHT_BRACKET: 729 return "]"; 730 case TOKEN_LEFT_BRACE: 731 return "{"; 732 case TOKEN_RIGHT_BRACE: 733 return "}"; 734 735 default: 736 return "<unknown>"; 737 } 738 } 739 740 void ShaderParser::parseValueElement(DataType expectedDataType, ShaderCase::Value& result) 741 { 742 DataType scalarType = getDataTypeScalarType(expectedDataType); 743 int scalarSize = getDataTypeScalarSize(expectedDataType); 744 745 /* \todo [2010-04-19 petri] Support arrays. */ 746 ShaderCase::Value::Element elems[16]; 747 748 if (scalarSize > 1) 749 { 750 DE_ASSERT(mapDataTypeToken(m_curToken) == expectedDataType); 751 advanceToken(); // data type (float, vec2, etc.) 752 advanceToken(TOKEN_LEFT_PAREN); 753 } 754 755 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 756 { 757 if (scalarType == TYPE_FLOAT) 758 { 759 float signMult = 1.0f; 760 if (m_curToken == TOKEN_MINUS) 761 { 762 signMult = -1.0f; 763 advanceToken(); 764 } 765 766 assumeToken(TOKEN_FLOAT_LITERAL); 767 elems[scalarNdx].float32 = signMult * parseFloatLiteral(m_curTokenStr.c_str()); 768 advanceToken(TOKEN_FLOAT_LITERAL); 769 } 770 else if (scalarType == TYPE_INT || scalarType == TYPE_UINT) 771 { 772 int signMult = 1; 773 if (m_curToken == TOKEN_MINUS) 774 { 775 signMult = -1; 776 advanceToken(); 777 } 778 779 assumeToken(TOKEN_INT_LITERAL); 780 elems[scalarNdx].int32 = signMult * parseIntLiteral(m_curTokenStr.c_str()); 781 advanceToken(TOKEN_INT_LITERAL); 782 } 783 else 784 { 785 DE_ASSERT(scalarType == TYPE_BOOL); 786 elems[scalarNdx].bool32 = (m_curToken == TOKEN_TRUE); 787 if (m_curToken != TOKEN_TRUE && m_curToken != TOKEN_FALSE) 788 parseError(string("unexpected token, expecting bool: " + m_curTokenStr)); 789 advanceToken(); // true/false 790 } 791 792 if (scalarNdx != (scalarSize - 1)) 793 advanceToken(TOKEN_COMMA); 794 } 795 796 if (scalarSize > 1) 797 advanceToken(TOKEN_RIGHT_PAREN); 798 799 // Store results. 800 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 801 result.elements.push_back(elems[scalarNdx]); 802 } 803 804 void ShaderParser::parseValue(ShaderCase::ValueBlock& valueBlock) 805 { 806 PARSE_DBG((" parseValue()\n")); 807 808 // Parsed results. 809 ShaderCase::Value result; 810 811 // Parse storage. 812 if (m_curToken == TOKEN_UNIFORM) 813 result.storageType = ShaderCase::Value::STORAGE_UNIFORM; 814 else if (m_curToken == TOKEN_INPUT) 815 result.storageType = ShaderCase::Value::STORAGE_INPUT; 816 else if (m_curToken == TOKEN_OUTPUT) 817 result.storageType = ShaderCase::Value::STORAGE_OUTPUT; 818 else 819 parseError(string("unexpected token encountered when parsing value classifier")); 820 advanceToken(); 821 822 // Parse data type. 823 result.dataType = mapDataTypeToken(m_curToken); 824 if (result.dataType == TYPE_INVALID) 825 parseError(string("unexpected token when parsing value data type: " + m_curTokenStr)); 826 advanceToken(); 827 828 // Parse value name. 829 if (m_curToken == TOKEN_IDENTIFIER || m_curToken == TOKEN_STRING) 830 { 831 if (m_curToken == TOKEN_IDENTIFIER) 832 result.valueName = m_curTokenStr; 833 else 834 result.valueName = parseStringLiteral(m_curTokenStr.c_str()); 835 } 836 else 837 parseError(string("unexpected token when parsing value name: " + m_curTokenStr)); 838 advanceToken(); 839 840 // Parse assignment operator. 841 advanceToken(TOKEN_ASSIGN); 842 843 // Parse actual value. 844 if (m_curToken == TOKEN_LEFT_BRACKET) // value list 845 { 846 advanceToken(TOKEN_LEFT_BRACKET); 847 result.arrayLength = 0; 848 849 for (;;) 850 { 851 parseValueElement(result.dataType, result); 852 result.arrayLength++; 853 854 if (m_curToken == TOKEN_RIGHT_BRACKET) 855 break; 856 else if (m_curToken == TOKEN_VERTICAL_BAR) 857 { 858 advanceToken(); 859 continue; 860 } 861 else 862 parseError(string("unexpected token in value element array: " + m_curTokenStr)); 863 } 864 865 advanceToken(TOKEN_RIGHT_BRACKET); 866 } 867 else // arrays, single elements 868 { 869 parseValueElement(result.dataType, result); 870 result.arrayLength = 1; 871 } 872 873 advanceToken(TOKEN_SEMI_COLON); // end of declaration 874 875 valueBlock.values.push_back(result); 876 } 877 878 void ShaderParser::parseValueBlock(ShaderCase::ValueBlock& valueBlock) 879 { 880 PARSE_DBG((" parseValueBlock()\n")); 881 advanceToken(TOKEN_VALUES); 882 advanceToken(TOKEN_LEFT_BRACE); 883 884 for (;;) 885 { 886 if (m_curToken == TOKEN_UNIFORM || m_curToken == TOKEN_INPUT || m_curToken == TOKEN_OUTPUT) 887 parseValue(valueBlock); 888 else if (m_curToken == TOKEN_RIGHT_BRACE) 889 break; 890 else 891 parseError(string("unexpected token when parsing a value block: " + m_curTokenStr)); 892 } 893 894 advanceToken(TOKEN_RIGHT_BRACE); 895 896 // Compute combined array length of value block. 897 int arrayLength = 1; 898 for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++) 899 { 900 const ShaderCase::Value& val = valueBlock.values[valueNdx]; 901 if (val.arrayLength > 1) 902 { 903 DE_ASSERT(arrayLength == 1 || arrayLength == val.arrayLength); 904 arrayLength = val.arrayLength; 905 } 906 } 907 valueBlock.arrayLength = arrayLength; 908 } 909 910 void ShaderParser::parseShaderCase(vector<tcu::TestNode*>& shaderNodeList) 911 { 912 // Parse 'case'. 913 PARSE_DBG((" parseShaderCase()\n")); 914 advanceToken(TOKEN_CASE); 915 916 // Parse case name. 917 string caseName = m_curTokenStr; 918 advanceToken(); // \note [pyry] All token types are allowed here. 919 920 // Setup case. 921 vector<ShaderCase::ValueBlock> valueBlockList; 922 923 GLSLVersion version = DEFAULT_GLSL_VERSION; 924 ShaderCase::ExpectResult expectResult = ShaderCase::EXPECT_PASS; 925 string description; 926 string bothSource; 927 string vertexSource; 928 string fragmentSource; 929 930 for (;;) 931 { 932 if (m_curToken == TOKEN_END) 933 break; 934 else if (m_curToken == TOKEN_DESC) 935 { 936 advanceToken(); 937 assumeToken(TOKEN_STRING); 938 939 description = parseStringLiteral(m_curTokenStr.c_str()); 940 advanceToken(); 941 } 942 else if (m_curToken == TOKEN_EXPECT) 943 { 944 advanceToken(); 945 assumeToken(TOKEN_IDENTIFIER); 946 947 if (m_curTokenStr == "pass") 948 expectResult = ShaderCase::EXPECT_PASS; 949 else if (m_curTokenStr == "compile_fail") 950 expectResult = ShaderCase::EXPECT_COMPILE_FAIL; 951 else if (m_curTokenStr == "link_fail") 952 expectResult = ShaderCase::EXPECT_LINK_FAIL; 953 else 954 parseError(string("invalid expected result value: " + m_curTokenStr)); 955 956 advanceToken(); 957 } 958 else if (m_curToken == TOKEN_VALUES) 959 { 960 ShaderCase::ValueBlock block; 961 parseValueBlock(block); 962 valueBlockList.push_back(block); 963 } 964 else if (m_curToken == TOKEN_BOTH || m_curToken == TOKEN_VERTEX || m_curToken == TOKEN_FRAGMENT) 965 { 966 Token token = m_curToken; 967 advanceToken(); 968 assumeToken(TOKEN_SHADER_SOURCE); 969 string source = parseShaderSource(m_curTokenStr.c_str()); 970 advanceToken(); 971 if (token == TOKEN_BOTH) 972 bothSource = source; 973 else if (token == TOKEN_VERTEX) 974 vertexSource = source; 975 else if (token == TOKEN_FRAGMENT) 976 fragmentSource = source; 977 else 978 DE_ASSERT(DE_FALSE); 979 } 980 else if (m_curToken == TOKEN_VERSION) 981 { 982 advanceToken(); 983 984 int versionNum = 0; 985 std::string postfix = ""; 986 987 assumeToken(TOKEN_INT_LITERAL); 988 versionNum = parseIntLiteral(m_curTokenStr.c_str()); 989 advanceToken(); 990 991 if (m_curToken == TOKEN_IDENTIFIER) 992 { 993 postfix = m_curTokenStr; 994 advanceToken(); 995 } 996 997 if (versionNum == 100 && postfix == "es") 998 version = glu::GLSL_VERSION_100_ES; 999 else if (versionNum == 300 && postfix == "es") 1000 version = glu::GLSL_VERSION_300_ES; 1001 else if (versionNum == 310 && postfix == "es") 1002 version = glu::GLSL_VERSION_310_ES; 1003 else if (versionNum == 130) 1004 version = glu::GLSL_VERSION_130; 1005 else if (versionNum == 140) 1006 version = glu::GLSL_VERSION_140; 1007 else if (versionNum == 150) 1008 version = glu::GLSL_VERSION_150; 1009 else if (versionNum == 330) 1010 version = glu::GLSL_VERSION_330; 1011 else if (versionNum == 400) 1012 version = glu::GLSL_VERSION_400; 1013 else if (versionNum == 410) 1014 version = glu::GLSL_VERSION_410; 1015 else if (versionNum == 420) 1016 version = glu::GLSL_VERSION_420; 1017 else if (versionNum == 430) 1018 version = glu::GLSL_VERSION_430; 1019 else if (versionNum == 440) 1020 version = glu::GLSL_VERSION_440; 1021 else if (versionNum == 450) 1022 version = glu::GLSL_VERSION_450; 1023 else 1024 parseError("Unknown GLSL version"); 1025 } 1026 else 1027 parseError(string("unexpected token while parsing shader case: " + m_curTokenStr)); 1028 } 1029 1030 advanceToken(TOKEN_END); // case end 1031 1032 if (bothSource.length() > 0) 1033 { 1034 DE_ASSERT(vertexSource.length() == 0); 1035 DE_ASSERT(fragmentSource.length() == 0); 1036 1037 string vertName = caseName + "_vertex"; 1038 string fragName = caseName + "_fragment"; 1039 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, vertName.c_str(), description.c_str(), 1040 expectResult, valueBlockList, version, bothSource.c_str(), DE_NULL)); 1041 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, fragName.c_str(), description.c_str(), 1042 expectResult, valueBlockList, version, DE_NULL, bothSource.c_str())); 1043 } 1044 else 1045 { 1046 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, caseName.c_str(), description.c_str(), 1047 expectResult, valueBlockList, version, vertexSource.c_str(), 1048 fragmentSource.c_str())); 1049 } 1050 } 1051 1052 void ShaderParser::parseShaderGroup(vector<tcu::TestNode*>& shaderNodeList) 1053 { 1054 // Parse 'case'. 1055 PARSE_DBG((" parseShaderGroup()\n")); 1056 advanceToken(TOKEN_GROUP); 1057 1058 // Parse case name. 1059 string name = m_curTokenStr; 1060 advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group. 1061 1062 // Parse description. 1063 assumeToken(TOKEN_STRING); 1064 string description = parseStringLiteral(m_curTokenStr.c_str()); 1065 advanceToken(TOKEN_STRING); 1066 1067 std::vector<tcu::TestNode*> children; 1068 1069 // Parse group children. 1070 for (;;) 1071 { 1072 if (m_curToken == TOKEN_END) 1073 break; 1074 else if (m_curToken == TOKEN_GROUP) 1075 parseShaderGroup(children); 1076 else if (m_curToken == TOKEN_CASE) 1077 parseShaderCase(children); 1078 else 1079 parseError(string("unexpected token while parsing shader group: " + m_curTokenStr)); 1080 } 1081 1082 advanceToken(TOKEN_END); // group end 1083 1084 // Create group node. 1085 tcu::TestCaseGroup* groupNode = new tcu::TestCaseGroup(m_testCtx, name.c_str(), description.c_str(), children); 1086 shaderNodeList.push_back(groupNode); 1087 } 1088 1089 vector<tcu::TestNode*> ShaderParser::parse(const char* input) 1090 { 1091 // Initialize parser. 1092 m_input = input; 1093 m_curPtr = m_input.c_str(); 1094 m_curToken = TOKEN_INVALID; 1095 m_curTokenStr = ""; 1096 advanceToken(); 1097 1098 vector<tcu::TestNode*> nodeList; 1099 1100 // Parse all cases. 1101 PARSE_DBG(("parse()\n")); 1102 for (;;) 1103 { 1104 if (m_curToken == TOKEN_CASE) 1105 parseShaderCase(nodeList); 1106 else if (m_curToken == TOKEN_GROUP) 1107 parseShaderGroup(nodeList); 1108 else if (m_curToken == TOKEN_EOF) 1109 break; 1110 else 1111 parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'"); 1112 } 1113 1114 assumeToken(TOKEN_EOF); 1115 // printf(" parsed %d test cases.\n", caseList.size()); 1116 return nodeList; 1117 } 1118 1119 } // sl 1120 1121 ShaderLibrary::ShaderLibrary(tcu::TestContext& testCtx, RenderContext& renderCtx) 1122 : m_testCtx(testCtx), m_renderCtx(renderCtx) 1123 { 1124 } 1125 1126 ShaderLibrary::~ShaderLibrary(void) 1127 { 1128 } 1129 1130 vector<tcu::TestNode*> ShaderLibrary::loadShaderFile(const char* fileName) 1131 { 1132 tcu::Resource* resource = m_testCtx.getArchive().getResource(fileName); 1133 std::vector<char> buf; 1134 1135 /* printf(" loading '%s'\n", fileName);*/ 1136 1137 try 1138 { 1139 int size = resource->getSize(); 1140 buf.resize(size + 1); 1141 resource->read((deUint8*)&buf[0], size); 1142 buf[size] = '\0'; 1143 } 1144 catch (const std::exception&) 1145 { 1146 delete resource; 1147 throw; 1148 } 1149 1150 delete resource; 1151 1152 sl::ShaderParser parser(m_testCtx, m_renderCtx); 1153 vector<tcu::TestNode*> nodes = parser.parse(&buf[0]); 1154 1155 return nodes; 1156 } 1157 1158 // ShaderLibraryGroup 1159 1160 ShaderLibraryGroup::ShaderLibraryGroup(Context& context, const char* name, const char* description, 1161 const char* filename) 1162 : TestCaseGroup(context, name, description), m_filename(filename) 1163 { 1164 } 1165 1166 ShaderLibraryGroup::~ShaderLibraryGroup(void) 1167 { 1168 } 1169 1170 void ShaderLibraryGroup::init(void) 1171 { 1172 deqp::ShaderLibrary shaderLibrary(m_testCtx, m_context.getRenderContext()); 1173 std::vector<tcu::TestNode*> children = shaderLibrary.loadShaderFile(m_filename.c_str()); 1174 1175 for (int i = 0; i < (int)children.size(); i++) 1176 addChild(children[i]); 1177 } 1178 1179 } // deqp 1180