diff options
Diffstat (limited to 'thirdparty/glslang/SPIRV/GlslangToSpv.cpp')
-rw-r--r-- | thirdparty/glslang/SPIRV/GlslangToSpv.cpp | 548 |
1 files changed, 492 insertions, 56 deletions
diff --git a/thirdparty/glslang/SPIRV/GlslangToSpv.cpp b/thirdparty/glslang/SPIRV/GlslangToSpv.cpp index 1adebef878..c323bcdb09 100644 --- a/thirdparty/glslang/SPIRV/GlslangToSpv.cpp +++ b/thirdparty/glslang/SPIRV/GlslangToSpv.cpp @@ -160,6 +160,7 @@ protected: spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const; spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, std::vector<unsigned int>& operands) const; spv::StorageClass TranslateStorageClass(const glslang::TType&); + void TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>&, std::vector<unsigned>&) const; void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType); spv::Id createSpvVariable(const glslang::TIntermSymbol*, spv::Id forcedType); spv::Id getSampledType(const glslang::TSampler&); @@ -178,6 +179,7 @@ protected: spv::Id accessChainLoad(const glslang::TType& type); void accessChainStore(const glslang::TType& type, spv::Id rvalue); void multiTypeStore(const glslang::TType&, spv::Id rValue); + spv::Id convertLoadedBoolInUniformToUint(const glslang::TType& type, spv::Id nominalTypeId, spv::Id loadedId); glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const; int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix); int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix); @@ -255,17 +257,17 @@ protected: bool nanMinMaxClamp; // true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp spv::Id stdBuiltins; spv::Id nonSemanticDebugPrintf; - std::unordered_map<const char*, spv::Id> extBuiltinMap; + std::unordered_map<std::string, spv::Id> extBuiltinMap; - std::unordered_map<int, spv::Id> symbolValues; - std::unordered_set<int> rValueParameters; // set of formal function parameters passed as rValues, + std::unordered_map<long long, spv::Id> symbolValues; + std::unordered_set<long long> rValueParameters; // set of formal function parameters passed as rValues, // rather than a pointer std::unordered_map<std::string, spv::Function*> functionMap; std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount]; // for mapping glslang block indices to spv indices (e.g., due to hidden members): - std::unordered_map<int, std::vector<int>> memberRemapper; + std::unordered_map<long long, std::vector<int>> memberRemapper; // for mapping glslang symbol struct to symbol Id - std::unordered_map<const glslang::TTypeList*, int> glslangTypeToIdMap; + std::unordered_map<const glslang::TTypeList*, long long> glslangTypeToIdMap; std::stack<bool> breakForLoop; // false means break for switch std::unordered_map<std::string, const glslang::TIntermSymbol*> counterOriginator; // Map pointee types for EbtReference to their forward pointers @@ -380,6 +382,7 @@ spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useSto case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock; case glslang::EvqVaryingIn: return spv::DecorationBlock; case glslang::EvqVaryingOut: return spv::DecorationBlock; + case glslang::EvqShared: return spv::DecorationBlock; #ifndef GLSLANG_WEB case glslang::EvqPayload: return spv::DecorationBlock; case glslang::EvqPayloadIn: return spv::DecorationBlock; @@ -436,6 +439,7 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T break; case glslang::EbtBlock: switch (type.getQualifier().storage) { + case glslang::EvqShared: case glslang::EvqUniform: case glslang::EvqBuffer: switch (type.getQualifier().layoutPacking) { @@ -1029,6 +1033,10 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI return spv::BuiltInIncomingRayFlagsKHR; case glslang::EbvGeometryIndex: return spv::BuiltInRayGeometryIndexKHR; + case glslang::EbvCurrentRayTimeNV: + builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur); + builder.addCapability(spv::CapabilityRayTracingMotionBlurNV); + return spv::BuiltInCurrentRayTimeNV; // barycentrics case glslang::EbvBaryCoordNV: @@ -1247,6 +1255,10 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T { if (type.getBasicType() == glslang::EbtRayQuery) return spv::StorageClassPrivate; +#ifndef GLSLANG_WEB + if (type.getQualifier().isSpirvByReference()) + return spv::StorageClassFunction; +#endif if (type.getQualifier().isPipeInput()) return spv::StorageClassInput; if (type.getQualifier().isPipeOutput()) @@ -1278,6 +1290,12 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T return spv::StorageClassUniformConstant; } + if (type.getQualifier().storage == glslang::EvqShared && type.getBasicType() == glslang::EbtBlock) { + builder.addExtension(spv::E_SPV_KHR_workgroup_memory_explicit_layout); + builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayoutKHR); + return spv::StorageClassWorkgroup; + } + switch (type.getQualifier().storage) { case glslang::EvqGlobal: return spv::StorageClassPrivate; case glslang::EvqConstReadOnly: return spv::StorageClassFunction; @@ -1289,6 +1307,7 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T case glslang::EvqHitAttr: return spv::StorageClassHitAttributeKHR; case glslang::EvqCallableData: return spv::StorageClassCallableDataKHR; case glslang::EvqCallableDataIn: return spv::StorageClassIncomingCallableDataKHR; + case glslang::EvqSpirvStorageClass: return static_cast<spv::StorageClass>(type.getQualifier().spirvStorageClass); #endif default: assert(0); @@ -1298,6 +1317,52 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T return spv::StorageClassFunction; } +// Translate glslang constants to SPIR-V literals +void TGlslangToSpvTraverser::TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>& constants, + std::vector<unsigned>& literals) const +{ + for (auto constant : constants) { + if (constant->getBasicType() == glslang::EbtFloat) { + float floatValue = static_cast<float>(constant->getConstArray()[0].getDConst()); + unsigned literal = *reinterpret_cast<unsigned*>(&floatValue); + literals.push_back(literal); + } else if (constant->getBasicType() == glslang::EbtInt) { + unsigned literal = constant->getConstArray()[0].getIConst(); + literals.push_back(literal); + } else if (constant->getBasicType() == glslang::EbtUint) { + unsigned literal = constant->getConstArray()[0].getUConst(); + literals.push_back(literal); + } else if (constant->getBasicType() == glslang::EbtBool) { + unsigned literal = constant->getConstArray()[0].getBConst(); + literals.push_back(literal); + } else if (constant->getBasicType() == glslang::EbtString) { + auto str = constant->getConstArray()[0].getSConst()->c_str(); + unsigned literal = 0; + char* literalPtr = reinterpret_cast<char*>(&literal); + unsigned charCount = 0; + char ch = 0; + do { + ch = *(str++); + *(literalPtr++) = ch; + ++charCount; + if (charCount == 4) { + literals.push_back(literal); + literalPtr = reinterpret_cast<char*>(&literal); + charCount = 0; + } + } while (ch != 0); + + // Partial literal is padded with 0 + if (charCount > 0) { + for (; charCount < 4; ++charCount) + *(literalPtr++) = 0; + literals.push_back(literal); + } + } else + assert(0); // Unexpected type + } +} + // Add capabilities pertaining to how an array is indexed. void TGlslangToSpvTraverser::addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType) @@ -1485,7 +1550,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, if (glslangIntermediate->usingPhysicalStorageBuffer()) { addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT; - builder.addIncorporatedExtension(spv::E_SPV_EXT_physical_storage_buffer, spv::Spv_1_5); + builder.addIncorporatedExtension(spv::E_SPV_KHR_physical_storage_buffer, spv::Spv_1_5); builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT); } if (glslangIntermediate->usingVulkanMemoryModel()) { @@ -1518,6 +1583,13 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addCapability(spv::CapabilityRayTraversalPrimitiveCullingKHR); } +#ifndef GLSLANG_WEB + if (glslangIntermediate->getSubgroupUniformControlFlow()) { + builder.addExtension(spv::E_SPV_KHR_subgroup_uniform_control_flow); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeSubgroupUniformControlFlowKHR); + } +#endif + unsigned int mode; switch (glslangIntermediate->getStage()) { case EShLangVertex: @@ -1543,15 +1615,16 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addExtension(spv::E_SPV_KHR_post_depth_coverage); } - if (glslangIntermediate->getDepth() != glslang::EldUnchanged && glslangIntermediate->isDepthReplacing()) + if (glslangIntermediate->isDepthReplacing()) builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing); #ifndef GLSLANG_WEB switch(glslangIntermediate->getDepth()) { - case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break; - case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break; - default: mode = spv::ExecutionModeMax; break; + case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break; + case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break; + case glslang::EldUnchanged: mode = spv::ExecutionModeDepthUnchanged; break; + default: mode = spv::ExecutionModeMax; break; } if (mode != spv::ExecutionModeMax) builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); @@ -1719,6 +1792,53 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, default: break; } + +#ifndef GLSLANG_WEB + // + // Add SPIR-V requirements (GL_EXT_spirv_intrinsics) + // + if (glslangIntermediate->hasSpirvRequirement()) { + const glslang::TSpirvRequirement& spirvRequirement = glslangIntermediate->getSpirvRequirement(); + + // Add SPIR-V extension requirement + for (auto& extension : spirvRequirement.extensions) + builder.addExtension(extension.c_str()); + + // Add SPIR-V capability requirement + for (auto capability : spirvRequirement.capabilities) + builder.addCapability(static_cast<spv::Capability>(capability)); + } + + // + // Add SPIR-V execution mode qualifiers (GL_EXT_spirv_intrinsics) + // + if (glslangIntermediate->hasSpirvExecutionMode()) { + const glslang::TSpirvExecutionMode spirvExecutionMode = glslangIntermediate->getSpirvExecutionMode(); + + // Add spirv_execution_mode + for (auto& mode : spirvExecutionMode.modes) { + if (!mode.second.empty()) { + std::vector<unsigned> literals; + TranslateLiterals(mode.second, literals); + builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first), literals); + } else + builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first)); + } + + // Add spirv_execution_mode_id + for (auto& modeId : spirvExecutionMode.modeIds) { + std::vector<spv::Id> operandIds; + assert(!modeId.second.empty()); + for (auto extraOperand : modeId.second) { + int nextConst = 0; + spv::Id operandId = createSpvConstantFromConstUnionArray( + extraOperand->getType(), extraOperand->getConstArray(), nextConst, false); + operandIds.push_back(operandId); + } + builder.addExecutionModeId(shaderEntry, static_cast<spv::ExecutionMode>(modeId.first), operandIds); + } + } +#endif } // Finish creating SPV, after the traversal is complete. @@ -1986,7 +2106,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T { // This may be, e.g., an anonymous block-member selection, which generally need // index remapping due to hidden members in anonymous blocks. - int glslangId = glslangTypeToIdMap[node->getLeft()->getType().getStruct()]; + long long glslangId = glslangTypeToIdMap[node->getLeft()->getType().getStruct()]; if (memberRemapper.find(glslangId) != memberRemapper.end()) { std::vector<int>& remapper = memberRemapper[glslangId]; assert(remapper.size() > 0); @@ -2116,6 +2236,49 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T } } +spv::Id TGlslangToSpvTraverser::convertLoadedBoolInUniformToUint(const glslang::TType& type, + spv::Id nominalTypeId, + spv::Id loadedId) +{ + if (builder.isScalarType(nominalTypeId)) { + // Conversion for bool + spv::Id boolType = builder.makeBoolType(); + if (nominalTypeId != boolType) + return builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0)); + } else if (builder.isVectorType(nominalTypeId)) { + // Conversion for bvec + int vecSize = builder.getNumTypeComponents(nominalTypeId); + spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize); + if (nominalTypeId != bvecType) + loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId, + makeSmearedConstant(builder.makeUintConstant(0), vecSize)); + } else if (builder.isArrayType(nominalTypeId)) { + // Conversion for bool array + spv::Id boolArrayTypeId = convertGlslangToSpvType(type); + if (nominalTypeId != boolArrayTypeId) + { + // Use OpCopyLogical from SPIR-V 1.4 if available. + if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) + return builder.createUnaryOp(spv::OpCopyLogical, boolArrayTypeId, loadedId); + + glslang::TType glslangElementType(type, 0); + spv::Id elementNominalTypeId = builder.getContainedTypeId(nominalTypeId); + std::vector<spv::Id> constituents; + for (int index = 0; index < type.getOuterArraySize(); ++index) { + // get the element + spv::Id elementValue = builder.createCompositeExtract(loadedId, elementNominalTypeId, index); + + // recursively convert it + spv::Id elementConvertedValue = convertLoadedBoolInUniformToUint(glslangElementType, elementNominalTypeId, elementValue); + constituents.push_back(elementConvertedValue); + } + return builder.createCompositeConstruct(boolArrayTypeId, constituents); + } + } + + return loadedId; +} + // Figure out what, if any, type changes are needed when accessing a specific built-in. // Returns <the type SPIR-V requires for declarion, the type to translate to on use>. // Also see comment for 'forceType', regarding tracking SPIR-V-required types. @@ -2292,7 +2455,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI if (node->getOp() == glslang::EOpAtomicCounterIncrement || node->getOp() == glslang::EOpAtomicCounterDecrement || node->getOp() == glslang::EOpAtomicCounter || - node->getOp() == glslang::EOpInterpolateAtCentroid || + (node->getOp() == glslang::EOpInterpolateAtCentroid && + glslangIntermediate->getSource() != glslang::EShSourceHlsl) || node->getOp() == glslang::EOpRayQueryProceed || node->getOp() == glslang::EOpRayQueryGetRayTMin || node->getOp() == glslang::EOpRayQueryGetRayFlags || @@ -2300,10 +2464,14 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI node->getOp() == glslang::EOpRayQueryGetWorldRayDirection || node->getOp() == glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque || node->getOp() == glslang::EOpRayQueryTerminate || - node->getOp() == glslang::EOpRayQueryConfirmIntersection) { + node->getOp() == glslang::EOpRayQueryConfirmIntersection || + (node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference())) { operand = builder.accessChainGetLValue(); // Special case l-value operands lvalueCoherentFlags = builder.getAccessChain().coherentFlags; lvalueCoherentFlags |= TranslateCoherent(operandNode->getAsTyped()->getType()); + } else if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) { + // Will be translated to a literal value, make a placeholder here + operand = spv::NoResult; } else #endif { @@ -2324,6 +2492,38 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI result = createUnaryOperation(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType(), lvalueCoherentFlags); +#ifndef GLSLANG_WEB + // it could be attached to a SPIR-V intruction + if (!result) { + if (node->getOp() == glslang::EOpSpirvInst) { + const auto& spirvInst = node->getSpirvInstruction(); + if (spirvInst.set == "") { + spv::IdImmediate idImmOp = {true, operand}; + if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) { + // Translate the constant to a literal value + std::vector<unsigned> literals; + glslang::TVector<const glslang::TIntermConstantUnion*> constants; + constants.push_back(operandNode->getAsConstantUnion()); + TranslateLiterals(constants, literals); + idImmOp = {false, literals[0]}; + } + + if (node->getBasicType() == glslang::EbtVoid) + builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), {idImmOp}); + else + result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), {idImmOp}); + } else { + result = builder.createBuiltinCall( + resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()), + spirvInst.id, {operand}); + } + + if (node->getBasicType() == glslang::EbtVoid) + return false; // done with this node + } + } +#endif + if (result) { if (invertedType) { result = createInvertedSwizzle(decorations.precision, *node->getOperand(), result); @@ -2775,6 +2975,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; case glslang::EOpAtomicAdd: + case glslang::EOpAtomicSubtract: case glslang::EOpAtomicMin: case glslang::EOpAtomicMax: case glslang::EOpAtomicAnd: @@ -2821,6 +3022,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpIgnoreIntersectionNV: case glslang::EOpTerminateRayNV: case glslang::EOpTraceNV: + case glslang::EOpTraceRayMotionNV: case glslang::EOpTraceKHR: case glslang::EOpExecuteCallableNV: case glslang::EOpExecuteCallableKHR: @@ -2946,6 +3148,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; case glslang::EOpAtomicAdd: + case glslang::EOpAtomicSubtract: case glslang::EOpAtomicMin: case glslang::EOpAtomicMax: case glslang::EOpAtomicAnd: @@ -2966,7 +3169,13 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpInterpolateAtOffset: case glslang::EOpInterpolateAtVertex: if (arg == 0) { - lvalue = true; + // If GLSL, use the address of the interpolant argument. + // If HLSL, use an internal version of OpInterolates that takes + // the rvalue of the interpolant. A fixup pass in spirv-opt + // legalization will remove the OpLoad and convert to an lvalue. + // Had to do this because legalization will only propagate a + // builtin into an rvalue. + lvalue = glslangIntermediate->getSource() != glslang::EShSourceHlsl; // Does it need a swizzle inversion? If so, evaluation is inverted; // operate first on the swizzle base, then apply the swizzle. @@ -3012,6 +3221,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt if (arg == 1) lvalue = true; break; + case glslang::EOpSpirvInst: + if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvByReference()) + lvalue = true; + break; #endif default: break; @@ -3109,15 +3322,22 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt bool cond = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getBConst(); operands.push_back(builder.makeIntConstant(cond ? 1 : 0)); } else if ((arg == 10 && glslangOp == glslang::EOpTraceKHR) || + (arg == 11 && glslangOp == glslang::EOpTraceRayMotionNV) || (arg == 1 && glslangOp == glslang::EOpExecuteCallableKHR)) { - const int opdNum = glslangOp == glslang::EOpTraceKHR ? 10 : 1; - const int set = glslangOp == glslang::EOpTraceKHR ? 0 : 1; + const int opdNum = glslangOp == glslang::EOpTraceKHR ? 10 : (glslangOp == glslang::EOpTraceRayMotionNV ? 11 : 1); + const int set = glslangOp == glslang::EOpExecuteCallableKHR ? 1 : 0; + const int location = glslangOperands[opdNum]->getAsConstantUnion()->getConstArray()[0].getUConst(); auto itNode = locationToSymbol[set].find(location); visitSymbol(itNode->second); spv::Id symId = getSymbolId(itNode->second); operands.push_back(symId); - } else { +#ifndef GLSLANG_WEB + } else if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvLiteral()) { + // Will be translated to a literal value, make a placeholder here + operands.push_back(spv::NoResult); +#endif + } else { operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType())); } } @@ -3155,8 +3375,38 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt #endif if (atomic) { // Handle all atomics - result = createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(), + glslang::TBasicType typeProxy = (node->getOp() == glslang::EOpAtomicStore) + ? node->getSequence()[0]->getAsTyped()->getBasicType() : node->getBasicType(); + result = createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy, lvalueCoherentFlags); +#ifndef GLSLANG_WEB + } else if (node->getOp() == glslang::EOpSpirvInst) { + const auto& spirvInst = node->getSpirvInstruction(); + if (spirvInst.set == "") { + std::vector<spv::IdImmediate> idImmOps; + for (int i = 0; i < glslangOperands.size(); ++i) { + if (glslangOperands[i]->getAsTyped()->getQualifier().isSpirvLiteral()) { + // Translate the constant to a literal value + std::vector<unsigned> literals; + glslang::TVector<const glslang::TIntermConstantUnion*> constants; + constants.push_back(glslangOperands[i]->getAsConstantUnion()); + TranslateLiterals(constants, literals); + idImmOps.push_back({false, literals[0]}); + } else + idImmOps.push_back({true, operands[i]}); + } + + if (node->getBasicType() == glslang::EbtVoid) + builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), idImmOps); + else + result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), idImmOps); + } else { + result = builder.createBuiltinCall( + resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()), + spirvInst.id, operands); + } + noReturnValue = node->getBasicType() == glslang::EbtVoid; +#endif } else if (node->getOp() == glslang::EOpDebugPrintf) { if (!nonSemanticDebugPrintf) { nonSemanticDebugPrintf = builder.import("NonSemantic.DebugPrintf"); @@ -3437,6 +3687,11 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node) { +#ifndef GLSLANG_WEB + if (node->getQualifier().isSpirvLiteral()) + return; // Translated to a literal value, skip further processing +#endif + int nextConst = 0; spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false); @@ -3623,6 +3878,11 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* break; #endif default: + if (storageClass == spv::StorageClassWorkgroup && + node->getType().getBasicType() == glslang::EbtBlock) { + builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR); + break; + } if (node->getType().contains16BitFloat()) builder.addCapability(spv::CapabilityFloat16); if (node->getType().contains16BitInt()) @@ -3641,6 +3901,9 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* } else if (storageClass == spv::StorageClassStorageBuffer) { builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5); builder.addCapability(spv::CapabilityStorageBuffer8BitAccess); + } else if (storageClass == spv::StorageClassWorkgroup && + node->getType().getBasicType() == glslang::EbtBlock) { + builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR); } else { builder.addCapability(spv::CapabilityInt8); } @@ -3652,13 +3915,14 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* spv::Id initializer = spv::NoResult; - if (node->getType().getQualifier().storage == glslang::EvqUniform && - !node->getConstArray().empty()) { - int nextConst = 0; - initializer = createSpvConstantFromConstUnionArray(node->getType(), - node->getConstArray(), - nextConst, - false /* specConst */); + if (node->getType().getQualifier().storage == glslang::EvqUniform && !node->getConstArray().empty()) { + int nextConst = 0; + initializer = createSpvConstantFromConstUnionArray(node->getType(), + node->getConstArray(), + nextConst, + false /* specConst */); + } else if (node->getType().getQualifier().isNullInit()) { + initializer = builder.makeNullConstant(spvType); } return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer); @@ -3876,6 +4140,77 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty case glslang::EbtString: // no type used for OpString return 0; +#ifndef GLSLANG_WEB + case glslang::EbtSpirvType: { + // GL_EXT_spirv_intrinsics + const auto& spirvType = type.getSpirvType(); + const auto& spirvInst = spirvType.spirvInst; + + std::vector<spv::Id> operands; + for (const auto& typeParam : spirvType.typeParams) { + if (typeParam.isConstant) { + // Constant expression + if (typeParam.constant->isLiteral()) { + if (typeParam.constant->getBasicType() == glslang::EbtFloat) { + float floatValue = static_cast<float>(typeParam.constant->getConstArray()[0].getDConst()); + unsigned literal = *reinterpret_cast<unsigned*>(&floatValue); + operands.push_back(literal); + } else if (typeParam.constant->getBasicType() == glslang::EbtInt) { + unsigned literal = typeParam.constant->getConstArray()[0].getIConst(); + operands.push_back(literal); + } else if (typeParam.constant->getBasicType() == glslang::EbtUint) { + unsigned literal = typeParam.constant->getConstArray()[0].getUConst(); + operands.push_back(literal); + } else if (typeParam.constant->getBasicType() == glslang::EbtBool) { + unsigned literal = typeParam.constant->getConstArray()[0].getBConst(); + operands.push_back(literal); + } else if (typeParam.constant->getBasicType() == glslang::EbtString) { + auto str = typeParam.constant->getConstArray()[0].getSConst()->c_str(); + unsigned literal = 0; + char* literalPtr = reinterpret_cast<char*>(&literal); + unsigned charCount = 0; + char ch = 0; + do { + ch = *(str++); + *(literalPtr++) = ch; + ++charCount; + if (charCount == 4) { + operands.push_back(literal); + literalPtr = reinterpret_cast<char*>(&literal); + charCount = 0; + } + } while (ch != 0); + + // Partial literal is padded with 0 + if (charCount > 0) { + for (; charCount < 4; ++charCount) + *(literalPtr++) = 0; + operands.push_back(literal); + } + } else + assert(0); // Unexpected type + } else { + int nextConst = 0; + spv::Id constant = createSpvConstantFromConstUnionArray( + typeParam.constant->getType(), typeParam.constant->getConstArray(), nextConst, false); + operands.push_back(constant); + } + } else { + // Type specifier + spv::Id typeId = convertGlslangToSpvType(*typeParam.type); + operands.push_back(typeId); + } + } + + if (spirvInst.set == "") + spvType = builder.createOp(static_cast<spv::Op>(spirvInst.id), spv::NoType, operands); + else { + spvType = builder.createBuiltinCall( + spv::NoType, getExtBuiltins(spirvInst.set.c_str()), spirvInst.id, operands); + } + break; + } +#endif default: assert(0); break; @@ -4072,7 +4407,6 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, { // Name and decorate the non-hidden members int offset = -1; - int locationOffset = 0; // for use within the members of this struct bool memberLocationInvalid = type.isArrayOfArrays() || (type.isArray() && (type.getQualifier().isArrayedIo(glslangIntermediate->getStage()) == false)); for (int i = 0; i < (int)glslangMembers->size(); i++) { @@ -4130,10 +4464,6 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, if (!memberLocationInvalid && memberQualifier.hasLocation()) builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation); - if (qualifier.hasLocation()) // track for upcoming inheritance - locationOffset += glslangIntermediate->computeTypeLocationSize( - glslangMember, glslangIntermediate->getStage()); - // component, XFB, others if (glslangMember.getQualifier().hasComponent()) builder.addMemberDecoration(spvType, member, spv::DecorationComponent, @@ -4189,6 +4519,38 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV); builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough); } + + // + // Add SPIR-V decorations for members (GL_EXT_spirv_intrinsics) + // + if (glslangMember.getQualifier().hasSprivDecorate()) { + const glslang::TSpirvDecorate& spirvDecorate = glslangMember.getQualifier().getSpirvDecorate(); + + // Add spirv_decorate + for (auto& decorate : spirvDecorate.decorates) { + if (!decorate.second.empty()) { + std::vector<unsigned> literals; + TranslateLiterals(decorate.second, literals); + builder.addMemberDecoration(spvType, member, static_cast<spv::Decoration>(decorate.first), literals); + } + else + builder.addMemberDecoration(spvType, member, static_cast<spv::Decoration>(decorate.first)); + } + + // spirv_decorate_id not applied to members + assert(spirvDecorate.decorateIds.empty()); + + // Add spirv_decorate_string + for (auto& decorateString : spirvDecorate.decorateStrings) { + std::vector<const char*> strings; + assert(!decorateString.second.empty()); + for (auto extraOperand : decorateString.second) { + const char* string = extraOperand->getConstArray()[0].getSConst()->c_str(); + strings.push_back(string); + } + builder.addDecoration(spvType, static_cast<spv::Decoration>(decorateString.first), strings); + } + } #endif } @@ -4207,6 +4569,8 @@ spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arra glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim); if (specNode != nullptr) { builder.clearAccessChain(); + SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); + spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); specNode->traverse(this); return accessChainLoad(specNode->getAsTyped()->getType()); } @@ -4242,19 +4606,7 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type) // Need to convert to abstract types when necessary if (type.getBasicType() == glslang::EbtBool) { - if (builder.isScalarType(nominalTypeId)) { - // Conversion for bool - spv::Id boolType = builder.makeBoolType(); - if (nominalTypeId != boolType) - loadedId = builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0)); - } else if (builder.isVectorType(nominalTypeId)) { - // Conversion for bvec - int vecSize = builder.getNumTypeComponents(nominalTypeId); - spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize); - if (nominalTypeId != bvecType) - loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId, - makeSmearedConstant(builder.makeUintConstant(0), vecSize)); - } + loadedId = convertLoadedBoolInUniformToUint(type, nominalTypeId, loadedId); } return loadedId; @@ -4406,6 +4758,7 @@ glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang: // has to be a uniform or buffer block or task in/out blocks if (type.getQualifier().storage != glslang::EvqUniform && type.getQualifier().storage != glslang::EvqBuffer && + type.getQualifier().storage != glslang::EvqShared && !type.getQualifier().isTaskMemory()) return glslang::ElpNone; @@ -4575,6 +4928,9 @@ bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) return paramType.getBasicType() == glslang::EbtBlock; return paramType.containsOpaque() || // sampler, etc. +#ifndef GLSLANG_WEB + paramType.getQualifier().isSpirvByReference() || // spirv_by_reference +#endif (paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO } @@ -4968,7 +5324,10 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO int components = node->getType().getVectorSize(); - if (node->getOp() == glslang::EOpTextureFetch) { + if (node->getOp() == glslang::EOpImageLoad || + node->getOp() == glslang::EOpImageLoadLod || + node->getOp() == glslang::EOpTextureFetch || + node->getOp() == glslang::EOpTextureFetchOffset) { // These must produce 4 components, per SPIR-V spec. We'll add a conversion constructor if needed. // This will only happen through the HLSL path for operator[], so we do not have to handle e.g. // the EOpTexture/Proj/Lod/etc family. It would be harmless to do so, but would need more logic @@ -5530,7 +5889,7 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg ++lValueCount; } else { // process r-value, which involves a copy for a type mismatch - if (function->getParamType(a) != convertGlslangToSpvType(*argTypes[a]) || + if (function->getParamType(a) != builder.getTypeId(rValues[rValueCount]) || TranslatePrecisionDecoration(*argTypes[a]) != function->getParamPrecision(a)) { spv::Id argCopy = builder.createVariable(function->getParamPrecision(a), spv::StorageClassFunction, function->getParamType(a), "arg"); @@ -6813,9 +7172,6 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora break; case glslang::EOpConvPtrToUvec2: case glslang::EOpConvUvec2ToPtr: - if (builder.isVector(operand)) - builder.promoteIncorporatedExtension(spv::E_SPV_EXT_physical_storage_buffer, - spv::E_SPV_KHR_physical_storage_buffer, spv::Spv_1_5); convOp = spv::OpBitcast; break; #endif @@ -6864,29 +7220,58 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv case glslang::EOpImageAtomicAdd: case glslang::EOpAtomicCounterAdd: opCode = spv::OpAtomicIAdd; - if (typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { + if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { opCode = spv::OpAtomicFAddEXT; builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_add); - if (typeProxy == glslang::EbtFloat) + if (typeProxy == glslang::EbtFloat16) { + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float16_add); + builder.addCapability(spv::CapabilityAtomicFloat16AddEXT); + } else if (typeProxy == glslang::EbtFloat) { builder.addCapability(spv::CapabilityAtomicFloat32AddEXT); - else + } else { builder.addCapability(spv::CapabilityAtomicFloat64AddEXT); + } } break; + case glslang::EOpAtomicSubtract: case glslang::EOpAtomicCounterSubtract: opCode = spv::OpAtomicISub; break; case glslang::EOpAtomicMin: case glslang::EOpImageAtomicMin: case glslang::EOpAtomicCounterMin: - opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? - spv::OpAtomicUMin : spv::OpAtomicSMin; + if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { + opCode = spv::OpAtomicFMinEXT; + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max); + if (typeProxy == glslang::EbtFloat16) + builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT); + else if (typeProxy == glslang::EbtFloat) + builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT); + else + builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT); + } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) { + opCode = spv::OpAtomicUMin; + } else { + opCode = spv::OpAtomicSMin; + } break; case glslang::EOpAtomicMax: case glslang::EOpImageAtomicMax: case glslang::EOpAtomicCounterMax: - opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? - spv::OpAtomicUMax : spv::OpAtomicSMax; + if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { + opCode = spv::OpAtomicFMaxEXT; + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max); + if (typeProxy == glslang::EbtFloat16) + builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT); + else if (typeProxy == glslang::EbtFloat) + builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT); + else + builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT); + } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) { + opCode = spv::OpAtomicUMax; + } else { + opCode = spv::OpAtomicSMax; + } break; case glslang::EOpAtomicAnd: case glslang::EOpImageAtomicAnd: @@ -6995,6 +7380,10 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); } + if (builder.getConstantScalar(scopeId) == spv::ScopeQueueFamily) { + builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); + } + if (glslangIntermediate->usingVulkanMemoryModel() && builder.getConstantScalar(scopeId) == spv::ScopeDevice) { builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR); } @@ -7940,6 +8329,11 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: case glslang::EOpTraceNV: builder.createNoResultOp(spv::OpTraceNV, operands); return 0; + case glslang::EOpTraceRayMotionNV: + builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur); + builder.addCapability(spv::CapabilityRayTracingMotionBlurNV); + builder.createNoResultOp(spv::OpTraceRayMotionNV, operands); + return 0; case glslang::EOpTraceKHR: builder.createNoResultOp(spv::OpTraceRayKHR, operands); return 0; @@ -7991,7 +8385,7 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: opCode = spv::OpRayQueryGetIntersectionInstanceIdKHR; break; case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset: - typeId = builder.makeIntType(32); + typeId = builder.makeUintType(32); opCode = spv::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR; break; case glslang::EOpRayQueryGetIntersectionGeometryIndex: @@ -8424,6 +8818,48 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol builder.addDecoration(id, symbol->getType().getQualifier().restrict ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT); } + + // + // Add SPIR-V decorations for structure (GL_EXT_spirv_intrinsics) + // + if (symbol->getType().getQualifier().hasSprivDecorate()) { + const glslang::TSpirvDecorate& spirvDecorate = symbol->getType().getQualifier().getSpirvDecorate(); + + // Add spirv_decorate + for (auto& decorate : spirvDecorate.decorates) { + if (!decorate.second.empty()) { + std::vector<unsigned> literals; + TranslateLiterals(decorate.second, literals); + builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first), literals); + } + else + builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first)); + } + + // Add spirv_decorate_id + for (auto& decorateId : spirvDecorate.decorateIds) { + std::vector<spv::Id> operandIds; + assert(!decorateId.second.empty()); + for (auto extraOperand : decorateId.second) { + int nextConst = 0; + spv::Id operandId = createSpvConstantFromConstUnionArray( + extraOperand->getType(), extraOperand->getConstArray(), nextConst, false); + operandIds.push_back(operandId); + } + builder.addDecoration(id, static_cast<spv::Decoration>(decorateId.first), operandIds); + } + + // Add spirv_decorate_string + for (auto& decorateString : spirvDecorate.decorateStrings) { + std::vector<const char*> strings; + assert(!decorateString.second.empty()); + for (auto extraOperand : decorateString.second) { + const char* string = extraOperand->getConstArray()[0].getSConst()->c_str(); + strings.push_back(string); + } + builder.addDecoration(id, static_cast<spv::Decoration>(decorateString.first), strings); + } + } #endif return id; |