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