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