summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorEllie Hermaszewska <ellieh@nvidia.com>2023-12-15 23:41:27 +0800
committerGitHub <noreply@github.com>2023-12-15 23:41:27 +0800
commit21d17abb0e511806b7c93effc58f37169d837766 (patch)
treea39b8bc015d5f0a5e6fd12b6a31a92f162aaad44 /source
parent34f04a4670f86e64d4b35ce720281a6f0e72f733 (diff)
GLSL SSBO Support (#3400)
* Squash warnings and fix build with SLANG_EMBED_STDLIB * Add GLSLShaderStorageBuffer magic wrapper * Make GLSLSSBO not a uniform type * Buffers are global variables * Allow creating ssbo aggregate types * Allow reading from RWSB using builder * Nicer debug printing for ssbos * Lower SSBO to RWSB * Parse interface blocks into wrapped structs * Lower Interface Block Decls to structs * remove comment * Two simple ssbo tests * Move ssbo pass earlier * Correct mutable buffer detection * Do not replace ssbo usages outside of blocks * Treat GLSLSSBO as a mutable buffer for type layouts * regenerate vs projects * Correctly detect ssbo types * Diagnose illegal ssbo * remove unreachable code * neaten * ci wobble * Make GLSLSSBO ast handling more uniform * Add modifier cases for glsl * Use empty val info for unhandled interface blocks necessary for ./tests/glsl/out-binding-redeclaration.slang * more sophisticated modifier check * Correct ssbo wrapper name
Diffstat (limited to 'source')
-rw-r--r--source/slang/core.meta.slang5
-rw-r--r--source/slang/slang-ast-modifier.h49
-rw-r--r--source/slang/slang-ast-type.h2
-rw-r--r--source/slang/slang-check-decl.cpp15
-rw-r--r--source/slang/slang-check-expr.cpp34
-rw-r--r--source/slang/slang-check-modifier.cpp21
-rw-r--r--source/slang/slang-diagnostic-defs.h2
-rw-r--r--source/slang/slang-emit.cpp3
-rw-r--r--source/slang/slang-ir-inst-defs.h11
-rw-r--r--source/slang/slang-ir-insts.h5
-rw-r--r--source/slang/slang-ir-lower-glsl-ssbo-types.cpp207
-rw-r--r--source/slang/slang-ir-lower-glsl-ssbo-types.h14
-rw-r--r--source/slang/slang-ir.cpp32
-rw-r--r--source/slang/slang-ir.h2
-rw-r--r--source/slang/slang-lower-to-ir.cpp12
-rw-r--r--source/slang/slang-parser.cpp45
-rw-r--r--source/slang/slang-stdlib.cpp2
-rw-r--r--source/slang/slang-type-layout.cpp2
18 files changed, 397 insertions, 66 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index fbb18109e..bc214ceff 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -1293,6 +1293,11 @@ struct Primitives
}
};
+__generic<T>
+__intrinsic_type($(kIROp_GLSLShaderStorageBufferType))
+__magic_type(GLSLShaderStorageBufferType)
+struct GLSLShaderStorageBuffer {}
+
//@ hidden:
// Need to add constructors to the types above
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index 2b55c3414..2cf4c93cf 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -251,28 +251,6 @@ class SimpleModifier : public Modifier
};
-// Some GLSL-specific modifiers
-class GLSLBufferModifier : public SimpleModifier
-{
- SLANG_AST_CLASS(GLSLBufferModifier)
-};
-
-class GLSLWriteOnlyModifier : public SimpleModifier
-{
- SLANG_AST_CLASS(GLSLWriteOnlyModifier)
-};
-
-class GLSLReadOnlyModifier : public SimpleModifier
-{
- SLANG_AST_CLASS(GLSLReadOnlyModifier)
-};
-
-class GLSLPatchModifier : public SimpleModifier
-{
- SLANG_AST_CLASS(GLSLPatchModifier)
-};
-
-
// Indicates that this is a variable declaration that corresponds to
// a parameter block declaration in the source program.
class ImplicitParameterGroupVariableModifier : public Modifier
@@ -1413,6 +1391,13 @@ class TypeModifier : public Modifier
SLANG_AST_CLASS(TypeModifier)
};
+ /// A kind of syntax element which appears as a modifier in the syntax, but
+ /// we represent as a function over type expressions
+class WrappingTypeModifier : public TypeModifier
+{
+ SLANG_AST_CLASS(WrappingTypeModifier)
+};
+
/// A modifier that applies to a type and implies information about the
/// underlying format of a resource that uses that type as its element type.
///
@@ -1438,5 +1423,25 @@ class NoDiffModifier : public TypeModifier
SLANG_AST_CLASS(NoDiffModifier)
};
+// Some GLSL-specific modifiers
+class GLSLBufferModifier : public WrappingTypeModifier
+{
+ SLANG_AST_CLASS(GLSLBufferModifier)
+};
+
+class GLSLWriteOnlyModifier : public SimpleModifier
+{
+ SLANG_AST_CLASS(GLSLWriteOnlyModifier)
+};
+
+class GLSLReadOnlyModifier : public SimpleModifier
+{
+ SLANG_AST_CLASS(GLSLReadOnlyModifier)
+};
+
+class GLSLPatchModifier : public SimpleModifier
+{
+ SLANG_AST_CLASS(GLSLPatchModifier)
+};
} // namespace Slang
diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h
index 214d80916..713446e93 100644
--- a/source/slang/slang-ast-type.h
+++ b/source/slang/slang-ast-type.h
@@ -384,7 +384,7 @@ class GLSLOutputParameterGroupType : public VaryingParameterGroupType
// type for GLLSL `buffer` blocks
-class GLSLShaderStorageBufferType : public UniformParameterGroupType
+class GLSLShaderStorageBufferType : public PointerLikeType
{
SLANG_AST_CLASS(GLSLShaderStorageBufferType)
};
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 75aed010d..0df9619b6 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -1253,7 +1253,8 @@ namespace Slang
// without any `uniform` modifiers as true global variables by default.
if (!varDecl->findModifier<HLSLUniformModifier>() &&
!varDecl->findModifier<InModifier>() &&
- !varDecl->findModifier<OutModifier>())
+ !varDecl->findModifier<OutModifier>() &&
+ !varDecl->findModifier<GLSLBufferModifier>())
{
if (!as<ResourceType>(varDecl->type) && !as<PointerLikeType>(varDecl->type))
{
@@ -1584,7 +1585,7 @@ namespace Slang
addModifier(aggTypeDecl, m_astBuilder->create<SynthesizedModifier>());
// The visibility of synthesized decl should be the min of the parent decl and the requirement.
- if (auto visModifier = requirementDeclRef.getDecl()->findModifier<VisibilityModifier>())
+ if (requirementDeclRef.getDecl()->findModifier<VisibilityModifier>())
{
auto requirementVisibility = getDeclVisibility(requirementDeclRef.getDecl());
auto thisVisibility = getDeclVisibility(context->parentDecl);
@@ -1833,7 +1834,7 @@ namespace Slang
if (moduleDecl->members.getCount() > 0)
{
auto firstMember = moduleDecl->members[0];
- if (auto implDecl = as<ImplementingDecl>(firstMember))
+ if (as<ImplementingDecl>(firstMember))
{
if (!getShared()->isInLanguageServer())
{
@@ -2993,7 +2994,7 @@ namespace Slang
addModifier(synFuncDecl, attr);
}
// The visibility of synthesized decl should be the min of the parent decl and the requirement.
- if (auto visModifier = requiredMemberDeclRef.getDecl()->findModifier<VisibilityModifier>())
+ if (requiredMemberDeclRef.getDecl()->findModifier<VisibilityModifier>())
{
auto requirementVisibility = getDeclVisibility(requiredMemberDeclRef.getDecl());
auto thisVisibility = getDeclVisibility(context->parentDecl);
@@ -3539,7 +3540,7 @@ namespace Slang
synPropertyDecl->parentDecl = context->parentDecl;
// The visibility of synthesized decl should be the min of the parent decl and the requirement.
- if (auto visModifier = requiredMemberDeclRef.getDecl()->findModifier<VisibilityModifier>())
+ if (requiredMemberDeclRef.getDecl()->findModifier<VisibilityModifier>())
{
auto requirementVisibility = getDeclVisibility(requiredMemberDeclRef.getDecl());
auto thisVisibility = getDeclVisibility(context->parentDecl);
@@ -7049,11 +7050,11 @@ namespace Slang
}
auto firstMember = fileDecl->members[0];
- if (auto moduleDeclaration = as<ModuleDeclarationDecl>(firstMember))
+ if (as<ModuleDeclarationDecl>(firstMember))
{
// We are trying to implement a file that defines a module, this is expected.
}
- else if (auto implementing = as<ImplementingDecl>(firstMember))
+ else if (as<ImplementingDecl>(firstMember))
{
getSink()->diagnose(decl->moduleNameAndLoc.loc, Diagnostics::implementingMustReferencePrimaryModuleFile);
return;
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index 59f7f2aa1..3aaeade74 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -299,21 +299,25 @@ namespace Slang
static bool isMutableGLSLBufferBlockVarExpr(Expr* expr)
{
- if(const auto varExpr = as<VarExpr>(expr))
- {
- if(const auto declRefType = as<DeclRefType>(varExpr->type->getCanonicalType()))
- {
- if(declRefType->getDeclRef().getDecl()->isDerivedFrom(ASTNodeType::GLSLInterfaceBlockDecl))
- {
- const auto d = varExpr->declRef.getDecl();
- if(d->hasModifier<GLSLBufferModifier>() && !d->hasModifier<GLSLReadOnlyModifier>())
- {
- return true;
- }
- }
- }
- }
- return false;
+ const auto derefExpr = as<DerefExpr>(expr);
+ if(!derefExpr)
+ return false;
+ const auto varExpr = as<VarExpr>(derefExpr->base);
+ // Check the declaration type
+ if(!varExpr)
+ return false;
+
+ const auto varExprType = varExpr->type->getCanonicalType();
+ const auto ssbt = as<GLSLShaderStorageBufferType>(varExprType);
+ if(!ssbt)
+ return false;
+
+ // Check the modifiers on the declaration
+ const auto d = varExpr->declRef.getDecl();
+ if(d->hasModifier<GLSLReadOnlyModifier>())
+ return false;
+
+ return true;
}
DeclRefExpr* SemanticsVisitor::ConstructDeclRefExpr(
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp
index a9a8c19da..c9800b325 100644
--- a/source/slang/slang-check-modifier.cpp
+++ b/source/slang/slang-check-modifier.cpp
@@ -999,16 +999,15 @@ namespace Slang
}
}
- bool isModifierAllowedOnDecl(ASTNodeType modifierType, Decl* decl)
+ bool isModifierAllowedOnDecl(bool isGLSLInput, ASTNodeType modifierType, Decl* decl)
{
switch (modifierType)
{
- // Allowed only on parameters and global variables.
+ // In addition to the above cases, these are also present on empty
+ // global declarations, for instance
+ // layout(local_size_x=1) in;
case ASTNodeType::InModifier:
- case ASTNodeType::OutModifier:
case ASTNodeType::InOutModifier:
- case ASTNodeType::RefModifier:
- case ASTNodeType::ConstRefModifier:
case ASTNodeType::GLSLLayoutModifier:
case ASTNodeType::GLSLParsedLayoutModifier:
case ASTNodeType::GLSLConstantIDLayoutModifier:
@@ -1017,6 +1016,16 @@ namespace Slang
case ASTNodeType::GLSLLayoutModifierGroupMarker:
case ASTNodeType::GLSLLayoutModifierGroupBegin:
case ASTNodeType::GLSLLayoutModifierGroupEnd:
+ // If we are in GLSL mode, also allow these but otherwise fall to
+ // the regular check
+ if(isGLSLInput && as<EmptyDecl>(decl) && isGlobalDecl(decl))
+ return true;
+ [[fallthrough]];
+
+ // Allowed only on parameters and global variables.
+ case ASTNodeType::OutModifier:
+ case ASTNodeType::RefModifier:
+ case ASTNodeType::ConstRefModifier:
case ASTNodeType::GLSLBufferModifier:
case ASTNodeType::GLSLWriteOnlyModifier:
case ASTNodeType::GLSLReadOnlyModifier:
@@ -1114,7 +1123,7 @@ namespace Slang
if (auto decl = as<Decl>(syntaxNode))
{
- if (!isModifierAllowedOnDecl(m->astNodeType, decl))
+ if (!isModifierAllowedOnDecl(getLinkage()->getAllowGLSLInput(), m->astNodeType, decl))
{
getSink()->diagnose(m, Diagnostics::modifierNotAllowed, m);
return m;
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 429865b75..b7189ab0d 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -767,6 +767,8 @@ DIAGNOSTIC(57001, Warning, spirvOptFailed, "spirv-opt failed. $0")
// GLSL Compatibility
DIAGNOSTIC(58001, Error, entryPointMustReturnVoidWhenGlobalOutputPresent, "entry point must return 'void' when global output variables are present.")
+DIAGNOSTIC(58002, Error, unhandledGLSLSSBOType, "Unhandled GLSL Shader Storage Buffer Object contents, unsized arrays as a final parameter must be the only parameter")
+
//
// 8xxxx - Issues specific to a particular library/technology/platform/etc.
//
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index 684943ef3..306ad9abd 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -35,6 +35,7 @@
#include "slang-ir-lower-append-consume-structured-buffer.h"
#include "slang-ir-lower-binding-query.h"
#include "slang-ir-lower-generics.h"
+#include "slang-ir-lower-glsl-ssbo-types.h"
#include "slang-ir-lower-tuple-types.h"
#include "slang-ir-lower-result-type.h"
#include "slang-ir-lower-optional-type.h"
@@ -240,6 +241,8 @@ Result linkAndOptimizeIR(
// un-specialized IR.
dumpIRIfEnabled(codeGenContext, irModule);
+ lowerGLSLShaderStorageBufferObjects(irModule, sink);
+
translateGLSLGlobalVar(codeGenContext, irModule);
// Replace any global constants with their values.
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index cce31ed61..0abfdc694 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -197,21 +197,20 @@ INST(Nop, nop, 0, 0)
INST(ConstantBufferType, ConstantBuffer, 1, HOISTABLE)
INST(TextureBufferType, TextureBuffer, 1, HOISTABLE)
INST(ParameterBlockType, ParameterBlock, 1, HOISTABLE)
- INST(GLSLShaderStorageBufferType, GLSLShaderStorageBuffer, 0, HOISTABLE)
- INST_RANGE(UniformParameterGroupType, ConstantBufferType, GLSLShaderStorageBufferType)
+ INST_RANGE(UniformParameterGroupType, ConstantBufferType, ParameterBlockType)
/* VaryingParameterGroupType */
INST(GLSLInputParameterGroupType, GLSLInputParameterGroup, 0, HOISTABLE)
INST(GLSLOutputParameterGroupType, GLSLOutputParameterGroup, 0, HOISTABLE)
INST_RANGE(VaryingParameterGroupType, GLSLInputParameterGroupType, GLSLOutputParameterGroupType)
- INST_RANGE(ParameterGroupType, ConstantBufferType, GLSLOutputParameterGroupType)
- INST_RANGE(PointerLikeType, ConstantBufferType, GLSLOutputParameterGroupType)
- INST_RANGE(BuiltinGenericType, HLSLPointStreamType, GLSLOutputParameterGroupType)
+ INST(GLSLShaderStorageBufferType, GLSLShaderStorageBuffer, 1, HOISTABLE)
+ INST_RANGE(ParameterGroupType, ConstantBufferType, GLSLShaderStorageBufferType)
+ INST_RANGE(PointerLikeType, ConstantBufferType, GLSLShaderStorageBufferType)
+ INST_RANGE(BuiltinGenericType, HLSLPointStreamType, GLSLShaderStorageBufferType)
INST(RayQueryType, RayQuery, 1, HOISTABLE)
INST(HitObjectType, HitObject, 0, HOISTABLE)
-
// A user-defined structure declaration at the IR level.
// Unlike in the AST where there is a distinction between
// a `StructDecl` and a `DeclRefType` that refers to it,
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 1257b8971..4953a5287 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -3732,6 +3732,9 @@ public:
// Create an initially empty `class` type.
IRClassType* createClassType();
+ // Create an initially empty `GLSLShaderStorageBufferType` type.
+ IRGLSLShaderStorageBufferType* createGLSLShaderStorableBufferType();
+
// Create an empty `interface` type.
IRInterfaceType* createInterfaceType(UInt operandCount, IRInst* const* operands);
@@ -4080,6 +4083,8 @@ public:
IRSPIRVAsmInst* emitSPIRVAsmInst(IRInst* opcode, List<IRInst*> operands);
IRSPIRVAsm* emitSPIRVAsm(IRType* type);
IRInst* emitGenericAsm(UnownedStringSlice asmText);
+
+ IRInst* emitRWStructuredBufferGetElementPtr(IRInst* structuredBuffer, IRInst* index);
//
// Decorations
//
diff --git a/source/slang/slang-ir-lower-glsl-ssbo-types.cpp b/source/slang/slang-ir-lower-glsl-ssbo-types.cpp
new file mode 100644
index 000000000..010c898ad
--- /dev/null
+++ b/source/slang/slang-ir-lower-glsl-ssbo-types.cpp
@@ -0,0 +1,207 @@
+#include "slang-ir-lower-glsl-ssbo-types.h"
+#include "slang-ir.h"
+#include "slang-ir-insts.h"
+
+namespace Slang
+{
+ template<typename F>
+ static void overAllInsts(IRModule* module, F f)
+ {
+ InstWorkList workList{module};
+ InstHashSet workListSet{module};
+
+ workList.add(module->getModuleInst());
+ workListSet.add(module->getModuleInst());
+ while(workList.getCount())
+ {
+ const auto inst = workList.getLast();
+ workList.removeLast();
+ workListSet.remove(inst);
+
+ f(inst);
+
+ for(auto child = inst->getLastChild(); child; child = child->getPrevInst())
+ {
+ if(workListSet.contains(child))
+ continue;
+ workList.add(child);
+ workListSet.add(child);
+ }
+ }
+ }
+
+ struct ArrayLikeSSBOInfo
+ {
+ IRType* backingStruct;
+ IRType* elementType;
+ IRStructKey* elementsKey;
+ };
+
+ struct StructLikeSSBOInfo
+ {
+ IRType* backingStruct;
+ };
+
+ struct SSBOIndexInfo
+ {
+ IRInst* ssboVar;
+ IRInst* index;
+ };
+
+ static void lowerArrayLikeSSBOs(IRModule* module)
+ {
+ // Here we will:
+ // - Identify SSBO types which comprise a single array field with
+ // element type T
+ // - Create a (RW)StructuredBuffer<T> type
+ // - Replace all uses of the SSBO with the StructuredBuffer type
+
+ Dictionary<IRGLSLShaderStorageBufferType*, ArrayLikeSSBOInfo> arrayLikeSSBOTypes;
+ overAllInsts(module, [&](IRInst* inst){
+ if(const auto ssbo = as<IRGLSLShaderStorageBufferType>(inst))
+ {
+ if(const auto backingStruct = as<IRStructType>(ssbo->getElementType()))
+ {
+ auto members = backingStruct->getFields();
+ if(members.getFirst() != members.getLast())
+ return;
+ const auto onlyMember = members.getFirst();
+ if(!onlyMember)
+ return;
+ const auto onlyArrayMember = as<IRUnsizedArrayType>(onlyMember->getFieldType());
+ if(!onlyArrayMember)
+ return;
+ const auto elemType = onlyArrayMember->getElementType();
+ arrayLikeSSBOTypes.add(ssbo, {backingStruct, elemType, onlyMember->getKey()});
+ }
+ }
+ });
+
+ IRBuilder builder{module};
+ for(const auto& [ssbo, info] : arrayLikeSSBOTypes)
+ {
+ builder.setInsertAfter(ssbo);
+ IRInst* operands = info.elementType;
+ const auto sb = builder.getType(
+ kIROp_HLSLRWStructuredBufferType,
+ 1,
+ &operands
+ );
+ ssbo->replaceUsesWith(sb);
+ ssbo->removeAndDeallocate();
+
+ Dictionary<IRInst*, SSBOIndexInfo> indexes;
+ traverseUses(info.elementsKey, [&](IRUse* use){
+ if(const auto fieldAddress = as<IRFieldAddress>(use->getUser()))
+ {
+ traverseUses(use->user, [&](IRUse* arrayUse){
+ if(const auto gep = as<IRGetElementPtr>(arrayUse->user))
+ {
+ SLANG_ASSERT(gep->getBase() == use->user);
+ indexes.add(gep, {fieldAddress->getBase(), gep->getIndex()});
+ }
+ else
+ {
+ SLANG_UNIMPLEMENTED_X("Unhandled use of array-like SSBO");
+ }
+ });
+ }
+ else if(as<IRStructField>(use->getUser()))
+ {
+ // We expect and can ignore the use when declaring a struct field
+ }
+ else
+ {
+ SLANG_UNIMPLEMENTED_X("Unhandled use of array-like SSBO");
+ }
+ });
+ for(const auto& [elemPtr, index] : indexes)
+ {
+ builder.setInsertBefore(elemPtr);
+ const auto sbp = builder.emitRWStructuredBufferGetElementPtr(index.ssboVar, index.index);
+ elemPtr->replaceUsesWith(sbp);
+ elemPtr->removeAndDeallocate();
+ }
+ }
+ }
+
+ static void lowerStructLikeSSBOs(IRModule* module)
+ {
+ // Here we will:
+ // - Identify SSBO types without an unsized array member in the backing
+ // struct, T
+ // - Create a (RW)StructuredBuffer<T> type
+ // - Replace all uses of the SSBO with the StructuredBuffer type
+
+ Dictionary<IRGLSLShaderStorageBufferType*, StructLikeSSBOInfo> structLikeSSBOTypes;
+ overAllInsts(module, [&](IRInst* inst){
+ if(const auto ssbo = as<IRGLSLShaderStorageBufferType>(inst))
+ {
+ // Storage buffers are always backed by a struct
+ if(const auto backingStruct = as<IRStructType>(ssbo->getElementType()))
+ {
+ auto members = backingStruct->getFields();
+ const auto lastMember = members.getLast();
+ if(lastMember && as<IRUnsizedArrayType>(lastMember->getFieldType()))
+ return;
+ structLikeSSBOTypes.add(ssbo, {backingStruct});
+ }
+ }
+ });
+
+ // Collect the uses of these ssbos
+ InstHashSet ssboUses(module);
+ overAllInsts(module, [&](IRInst* inst){
+ StructLikeSSBOInfo slsi;
+ if(const auto ssboType = as<IRGLSLShaderStorageBufferType>(inst->getDataType()))
+ if(structLikeSSBOTypes.tryGetValue(ssboType, slsi))
+ ssboUses.add(inst);
+ });
+
+ IRBuilder builder{module};
+ for(const auto& [ssbo, info] : structLikeSSBOTypes)
+ {
+ builder.setInsertAfter(ssbo);
+ IRInst* operands = info.backingStruct;
+ const auto sb = builder.getType(
+ kIROp_HLSLRWStructuredBufferType,
+ 1,
+ &operands
+ );
+
+ ssbo->replaceUsesWith(sb);
+ ssbo->removeAndDeallocate();
+ }
+
+ for(const auto& var : *ssboUses.set)
+ {
+ traverseUses(var, [&](IRUse* use){
+ // We only want to insert this access into blocks, anything
+ // else we assume is just using the identity of the ssbo (for
+ // instance IRStructFieldLayoutAttr)
+ if(!as<IRBlock>(use->getUser()->getParent()))
+ return;
+ builder.setInsertBefore(use->getUser());
+ const auto sbp = builder.emitRWStructuredBufferGetElementPtr(var, builder.getIntValue(builder.getIntType(), 0));
+ use->set(sbp);
+ });
+ }
+ }
+
+ static void diagnoseRemainingSSBOs(IRModule* module, DiagnosticSink* sink)
+ {
+ overAllInsts(module, [&](IRInst* inst){
+ if(const auto ssbo = as<IRGLSLShaderStorageBufferType>(inst))
+ {
+ sink->diagnose(ssbo, Diagnostics::unhandledGLSLSSBOType);
+ }
+ });
+ }
+
+ void lowerGLSLShaderStorageBufferObjects(IRModule* module, DiagnosticSink* sink)
+ {
+ lowerArrayLikeSSBOs(module);
+ lowerStructLikeSSBOs(module);
+ diagnoseRemainingSSBOs(module, sink);
+ }
+}
diff --git a/source/slang/slang-ir-lower-glsl-ssbo-types.h b/source/slang/slang-ir-lower-glsl-ssbo-types.h
new file mode 100644
index 000000000..fb8ea3917
--- /dev/null
+++ b/source/slang/slang-ir-lower-glsl-ssbo-types.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "slang-ir.h"
+
+namespace Slang
+{
+ struct IRModule;
+ class DiagnosticSink;
+
+ /// Lower tuple types to ordinary `struct`s.
+ void lowerGLSLShaderStorageBufferObjects(
+ IRModule* module,
+ DiagnosticSink* sink);
+}
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 833ce5bb5..f9a1276fe 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -4418,6 +4418,16 @@ namespace Slang
return classType;
}
+ IRGLSLShaderStorageBufferType* IRBuilder::createGLSLShaderStorableBufferType()
+ {
+ IRGLSLShaderStorageBufferType* ssboType = createInst<IRGLSLShaderStorageBufferType>(
+ this,
+ kIROp_GLSLShaderStorageBufferType,
+ getTypeKind());
+ addGlobalValue(this, ssboType);
+ return ssboType;
+ }
+
IRInterfaceType* IRBuilder::createInterfaceType(UInt operandCount, IRInst* const* operands)
{
IRInterfaceType* interfaceType = createInst<IRInterfaceType>(
@@ -5932,6 +5942,22 @@ namespace Slang
return emitIntrinsicInst(nullptr, kIROp_GenericAsm, 1, &arg);
}
+ IRInst* IRBuilder::emitRWStructuredBufferGetElementPtr(IRInst* structuredBuffer, IRInst* index)
+ {
+ const auto sbt = cast<IRHLSLRWStructuredBufferType>(structuredBuffer->getDataType());
+ const auto t = getPtrType(sbt->getElementType());
+ IRInst* const operands[2] = {structuredBuffer, index};
+ const auto i = createInst<IRRWStructuredBufferGetElementPtr>(
+ this,
+ kIROp_RWStructuredBufferGetElementPtr,
+ t,
+ 2,
+ operands
+ );
+ addInst(i);
+ return i;
+ }
+
//
// Decorations
//
@@ -6416,6 +6442,8 @@ namespace Slang
switch( inst->getOp() )
{
case kIROp_StructType:
+ case kIROp_ClassType:
+ case kIROp_GLSLShaderStorageBufferType:
case kIROp_InterfaceType:
return false;
@@ -6812,6 +6840,8 @@ namespace Slang
case kIROp_WitnessTable:
case kIROp_StructType:
+ case kIROp_ClassType:
+ case kIROp_GLSLShaderStorageBufferType:
case kIROp_SPIRVAsm:
dumpIRParentInst(context, inst);
return;
@@ -7012,6 +7042,7 @@ namespace Slang
{
case kIROp_StructType:
case kIROp_ClassType:
+ case kIROp_GLSLShaderStorageBufferType:
case kIROp_InterfaceType:
case kIROp_Generic:
case kIROp_Param:
@@ -7737,6 +7768,7 @@ namespace Slang
// All of the cases for "global values" are side-effect-free.
case kIROp_StructType:
case kIROp_StructField:
+ case kIROp_GLSLShaderStorageBufferType:
case kIROp_RTTIPointerType:
case kIROp_RTTIObject:
case kIROp_RTTIType:
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index f1a4bdf3f..828d50c48 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -1519,7 +1519,7 @@ SIMPLE_IR_TYPE(ConstantBufferType, UniformParameterGroupType)
SIMPLE_IR_TYPE(TextureBufferType, UniformParameterGroupType)
SIMPLE_IR_TYPE(GLSLInputParameterGroupType, VaryingParameterGroupType)
SIMPLE_IR_TYPE(GLSLOutputParameterGroupType, VaryingParameterGroupType)
-SIMPLE_IR_TYPE(GLSLShaderStorageBufferType, UniformParameterGroupType)
+SIMPLE_IR_TYPE(GLSLShaderStorageBufferType, ParameterGroupType)
SIMPLE_IR_TYPE(ParameterBlockType, UniformParameterGroupType)
struct IRArrayTypeBase : IRType
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 7621f3080..b43821cf1 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -8072,7 +8072,14 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
}
else if (as<GLSLInterfaceBlockDecl>(decl))
{
- return LoweredValInfo();
+ if(decl->findModifier<GLSLBufferModifier>())
+ {
+ irAggType = subBuilder->createStructType();
+ }
+ else
+ {
+ return LoweredValInfo();
+ }
}
else
{
@@ -8115,7 +8122,8 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
if(auto superDeclRefType = as<DeclRefType>(superType))
{
if (superDeclRefType->getDeclRef().as<StructDecl>() ||
- superDeclRefType->getDeclRef().as<ClassDecl>())
+ superDeclRefType->getDeclRef().as<ClassDecl>() ||
+ superDeclRefType->getDeclRef().as<GLSLInterfaceBlockDecl>())
{
auto superKey = (IRStructKey*) getSimpleVal(context, ensureDecl(context, inheritanceDecl));
auto irSuperType = lowerType(subContext, superType.type);
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 1a7845a25..1fd8bffcc 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -190,7 +190,7 @@ namespace Slang
void parseSourceFile(ContainerDecl* parentDecl);
Decl* ParseStruct();
ClassDecl* ParseClass();
- GLSLInterfaceBlockDecl* ParseGLSLInterfaceBlock();
+ Decl* ParseGLSLInterfaceBlock();
Stmt* ParseStatement(Stmt* parentStmt = nullptr);
Stmt* parseBlockStatement();
Stmt* parseLabelStatement();
@@ -2379,6 +2379,15 @@ namespace Slang
}
}
+ static String _wrappingModifierType(const WrappingTypeModifier* mod)
+ {
+ if(as<GLSLBufferModifier>(mod))
+ {
+ return "GLSLShaderStorageBuffer";
+ }
+ SLANG_UNREACHABLE("unhandled wrapping type modifier");
+ }
+
/// Apply any type modifier in `ioBaseModifiers` to the given `typeExpr`.
///
/// If any type modifiers were present, `ioBaseModifiers` will be updated
@@ -2424,6 +2433,30 @@ namespace Slang
//
baseModifierLink = &baseModifier->next;
}
+ else if(const auto wrappingTypeModifier = as<WrappingTypeModifier>(typeModifier))
+ {
+ // This is where we match things which are modifiers in the
+ // syntax, but we match conceptually as wrappers around a type
+ // expression
+
+ // Firstly, disptach the modifier, we don't need it again
+ baseModifierLink = &baseModifier->next;
+
+ // Conjure up the generic wrapper type
+ // Make sure to use the outer scope, to avoid user name shadowing
+ auto bufferWrapperTypeExpr = parser->astBuilder->create<VarExpr>();
+ bufferWrapperTypeExpr->loc = wrappingTypeModifier->loc;
+ bufferWrapperTypeExpr->name = getName(parser, _wrappingModifierType(wrappingTypeModifier));
+ bufferWrapperTypeExpr->scope = parser->outerScope;
+
+ // Apply the wrapper
+ auto bufferPointerTypeExpr = parser->astBuilder->create<GenericAppExpr>();
+ bufferPointerTypeExpr->loc = wrappingTypeModifier->loc;
+ bufferPointerTypeExpr->functionExpr = bufferWrapperTypeExpr;
+ bufferPointerTypeExpr->arguments.add(typeExpr);
+
+ typeExpr = bufferPointerTypeExpr;
+ }
else
{
// If we have a type modifier, we need to graft it onto
@@ -2533,9 +2566,10 @@ namespace Slang
&& parser->LookAheadToken(TokenType::Identifier)
&& parser->LookAheadToken(TokenType::LBrace,1) )
{
- auto decl = parser->ParseGLSLInterfaceBlock();
- typeSpec.decl = decl;
- typeSpec.expr = createDeclRefType(parser, decl);
+ // Parse the struct-like part
+ auto innerStructDecl = parser->ParseGLSLInterfaceBlock();
+ typeSpec.decl = innerStructDecl;
+ typeSpec.expr = createDeclRefType(parser, typeSpec.decl);
return typeSpec;
}
else if(parser->LookAheadToken("enum"))
@@ -4589,11 +4623,12 @@ namespace Slang
return rs;
}
- GLSLInterfaceBlockDecl* Parser::ParseGLSLInterfaceBlock()
+ Decl* Parser::ParseGLSLInterfaceBlock()
{
//
// MyBlockName { float myData[]; } myBufferName;
//
+ // This returns a struct decl representing the fields
auto* rs = astBuilder->create<GLSLInterfaceBlockDecl>();
FillPosition(rs);
diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp
index 7fbd021b1..55b023a36 100644
--- a/source/slang/slang-stdlib.cpp
+++ b/source/slang/slang-stdlib.cpp
@@ -284,6 +284,7 @@ namespace Slang
};
// Integer types that can be used in atomic operations in CUDA.
+ [[maybe_unused]]
static const char* kCudaAtomicIntegerTypes[] = { "int", "uint", "uint64_t", "int64_t" };
// Both the following functions use these macros.
@@ -315,7 +316,6 @@ namespace Slang
const String path = getStdlibPath();
StringBuilder sb;
#include "hlsl.meta.slang.h"
- File::writeAllText("d:\\stdlib1.txt", sb.toString());
hlslLibraryCode = StringBlob::moveCreate(sb);
}
#endif
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index 691e5864c..074aa3350 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -3905,6 +3905,8 @@ static TypeLayoutResult _createTypeLayout(
// This case is mostly to allow users to add new resource types...
CASE(UntypedBufferResourceType, RawBuffer);
+ CASE(GLSLShaderStorageBufferType, MutableBuffer);
+
#undef CASE
else if(auto basicType = as<BasicExpressionType>(type))