1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2015 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Shader .test file utilities.
22 *//*--------------------------------------------------------------------*/
24 #include "gluShaderLibrary.hpp"
26 #include "tcuStringTemplate.hpp"
27 #include "tcuResource.hpp"
28 #include "tcuTestLog.hpp"
30 #include "deStringUtil.hpp"
31 #include "deUniquePtr.hpp"
32 #include "deFilePath.hpp"
34 #include "glwEnums.hpp"
41 # define PARSE_DBG(X) printf X
43 # define PARSE_DBG(X) DE_NULL_STATEMENT
56 using std::ostringstream;
62 bool isValid (const ValueBlock& block)
64 for (size_t storageNdx = 0; storageNdx < 3; ++storageNdx)
66 const vector<Value>& values = storageNdx == 0 ? block.inputs :
67 storageNdx == 1 ? block.outputs :
69 const size_t refArrayLen = values.empty() ? 0 : (values[0].elements.size() / (size_t)values[0].type.getScalarSize());
71 for (size_t valNdx = 0; valNdx < values.size(); ++valNdx)
73 const Value& value = values[valNdx];
75 if (!value.type.isBasicType())
77 print("ERROR: Value '%s' is of unsupported type!\n", value.name.c_str());
81 if (value.elements.size() != refArrayLen*(size_t)value.type.getScalarSize())
83 print("ERROR: Value '%s' has invalid number of scalars!\n", value.name.c_str());
92 bool isValid (const ShaderCaseSpecification& spec)
94 const deUint32 vtxFragMask = (1u << SHADERTYPE_VERTEX)
95 | (1u << SHADERTYPE_FRAGMENT);
96 const deUint32 tessCtrlEvalMask = (1u << SHADERTYPE_TESSELLATION_CONTROL)
97 | (1u << SHADERTYPE_TESSELLATION_EVALUATION);
98 const deUint32 supportedStageMask = vtxFragMask | tessCtrlEvalMask
99 | (1u << SHADERTYPE_GEOMETRY);
100 const bool isSeparable = !spec.programs.empty() && spec.programs[0].sources.separable;
102 if (spec.programs.empty())
104 print("ERROR: No programs specified!\n");
108 if (spec.fullGLSLES100Required)
110 if (spec.targetVersion != GLSL_VERSION_100_ES)
112 print("ERROR: Full GLSL ES 1.00 support requested for other GLSL version!\n");
116 if (spec.expectResult != EXPECT_PASS &&
117 spec.expectResult != EXPECT_VALIDATION_FAIL &&
118 spec.expectResult != EXPECT_BUILD_SUCCESSFUL)
120 print("ERROR: Full GLSL ES 1.00 support doesn't make sense when expecting compile/link failure!\n");
125 if (!de::inBounds(spec.caseType, (CaseType)0, CASETYPE_LAST))
127 print("ERROR: Invalid case type!\n");
131 if (!de::inBounds(spec.expectResult, (ExpectResult)0, EXPECT_LAST))
133 print("ERROR: Invalid expected result!\n");
137 if (!isValid(spec.values))
140 if (!spec.values.inputs.empty() && !spec.values.outputs.empty() &&
141 spec.values.inputs[0].elements.size() / spec.values.inputs[0].type.getScalarSize() != spec.values.outputs[0].elements.size() / spec.values.outputs[0].type.getScalarSize())
143 print("ERROR: Number of input and output elements don't match!\n");
149 deUint32 usedStageMask = 0u;
151 if (spec.caseType != CASETYPE_COMPLETE)
153 print("ERROR: Separable shaders supported only for complete cases!\n");
157 for (size_t progNdx = 0; progNdx < spec.programs.size(); ++progNdx)
159 for (int shaderStageNdx = 0; shaderStageNdx < SHADERTYPE_LAST; ++shaderStageNdx)
161 const deUint32 curStageMask = (1u << shaderStageNdx);
163 if (supportedStageMask & curStageMask)
165 const bool hasShader = !spec.programs[progNdx].sources.sources[shaderStageNdx].empty();
166 const bool isEnabled = (spec.programs[progNdx].activeStages & curStageMask) != 0;
168 if (hasShader != isEnabled)
170 print("ERROR: Inconsistent source/enable for shader stage %s!\n", getShaderTypeName((ShaderType)shaderStageNdx));
174 if (hasShader && (usedStageMask & curStageMask) != 0)
176 print("ERROR: Stage %s enabled on multiple programs!\n", getShaderTypeName((ShaderType)shaderStageNdx));
181 usedStageMask |= curStageMask;
183 else if (!spec.programs[progNdx].sources.sources[shaderStageNdx].empty())
185 print("ERROR: Source specified for unsupported shader stage %s!\n", getShaderTypeName((ShaderType)shaderStageNdx));
191 if ((usedStageMask & vtxFragMask) != vtxFragMask)
193 print("ERROR: Vertex and fragment shaders are mandatory!\n");
197 if ((usedStageMask & tessCtrlEvalMask) != 0 && (usedStageMask & tessCtrlEvalMask) != tessCtrlEvalMask)
199 print("ERROR: Both tessellation control and eval shaders must be either enabled or disabled!\n");
205 const bool hasVertex = !spec.programs[0].sources.sources[SHADERTYPE_VERTEX].empty();
206 const bool hasFragment = !spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].empty();
208 if (spec.programs.size() != 1)
210 print("ERROR: Only cases using separable programs can have multiple programs!\n");
214 if (spec.caseType == CASETYPE_VERTEX_ONLY && (!hasVertex || hasFragment))
216 print("ERROR: Vertex-only case must have only vertex shader!\n");
220 if (spec.caseType == CASETYPE_FRAGMENT_ONLY && (hasVertex || !hasFragment))
222 print("ERROR: Fragment-only case must have only fragment shader!\n");
226 if (spec.caseType == CASETYPE_COMPLETE && (!hasVertex || !hasFragment))
228 print("ERROR: Complete case must have at least vertex and fragment shaders\n");
238 static const glu::GLSLVersion DEFAULT_GLSL_VERSION = glu::GLSL_VERSION_100_ES;
240 DE_INLINE deBool isWhitespace (char c)
242 return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n');
245 DE_INLINE deBool isEOL (char c)
247 return (c == '\r') || (c == '\n');
250 DE_INLINE deBool isNumeric (char c)
252 return deInRange32(c, '0', '9');
255 DE_INLINE deBool isAlpha (char c)
257 return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z');
260 DE_INLINE deBool isCaseNameChar (char c)
262 return deInRange32(c, 'a', 'z') || deInRange32(c, 'A', 'Z') || deInRange32(c, '0', '9') || (c == '_') || (c == '-') || (c == '.');
265 struct CaseRequirement
270 TYPE_FULL_GLSL_ES_100_SUPPORT,
271 TYPE_IMPLEMENTATION_LIMIT,
279 RequiredExtension extension;
281 // TYPE_IMPLEMENTATION_LIMIT
282 RequiredCapability requiredCap;
284 CaseRequirement (void) : type(TYPE_LAST) {}
286 static CaseRequirement createFullGLSLES100SpecificationRequirement (void)
289 req.type = TYPE_FULL_GLSL_ES_100_SUPPORT;
293 static CaseRequirement createAnyExtensionRequirement (const vector<string>& alternatives, deUint32 effectiveStages)
296 req.type = TYPE_EXTENSION;
297 req.extension = RequiredExtension(alternatives, effectiveStages);
301 static CaseRequirement createLimitRequirement (deUint32 enumName, int referenceValue)
304 req.type = TYPE_IMPLEMENTATION_LIMIT;
305 req.requiredCap = RequiredCapability(enumName, referenceValue);
313 ShaderParser (const tcu::Archive& archive, const std::string& filename, ShaderCaseFactory* caseFactory);
314 ~ShaderParser (void);
316 vector<tcu::TestNode*> parse (void);
373 TOKEN_TESSELLATION_CONTROL,
374 TOKEN_TESSELLATION_EVALUATION,
379 TOKEN_PIPELINE_PROGRAM,
400 void parseError (const std::string& errorStr);
401 float parseFloatLiteral (const char* str);
402 int parseIntLiteral (const char* str);
403 string parseStringLiteral (const char* str);
404 string parseShaderSource (const char* str);
405 void advanceToken (void);
406 void advanceToken (Token assumed);
407 void assumeToken (Token token);
408 DataType mapDataTypeToken (Token token);
409 const char* getTokenName (Token token);
410 deUint32 getShaderStageLiteralFlag (void);
411 deUint32 getGLEnumFromName (const std::string& enumName);
413 void parseValueElement (DataType dataType, Value& result);
414 void parseValue (ValueBlock& valueBlock);
415 void parseValueBlock (ValueBlock& valueBlock);
416 deUint32 parseShaderStageList (void);
417 void parseRequirement (CaseRequirement& valueBlock);
418 void parseExpectResult (ExpectResult& expectResult);
419 void parseFormat (DataType& format);
420 void parseGLSLVersion (glu::GLSLVersion& version);
421 void parsePipelineProgram (ProgramSpecification& program);
422 void parseShaderCase (vector<tcu::TestNode*>& shaderNodeList);
423 void parseShaderGroup (vector<tcu::TestNode*>& shaderNodeList);
424 void parseImport (vector<tcu::TestNode*>& shaderNodeList);
426 const tcu::Archive& m_archive;
427 const string m_filename;
428 ShaderCaseFactory* const m_caseFactory;
430 UniquePtr<tcu::Resource> m_resource;
431 vector<char> m_input;
433 const char* m_curPtr;
435 std::string m_curTokenStr;
438 ShaderParser::ShaderParser (const tcu::Archive& archive, const string& filename, ShaderCaseFactory* caseFactroy)
439 : m_archive (archive)
440 , m_filename (filename)
441 , m_caseFactory (caseFactroy)
442 , m_resource (archive.getResource(m_filename.c_str()))
444 , m_curToken (TOKEN_LAST)
448 ShaderParser::~ShaderParser (void)
452 void ShaderParser::parseError (const std::string& errorStr)
454 string atStr = string(m_curPtr, 80);
455 throw tcu::InternalError((string("Parser error: ") + errorStr + " near '" + atStr + " ...'").c_str(), DE_NULL, __FILE__, __LINE__);
458 float ShaderParser::parseFloatLiteral (const char* str)
460 return (float)atof(str);
463 int ShaderParser::parseIntLiteral (const char* str)
468 string ShaderParser::parseStringLiteral (const char* str)
474 while (*p != endChar && *p)
480 case 0: DE_ASSERT(DE_FALSE); break;
481 case 'n': o << '\n'; break;
482 case 't': o << '\t'; break;
483 default: o << p[1]; break;
495 static string removeExtraIndentation (const string& source)
497 // Detect indentation from first line.
498 int numIndentChars = 0;
499 for (int ndx = 0; ndx < (int)source.length() && isWhitespace(source[ndx]); ndx++)
500 numIndentChars += source[ndx] == '\t' ? 4 : 1;
502 // Process all lines and remove preceding indentation.
503 ostringstream processed;
505 bool atLineStart = true;
506 int indentCharsOmitted = 0;
508 for (int pos = 0; pos < (int)source.length(); pos++)
510 char c = source[pos];
512 if (atLineStart && indentCharsOmitted < numIndentChars && (c == ' ' || c == '\t'))
514 indentCharsOmitted += c == '\t' ? 4 : 1;
518 if (source[pos] == '\r' && source[pos+1] == '\n')
527 indentCharsOmitted = 0;
537 return processed.str();
540 string ShaderParser::parseShaderSource (const char* str)
542 const char* p = str+2;
545 // Eat first empty line from beginning.
546 while (*p == ' ') p++;
550 while ((p[0] != '"') || (p[1] != '"'))
556 case 0: DE_ASSERT(DE_FALSE); break;
557 case 'n': o << '\n'; break;
558 case 't': o << '\t'; break;
559 default: o << p[1]; break;
568 return removeExtraIndentation(o.str());
571 void ShaderParser::advanceToken (void)
574 m_curPtr += m_curTokenStr.length();
576 // Reset token (for safety).
577 m_curToken = TOKEN_INVALID;
580 // Eat whitespace & comments while they last.
583 while (isWhitespace(*m_curPtr))
586 // Check for EOL comment.
587 if (*m_curPtr == '#')
589 while (*m_curPtr && !isEOL(*m_curPtr))
598 m_curToken = TOKEN_EOF;
599 m_curTokenStr = "<EOF>";
601 else if (isAlpha(*m_curPtr))
609 static const Named s_named[] =
611 { "true", TOKEN_TRUE },
612 { "false", TOKEN_FALSE },
613 { "desc", TOKEN_DESC },
614 { "expect", TOKEN_EXPECT },
615 { "group", TOKEN_GROUP },
616 { "case", TOKEN_CASE },
617 { "end", TOKEN_END },
618 { "output_color", TOKEN_OUTPUT_COLOR },
619 { "format", TOKEN_FORMAT },
620 { "values", TOKEN_VALUES },
621 { "both", TOKEN_BOTH },
622 { "vertex", TOKEN_VERTEX },
623 { "fragment", TOKEN_FRAGMENT },
624 { "uniform", TOKEN_UNIFORM },
625 { "input", TOKEN_INPUT },
626 { "output", TOKEN_OUTPUT },
627 { "float", TOKEN_FLOAT },
628 { "vec2", TOKEN_FLOAT_VEC2 },
629 { "vec3", TOKEN_FLOAT_VEC3 },
630 { "vec4", TOKEN_FLOAT_VEC4 },
631 { "mat2", TOKEN_FLOAT_MAT2 },
632 { "mat2x3", TOKEN_FLOAT_MAT2X3 },
633 { "mat2x4", TOKEN_FLOAT_MAT2X4 },
634 { "mat3x2", TOKEN_FLOAT_MAT3X2 },
635 { "mat3", TOKEN_FLOAT_MAT3 },
636 { "mat3x4", TOKEN_FLOAT_MAT3X4 },
637 { "mat4x2", TOKEN_FLOAT_MAT4X2 },
638 { "mat4x3", TOKEN_FLOAT_MAT4X3 },
639 { "mat4", TOKEN_FLOAT_MAT4 },
640 { "int", TOKEN_INT },
641 { "ivec2", TOKEN_INT_VEC2 },
642 { "ivec3", TOKEN_INT_VEC3 },
643 { "ivec4", TOKEN_INT_VEC4 },
644 { "uint", TOKEN_UINT },
645 { "uvec2", TOKEN_UINT_VEC2 },
646 { "uvec3", TOKEN_UINT_VEC3 },
647 { "uvec4", TOKEN_UINT_VEC4 },
648 { "bool", TOKEN_BOOL },
649 { "bvec2", TOKEN_BOOL_VEC2 },
650 { "bvec3", TOKEN_BOOL_VEC3 },
651 { "bvec4", TOKEN_BOOL_VEC4 },
652 { "version", TOKEN_VERSION },
653 { "tessellation_control", TOKEN_TESSELLATION_CONTROL },
654 { "tessellation_evaluation", TOKEN_TESSELLATION_EVALUATION },
655 { "geometry", TOKEN_GEOMETRY },
656 { "require", TOKEN_REQUIRE },
658 { "import", TOKEN_IMPORT },
659 { "pipeline_program", TOKEN_PIPELINE_PROGRAM },
660 { "active_stages", TOKEN_ACTIVE_STAGES },
663 const char* end = m_curPtr + 1;
664 while (isCaseNameChar(*end))
666 m_curTokenStr = string(m_curPtr, end - m_curPtr);
668 m_curToken = TOKEN_IDENTIFIER;
670 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_named); ndx++)
672 if (m_curTokenStr == s_named[ndx].str)
674 m_curToken = s_named[ndx].token;
679 else if (isNumeric(*m_curPtr))
681 /* \todo [2010-03-31 petri] Hex? */
682 const char* p = m_curPtr;
683 while (isNumeric(*p))
688 while (isNumeric(*p))
691 if (*p == 'e' || *p == 'E')
694 if (*p == '+' || *p == '-')
696 DE_ASSERT(isNumeric(*p));
697 while (isNumeric(*p))
701 m_curToken = TOKEN_FLOAT_LITERAL;
702 m_curTokenStr = string(m_curPtr, p - m_curPtr);
706 m_curToken = TOKEN_INT_LITERAL;
707 m_curTokenStr = string(m_curPtr, p - m_curPtr);
710 else if (*m_curPtr == '"' && m_curPtr[1] == '"')
712 const char* p = m_curPtr + 2;
714 while ((p[0] != '"') || (p[1] != '"'))
719 DE_ASSERT(p[1] != 0);
727 m_curToken = TOKEN_SHADER_SOURCE;
728 m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr));
730 else if (*m_curPtr == '"' || *m_curPtr == '\'')
732 char endChar = *m_curPtr;
733 const char* p = m_curPtr + 1;
735 while (*p != endChar)
740 DE_ASSERT(p[1] != 0);
748 m_curToken = TOKEN_STRING;
749 m_curTokenStr = string(m_curPtr, (int)(p - m_curPtr));
759 static const SimpleToken s_simple[] =
761 { "=", TOKEN_ASSIGN },
763 { "-", TOKEN_MINUS },
764 { ",", TOKEN_COMMA },
765 { "|", TOKEN_VERTICAL_BAR },
766 { ";", TOKEN_SEMI_COLON },
767 { "(", TOKEN_LEFT_PAREN },
768 { ")", TOKEN_RIGHT_PAREN },
769 { "[", TOKEN_LEFT_BRACKET },
770 { "]", TOKEN_RIGHT_BRACKET },
771 { "{", TOKEN_LEFT_BRACE },
772 { "}", TOKEN_RIGHT_BRACE },
773 { ">", TOKEN_GREATER },
776 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_simple); ndx++)
778 if (strncmp(s_simple[ndx].str, m_curPtr, strlen(s_simple[ndx].str)) == 0)
780 m_curToken = s_simple[ndx].token;
781 m_curTokenStr = s_simple[ndx].str;
786 // Otherwise invalid token.
787 m_curToken = TOKEN_INVALID;
788 m_curTokenStr = *m_curPtr;
792 void ShaderParser::advanceToken (Token assumed)
794 assumeToken(assumed);
798 void ShaderParser::assumeToken (Token token)
800 if (m_curToken != token)
801 parseError((string("unexpected token '") + m_curTokenStr + "', expecting '" + getTokenName(token) + "'").c_str());
802 DE_TEST_ASSERT(m_curToken == token);
805 DataType ShaderParser::mapDataTypeToken (Token token)
809 case TOKEN_FLOAT: return TYPE_FLOAT;
810 case TOKEN_FLOAT_VEC2: return TYPE_FLOAT_VEC2;
811 case TOKEN_FLOAT_VEC3: return TYPE_FLOAT_VEC3;
812 case TOKEN_FLOAT_VEC4: return TYPE_FLOAT_VEC4;
813 case TOKEN_FLOAT_MAT2: return TYPE_FLOAT_MAT2;
814 case TOKEN_FLOAT_MAT2X3: return TYPE_FLOAT_MAT2X3;
815 case TOKEN_FLOAT_MAT2X4: return TYPE_FLOAT_MAT2X4;
816 case TOKEN_FLOAT_MAT3X2: return TYPE_FLOAT_MAT3X2;
817 case TOKEN_FLOAT_MAT3: return TYPE_FLOAT_MAT3;
818 case TOKEN_FLOAT_MAT3X4: return TYPE_FLOAT_MAT3X4;
819 case TOKEN_FLOAT_MAT4X2: return TYPE_FLOAT_MAT4X2;
820 case TOKEN_FLOAT_MAT4X3: return TYPE_FLOAT_MAT4X3;
821 case TOKEN_FLOAT_MAT4: return TYPE_FLOAT_MAT4;
822 case TOKEN_INT: return TYPE_INT;
823 case TOKEN_INT_VEC2: return TYPE_INT_VEC2;
824 case TOKEN_INT_VEC3: return TYPE_INT_VEC3;
825 case TOKEN_INT_VEC4: return TYPE_INT_VEC4;
826 case TOKEN_UINT: return TYPE_UINT;
827 case TOKEN_UINT_VEC2: return TYPE_UINT_VEC2;
828 case TOKEN_UINT_VEC3: return TYPE_UINT_VEC3;
829 case TOKEN_UINT_VEC4: return TYPE_UINT_VEC4;
830 case TOKEN_BOOL: return TYPE_BOOL;
831 case TOKEN_BOOL_VEC2: return TYPE_BOOL_VEC2;
832 case TOKEN_BOOL_VEC3: return TYPE_BOOL_VEC3;
833 case TOKEN_BOOL_VEC4: return TYPE_BOOL_VEC4;
834 default: return TYPE_INVALID;
838 const char* ShaderParser::getTokenName (Token token)
842 case TOKEN_INVALID: return "<invalid>";
843 case TOKEN_EOF: return "<eof>";
844 case TOKEN_STRING: return "<string>";
845 case TOKEN_SHADER_SOURCE: return "source";
847 case TOKEN_INT_LITERAL: return "<int>";
848 case TOKEN_FLOAT_LITERAL: return "<float>";
851 case TOKEN_IDENTIFIER: return "<identifier>";
852 case TOKEN_TRUE: return "true";
853 case TOKEN_FALSE: return "false";
854 case TOKEN_DESC: return "desc";
855 case TOKEN_EXPECT: return "expect";
856 case TOKEN_GROUP: return "group";
857 case TOKEN_CASE: return "case";
858 case TOKEN_END: return "end";
859 case TOKEN_VALUES: return "values";
860 case TOKEN_BOTH: return "both";
861 case TOKEN_VERTEX: return "vertex";
862 case TOKEN_FRAGMENT: return "fragment";
863 case TOKEN_TESSELLATION_CONTROL: return "tessellation_control";
864 case TOKEN_TESSELLATION_EVALUATION: return "tessellation_evaluation";
865 case TOKEN_GEOMETRY: return "geometry";
866 case TOKEN_REQUIRE: return "require";
867 case TOKEN_UNIFORM: return "uniform";
868 case TOKEN_INPUT: return "input";
869 case TOKEN_OUTPUT: return "output";
870 case TOKEN_FLOAT: return "float";
871 case TOKEN_FLOAT_VEC2: return "vec2";
872 case TOKEN_FLOAT_VEC3: return "vec3";
873 case TOKEN_FLOAT_VEC4: return "vec4";
874 case TOKEN_FLOAT_MAT2: return "mat2";
875 case TOKEN_FLOAT_MAT2X3: return "mat2x3";
876 case TOKEN_FLOAT_MAT2X4: return "mat2x4";
877 case TOKEN_FLOAT_MAT3X2: return "mat3x2";
878 case TOKEN_FLOAT_MAT3: return "mat3";
879 case TOKEN_FLOAT_MAT3X4: return "mat3x4";
880 case TOKEN_FLOAT_MAT4X2: return "mat4x2";
881 case TOKEN_FLOAT_MAT4X3: return "mat4x3";
882 case TOKEN_FLOAT_MAT4: return "mat4";
883 case TOKEN_INT: return "int";
884 case TOKEN_INT_VEC2: return "ivec2";
885 case TOKEN_INT_VEC3: return "ivec3";
886 case TOKEN_INT_VEC4: return "ivec4";
887 case TOKEN_UINT: return "uint";
888 case TOKEN_UINT_VEC2: return "uvec2";
889 case TOKEN_UINT_VEC3: return "uvec3";
890 case TOKEN_UINT_VEC4: return "uvec4";
891 case TOKEN_BOOL: return "bool";
892 case TOKEN_BOOL_VEC2: return "bvec2";
893 case TOKEN_BOOL_VEC3: return "bvec3";
894 case TOKEN_BOOL_VEC4: return "bvec4";
895 case TOKEN_IN: return "in";
896 case TOKEN_IMPORT: return "import";
897 case TOKEN_PIPELINE_PROGRAM: return "pipeline_program";
898 case TOKEN_ACTIVE_STAGES: return "active_stages";
900 case TOKEN_ASSIGN: return "=";
901 case TOKEN_PLUS: return "+";
902 case TOKEN_MINUS: return "-";
903 case TOKEN_COMMA: return ",";
904 case TOKEN_VERTICAL_BAR: return "|";
905 case TOKEN_SEMI_COLON: return ";";
906 case TOKEN_LEFT_PAREN: return "(";
907 case TOKEN_RIGHT_PAREN: return ")";
908 case TOKEN_LEFT_BRACKET: return "[";
909 case TOKEN_RIGHT_BRACKET: return "]";
910 case TOKEN_LEFT_BRACE: return "{";
911 case TOKEN_RIGHT_BRACE: return "}";
912 case TOKEN_GREATER: return ">";
914 default: return "<unknown>";
918 deUint32 ShaderParser::getShaderStageLiteralFlag (void)
922 case TOKEN_VERTEX: return (1 << glu::SHADERTYPE_VERTEX);
923 case TOKEN_FRAGMENT: return (1 << glu::SHADERTYPE_FRAGMENT);
924 case TOKEN_GEOMETRY: return (1 << glu::SHADERTYPE_GEOMETRY);
925 case TOKEN_TESSELLATION_CONTROL: return (1 << glu::SHADERTYPE_TESSELLATION_CONTROL);
926 case TOKEN_TESSELLATION_EVALUATION: return (1 << glu::SHADERTYPE_TESSELLATION_EVALUATION);
929 parseError(std::string() + "invalid shader stage name, got " + m_curTokenStr);
934 deUint32 ShaderParser::getGLEnumFromName (const std::string& enumName)
942 { "GL_MAX_VERTEX_IMAGE_UNIFORMS", GL_MAX_VERTEX_IMAGE_UNIFORMS },
943 { "GL_MAX_VERTEX_ATOMIC_COUNTERS", GL_MAX_VERTEX_ATOMIC_COUNTERS },
944 { "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS", GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS },
945 { "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS", GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS },
948 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(names); ++ndx)
949 if (names[ndx].name == enumName)
950 return names[ndx].value;
952 parseError(std::string() + "unknown enum name, got " + enumName);
956 void ShaderParser::parseValueElement (DataType expectedDataType, Value& result)
958 DataType scalarType = getDataTypeScalarType(expectedDataType);
959 int scalarSize = getDataTypeScalarSize(expectedDataType);
961 /* \todo [2010-04-19 petri] Support arrays. */
962 Value::Element elems[16];
966 DE_ASSERT(mapDataTypeToken(m_curToken) == expectedDataType);
967 advanceToken(); // data type (float, vec2, etc.)
968 advanceToken(TOKEN_LEFT_PAREN);
971 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
973 if (scalarType == TYPE_FLOAT)
975 float signMult = 1.0f;
976 if (m_curToken == TOKEN_MINUS)
982 assumeToken(TOKEN_FLOAT_LITERAL);
983 elems[scalarNdx].float32 = signMult * parseFloatLiteral(m_curTokenStr.c_str());
984 advanceToken(TOKEN_FLOAT_LITERAL);
986 else if (scalarType == TYPE_INT || scalarType == TYPE_UINT)
989 if (m_curToken == TOKEN_MINUS)
995 assumeToken(TOKEN_INT_LITERAL);
996 elems[scalarNdx].int32 = signMult * parseIntLiteral(m_curTokenStr.c_str());
997 advanceToken(TOKEN_INT_LITERAL);
1001 DE_ASSERT(scalarType == TYPE_BOOL);
1002 elems[scalarNdx].bool32 = (m_curToken == TOKEN_TRUE);
1003 if (m_curToken != TOKEN_TRUE && m_curToken != TOKEN_FALSE)
1004 parseError(string("unexpected token, expecting bool: " + m_curTokenStr));
1005 advanceToken(); // true/false
1008 if (scalarNdx != (scalarSize - 1))
1009 advanceToken(TOKEN_COMMA);
1013 advanceToken(TOKEN_RIGHT_PAREN);
1016 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1017 result.elements.push_back(elems[scalarNdx]);
1020 void ShaderParser::parseValue (ValueBlock& valueBlock)
1022 PARSE_DBG((" parseValue()\n"));
1025 vector<Value>* dstBlock = DE_NULL;
1026 DataType basicType = TYPE_LAST;
1027 std::string valueName;
1030 if (m_curToken == TOKEN_UNIFORM)
1031 dstBlock = &valueBlock.uniforms;
1032 else if (m_curToken == TOKEN_INPUT)
1033 dstBlock = &valueBlock.inputs;
1034 else if (m_curToken == TOKEN_OUTPUT)
1035 dstBlock = &valueBlock.outputs;
1037 parseError(string("unexpected token encountered when parsing value classifier"));
1041 basicType = mapDataTypeToken(m_curToken);
1042 if (basicType == TYPE_INVALID)
1043 parseError(string("unexpected token when parsing value data type: " + m_curTokenStr));
1046 // Parse value name.
1047 if (m_curToken == TOKEN_IDENTIFIER || m_curToken == TOKEN_STRING)
1049 if (m_curToken == TOKEN_IDENTIFIER)
1050 valueName = m_curTokenStr;
1052 valueName = parseStringLiteral(m_curTokenStr.c_str());
1055 parseError(string("unexpected token when parsing value name: " + m_curTokenStr));
1058 // Parse assignment operator.
1059 advanceToken(TOKEN_ASSIGN);
1063 value.name = valueName;
1064 value.type = VarType(basicType, PRECISION_LAST);
1065 dstBlock->push_back(value);
1068 // Parse actual value.
1069 if (m_curToken == TOKEN_LEFT_BRACKET) // value list
1071 int arrayLength = 0; // \todo [2015-08-03 pyry] Currently unused
1073 advanceToken(TOKEN_LEFT_BRACKET);
1077 parseValueElement(basicType, dstBlock->back());
1080 if (m_curToken == TOKEN_RIGHT_BRACKET)
1082 else if (m_curToken == TOKEN_VERTICAL_BAR)
1088 parseError(string("unexpected token in value element array: " + m_curTokenStr));
1091 advanceToken(TOKEN_RIGHT_BRACKET);
1093 else // single elements
1095 parseValueElement(basicType, dstBlock->back());
1098 advanceToken(TOKEN_SEMI_COLON); // end of declaration
1101 void ShaderParser::parseValueBlock (ValueBlock& valueBlock)
1103 PARSE_DBG((" parseValueBlock()\n"));
1104 advanceToken(TOKEN_VALUES);
1105 advanceToken(TOKEN_LEFT_BRACE);
1109 if (m_curToken == TOKEN_UNIFORM || m_curToken == TOKEN_INPUT || m_curToken == TOKEN_OUTPUT)
1110 parseValue(valueBlock);
1111 else if (m_curToken == TOKEN_RIGHT_BRACE)
1114 parseError(string("unexpected token when parsing a value block: " + m_curTokenStr));
1117 advanceToken(TOKEN_RIGHT_BRACE);
1120 deUint32 ShaderParser::parseShaderStageList (void)
1124 assumeToken(TOKEN_LEFT_BRACE);
1126 // don't allow 0-sized lists
1128 mask |= getShaderStageLiteralFlag();
1133 if (m_curToken == TOKEN_RIGHT_BRACE)
1135 else if (m_curToken == TOKEN_COMMA)
1140 stageFlag = getShaderStageLiteralFlag();
1141 if (stageFlag & mask)
1142 parseError(string("stage already set in the shader stage set: " + m_curTokenStr));
1148 parseError(string("invalid shader stage set token: " + m_curTokenStr));
1150 advanceToken(TOKEN_RIGHT_BRACE);
1155 void ShaderParser::parseRequirement (CaseRequirement& valueBlock)
1157 PARSE_DBG((" parseRequirement()\n"));
1160 assumeToken(TOKEN_IDENTIFIER);
1162 if (m_curTokenStr == "extension")
1164 std::vector<std::string> anyExtensionStringList;
1165 deUint32 affectedCasesFlags = -1; // by default all stages
1168 assumeToken(TOKEN_LEFT_BRACE);
1171 assumeToken(TOKEN_STRING);
1173 anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str()));
1178 if (m_curToken == TOKEN_RIGHT_BRACE)
1180 else if (m_curToken == TOKEN_VERTICAL_BAR)
1183 assumeToken(TOKEN_STRING);
1185 anyExtensionStringList.push_back(parseStringLiteral(m_curTokenStr.c_str()));
1189 parseError(string("invalid extension list token: " + m_curTokenStr));
1191 advanceToken(TOKEN_RIGHT_BRACE);
1193 if (m_curToken == TOKEN_IN)
1196 affectedCasesFlags = parseShaderStageList();
1199 valueBlock = CaseRequirement::createAnyExtensionRequirement(anyExtensionStringList, affectedCasesFlags);
1201 else if (m_curTokenStr == "limit")
1208 assumeToken(TOKEN_STRING);
1209 limitEnum = getGLEnumFromName(parseStringLiteral(m_curTokenStr.c_str()));
1212 assumeToken(TOKEN_GREATER);
1215 assumeToken(TOKEN_INT_LITERAL);
1216 limitValue = parseIntLiteral(m_curTokenStr.c_str());
1219 valueBlock = CaseRequirement::createLimitRequirement(limitEnum, limitValue);
1221 else if (m_curTokenStr == "full_glsl_es_100_support")
1225 valueBlock = CaseRequirement::createFullGLSLES100SpecificationRequirement();
1228 parseError(string("invalid requirement value: " + m_curTokenStr));
1231 void ShaderParser::parseExpectResult (ExpectResult& expectResult)
1233 assumeToken(TOKEN_IDENTIFIER);
1235 if (m_curTokenStr == "pass")
1236 expectResult = EXPECT_PASS;
1237 else if (m_curTokenStr == "compile_fail")
1238 expectResult = EXPECT_COMPILE_FAIL;
1239 else if (m_curTokenStr == "link_fail")
1240 expectResult = EXPECT_LINK_FAIL;
1241 else if (m_curTokenStr == "compile_or_link_fail")
1242 expectResult = EXPECT_COMPILE_LINK_FAIL;
1243 else if (m_curTokenStr == "validation_fail")
1244 expectResult = EXPECT_VALIDATION_FAIL;
1245 else if (m_curTokenStr == "build_successful")
1246 expectResult = EXPECT_BUILD_SUCCESSFUL;
1248 parseError(string("invalid expected result value: " + m_curTokenStr));
1253 void ShaderParser::parseFormat (DataType& format)
1255 format = mapDataTypeToken(m_curToken);
1259 void ShaderParser::parseGLSLVersion (glu::GLSLVersion& version)
1262 std::string postfix = "";
1264 assumeToken(TOKEN_INT_LITERAL);
1265 versionNum = parseIntLiteral(m_curTokenStr.c_str());
1268 if (m_curToken == TOKEN_IDENTIFIER)
1270 postfix = m_curTokenStr;
1274 DE_STATIC_ASSERT(glu::GLSL_VERSION_LAST == 15);
1276 if (versionNum == 100 && postfix == "es") version = glu::GLSL_VERSION_100_ES;
1277 else if (versionNum == 300 && postfix == "es") version = glu::GLSL_VERSION_300_ES;
1278 else if (versionNum == 310 && postfix == "es") version = glu::GLSL_VERSION_310_ES;
1279 else if (versionNum == 320 && postfix == "es") version = glu::GLSL_VERSION_320_ES;
1280 else if (versionNum == 130) version = glu::GLSL_VERSION_130;
1281 else if (versionNum == 140) version = glu::GLSL_VERSION_140;
1282 else if (versionNum == 150) version = glu::GLSL_VERSION_150;
1283 else if (versionNum == 330) version = glu::GLSL_VERSION_330;
1284 else if (versionNum == 400) version = glu::GLSL_VERSION_400;
1285 else if (versionNum == 410) version = glu::GLSL_VERSION_410;
1286 else if (versionNum == 420) version = glu::GLSL_VERSION_420;
1287 else if (versionNum == 430) version = glu::GLSL_VERSION_430;
1288 else if (versionNum == 440) version = glu::GLSL_VERSION_440;
1289 else if (versionNum == 450) version = glu::GLSL_VERSION_450;
1290 else if (versionNum == 460) version = glu::GLSL_VERSION_460;
1292 parseError("Unknown GLSL version");
1295 void ShaderParser::parsePipelineProgram (ProgramSpecification& program)
1297 advanceToken(TOKEN_PIPELINE_PROGRAM);
1301 if (m_curToken == TOKEN_END)
1303 else if (m_curToken == TOKEN_ACTIVE_STAGES)
1306 program.activeStages = parseShaderStageList();
1308 else if (m_curToken == TOKEN_REQUIRE)
1310 CaseRequirement requirement;
1311 parseRequirement(requirement);
1313 if (requirement.type == CaseRequirement::TYPE_EXTENSION)
1314 program.requiredExtensions.push_back(requirement.extension);
1316 parseError("only extension requirements are allowed inside pipeline program");
1318 else if (m_curToken == TOKEN_VERTEX ||
1319 m_curToken == TOKEN_FRAGMENT ||
1320 m_curToken == TOKEN_TESSELLATION_CONTROL ||
1321 m_curToken == TOKEN_TESSELLATION_EVALUATION ||
1322 m_curToken == TOKEN_GEOMETRY)
1324 const Token token = m_curToken;
1328 assumeToken(TOKEN_SHADER_SOURCE);
1329 source = parseShaderSource(m_curTokenStr.c_str());
1334 case TOKEN_VERTEX: program.sources.sources[SHADERTYPE_VERTEX].push_back(source); break;
1335 case TOKEN_FRAGMENT: program.sources.sources[SHADERTYPE_FRAGMENT].push_back(source); break;
1336 case TOKEN_TESSELLATION_CONTROL: program.sources.sources[SHADERTYPE_TESSELLATION_CONTROL].push_back(source); break;
1337 case TOKEN_TESSELLATION_EVALUATION: program.sources.sources[SHADERTYPE_TESSELLATION_EVALUATION].push_back(source); break;
1338 case TOKEN_GEOMETRY: program.sources.sources[SHADERTYPE_GEOMETRY].push_back(source); break;
1340 parseError(DE_FALSE);
1344 parseError(string("invalid pipeline program value: " + m_curTokenStr));
1346 advanceToken(TOKEN_END);
1348 if (program.activeStages == 0)
1349 parseError("program pipeline object must have active stages");
1352 void ShaderParser::parseShaderCase (vector<tcu::TestNode*>& shaderNodeList)
1355 PARSE_DBG((" parseShaderCase()\n"));
1356 advanceToken(TOKEN_CASE);
1359 string caseName = m_curTokenStr;
1360 advanceToken(); // \note [pyry] All token types are allowed here.
1362 // \todo [pyry] Optimize by parsing most stuff directly to ShaderCaseSpecification
1365 GLSLVersion version = DEFAULT_GLSL_VERSION;
1366 ExpectResult expectResult = EXPECT_PASS;
1367 OutputType outputType = OUTPUT_RESULT;
1368 DataType format = TYPE_LAST;
1371 vector<string> vertexSources;
1372 vector<string> fragmentSources;
1373 vector<string> tessellationCtrlSources;
1374 vector<string> tessellationEvalSources;
1375 vector<string> geometrySources;
1376 ValueBlock valueBlock;
1377 bool valueBlockSeen = false;
1378 vector<CaseRequirement> requirements;
1379 vector<ProgramSpecification> pipelinePrograms;
1383 if (m_curToken == TOKEN_END)
1385 else if (m_curToken == TOKEN_DESC)
1388 assumeToken(TOKEN_STRING);
1389 description = parseStringLiteral(m_curTokenStr.c_str());
1392 else if (m_curToken == TOKEN_EXPECT)
1395 parseExpectResult(expectResult);
1397 else if (m_curToken == TOKEN_OUTPUT_COLOR)
1399 outputType = OUTPUT_COLOR;
1401 parseFormat(format);
1403 else if (m_curToken == TOKEN_VALUES)
1406 parseError("multiple value blocks");
1407 parseValueBlock(valueBlock);
1408 valueBlockSeen = true;
1410 else if (m_curToken == TOKEN_BOTH ||
1411 m_curToken == TOKEN_VERTEX ||
1412 m_curToken == TOKEN_FRAGMENT ||
1413 m_curToken == TOKEN_TESSELLATION_CONTROL ||
1414 m_curToken == TOKEN_TESSELLATION_EVALUATION ||
1415 m_curToken == TOKEN_GEOMETRY)
1417 const Token token = m_curToken;
1421 assumeToken(TOKEN_SHADER_SOURCE);
1422 source = parseShaderSource(m_curTokenStr.c_str());
1427 case TOKEN_VERTEX: vertexSources.push_back(source); break;
1428 case TOKEN_FRAGMENT: fragmentSources.push_back(source); break;
1429 case TOKEN_TESSELLATION_CONTROL: tessellationCtrlSources.push_back(source); break;
1430 case TOKEN_TESSELLATION_EVALUATION: tessellationEvalSources.push_back(source); break;
1431 case TOKEN_GEOMETRY: geometrySources.push_back(source); break;
1434 if (!bothSource.empty())
1435 parseError("multiple 'both' blocks");
1436 bothSource = source;
1441 parseError(DE_FALSE);
1444 else if (m_curToken == TOKEN_VERSION)
1447 parseGLSLVersion(version);
1449 else if (m_curToken == TOKEN_REQUIRE)
1451 CaseRequirement requirement;
1452 parseRequirement(requirement);
1453 requirements.push_back(requirement);
1455 else if (m_curToken == TOKEN_PIPELINE_PROGRAM)
1457 ProgramSpecification pipelineProgram;
1458 parsePipelineProgram(pipelineProgram);
1459 pipelineProgram.sources.separable = true;
1460 pipelinePrograms.push_back(pipelineProgram);
1463 parseError(string("unexpected token while parsing shader case: " + m_curTokenStr));
1466 advanceToken(TOKEN_END); // case end
1468 // \todo [pyry] Clean up
1469 vector<RequiredCapability> requiredCaps;
1470 vector<RequiredExtension> requiredExts;
1471 bool fullGLSLES100Required = false;
1473 for (size_t reqNdx = 0; reqNdx < requirements.size(); ++reqNdx)
1475 const CaseRequirement& requirement = requirements[reqNdx];
1477 if (requirement.type == CaseRequirement::TYPE_EXTENSION)
1478 requiredExts.push_back(requirement.extension);
1479 else if (requirement.type == CaseRequirement::TYPE_IMPLEMENTATION_LIMIT)
1480 requiredCaps.push_back(requirement.requiredCap);
1481 else if (requirement.type == CaseRequirement::TYPE_FULL_GLSL_ES_100_SUPPORT)
1482 fullGLSLES100Required = true;
1487 if (!bothSource.empty())
1489 if (!vertexSources.empty() ||
1490 !fragmentSources.empty() ||
1491 !tessellationCtrlSources.empty() ||
1492 !tessellationEvalSources.empty() ||
1493 !geometrySources.empty() ||
1494 !pipelinePrograms.empty())
1496 parseError("'both' cannot be mixed with other shader stages");
1501 ShaderCaseSpecification spec;
1502 spec.caseType = CASETYPE_VERTEX_ONLY;
1503 spec.expectResult = expectResult;
1504 spec.targetVersion = version;
1505 spec.fullGLSLES100Required = fullGLSLES100Required;
1506 spec.requiredCaps = requiredCaps;
1507 spec.values = valueBlock;
1509 spec.programs.resize(1);
1510 spec.programs[0].sources << VertexSource(bothSource);
1511 spec.programs[0].requiredExtensions = requiredExts;
1513 shaderNodeList.push_back(m_caseFactory->createCase(caseName + "_vertex", description, ShaderCaseSpecification(spec)));
1518 ShaderCaseSpecification spec;
1519 spec.caseType = CASETYPE_FRAGMENT_ONLY;
1520 spec.expectResult = expectResult;
1521 spec.targetVersion = version;
1522 spec.fullGLSLES100Required = fullGLSLES100Required;
1523 spec.requiredCaps = requiredCaps;
1524 spec.values = valueBlock;
1526 spec.programs.resize(1);
1527 spec.programs[0].sources << FragmentSource(bothSource);
1528 spec.programs[0].requiredExtensions = requiredExts;
1530 shaderNodeList.push_back(m_caseFactory->createCase(caseName + "_fragment", description, ShaderCaseSpecification(spec)));
1533 else if (pipelinePrograms.empty())
1535 ShaderCaseSpecification spec;
1536 spec.caseType = CASETYPE_COMPLETE;
1537 spec.expectResult = expectResult;
1538 spec.outputType = outputType;
1539 spec.outputFormat = format;
1540 spec.targetVersion = version;
1541 spec.fullGLSLES100Required = fullGLSLES100Required;
1542 spec.requiredCaps = requiredCaps;
1543 spec.values = valueBlock;
1545 spec.programs.resize(1);
1546 spec.programs[0].sources.sources[SHADERTYPE_VERTEX].swap(vertexSources);
1547 spec.programs[0].sources.sources[SHADERTYPE_FRAGMENT].swap(fragmentSources);
1548 spec.programs[0].sources.sources[SHADERTYPE_TESSELLATION_CONTROL].swap(tessellationCtrlSources);
1549 spec.programs[0].sources.sources[SHADERTYPE_TESSELLATION_EVALUATION].swap(tessellationEvalSources);
1550 spec.programs[0].sources.sources[SHADERTYPE_GEOMETRY].swap(geometrySources);
1551 spec.programs[0].requiredExtensions.swap(requiredExts);
1553 shaderNodeList.push_back(m_caseFactory->createCase(caseName, description, ShaderCaseSpecification(spec)));
1557 if (!vertexSources.empty() ||
1558 !fragmentSources.empty() ||
1559 !tessellationCtrlSources.empty() ||
1560 !tessellationEvalSources.empty() ||
1561 !geometrySources.empty())
1563 parseError("pipeline programs cannot be mixed with complete programs");
1566 if (!requiredExts.empty())
1567 parseError("global extension requirements cannot be mixed with pipeline programs");
1569 // Pipeline case, multiple programs
1571 ShaderCaseSpecification spec;
1572 spec.caseType = CASETYPE_COMPLETE;
1573 spec.expectResult = expectResult;
1574 spec.targetVersion = version;
1575 spec.fullGLSLES100Required = fullGLSLES100Required;
1576 spec.requiredCaps = requiredCaps;
1577 spec.values = valueBlock;
1579 spec.programs.swap(pipelinePrograms);
1581 shaderNodeList.push_back(m_caseFactory->createCase(caseName, description, ShaderCaseSpecification(spec)));
1586 void ShaderParser::parseShaderGroup (vector<tcu::TestNode*>& shaderNodeList)
1589 PARSE_DBG((" parseShaderGroup()\n"));
1590 advanceToken(TOKEN_GROUP);
1593 string name = m_curTokenStr;
1594 advanceToken(); // \note [pyry] We don't want to check token type here (for instance to allow "uniform") group.
1596 // Parse description.
1597 assumeToken(TOKEN_STRING);
1598 string description = parseStringLiteral(m_curTokenStr.c_str());
1599 advanceToken(TOKEN_STRING);
1601 std::vector<tcu::TestNode*> children;
1603 // Parse group children.
1606 if (m_curToken == TOKEN_END)
1608 else if (m_curToken == TOKEN_GROUP)
1609 parseShaderGroup(children);
1610 else if (m_curToken == TOKEN_CASE)
1611 parseShaderCase(children);
1612 else if (m_curToken == TOKEN_IMPORT)
1613 parseImport(children);
1615 parseError(string("unexpected token while parsing shader group: " + m_curTokenStr));
1618 advanceToken(TOKEN_END); // group end
1620 // Create group node.
1621 tcu::TestCaseGroup* groupNode = m_caseFactory->createGroup(name, description, children);
1622 shaderNodeList.push_back(groupNode);
1625 void ShaderParser::parseImport (vector<tcu::TestNode*>& shaderNodeList)
1627 std::string importFileName;
1629 advanceToken(TOKEN_IMPORT);
1631 assumeToken(TOKEN_STRING);
1632 importFileName = parseStringLiteral(m_curTokenStr.c_str());
1633 advanceToken(TOKEN_STRING);
1636 ShaderParser subParser (m_archive, de::FilePath::join(de::FilePath(m_filename).getDirName(), importFileName).getPath(), m_caseFactory);
1637 const vector<tcu::TestNode*> importedCases = subParser.parse();
1639 // \todo [2015-08-03 pyry] Not exception safe
1640 shaderNodeList.insert(shaderNodeList.end(), importedCases.begin(), importedCases.end());
1644 vector<tcu::TestNode*> ShaderParser::parse (void)
1646 const int dataLen = m_resource->getSize();
1648 m_input.resize(dataLen+1);
1649 m_resource->setPosition(0);
1650 m_resource->read((deUint8*)&m_input[0], dataLen);
1651 m_input[dataLen] = '\0';
1653 // Initialize parser.
1654 m_curPtr = &m_input[0];
1655 m_curToken = TOKEN_INVALID;
1659 vector<tcu::TestNode*> nodeList;
1662 PARSE_DBG(("parse()\n"));
1665 if (m_curToken == TOKEN_CASE)
1666 parseShaderCase(nodeList);
1667 else if (m_curToken == TOKEN_GROUP)
1668 parseShaderGroup(nodeList);
1669 else if (m_curToken == TOKEN_IMPORT)
1670 parseImport(nodeList);
1671 else if (m_curToken == TOKEN_EOF)
1674 parseError(string("invalid token encountered at main level: '") + m_curTokenStr + "'");
1677 assumeToken(TOKEN_EOF);
1678 // printf(" parsed %d test cases.\n", caseList.size());
1682 std::vector<tcu::TestNode*> parseFile (const tcu::Archive& archive, const std::string& filename, ShaderCaseFactory* caseFactory)
1684 sl::ShaderParser parser (archive, filename, caseFactory);
1686 return parser.parse();
1689 // Execution utilities
1691 static void dumpValue (tcu::TestLog& log, const Value& val, const char* storageName, int arrayNdx)
1693 const char* const valueName = val.name.c_str();
1694 const DataType dataType = val.type.getBasicType();
1695 int scalarSize = getDataTypeScalarSize(dataType);
1696 ostringstream result;
1698 result << " " << storageName << " ";
1700 result << getDataTypeName(dataType) << " " << valueName << ":";
1702 if (isDataTypeScalar(dataType))
1704 if (isDataTypeVector(dataType))
1706 else if (isDataTypeMatrix(dataType))
1709 if (isDataTypeScalarOrVector(dataType))
1711 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1713 int elemNdx = arrayNdx;
1714 const Value::Element& e = val.elements[elemNdx*scalarSize + scalarNdx];
1715 result << ((scalarNdx != 0) ? ", " : "");
1717 if (isDataTypeFloatOrVec(dataType))
1718 result << e.float32;
1719 else if (isDataTypeIntOrIVec(dataType))
1721 else if (isDataTypeUintOrUVec(dataType))
1722 result << (deUint32)e.int32;
1723 else if (isDataTypeBoolOrBVec(dataType))
1724 result << (e.bool32 ? "true" : "false");
1727 else if (isDataTypeMatrix(dataType))
1729 int numRows = getDataTypeMatrixNumRows(dataType);
1730 int numCols = getDataTypeMatrixNumColumns(dataType);
1731 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1734 for (int colNdx = 0; colNdx < numCols; colNdx++)
1736 int elemNdx = arrayNdx;
1737 float v = val.elements[elemNdx*scalarSize + rowNdx*numCols + colNdx].float32;
1738 result << ((colNdx==0) ? "" : ", ") << v;
1744 if (isDataTypeScalar(dataType))
1746 else if (isDataTypeVector(dataType))
1749 log << TestLog::Message << result.str() << TestLog::EndMessage;
1752 static void dumpValues (tcu::TestLog& log, const vector<Value>& values, const char* storageName, int arrayNdx)
1754 for (size_t valNdx = 0; valNdx < values.size(); valNdx++)
1755 dumpValue(log, values[valNdx], storageName, arrayNdx);
1758 void dumpValues (tcu::TestLog& log, const ValueBlock& values, int arrayNdx)
1760 dumpValues(log, values.inputs, "input", arrayNdx);
1761 dumpValues(log, values.outputs, "expected", arrayNdx);
1762 dumpValues(log, values.uniforms, "uniform", arrayNdx);
1765 static void generateExtensionStatements (std::ostringstream& buf, const std::vector<RequiredExtension>& extensions, glu::ShaderType type)
1767 for (size_t ndx = 0; ndx < extensions.size(); ++ndx)
1769 DE_ASSERT(extensions[ndx].effectiveStages != 0u &&
1770 extensions[ndx].alternatives.size() == 1);
1772 if ((extensions[ndx].effectiveStages & (1u << (deUint32)type)) != 0)
1773 buf << "#extension " << extensions[ndx].alternatives[0] << " : require\n";
1777 // Injects #extension XXX : require lines after the last preprocessor directive in the shader code. Does not support line continuations
1778 std::string injectExtensionRequirements (const std::string& baseCode, const std::vector<RequiredExtension>& extensions, glu::ShaderType shaderType)
1780 std::istringstream baseCodeBuf (baseCode);
1781 std::ostringstream resultBuf;
1783 bool firstNonPreprocessorLine = true;
1784 std::ostringstream extStr;
1786 generateExtensionStatements(extStr, extensions, shaderType);
1788 // skip if no requirements
1789 if (extStr.str().empty())
1792 while (std::getline(baseCodeBuf, line))
1795 const std::string::size_type firstNonWhitespace = line.find_first_not_of("\t ");
1796 const bool isPreprocessorDirective = (firstNonWhitespace != std::string::npos && line.at(firstNonWhitespace) == '#');
1798 // Inject #extensions
1799 if (!isPreprocessorDirective && firstNonPreprocessorLine)
1801 firstNonPreprocessorLine = false;
1802 resultBuf << extStr.str();
1805 resultBuf << line << "\n";
1808 return resultBuf.str();
1811 void genCompareFunctions (ostringstream& stream, const ValueBlock& valueBlock, bool useFloatTypes)
1813 bool cmpTypeFound[TYPE_LAST];
1814 for (int i = 0; i < TYPE_LAST; i++)
1815 cmpTypeFound[i] = false;
1817 for (size_t valueNdx = 0; valueNdx < valueBlock.outputs.size(); valueNdx++)
1819 const Value& val = valueBlock.outputs[valueNdx];
1820 cmpTypeFound[(size_t)val.type.getBasicType()] = true;
1825 if (cmpTypeFound[TYPE_BOOL]) stream << "bool isOk (float a, bool b) { return ((a > 0.5) == b); }\n";
1826 if (cmpTypeFound[TYPE_BOOL_VEC2]) stream << "bool isOk (vec2 a, bvec2 b) { return (greaterThan(a, vec2(0.5)) == b); }\n";
1827 if (cmpTypeFound[TYPE_BOOL_VEC3]) stream << "bool isOk (vec3 a, bvec3 b) { return (greaterThan(a, vec3(0.5)) == b); }\n";
1828 if (cmpTypeFound[TYPE_BOOL_VEC4]) stream << "bool isOk (vec4 a, bvec4 b) { return (greaterThan(a, vec4(0.5)) == b); }\n";
1829 if (cmpTypeFound[TYPE_INT]) stream << "bool isOk (float a, int b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1)); }\n";
1830 if (cmpTypeFound[TYPE_INT_VEC2]) stream << "bool isOk (vec2 a, ivec2 b) { return (ivec2(floor(a + 0.5)) == b); }\n";
1831 if (cmpTypeFound[TYPE_INT_VEC3]) stream << "bool isOk (vec3 a, ivec3 b) { return (ivec3(floor(a + 0.5)) == b); }\n";
1832 if (cmpTypeFound[TYPE_INT_VEC4]) stream << "bool isOk (vec4 a, ivec4 b) { return (ivec4(floor(a + 0.5)) == b); }\n";
1833 if (cmpTypeFound[TYPE_UINT]) stream << "bool isOk (float a, uint b) { float atemp = a+0.5; return (float(b) <= atemp && atemp <= float(b+1u)); }\n";
1834 if (cmpTypeFound[TYPE_UINT_VEC2]) stream << "bool isOk (vec2 a, uvec2 b) { return (uvec2(floor(a + 0.5)) == b); }\n";
1835 if (cmpTypeFound[TYPE_UINT_VEC3]) stream << "bool isOk (vec3 a, uvec3 b) { return (uvec3(floor(a + 0.5)) == b); }\n";
1836 if (cmpTypeFound[TYPE_UINT_VEC4]) stream << "bool isOk (vec4 a, uvec4 b) { return (uvec4(floor(a + 0.5)) == b); }\n";
1840 if (cmpTypeFound[TYPE_BOOL]) stream << "bool isOk (bool a, bool b) { return (a == b); }\n";
1841 if (cmpTypeFound[TYPE_BOOL_VEC2]) stream << "bool isOk (bvec2 a, bvec2 b) { return (a == b); }\n";
1842 if (cmpTypeFound[TYPE_BOOL_VEC3]) stream << "bool isOk (bvec3 a, bvec3 b) { return (a == b); }\n";
1843 if (cmpTypeFound[TYPE_BOOL_VEC4]) stream << "bool isOk (bvec4 a, bvec4 b) { return (a == b); }\n";
1844 if (cmpTypeFound[TYPE_INT]) stream << "bool isOk (int a, int b) { return (a == b); }\n";
1845 if (cmpTypeFound[TYPE_INT_VEC2]) stream << "bool isOk (ivec2 a, ivec2 b) { return (a == b); }\n";
1846 if (cmpTypeFound[TYPE_INT_VEC3]) stream << "bool isOk (ivec3 a, ivec3 b) { return (a == b); }\n";
1847 if (cmpTypeFound[TYPE_INT_VEC4]) stream << "bool isOk (ivec4 a, ivec4 b) { return (a == b); }\n";
1848 if (cmpTypeFound[TYPE_UINT]) stream << "bool isOk (uint a, uint b) { return (a == b); }\n";
1849 if (cmpTypeFound[TYPE_UINT_VEC2]) stream << "bool isOk (uvec2 a, uvec2 b) { return (a == b); }\n";
1850 if (cmpTypeFound[TYPE_UINT_VEC3]) stream << "bool isOk (uvec3 a, uvec3 b) { return (a == b); }\n";
1851 if (cmpTypeFound[TYPE_UINT_VEC4]) stream << "bool isOk (uvec4 a, uvec4 b) { return (a == b); }\n";
1854 if (cmpTypeFound[TYPE_FLOAT]) stream << "bool isOk (float a, float b, float eps) { return (abs(a-b) <= (eps*abs(b) + eps)); }\n";
1855 if (cmpTypeFound[TYPE_FLOAT_VEC2]) stream << "bool isOk (vec2 a, vec2 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1856 if (cmpTypeFound[TYPE_FLOAT_VEC3]) stream << "bool isOk (vec3 a, vec3 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1857 if (cmpTypeFound[TYPE_FLOAT_VEC4]) stream << "bool isOk (vec4 a, vec4 b, float eps) { return all(lessThanEqual(abs(a-b), (eps*abs(b) + eps))); }\n";
1859 if (cmpTypeFound[TYPE_FLOAT_MAT2]) stream << "bool isOk (mat2 a, mat2 b, float eps) { vec2 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec2(eps))); }\n";
1860 if (cmpTypeFound[TYPE_FLOAT_MAT2X3]) stream << "bool isOk (mat2x3 a, mat2x3 b, float eps) { vec3 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec3(eps))); }\n";
1861 if (cmpTypeFound[TYPE_FLOAT_MAT2X4]) stream << "bool isOk (mat2x4 a, mat2x4 b, float eps) { vec4 diff = max(abs(a[0]-b[0]), abs(a[1]-b[1])); return all(lessThanEqual(diff, vec4(eps))); }\n";
1862 if (cmpTypeFound[TYPE_FLOAT_MAT3X2]) stream << "bool isOk (mat3x2 a, mat3x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec2(eps))); }\n";
1863 if (cmpTypeFound[TYPE_FLOAT_MAT3]) stream << "bool isOk (mat3 a, mat3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec3(eps))); }\n";
1864 if (cmpTypeFound[TYPE_FLOAT_MAT3X4]) stream << "bool isOk (mat3x4 a, mat3x4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), abs(a[2]-b[2])); return all(lessThanEqual(diff, vec4(eps))); }\n";
1865 if (cmpTypeFound[TYPE_FLOAT_MAT4X2]) stream << "bool isOk (mat4x2 a, mat4x2 b, float eps) { vec2 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec2(eps))); }\n";
1866 if (cmpTypeFound[TYPE_FLOAT_MAT4X3]) stream << "bool isOk (mat4x3 a, mat4x3 b, float eps) { vec3 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec3(eps))); }\n";
1867 if (cmpTypeFound[TYPE_FLOAT_MAT4]) stream << "bool isOk (mat4 a, mat4 b, float eps) { vec4 diff = max(max(abs(a[0]-b[0]), abs(a[1]-b[1])), max(abs(a[2]-b[2]), abs(a[3]-b[3]))); return all(lessThanEqual(diff, vec4(eps))); }\n";