1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) Module
3 * -----------------------------------------------
4 *
5 * Copyright 2014 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 Compiler test case.
22 *//*--------------------------------------------------------------------*/
23
24 #include "glsShaderLibrary.hpp"
25 #include "glsShaderLibraryCase.hpp"
26 #include "gluShaderUtil.hpp"
27 #include "tcuResource.hpp"
28 #include "glwEnums.hpp"
29
30 #include "deInt32.h"
31
32 #include <string>
33 #include <vector>
34 #include <fstream>
35 #include <sstream>
36
37 #include <string.h>
38 #include <stdarg.h>
39 #include <stdlib.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 gls
56 {
57 namespace sl
58 {
59
60 static const glu::GLSLVersion DEFAULT_GLSL_VERSION = glu::GLSL_VERSION_100_ES;
61
isWhitespace(char c)62 DE_INLINE deBool isWhitespace (char c)
63 {
64 return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
65 }
66
isEOL(char c)67 DE_INLINE deBool isEOL (char c)
68 {
69 return (c == '\r') || (c == '\n');
70 }
71
isNumeric(char c)72 DE_INLINE deBool isNumeric (char c)
73 {
74 return deInRange32(c, '0', '9');
75 }
76
isAlpha(char c)77 DE_INLINE deBool isAlpha (char c)
78 {
79 return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z');
80 }
81
isCaseNameChar(char c)82 DE_INLINE deBool isCaseNameChar (char c)
83 {
84 return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z') || deInRange32(c, '0', '9') || (c == '_') || (c == '-') || (c == '.');
85 }
86
87 // \todo [2011-02-11 pyry] Should not depend on Context or TestContext!
88 class ShaderParser
89 {
90 public:
91 ShaderParser (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* currentDir = DE_NULL);
92 ~ShaderParser (void);
93
94 vector<tcu::TestNode*> parse (const char* input);
95
96 private:
97 enum Token
98 {
99 TOKEN_INVALID = 0,
100 TOKEN_EOF,
101 TOKEN_STRING,
102 TOKEN_SHADER_SOURCE,
103
104 TOKEN_INT_LITERAL,
105 TOKEN_FLOAT_LITERAL,
106
107 // identifiers
108 TOKEN_IDENTIFIER,
109 TOKEN_TRUE,
110 TOKEN_FALSE,
111 TOKEN_DESC,
112 TOKEN_EXPECT,
113 TOKEN_GROUP,
114 TOKEN_CASE,
115 TOKEN_END,
116 TOKEN_VALUES,
117 TOKEN_BOTH,
118 TOKEN_VERTEX,
119 TOKEN_FRAGMENT,
120 TOKEN_UNIFORM,
121 TOKEN_INPUT,
122 TOKEN_OUTPUT,
123 TOKEN_FLOAT,
124 TOKEN_FLOAT_VEC2,
125 TOKEN_FLOAT_VEC3,
126 TOKEN_FLOAT_VEC4,
127 TOKEN_FLOAT_MAT2,
128 TOKEN_FLOAT_MAT2X3,
129 TOKEN_FLOAT_MAT2X4,
130 TOKEN_FLOAT_MAT3X2,
131 TOKEN_FLOAT_MAT3,
132 TOKEN_FLOAT_MAT3X4,
133 TOKEN_FLOAT_MAT4X2,
134 TOKEN_FLOAT_MAT4X3,
135 TOKEN_FLOAT_MAT4,
136 TOKEN_INT,
137 TOKEN_INT_VEC2,
138 TOKEN_INT_VEC3,
139 TOKEN_INT_VEC4,
140 TOKEN_UINT,
141 TOKEN_UINT_VEC2,
142 TOKEN_UINT_VEC3,
143 TOKEN_UINT_VEC4,
144 TOKEN_BOOL,
145 TOKEN_BOOL_VEC2,
146 TOKEN_BOOL_VEC3,
147 TOKEN_BOOL_VEC4,
148 TOKEN_VERSION,
149 TOKEN_TESSELLATION_CONTROL,
150 TOKEN_TESSELLATION_EVALUATION,
151 TOKEN_GEOMETRY,
152 TOKEN_REQUIRE,
153 TOKEN_IN,
154 TOKEN_IMPORT,
155 TOKEN_PIPELINE_PROGRAM,
156 TOKEN_ACTIVE_STAGES,
157
158 // symbols
159 TOKEN_ASSIGN,
160 TOKEN_PLUS,
161 TOKEN_MINUS,
162 TOKEN_COMMA,
163 TOKEN_VERTICAL_BAR,
164 TOKEN_SEMI_COLON,
165 TOKEN_LEFT_PAREN,
166 TOKEN_RIGHT_PAREN,
167 TOKEN_LEFT_BRACKET,
168 TOKEN_RIGHT_BRACKET,
169 TOKEN_LEFT_BRACE,
170 TOKEN_RIGHT_BRACE,
171 TOKEN_GREATER,
172
173 TOKEN_LAST
174 };
175
176 void parseError (const std::string& errorStr);
177 float parseFloatLiteral (const char* str);
178 int parseIntLiteral (const char* str);
179 string parseStringLiteral (const char* str);
180 string parseShaderSource (const char* str);
181 void advanceToken (void);
182 void advanceToken (Token assumed);
183 void assumeToken (Token token);
184 DataType mapDataTypeToken (Token token);
185 const char* getTokenName (Token token);
186 deUint32 getShaderStageLiteralFlag (void);
187 deUint32 getGLEnumFromName (const std::string& enumName);
188
189 void parseValueElement (DataType dataType, ShaderCase::Value& result);
190 void parseValue (ShaderCase::ValueBlock& valueBlock);
191 void parseValueBlock (ShaderCase::ValueBlock& valueBlock);
192 deUint32 parseShaderStageList (void);
193 void parseRequirement (ShaderCase::CaseRequirement& valueBlock);
194 void parseExpectResult (ShaderCase::ExpectResult& expectResult);
195 void parseGLSLVersion (glu::GLSLVersion& version);
196 void parsePipelineProgram (ShaderCase::PipelineProgram& program);
197 void parseShaderCase (vector<tcu::TestNode*>& shaderNodeList);
198 void parseShaderGroup (vector<tcu::TestNode*>& shaderNodeList);
199 void parseImport (vector<tcu::TestNode*>& shaderNodeList);
200
201 // Member variables.
202 tcu::TestContext& m_testCtx;
203 RenderContext& m_renderCtx;
204 const glu::ContextInfo& m_contextInfo;
205 std::string m_input;
206 const char* m_curPtr;
207 Token m_curToken;
208 std::string m_curTokenStr;
209 const char* const m_currentDir;
210 };
211
ShaderParser(tcu::TestContext & testCtx,RenderContext & renderCtx,const glu::ContextInfo & contextInfo,const char * currentDir)212 ShaderParser::ShaderParser (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo, const char* currentDir)
213 : m_testCtx (testCtx)
214 , m_renderCtx (renderCtx)
215 , m_contextInfo (contextInfo)
216 , m_curPtr (DE_NULL)
217 , m_curToken (TOKEN_LAST)
218 , m_currentDir (currentDir)
219 {
220 }
221
~ShaderParser(void)222 ShaderParser::~ShaderParser (void)
223 {
224 // nada
225 }
226
parseError(const std::string & errorStr)227 void ShaderParser::parseError (const std::string& errorStr)
228 {
229 string atStr = string(m_curPtr, 80);
230 throw tcu::InternalError((string("Parser error: ") + errorStr + " near '" + atStr + " ...'").c_str(), "", __FILE__, __LINE__);
231 }
232
parseFloatLiteral(const char * str)233 float ShaderParser::parseFloatLiteral (const char* str)
234 {
235 return (float)atof(str);
236 }
237
parseIntLiteral(const char * str)238 int ShaderParser::parseIntLiteral (const char* str)
239 {
240 return atoi(str);
241 }
242
parseStringLiteral(const char * str)243 string ShaderParser::parseStringLiteral (const char* str)
244 {
245 const char* p = str;
246 char endChar = *p++;
247 ostringstream o;
248
249 while (*p != endChar && *p)
250 {
251 if (*p == '\\')
252 {
253 switch (p[1])
254 {
255 case 0: DE_ASSERT(DE_FALSE); break;
256 case 'n': o << '\n'; break;
257 case 't': o << '\t'; break;
258 default: o << p[1]; break;
259 }
260
261 p += 2;
262 }
263 else
264 o << *p++;
265 }
266
267 return o.str();
268 }
269
removeExtraIndentation(const string & source)270 static string removeExtraIndentation (const string& source)
271 {
272 // Detect indentation from first line.
273 int numIndentChars = 0;
274 for (int ndx = 0; ndx < (int)source.length() && isWhitespace(source[ndx]); ndx++)
275 numIndentChars += source[ndx] == '\t' ? 4 : 1;
276
277 // Process all lines and remove preceding indentation.
278 ostringstream processed;
279 {
280 bool atLineStart = true;
281 int indentCharsOmitted = 0;
282
283 for (int pos = 0; pos < (int)source.length(); pos++)
284 {
285 char c = source[pos];
286
287 if (atLineStart && indentCharsOmitted < numIndentChars && (c == ' ' || c == '\t'))
288 {
289 indentCharsOmitted += c == '\t' ? 4 : 1;
290 }
291 else if (isEOL(c))
292 {
293 if (source[pos] == '\r' && source[pos+1] == '\n')
294 {
295 pos += 1;
296 processed << '\n';
297 }
298 else
299 processed << c;
300
301 atLineStart = true;
302 indentCharsOmitted = 0;
303 }
304 else
305 {
306 processed << c;
307 atLineStart = false;
308 }
309 }
310 }
311
312 return processed.str();
313 }
314
parseShaderSource(const char * str)315 string ShaderParser::parseShaderSource (const char* str)
316 {
317 const char* p = str+2;
318 ostringstream o;
319
320 // Eat first empty line from beginning.
321 while (*p == ' ') p++;
322 if (*p == '\r') p++;
323 if (*p == '\n') p++;
324
325 while ((p[0] != '"') || (p[1] != '"'))
326 {
327 if (*p == '\\')
328 {
329 switch (p[1])
330 {
331 case 0: DE_ASSERT(DE_FALSE); break;
332 case 'n': o << '\n'; break;
333 case 't': o << '\t'; break;
334 default: o << p[1]; break;
335 }
336
337 p += 2;
338 }
339 else
340 o << *p++;
341 }
342
343 return removeExtraIndentation(o.str());
344 }
345
advanceToken(void)346 void ShaderParser::advanceToken (void)
347 {
348 // Skip old token.
349 m_curPtr += m_curTokenStr.length();
350
351 // Reset token (for safety).
352 m_curToken = TOKEN_INVALID;
353 m_curTokenStr = "";
354
355 // Eat whitespace & comments while they last.
356 for (;;)
357 {
358 while (isWhitespace(*m_curPtr))
359 m_curPtr++;
360
361 // Check for EOL comment.
362 if (*m_curPtr == '#')
363 {
364 while (*m_curPtr && !isEOL(*m_curPtr))
365 m_curPtr++;
366 }
367 else
368 break;
369 }
370
371 if (!*m_curPtr)
372 {
373 m_curToken = TOKEN_EOF;
374 m_curTokenStr = "<EOF>";
375 }
376 else if (isAlpha(*m_curPtr))
377 {
378 struct Named
379 {
380 const char* str;
381 Token token;
382 };
383
384 static const Named s_named[] =
385 {
386 { "true", TOKEN_TRUE },
387 { "false", TOKEN_FALSE },
388 { "desc", TOKEN_DESC },
389 { "expect", TOKEN_EXPECT },
390 { "group", TOKEN_GROUP },
391 { "case", TOKEN_CASE },
392 { "end", TOKEN_END },
393 { "values", TOKEN_VALUES },
394 { "both", TOKEN_BOTH },
395 { "vertex", TOKEN_VERTEX },
396 { "fragment", TOKEN_FRAGMENT },
397 { "uniform", TOKEN_UNIFORM },
398 { "input", TOKEN_INPUT },
399 { "output", TOKEN_OUTPUT },
400 { "float", TOKEN_FLOAT },
401 { "vec2", TOKEN_FLOAT_VEC2 },
402 { "vec3", TOKEN_FLOAT_VEC3 },
403 { "vec4", TOKEN_FLOAT_VEC4 },
404 { "mat2", TOKEN_FLOAT_MAT2 },
405 { "mat2x3", TOKEN_FLOAT_MAT2X3 },
406 { "mat2x4", TOKEN_FLOAT_MAT2X4 },
407 { "mat3x2", TOKEN_FLOAT_MAT3X2 },
408 { "mat3", TOKEN_FLOAT_MAT3 },
409 { "mat3x4", TOKEN_FLOAT_MAT3X4 },
410 { "mat4x2", TOKEN_FLOAT_MAT4X2 },
411 { "mat4x3", TOKEN_FLOAT_MAT4X3 },
412 { "mat4", TOKEN_FLOAT_MAT4 },
413 { "int", TOKEN_INT },
414 { "ivec2", TOKEN_INT_VEC2 },
415 { "ivec3", TOKEN_INT_VEC3 },
416 { "ivec4", TOKEN_INT_VEC4 },
417 { "uint", TOKEN_UINT },
418 { "uvec2", TOKEN_UINT_VEC2 },
419 { "uvec3", TOKEN_UINT_VEC3 },
420 { "uvec4", TOKEN_UINT_VEC4 },
421 { "bool", TOKEN_BOOL },
422 { "bvec2", TOKEN_BOOL_VEC2 },
423 { "bvec3", TOKEN_BOOL_VEC3 },
424 { "bvec4", TOKEN_BOOL_VEC4 },
425 { "version", TOKEN_VERSION },
426 { "tessellation_control", TOKEN_TESSELLATION_CONTROL },
427 { "tessellation_evaluation", TOKEN_TESSELLATION_EVALUATION },
428 { "geometry", TOKEN_GEOMETRY },
429 { "require", TOKEN_REQUIRE },
430 { "in", TOKEN_IN },
431 { "import", TOKEN_IMPORT },
432 { "pipeline_program", TOKEN_PIPELINE_PROGRAM },
433 { "active_stages", TOKEN_ACTIVE_STAGES },
434 };
435
436 const char* end = m_curPtr + 1;
437 while (isCaseNameChar(*end))
438 end++;
439 m_curTokenStr = string(m_curPtr, end - m_curPtr);
440
441 m_curToken = TOKEN_IDENTIFIER;
442
443 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_named); ndx++)
444 {
445 if (m_curTokenStr == s_named[ndx].str)
446 {
447 m_curToken = s_named[ndx].token;
448 break;
449 }
450 }
451 }
452 else if (isNumeric(*m_curPtr))
453 {
454 /* \todo [2010-03-31 petri] Hex? */
455 const char* p = m_curPtr;
456 while (isNumeric(*p))
457 p++;
458 if (*p == '.')
459 {
460 p++;
461 while (isNumeric(*p))
462 p++;
463
464 if (*p == 'e' || *p == 'E')
465 {
466 p++;
467 if (*p == '+' || *p == '-')
468 p++;
469 DE_ASSERT(isNumeric(*p));
470 while (isNumeric(*p))
471 p++;
472 }
473
474 m_curToken = TOKEN_FLOAT_LITERAL;
475 m_curTokenStr = string(m_curPtr, p - m_curPtr);
476 }
477 else
478 {
479 m_curToken = TOKEN_INT_LITERAL;
480 m_curTokenStr = string(m_curPtr, p - m_curPtr);
481 }
482 }
483 else if (*m_curPtr == '"' && m_curPtr[1] == '"')
484 {
485 const char* p = m_curPtr + 2;
486
487 while ((p[0] != '"') || (p[1] != '"'))
488 {
489 DE_ASSERT(*p);
490 if (*p == '\\')
491 {
492 DE_ASSERT(p[1] != 0);
493 p += 2;
494 }
495 else
496 p++;
497 }
498 p += 2;
499
500 m_curToken = TOKEN_SHADER_SOURCE;
501 m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr));
502 }
503 else if (*m_curPtr == '"' || *m_curPtr == '\'')
504 {
505 char endChar = *m_curPtr;
506 const char* p = m_curPtr + 1;
507
508 while (*p != endChar)
509 {
510 DE_ASSERT(*p);
511 if (*p == '\\')
512 {
513 DE_ASSERT(p[1] != 0);
514 p += 2;
515 }
516 else
517 p++;
518 }
519 p++;
520
521 m_curToken = TOKEN_STRING;
522 m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr));
523 }
524 else
525 {
526 struct SimpleToken
527 {
528 const char* str;
529 Token token;
530 };
531
532 static const SimpleToken s_simple[] =
533 {
534 { "=", TOKEN_ASSIGN },
535 { "+", TOKEN_PLUS },
536 { "-", TOKEN_MINUS },
537 { ",", TOKEN_COMMA },
538 { "|", TOKEN_VERTICAL_BAR },
539 { ";", TOKEN_SEMI_COLON },
540 { "(", TOKEN_LEFT_PAREN },
541 { ")", TOKEN_RIGHT_PAREN },
542 { "[", TOKEN_LEFT_BRACKET },
543 { "]", TOKEN_RIGHT_BRACKET },
544 { "{", TOKEN_LEFT_BRACE },
545 { "}", TOKEN_RIGHT_BRACE },
546 { ">", TOKEN_GREATER },
547 };
548
549 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_simple); ndx++)
550 {
551 if (strncmp(s_simple[ndx].str, m_curPtr, strlen(s_simple[ndx].str)) == 0)
552 {
553 m_curToken = s_simple[ndx].token;
554 m_curTokenStr = s_simple[ndx].str;
555 return;
556 }
557 }
558
559 // Otherwise invalid token.
560 m_curToken = TOKEN_INVALID;
561 m_curTokenStr = *m_curPtr;
562 }
563 }
564
advanceToken(Token assumed)565 void ShaderParser::advanceToken (Token assumed)
566 {
567 assumeToken(assumed);
568 advanceToken();
569 }
570
assumeToken(Token token)571 void ShaderParser::assumeToken (Token token)
572 {
573 if (m_curToken != token)
574 parseError((string("unexpected token '") + m_curTokenStr + "', expecting '" + getTokenName(token) + "'").c_str());
575 DE_TEST_ASSERT(m_curToken == token);
576 }
577
mapDataTypeToken(Token token)578 DataType ShaderParser::mapDataTypeToken (Token token)
579 {
580 switch (token)
581 {
582 case TOKEN_FLOAT: return TYPE_FLOAT;
583 case TOKEN_FLOAT_VEC2: return TYPE_FLOAT_VEC2;
584 case TOKEN_FLOAT_VEC3: return TYPE_FLOAT_VEC3;
585 case TOKEN_FLOAT_VEC4: return TYPE_FLOAT_VEC4;
586 case TOKEN_FLOAT_MAT2: return TYPE_FLOAT_MAT2;
587 case TOKEN_FLOAT_MAT2X3: return TYPE_FLOAT_MAT2X3;
588 case TOKEN_FLOAT_MAT2X4: return TYPE_FLOAT_MAT2X4;
589 case TOKEN_FLOAT_MAT3X2: return TYPE_FLOAT_MAT3X2;
590 case TOKEN_FLOAT_MAT3: return TYPE_FLOAT_MAT3;
591 case TOKEN_FLOAT_MAT3X4: return TYPE_FLOAT_MAT3X4;
592 case TOKEN_FLOAT_MAT4X2: return TYPE_FLOAT_MAT4X2;
593 case TOKEN_FLOAT_MAT4X3: return TYPE_FLOAT_MAT4X3;
594 case TOKEN_FLOAT_MAT4: return TYPE_FLOAT_MAT4;
595 case TOKEN_INT: return TYPE_INT;
596 case TOKEN_INT_VEC2: return TYPE_INT_VEC2;
597 case TOKEN_INT_VEC3: return TYPE_INT_VEC3;
598 case TOKEN_INT_VEC4: return TYPE_INT_VEC4;
599 case TOKEN_UINT: return TYPE_UINT;
600 case TOKEN_UINT_VEC2: return TYPE_UINT_VEC2;
601 case TOKEN_UINT_VEC3: return TYPE_UINT_VEC3;
602 case TOKEN_UINT_VEC4: return TYPE_UINT_VEC4;
603 case TOKEN_BOOL: return TYPE_BOOL;
604 case TOKEN_BOOL_VEC2: return TYPE_BOOL_VEC2;
605 case TOKEN_BOOL_VEC3: return TYPE_BOOL_VEC3;
606 case TOKEN_BOOL_VEC4: return TYPE_BOOL_VEC4;
607 default: 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: return "<invalid>";
616 case TOKEN_EOF: return "<eof>";
617 case TOKEN_STRING: return "<string>";
618 case TOKEN_SHADER_SOURCE: return "source";
619
620 case TOKEN_INT_LITERAL: return "<int>";
621 case TOKEN_FLOAT_LITERAL: return "<float>";
622
623 // identifiers
624 case TOKEN_IDENTIFIER: return "<identifier>";
625 case TOKEN_TRUE: return "true";
626 case TOKEN_FALSE: return "false";
627 case TOKEN_DESC: return "desc";
628 case TOKEN_EXPECT: return "expect";
629 case TOKEN_GROUP: return "group";
630 case TOKEN_CASE: return "case";
631 case TOKEN_END: return "end";
632 case TOKEN_VALUES: return "values";
633 case TOKEN_BOTH: return "both";
634 case TOKEN_VERTEX: return "vertex";
635 case TOKEN_FRAGMENT: return "fragment";
636 case TOKEN_TESSELLATION_CONTROL: return "tessellation_control";
637 case TOKEN_TESSELLATION_EVALUATION: return "tessellation_evaluation";
638 case TOKEN_GEOMETRY: return "geometry";
639 case TOKEN_REQUIRE: return "require";
640 case TOKEN_UNIFORM: return "uniform";
641 case TOKEN_INPUT: return "input";
642 case TOKEN_OUTPUT: return "output";
643 case TOKEN_FLOAT: return "float";
644 case TOKEN_FLOAT_VEC2: return "vec2";
645 case TOKEN_FLOAT_VEC3: return "vec3";
646 case TOKEN_FLOAT_VEC4: return "vec4";
647 case TOKEN_FLOAT_MAT2: return "mat2";
648 case TOKEN_FLOAT_MAT2X3: return "mat2x3";
649 case TOKEN_FLOAT_MAT2X4: return "mat2x4";
650 case TOKEN_FLOAT_MAT3X2: return "mat3x2";
651 case TOKEN_FLOAT_MAT3: return "mat3";
652 case TOKEN_FLOAT_MAT3X4: return "mat3x4";
653 case TOKEN_FLOAT_MAT4X2: return "mat4x2";
654 case TOKEN_FLOAT_MAT4X3: return "mat4x3";
655 case TOKEN_FLOAT_MAT4: return "mat4";
656 case TOKEN_INT: return "int";
657 case TOKEN_INT_VEC2: return "ivec2";
658 case TOKEN_INT_VEC3: return "ivec3";
659 case TOKEN_INT_VEC4: return "ivec4";
660 case TOKEN_UINT: return "uint";
661 case TOKEN_UINT_VEC2: return "uvec2";
662 case TOKEN_UINT_VEC3: return "uvec3";
663 case TOKEN_UINT_VEC4: return "uvec4";
664 case TOKEN_BOOL: return "bool";
665 case TOKEN_BOOL_VEC2: return "bvec2";
666 case TOKEN_BOOL_VEC3: return "bvec3";
667 case TOKEN_BOOL_VEC4: return "bvec4";
668 case TOKEN_IN: return "in";
669 case TOKEN_IMPORT: return "import";
670 case TOKEN_PIPELINE_PROGRAM: return "pipeline_program";
671 case TOKEN_ACTIVE_STAGES: return "active_stages";
672
673 case TOKEN_ASSIGN: return "=";
674 case TOKEN_PLUS: return "+";
675 case TOKEN_MINUS: return "-";
676 case TOKEN_COMMA: return ",";
677 case TOKEN_VERTICAL_BAR: return "|";
678 case TOKEN_SEMI_COLON: return ";";
679 case TOKEN_LEFT_PAREN: return "(";
680 case TOKEN_RIGHT_PAREN: return ")";
681 case TOKEN_LEFT_BRACKET: return "[";
682 case TOKEN_RIGHT_BRACKET: return "]";
683 case TOKEN_LEFT_BRACE: return "{";
684 case TOKEN_RIGHT_BRACE: return "}";
685 case TOKEN_GREATER: return ">";
686
687 default: return "<unknown>";
688 }
689 }
690
getShaderStageLiteralFlag(void)691 deUint32 ShaderParser::getShaderStageLiteralFlag (void)
692 {
693 switch (m_curToken)
694 {
695 case TOKEN_VERTEX: return (1 << glu::SHADERTYPE_VERTEX);
696 case TOKEN_FRAGMENT: return (1 << glu::SHADERTYPE_FRAGMENT);
697 case TOKEN_GEOMETRY: return (1 << glu::SHADERTYPE_GEOMETRY);
698 case TOKEN_TESSELLATION_CONTROL: return (1 << glu::SHADERTYPE_TESSELLATION_CONTROL);
699 case TOKEN_TESSELLATION_EVALUATION: return (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
700
701 default:
702 parseError(std::string() + "invalid shader stage name, got " + m_curTokenStr);
703 return 0;
704 }
705 }
706
getGLEnumFromName(const std::string & enumName)707 deUint32 ShaderParser::getGLEnumFromName (const std::string& enumName)
708 {
709 static const struct
710 {
711 const char* name;
712 deUint32 value;
713 } names[] =
714 {
715 { "GL_MAX_VERTEX_IMAGE_UNIFORMS", GL_MAX_VERTEX_IMAGE_UNIFORMS },
716 { "GL_MAX_VERTEX_ATOMIC_COUNTERS", GL_MAX_VERTEX_ATOMIC_COUNTERS },
717 { "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS", GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS },
718 { "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS", GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS },
719 };
720
721 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(names); ++ndx)
722 if (names[ndx].name == enumName)
723 return names[ndx].value;
724
725 parseError(std::string() + "unknown enum name, got " + enumName);
726 return 0;
727 }
728
parseValueElement(DataType expectedDataType,ShaderCase::Value & result)729 void ShaderParser::parseValueElement (DataType expectedDataType, ShaderCase::Value& result)
730 {
731 DataType scalarType = getDataTypeScalarType(expectedDataType);
732 int scalarSize = getDataTypeScalarSize(expectedDataType);
733
734 /* \todo [2010-04-19 petri] Support arrays. */
735 ShaderCase::Value::Element elems[16];
736
737 if (scalarSize > 1)
738 {
739 DE_ASSERT(mapDataTypeToken(m_curToken) == expectedDataType);
740 advanceToken(); // data type (float, vec2, etc.)
741 advanceToken(TOKEN_LEFT_PAREN);
742 }
743
744 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
745 {
746 if (scalarType == TYPE_FLOAT)
747 {
748 float signMult = 1.0f;
749 if (m_curToken == TOKEN_MINUS)
750 {
751 signMult = -1.0f;
752 advanceToken();
753 }
754
755 assumeToken(TOKEN_FLOAT_LITERAL);
756 elems[scalarNdx].float32 = signMult * parseFloatLiteral(m_curTokenStr.c_str());
757 advanceToken(TOKEN_FLOAT_LITERAL);
758 }
759 else if (scalarType == TYPE_INT || scalarType == TYPE_UINT)
760 {
761 int signMult = 1;
762 if (m_curToken == TOKEN_MINUS)
763 {
764 signMult = -1;
765 advanceToken();
766 }
767
768 assumeToken(TOKEN_INT_LITERAL);
769 elems[scalarNdx].int32 = signMult * parseIntLiteral(m_curTokenStr.c_str());
770 advanceToken(TOKEN_INT_LITERAL);
771 }
772 else
773 {
774 DE_ASSERT(scalarType == TYPE_BOOL);
775 elems[scalarNdx].bool32 = (m_curToken == TOKEN_TRUE);
776 if (m_curToken != TOKEN_TRUE && m_curToken != TOKEN_FALSE)
777 parseError(string("unexpected token, expecting bool: " + m_curTokenStr));
778 advanceToken(); // true/false
779 }
780
781 if (scalarNdx != (scalarSize - 1))
782 advanceToken(TOKEN_COMMA);
783 }
784
785 if (scalarSize > 1)
786 advanceToken(TOKEN_RIGHT_PAREN);
787
788 // Store results.
789 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
790 result.elements.push_back(elems[scalarNdx]);
791 }
792
parseValue(ShaderCase::ValueBlock & valueBlock)793 void ShaderParser::parseValue (ShaderCase::ValueBlock& valueBlock)
794 {
795 PARSE_DBG((" parseValue()\n"));
796
797 // Parsed results.
798 ShaderCase::Value result;
799
800 // Parse storage.
801 if (m_curToken == TOKEN_UNIFORM)
802 result.storageType = ShaderCase::Value::STORAGE_UNIFORM;
803 else if (m_curToken == TOKEN_INPUT)
804 result.storageType = ShaderCase::Value::STORAGE_INPUT;
805 else if (m_curToken == TOKEN_OUTPUT)
806 result.storageType = ShaderCase::Value::STORAGE_OUTPUT;
807 else
808 parseError(string("unexpected token encountered when parsing value classifier"));
809 advanceToken();
810
811 // Parse data type.
812 result.dataType = mapDataTypeToken(m_curToken);
813 if (result.dataType == TYPE_INVALID)
814 parseError(string("unexpected token when parsing value data type: " + m_curTokenStr));
815 advanceToken();
816
817 // Parse value name.
818 if (m_curToken == TOKEN_IDENTIFIER || m_curToken == TOKEN_STRING)
819 {
820 if (m_curToken == TOKEN_IDENTIFIER)
821 result.valueName = m_curTokenStr;
822 else
823 result.valueName = parseStringLiteral(m_curTokenStr.c_str());
824 }
825 else
826 parseError(string("unexpected token when parsing value name: " + m_curTokenStr));
827 advanceToken();
828
829 // Parse assignment operator.
830 advanceToken(TOKEN_ASSIGN);
831
832 // Parse actual value.
833 if (m_curToken == TOKEN_LEFT_BRACKET) // value list
834 {
835 advanceToken(TOKEN_LEFT_BRACKET);
836 result.arrayLength = 0;
837
838 for (;;)
839 {
840 parseValueElement(result.dataType, result);
841 result.arrayLength++;
842
843 if (m_curToken == TOKEN_RIGHT_BRACKET)
844 break;
845 else if (m_curToken == TOKEN_VERTICAL_BAR)
846 {
847 advanceToken();
848 continue;
849 }
850 else
851 parseError(string("unexpected token in value element array: " + m_curTokenStr));
852 }
853
854 advanceToken(TOKEN_RIGHT_BRACKET);
855 }
856 else // arrays, single elements
857 {
858 parseValueElement(result.dataType, result);
859 result.arrayLength = 1;
860 }
861
862 advanceToken(TOKEN_SEMI_COLON); // end of declaration
863
864 valueBlock.values.push_back(result);
865 }
866
parseValueBlock(ShaderCase::ValueBlock & valueBlock)867 void ShaderParser::parseValueBlock (ShaderCase::ValueBlock& valueBlock)
868 {
869 PARSE_DBG((" parseValueBlock()\n"));
870 advanceToken(TOKEN_VALUES);
871 advanceToken(TOKEN_LEFT_BRACE);
872
873 for (;;)
874 {
875 if (m_curToken == TOKEN_UNIFORM || m_curToken == TOKEN_INPUT || m_curToken == TOKEN_OUTPUT)
876 parseValue(valueBlock);
877 else if (m_curToken == TOKEN_RIGHT_BRACE)
878 break;
879 else
880 parseError(string("unexpected token when parsing a value block: " + m_curTokenStr));
881 }
882
883 advanceToken(TOKEN_RIGHT_BRACE);
884
885 // Compute combined array length of value block.
886 int arrayLength = 1;
887 for (int valueNdx = 0; valueNdx < (int)valueBlock.values.size(); valueNdx++)
888 {
889 const ShaderCase::Value& val = valueBlock.values[valueNdx];
890 if (val.arrayLength > 1)
891 {
892 DE_ASSERT(arrayLength == 1 || arrayLength == val.arrayLength);
893 arrayLength = val.arrayLength;
894 }
895 }
896 valueBlock.arrayLength = arrayLength;
897 }
898
parseShaderStageList(void)899 deUint32 ShaderParser::parseShaderStageList (void)
900 {
901 deUint32 mask = 0;
902
903 assumeToken(TOKEN_LEFT_BRACE);
904
905 // don't allow 0-sized lists
906 advanceToken();
907 mask |= getShaderStageLiteralFlag();
908 advanceToken();
909
910 for (;;)
911 {
912 if (m_curToken == TOKEN_RIGHT_BRACE)
913 break;
914 else if (m_curToken == TOKEN_COMMA)
915 {
916 deUint32 stageFlag;
917 advanceToken();
918
919 stageFlag = getShaderStageLiteralFlag();
920 if (stageFlag & mask)
921 parseError(string("stage already set in the shader stage set: " + m_curTokenStr));
922
923 mask |= stageFlag;
924 advanceToken();
925 }
926 else
927 parseError(string("invalid shader stage set token: " + m_curTokenStr));
928 }
929 advanceToken(TOKEN_RIGHT_BRACE);
930
931 return mask;
932 }
933
parseRequirement(ShaderCase::CaseRequirement & valueBlock)934 void ShaderParser::parseRequirement (ShaderCase::CaseRequirement& valueBlock)
935 {
936 PARSE_DBG((" parseRequirement()\n"));
937
938 advanceToken();
939 assumeToken(TOKEN_IDENTIFIER);
940
941 if (m_curTokenStr == "extension")
942 {
943 std::vector<std::string> anyExtensionStringList;
944 deUint32 affectedCasesFlags = -1; // by default all stages
945
946 advanceToken();
947 assumeToken(TOKEN_LEFT_BRACE);
948
949 advanceToken();
950 assumeToken(TOKEN_STRING);
951
952 anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str()));
953 advanceToken();
954
955 for (;;)
956 {
957 if (m_curToken == TOKEN_RIGHT_BRACE)
958 break;
959 else if (m_curToken == TOKEN_VERTICAL_BAR)
960 {
961 advanceToken();
962 assumeToken(TOKEN_STRING);
963
964 anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str()));
965 advanceToken();
966 }
967 else
968 parseError(string("invalid extension list token: " + m_curTokenStr));
969 }
970 advanceToken(TOKEN_RIGHT_BRACE);
971
972 if (m_curToken == TOKEN_IN)
973 {
974 advanceToken();
975 affectedCasesFlags = parseShaderStageList();
976 }
977
978 valueBlock = ShaderCase::CaseRequirement::createAnyExtensionRequirement(anyExtensionStringList, affectedCasesFlags);
979 }
980 else if (m_curTokenStr == "limit")
981 {
982 deUint32 limitEnum;
983 int limitValue;
984
985 advanceToken();
986
987 assumeToken(TOKEN_STRING);
988 limitEnum = getGLEnumFromName(parseStringLiteral(m_curTokenStr.c_str()));
989 advanceToken();
990
991 assumeToken(TOKEN_GREATER);
992 advanceToken();
993
994 assumeToken(TOKEN_INT_LITERAL);
995 limitValue = parseIntLiteral(m_curTokenStr.c_str());
996 advanceToken();
997
998 valueBlock = ShaderCase::CaseRequirement::createLimitRequirement(limitEnum, limitValue);
999 }
1000 else if (m_curTokenStr == "full_glsl_es_100_support")
1001 {
1002 advanceToken();
1003
1004 valueBlock = ShaderCase::CaseRequirement::createFullGLSLES100SpecificationRequirement();
1005 }
1006 else
1007 parseError(string("invalid requirement value: " + m_curTokenStr));
1008 }
1009
parseExpectResult(ShaderCase::ExpectResult & expectResult)1010 void ShaderParser::parseExpectResult (ShaderCase::ExpectResult& expectResult)
1011 {
1012 assumeToken(TOKEN_IDENTIFIER);
1013
1014 if (m_curTokenStr == "pass")
1015 expectResult = ShaderCase::EXPECT_PASS;
1016 else if (m_curTokenStr == "compile_fail")
1017 expectResult = ShaderCase::EXPECT_COMPILE_FAIL;
1018 else if (m_curTokenStr == "link_fail")
1019 expectResult = ShaderCase::EXPECT_LINK_FAIL;
1020 else if (m_curTokenStr == "compile_or_link_fail")
1021 expectResult = ShaderCase::EXPECT_COMPILE_LINK_FAIL;
1022 else if (m_curTokenStr == "validation_fail")
1023 expectResult = ShaderCase::EXPECT_VALIDATION_FAIL;
1024 else if (m_curTokenStr == "build_successful")
1025 expectResult = ShaderCase::EXPECT_BUILD_SUCCESSFUL;
1026 else
1027 parseError(string("invalid expected result value: " + m_curTokenStr));
1028
1029 advanceToken();
1030 }
1031
parseGLSLVersion(glu::GLSLVersion & version)1032 void ShaderParser::parseGLSLVersion (glu::GLSLVersion& version)
1033 {
1034 int versionNum = 0;
1035 std::string postfix = "";
1036
1037 assumeToken(TOKEN_INT_LITERAL);
1038 versionNum = parseIntLiteral(m_curTokenStr.c_str());
1039 advanceToken();
1040
1041 if (m_curToken == TOKEN_IDENTIFIER)
1042 {
1043 postfix = m_curTokenStr;
1044 advanceToken();
1045 }
1046
1047 if (versionNum == 100 && postfix == "es") version = glu::GLSL_VERSION_100_ES;
1048 else if (versionNum == 300 && postfix == "es") version = glu::GLSL_VERSION_300_ES;
1049 else if (versionNum == 310 && postfix == "es") version = glu::GLSL_VERSION_310_ES;
1050 else if (versionNum == 130) version = glu::GLSL_VERSION_130;
1051 else if (versionNum == 140) version = glu::GLSL_VERSION_140;
1052 else if (versionNum == 150) version = glu::GLSL_VERSION_150;
1053 else if (versionNum == 330) version = glu::GLSL_VERSION_330;
1054 else if (versionNum == 400) version = glu::GLSL_VERSION_400;
1055 else if (versionNum == 410) version = glu::GLSL_VERSION_410;
1056 else if (versionNum == 420) version = glu::GLSL_VERSION_420;
1057 else if (versionNum == 430) version = glu::GLSL_VERSION_430;
1058 else
1059 parseError("Unknown GLSL version");
1060 }
1061
parsePipelineProgram(ShaderCase::PipelineProgram & program)1062 void ShaderParser::parsePipelineProgram (ShaderCase::PipelineProgram& program)
1063 {
1064 deUint32 activeStages = 0;
1065 vector<string> vertexSources;
1066 vector<string> fragmentSources;
1067 vector<string> tessellationCtrlSources;
1068 vector<string> tessellationEvalSources;
1069 vector<string> geometrySources;
1070 vector<ShaderCase::CaseRequirement> requirements;
1071
1072 advanceToken(TOKEN_PIPELINE_PROGRAM);
1073
1074 for (;;)
1075 {
1076 if (m_curToken == TOKEN_END)
1077 break;
1078 else if (m_curToken == TOKEN_ACTIVE_STAGES)
1079 {
1080 advanceToken();
1081 activeStages = parseShaderStageList();
1082 }
1083 else if (m_curToken == TOKEN_REQUIRE)
1084 {
1085 ShaderCase::CaseRequirement requirement;
1086 parseRequirement(requirement);
1087 requirements.push_back(requirement);
1088 }
1089 else if (m_curToken == TOKEN_VERTEX ||
1090 m_curToken == TOKEN_FRAGMENT ||
1091 m_curToken == TOKEN_TESSELLATION_CONTROL ||
1092 m_curToken == TOKEN_TESSELLATION_EVALUATION ||
1093 m_curToken == TOKEN_GEOMETRY)
1094 {
1095 const Token token = m_curToken;
1096 string source;
1097
1098 advanceToken();
1099 assumeToken(TOKEN_SHADER_SOURCE);
1100 source = parseShaderSource(m_curTokenStr.c_str());
1101 advanceToken();
1102
1103 switch (token)
1104 {
1105 case TOKEN_VERTEX: vertexSources.push_back(source); break;
1106 case TOKEN_FRAGMENT: fragmentSources.push_back(source); break;
1107 case TOKEN_TESSELLATION_CONTROL: tessellationCtrlSources.push_back(source); break;
1108 case TOKEN_TESSELLATION_EVALUATION: tessellationEvalSources.push_back(source); break;
1109 case TOKEN_GEOMETRY: geometrySources.push_back(source); break;
1110 default:
1111 parseError(DE_FALSE);
1112 }
1113 }
1114 else
1115 parseError(string("invalid pipeline program value: " + m_curTokenStr));
1116 }
1117 advanceToken(TOKEN_END);
1118
1119 if (activeStages == 0)
1120 parseError("program pipeline object must have active stages");
1121
1122 // return pipeline part
1123 program.activeStageBits = activeStages;
1124 program.requirements.swap(requirements);
1125 program.vertexSources.swap(vertexSources);
1126 program.fragmentSources.swap(fragmentSources);
1127 program.tessCtrlSources.swap(tessellationCtrlSources);
1128 program.tessEvalSources.swap(tessellationEvalSources);
1129 program.geometrySources.swap(geometrySources);
1130 }
1131
parseShaderCase(vector<tcu::TestNode * > & shaderNodeList)1132 void ShaderParser::parseShaderCase (vector<tcu::TestNode*>& shaderNodeList)
1133 {
1134 // Parse 'case'.
1135 PARSE_DBG((" parseShaderCase()\n"));
1136 advanceToken(TOKEN_CASE);
1137
1138 // Parse case name.
1139 string caseName = m_curTokenStr;
1140 advanceToken(); // \note [pyry] All token types are allowed here.
1141
1142 // Setup case.
1143 GLSLVersion version = DEFAULT_GLSL_VERSION;
1144 ShaderCase::ExpectResult expectResult = ShaderCase::EXPECT_PASS;
1145 string description;
1146 string bothSource;
1147 vector<string> vertexSources;
1148 vector<string> fragmentSources;
1149 vector<string> tessellationCtrlSources;
1150 vector<string> tessellationEvalSources;
1151 vector<string> geometrySources;
1152 vector<ShaderCase::ValueBlock> valueBlockList;
1153 vector<ShaderCase::CaseRequirement> requirements;
1154 vector<ShaderCase::PipelineProgram> pipelinePrograms;
1155
1156 for (;;)
1157 {
1158 if (m_curToken == TOKEN_END)
1159 break;
1160 else if (m_curToken == TOKEN_DESC)
1161 {
1162 advanceToken();
1163 assumeToken(TOKEN_STRING);
1164 description = parseStringLiteral(m_curTokenStr.c_str());
1165 advanceToken();
1166 }
1167 else if (m_curToken == TOKEN_EXPECT)
1168 {
1169 advanceToken();
1170 parseExpectResult(expectResult);
1171 }
1172 else if (m_curToken == TOKEN_VALUES)
1173 {
1174 ShaderCase::ValueBlock block;
1175 parseValueBlock(block);
1176 valueBlockList.push_back(block);
1177 }
1178 else if (m_curToken == TOKEN_BOTH ||
1179 m_curToken == TOKEN_VERTEX ||
1180 m_curToken == TOKEN_FRAGMENT ||
1181 m_curToken == TOKEN_TESSELLATION_CONTROL ||
1182 m_curToken == TOKEN_TESSELLATION_EVALUATION ||
1183 m_curToken == TOKEN_GEOMETRY)
1184 {
1185 const Token token = m_curToken;
1186 string source;
1187
1188 advanceToken();
1189 assumeToken(TOKEN_SHADER_SOURCE);
1190 source = parseShaderSource(m_curTokenStr.c_str());
1191 advanceToken();
1192
1193 switch (token)
1194 {
1195 case TOKEN_VERTEX: vertexSources.push_back(source); break;
1196 case TOKEN_FRAGMENT: fragmentSources.push_back(source); break;
1197 case TOKEN_TESSELLATION_CONTROL: tessellationCtrlSources.push_back(source); break;
1198 case TOKEN_TESSELLATION_EVALUATION: tessellationEvalSources.push_back(source); break;
1199 case TOKEN_GEOMETRY: geometrySources.push_back(source); break;
1200 case TOKEN_BOTH:
1201 {
1202 if (!bothSource.empty())
1203 parseError("multiple 'both' blocks");
1204 bothSource = source;
1205 break;
1206 }
1207
1208 default:
1209 parseError(DE_FALSE);
1210 }
1211 }
1212 else if (m_curToken == TOKEN_VERSION)
1213 {
1214 advanceToken();
1215 parseGLSLVersion(version);
1216 }
1217 else if (m_curToken == TOKEN_REQUIRE)
1218 {
1219 ShaderCase::CaseRequirement requirement;
1220 parseRequirement(requirement);
1221 requirements.push_back(requirement);
1222 }
1223 else if (m_curToken == TOKEN_PIPELINE_PROGRAM)
1224 {
1225 ShaderCase::PipelineProgram pipelineProgram;
1226 parsePipelineProgram(pipelineProgram);
1227 pipelinePrograms.push_back(pipelineProgram);
1228 }
1229 else
1230 parseError(string("unexpected token while parsing shader case: " + m_curTokenStr));
1231 }
1232
1233 advanceToken(TOKEN_END); // case end
1234
1235 if (!bothSource.empty())
1236 {
1237 if (!vertexSources.empty() ||
1238 !fragmentSources.empty() ||
1239 !tessellationCtrlSources.empty() ||
1240 !tessellationEvalSources.empty() ||
1241 !geometrySources.empty() ||
1242 !pipelinePrograms.empty())
1243 {
1244 parseError("'both' cannot be mixed with other shader stages");
1245 }
1246
1247 // vertex
1248 {
1249 ShaderCase::ShaderCaseSpecification spec = ShaderCase::ShaderCaseSpecification::generateSharedSourceVertexCase(expectResult, version, valueBlockList, bothSource);
1250 spec.requirements = requirements;
1251
1252 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, m_contextInfo, (caseName + "_vertex").c_str(), description.c_str(), spec));
1253 }
1254
1255 // fragment
1256 {
1257 ShaderCase::ShaderCaseSpecification spec = ShaderCase::ShaderCaseSpecification::generateSharedSourceFragmentCase(expectResult, version, valueBlockList, bothSource);
1258 spec.requirements = requirements;
1259
1260 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, m_contextInfo, (caseName + "_fragment").c_str(), description.c_str(), spec));
1261 }
1262 }
1263 else if (pipelinePrograms.empty())
1264 {
1265 ShaderCase::ShaderCaseSpecification spec;
1266
1267 spec.expectResult = expectResult;
1268 spec.caseType = ShaderCase::CASETYPE_COMPLETE;
1269 spec.targetVersion = version;
1270 spec.requirements.swap(requirements);
1271 spec.valueBlocks.swap(valueBlockList);
1272 spec.vertexSources.swap(vertexSources);
1273 spec.fragmentSources.swap(fragmentSources);
1274 spec.tessCtrlSources.swap(tessellationCtrlSources);
1275 spec.tessEvalSources.swap(tessellationEvalSources);
1276 spec.geometrySources.swap(geometrySources);
1277
1278 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, m_contextInfo, caseName.c_str(), description.c_str(), spec));
1279 }
1280 else
1281 {
1282 if (!vertexSources.empty() ||
1283 !fragmentSources.empty() ||
1284 !tessellationCtrlSources.empty() ||
1285 !tessellationEvalSources.empty() ||
1286 !geometrySources.empty())
1287 {
1288 parseError("pipeline programs cannot be mixed with complete programs");
1289 }
1290
1291 // Pipeline case, multiple programs
1292 {
1293 ShaderCase::PipelineCaseSpecification spec;
1294
1295 spec.expectResult = expectResult;
1296 spec.caseType = ShaderCase::CASETYPE_COMPLETE;
1297 spec.targetVersion = version;
1298 spec.valueBlocks.swap(valueBlockList);
1299 spec.programs.swap(pipelinePrograms);
1300
1301 shaderNodeList.push_back(new ShaderCase(m_testCtx, m_renderCtx, m_contextInfo, caseName.c_str(), description.c_str(), spec));
1302 }
1303 }
1304 }
1305
parseShaderGroup(vector<tcu::TestNode * > & shaderNodeList)1306 void ShaderParser::parseShaderGroup (vector<tcu::TestNode*>& shaderNodeList)
1307 {
1308 // Parse 'case'.
1309 PARSE_DBG((" parseShaderGroup()\n"));
1310 advanceToken(TOKEN_GROUP);
1311
1312 // Parse case name.
1313 string name = m_curTokenStr;
1314 advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
1315
1316 // Parse description.
1317 assumeToken(TOKEN_STRING);
1318 string description = parseStringLiteral(m_curTokenStr.c_str());
1319 advanceToken(TOKEN_STRING);
1320
1321 std::vector<tcu::TestNode*> children;
1322
1323 // Parse group children.
1324 for (;;)
1325 {
1326 if (m_curToken == TOKEN_END)
1327 break;
1328 else if (m_curToken == TOKEN_GROUP)
1329 parseShaderGroup(children);
1330 else if (m_curToken == TOKEN_CASE)
1331 parseShaderCase(children);
1332 else if (m_curToken == TOKEN_IMPORT)
1333 parseImport(children);
1334 else
1335 parseError(string("unexpected token while parsing shader group: " + m_curTokenStr));
1336 }
1337
1338 advanceToken(TOKEN_END); // group end
1339
1340 // Create group node.
1341 tcu::TestCaseGroup* groupNode = new tcu::TestCaseGroup(m_testCtx, name.c_str(), description.c_str(), children);
1342 shaderNodeList.push_back(groupNode);
1343 }
1344
parseImport(vector<tcu::TestNode * > & shaderNodeList)1345 void ShaderParser::parseImport (vector<tcu::TestNode*>& shaderNodeList)
1346 {
1347 ShaderLibrary subLibrary (m_testCtx, m_renderCtx, m_contextInfo);
1348 vector<tcu::TestNode*> importedCases;
1349 std::string filename;
1350
1351 if (!m_currentDir)
1352 parseError(string("cannot use import in inline shader source"));
1353
1354 advanceToken(TOKEN_IMPORT);
1355
1356 assumeToken(TOKEN_STRING);
1357 filename = m_currentDir + parseStringLiteral(m_curTokenStr.c_str());
1358 advanceToken(TOKEN_STRING);
1359
1360 importedCases = subLibrary.loadShaderFile(filename.c_str());
1361 shaderNodeList.insert(shaderNodeList.end(), importedCases.begin(), importedCases.end());
1362 }
1363
parse(const char * input)1364 vector<tcu::TestNode*> ShaderParser::parse (const char* input)
1365 {
1366 // Initialize parser.
1367 m_input = input;
1368 m_curPtr = m_input.c_str();
1369 m_curToken = TOKEN_INVALID;
1370 m_curTokenStr = "";
1371 advanceToken();
1372
1373 vector<tcu::TestNode*> nodeList;
1374
1375 // Parse all cases.
1376 PARSE_DBG(("parse()\n"));
1377 for (;;)
1378 {
1379 if (m_curToken == TOKEN_CASE)
1380 parseShaderCase(nodeList);
1381 else if (m_curToken == TOKEN_GROUP)
1382 parseShaderGroup(nodeList);
1383 else if (m_curToken == TOKEN_IMPORT)
1384 parseImport(nodeList);
1385 else if (m_curToken == TOKEN_EOF)
1386 break;
1387 else
1388 parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'");
1389 }
1390
1391 assumeToken(TOKEN_EOF);
1392 // printf(" parsed %d test cases.\n", caseList.size());
1393 return nodeList;
1394 }
1395
1396 } // sl
1397
getFileDirectory(const std::string & filePath)1398 static std::string getFileDirectory (const std::string& filePath)
1399 {
1400 const std::string::size_type lastDelim = filePath.find_last_of('/');
1401
1402 if (lastDelim == std::string::npos)
1403 return "";
1404 else
1405 return filePath.substr(0, lastDelim+1);
1406 }
1407
ShaderLibrary(tcu::TestContext & testCtx,RenderContext & renderCtx,const glu::ContextInfo & contextInfo)1408 ShaderLibrary::ShaderLibrary (tcu::TestContext& testCtx, RenderContext& renderCtx, const glu::ContextInfo& contextInfo)
1409 : m_testCtx (testCtx)
1410 , m_renderCtx (renderCtx)
1411 , m_contextInfo (contextInfo)
1412 {
1413 }
1414
~ShaderLibrary(void)1415 ShaderLibrary::~ShaderLibrary (void)
1416 {
1417 }
1418
loadShaderFile(const char * fileName)1419 vector<tcu::TestNode*> ShaderLibrary::loadShaderFile (const char* fileName)
1420 {
1421 tcu::Resource* resource = m_testCtx.getArchive().getResource(fileName);
1422 std::string fileDirectory = getFileDirectory(fileName);
1423 std::vector<char> buf;
1424
1425 /* printf(" loading '%s'\n", fileName);*/
1426
1427 try
1428 {
1429 int size = resource->getSize();
1430 buf.resize(size + 1);
1431 resource->read((deUint8*)&buf[0], size);
1432 buf[size] = '\0';
1433 }
1434 catch (const std::exception&)
1435 {
1436 delete resource;
1437 throw;
1438 }
1439
1440 delete resource;
1441
1442 sl::ShaderParser parser(m_testCtx, m_renderCtx, m_contextInfo, fileDirectory.c_str());
1443 vector<tcu::TestNode*> nodes = parser.parse(&buf[0]);
1444
1445 return nodes;
1446 }
1447
parseShader(const char * shaderSource)1448 vector<tcu::TestNode*> ShaderLibrary::parseShader (const char* shaderSource)
1449 {
1450 sl::ShaderParser parser(m_testCtx, m_renderCtx, m_contextInfo);
1451 vector<tcu::TestNode*> nodes = parser.parse(shaderSource);
1452
1453 return nodes;
1454 }
1455
1456 } // gls
1457 } // deqp
1458