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
isWhitespace(char c)60 DE_INLINE deBool isWhitespace(char c)
61 {
62 return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
63 }
64
isEOL(char c)65 DE_INLINE deBool isEOL(char c)
66 {
67 return (c == '\r') || (c == '\n');
68 }
69
isNumeric(char c)70 DE_INLINE deBool isNumeric(char c)
71 {
72 return deInRange32(c, '0', '9');
73 }
74
isAlpha(char c)75 DE_INLINE deBool isAlpha(char c)
76 {
77 return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z');
78 }
79
isCaseNameChar(char c)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
ShaderParser(tcu::TestContext & testCtx,RenderContext & renderCtx)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
~ShaderParser(void)197 ShaderParser::~ShaderParser(void)
198 {
199 // nada
200 }
201
parseError(const std::string & errorStr)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
parseFloatLiteral(const char * str)209 float ShaderParser::parseFloatLiteral(const char* str)
210 {
211 return (float)atof(str);
212 }
213
parseIntLiteral(const char * str)214 long long int ShaderParser::parseIntLiteral(const char* str)
215 {
216 return strtoll(str, NULL, 0);
217 }
218
parseStringLiteral(const char * str)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
removeExtraIndentation(const string & source)254 static string removeExtraIndentation(const string& source)
255 {
256 // Detect indentation from first line.
257 int numIndentChars = 0;
258 for (int ndx = 0; ndx < (int)source.length() && isWhitespace(source[ndx]); 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
parseShaderSource(const char * str)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
advanceToken(void)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
advanceToken(Token assumed)537 void ShaderParser::advanceToken(Token assumed)
538 {
539 assumeToken(assumed);
540 advanceToken();
541 }
542
assumeToken(Token token)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
mapDataTypeToken(Token token)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
getTokenName(Token token)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
parseValueElement(DataType expectedDataType,ShaderCase::Value & result)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 = (deInt32)(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
parseValue(ShaderCase::ValueBlock & valueBlock)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
parseValueBlock(ShaderCase::ValueBlock & valueBlock)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
parseShaderCase(vector<tcu::TestNode * > & shaderNodeList)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 switch (token)
972 {
973 case TOKEN_BOTH:
974 bothSource = source;
975 break;
976 case TOKEN_VERTEX:
977 vertexSource = source;
978 break;
979 case TOKEN_FRAGMENT:
980 fragmentSource = source;
981 break;
982 default:
983 DE_ASSERT(DE_FALSE);
984 }
985 }
986 else if (m_curToken == TOKEN_VERSION)
987 {
988 advanceToken();
989
990 int versionNum = 0;
991 std::string postfix = "";
992
993 assumeToken(TOKEN_INT_LITERAL);
994 versionNum = (int)parseIntLiteral(m_curTokenStr.c_str());
995 advanceToken();
996
997 if (m_curToken == TOKEN_IDENTIFIER)
998 {
999 postfix = m_curTokenStr;
1000 advanceToken();
1001 }
1002
1003 if (versionNum == 100 && postfix == "es")
1004 version = glu::GLSL_VERSION_100_ES;
1005 else if (versionNum == 300 && postfix == "es")
1006 version = glu::GLSL_VERSION_300_ES;
1007 else if (versionNum == 310 && postfix == "es")
1008 version = glu::GLSL_VERSION_310_ES;
1009 else if (versionNum == 130)
1010 version = glu::GLSL_VERSION_130;
1011 else if (versionNum == 140)
1012 version = glu::GLSL_VERSION_140;
1013 else if (versionNum == 150)
1014 version = glu::GLSL_VERSION_150;
1015 else if (versionNum == 330)
1016 version = glu::GLSL_VERSION_330;
1017 else if (versionNum == 400)
1018 version = glu::GLSL_VERSION_400;
1019 else if (versionNum == 410)
1020 version = glu::GLSL_VERSION_410;
1021 else if (versionNum == 420)
1022 version = glu::GLSL_VERSION_420;
1023 else if (versionNum == 430)
1024 version = glu::GLSL_VERSION_430;
1025 else if (versionNum == 440)
1026 version = glu::GLSL_VERSION_440;
1027 else if (versionNum == 450)
1028 version = glu::GLSL_VERSION_450;
1029 else
1030 parseError("Unknown GLSL version");
1031 }
1032 else
1033 parseError(string("unexpected token while parsing shader case: " + m_curTokenStr));
1034 }
1035
1036 advanceToken(TOKEN_END); // case end
1037
1038 if (bothSource.length() > 0)
1039 {
1040 DE_ASSERT(vertexSource.length() == 0);
1041 DE_ASSERT(fragmentSource.length() == 0);
1042
1043 string vertName = caseName + "_vertex";
1044 string fragName = caseName + "_fragment";
1045 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, vertName.c_str(), description.c_str(),
1046 expectResult, valueBlockList, version, bothSource.c_str(), DE_NULL));
1047 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, fragName.c_str(), description.c_str(),
1048 expectResult, valueBlockList, version, DE_NULL, bothSource.c_str()));
1049 }
1050 else
1051 {
1052 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, caseName.c_str(), description.c_str(),
1053 expectResult, valueBlockList, version, vertexSource.c_str(),
1054 fragmentSource.c_str()));
1055 }
1056 }
1057
parseShaderGroup(vector<tcu::TestNode * > & shaderNodeList)1058 void ShaderParser::parseShaderGroup(vector<tcu::TestNode*>& shaderNodeList)
1059 {
1060 // Parse 'case'.
1061 PARSE_DBG((" parseShaderGroup()\n"));
1062 advanceToken(TOKEN_GROUP);
1063
1064 // Parse case name.
1065 string name = m_curTokenStr;
1066 advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
1067
1068 // Parse description.
1069 assumeToken(TOKEN_STRING);
1070 string description = parseStringLiteral(m_curTokenStr.c_str());
1071 advanceToken(TOKEN_STRING);
1072
1073 std::vector<tcu::TestNode*> children;
1074
1075 // Parse group children.
1076 for (;;)
1077 {
1078 if (m_curToken == TOKEN_END)
1079 break;
1080 else if (m_curToken == TOKEN_GROUP)
1081 parseShaderGroup(children);
1082 else if (m_curToken == TOKEN_CASE)
1083 parseShaderCase(children);
1084 else
1085 parseError(string("unexpected token while parsing shader group: " + m_curTokenStr));
1086 }
1087
1088 advanceToken(TOKEN_END); // group end
1089
1090 // Create group node.
1091 tcu::TestCaseGroup* groupNode = new tcu::TestCaseGroup(m_testCtx, name.c_str(), description.c_str(), children);
1092 shaderNodeList.push_back(groupNode);
1093 }
1094
parse(const char * input)1095 vector<tcu::TestNode*> ShaderParser::parse(const char* input)
1096 {
1097 // Initialize parser.
1098 m_input = input;
1099 m_curPtr = m_input.c_str();
1100 m_curToken = TOKEN_INVALID;
1101 m_curTokenStr = "";
1102 advanceToken();
1103
1104 vector<tcu::TestNode*> nodeList;
1105
1106 // Parse all cases.
1107 PARSE_DBG(("parse()\n"));
1108 for (;;)
1109 {
1110 if (m_curToken == TOKEN_CASE)
1111 parseShaderCase(nodeList);
1112 else if (m_curToken == TOKEN_GROUP)
1113 parseShaderGroup(nodeList);
1114 else if (m_curToken == TOKEN_EOF)
1115 break;
1116 else
1117 parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'");
1118 }
1119
1120 assumeToken(TOKEN_EOF);
1121 // printf(" parsed %d test cases.\n", caseList.size());
1122 return nodeList;
1123 }
1124
1125 } // sl
1126
ShaderLibrary(tcu::TestContext & testCtx,RenderContext & renderCtx)1127 ShaderLibrary::ShaderLibrary(tcu::TestContext& testCtx, RenderContext& renderCtx)
1128 : m_testCtx(testCtx), m_renderCtx(renderCtx)
1129 {
1130 }
1131
~ShaderLibrary(void)1132 ShaderLibrary::~ShaderLibrary(void)
1133 {
1134 }
1135
loadShaderFile(const char * fileName)1136 vector<tcu::TestNode*> ShaderLibrary::loadShaderFile(const char* fileName)
1137 {
1138 tcu::Resource* resource = m_testCtx.getArchive().getResource(fileName);
1139 std::vector<char> buf;
1140
1141 /* printf(" loading '%s'\n", fileName);*/
1142
1143 try
1144 {
1145 int size = resource->getSize();
1146 buf.resize(size + 1);
1147 resource->read((deUint8*)&buf[0], size);
1148 buf[size] = '\0';
1149 }
1150 catch (const std::exception&)
1151 {
1152 delete resource;
1153 throw;
1154 }
1155
1156 delete resource;
1157
1158 sl::ShaderParser parser(m_testCtx, m_renderCtx);
1159 vector<tcu::TestNode*> nodes = parser.parse(&buf[0]);
1160
1161 return nodes;
1162 }
1163
1164 // ShaderLibraryGroup
1165
ShaderLibraryGroup(Context & context,const char * name,const char * description,const char * filename)1166 ShaderLibraryGroup::ShaderLibraryGroup(Context& context, const char* name, const char* description,
1167 const char* filename)
1168 : TestCaseGroup(context, name, description), m_filename(filename)
1169 {
1170 }
1171
~ShaderLibraryGroup(void)1172 ShaderLibraryGroup::~ShaderLibraryGroup(void)
1173 {
1174 }
1175
init(void)1176 void ShaderLibraryGroup::init(void)
1177 {
1178 deqp::ShaderLibrary shaderLibrary(m_testCtx, m_context.getRenderContext());
1179 std::vector<tcu::TestNode*> children = shaderLibrary.loadShaderFile(m_filename.c_str());
1180
1181 for (int i = 0; i < (int)children.size(); i++)
1182 addChild(children[i]);
1183 }
1184
1185 } // deqp
1186