diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2023-12-15 23:41:27 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-12-15 23:41:27 +0800 |
| commit | 21d17abb0e511806b7c93effc58f37169d837766 (patch) | |
| tree | a39b8bc015d5f0a5e6fd12b6a31a92f162aaad44 /source | |
| parent | 34f04a4670f86e64d4b35ce720281a6f0e72f733 (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.slang | 5 | ||||
| -rw-r--r-- | source/slang/slang-ast-modifier.h | 49 | ||||
| -rw-r--r-- | source/slang/slang-ast-type.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 15 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 34 | ||||
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 21 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-emit.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 11 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-glsl-ssbo-types.cpp | 207 | ||||
| -rw-r--r-- | source/slang/slang-ir-lower-glsl-ssbo-types.h | 14 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 32 | ||||
| -rw-r--r-- | source/slang/slang-ir.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 12 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 45 | ||||
| -rw-r--r-- | source/slang/slang-stdlib.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-type-layout.cpp | 2 |
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)) |
