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