Skip to content

Commit 523e9f0

Browse files
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>
1 parent 34497ae commit 523e9f0

13 files changed

+357
-90
lines changed

source/slang/slang-ast-modifier.h

+40
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,38 @@ class UncheckedAttribute : public AttributeBase
693693
Scope* scope = nullptr;
694694
};
695695

696+
// A GLSL layout qualifier whose value has not yet been resolved or validated.
697+
class UncheckedGLSLLayoutAttribute : public AttributeBase
698+
{
699+
SLANG_AST_CLASS(UncheckedGLSLLayoutAttribute)
700+
701+
SLANG_UNREFLECTED
702+
};
703+
704+
// GLSL `binding` layout qualifier, does not include `set`.
705+
class UncheckedGLSLBindingLayoutAttribute : public UncheckedGLSLLayoutAttribute
706+
{
707+
SLANG_AST_CLASS(UncheckedGLSLBindingLayoutAttribute)
708+
709+
SLANG_UNREFLECTED
710+
};
711+
712+
// GLSL `set` layout qualifier, does not include `binding`.
713+
class UncheckedGLSLSetLayoutAttribute : public UncheckedGLSLLayoutAttribute
714+
{
715+
SLANG_AST_CLASS(UncheckedGLSLSetLayoutAttribute)
716+
717+
SLANG_UNREFLECTED
718+
};
719+
720+
// GLSL `offset` layout qualifier.
721+
class UncheckedGLSLOffsetLayoutAttribute : public UncheckedGLSLLayoutAttribute
722+
{
723+
SLANG_AST_CLASS(UncheckedGLSLOffsetLayoutAttribute)
724+
725+
SLANG_UNREFLECTED
726+
};
727+
696728
// A `[name(arg0, ...)]` style attribute that has been validated.
697729
class Attribute : public AttributeBase
698730
{
@@ -854,6 +886,14 @@ class GLSLOffsetLayoutAttribute : public Attribute
854886
int64_t offset;
855887
};
856888

889+
// Implicitly added offset qualifier when no offset is specified.
890+
class GLSLImplicitOffsetLayoutAttribute : public AttributeBase
891+
{
892+
SLANG_AST_CLASS(GLSLImplicitOffsetLayoutAttribute)
893+
894+
SLANG_UNREFLECTED
895+
};
896+
857897
class GLSLSimpleIntegerLayoutAttribute : public Attribute
858898
{
859899
SLANG_AST_CLASS(GLSLSimpleIntegerLayoutAttribute)

source/slang/slang-check-impl.h

+24
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,17 @@ struct ImplicitCastMethodKey
614614
}
615615
};
616616

617+
/// Used to track offsets for atomic counter storage qualifiers.
618+
struct GLSLBindingOffsetTracker
619+
{
620+
public:
621+
void setBindingOffset(int binding, int64_t byteOffset);
622+
int64_t getNextBindingOffset(int binding);
623+
624+
private:
625+
Dictionary<int, int64_t> bindingToByteOffset;
626+
};
627+
617628
/// Shared state for a semantics-checking session.
618629
struct SharedSemanticsContext : public RefObject
619630
{
@@ -645,6 +656,8 @@ struct SharedSemanticsContext : public RefObject
645656
List<ModuleDecl*> importedModulesList;
646657
HashSet<ModuleDecl*> importedModulesSet;
647658

659+
GLSLBindingOffsetTracker m_glslBindingOffsetTracker;
660+
648661
public:
649662
SharedSemanticsContext(
650663
Linkage* linkage,
@@ -705,6 +718,8 @@ struct SharedSemanticsContext : public RefObject
705718
InheritanceCircularityInfo* next = nullptr;
706719
};
707720

721+
GLSLBindingOffsetTracker* getGLSLBindingOffsetTracker() { return &m_glslBindingOffsetTracker; }
722+
708723
/// Get the processed inheritance information for `type`, including all its facets
709724
InheritanceInfo getInheritanceInfo(
710725
Type* type,
@@ -1055,6 +1070,11 @@ struct SemanticsContext
10551070

10561071
OrderedHashSet<Type*>* getCapturedTypePacks() { return m_capturedTypePacks; }
10571072

1073+
GLSLBindingOffsetTracker* getGLSLBindingOffsetTracker()
1074+
{
1075+
return m_shared->getGLSLBindingOffsetTracker();
1076+
}
1077+
10581078
private:
10591079
SharedSemanticsContext* m_shared = nullptr;
10601080

@@ -1647,6 +1667,10 @@ struct SemanticsVisitor : public SemanticsContext
16471667
UncheckedAttribute* uncheckedAttr,
16481668
ModifiableSyntaxNode* attrTarget);
16491669

1670+
AttributeBase* checkGLSLLayoutAttribute(
1671+
UncheckedGLSLLayoutAttribute* uncheckedAttr,
1672+
ModifiableSyntaxNode* attrTarget);
1673+
16501674
Modifier* checkModifier(
16511675
Modifier* m,
16521676
ModifiableSyntaxNode* syntaxNode,

source/slang/slang-check-modifier.cpp

+153-6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ ConstantIntVal* SemanticsVisitor::checkConstantIntVal(Expr* expr)
3232
IntegerConstantExpressionCoercionType::AnyInteger,
3333
nullptr,
3434
ConstantFoldingKind::CompileTime);
35+
3536
if (!intVal)
3637
return nullptr;
3738

@@ -524,17 +525,32 @@ Modifier* SemanticsVisitor::validateAttribute(
524525
}
525526

526527
// TODO(JS): Prior validation currently doesn't ensure both args are ints (as specified in
527-
// core.meta.slang), so check here to make sure they both are
528-
auto binding = checkConstantIntVal(attr->args[0]);
529-
auto set = checkConstantIntVal(attr->args[1]);
528+
// core.meta.slang), so check here to make sure they both are.
529+
//
530+
// Binding attribute may also be created from GLSL style layout qualifiers where only one of
531+
// the args are specified, hence check for each individually.
532+
ConstantIntVal* binding = nullptr;
533+
if (attr->args[0])
534+
binding = checkConstantIntVal(attr->args[0]);
535+
536+
ConstantIntVal* set = nullptr;
537+
if (attr->args[1])
538+
set = checkConstantIntVal(attr->args[1]);
530539

531-
if (binding == nullptr || set == nullptr)
540+
if (!binding && !set)
532541
{
533542
return nullptr;
534543
}
535544

536-
bindingAttr->binding = int32_t(binding->getValue());
537-
bindingAttr->set = int32_t(set->getValue());
545+
if (binding)
546+
{
547+
bindingAttr->binding = int32_t(binding->getValue());
548+
}
549+
550+
if (set)
551+
{
552+
bindingAttr->set = int32_t(set->getValue());
553+
}
538554
}
539555
else if (auto simpleLayoutAttr = as<GLSLSimpleIntegerLayoutAttribute>(attr))
540556
{
@@ -1430,6 +1446,97 @@ bool isModifierAllowedOnDecl(bool isGLSLInput, ASTNodeType modifierType, Decl* d
14301446
}
14311447
}
14321448

1449+
void GLSLBindingOffsetTracker::setBindingOffset(int binding, int64_t byteOffset)
1450+
{
1451+
bindingToByteOffset.set(binding, byteOffset);
1452+
}
1453+
1454+
int64_t GLSLBindingOffsetTracker::getNextBindingOffset(int binding)
1455+
{
1456+
int64_t currentOffset;
1457+
if (bindingToByteOffset.addIfNotExists(binding, 0))
1458+
currentOffset = 0;
1459+
else
1460+
currentOffset = bindingToByteOffset.getValue(binding) + sizeof(uint32_t);
1461+
1462+
bindingToByteOffset.set(binding, currentOffset + sizeof(uint32_t));
1463+
return currentOffset;
1464+
}
1465+
1466+
AttributeBase* SemanticsVisitor::checkGLSLLayoutAttribute(
1467+
UncheckedGLSLLayoutAttribute* uncheckedAttr,
1468+
ModifiableSyntaxNode* attrTarget)
1469+
{
1470+
SLANG_ASSERT(uncheckedAttr->args.getCount() == 1);
1471+
1472+
Attribute* attr = nullptr;
1473+
1474+
// False if the current unchecked attribute node is deleted and does not result in a new checked
1475+
// attribute.
1476+
bool addNode = true;
1477+
1478+
if (as<UncheckedGLSLBindingLayoutAttribute>(uncheckedAttr) ||
1479+
as<UncheckedGLSLSetLayoutAttribute>(uncheckedAttr))
1480+
{
1481+
// Binding and set are coupled together as a descriptor table slot resource for codegen.
1482+
// Attempt to retrieve and annotate an existing binding attribute or create a new one.
1483+
attr = attrTarget->findModifier<GLSLBindingAttribute>();
1484+
if (!attr)
1485+
{
1486+
attr = m_astBuilder->create<GLSLBindingAttribute>();
1487+
}
1488+
else
1489+
{
1490+
addNode = false;
1491+
}
1492+
1493+
// `validateAttribute`, which will be called to parse the binding arguments, also accepts
1494+
// modifiers from vk::binding and gl::binding where both set and binding are specified.
1495+
// Binding is the first and set is the second argument - specify them explicitly here.
1496+
if (as<UncheckedGLSLBindingLayoutAttribute>(uncheckedAttr))
1497+
{
1498+
uncheckedAttr->args.add(nullptr);
1499+
}
1500+
else
1501+
{
1502+
uncheckedAttr->args.add(uncheckedAttr->args[0]);
1503+
uncheckedAttr->args[0] = nullptr;
1504+
}
1505+
1506+
SLANG_ASSERT(uncheckedAttr->args.getCount() == 2);
1507+
}
1508+
else if (as<UncheckedGLSLOffsetLayoutAttribute>(uncheckedAttr))
1509+
{
1510+
attr = m_astBuilder->create<GLSLOffsetLayoutAttribute>();
1511+
}
1512+
else
1513+
{
1514+
getSink()->diagnose(uncheckedAttr, Diagnostics::unrecognizedGLSLLayoutQualifier);
1515+
}
1516+
1517+
if (attr)
1518+
{
1519+
attr->keywordName = uncheckedAttr->keywordName;
1520+
attr->originalIdentifierToken = uncheckedAttr->originalIdentifierToken;
1521+
attr->args = uncheckedAttr->args;
1522+
attr->loc = uncheckedAttr->loc;
1523+
1524+
// Offset constant folding computation is deferred until all other modifiers are checked to
1525+
// ensure bindinig is checked first.
1526+
if (!as<GLSLOffsetLayoutAttribute>(attr))
1527+
{
1528+
validateAttribute(attr, nullptr, attrTarget);
1529+
}
1530+
}
1531+
1532+
if (!addNode)
1533+
{
1534+
attr = nullptr;
1535+
}
1536+
1537+
return attr;
1538+
}
1539+
14331540
Modifier* SemanticsVisitor::checkModifier(
14341541
Modifier* m,
14351542
ModifiableSyntaxNode* syntaxNode,
@@ -1455,6 +1562,21 @@ Modifier* SemanticsVisitor::checkModifier(
14551562
return checkedAttr;
14561563
}
14571564

1565+
if (auto glslLayoutAttribute = as<UncheckedGLSLLayoutAttribute>(m))
1566+
{
1567+
return checkGLSLLayoutAttribute(glslLayoutAttribute, syntaxNode);
1568+
}
1569+
1570+
if (const auto glslImplicitOffsetAttribute = as<GLSLImplicitOffsetLayoutAttribute>(m))
1571+
{
1572+
auto offsetAttr = m_astBuilder->create<GLSLOffsetLayoutAttribute>();
1573+
offsetAttr->loc = glslImplicitOffsetAttribute->loc;
1574+
1575+
// Offset constant folding computation is deferred until all other modifiers are checked to
1576+
// ensure bindinig is checked first.
1577+
return offsetAttr;
1578+
}
1579+
14581580
if (auto decl = as<Decl>(syntaxNode))
14591581
{
14601582
auto moduleDecl = getModuleDecl(decl);
@@ -1903,6 +2025,31 @@ void SemanticsVisitor::checkModifiers(ModifiableSyntaxNode* syntaxNode)
19032025
// install the new list of modifiers on the declaration
19042026
syntaxNode->modifiers.first = resultModifiers;
19052027

2028+
// GLSL offset layout qualifiers are resolved after all other modifiers are checked to ensure
2029+
// binding layout qualifiers are processed first.
2030+
if (auto glslOffsetAttribute = syntaxNode->findModifier<GLSLOffsetLayoutAttribute>())
2031+
{
2032+
if (const auto glslBindingAttribute = syntaxNode->findModifier<GLSLBindingAttribute>())
2033+
{
2034+
if (glslOffsetAttribute->args.getCount() == 0)
2035+
{
2036+
glslOffsetAttribute->offset = getGLSLBindingOffsetTracker()->getNextBindingOffset(
2037+
glslBindingAttribute->binding);
2038+
}
2039+
else if (const auto constVal = checkConstantIntVal(glslOffsetAttribute->args[0]))
2040+
{
2041+
glslOffsetAttribute->offset = uint64_t(constVal->getValue());
2042+
getGLSLBindingOffsetTracker()->setBindingOffset(
2043+
glslBindingAttribute->binding,
2044+
glslOffsetAttribute->offset);
2045+
}
2046+
}
2047+
else
2048+
{
2049+
getSink()->diagnose(glslOffsetAttribute, Diagnostics::missingLayoutBindingModifier);
2050+
}
2051+
}
2052+
19062053
postProcessingOnModifiers(syntaxNode->modifiers);
19072054
}
19082055

source/slang/slang-diagnostic-defs.h

+7
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,13 @@ DIAGNOSTIC(
12071207
Error,
12081208
cannotUseUnsizedTypeInConstantBuffer,
12091209
"cannot use unsized type '$0' in a constant buffer.")
1210+
DIAGNOSTIC(31216, Error, unrecognizedGLSLLayoutQualifier, "GLSL layout qualifier is unrecognized")
1211+
DIAGNOSTIC(
1212+
31217,
1213+
Error,
1214+
unrecognizedGLSLLayoutQualifierOrRequiresAssignment,
1215+
"GLSL layout qualifier is unrecognized or requires assignment")
1216+
12101217

12111218
// Enums
12121219

0 commit comments

Comments
 (0)