diff options
| author | Darren <65404740+fairywreath@users.noreply.github.com> | 2024-12-10 13:12:19 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-10 10:12:19 -0800 |
| commit | 523e9f012e42608df1f7dd91f5625f8171b6ca3d (patch) | |
| tree | f0ba1940c442ae85e03769047125a1fe73900fb7 /source/slang/slang-check-modifier.cpp | |
| parent | 34497ae6d779b16b75003c7d9b6ca04e58b4dc70 (diff) | |
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 <yonghe@outlook.com>
Diffstat (limited to 'source/slang/slang-check-modifier.cpp')
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 159 |
1 files changed, 153 insertions, 6 deletions
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<GLSLSimpleIntegerLayoutAttribute>(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<UncheckedGLSLBindingLayoutAttribute>(uncheckedAttr) || + as<UncheckedGLSLSetLayoutAttribute>(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<GLSLBindingAttribute>(); + if (!attr) + { + attr = m_astBuilder->create<GLSLBindingAttribute>(); + } + 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<UncheckedGLSLBindingLayoutAttribute>(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<UncheckedGLSLOffsetLayoutAttribute>(uncheckedAttr)) + { + attr = m_astBuilder->create<GLSLOffsetLayoutAttribute>(); + } + 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<GLSLOffsetLayoutAttribute>(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<UncheckedGLSLLayoutAttribute>(m)) + { + return checkGLSLLayoutAttribute(glslLayoutAttribute, syntaxNode); + } + + if (const auto glslImplicitOffsetAttribute = as<GLSLImplicitOffsetLayoutAttribute>(m)) + { + auto offsetAttr = m_astBuilder->create<GLSLOffsetLayoutAttribute>(); + 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<Decl>(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<GLSLOffsetLayoutAttribute>()) + { + if (const auto glslBindingAttribute = syntaxNode->findModifier<GLSLBindingAttribute>()) + { + 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); } |
