summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-modifier.cpp
diff options
context:
space:
mode:
authorDarren <65404740+fairywreath@users.noreply.github.com>2024-12-10 13:12:19 -0500
committerGitHub <noreply@github.com>2024-12-10 10:12:19 -0800
commit523e9f012e42608df1f7dd91f5625f8171b6ca3d (patch)
treef0ba1940c442ae85e03769047125a1fe73900fb7 /source/slang/slang-check-modifier.cpp
parent34497ae6d779b16b75003c7d9b6ca04e58b4dc70 (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.cpp159
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);
}