From: John Kessenich Date: Wed, 19 Aug 2015 05:17:15 +0000 (-0600) Subject: Front-end "pure" built-in TOperator: Finish adding full support, but still turned... X-Git-Tag: upstream/0.1~407 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ef676b0a59a13bdd51a5d0e2beae2a2ca06c6a15;p=platform%2Fupstream%2Fglslang.git Front-end "pure" built-in TOperator: Finish adding full support, but still turned off. This is to avoid all need to do text comparison of built-in function names when consuming the AST. All built-in functions get enumerants. Will want to turn on soon. See PureOperatorBuiltins. See issue #8. --- diff --git a/Test/300.frag b/Test/300.frag index ff2da1f..97f3101 100644 --- a/Test/300.frag +++ b/Test/300.frag @@ -59,7 +59,7 @@ void main() v = textureLod(s2DArray, c3D, 1.2); f = textureOffset(s2DShadow, c3D, ic2D, c1D); // ERROR, offset argument not constant v = texelFetch(s3D, ic3D, ic1D); - v = texelFetchOffset(arrayedSampler[2], ic2D, 4, ic2D); + v = texelFetchOffset(arrayedSampler[2], ic2D, 4, ic2D); // ERROR, offset argument not constant f = textureLodOffset(s2DShadow, c3D, c1D, ic2D); v = textureProjLodOffset(s2D, c3D, c1D, ic2D); v = textureGrad(sCube, c3D, c3D, c3D); diff --git a/Test/baseResults/newTexture.frag.out b/Test/baseResults/newTexture.frag.out index 8690143..625dd80 100644 --- a/Test/baseResults/newTexture.frag.out +++ b/Test/baseResults/newTexture.frag.out @@ -49,7 +49,9 @@ Shader version: 430 0:43 'ic2D' (flat in 2-component vector of int) 0:43 Constant: 0:43 4 (const int) -0:43 'ic2D' (flat in 2-component vector of int) +0:43 Constant: +0:43 3 (const int) +0:43 3 (const int) 0:44 add second child into first child (temp float) 0:44 direct index (temp float) 0:44 'v' (temp 4-component vector of float) @@ -301,7 +303,9 @@ Shader version: 430 0:43 'ic2D' (flat in 2-component vector of int) 0:43 Constant: 0:43 4 (const int) -0:43 'ic2D' (flat in 2-component vector of int) +0:43 Constant: +0:43 3 (const int) +0:43 3 (const int) 0:44 add second child into first child (temp float) 0:44 direct index (temp float) 0:44 'v' (temp 4-component vector of float) diff --git a/Test/newTexture.frag b/Test/newTexture.frag index 9d01209..138536d 100644 --- a/Test/newTexture.frag +++ b/Test/newTexture.frag @@ -40,7 +40,7 @@ void main() v += textureLod(s2DArray, c3D, 1.2); v.y += textureOffset(s2DShadow, c3D, ivec2(3), c1D); v += texelFetch(s3D, ic3D, ic1D); - v += texelFetchOffset(s2D, ic2D, 4, ic2D); + v += texelFetchOffset(s2D, ic2D, 4, ivec2(3)); v.y += textureLodOffset(s2DShadow, c3D, c1D, ivec2(3)); v += textureProjLodOffset(s2D, c3D, c1D, ivec2(3)); v += textureGrad(sCube, c3D, c3D, c3D); diff --git a/Test/spv.newTexture.frag b/Test/spv.newTexture.frag index 5e3fb43..edb0423 100644 --- a/Test/spv.newTexture.frag +++ b/Test/spv.newTexture.frag @@ -38,7 +38,7 @@ void main() v += textureLod(s2DArray, c3D, 1.2); v.y += textureOffset(s2DShadow, c3D, ivec2(3), c1D); v += texelFetch(s3D, ic3D, ic1D); - v += texelFetchOffset(s2D, ic2D, 4, ic2D); + v += texelFetchOffset(s2D, ic2D, 4, ivec2(3)); v.y += textureLodOffset(s2DShadow, c3D, c1D, ivec2(3)); v += textureProjLodOffset(s2D, c3D, c1D, ivec2(3)); v += textureGrad(sCube, c3D, c3D, c3D); diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index 627fb92..9078485 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -2,5 +2,5 @@ // For the version, it uses the latest git tag followed by the number of commits. // For the date, it uses the current date (when then script is run). -#define GLSLANG_REVISION "2.3.723" +#define GLSLANG_REVISION "2.3.725" #define GLSLANG_DATE "18-Aug-2015" diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp index 450884b..9dbefb2 100644 --- a/glslang/MachineIndependent/Initialize.cpp +++ b/glslang/MachineIndependent/Initialize.cpp @@ -59,7 +59,7 @@ bool ARBCompatibility = true; const bool ForwardCompatibility = false; // change this back to false if depending on textual spellings of texturing calls when consuming the AST -const bool PureOperatorBuiltins = false; +bool PureOperatorBuiltins = false; inline bool IncludeLegacy(int version, EProfile profile) { @@ -3097,7 +3097,7 @@ void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymb // // Next, identify which built-ins have a mapping to an operator. - // Those that are not identified as such are + // If PureOperatorBuiltins is false, those that are not identified as such are // expected to be resolved through a library of functions, versus as // operations. // @@ -3267,30 +3267,59 @@ void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymb symbolTable.relateToOperator("textureGatherOffset", EOpTextureGatherOffset); symbolTable.relateToOperator("textureGatherOffsets", EOpTextureGatherOffsets); - if (IncludeLegacy(version, profile)) { - // TBD: add ftransform(), any others? - symbolTable.relateToOperator("texture1D", EOpTexture); - symbolTable.relateToOperator("texture1DProj", EOpTextureProj); - symbolTable.relateToOperator("texture1DLod", EOpTextureLod); - symbolTable.relateToOperator("texture1DProjLod", EOpTextureProjLod); - symbolTable.relateToOperator("texture2D", EOpTexture); - symbolTable.relateToOperator("texture2DProj", EOpTextureProj); - symbolTable.relateToOperator("texture2DLod", EOpTextureLod); - symbolTable.relateToOperator("texture2DProjLod", EOpTextureProjLod); - symbolTable.relateToOperator("texture3D", EOpTexture); - symbolTable.relateToOperator("texture3DProj", EOpTextureProj); - symbolTable.relateToOperator("texture3DLod", EOpTextureLod); - symbolTable.relateToOperator("texture3DProjLod", EOpTextureProjLod); - symbolTable.relateToOperator("textureCube", EOpTexture); - symbolTable.relateToOperator("textureCubeLod", EOpTextureLod); - symbolTable.relateToOperator("shadow1D", EOpTexture); - symbolTable.relateToOperator("shadow2D", EOpTexture); - symbolTable.relateToOperator("shadow1DProj", EOpTextureProj); - symbolTable.relateToOperator("shadow2DProj", EOpTextureProj); - symbolTable.relateToOperator("shadow1DLod", EOpTextureLod); - symbolTable.relateToOperator("shadow2DLod", EOpTextureLod); - symbolTable.relateToOperator("shadow1DProjLod", EOpTextureProjLod); - symbolTable.relateToOperator("shadow2DProjLod", EOpTextureProjLod); + if (IncludeLegacy(version, profile) || (profile == EEsProfile && version == 100)) { + symbolTable.relateToOperator("ftransform", EOpFtransform); + + symbolTable.relateToOperator("texture1D", EOpTexture); + symbolTable.relateToOperator("texture1DGradARB", EOpTextureGrad); + symbolTable.relateToOperator("texture1DProj", EOpTextureProj); + symbolTable.relateToOperator("texture1DProjGradARB", EOpTextureProjGrad); + symbolTable.relateToOperator("texture1DLod", EOpTextureLod); + symbolTable.relateToOperator("texture1DProjLod", EOpTextureProjLod); + + symbolTable.relateToOperator("texture2DRect", EOpTexture); + symbolTable.relateToOperator("texture2DRectProj", EOpTextureProj); + symbolTable.relateToOperator("texture2DRectGradARB", EOpTextureGrad); + symbolTable.relateToOperator("texture2DRectProjGradARB", EOpTextureProjGrad); + symbolTable.relateToOperator("shadow2DRect", EOpTexture); + symbolTable.relateToOperator("shadow2DRectProj", EOpTextureProj); + symbolTable.relateToOperator("shadow2DRectGradARB", EOpTextureGrad); + symbolTable.relateToOperator("shadow2DRectProjGradARB", EOpTextureProjGrad); + + symbolTable.relateToOperator("texture2D", EOpTexture); + symbolTable.relateToOperator("texture2DProj", EOpTextureProj); + symbolTable.relateToOperator("texture2DGradEXT", EOpTextureGrad); + symbolTable.relateToOperator("texture2DGradARB", EOpTextureGrad); + symbolTable.relateToOperator("texture2DProjGradEXT", EOpTextureProjGrad); + symbolTable.relateToOperator("texture2DProjGradARB", EOpTextureProjGrad); + symbolTable.relateToOperator("texture2DLod", EOpTextureLod); + symbolTable.relateToOperator("texture2DLodEXT", EOpTextureLod); + symbolTable.relateToOperator("texture2DProjLod", EOpTextureProjLod); + symbolTable.relateToOperator("texture2DProjLodEXT", EOpTextureProjLod); + + symbolTable.relateToOperator("texture3D", EOpTexture); + symbolTable.relateToOperator("texture3DGradARB", EOpTextureGrad); + symbolTable.relateToOperator("texture3DProj", EOpTextureProj); + symbolTable.relateToOperator("texture3DProjGradARB", EOpTextureProjGrad); + symbolTable.relateToOperator("texture3DLod", EOpTextureLod); + symbolTable.relateToOperator("texture3DProjLod", EOpTextureProjLod); + symbolTable.relateToOperator("textureCube", EOpTexture); + symbolTable.relateToOperator("textureCubeGradEXT", EOpTextureGrad); + symbolTable.relateToOperator("textureCubeGradARB", EOpTextureGrad); + symbolTable.relateToOperator("textureCubeLod", EOpTextureLod); + symbolTable.relateToOperator("textureCubeLodEXT", EOpTextureLod); + symbolTable.relateToOperator("shadow1D", EOpTexture); + symbolTable.relateToOperator("shadow1DGradARB", EOpTextureGrad); + symbolTable.relateToOperator("shadow2D", EOpTexture); + symbolTable.relateToOperator("shadow2DGradARB", EOpTextureGrad); + symbolTable.relateToOperator("shadow1DProj", EOpTextureProj); + symbolTable.relateToOperator("shadow2DProj", EOpTextureProj); + symbolTable.relateToOperator("shadow1DProjGradARB", EOpTextureProjGrad); + symbolTable.relateToOperator("shadow2DProjGradARB", EOpTextureProjGrad); + symbolTable.relateToOperator("shadow1DLod", EOpTextureLod); + symbolTable.relateToOperator("shadow2DLod", EOpTextureLod); + symbolTable.relateToOperator("shadow1DProjLod", EOpTextureProjLod); + symbolTable.relateToOperator("shadow2DProjLod", EOpTextureProjLod); } } diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index 297a2fb..c31396d 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -1107,11 +1107,14 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction result = intermediate.addBuiltInFunctionCall(loc, op, fnCandidate->getParamCount() == 1, arguments, fnCandidate->getType()); if (result == nullptr) { error(arguments->getLoc(), " wrong operand type", "Internal Error", - "built in unary operator function. Type: %s", - static_cast(arguments)->getCompleteString().c_str()); + "built in unary operator function. Type: %s", + static_cast(arguments)->getCompleteString().c_str()); + } else if (result->getAsOperator()) { + builtInOpCheck(loc, *fnCandidate, *result->getAsOperator()); } } else { - // This is a function call not mapped to built-in operator, but it could still be a built-in function + // This is a function call not mapped to built-in operator. + // It could still be a built-in function, but only if PureOperatorBuiltins == false. result = intermediate.setAggregateOperator(arguments, EOpFunctionCall, fnCandidate->getType(), loc); TIntermAggregate* call = result->getAsAggregate(); call->setName(fnCandidate->getMangledName()); @@ -1325,6 +1328,173 @@ TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& funct } // +// Do additional checking of built-in function calls that is not caught +// by normal semantic checks on argument type, extension tagging, etc. +// +// Assumes there has been a semantically correct match to a built-in function prototype. +// +void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermOperator& callNode) +{ + // Set up convenience accessors to the argument(s). There is almost always + // multiple arguments for the cases below, but when there might be one, + // check the unaryArg first. + const TIntermSequence* argp = nullptr; // confusing to use [] syntax on a pointer, so this is to help get a reference + const TIntermTyped* unaryArg = nullptr; + const TIntermTyped* arg0 = nullptr; + if (callNode.getAsAggregate()) { + argp = &callNode.getAsAggregate()->getSequence(); + if (argp->size() > 0) + arg0 = (*argp)[0]->getAsTyped(); + } else { + assert(callNode.getAsUnaryNode()); + unaryArg = callNode.getAsUnaryNode()->getOperand(); + arg0 = unaryArg; + } + const TIntermSequence& aggArgs = *argp; // only valid when unaryArg is nullptr + + // built-in texturing functions get their return value precision from the precision of the sampler + if (fnCandidate.getType().getQualifier().precision == EpqNone && + fnCandidate.getParamCount() > 0 && fnCandidate[0].type->getBasicType() == EbtSampler) + callNode.getQualifier().precision = arg0->getQualifier().precision; + + switch (callNode.getOp()) { + case EOpTextureGather: + case EOpTextureGatherOffset: + case EOpTextureGatherOffsets: + { + // Figure out which variants are allowed by what extensions, + // and what arguments must be constant for which situations. + + TString featureString = fnCandidate.getName() + "(...)"; + const char* feature = featureString.c_str(); + profileRequires(loc, EEsProfile, 310, nullptr, feature); + int compArg = -1; // track which argument, if any, is the constant component argument + switch (callNode.getOp()) { + case EOpTextureGather: + // More than two arguments needs gpu_shader5, and rectangular or shadow needs gpu_shader5, + // otherwise, need GL_ARB_texture_gather. + if (fnCandidate.getParamCount() > 2 || fnCandidate[0].type->getSampler().dim == EsdRect || fnCandidate[0].type->getSampler().shadow) { + profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature); + if (! fnCandidate[0].type->getSampler().shadow) + compArg = 2; + } else + profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature); + break; + case EOpTextureGatherOffset: + // GL_ARB_texture_gather is good enough for 2D non-shadow textures with no component argument + if (fnCandidate[0].type->getSampler().dim == Esd2D && ! fnCandidate[0].type->getSampler().shadow && fnCandidate.getParamCount() == 3) + profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_texture_gather, feature); + else + profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature); + if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion()) + profileRequires(loc, EEsProfile, 0, Num_AEP_gpu_shader5, AEP_gpu_shader5, "non-constant offset argument"); + if (! fnCandidate[0].type->getSampler().shadow) + compArg = 3; + break; + case EOpTextureGatherOffsets: + profileRequires(loc, ~EEsProfile, 400, E_GL_ARB_gpu_shader5, feature); + if (! fnCandidate[0].type->getSampler().shadow) + compArg = 3; + // check for constant offsets + if (! aggArgs[fnCandidate[0].type->getSampler().shadow ? 3 : 2]->getAsConstantUnion()) + error(loc, "must be a compile-time constant:", feature, "offsets argument"); + break; + default: + break; + } + + if (compArg > 0 && compArg < fnCandidate.getParamCount()) { + if (aggArgs[compArg]->getAsConstantUnion()) { + int value = aggArgs[compArg]->getAsConstantUnion()->getConstArray()[0].getIConst(); + if (value < 0 || value > 3) + error(loc, "must be 0, 1, 2, or 3:", feature, "component argument"); + } else + error(loc, "must be a compile-time constant:", feature, "component argument"); + } + + break; + } + + case EOpTextureOffset: + case EOpTextureFetchOffset: + case EOpTextureProjOffset: + case EOpTextureLodOffset: + case EOpTextureProjLodOffset: + case EOpTextureGradOffset: + case EOpTextureProjGradOffset: + { + // Handle texture-offset limits checking + // Pick which argument has to hold constant offsets + int arg = -1; + switch (callNode.getOp()) { + case EOpTextureOffset: arg = 2; break; + case EOpTextureFetchOffset: arg = 3; break; + case EOpTextureProjOffset: arg = 2; break; + case EOpTextureLodOffset: arg = 3; break; + case EOpTextureProjLodOffset: arg = 3; break; + case EOpTextureGradOffset: arg = 4; break; + case EOpTextureProjGradOffset: arg = 4; break; + default: + assert(0); + break; + } + + if (arg > 0) { + if (! aggArgs[arg]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "texel offset", ""); + else { + const TType& type = aggArgs[arg]->getAsTyped()->getType(); + for (int c = 0; c < type.getVectorSize(); ++c) { + int offset = aggArgs[arg]->getAsConstantUnion()->getConstArray()[c].getIConst(); + if (offset > resources.maxProgramTexelOffset || offset < resources.minProgramTexelOffset) + error(loc, "value is out of range:", "texel offset", "[gl_MinProgramTexelOffset, gl_MaxProgramTexelOffset]"); + } + } + } + + break; + } + + case EOpTextureQuerySamples: + case EOpImageQuerySamples: + // GL_ARB_shader_texture_image_samples + profileRequires(loc, ~EEsProfile, 450, E_GL_ARB_shader_texture_image_samples, "textureSamples and imageSamples"); + break; + + case EOpImageAtomicAdd: + case EOpImageAtomicMin: + case EOpImageAtomicMax: + case EOpImageAtomicAnd: + case EOpImageAtomicOr: + case EOpImageAtomicXor: + case EOpImageAtomicExchange: + case EOpImageAtomicCompSwap: + { + // Make sure the image types have the correct layout() format and correct argument types + const TType& imageType = arg0->getType(); + if (imageType.getSampler().type == EbtInt || imageType.getSampler().type == EbtUint) { + if (imageType.getQualifier().layoutFormat != ElfR32i && imageType.getQualifier().layoutFormat != ElfR32ui) + error(loc, "only supported on image with format r32i or r32ui", fnCandidate.getName().c_str(), ""); + } else { + if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") != 0) + error(loc, "only supported on integer images", fnCandidate.getName().c_str(), ""); + else if (imageType.getQualifier().layoutFormat != ElfR32f && profile == EEsProfile) + error(loc, "only supported on image with format r32f", fnCandidate.getName().c_str(), ""); + } + + break; + } + + default: + break; + } +} + +extern bool PureOperatorBuiltins; + +// Deprecated! Use PureOperatorBuiltins == true instead, in which case this +// functionality is handled in builtInOpCheck() instead of here. +// // Do additional checking of built-in function calls that were not mapped // to built-in operations (e.g., texturing functions). // @@ -1332,10 +1502,18 @@ TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& funct // void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fnCandidate, TIntermAggregate& callNode) { + // Further maintainance of this function is deprecated, because the "correct" + // future-oriented design is to not have to do string compares on function names. + + // If PureOperatorBuiltins == true, then all built-ins should be mapped + // to a TOperator, and this function would then never get called. + + assert(PureOperatorBuiltins == false); + // built-in texturing functions get their return value precision from the precision of the sampler if (fnCandidate.getType().getQualifier().precision == EpqNone && fnCandidate.getParamCount() > 0 && fnCandidate[0].type->getBasicType() == EbtSampler) - callNode.getQualifier().precision = callNode.getAsAggregate()->getSequence()[0]->getAsTyped()->getQualifier().precision; + callNode.getQualifier().precision = callNode.getSequence()[0]->getAsTyped()->getQualifier().precision; if (fnCandidate.getName().compare(0, 7, "texture") == 0) { if (fnCandidate.getName().compare(0, 13, "textureGather") == 0) { diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 81c9eac..17a5b3f 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -119,6 +119,7 @@ public: TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*); void addInputArgumentConversions(const TFunction&, TIntermNode*&) const; TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const; + void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&); void nonOpBuiltInCheck(const TSourceLoc&, const TFunction&, TIntermAggregate&); TFunction* handleConstructorCall(const TSourceLoc&, const TPublicType&);