diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 576607dadcefe511d95419a224bc6b75a2b47814..b73e538463ca2f8086fee25856dfd4f528b1c41d 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -158,6 +158,8 @@ protected: void declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember); bool isShaderEntryPoint(const glslang::TIntermAggregate* node); + bool writableParam(glslang::TStorageQualifier); + bool originalParam(glslang::TStorageQualifier, const glslang::TType&, bool implicitThisParam); void makeFunctions(const glslang::TIntermSequence&); void makeGlobalInitializers(const glslang::TIntermSequence&); void visitFunctions(const glslang::TIntermSequence&); @@ -2969,6 +2971,24 @@ bool TGlslangToSpvTraverser::isShaderEntryPoint(const glslang::TIntermAggregate* return node->getName().compare(glslangIntermediate->getEntryPointMangledName().c_str()) == 0; } +// Does parameter need a place to keep writes, separate from the original? +bool TGlslangToSpvTraverser::writableParam(glslang::TStorageQualifier qualifier) +{ + return qualifier != glslang::EvqConstReadOnly; +} + +// Is parameter pass-by-original? +bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, const glslang::TType& paramType, + bool implicitThisParam) +{ + if (implicitThisParam) // implicit this + return true; + if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) + return false; + return paramType.containsOpaque() || // sampler, etc. + (paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO +} + // Make all the functions, skeletally, without actually visiting their bodies. void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions) { @@ -3005,23 +3025,13 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() == glslangIntermediate->implicitThisName; - const auto canPassOriginal = [&](const glslang::TType& paramType, bool firstParam) -> bool { - if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) - return firstParam && implicitThis; - else - return paramType.containsOpaque() || // sampler, etc. - (paramType.getBasicType() == glslang::EbtBlock && - paramType.getQualifier().storage == glslang::EvqBuffer) || // SSBO - (firstParam && implicitThis); // implicit 'this' - }; - paramDecorations.resize(parameters.size()); for (int p = 0; p < (int)parameters.size(); ++p) { const glslang::TType& paramType = parameters[p]->getAsTyped()->getType(); spv::Id typeId = convertGlslangToSpvType(paramType); - if (canPassOriginal(paramType, p == 0)) + if (originalParam(paramType.getQualifier().storage, paramType, implicitThis && p == 0)) typeId = builder.makePointer(TranslateStorageClass(paramType), typeId); - else if (paramType.getQualifier().storage != glslang::EvqConstReadOnly) + else if (writableParam(paramType.getQualifier().storage)) typeId = builder.makePointer(spv::StorageClassFunction, typeId); else rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId()); @@ -3581,13 +3591,6 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg const glslang::TIntermSequence& glslangArgs = node->getSequence(); const glslang::TQualifierList& qualifiers = node->getQualifierList(); - // Encapsulate lvalue logic, used in multiple places below, for safety. - const auto isLValue = [&](int qualifier, const glslang::TType& paramType) -> bool { - if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) - return qualifier != glslang::EvqConstReadOnly; - return qualifier != glslang::EvqConstReadOnly || paramType.containsOpaque(); - }; - // See comments in makeFunctions() for details about the semantics for parameter passing. // // These imply we need a four step process: @@ -3606,8 +3609,9 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg builder.clearAccessChain(); glslangArgs[a]->traverse(this); argTypes.push_back(¶mType); - // keep outputs and opaque objects as l-values, evaluate input-only as r-values - if (isLValue(qualifiers[a], paramType)) { + // keep outputs and pass-by-originals as l-values, evaluate others as r-values + if (writableParam(qualifiers[a]) || + originalParam(qualifiers[a], paramType, function->hasImplicitThis() && a == 0)) { // save l-value lValues.push_back(builder.getAccessChain()); } else { @@ -3626,14 +3630,11 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg for (int a = 0; a < (int)glslangArgs.size(); ++a) { const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType(); spv::Id arg; - if ((a == 0 && function->hasImplicitThis()) || - (glslangIntermediate->getSource() != glslang::EShSourceHlsl && - (paramType.containsOpaque() || - (paramType.getBasicType() == glslang::EbtBlock && qualifiers[a] == glslang::EvqBuffer)))) { + if (originalParam(qualifiers[a], paramType, function->hasImplicitThis() && a == 0)) { builder.setAccessChain(lValues[lValueCount]); arg = builder.accessChainGetLValue(); ++lValueCount; - } else if (isLValue(qualifiers[a], paramType)) { + } else if (writableParam(qualifiers[a])) { // need space to hold the copy arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param"); if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) { @@ -3660,7 +3661,9 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg lValueCount = 0; for (int a = 0; a < (int)glslangArgs.size(); ++a) { const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType(); - if (isLValue(qualifiers[a], paramType)) { + if (originalParam(qualifiers[a], paramType, function->hasImplicitThis() && a == 0)) + ++lValueCount; + else if (writableParam(qualifiers[a])) { if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) { spv::Id copy = builder.createLoad(spvArgs[a]); builder.setAccessChain(lValues[lValueCount]); diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h index 97e3e47803ef8afe531ab4375268910dc72e0f20..4a2b53047d8ea452eafcb47b8801123a67418acf 100644 --- a/glslang/Include/intermediate.h +++ b/glslang/Include/intermediate.h @@ -1286,7 +1286,7 @@ protected: }; typedef TVector<TIntermNode*> TIntermSequence; -typedef TVector<int> TQualifierList; +typedef TVector<TStorageQualifier> TQualifierList; // // Nodes that operate on an arbitrary sized set of children. //