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