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