diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index bd04bea6301d9ceea31f55a075df07207868ccaf..6cc2a7350cf76cff36c4e7afd06777d2e21bd53b 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -126,7 +126,16 @@ const char* DefaultConfig = "MaxVertexOutputVectors 16\n" "MaxFragmentInputVectors 15\n" "MinProgramTexelOffset -8\n" -"MaxProgramTexelOffset 7\n" +"MaxProgramTexelOffset 7\n" +"nonInductiveForLoops 1\n" +"whileLoops 1\n" +"doWhileLoops 1\n" +"generalUniformIndexing 1\n" +"generalAttributeMatrixVectorIndexing 1\n" +"generalVaryingIndexing 1\n" +"generalSamplerIndexing 1\n" +"generalVariableIndexing 1\n" +"generalConstantMatrixVectorIndexing 1\n" ; // @@ -199,6 +208,24 @@ void ProcessConfigFile() Resources.minProgramTexelOffset = value; else if (strcmp(token, "MaxProgramTexelOffset") == 0) Resources.maxProgramTexelOffset = value; + else if (strcmp(token, "nonInductiveForLoops") == 0) + Resources.limits.nonInductiveForLoops = (value != 0); + else if (strcmp(token, "whileLoops") == 0) + Resources.limits.whileLoops = (value != 0); + else if (strcmp(token, "doWhileLoops") == 0) + Resources.limits.doWhileLoops = (value != 0); + else if (strcmp(token, "generalUniformIndexing") == 0) + Resources.limits.generalUniformIndexing = (value != 0); + else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0) + Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0); + else if (strcmp(token, "generalVaryingIndexing") == 0) + Resources.limits.generalVaryingIndexing = (value != 0); + else if (strcmp(token, "generalSamplerIndexing") == 0) + Resources.limits.generalSamplerIndexing = (value != 0); + else if (strcmp(token, "generalVariableIndexing") == 0) + Resources.limits.generalVariableIndexing = (value != 0); + else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0) + Resources.limits.generalConstantMatrixVectorIndexing = (value != 0); else printf("Warning: unrecognized limit (%s) in configuration file.\n", token); diff --git a/Test/100.conf b/Test/100.conf new file mode 100644 index 0000000000000000000000000000000000000000..29b9b63d75ab9b3a38022ebe762edf044a5f9cce --- /dev/null +++ b/Test/100.conf @@ -0,0 +1,28 @@ +MaxLights 32 +MaxClipPlanes 6 +MaxTextureUnits 32 +MaxTextureCoords 32 +MaxVertexAttribs 8 +MaxVertexUniformComponents 4096 +MaxVaryingFloats 64 +MaxVertexTextureImageUnits 0 +MaxCombinedTextureImageUnits 8 +MaxTextureImageUnits 8 +MaxFragmentUniformComponents 4096 +MaxDrawBuffers 1 +MaxVertexUniformVectors 16 +MaxVaryingVectors 8 +MaxFragmentUniformVectors 16 +MaxVertexOutputVectors 16 +MaxFragmentInputVectors 15 +MinProgramTexelOffset -8 +MaxProgramTexelOffset 7 +nonInductiveForLoops 0 +whileLoops 0 +doWhileLoops 0 +generalUniformIndexing 0 +generalAttributeMatrixVectorIndexing 0 +generalVaryingIndexing 0 +generalSamplerIndexing 0 +generalVariableIndexing 0 +generalConstantMatrixVectorIndexing 0 diff --git a/Test/100Limits.vert b/Test/100Limits.vert new file mode 100644 index 0000000000000000000000000000000000000000..7ed1ef820749e2f5185215a440b9f37fbb2f2ec4 --- /dev/null +++ b/Test/100Limits.vert @@ -0,0 +1,53 @@ +#version 100 + +int ga, gb; +float f; + +uniform sampler2D fsa[3]; +uniform float fua[10]; +attribute mat3 am3; +attribute vec2 av2; +varying vec4 va[4]; + +const mat2 m2 = mat2(1.0); +const vec3 v3 = vec3(2.0); + +void foo(inout float a) {} + +void main() +{ + while (ga < gb) { } + + do { } while (false); + + for ( ga = 0; ; ); + for ( bool a = false; ; ); + for (float a = 0.0; a == sin(f); ); + for ( int a = 0; a < 10; a *= 2); + for ( int a = 0; a <= 20; ++a) --a; + for (float a = 0.0; a <= 20.0; a += 2.0); + for (float a = 0.0; a <= 20.0; a += 2.0) foo(a); + + int ia[9]; + + fsa[ga]; + fua[ga]; + am3[ga]; + av2[ga]; + va[ga]; + m2[ga]; + v3[ga]; + ia[ga]; + + for ( int a = 3; a >= 0; --a) { + fsa[a]; + fua[a+2]; + am3[3*a]; + av2[3*a]; + va[a-1]; + m2[a/2]; + v3[a]; + ia[a]; + } + +} diff --git a/Test/baseResults/100Limits.vert.out b/Test/baseResults/100Limits.vert.out new file mode 100644 index 0000000000000000000000000000000000000000..fe68fd592570ee321c8c8e110122e91120fba9fa --- /dev/null +++ b/Test/baseResults/100Limits.vert.out @@ -0,0 +1,235 @@ +0:? Sequence +0:15 Function Definition: foo(f1; (void) +0:15 Function Parameters: +0:15 'a' (inout highp float) +0:17 Function Definition: main( (void) +0:17 Function Parameters: +0:19 Sequence +0:19 Loop with condition tested first +0:19 Loop Condition +0:19 Compare Less Than (bool) +0:19 'ga' (highp int) +0:19 'gb' (highp int) +0:19 No loop body +0:21 Loop with condition not tested first +0:21 Loop Condition +0:21 Constant: +0:21 false (const bool) +0:21 No loop body +0:23 Sequence +0:23 move second child to first child (highp int) +0:23 'ga' (highp int) +0:23 Constant: +0:23 0 (const int) +0:23 Loop with condition tested first +0:23 No loop condition +0:23 No loop body +0:24 Sequence +0:24 Sequence +0:24 move second child to first child (bool) +0:24 'a' (bool) +0:24 Constant: +0:24 false (const bool) +0:24 Loop with condition tested first +0:24 No loop condition +0:24 No loop body +0:25 Sequence +0:25 Sequence +0:25 move second child to first child (highp float) +0:25 'a' (highp float) +0:25 Constant: +0:25 0.000000 +0:25 Loop with condition tested first +0:25 Loop Condition +0:25 Compare Equal (bool) +0:25 'a' (highp float) +0:25 sine (highp float) +0:25 'f' (highp float) +0:25 No loop body +0:26 Sequence +0:26 Sequence +0:26 move second child to first child (highp int) +0:26 'a' (highp int) +0:26 Constant: +0:26 0 (const int) +0:26 Loop with condition tested first +0:26 Loop Condition +0:26 Compare Less Than (bool) +0:26 'a' (highp int) +0:26 Constant: +0:26 10 (const int) +0:26 No loop body +0:26 Loop Terminal Expression +0:26 multiply second child into first child (highp int) +0:26 'a' (highp int) +0:26 Constant: +0:26 2 (const int) +0:27 Sequence +0:27 Sequence +0:27 move second child to first child (highp int) +0:27 'a' (highp int) +0:27 Constant: +0:27 0 (const int) +0:27 Loop with condition tested first +0:27 Loop Condition +0:27 Compare Less Than or Equal (bool) +0:27 'a' (highp int) +0:27 Constant: +0:27 20 (const int) +0:27 Loop Body +0:27 Pre-Decrement (highp int) +0:27 'a' (highp int) +0:27 Loop Terminal Expression +0:27 Pre-Increment (highp int) +0:27 'a' (highp int) +0:28 Sequence +0:28 Sequence +0:28 move second child to first child (highp float) +0:28 'a' (highp float) +0:28 Constant: +0:28 0.000000 +0:28 Loop with condition tested first +0:28 Loop Condition +0:28 Compare Less Than or Equal (bool) +0:28 'a' (highp float) +0:28 Constant: +0:28 20.000000 +0:28 No loop body +0:28 Loop Terminal Expression +0:28 add second child into first child (highp float) +0:28 'a' (highp float) +0:28 Constant: +0:28 2.000000 +0:29 Sequence +0:29 Sequence +0:29 move second child to first child (highp float) +0:29 'a' (highp float) +0:29 Constant: +0:29 0.000000 +0:29 Loop with condition tested first +0:29 Loop Condition +0:29 Compare Less Than or Equal (bool) +0:29 'a' (highp float) +0:29 Constant: +0:29 20.000000 +0:29 Loop Body +0:29 Function Call: foo(f1; (void) +0:29 'a' (highp float) +0:29 Loop Terminal Expression +0:29 add second child into first child (highp float) +0:29 'a' (highp float) +0:29 Constant: +0:29 2.000000 +0:33 indirect index (uniform lowp sampler2D) +0:33 'fsa' (uniform 3-element array of lowp sampler2D) +0:33 'ga' (highp int) +0:34 indirect index (uniform highp float) +0:34 'fua' (uniform 10-element array of highp float) +0:34 'ga' (highp int) +0:35 indirect index (in highp 3-component vector of float) +0:35 'am3' (in highp 3X3 matrix of float) +0:35 'ga' (highp int) +0:36 indirect index (in highp float) +0:36 'av2' (in highp 2-component vector of float) +0:36 'ga' (highp int) +0:37 indirect index (smooth out highp 4-component vector of float) +0:37 'va' (smooth out 4-element array of highp 4-component vector of float) +0:37 'ga' (highp int) +0:38 indirect index (const highp 2-component vector of float) +0:38 Constant: +0:38 1.000000 +0:38 0.000000 +0:38 0.000000 +0:38 1.000000 +0:38 'ga' (highp int) +0:39 indirect index (const highp float) +0:39 Constant: +0:39 2.000000 +0:39 2.000000 +0:39 2.000000 +0:39 'ga' (highp int) +0:40 indirect index (highp int) +0:40 'ia' (9-element array of highp int) +0:40 'ga' (highp int) +0:42 Sequence +0:42 Sequence +0:42 move second child to first child (highp int) +0:42 'a' (highp int) +0:42 Constant: +0:42 3 (const int) +0:42 Loop with condition tested first +0:42 Loop Condition +0:42 Compare Greater Than or Equal (bool) +0:42 'a' (highp int) +0:42 Constant: +0:42 0 (const int) +0:42 Loop Body +0:43 Sequence +0:43 indirect index (uniform lowp sampler2D) +0:43 'fsa' (uniform 3-element array of lowp sampler2D) +0:43 'a' (highp int) +0:44 indirect index (uniform highp float) +0:44 'fua' (uniform 10-element array of highp float) +0:44 add (highp int) +0:44 'a' (highp int) +0:44 Constant: +0:44 2 (const int) +0:45 indirect index (in highp 3-component vector of float) +0:45 'am3' (in highp 3X3 matrix of float) +0:45 component-wise multiply (highp int) +0:45 Constant: +0:45 3 (const int) +0:45 'a' (highp int) +0:46 indirect index (in highp float) +0:46 'av2' (in highp 2-component vector of float) +0:46 component-wise multiply (highp int) +0:46 Constant: +0:46 3 (const int) +0:46 'a' (highp int) +0:47 indirect index (smooth out highp 4-component vector of float) +0:47 'va' (smooth out 4-element array of highp 4-component vector of float) +0:47 subtract (highp int) +0:47 'a' (highp int) +0:47 Constant: +0:47 1 (const int) +0:48 indirect index (const highp 2-component vector of float) +0:48 Constant: +0:48 1.000000 +0:48 0.000000 +0:48 0.000000 +0:48 1.000000 +0:48 divide (highp int) +0:48 'a' (highp int) +0:48 Constant: +0:48 2 (const int) +0:49 indirect index (const highp float) +0:49 Constant: +0:49 2.000000 +0:49 2.000000 +0:49 2.000000 +0:49 'a' (highp int) +0:50 indirect index (highp int) +0:50 'ia' (9-element array of highp int) +0:50 'a' (highp int) +0:42 Loop Terminal Expression +0:42 Pre-Decrement (highp int) +0:42 'a' (highp int) +0:? Linker Objects +0:? 'ga' (highp int) +0:? 'gb' (highp int) +0:? 'f' (highp float) +0:? 'fsa' (uniform 3-element array of lowp sampler2D) +0:? 'fua' (uniform 10-element array of highp float) +0:? 'am3' (in highp 3X3 matrix of float) +0:? 'av2' (in highp 2-component vector of float) +0:? 'va' (smooth out 4-element array of highp 4-component vector of float) +0:? 'm2' (const highp 2X2 matrix of float) +0:? 1.000000 +0:? 0.000000 +0:? 0.000000 +0:? 1.000000 +0:? 'v3' (const highp 3-component vector of float) +0:? 2.000000 +0:? 2.000000 +0:? 2.000000 + diff --git a/Test/baseResults/100LimitsConf.vert.out b/Test/baseResults/100LimitsConf.vert.out new file mode 100644 index 0000000000000000000000000000000000000000..0d51c812db93013975cf0cefdd8ef93b09f73024 --- /dev/null +++ b/Test/baseResults/100LimitsConf.vert.out @@ -0,0 +1,5 @@ +ERROR: 0:19: 'limitation' : while loops not available +ERROR: 0:21: 'limitation' : do-while loops not available +ERROR: 2 compilation errors. No code generated. + + diff --git a/Test/baseResults/test.conf b/Test/baseResults/test.conf index 2f04420ee2f538e4e6e2241e73dc2045bf9b85bf..80fafc98ea31c3f2d38705f588e63738e3eb362e 100644 --- a/Test/baseResults/test.conf +++ b/Test/baseResults/test.conf @@ -17,3 +17,12 @@ MaxVertexOutputVectors 16 MaxFragmentInputVectors 15 MinProgramTexelOffset -8 MaxProgramTexelOffset 7 +nonInductiveForLoops 1 +whileLoops 1 +doWhileLoops 1 +generalUniformIndexing 1 +generalAttributeMatrixVectorIndexing 1 +generalVaryingIndexing 1 +generalSamplerIndexing 1 +generalVariableIndexing 1 +generalConstantMatrixVectorIndexing 1 diff --git a/Test/runtests b/Test/runtests index ba1c7ee3ec6907ba94afc4cd758827761eb6ed4e..b9e9f71426fb442d6ff40c9763211c2791de8300 100644 --- a/Test/runtests +++ b/Test/runtests @@ -5,13 +5,15 @@ BASEDIR=baseResults EXE=./glslangValidator.exe # -# configuration file test +# configuration file tests # echo running configuration file test $EXE -c > $TARGETDIR/test.conf diff -b $BASEDIR/test.conf $TARGETDIR/test.conf $EXE -i $TARGETDIR/test.conf specExamples.vert > $TARGETDIR/specExamples.vert.out diff -b $BASEDIR/specExamples.vert.out $TARGETDIR +$EXE 100Limits.vert 100.conf > $TARGETDIR/100LimitsConf.vert.out +diff -b $BASEDIR/100LimitsConf.vert.out $TARGETDIR/100LimitsConf.vert.out # # isolated compilation tests diff --git a/Test/testlist b/Test/testlist index 0789f1b5b805fc90a59da4125d242b66da138ced..31cfa7584560766e3c7d7871c03879963463efe5 100644 --- a/Test/testlist +++ b/Test/testlist @@ -39,6 +39,7 @@ forwardRef.frag uint.frag switch.frag tokenLength.vert +100Limits.vert 100scope.vert 300scope.vert 400.frag diff --git a/Todo.txt b/Todo.txt index 0f9eb5a7381ea08e9df4c72196c7dd5f6d1594e0..a5da56765a8d5c95075441bdfd783576f3773980 100644 --- a/Todo.txt +++ b/Todo.txt @@ -1,5 +1,7 @@ Current functionality level: ESSL 3.0 +- extension adding process + Link Validation + provide input config file for setting limits - also consider spitting out measures of complexity @@ -25,6 +27,7 @@ Link Validation + Non ES: value checking of uniform initializers + Non ES: location match - location aliasing/overlap (except desktop vertex shader inputs) + - 1.0: count the number of uniforms and varyings, compare against limits + recursion for functions - Non ES: block matching - Non ES: component/binding/index/offset match check @@ -43,11 +46,14 @@ Link Validation - 4.4: component aliasing (except desktop vertex shader inputs) Shader Functionality to Implement/Finish + ESSL 2.0 (#version 100) + - implement non-inductive loop limitation detection + - implement non-inductive array accesses limitation detection ESSL 3.0 - "const" compile-time constant propagation in the front-end has to be complete, for all built-in functions GLSL 1.2 - - Handle multiple compilation units per stage - - Allow initializers on uniform declarations + + Handle multiple compilation units per stage + + Allow initializers on uniform declarations - signature matching takes type conversions into account, ambiguity is an error GLSL 1.3 . flat is for both user and predeclared built-in in/out variables diff --git a/glslang/Include/ResourceLimits.h b/glslang/Include/ResourceLimits.h index 70ff2a1df2535308e32dc226b53516af853f88cb..5c7fb0937425e69ffc813f12248170411ea9361f 100644 --- a/glslang/Include/ResourceLimits.h +++ b/glslang/Include/ResourceLimits.h @@ -37,6 +37,18 @@ #ifndef _RESOURCE_LIMITS_INCLUDED_ #define _RESOURCE_LIMITS_INCLUDED_ +struct TLimits { + bool nonInductiveForLoops; + bool whileLoops; + bool doWhileLoops; + bool generalUniformIndexing; + bool generalAttributeMatrixVectorIndexing; + bool generalVaryingIndexing; + bool generalSamplerIndexing; + bool generalVariableIndexing; + bool generalConstantMatrixVectorIndexing; +}; + struct TBuiltInResource { int maxLights; int maxClipPlanes; @@ -57,6 +69,7 @@ struct TBuiltInResource { int maxFragmentInputVectors; int minProgramTexelOffset; int maxProgramTexelOffset; + TLimits limits; }; #endif // _RESOURCE_LIMITS_INCLUDED_ diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 36b3c9d86fade2a55b00b1f1b69bb4a953fc20a2..14ab9e794b752dbc9c3496186e028a3df755f6e5 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -539,9 +539,11 @@ TIntermTyped* TParseContext::handleBracketDereference(TSourceLoc loc, TIntermTyp error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable"); if (base->getBasicType() == EbtBlock) requireProfile(base->getLoc(), static_cast<EProfileMask>(~EEsProfileMask), "variable indexing block array"); - if (base->getBasicType() == EbtSampler) { - requireProfile(base->getLoc(), static_cast<EProfileMask>(ECoreProfileMask | ECompatibilityProfileMask), "variable indexing sampler array"); - profileRequires(base->getLoc(), ECoreProfile, 400, 0, "variable indexing sampler array"); + if (base->getBasicType() == EbtSampler && version >= 130) { + const char* explanation = "variable indexing sampler array"; + requireProfile(base->getLoc(), static_cast<EProfileMask>(ECoreProfileMask | ECompatibilityProfileMask), explanation); + profileRequires(base->getLoc(), ECoreProfile, 400, 0, explanation); + profileRequires(base->getLoc(), ECompatibilityProfile, 400, 0, explanation); } result = intermediate.addIndex(EOpIndexIndirect, base, index, loc); diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 2226f25bb74d48270f7c8c02c2d9f997e0c036f2..669bd8230291fef2e2657af5fc1077ee72ac6880 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -201,6 +201,7 @@ public: TPrecisionQualifier defaultPrecision[EbtNumTypes]; TSourceLoc currentLoc; bool tokensBeforeEOF; + TLimits limits; protected: TScanContext* scanContext; diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index 4a75e1a32eec7cdbc1ad59d60a01ba0ff24e7e5f..c99fe3b2fc95d78f026b92475519fe87e9528597 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -451,6 +451,7 @@ bool CompileDeferred( TPpContext ppContext(parseContext); parseContext.setScanContext(&scanContext); parseContext.setPpContext(&ppContext); + parseContext.limits = resources->limits; if (! goodVersion) parseContext.addError(); diff --git a/glslang/MachineIndependent/glslang.y b/glslang/MachineIndependent/glslang.y index 3443ded29778641cebe3def1317b66e9b444849e..c99e255878310ea4073c6780b7b4f593fd258d3b 100644 --- a/glslang/MachineIndependent/glslang.y +++ b/glslang/MachineIndependent/glslang.y @@ -2226,6 +2226,8 @@ case_label iteration_statement : WHILE LEFT_PAREN { + if (! parseContext.limits.whileLoops) + parseContext.error($1.loc, "while loops not available", "limitation", ""); parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; } @@ -2235,6 +2237,9 @@ iteration_statement --parseContext.loopNestingLevel; } | DO { ++parseContext.loopNestingLevel; } statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { + if (! parseContext.limits.whileLoops) + parseContext.error($1.loc, "do-while loops not available", "limitation", ""); + parseContext.boolCheck($8.loc, $6); $$ = parseContext.intermediate.addLoop($3, $6, 0, false, $4.loc);