diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 0fc57305..26d2f4bc 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -118,6 +118,9 @@ protected: spv::ImageFormat TranslateImageFormat(const glslang::TType& type); spv::Id createSpvVariable(const glslang::TIntermSymbol*); spv::Id getSampledType(const glslang::TSampler&); + spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&); + spv::Id createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped&, spv::Id parentResult); + void convertSwizzle(const glslang::TIntermAggregate&, std::vector& swizzle); spv::Id convertGlslangToSpvType(const glslang::TType& type); spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&); spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct, @@ -1025,10 +1028,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T case glslang::EOpVectorSwizzle: { node->getLeft()->traverse(this); - glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence(); std::vector swizzle; - for (int i = 0; i < (int)swizzleSequence.size(); ++i) - swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst()); + convertSwizzle(*node->getRight()->getAsAggregate(), swizzle); builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType())); } return false; @@ -1118,8 +1119,18 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI // Start by evaluating the operand + // Does it need a swizzle inversion? If so, evaluation is inverted; + // operate first on the swizzle base, then apply the swizzle. + spv::Id invertedType = spv::NoType; + auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); }; + if (node->getOp() == glslang::EOpInterpolateAtCentroid) + invertedType = getInvertedSwizzleType(*node->getOperand()); + builder.clearAccessChain(); - node->getOperand()->traverse(this); + if (invertedType != spv::NoType) + node->getOperand()->getAsBinaryNode()->getLeft()->traverse(this); + else + node->getOperand()->traverse(this); spv::Id operand = spv::NoResult; @@ -1136,13 +1147,16 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI // it could be a conversion if (! result) - result = createConversion(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); + result = createConversion(node->getOp(), precision, noContraction, resultType(), operand, node->getOperand()->getBasicType()); // if not, then possibly an operation if (! result) - result = createUnaryOperation(node->getOp(), precision, noContraction, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType()); + result = createUnaryOperation(node->getOp(), precision, noContraction, resultType(), operand, node->getOperand()->getBasicType()); if (result) { + if (invertedType) + result = createInvertedSwizzle(precision, *node->getOperand(), result); + builder.clearAccessChain(); builder.setAccessChainRValue(result); @@ -1210,6 +1224,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); spv::Id result = spv::NoResult; + spv::Id invertedType = spv::NoType; // to use to override the natural type of the node + auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); }; // try texturing result = createImageTextureFunctionCall(node); @@ -1366,19 +1382,18 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt { std::vector arguments; translateArguments(*node, arguments); - spv::Id resultTypeId = convertGlslangToSpvType(node->getType()); spv::Id constructed; if (node->getOp() == glslang::EOpConstructTextureSampler) - constructed = builder.createOp(spv::OpSampledImage, resultTypeId, arguments); + constructed = builder.createOp(spv::OpSampledImage, resultType(), arguments); else if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) { std::vector constituents; for (int c = 0; c < (int)arguments.size(); ++c) constituents.push_back(arguments[c]); - constructed = builder.createCompositeConstruct(resultTypeId, constituents); + constructed = builder.createCompositeConstruct(resultType(), constituents); } else if (isMatrix) - constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId); + constructed = builder.createMatrixConstructor(precision, arguments, resultType()); else - constructed = builder.createConstructor(precision, arguments, resultTypeId); + constructed = builder.createConstructor(precision, arguments, resultType()); builder.clearAccessChain(); builder.setAccessChainRValue(constructed); @@ -1407,7 +1422,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; } case glslang::EOpMul: - // compontent-wise matrix multiply + // component-wise matrix multiply binOp = glslang::EOpMul; break; case glslang::EOpOuterProduct: @@ -1476,7 +1491,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt spv::Id rightId = accessChainLoad(right->getType()); result = createBinaryOperation(binOp, precision, TranslateNoContractionDecoration(node->getType().getQualifier()), - convertGlslangToSpvType(node->getType()), leftId, rightId, + resultType(), leftId, rightId, left->getType().getBasicType(), reduceComparison); // code above should only make binOp that exists in createBinaryOperation @@ -1493,9 +1508,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt glslang::TIntermSequence& glslangOperands = node->getSequence(); std::vector operands; for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) { - builder.clearAccessChain(); - glslangOperands[arg]->traverse(this); - // special case l-value operands; there are just a few bool lvalue = false; switch (node->getOp()) { @@ -1509,8 +1521,15 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt #ifdef AMD_EXTENSIONS case glslang::EOpInterpolateAtVertex: #endif - if (arg == 0) + if (arg == 0) { lvalue = true; + + // Does it need a swizzle inversion? If so, evaluation is inverted; + // operate first on the swizzle base, then apply the swizzle. + if (glslangOperands[0]->getAsOperator() && + glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle) + invertedType = convertGlslangToSpvType(glslangOperands[0]->getAsBinaryNode()->getLeft()->getType()); + } break; case glslang::EOpAtomicAdd: case glslang::EOpAtomicMin: @@ -1536,6 +1555,11 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt default: break; } + builder.clearAccessChain(); + if (invertedType != spv::NoType && arg == 0) + glslangOperands[0]->getAsBinaryNode()->getLeft()->traverse(this); + else + glslangOperands[arg]->traverse(this); if (lvalue) operands.push_back(builder.accessChainGetLValue()); else @@ -1544,24 +1568,26 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt if (atomic) { // Handle all atomics - result = createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); + result = createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType()); } else { // Pass through to generic operations. switch (glslangOperands.size()) { case 0: - result = createNoArgOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType())); + result = createNoArgOperation(node->getOp(), precision, resultType()); break; case 1: result = createUnaryOperation( node->getOp(), precision, TranslateNoContractionDecoration(node->getType().getQualifier()), - convertGlslangToSpvType(node->getType()), operands.front(), + resultType(), operands.front(), glslangOperands[0]->getAsTyped()->getBasicType()); break; default: - result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); + result = createMiscOperation(node->getOp(), precision, resultType(), operands, node->getBasicType()); break; } + if (invertedType) + result = createInvertedSwizzle(precision, *glslangOperands[0]->getAsBinaryNode(), result); } if (noReturnValue) @@ -1813,6 +1839,36 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) } } +// If node is a swizzle operation, return the type that should be used if +// the swizzle base is first consumed by another operation, before the swizzle +// is applied. +spv::Id TGlslangToSpvTraverser::getInvertedSwizzleType(const glslang::TIntermTyped& node) +{ + if (node.getAsOperator() && + node.getAsOperator()->getOp() == glslang::EOpVectorSwizzle) + return convertGlslangToSpvType(node.getAsBinaryNode()->getLeft()->getType()); + else + return spv::NoType; +} + +// When inverting a swizzle with a parent op, this function +// will apply the swizzle operation to a completed parent operation. +spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node, spv::Id parentResult) +{ + std::vector swizzle; + convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle); + return builder.createRvalueSwizzle(precision, convertGlslangToSpvType(node.getType()), parentResult, swizzle); +} + + +// Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V. +void TGlslangToSpvTraverser::convertSwizzle(const glslang::TIntermAggregate& node, std::vector& swizzle) +{ + const glslang::TIntermSequence& swizzleSequence = node.getSequence(); + for (int i = 0; i < (int)swizzleSequence.size(); ++i) + swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst()); +} + // Convert from a glslang type to an SPV type, by calling into a // recursive version of this function. This establishes the inherited // layout state rooted from the top-level type. @@ -2505,6 +2561,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO if (! node->isImage() && ! node->isTexture()) { return spv::NoResult; } + auto resultType = [&node,this]{ return convertGlslangToSpvType(node->getType()); }; // Process a GLSL texturing op (will be SPV image) const glslang::TSampler sampler = node->getAsAggregate() ? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler() @@ -2571,7 +2628,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO operands.push_back(spv::ImageOperandsSampleMask); operands.push_back(*(opIt++)); } - return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands); + return builder.createOp(spv::OpImageRead, resultType(), operands); } operands.push_back(*(opIt++)); @@ -2582,7 +2639,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO } if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown) builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat); - return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands); + return builder.createOp(spv::OpImageRead, resultType(), operands); } else if (node->getOp() == glslang::EOpImageStore) { if (sampler.ms) { operands.push_back(*(opIt + 1)); @@ -2606,7 +2663,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO // Create the return type that was a special structure spv::Id texelOut = *opIt; - spv::Id typeId0 = convertGlslangToSpvType(node->getType()); + spv::Id typeId0 = resultType(); spv::Id typeId1 = builder.getDerefTypeId(texelOut); spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1); @@ -2622,7 +2679,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO // as the first source operand, is required by SPIR-V atomic operations. operands.push_back(sampler.ms ? *(opIt++) : builder.makeUintConstant(0)); // For non-MS, the value should be 0 - spv::Id resultTypeId = builder.makePointer(spv::StorageClassImage, convertGlslangToSpvType(node->getType())); + spv::Id resultTypeId = builder.makePointer(spv::StorageClassImage, resultType()); spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands); std::vector operands; @@ -2630,7 +2687,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO for (; opIt != arguments.end(); ++opIt) operands.push_back(*opIt); - return createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType()); + return createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType()); } } @@ -2770,7 +2827,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO } } - return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params); + return builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params); } spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node) diff --git a/Test/baseResults/spv.swizzleInversion.frag.out b/Test/baseResults/spv.swizzleInversion.frag.out new file mode 100755 index 00000000..6b922065 --- /dev/null +++ b/Test/baseResults/spv.swizzleInversion.frag.out @@ -0,0 +1,81 @@ +spv.swizzleInversion.frag +Warning, version 450 is not yet complete; most version-specific features are present, but some are missing. + + +Linked fragment stage: + + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 46 + + Capability Shader + Capability InterpolationFunction + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 12 37 + ExecutionMode 4 OriginUpperLeft + Source GLSL 450 + Name 4 "main" + Name 9 "v43" + Name 12 "in4" + Name 17 "v42" + Name 23 "v44" + Name 29 "v41" + Name 35 "v33" + Name 37 "in3" + Name 40 "v32" + Name 43 "v31" + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 3 + 8: TypePointer Function 7(fvec3) + 10: TypeVector 6(float) 4 + 11: TypePointer Input 10(fvec4) + 12(in4): 11(ptr) Variable Input + 15: TypeVector 6(float) 2 + 16: TypePointer Function 15(fvec2) + 18: TypeInt 32 1 + 19: 18(int) Constant 1 + 22: TypePointer Function 10(fvec4) + 24: 6(float) Constant 1073741824 + 25: 15(fvec2) ConstantComposite 24 24 + 28: TypePointer Function 6(float) + 30: TypeInt 32 0 + 31: 30(int) Constant 1 + 32: TypePointer Input 6(float) + 36: TypePointer Input 7(fvec3) + 37(in3): 36(ptr) Variable Input + 4(main): 2 Function None 3 + 5: Label + 9(v43): 8(ptr) Variable Function + 17(v42): 16(ptr) Variable Function + 23(v44): 22(ptr) Variable Function + 29(v41): 28(ptr) Variable Function + 35(v33): 8(ptr) Variable Function + 40(v32): 16(ptr) Variable Function + 43(v31): 28(ptr) Variable Function + 13: 10(fvec4) ExtInst 1(GLSL.std.450) 76(InterpolateAtCentroid) 12(in4) + 14: 7(fvec3) VectorShuffle 13 13 3 2 0 + Store 9(v43) 14 + 20: 10(fvec4) ExtInst 1(GLSL.std.450) 77(InterpolateAtSample) 12(in4) 19 + 21: 15(fvec2) VectorShuffle 20 20 2 0 + Store 17(v42) 21 + 26: 10(fvec4) ExtInst 1(GLSL.std.450) 78(InterpolateAtOffset) 12(in4) 25 + 27: 10(fvec4) VectorShuffle 26 26 2 1 0 3 + Store 23(v44) 27 + 33: 32(ptr) AccessChain 12(in4) 31 + 34: 6(float) ExtInst 1(GLSL.std.450) 78(InterpolateAtOffset) 33 25 + Store 29(v41) 34 + 38: 7(fvec3) ExtInst 1(GLSL.std.450) 76(InterpolateAtCentroid) 37(in3) + 39: 7(fvec3) VectorShuffle 38 38 1 2 0 + Store 35(v33) 39 + 41: 7(fvec3) ExtInst 1(GLSL.std.450) 77(InterpolateAtSample) 37(in3) 19 + 42: 15(fvec2) VectorShuffle 41 41 2 0 + Store 40(v32) 42 + 44: 32(ptr) AccessChain 12(in4) 31 + 45: 6(float) ExtInst 1(GLSL.std.450) 78(InterpolateAtOffset) 44 25 + Store 43(v31) 45 + Return + FunctionEnd diff --git a/Test/spv.swizzleInversion.frag b/Test/spv.swizzleInversion.frag new file mode 100644 index 00000000..9dca62f8 --- /dev/null +++ b/Test/spv.swizzleInversion.frag @@ -0,0 +1,16 @@ +#version 450 + +in vec4 in4; +in vec3 in3; + +void main() +{ + vec3 v43 = interpolateAtCentroid(in4.wzx); + vec2 v42 = interpolateAtSample(in4.zx, 1); + vec4 v44 = interpolateAtOffset(in4.zyxw, vec2(2.0)); + float v41 = interpolateAtOffset(in4.y, vec2(2.0)); + + vec3 v33 = interpolateAtCentroid(in3.yzx); + vec2 v32 = interpolateAtSample(in3.zx, 1); + float v31 = interpolateAtOffset(in4.y, vec2(2.0)); +} diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index c328407f..5ab3596b 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 "SPIRV99.1339" -#define GLSLANG_DATE "25-Jul-2016" +#define GLSLANG_REVISION "SPIRV99.1340" +#define GLSLANG_DATE "26-Jul-2016" diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp index dbe0507d..a8f3dd86 100644 --- a/gtests/Spv.FromFile.cpp +++ b/gtests/Spv.FromFile.cpp @@ -184,6 +184,7 @@ INSTANTIATE_TEST_CASE_P( "spv.structure.frag", "spv.switch.frag", "spv.swizzle.frag", + "spv.swizzleInversion.frag", "spv.test.frag", "spv.test.vert", "spv.texture.frag",