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