From 523e9f012e42608df1f7dd91f5625f8171b6ca3d Mon Sep 17 00:00:00 2001 From: Darren <65404740+fairywreath@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:12:19 -0500 Subject: Enable exprs for GLSL binding layout qualifiers (#5807) * Allow glsl set and binding layout qualifiers to be compile time integer exprs * add new tests * add comments * cleanup on asserts * addressed review comments and cleanup * fix missing set expr in test * fixed tests and cleanup --------- Co-authored-by: Yong He --- source/slang/slang-check-modifier.cpp | 159 ++++++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 6 deletions(-) (limited to 'source/slang/slang-check-modifier.cpp') diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index a1e0f7876..aebfe3b96 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -32,6 +32,7 @@ ConstantIntVal* SemanticsVisitor::checkConstantIntVal(Expr* expr) IntegerConstantExpressionCoercionType::AnyInteger, nullptr, ConstantFoldingKind::CompileTime); + if (!intVal) return nullptr; @@ -524,17 +525,32 @@ Modifier* SemanticsVisitor::validateAttribute( } // TODO(JS): Prior validation currently doesn't ensure both args are ints (as specified in - // core.meta.slang), so check here to make sure they both are - auto binding = checkConstantIntVal(attr->args[0]); - auto set = checkConstantIntVal(attr->args[1]); + // core.meta.slang), so check here to make sure they both are. + // + // Binding attribute may also be created from GLSL style layout qualifiers where only one of + // the args are specified, hence check for each individually. + ConstantIntVal* binding = nullptr; + if (attr->args[0]) + binding = checkConstantIntVal(attr->args[0]); + + ConstantIntVal* set = nullptr; + if (attr->args[1]) + set = checkConstantIntVal(attr->args[1]); - if (binding == nullptr || set == nullptr) + if (!binding && !set) { return nullptr; } - bindingAttr->binding = int32_t(binding->getValue()); - bindingAttr->set = int32_t(set->getValue()); + if (binding) + { + bindingAttr->binding = int32_t(binding->getValue()); + } + + if (set) + { + bindingAttr->set = int32_t(set->getValue()); + } } else if (auto simpleLayoutAttr = as(attr)) { @@ -1430,6 +1446,97 @@ bool isModifierAllowedOnDecl(bool isGLSLInput, ASTNodeType modifierType, Decl* d } } +void GLSLBindingOffsetTracker::setBindingOffset(int binding, int64_t byteOffset) +{ + bindingToByteOffset.set(binding, byteOffset); +} + +int64_t GLSLBindingOffsetTracker::getNextBindingOffset(int binding) +{ + int64_t currentOffset; + if (bindingToByteOffset.addIfNotExists(binding, 0)) + currentOffset = 0; + else + currentOffset = bindingToByteOffset.getValue(binding) + sizeof(uint32_t); + + bindingToByteOffset.set(binding, currentOffset + sizeof(uint32_t)); + return currentOffset; +} + +AttributeBase* SemanticsVisitor::checkGLSLLayoutAttribute( + UncheckedGLSLLayoutAttribute* uncheckedAttr, + ModifiableSyntaxNode* attrTarget) +{ + SLANG_ASSERT(uncheckedAttr->args.getCount() == 1); + + Attribute* attr = nullptr; + + // False if the current unchecked attribute node is deleted and does not result in a new checked + // attribute. + bool addNode = true; + + if (as(uncheckedAttr) || + as(uncheckedAttr)) + { + // Binding and set are coupled together as a descriptor table slot resource for codegen. + // Attempt to retrieve and annotate an existing binding attribute or create a new one. + attr = attrTarget->findModifier(); + if (!attr) + { + attr = m_astBuilder->create(); + } + else + { + addNode = false; + } + + // `validateAttribute`, which will be called to parse the binding arguments, also accepts + // modifiers from vk::binding and gl::binding where both set and binding are specified. + // Binding is the first and set is the second argument - specify them explicitly here. + if (as(uncheckedAttr)) + { + uncheckedAttr->args.add(nullptr); + } + else + { + uncheckedAttr->args.add(uncheckedAttr->args[0]); + uncheckedAttr->args[0] = nullptr; + } + + SLANG_ASSERT(uncheckedAttr->args.getCount() == 2); + } + else if (as(uncheckedAttr)) + { + attr = m_astBuilder->create(); + } + else + { + getSink()->diagnose(uncheckedAttr, Diagnostics::unrecognizedGLSLLayoutQualifier); + } + + if (attr) + { + attr->keywordName = uncheckedAttr->keywordName; + attr->originalIdentifierToken = uncheckedAttr->originalIdentifierToken; + attr->args = uncheckedAttr->args; + attr->loc = uncheckedAttr->loc; + + // Offset constant folding computation is deferred until all other modifiers are checked to + // ensure bindinig is checked first. + if (!as(attr)) + { + validateAttribute(attr, nullptr, attrTarget); + } + } + + if (!addNode) + { + attr = nullptr; + } + + return attr; +} + Modifier* SemanticsVisitor::checkModifier( Modifier* m, ModifiableSyntaxNode* syntaxNode, @@ -1455,6 +1562,21 @@ Modifier* SemanticsVisitor::checkModifier( return checkedAttr; } + if (auto glslLayoutAttribute = as(m)) + { + return checkGLSLLayoutAttribute(glslLayoutAttribute, syntaxNode); + } + + if (const auto glslImplicitOffsetAttribute = as(m)) + { + auto offsetAttr = m_astBuilder->create(); + offsetAttr->loc = glslImplicitOffsetAttribute->loc; + + // Offset constant folding computation is deferred until all other modifiers are checked to + // ensure bindinig is checked first. + return offsetAttr; + } + if (auto decl = as(syntaxNode)) { auto moduleDecl = getModuleDecl(decl); @@ -1903,6 +2025,31 @@ void SemanticsVisitor::checkModifiers(ModifiableSyntaxNode* syntaxNode) // install the new list of modifiers on the declaration syntaxNode->modifiers.first = resultModifiers; + // GLSL offset layout qualifiers are resolved after all other modifiers are checked to ensure + // binding layout qualifiers are processed first. + if (auto glslOffsetAttribute = syntaxNode->findModifier()) + { + if (const auto glslBindingAttribute = syntaxNode->findModifier()) + { + if (glslOffsetAttribute->args.getCount() == 0) + { + glslOffsetAttribute->offset = getGLSLBindingOffsetTracker()->getNextBindingOffset( + glslBindingAttribute->binding); + } + else if (const auto constVal = checkConstantIntVal(glslOffsetAttribute->args[0])) + { + glslOffsetAttribute->offset = uint64_t(constVal->getValue()); + getGLSLBindingOffsetTracker()->setBindingOffset( + glslBindingAttribute->binding, + glslOffsetAttribute->offset); + } + } + else + { + getSink()->diagnose(glslOffsetAttribute, Diagnostics::missingLayoutBindingModifier); + } + } + postProcessingOnModifiers(syntaxNode->modifiers); } -- cgit v1.2.3