diff options
| author | Yong He <yonghe@outlook.com> | 2023-05-02 20:29:38 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-05-02 20:29:38 -0700 |
| commit | d52376a65f37fcbbb67428b917fd3819436b6dfb (patch) | |
| tree | da25b3c9a00bd003b1970b4a6c4eb38eccf62aa1 /source | |
| parent | 55291b0bf6d729fcbaf75a01926da7da8975b8e9 (diff) | |
Various dxc/fxc compatibility fixes. (#2863)
* Various dxc/fxc compatibility fixes.
* Cleanup.
* Fix test cases.
* Fix comments.
---------
Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'source')
28 files changed, 483 insertions, 61 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 6a35f496b..a2ed1d1df 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -762,6 +762,8 @@ struct String } }; +typedef String string; + __magic_type(NativeStringType) __intrinsic_type($(kIROp_NativeStringType)) struct NativeString @@ -1334,8 +1336,8 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) } // `GetDimensions` - - for(int isFloat = 0; isFloat < 2; ++isFloat) + const char* dimParamTypes[] = {"out float ", "out int ", "out uint "}; + for(auto t : dimParamTypes) for(int includeMipInfo = 0; includeMipInfo < 2; ++includeMipInfo) { { @@ -1417,8 +1419,6 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << ")\")\n"; } - char const* t = isFloat ? "out float " : "out uint "; - sb << "[__readNone]\n"; sb << "void GetDimensions("; if(includeMipInfo) @@ -2967,6 +2967,12 @@ attribute_syntax [vk_index(index : int)] : GLSLIndexAttribute; __attributeTarget(FuncDecl) attribute_syntax [vk_spirv_instruction(op : int, set : String = "")] : SPIRVInstructionOpAttribute; +__attributeTarget(FuncDecl) +attribute_syntax [spv_target_env_1_3] : SPIRVTargetEnv13Attribute; + +__attributeTarget(VarDeclBase) +attribute_syntax [disable_array_flattening] : DisableArrayFlatteningAttribute; + // Statement Attributes __attributeTarget(LoopStmt) diff --git a/source/slang/slang-api.cpp b/source/slang/slang-api.cpp index a03aa9071..864bc8b7d 100644 --- a/source/slang/slang-api.cpp +++ b/source/slang/slang-api.cpp @@ -284,7 +284,6 @@ SLANG_API void spSetLineDirectiveMode( request->setLineDirectiveMode(mode); } - SLANG_API void spSetTargetForceGLSLScalarBufferLayout( slang::ICompileRequest* request, int targetIndex, bool forceScalarLayout) { diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 1083afae4..ab66febb9 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -304,6 +304,8 @@ class HLSLRegisterSemantic : public HLSLLayoutSemantic class HLSLPackOffsetSemantic : public HLSLLayoutSemantic { SLANG_AST_CLASS(HLSLPackOffsetSemantic) + + Index uniformOffset = 0; }; @@ -731,6 +733,18 @@ class SPIRVInstructionOpAttribute : public Attribute SLANG_AST_CLASS(SPIRVInstructionOpAttribute) }; +// [[spv_target_env_1_3]] +class SPIRVTargetEnv13Attribute : public Attribute +{ + SLANG_AST_CLASS(SPIRVTargetEnv13Attribute); +}; + +// [[disable_array_flattening]] +class DisableArrayFlatteningAttribute : public Attribute +{ + SLANG_AST_CLASS(DisableArrayFlatteningAttribute); +}; + // TODO: for attributes that take arguments, the syntax node // classes should provide accessors for the values of those arguments. diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index 61f3f1196..2d5f6aad7 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -918,6 +918,40 @@ namespace Slang // See SemanticsDeclHeaderVisitor::checkExtensionExternVarAttribute. } } + + if (auto packOffsetModifier = as<HLSLPackOffsetSemantic>(m)) + { + if (!packOffsetModifier->registerName.getContent().startsWith("c")) + { + getSink()->diagnose(packOffsetModifier, Diagnostics::unknownRegisterClass, packOffsetModifier->registerName); + return m; + } + auto uniformOffset = stringToInt(packOffsetModifier->registerName.getContent().tail(1)) * 16; + if (packOffsetModifier->componentMask.getContentLength()) + { + switch (packOffsetModifier->componentMask.getContent()[0]) + { + case 'x': + uniformOffset += 0; + break; + case 'y': + uniformOffset += 4; + break; + case 'z': + uniformOffset += 8; + break; + case 'w': + uniformOffset += 12; + break; + default: + getSink()->diagnose(packOffsetModifier, Diagnostics::invalidComponentMask, packOffsetModifier->componentMask); + break; + } + } + packOffsetModifier->uniformOffset = uniformOffset; + return packOffsetModifier; + } + // Default behavior is to leave things as they are, // and assume that modifiers are mostly already checked. // diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index fc46b25b6..117c3f037 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1589,7 +1589,6 @@ namespace Slang SlangTargetFlags getTargetFlags() { return targetFlags; } CapabilitySet getTargetCaps(); bool getForceGLSLScalarBufferLayout() { return forceGLSLScalarBufferLayout; } - Session* getSession(); MatrixLayoutMode getDefaultMatrixLayoutMode(); @@ -1756,6 +1755,15 @@ namespace Slang /// Get the parent session for this linkage Session* getSessionImpl() { return m_session; } + bool getEnableEffectAnnotations() + { + return m_enableEffectAnnotations; + } + void setEnableEffectAnnotations(bool value) + { + m_enableEffectAnnotations = value; + } + // Information on the targets we are being asked to // generate code for. List<RefPtr<TargetRequest>> targets; @@ -1914,6 +1922,7 @@ namespace Slang bool m_requireCacheFileSystem = false; bool m_useFalcorCustomSharedKeywordSemantics = false; + bool m_enableEffectAnnotations = false; // Modules that have been read in with the -r option List<ComPtr<IArtifact>> m_libModules; @@ -2550,6 +2559,7 @@ namespace Slang virtual SLANG_NO_THROW SlangCompileFlags SLANG_MCALL getCompileFlags() SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL setDumpIntermediates(int enable) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL setDumpIntermediatePrefix(const char* prefix) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void SLANG_MCALL setEnableEffectAnnotations(bool value) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL setLineDirectiveMode(SlangLineDirectiveMode mode) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL setCodeGenTarget(SlangCompileTarget target) SLANG_OVERRIDE; virtual SLANG_NO_THROW int SLANG_MCALL addCodeGenTarget(SlangCompileTarget target) SLANG_OVERRIDE; diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 0b6494ad5..a35c48a6a 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -544,8 +544,8 @@ DIAGNOSTIC(39007, Error, unknownRegisterClass, "unknown register class: '$0'") DIAGNOSTIC(39008, Error, expectedARegisterIndex, "expected a register index after '$0'") DIAGNOSTIC(39009, Error, expectedSpace, "expected 'space', got '$0'") DIAGNOSTIC(39010, Error, expectedSpaceIndex, "expected a register space index after 'space'") -DIAGNOSTIC(39011, Error, componentMaskNotSupported, "explicit register component masks are not yet supported in Slang") -DIAGNOSTIC(39012, Error, packOffsetNotSupported, "explicit 'packoffset' bindings are not yet supported in Slang") +DIAGNOSTIC(39011, Error, invalidComponentMask, "invalid register component mask '$0'.") + DIAGNOSTIC(39013, Warning, registerModifierButNoVulkanLayout, "shader parameter '$0' has a 'register' specified for D3D, but no '[[vk::binding(...)]]` specified for Vulkan") DIAGNOSTIC(39014, Error, unexpectedSpecifierAfterSpace, "unexpected specifier after register space: '$0'") DIAGNOSTIC(39015, Error, wholeSpaceParameterRequiresZeroBinding, "shader parameter '$0' consumes whole descriptor sets, so the binding must be in the form '[[vk::binding(0, ...)]]'; the non-zero binding '$1' is not allowed") diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 5a40b51ef..2b5323e3f 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -1797,6 +1797,37 @@ void CLikeSourceEmitter::diagnoseUnhandledInst(IRInst* inst) getSink()->diagnose(inst, Diagnostics::unimplemented, "unexpected IR opcode during code emit"); } +bool CLikeSourceEmitter::hasExplicitConstantBufferOffset(IRInst* cbufferType) +{ + auto type = as<IRUniformParameterGroupType>(cbufferType); + if (!type) + return false; + if (as<IRGLSLShaderStorageBufferType>(cbufferType)) + return false; + auto structType = as<IRStructType>(type->getElementType()); + if (!structType) + return false; + for (auto ff : structType->getFields()) + { + if (ff->getKey()->findDecoration<IRPackOffsetDecoration>()) + return true; + } + return false; +} + +bool CLikeSourceEmitter::isSingleElementConstantBuffer(IRInst* cbufferType) +{ + auto type = as<IRUniformParameterGroupType>(cbufferType); + if (!type) + return false; + if (as<IRGLSLShaderStorageBufferType>(cbufferType)) + return false; + auto structType = as<IRStructType>(type->getElementType()); + if (structType) + return false; + return true; +} + void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inOuterPrec) { EmitOpInfo outerPrec = inOuterPrec; @@ -1895,11 +1926,6 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO m_writer->emit("->"); else m_writer->emit("."); - if(getSourceLanguage() == SourceLanguage::GLSL - && as<IRUniformParameterGroupType>(base->getDataType())) - { - m_writer->emit("_data."); - } m_writer->emit(getName(fieldExtract->getField())); break; } @@ -1930,14 +1956,13 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO { auto prec = getInfo(EmitOp::Postfix); needClose = maybeEmitParens(outerPrec, prec); - - auto base = ii->getBase(); - emitOperand(base, leftSide(outerPrec, prec)); - m_writer->emit("."); - if(getSourceLanguage() == SourceLanguage::GLSL - && as<IRUniformParameterGroupType>(base->getDataType())) + auto skipBase = isD3DTarget(getTargetReq()) && + hasExplicitConstantBufferOffset(ii->getBase()->getDataType()); + if (!skipBase) { - m_writer->emit("_data."); + auto base = ii->getBase(); + emitOperand(base, leftSide(outerPrec, prec)); + m_writer->emit("."); } m_writer->emit(getName(ii->getField())); } @@ -2032,8 +2057,7 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO { auto base = inst->getOperand(0); emitDereferenceOperand(base, outerPrec); - if(getSourceLanguage() == SourceLanguage::GLSL - && as<IRUniformParameterGroupType>(base->getDataType())) + if (isKhronosTarget(getTargetReq()) && isSingleElementConstantBuffer(base->getDataType())) { m_writer->emit("._data"); } @@ -2628,9 +2652,9 @@ void CLikeSourceEmitter::emitSemanticsUsingVarLayout(IRVarLayout* varLayout) } } -void CLikeSourceEmitter::emitSemantics(IRInst* inst) +void CLikeSourceEmitter::emitSemantics(IRInst* inst, bool allowOffsetLayout) { - emitSemanticsImpl(inst); + emitSemanticsImpl(inst, allowOffsetLayout); } void CLikeSourceEmitter::emitLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling) @@ -3105,11 +3129,11 @@ void CLikeSourceEmitter::emitStruct(IRStructType* structType) m_writer->emit(getName(structType)); - emitStructDeclarationsBlock(structType); + emitStructDeclarationsBlock(structType, false); m_writer->emit(";\n\n"); } -void CLikeSourceEmitter::emitStructDeclarationsBlock(IRStructType* structType) +void CLikeSourceEmitter::emitStructDeclarationsBlock(IRStructType* structType, bool allowOffsetLayout) { m_writer->emit("\n{\n"); m_writer->indent(); @@ -3130,8 +3154,15 @@ void CLikeSourceEmitter::emitStructDeclarationsBlock(IRStructType* structType) emitInterpolationModifiers(fieldKey, fieldType, nullptr); } + if (allowOffsetLayout) + { + if (auto packOffsetDecoration = fieldKey->findDecoration<IRPackOffsetDecoration>()) + { + emitPackOffsetModifier(fieldKey, fieldType, packOffsetDecoration); + } + } emitType(fieldType, getName(fieldKey)); - emitSemantics(fieldKey); + emitSemantics(fieldKey, allowOffsetLayout); m_writer->emit(";\n"); } diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index bfe3dcc4e..393ab602c 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -292,6 +292,8 @@ public: void emitType(IRType* type); void emitType(IRType* type, Name* name, SourceLoc const& nameLoc); void emitType(IRType* type, NameLoc const& nameAndLoc); + bool hasExplicitConstantBufferOffset(IRInst* cbufferType); + bool isSingleElementConstantBuffer(IRInst* cbufferType); // // Expressions @@ -363,7 +365,7 @@ public: void diagnoseUnhandledInst(IRInst* inst); void emitInst(IRInst* inst); - void emitSemantics(IRInst* inst); + void emitSemantics(IRInst* inst, bool allowOffsets = false); void emitSemanticsUsingVarLayout(IRVarLayout* varLayout); void emitLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling = "register"); @@ -405,7 +407,7 @@ public: void emitStruct(IRStructType* structType); // This is used independently of `emitStruct` by some GLSL parameter group // output functionality - void emitStructDeclarationsBlock(IRStructType* structType); + void emitStructDeclarationsBlock(IRStructType* structType, bool allowOffsetLayout); void emitClass(IRClassType* structType); /// Emit type attributes that should appear after, e.g., a `struct` keyword @@ -413,7 +415,7 @@ public: void emitInterpolationModifiers(IRInst* varInst, IRType* valueType, IRVarLayout* layout); void emitMeshOutputModifiers(IRInst* varInst); - + virtual void emitPackOffsetModifier(IRInst* /*varInst*/, IRType* /*valueType*/, IRPackOffsetDecoration* /*decoration*/) {}; /// Emit modifiers that should apply even for a declaration of an SSA temporary. @@ -494,10 +496,11 @@ public: virtual void emitPreModuleImpl() {} virtual void emitRateQualifiersImpl(IRRate* rate) { SLANG_UNUSED(rate); } - virtual void emitSemanticsImpl(IRInst* inst) { SLANG_UNUSED(inst); } + virtual void emitSemanticsImpl(IRInst* inst, bool allowOffsetLayout) { SLANG_UNUSED(inst); SLANG_UNUSED(allowOffsetLayout); } virtual void emitSimpleFuncParamImpl(IRParam* param); virtual void emitSimpleFuncParamsImpl(IRFunc* func); virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) { SLANG_UNUSED(varInst); SLANG_UNUSED(valueType); SLANG_UNUSED(layout); } + virtual void emitMeshOutputModifiersImpl(IRInst* varInst) { SLANG_UNUSED(varInst) } virtual void emitSimpleTypeImpl(IRType* type) = 0; virtual void emitVarDecorationsImpl(IRInst* varDecl) { SLANG_UNUSED(varDecl); } diff --git a/source/slang/slang-emit-cuda.cpp b/source/slang/slang-emit-cuda.cpp index a1e21f626..a6501b5be 100644 --- a/source/slang/slang-emit-cuda.cpp +++ b/source/slang/slang-emit-cuda.cpp @@ -745,9 +745,9 @@ void CUDASourceEmitter::emitSimpleValueImpl(IRInst* inst) } -void CUDASourceEmitter::emitSemanticsImpl(IRInst* inst) +void CUDASourceEmitter::emitSemanticsImpl(IRInst* inst, bool allowOffsetLayout) { - Super::emitSemanticsImpl(inst); + Super::emitSemanticsImpl(inst, allowOffsetLayout); } void CUDASourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) diff --git a/source/slang/slang-emit-cuda.h b/source/slang/slang-emit-cuda.h index 2ba7dd6a3..47f6eea06 100644 --- a/source/slang/slang-emit-cuda.h +++ b/source/slang/slang-emit-cuda.h @@ -69,7 +69,7 @@ protected: virtual void emitPreModuleImpl() SLANG_OVERRIDE; virtual void emitRateQualifiersImpl(IRRate* rate) SLANG_OVERRIDE; - virtual void emitSemanticsImpl(IRInst* inst) SLANG_OVERRIDE; + virtual void emitSemanticsImpl(IRInst* inst, bool allowOffsetLayout) SLANG_OVERRIDE; virtual void emitSimpleFuncImpl(IRFunc* func) SLANG_OVERRIDE; virtual void emitSimpleFuncParamsImpl(IRFunc* func) SLANG_OVERRIDE; virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) SLANG_OVERRIDE; diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp index 0abd78137..bc170dadc 100644 --- a/source/slang/slang-emit-glsl.cpp +++ b/source/slang/slang-emit-glsl.cpp @@ -339,16 +339,25 @@ void GLSLSourceEmitter::_emitGLSLParameterGroup(IRGlobalParam* varDecl, IRUnifor m_writer->emit("_S"); m_writer->emit(m_uniqueIDCounter++); - m_writer->emit("\n{\n"); - m_writer->indent(); auto elementType = type->getElementType(); - - emitType(elementType, "_data"); - m_writer->emit(";\n"); - - m_writer->dedent(); - m_writer->emit("} "); + auto structType = as<IRStructType>(elementType); + if (!as<IRGLSLShaderStorageBufferType>(type) && structType) + { + // We need to emit the fields of the struct as individual variables + // in the constant buffer. + // + emitStructDeclarationsBlock(structType, true); + } + else + { + m_writer->emit("\n{\n"); + m_writer->indent(); + emitType(elementType, "_data"); + m_writer->emit(";\n"); + m_writer->dedent(); + m_writer->emit("} "); + } m_writer->emit(getName(varDecl)); @@ -794,7 +803,7 @@ void GLSLSourceEmitter::_maybeEmitGLSLBuiltin(IRGlobalParam* var, UnownedStringS m_writer->emit("out"); m_writer->emit(" "); m_writer->emit(elementTypeName); - emitStructDeclarationsBlock(elementType); + emitStructDeclarationsBlock(elementType, false); m_writer->emit(" "); m_writer->emit(name); emitArrayBrackets(arrayType); @@ -1157,7 +1166,7 @@ void GLSLSourceEmitter::_emitGLSLPerVertexVaryingFragmentInput(IRGlobalParam* pa // _emitType(type, &arrayDeclarator); - emitSemantics(param); + emitSemantics(param, false); emitLayoutSemantics(param); @@ -2372,6 +2381,17 @@ void GLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType* } } +void GLSLSourceEmitter::emitPackOffsetModifier(IRInst* varInst, IRType* valueType, IRPackOffsetDecoration* decoration) +{ + SLANG_UNUSED(varInst); + SLANG_UNUSED(valueType); + + _requireGLSLExtension(UnownedStringSlice::fromLiteral("GL_ARB_enhanced_layouts")); + m_writer->emit("layout(offset = "); + m_writer->emit(decoration->getRegisterOffset()->getValue() * 16 + decoration->getComponentOffset()->getValue() * 4); + m_writer->emit(")\n"); +} + void GLSLSourceEmitter::emitMeshOutputModifiersImpl(IRInst* varInst) { if(varInst->findDecoration<IRGLSLPrimitivesRateDecoration>()) diff --git a/source/slang/slang-emit-glsl.h b/source/slang/slang-emit-glsl.h index 99259463b..48c6971aa 100644 --- a/source/slang/slang-emit-glsl.h +++ b/source/slang/slang-emit-glsl.h @@ -33,6 +33,8 @@ protected: virtual void emitRateQualifiersImpl(IRRate* rate) SLANG_OVERRIDE; virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) SLANG_OVERRIDE; + virtual void emitPackOffsetModifier(IRInst* varInst, IRType* valueType, IRPackOffsetDecoration* decoration) SLANG_OVERRIDE; + virtual void emitMeshOutputModifiersImpl(IRInst* varInst) SLANG_OVERRIDE; virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE; virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE; diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp index e07d9facc..434f0803e 100644 --- a/source/slang/slang-emit-hlsl.cpp +++ b/source/slang/slang-emit-hlsl.cpp @@ -208,10 +208,20 @@ void HLSLSourceEmitter::_emitHLSLParameterGroup(IRGlobalParam* varDecl, IRUnifor _emitHLSLRegisterSemantic(LayoutResourceKind::ConstantBuffer, &containerChain); + auto elementType = type->getElementType(); + if (hasExplicitConstantBufferOffset(type)) + { + // If the user has provided any explicit `packoffset` modifiers, + // we have to unwrap the struct and emit the fields directly. + emitStructDeclarationsBlock(as<IRStructType>(elementType), true); + m_writer->emit("\n"); + return; + } + + m_writer->emit("\n{\n"); m_writer->indent(); - auto elementType = type->getElementType(); emitType(elementType, getName(varDecl)); m_writer->emit(";\n"); @@ -989,7 +999,7 @@ void HLSLSourceEmitter::emitRateQualifiersImpl(IRRate* rate) } } -void HLSLSourceEmitter::emitSemanticsImpl(IRInst* inst) +void HLSLSourceEmitter::emitSemanticsImpl(IRInst* inst, bool allowOffsets) { if (auto semanticDecoration = inst->findDecoration<IRSemanticDecoration>()) { @@ -997,6 +1007,33 @@ void HLSLSourceEmitter::emitSemanticsImpl(IRInst* inst) m_writer->emit(semanticDecoration->getSemanticName()); return; } + else if (auto packOffsetDecoration = inst->findDecoration<IRPackOffsetDecoration>()) + { + if (allowOffsets) + { + m_writer->emit(" : packoffset(c"); + m_writer->emit(packOffsetDecoration->getRegisterOffset()->getValue()); + if (packOffsetDecoration->getComponentOffset()) + { + switch (packOffsetDecoration->getComponentOffset()->getValue()) + { + case 0: + break; + case 1: + m_writer->emit(".y"); + break; + case 2: + m_writer->emit(".z"); + break; + case 3: + m_writer->emit(".w"); + break; + } + } + m_writer->emit(")"); + return; + } + } if( auto readAccessSemantic = inst->findDecoration<IRStageReadAccessDecoration>()) _emitStageAccessSemantic(readAccessSemantic, "read"); @@ -1114,6 +1151,14 @@ void HLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType* } } +void HLSLSourceEmitter::emitPackOffsetModifier(IRInst* varInst, IRType* valueType, IRPackOffsetDecoration* layout) +{ + SLANG_UNUSED(varInst); + SLANG_UNUSED(valueType); + SLANG_UNUSED(layout); + // We emit packoffset as a semantic in `emitSemantic`, so nothing to do here. +} + void HLSLSourceEmitter::emitMeshOutputModifiersImpl(IRInst* varInst) { if(auto modifier = varInst->findDecoration<IRMeshOutputDecoration>()) diff --git a/source/slang/slang-emit-hlsl.h b/source/slang/slang-emit-hlsl.h index 0a4e7fde8..d69e054b4 100644 --- a/source/slang/slang-emit-hlsl.h +++ b/source/slang/slang-emit-hlsl.h @@ -36,9 +36,11 @@ protected: virtual void emitFrontMatterImpl(TargetRequest* targetReq) SLANG_OVERRIDE; virtual void emitRateQualifiersImpl(IRRate* rate) SLANG_OVERRIDE; - virtual void emitSemanticsImpl(IRInst* inst) SLANG_OVERRIDE; + virtual void emitSemanticsImpl(IRInst* inst, bool allowOffsets) SLANG_OVERRIDE; virtual void emitSimpleFuncParamImpl(IRParam* param) SLANG_OVERRIDE; virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) SLANG_OVERRIDE; + virtual void emitPackOffsetModifier(IRInst* varInst, IRType* valueType, IRPackOffsetDecoration* decoration) SLANG_OVERRIDE; + virtual void emitMeshOutputModifiersImpl(IRInst* varInst) SLANG_OVERRIDE; virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE; virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE; diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 62a1365c0..88b616996 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -54,6 +54,7 @@ #include "slang-ir-wrap-structured-buffers.h" #include "slang-ir-liveness.h" #include "slang-ir-glsl-liveness.h" +#include "slang-ir-legalize-uniform-buffer-load.h" #include "slang-ir-string-hash.h" #include "slang-ir-simplify-for-emit.h" #include "slang-ir-pytorch-cpp-binding.h" @@ -846,6 +847,11 @@ Result linkAndOptimizeIR( // arrays that the emitters can deal with. legalizeMeshOutputTypes(irModule); + if (isKhronosTarget(targetRequest) || target == CodeGenTarget::HLSL) + { + legalizeUniformBufferLoad(irModule); + } + // Lower all bit_cast operations on complex types into leaf-level // bit_cast on basic types. lowerBitCast(targetRequest, irModule); diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index b00972cce..ffdd2b337 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -661,7 +661,6 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST(PublicDecoration, public, 0, 0) INST(HLSLExportDecoration, hlslExport, 0, 0) INST(PatchConstantFuncDecoration, patchConstantFunc, 1, 0) - INST(OutputControlPointsDecoration, outputControlPoints, 1, 0) INST(OutputTopologyDecoration, outputTopology, 1, 0) INST(PartitioningDecoration, partioning, 1, 0) @@ -782,6 +781,7 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST_RANGE(StageAccessDecoration, StageReadAccessDecoration, StageWriteAccessDecoration) INST(SemanticDecoration, semantic, 2, 0) + INST(PackOffsetDecoration, packoffset, 2, 0) INST(SPIRVOpDecoration, spirvOpDecoration, 1, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 4495d1a3d..9c31798e0 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -1116,6 +1116,18 @@ struct IRSemanticDecoration : public IRDecoration int getSemanticIndex() { return int(getIntVal(getSemanticIndexOperand())); } }; +struct IRPackOffsetDecoration : IRDecoration +{ + enum + { + kOp = kIROp_PackOffsetDecoration + }; + IR_LEAF_ISA(PackOffsetDecoration) + + IRIntLit* getRegisterOffset() { return cast<IRIntLit>(getOperand(0)); } + IRIntLit* getComponentOffset() { return cast<IRIntLit>(getOperand(1)); } +}; + struct IRStageAccessDecoration : public IRDecoration { IR_PARENT_ISA(StageAccessDecoration) diff --git a/source/slang/slang-ir-legalize-uniform-buffer-load.cpp b/source/slang/slang-ir-legalize-uniform-buffer-load.cpp new file mode 100644 index 000000000..6acf38ee6 --- /dev/null +++ b/source/slang/slang-ir-legalize-uniform-buffer-load.cpp @@ -0,0 +1,50 @@ +#include "slang-ir-legalize-uniform-buffer-load.h" + +namespace Slang +{ +void legalizeUniformBufferLoad(IRModule* module) +{ + List<IRLoad*> workList; + for (auto globalInst : module->getGlobalInsts()) + { + if (auto func = as<IRGlobalValueWithCode>(globalInst)) + { + for (auto block : func->getBlocks()) + { + for (auto inst : block->getChildren()) + { + if (auto load = as<IRLoad>(inst)) + { + auto uniformBufferType = as<IRConstantBufferType>(load->getPtr()->getDataType()); + if (!uniformBufferType) + continue; + workList.add(load); + } + } + } + } + } + + IRBuilder builder(module); + for (auto load : workList) + { + auto uniformBufferType = as<IRConstantBufferType>(load->getPtr()->getDataType()); + SLANG_ASSERT(uniformBufferType); + auto structType = as<IRStructType>(uniformBufferType->getElementType()); + if (!structType) + continue; + builder.setInsertBefore(load); + List<IRInst*> fieldLoads; + for (auto field : structType->getFields()) + { + auto fieldAddr = builder.emitFieldAddress( + builder.getPtrType(field->getFieldType()), load->getPtr(), field->getKey()); + auto fieldLoad = builder.emitLoad(fieldAddr); + fieldLoads.add(fieldLoad); + } + auto makeStruct = builder.emitMakeStruct(structType, fieldLoads); + load->replaceUsesWith(makeStruct); + } +} + +} diff --git a/source/slang/slang-ir-legalize-uniform-buffer-load.h b/source/slang/slang-ir-legalize-uniform-buffer-load.h new file mode 100644 index 000000000..fff1867b6 --- /dev/null +++ b/source/slang/slang-ir-legalize-uniform-buffer-load.h @@ -0,0 +1,12 @@ +// slang-ir-legalize-uniform-buffer-load.h +#pragma once + +#include "slang-ir-insts.h" + +namespace Slang +{ + struct IRModule; + + // Legalize a load(IRUniformParameterGroupType) into a makeStruct(load(fieldAddr),...) for glsl. + void legalizeUniformBufferLoad(IRModule* module); +} diff --git a/source/slang/slang-ir-use-uninitialized-out-param.cpp b/source/slang/slang-ir-use-uninitialized-out-param.cpp index 64f5f8bd3..977876c6b 100644 --- a/source/slang/slang-ir-use-uninitialized-out-param.cpp +++ b/source/slang/slang-ir-use-uninitialized-out-param.cpp @@ -63,6 +63,7 @@ namespace Slang addresses.add(use->getUser()); break; case kIROp_Store: + case kIROp_SwizzledStore: // If we see a store of this address, add it to stores set. if (use == use->getUser()->getOperands()) stores.add(StoreSite{ use->getUser(), addr }); diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp index 95240a26c..506e96c81 100644 --- a/source/slang/slang-ir-util.cpp +++ b/source/slang/slang-ir-util.cpp @@ -430,6 +430,11 @@ bool canInstHaveSideEffectAtAddress(IRGlobalValueWithCode* func, IRInst* inst, I if (canAddressesPotentiallyAlias(func, as<IRStore>(inst)->getPtr(), addr)) return true; break; + case kIROp_SwizzledStore: + // If the target of the swizzled store inst may overlap addr, return true. + if (canAddressesPotentiallyAlias(func, as<IRSwizzledStore>(inst)->getDest(), addr)) + return true; + break; case kIROp_Call: { auto call = as<IRCall>(inst); diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 1511615ed..de2d5aff2 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -7648,6 +7648,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> irAggType, fieldKey, fieldType); + + if (auto packOffsetModifier = fieldDecl->findModifier<HLSLPackOffsetSemantic>()) + { + lowerPackOffsetModifier(fieldKey, packOffsetModifier); + } } // There may be members not handled by the above logic (e.g., @@ -7663,6 +7668,36 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return LoweredValInfo::simple(finishOuterGenerics(subBuilder, irAggType, outerGeneric)); } + void lowerPackOffsetModifier(IRInst* inst, HLSLPackOffsetSemantic* semantic) + { + auto builder = getBuilder(); + int registerOffset = stringToInt(semantic->registerName.getName()->text.getUnownedSlice().tail(1)); + int componentOffset = 0; + if (semantic->componentMask.getContentLength() != 0) + { + switch (semantic->componentMask.getContent()[0]) + { + case 'x': + componentOffset = 0; + break; + case 'y': + componentOffset = 1; + break; + case 'z': + componentOffset = 2; + break; + case 'w': + componentOffset = 3; + break; + } + } + builder->addDecoration( + inst, + kIROp_PackOffsetDecoration, + builder->getIntValue(builder->getIntType(), registerOffset), + builder->getIntValue(builder->getIntType(), componentOffset)); + } + void lowerRayPayloadAccessModifier(IRInst* inst, RayPayloadAccessSemantic* semantic, IROp op) { auto builder = getBuilder(); diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index 8437d9a6c..353c6e57f 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -81,6 +81,8 @@ enum class OptionKind LineDirectiveMode, Optimization, Obfuscate, + GLSLForceScalarLayout, + EnableEffectAnnotations, // Downstream @@ -415,6 +417,13 @@ void initCommandOptions(CommandOptions& options) "for GLSL output." }, { OptionKind::Optimization, "-O...", "-O<optimization-level>", "Set the optimization level."}, { OptionKind::Obfuscate, "-obfuscate", nullptr, "Remove all source file information from outputs." }, + { OptionKind::GLSLForceScalarLayout, + "-force-glsl-scalar-layout", + nullptr, + "Force using scalar block layout for uniform and shader storage buffers in GLSL output."}, + { OptionKind::EnableEffectAnnotations, + "-enable-effect-annotations", + "Enables support for legacy effect annotation syntax."}, }; _addOptions(makeConstArrayView(targetOpts), options); @@ -656,7 +665,7 @@ struct OptionsParser SlangTargetFlags targetFlags = 0; int targetID = -1; FloatingPointMode floatingPointMode = FloatingPointMode::Default; - + bool forceGLSLScalarLayout = false; List<CapabilityAtom> capabilityAtoms; // State for tracking command-line errors @@ -1831,6 +1840,16 @@ struct OptionsParser setFloatingPointMode(getCurrentTarget(), FloatingPointMode(value)); break; } + case OptionKind::GLSLForceScalarLayout: + { + getCurrentTarget()->forceGLSLScalarLayout = true; + break; + } + case OptionKind::EnableEffectAnnotations: + { + compileRequest->setEnableEffectAnnotations(true); + break; + } case OptionKind::Optimization: { UnownedStringSlice levelSlice = argValue.getUnownedSlice().tail(2); @@ -2525,6 +2544,10 @@ struct OptionsParser { compileRequest->setTargetFloatingPointMode(targetID, SlangFloatingPointMode(rawTarget.floatingPointMode)); } + if (rawTarget.forceGLSLScalarLayout) + { + compileRequest->setTargetForceGLSLScalarBufferLayout(targetID, true); + } } if(defaultMatrixLayoutMode != SLANG_MATRIX_LAYOUT_MODE_UNKNOWN) diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index bd33b6f37..721d4204d 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -594,12 +594,6 @@ LayoutSemanticInfo ExtractLayoutSemanticInfo( spaceToken->loc, getSink(context)); - // TODO: handle component mask part of things... - if( semantic->componentMask.hasContent()) - { - getSink(context)->diagnose(semantic->componentMask, Diagnostics::componentMaskNotSupported); - } - return info; } diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 88cc6fac2..78433a96f 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -77,6 +77,11 @@ namespace Slang Postfix, }; + struct ParserOptions + { + bool enableEffectAnnotations = false; + }; + // TODO: implement two pass parsing for file reference and struct type recognition class Parser @@ -103,6 +108,7 @@ namespace Slang TokenReader tokenReader; DiagnosticSink* sink; SourceLoc lastErrorLoc; + ParserOptions options; int genericDepth = 0; @@ -150,11 +156,13 @@ namespace Slang ASTBuilder* inAstBuilder, TokenSpan const& _tokens, DiagnosticSink * sink, - Scope* outerScope) + Scope* outerScope, + ParserOptions inOptions) : tokenReader(_tokens) , astBuilder(inAstBuilder) , sink(sink) , outerScope(outerScope) + , options(inOptions) {} Parser(const Parser & other) = default; @@ -1750,6 +1758,51 @@ namespace Slang case TokenType::LParent: break; + case TokenType::OpLess: + { + if (parser->options.enableEffectAnnotations) + { + // If we are in a context where effect annotations are allowed, + // then we need to disambiguate the content after "<" to see if it + // should be parsed as an annotation or generic argument list. + // If we can determine the content inside a `<>` is an annotation, + // we will skip the tokens inside the angle brackets. + // + if (parser->tokenReader.peekTokenType() == TokenType::OpLess) + { + if (parser->LookAheadToken("let", 1)) + { + // If we see `<let` then we are looking at a generic arg list. + } + else if (parser->LookAheadToken(":", 2)) + { + // If we see a "< xxx :", we can also parse it as a generic arg list. + } + else + { + // Otherwise, we may be looking at an effect annotation. + // For now we just skip tokens until we see `>`, if we see any `;` in between, + // we can conclude that this is an annotation. + TokenReader tempReader = parser->tokenReader; + bool foundSemicolon = false; + while (tempReader.peekTokenType() != TokenType::OpGreater && + tempReader.peekTokenType() != TokenType::EndOfFile) + { + if (tempReader.peekTokenType() == TokenType::Semicolon) + foundSemicolon = true; + tempReader.advanceToken(); + } + if (foundSemicolon) + { + parser->tokenReader = tempReader; + parser->ReadToken(TokenType::OpGreater); + } + } + } + } + + } + break; default: break; } @@ -2570,7 +2623,6 @@ namespace Slang && !initDeclarator.initializer && !initDeclarator.semantics.first) { - // Looks like a function, so parse it like one. UnwrapDeclarator(parser->astBuilder, initDeclarator, &declaratorInfo); return parseTraditionalFuncDecl(parser, declaratorInfo); } @@ -2714,8 +2766,6 @@ namespace Slang parseHLSLRegisterNameAndOptionalComponentMask(parser, semantic); parser->ReadToken(TokenType::RParent); - - parser->sink->diagnose(semantic, Diagnostics::packOffsetNotSupported); } static RayPayloadAccessSemantic* _parseRayPayloadAccessSemantic(Parser* parser, RayPayloadAccessSemantic* semantic) @@ -6155,7 +6205,7 @@ namespace Slang NamePool* namePool, SourceLanguage sourceLanguage) { - Parser parser(astBuilder, tokens, sink, outerScope); + Parser parser(astBuilder, tokens, sink, outerScope, ParserOptions{}); parser.currentScope = outerScope; parser.namePool = namePool; parser.sourceLanguage = sourceLanguage; @@ -6170,7 +6220,10 @@ namespace Slang DiagnosticSink* sink, Scope* outerScope) { - Parser parser(astBuilder, tokens, sink, outerScope); + ParserOptions options = {}; + options.enableEffectAnnotations = translationUnit->compileRequest->getLinkage()->getEnableEffectAnnotations(); + + Parser parser(astBuilder, tokens, sink, outerScope, options); parser.namePool = translationUnit->getNamePool(); parser.sourceLanguage = translationUnit->sourceLanguage; diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index 0f1341afd..79236fc48 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -3183,6 +3183,35 @@ RefPtr<VarLayout> StructTypeLayoutBuilder::addField( return fieldLayout; } +RefPtr<VarLayout> StructTypeLayoutBuilder::addExplicitUniformField(DeclRef<VarDeclBase> field, TypeLayoutResult fieldResult) +{ + auto packoffsetModifier = field.getDecl()->findModifier<HLSLPackOffsetSemantic>(); + if (!packoffsetModifier) + return nullptr; + + RefPtr<VarLayout> fieldLayout = new VarLayout(); + fieldLayout->varDecl = field; + fieldLayout->typeLayout = fieldResult.layout; + m_typeLayout->fields.add(fieldLayout); + if (field) + { + m_typeLayout->mapVarToLayout.add(field.getDecl(), fieldLayout); + } + UInt uniformOffset = packoffsetModifier->uniformOffset; + if (fieldResult.layout->FindResourceInfo(LayoutResourceKind::Uniform)) + { + fieldLayout->AddResourceInfo(LayoutResourceKind::Uniform)->index = uniformOffset; + } + UniformLayoutInfo fieldInfo = fieldResult.info.getUniformLayout(); + auto uniformInfo = m_info; + m_rules->AddStructField(&uniformInfo, fieldInfo); + m_info.alignment = uniformInfo.alignment; + m_info.size.raw = Math::Max( + m_info.size.getFiniteValue(), + (size_t)(uniformOffset + fieldResult.layout->FindResourceInfo(LayoutResourceKind::Uniform)->count.getFiniteValue())); + return fieldLayout; +} + RefPtr<VarLayout> StructTypeLayoutBuilder::addField( DeclRef<VarDeclBase> field, RefPtr<TypeLayout> fieldTypeLayout) @@ -3684,8 +3713,29 @@ static TypeLayoutResult _createTypeLayout( typeLayoutBuilder.beginLayout(type, rules); auto typeLayout = typeLayoutBuilder.getTypeLayout(); + + // First, add all fields with explicit offsets. + for (auto field : getFields(structDeclRef, MemberFilterStyle::Instance)) + { + // If the field has an explicit offset, then we will + // use that to place it. + // + if (auto packOffsetModifier = field.getDecl()->findModifier<HLSLPackOffsetSemantic>()) + { + TypeLayoutResult fieldResult = _createTypeLayout( + context, + getType(context.astBuilder, field), + field.getDecl()); + typeLayoutBuilder.addExplicitUniformField(field, fieldResult); + continue; + } + + } for (auto field : getFields(structDeclRef, MemberFilterStyle::Instance)) { + if (auto packOffsetModifier = field.getDecl()->findModifier<HLSLPackOffsetSemantic>()) + continue; + // The fields of a `struct` type may include existential (interface) // types (including as nested sub-fields), and any types present // in those fields will need to be specialized based on the diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h index e0b391232..0b6dd42d8 100644 --- a/source/slang/slang-type-layout.h +++ b/source/slang/slang-type-layout.h @@ -1138,6 +1138,10 @@ public: DeclRef<VarDeclBase> field, TypeLayoutResult fieldResult); + RefPtr<VarLayout> addExplicitUniformField( + DeclRef<VarDeclBase> field, + TypeLayoutResult fieldResult); + /// Add a field to the struct type layout. /// /// One of the `beginLayout*()` functions must have been called previously. diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 9c75aa63e..ec5a7084e 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -608,6 +608,12 @@ SLANG_NO_THROW SlangResult SLANG_MCALL Session::createSession( { linkage->setFileSystem(desc.fileSystem); } + + if (desc.structureSize >= offsetof(slang::SessionDesc, enableEffectAnnotations)) + { + linkage->setEnableEffectAnnotations(desc.enableEffectAnnotations); + } + *outSession = asExternal(linkage.detach()); return SLANG_OK; } @@ -4804,6 +4810,11 @@ void EndToEndCompileRequest::addPreprocessorDefine(const char* key, const char* getLinkage()->addPreprocessorDefine(key, value); } +void EndToEndCompileRequest::setEnableEffectAnnotations(bool value) +{ + getLinkage()->setEnableEffectAnnotations(value); +} + char const* EndToEndCompileRequest::getDiagnosticOutput() { return m_diagnosticOutput.begin(); |
