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